10 #include <fmt/format.h> 
   11 #include <gtest/gtest.h> 
   19 #include "mock/daqifMock.hpp" 
   22 using namespace ::testing;
 
   23 using namespace std::literals;
 
   39         , m_event_log(std::make_shared<
daq::ObservableEventLog>())
 
   41               m_io_ctx, m_mal_mock, m_mgr_mock, 
"ocm", 
"/tmp", m_event_log)) {
 
   44         m_metadata_sources = 
"meta@zpb.rr://uri";
 
   45         m_prim_sources = 
"prim@zpb.rr://uri";
 
   46         m_daq_properties = R
"( 
   55                         "type": "valueKeyword", 
   84 TEST(TestParseSingleSource, Successful) {
 
   88     EXPECT_EQ(expected, parsed);
 
   91 TEST(TestParseSingleSource, LeadingOrTrailingSpacesAreAllowed) {
 
   98 TEST(TestParseSingleSource, Incomplete) {
 
  101                  std::invalid_argument);
 
  103                  std::invalid_argument);
 
  104     EXPECT_THROW(
ParseSourceUri(fmt::format(
"@,")), std::invalid_argument);
 
  106                  std::invalid_argument);
 
  108                  std::invalid_argument);
 
  111 TEST(TestParseMultipleSources, Successful) {
 
  114     std::vector<ParsedSource> result{expected1, expected2};
 
  131 TEST(TestParseSingleSource, Empty) {
 
  134                  std::invalid_argument);
 
  135     EXPECT_THROW(
ParseSourceUri(fmt::format(
"{}@,{} ", expected.
name, 
"")), std::invalid_argument);
 
  137                  std::invalid_argument);
 
  140 TEST(TestParseDaqContext, Successful) {
 
  141     auto max_err_ms = 0.001;
 
  143         auto properties_str = R
"( 
  147                             "type": "esoKeyword", 
  152                             "type": "valueKeyword", 
  161         EXPECT_THAT(
static_cast<double>(properties.await_interval.count()),
 
  162                     DoubleNear(100, max_err_ms));
 
  165         auto properties_str = R
"( 
  171         EXPECT_THAT(
static_cast<double>(properties.await_interval.count()),
 
  172                     DoubleNear(1000, max_err_ms));
 
  176 TEST(TestParseDaqContext, Failures) {
 
  184     EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv, _)).WillOnce(Return(
true));
 
  187     auto fut = m_daq_impl->StartDaq(
"id", 
"prefix", m_prim_sources, m_metadata_sources, 
"");
 
  189     ASSERT_TRUE(fut.is_ready()) << 
"future should be ready by now since daq with id already exist";
 
  190     EXPECT_THROW(fut.get(), daqif::DaqException);
 
  197     EXPECT_CALL(m_mgr_mock, MakeDaqId(_)).WillOnce(Return(
"id"));
 
  199         .WillOnce(Return(ByMove(boost::make_ready_future<daq::State>(daq::State::Acquiring))));
 
  201     EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_, 
"daqif_DaqReply"))
 
  202         .WillOnce(Return(fake_reply))
 
  203         .RetiresOnSaturation();
 
  206     auto fut = m_daq_impl->StartDaq(
"", 
"prefix", m_prim_sources, m_metadata_sources, 
"");
 
  210     ASSERT_TRUE(fut.is_ready()) << 
"future should be ready immediately since we faked a " 
  211                                    "synchronous start with make_ready_future";
 
  212     EXPECT_TRUE(fut.has_value());
 
  213     auto reply = fut.get();
 
  215     EXPECT_EQ(reply->getId(), 
"id");
 
  222     auto fut = m_daq_impl->StartDaq(
"id", 
"prefix", 
"", m_metadata_sources, 
"INVALID JSON");
 
  224     ASSERT_TRUE(fut.is_ready()) << 
"future should be ready by now since daq with id already exist";
 
  225     EXPECT_THROW(fut.get(), daqif::DaqException);
 
  233     auto fut = m_daq_impl->StartDaq(
"id", 
"prefix", 
"", m_metadata_sources, 
"[]");
 
  235     ASSERT_TRUE(fut.is_ready());
 
  236     EXPECT_THROW(fut.get(), daqif::DaqException);
 
  244     auto fut = m_daq_impl->StartDaq(
"id", 
"/path/prefix", 
"", m_metadata_sources, m_daq_properties);
 
  246     ASSERT_TRUE(fut.is_ready());
 
  247     EXPECT_THROW(fut.get(), daqif::DaqException);
 
  254     EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv, _)).WillOnce(Return(
false));
 
  256         .WillOnce(Return(ByMove(boost::make_ready_future<daq::State>(daq::State::Acquiring))));
 
  258     EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_, 
"daqif_DaqReply"))
 
  259         .WillOnce(Return(fake_reply))
 
  260         .RetiresOnSaturation();
 
  263     auto fut = m_daq_impl->StartDaq(
"id", 
"prefix", 
"", m_metadata_sources, m_daq_properties);
 
  268     ASSERT_TRUE(fut.is_ready()) << 
"future should be ready immediately since we faked a " 
  269                                    "synchronous start with make_ready_future";
 
  270     EXPECT_TRUE(fut.has_value());
 
  271     auto reply = fut.get();
 
  273     EXPECT_EQ(reply->getId(), 
"id");
 
  278     EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv, _)).WillOnce(Return(
false));
 
  279     EXPECT_CALL(m_mgr_mock, StartDaqAsync(_)).WillOnce(Throw(std::runtime_error(
"error")));
 
  282     auto fut = m_daq_impl->StartDaq(
"id", 
"prefix", 
"", m_metadata_sources, 
"");
 
  284     ASSERT_TRUE(fut.is_ready()) << 
"future should be ready immediately since we faked a " 
  285                                    "synchronous start with make_ready_future";
 
  286     EXPECT_THROW(fut.get(), daqif::DaqException)
 
  287         << 
"future should have contained the ICD exception type";
 
  293     EXPECT_CALL(m_mgr_mock, MakeDaqId(_)).WillOnce(Return(
"fileid"));
 
  294     EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv, _)).WillOnce(Return(
false));
 
  296         .WillOnce(Return(ByMove(boost::make_exceptional_future<daq::State>(
 
  300     auto fut = m_daq_impl->StartDaq(
"id", 
"prefix", 
"", m_metadata_sources, 
"");
 
  302     ASSERT_TRUE(fut.is_ready())
 
  303         << 
"future should be ready now since we faked a synchronous start with make_ready_future";
 
  304     EXPECT_THROW(fut.get(), daqif::DaqException)
 
  305         << 
"future should have contained the ICD exception type";
 
  311     EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv, _)).Times(Between(0, 1)).WillRepeatedly(Return(
false));
 
  313     EXPECT_CALL(m_mgr_mock, StopDaqAsync(
"id"sv, daq::ErrorPolicy::Strict))
 
  314         .Times(Between(0, 1))
 
  315         .WillOnce(Return(ByMove(
 
  316             boost::make_exceptional_future<daq::Status>(std::invalid_argument(
"no such id")))));
 
  319     auto reply_fut = m_daq_impl->StopDaq(
"id");
 
  321     ASSERT_TRUE(reply_fut.is_ready());
 
  322     EXPECT_THROW(reply_fut.get(), daqif::DaqException);
 
  331     EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv, _)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
 
  332     EXPECT_CALL(m_mgr_mock, StopDaqAsync(
"id"sv, daq::ErrorPolicy::Strict))
 
  333         .WillOnce(Return(ByMove(boost::make_ready_future<daq::Status>(status))));
 
  334     EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_, 
"daqif_DaqReply"))
 
  335         .WillOnce(Return(fake_reply))
 
  336         .RetiresOnSaturation();
 
  339     auto reply_fut = m_daq_impl->StopDaq(
"id");
 
  341     ASSERT_TRUE(reply_fut.is_ready());
 
  342     std::shared_ptr<daqif::DaqReply> reply = reply_fut.get();
 
  343     EXPECT_EQ(reply->getId(), 
"id");
 
  352     EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv, _)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
 
  354         .WillOnce(Return(ByMove(boost::make_ready_future<daq::Status>(status))));
 
  355     EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_, 
"daqif_DaqReply"))
 
  356         .WillOnce(Return(fake_reply))
 
  357         .RetiresOnSaturation();
 
  360     auto reply_fut = m_daq_impl->ForceStopDaq(
"id");
 
  362     ASSERT_TRUE(reply_fut.is_ready());
 
  363     std::shared_ptr<daqif::DaqReply> reply = reply_fut.get();
 
  364     EXPECT_EQ(reply->getId(), 
"id");
 
  370     EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv, _)).Times(Between(0, 1)).WillRepeatedly(Return(
false));
 
  371     EXPECT_CALL(m_mgr_mock, AbortDaqAsync(
"id"sv, daq::ErrorPolicy::Strict))
 
  372         .Times(Between(0, 1))
 
  373         .WillOnce(Return(ByMove(
 
  374             boost::make_exceptional_future<daq::Status>(std::invalid_argument(
"no such id")))));
 
  377     auto reply_fut = m_daq_impl->AbortDaq(
"id");
 
  379     ASSERT_TRUE(reply_fut.is_ready());
 
  380     EXPECT_THROW(reply_fut.get(), daqif::DaqException);
 
  388     reply_status.state = daq::State::Aborted;
 
  391     EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv, _)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
 
  392     EXPECT_CALL(m_mgr_mock, AbortDaqAsync(
"id"sv, daq::ErrorPolicy::Strict))
 
  393         .WillOnce(Return(ByMove(boost::make_ready_future<daq::Status>(reply_status))));
 
  394     EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_, 
"daqif_DaqReply"))
 
  395         .WillOnce(Return(fake_reply))
 
  396         .RetiresOnSaturation();
 
  399     auto reply_fut = m_daq_impl->AbortDaq(
"id");
 
  401     ASSERT_TRUE(reply_fut.is_ready());
 
  402     std::shared_ptr<daqif::DaqReply> reply = reply_fut.get();
 
  403     EXPECT_EQ(reply->getId(), 
"id");
 
  410     reply_status.state = daq::State::Aborted;
 
  413     EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv, _)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
 
  415         .WillOnce(Return(ByMove(boost::make_ready_future<daq::Status>(reply_status))));
 
  416     EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_, 
"daqif_DaqReply"))
 
  417         .WillOnce(Return(fake_reply))
 
  418         .RetiresOnSaturation();
 
  421     auto reply_fut = m_daq_impl->ForceAbortDaq(
"id");
 
  423     ASSERT_TRUE(reply_fut.is_ready());
 
  424     std::shared_ptr<daqif::DaqReply> reply = reply_fut.get();
 
  425     EXPECT_EQ(reply->getId(), 
"id");
 
  430     std::string keywords = R
"( 
  433               "type":"valueKeyword", 
  450     EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv, _)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
 
  452     EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_, 
"daqif_DaqReply"))
 
  453         .WillOnce(Return(fake_reply))
 
  454         .RetiresOnSaturation();
 
  457     auto reply_fut = m_daq_impl->UpdateKeywords(
"id", keywords);
 
  459     ASSERT_TRUE(reply_fut.is_ready());
 
  460     std::shared_ptr<daqif::DaqReply> reply = reply_fut.get();
 
  461     EXPECT_EQ(reply->getId(), 
"id");
 
  462     EXPECT_EQ(reply->getError(), 
false);
 
  467     std::string keywords_with_trailing_comma = R
"( 
  470               "type":"valueKeyword", 
  482     EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv, _)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
 
  486     auto reply_fut = m_daq_impl->UpdateKeywords(
"id", keywords_with_trailing_comma);
 
  488     ASSERT_TRUE(reply_fut.is_ready());
 
  489     EXPECT_THROW(reply_fut.get(), daqif::DaqException);
 
  494     std::string keywords_with_unknown_type = R
"( 
  497               "type":"unknownKeywordHere", 
  504     EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv, _)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
 
  508     auto reply_fut = m_daq_impl->UpdateKeywords(
"id", keywords_with_unknown_type);
 
  510     ASSERT_TRUE(reply_fut.is_ready());
 
  511     EXPECT_THROW(reply_fut.get(), daqif::DaqException);
 
  516     EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv, _)).Times(Between(0, 1)).WillRepeatedly(Return(
false));
 
  517     EXPECT_CALL(m_mgr_mock, GetStatus(
"id"sv))
 
  518         .Times(Between(0, 1))
 
  519         .WillOnce(Throw(std::invalid_argument(
"no such id")));
 
  522     auto reply_fut = m_daq_impl->GetStatus(
"id");
 
  523     EXPECT_FALSE(reply_fut.is_ready())
 
  524         << 
"future cannot be ready since implementation should use provided executor to provide " 
  527     ASSERT_TRUE(reply_fut.is_ready());
 
  528     EXPECT_THROW(reply_fut.get(), daqif::DaqException);
 
  536     EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv, _)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
 
  537     EXPECT_CALL(m_mgr_mock, GetStatus(
"id"sv)).Times(Between(0, 1)).WillOnce(Return(status));
 
  538     EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_, 
"daqif_DaqStatus"))
 
  539         .WillOnce(Return(fake_reply))
 
  540         .RetiresOnSaturation();
 
  543     auto reply_fut = m_daq_impl->GetStatus(
"id");
 
  544     EXPECT_FALSE(reply_fut.is_ready())
 
  545         << 
"future cannot be ready since implementation should use provided executor to provide " 
  548     ASSERT_TRUE(reply_fut.is_ready());
 
  549     std::shared_ptr<daqif::DaqStatus> reply = reply_fut.get();
 
  550     EXPECT_EQ(reply->getId(), 
"id");
 
  551     EXPECT_EQ(reply->getFileId(), 
"fileid");
 
  552     EXPECT_EQ(reply->getError(), 
false);
 
  553     EXPECT_EQ(reply->getState(), daqif::StateAcquiring);
 
  554     EXPECT_EQ(reply->getSubState(), daqif::Acquiring);
 
  559     auto status1 = std::make_shared<daq::ObservableStatus>(
"completed", 
"fileid1");
 
  560     auto status2 = std::make_shared<daq::ObservableStatus>(
"active1", 
"fileid2");
 
  561     auto status3 = std::make_shared<daq::ObservableStatus>(
"active2", 
"fileid3");
 
  562     auto status4 = std::make_shared<daq::ObservableStatus>(
"completed", 
"fileid4");
 
  564     status1->SetState(daq::State::Aborted);
 
  565     status4->SetState(daq::State::Aborted);
 
  567     auto daq1 = std::make_shared<DaqControllerFake>(status1);
 
  568     auto daq2 = std::make_shared<DaqControllerFake>(status2);
 
  569     auto daq3 = std::make_shared<DaqControllerFake>(status3);
 
  570     auto daq4 = std::make_shared<DaqControllerFake>(status4);
 
  571     std::vector<std::shared_ptr<daq::DaqController const>> daqs;
 
  572     daqs.push_back(daq1);
 
  573     daqs.push_back(daq2);
 
  574     daqs.push_back(daq3);
 
  575     daqs.push_back(daq4);
 
  580     EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_, 
"daqif_DaqStatus"))
 
  581         .WillOnce(Return(st1))
 
  582         .WillOnce(Return(st2))
 
  583         .RetiresOnSaturation();
 
  585     EXPECT_CALL(m_mgr_mock, GetDaqControllers()).WillOnce(Return(daqs));
 
  588     auto reply_fut = m_daq_impl->GetActiveList();
 
  590     ASSERT_TRUE(reply_fut.is_ready());
 
  591     auto reply = reply_fut.get();
 
  592     EXPECT_EQ(reply.size(), 2u);
 
  593     EXPECT_EQ(reply[0]->getId(), 
"active1");
 
  594     EXPECT_EQ(reply[1]->getId(), 
"active2");
 
  603         auto fut = m_daq_impl->AwaitDaqState(
"id", daqif::StateAcquiring, daqif::Acquiring, 0.0);
 
  605         ASSERT_TRUE(fut.is_ready());
 
  606         EXPECT_THROW(fut.get(), daqif::DaqException);
 
  611         auto fut = m_daq_impl->AwaitDaqState(
"id", daqif::StateMerging, daqif::Acquiring, 1.0);
 
  613         ASSERT_TRUE(fut.is_ready());
 
  614         EXPECT_THROW(fut.get(), daqif::DaqException);
 
  621     status.
state = daq::State::Acquiring;
 
  623     boost::promise<daq::Result<daq::Status>> promise;
 
  624     EXPECT_CALL(m_mgr_mock, AwaitDaqStateAsync(
"id"sv, daq::State::Acquiring, 1000ms))
 
  625         .WillOnce(Return(ByMove(promise.get_future())));
 
  629     EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_, 
"daqif_AwaitDaqReply"))
 
  630         .WillOnce(Return(reply))
 
  631         .RetiresOnSaturation();
 
  634     auto fut = m_daq_impl->AwaitDaqState(
"id", daqif::StateAcquiring, daqif::Acquiring, 1.0);
 
  635     ASSERT_FALSE(fut.is_ready());
 
  636     promise.set_value({
false, status});
 
  639         auto val = fut.get();
 
  640         EXPECT_FALSE(val->getTimeout());
 
  641         auto status = val->getStatus();
 
  642         EXPECT_EQ(status->getId(), 
"id");
 
  643         EXPECT_EQ(status->getError(), 
false);
 
  644         EXPECT_EQ(status->getState(), daqif::StateAcquiring);
 
  645         EXPECT_EQ(status->getSubState(), daqif::Acquiring);
 
  653     boost::promise<daq::State> mgr_promise;
 
  654     EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv, _)).WillOnce(Return(
false));
 
  655     EXPECT_CALL(m_mgr_mock, MakeDaqId(_)).WillOnce(Return(
"fileid"));
 
  656     EXPECT_CALL(m_mgr_mock, StartDaqAsync(_)).WillOnce(Return(ByMove(mgr_promise.get_future())));
 
  659     auto reply_fut = m_daq_impl->StartDaq(
"id", 
"prefix", m_prim_sources, m_metadata_sources, 
"");
 
  664     mgr_promise.set_value(daq::State::Acquiring);
 
  668     ASSERT_TRUE(reply_fut.is_ready());
 
  669     EXPECT_THROW(reply_fut.get(), daqif::DaqException);
 
  676     boost::promise<daq::Status> mgr_promise;
 
  679     EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv, _)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
 
  680     EXPECT_CALL(m_mgr_mock, StopDaqAsync(
"id"sv, daq::ErrorPolicy::Strict))
 
  681         .WillOnce(Return(ByMove(mgr_promise.get_future())));
 
  684     auto reply_fut = m_daq_impl->StopDaq(
"id");
 
  689     mgr_promise.set_value(
 
  694     ASSERT_TRUE(reply_fut.is_ready());
 
  695     EXPECT_THROW(reply_fut.get(), daqif::DaqException);
 
  702     boost::promise<daq::Status> mgr_promise;
 
  705     reply_status.state = daq::State::Aborted;
 
  708     EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv, _)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
 
  709     EXPECT_CALL(m_mgr_mock, AbortDaqAsync(
"id"sv, daq::ErrorPolicy::Strict))
 
  710         .WillOnce(Return(ByMove(mgr_promise.get_future())));
 
  713     auto reply_fut = m_daq_impl->AbortDaq(
"id");
 
  718     mgr_promise.set_value(reply_status);
 
  722     ASSERT_TRUE(reply_fut.is_ready());
 
  723     EXPECT_THROW(reply_fut.get(), daqif::DaqException);