10 #include <fmt/format.h>
11 #include <gtest/gtest.h>
22 using namespace ::testing;
23 using namespace std::literals;
38 , m_daq_impl(std::make_shared<
OcmDaqService>(m_io_ctx, m_mal_mock, m_mgr_mock,
"/tmp")) {
41 m_metadata_sources =
"meta@zpb.rr://uri";
42 m_prim_sources =
"prim@zpb.rr://uri";
43 m_daq_properties = R
"(
52 "type": "valueKeyword",
80 TEST(TestParseSingleSource, Successful) {
85 EXPECT_EQ(expected, parsed);
88 TEST(TestParseSingleSource, LeadingOrTrailingSpacesAreAllowed) {
101 TEST(TestParseSingleSource, Incomplete) {
105 std::invalid_argument);
108 std::invalid_argument);
109 EXPECT_THROW(
ParseSourceUri(fmt::format(
"@,")), std::invalid_argument);
111 std::invalid_argument);
113 std::invalid_argument);
116 TEST(TestParseMultipleSources, Successful) {
119 std::vector<ParsedSource> result{expected1, expected2};
142 TEST(TestParseSingleSource, Empty) {
145 std::invalid_argument);
147 std::invalid_argument);
149 std::invalid_argument);
152 TEST(TestParseDaqProperties, Successful) {
153 auto max_err_ms = 0.001;
155 auto properties_str = R
"(
159 "type": "esoKeyword",
164 "type": "valueKeyword",
173 EXPECT_THAT(
static_cast<double>(properties.await_interval.count()),
174 DoubleNear(100, max_err_ms));
177 auto properties_str = R
"(
183 EXPECT_THAT(
static_cast<double>(properties.await_interval.count()),
184 DoubleNear(1000, max_err_ms));
189 TEST(TestParseDaqProperties, Failures) {
191 std::invalid_argument);
193 std::invalid_argument);
199 EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv)).WillOnce(Return(
true));
202 auto fut = m_daq_impl->StartDaq(
"id",
"prefix", m_prim_sources, m_metadata_sources,
"");
204 ASSERT_TRUE(fut.is_ready()) <<
"future should be ready by now since daq with id already exist";
205 EXPECT_THROW(fut.get(), ocmif::DaqException);
214 EXPECT_CALL(m_mgr_mock, MakeDaqId()).WillOnce(Return(
"id"));
216 EXPECT_CALL(m_mgr_mock, StartDaqAsync(
"id"sv))
217 .WillOnce(Return(ByMove(boost::make_ready_future<daq::State>(daq::State::Acquiring))));
218 EXPECT_CALL(m_mal_mock, getClientUnsafe(_,
"metadaqif_MetaDaqAsync", _, _, _)).WillOnce(Return(mock_metadaq_client));
219 EXPECT_CALL(m_mal_mock, getClientUnsafe(_,
"recif_RecCmdsAsync", _, _, _)).WillOnce(Return(mock_recif_client));
221 EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_,
"ocmif_DaqReply"))
222 .WillOnce(Return(fake_reply))
223 .RetiresOnSaturation();
226 auto fut = m_daq_impl->StartDaq(
"",
"prefix", m_prim_sources, m_metadata_sources,
"");
230 ASSERT_TRUE(fut.is_ready()) <<
"future should be ready immediately since we faked a "
231 "synchronous start with make_ready_future";
232 EXPECT_TRUE(fut.has_value());
233 auto reply = fut.get();
235 EXPECT_EQ(reply->getId(),
"id");
243 auto fut = m_daq_impl->StartDaq(
"id",
"prefix",
"", m_metadata_sources,
"INVALID JSON");
245 ASSERT_TRUE(fut.is_ready()) <<
"future should be ready by now since daq with id already exist";
246 EXPECT_THROW(fut.get(), ocmif::DaqException);
254 auto fut = m_daq_impl->StartDaq(
"id",
"prefix",
"", m_metadata_sources,
"[]");
256 ASSERT_TRUE(fut.is_ready()) <<
"future should be ready by now since daq with id already exist";
257 EXPECT_THROW(fut.get(), ocmif::DaqException);
265 EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv)).WillOnce(Return(
false));
267 EXPECT_CALL(m_mgr_mock, StartDaqAsync(
"id"sv))
268 .WillOnce(Return(ByMove(boost::make_ready_future<daq::State>(daq::State::Acquiring))));
269 EXPECT_CALL(m_mal_mock, getClientUnsafe(_, _, _, _, _)).WillOnce(Return(mock_metadaq_client));
271 EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_,
"ocmif_DaqReply"))
272 .WillOnce(Return(fake_reply))
273 .RetiresOnSaturation();
276 auto fut = m_daq_impl->StartDaq(
"id",
"prefix",
"", m_metadata_sources, m_daq_properties);
281 ASSERT_TRUE(fut.is_ready()) <<
"future should be ready immediately since we faked a "
282 "synchronous start with make_ready_future";
283 EXPECT_TRUE(fut.has_value());
284 auto reply = fut.get();
286 EXPECT_EQ(reply->getId(),
"id");
293 EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv)).WillOnce(Return(
false));
295 .WillOnce(Throw(std::runtime_error(
"error")));
296 EXPECT_CALL(m_mgr_mock, StartDaqAsync(_)).Times(0);
297 EXPECT_CALL(m_mal_mock, getClientUnsafe(_, _, _, _, _)).WillOnce(Return(mock_metadaq_client));
300 auto fut = m_daq_impl->StartDaq(
"id",
"prefix",
"", m_metadata_sources,
"");
302 ASSERT_TRUE(fut.is_ready()) <<
"future should be ready immediately since we faked a "
303 "synchronous start with make_ready_future";
304 EXPECT_THROW(fut.get(), ocmif::DaqException)
305 <<
"future should have contained the ICD exception type";
312 EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv)).WillOnce(Return(
false));
314 EXPECT_CALL(m_mgr_mock, StartDaqAsync(
"id"sv))
315 .WillOnce(Return(ByMove(boost::make_exceptional_future<daq::State>(
317 EXPECT_CALL(m_mal_mock, getClientUnsafe(_, _, _, _, _)).WillOnce(Return(mock_metadaq_client));
320 auto fut = m_daq_impl->StartDaq(
"id",
"prefix",
"", m_metadata_sources,
"");
322 ASSERT_TRUE(fut.is_ready())
323 <<
"future should be ready now since we faked a synchronous start with make_ready_future";
324 EXPECT_THROW(fut.get(), ocmif::DaqException)
325 <<
"future should have contained the ICD exception type";
331 EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv)).Times(Between(0, 1)).WillRepeatedly(Return(
false));
333 EXPECT_CALL(m_mgr_mock, StopDaqAsync(
"id"sv, daq::ErrorPolicy::Strict))
334 .Times(Between(0, 1))
335 .WillOnce(Return(ByMove(
336 boost::make_exceptional_future<daq::Status>(std::invalid_argument(
"no such id")))));
339 auto reply_fut = m_daq_impl->StopDaq(
"id");
341 ASSERT_TRUE(reply_fut.is_ready());
342 EXPECT_THROW(reply_fut.get(), ocmif::DaqException);
351 EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
352 EXPECT_CALL(m_mgr_mock, StopDaqAsync(
"id"sv, daq::ErrorPolicy::Strict))
353 .WillOnce(Return(ByMove(boost::make_ready_future<daq::Status>(status))));
354 EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_,
"ocmif_DaqReply"))
355 .WillOnce(Return(fake_reply))
356 .RetiresOnSaturation();
359 auto reply_fut = m_daq_impl->StopDaq(
"id");
361 ASSERT_TRUE(reply_fut.is_ready());
362 std::shared_ptr<ocmif::DaqReply> reply = reply_fut.get();
363 EXPECT_EQ(reply->getId(),
"id");
372 EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
374 .WillOnce(Return(ByMove(boost::make_ready_future<daq::Status>(status))));
375 EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_,
"ocmif_DaqReply"))
376 .WillOnce(Return(fake_reply))
377 .RetiresOnSaturation();
380 auto reply_fut = m_daq_impl->ForceStopDaq(
"id");
382 ASSERT_TRUE(reply_fut.is_ready());
383 std::shared_ptr<ocmif::DaqReply> reply = reply_fut.get();
384 EXPECT_EQ(reply->getId(),
"id");
391 EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv)).Times(Between(0, 1)).WillRepeatedly(Return(
false));
392 EXPECT_CALL(m_mgr_mock, AbortDaqAsync(
"id"sv, daq::ErrorPolicy::Strict))
393 .Times(Between(0, 1))
394 .WillOnce(Return(ByMove(
395 boost::make_exceptional_future<daq::Status>(std::invalid_argument(
"no such id")))));
398 auto reply_fut = m_daq_impl->AbortDaq(
"id");
400 ASSERT_TRUE(reply_fut.is_ready());
401 EXPECT_THROW(reply_fut.get(), ocmif::DaqException);
412 EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
413 EXPECT_CALL(m_mgr_mock, AbortDaqAsync(
"id"sv, daq::ErrorPolicy::Strict))
414 .WillOnce(Return(ByMove(boost::make_ready_future<daq::Status>(reply_status))));
415 EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_,
"ocmif_DaqReply"))
416 .WillOnce(Return(fake_reply))
417 .RetiresOnSaturation();
420 auto reply_fut = m_daq_impl->AbortDaq(
"id");
422 ASSERT_TRUE(reply_fut.is_ready());
423 std::shared_ptr<ocmif::DaqReply> reply = reply_fut.get();
424 EXPECT_EQ(reply->getId(),
"id");
434 EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
436 .WillOnce(Return(ByMove(boost::make_ready_future<daq::Status>(reply_status))));
437 EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_,
"ocmif_DaqReply"))
438 .WillOnce(Return(fake_reply))
439 .RetiresOnSaturation();
442 auto reply_fut = m_daq_impl->ForceAbortDaq(
"id");
444 ASSERT_TRUE(reply_fut.is_ready());
445 std::shared_ptr<ocmif::DaqReply> reply = reply_fut.get();
446 EXPECT_EQ(reply->getId(),
"id");
451 std::string keywords = R
"(
454 "type":"valueKeyword",
472 EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
474 EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_,
"ocmif_DaqReply"))
475 .WillOnce(Return(fake_reply))
476 .RetiresOnSaturation();
479 auto reply_fut = m_daq_impl->UpdateKeywords(
"id", keywords);
481 ASSERT_TRUE(reply_fut.is_ready());
482 std::shared_ptr<ocmif::DaqReply> reply = reply_fut.get();
483 EXPECT_EQ(reply->getId(),
"id");
484 EXPECT_EQ(reply->getError(),
false);
489 std::string keywords_with_trailing_comma = R
"(
492 "type":"valueKeyword",
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_trailing_comma);
510 ASSERT_TRUE(reply_fut.is_ready());
511 EXPECT_THROW(reply_fut.get(), ocmif::DaqException);
516 std::string keywords_with_unknown_type = R
"(
519 "type":"unknownKeywordHere",
526 EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
530 auto reply_fut = m_daq_impl->UpdateKeywords(
"id", keywords_with_unknown_type);
532 ASSERT_TRUE(reply_fut.is_ready());
533 EXPECT_THROW(reply_fut.get(), ocmif::DaqException);
538 EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv)).Times(Between(0, 1)).WillRepeatedly(Return(
false));
539 EXPECT_CALL(m_mgr_mock, GetStatus(
"id"sv))
540 .Times(Between(0, 1))
541 .WillOnce(Throw(std::invalid_argument(
"no such id")));
544 auto reply_fut = m_daq_impl->GetStatus(
"id");
545 EXPECT_FALSE(reply_fut.is_ready())
546 <<
"future cannot be ready since implementation should use provided executor to provide "
549 ASSERT_TRUE(reply_fut.is_ready());
550 EXPECT_THROW(reply_fut.get(), ocmif::DaqException);
559 EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
560 EXPECT_CALL(m_mgr_mock, GetStatus(
"id"sv)).Times(Between(0, 1)).WillOnce(Return(status));
561 EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_,
"ocmif_DaqStatus"))
562 .WillOnce(Return(fake_reply))
563 .RetiresOnSaturation();
566 auto reply_fut = m_daq_impl->GetStatus(
"id");
567 EXPECT_FALSE(reply_fut.is_ready())
568 <<
"future cannot be ready since implementation should use provided executor to provide "
571 ASSERT_TRUE(reply_fut.is_ready());
572 std::shared_ptr<ocmif::DaqStatus> reply = reply_fut.get();
573 EXPECT_EQ(reply->getId(),
"id");
574 EXPECT_EQ(reply->getError(),
false);
575 EXPECT_EQ(reply->getState(), ocmif::StateAcquiring);
576 EXPECT_EQ(reply->getSubState(), ocmif::Acquiring);
581 auto status1 = std::make_shared<daq::ObservableStatus>(
"completed");
582 auto status2 = std::make_shared<daq::ObservableStatus>(
"active1");
583 auto status3 = std::make_shared<daq::ObservableStatus>(
"active2");
584 auto status4 = std::make_shared<daq::ObservableStatus>(
"completed");
589 auto daq1 = std::make_shared<DaqControllerFake>(status1);
590 auto daq2 = std::make_shared<DaqControllerFake>(status2);
591 auto daq3 = std::make_shared<DaqControllerFake>(status3);
592 auto daq4 = std::make_shared<DaqControllerFake>(status4);
593 std::vector<std::shared_ptr<daq::DaqController const>> daqs;
594 daqs.push_back(daq1);
595 daqs.push_back(daq2);
596 daqs.push_back(daq3);
597 daqs.push_back(daq4);
602 EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_,
"ocmif_DaqStatus"))
603 .WillOnce(Return(st1))
604 .WillOnce(Return(st2))
605 .RetiresOnSaturation();
607 EXPECT_CALL(m_mgr_mock, GetDaqControllers()).WillOnce(Return(daqs));
610 auto reply_fut = m_daq_impl->GetActiveList();
612 ASSERT_TRUE(reply_fut.is_ready());
613 auto reply = reply_fut.get();
614 EXPECT_EQ(reply.size(), 2u);
615 EXPECT_EQ(reply[0]->getId(),
"active1");
616 EXPECT_EQ(reply[1]->getId(),
"active2");
625 auto fut = m_daq_impl->AwaitDaqState(
"id", ocmif::StateAcquiring, ocmif::Acquiring, 0.0);
627 ASSERT_TRUE(fut.is_ready());
628 EXPECT_THROW(fut.get(), ocmif::DaqException);
633 auto fut = m_daq_impl->AwaitDaqState(
"id", ocmif::StateMerging, ocmif::Acquiring, 1.0);
635 ASSERT_TRUE(fut.is_ready());
636 EXPECT_THROW(fut.get(), ocmif::DaqException);
644 status.
state = daq::State::Acquiring;
646 boost::promise<daq::Result<daq::Status>> promise;
647 EXPECT_CALL(m_mgr_mock, AwaitDaqStateAsync(
"id"sv, daq::State::Acquiring, 1000ms))
648 .WillOnce(Return(ByMove(promise.get_future())));
652 EXPECT_CALL(m_mal_mock, getDataEntityUnsafe(_,
"ocmif_AwaitDaqReply"))
653 .WillOnce(Return(reply))
654 .RetiresOnSaturation();
657 auto fut = m_daq_impl->AwaitDaqState(
"id", ocmif::StateAcquiring, ocmif::Acquiring, 1.0);
658 ASSERT_FALSE(fut.is_ready());
659 promise.set_value({
false, status});
662 auto val = fut.get();
663 EXPECT_FALSE(val->getTimeout());
664 auto status = val->getStatus();
665 EXPECT_EQ(status->getId(),
"id");
666 EXPECT_EQ(status->getError(),
false);
667 EXPECT_EQ(status->getState(), ocmif::StateAcquiring);
668 EXPECT_EQ(status->getSubState(), ocmif::Acquiring);
676 EXPECT_CALL(m_mal_mock, getClientUnsafe(_,
"metadaqif_MetaDaqAsync", _, _, _)).WillOnce(Return(mock_metadaq_client));
678 EXPECT_CALL(m_mal_mock, getClientUnsafe(_,
"recif_RecCmdsAsync", _, _, _)).WillOnce(Return(mock_recif_client));
681 boost::promise<daq::State> mgr_promise;
682 EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv)).WillOnce(Return(
false));
684 EXPECT_CALL(m_mgr_mock, StartDaqAsync(
"id"sv))
685 .WillOnce(Return(ByMove(mgr_promise.get_future())));
688 auto reply_fut = m_daq_impl->StartDaq(
"id",
"prefix", m_prim_sources, m_metadata_sources,
"");
693 mgr_promise.set_value(daq::State::Acquiring);
697 ASSERT_TRUE(reply_fut.is_ready());
698 EXPECT_THROW(reply_fut.get(), ocmif::DaqException);
705 boost::promise<daq::Status> mgr_promise;
708 EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
709 EXPECT_CALL(m_mgr_mock, StopDaqAsync(
"id"sv, daq::ErrorPolicy::Strict))
710 .WillOnce(Return(ByMove(mgr_promise.get_future())));
713 auto reply_fut = m_daq_impl->StopDaq(
"id");
718 mgr_promise.set_value(
723 ASSERT_TRUE(reply_fut.is_ready());
724 EXPECT_THROW(reply_fut.get(), ocmif::DaqException);
731 boost::promise<daq::Status> mgr_promise;
737 EXPECT_CALL(m_mgr_mock, HaveDaq(
"id"sv)).Times(Between(0, 1)).WillRepeatedly(Return(
true));
738 EXPECT_CALL(m_mgr_mock, AbortDaqAsync(
"id"sv, daq::ErrorPolicy::Strict))
739 .WillOnce(Return(ByMove(mgr_promise.get_future())));
742 auto reply_fut = m_daq_impl->AbortDaq(
"id");
747 mgr_promise.set_value(reply_status);
751 ASSERT_TRUE(reply_fut.is_ready());
752 EXPECT_THROW(reply_fut.get(), ocmif::DaqException);