LCOV - code coverage report
Current view: top level - dfmodules/unittest - TriggerRecordBuilderData_test.cxx (source / functions) Coverage Total Hit
Test: code.result Lines: 100.0 % 120 120
Test Date: 2025-12-21 13:07:08 Functions: 100.0 % 12 12

            Line data    Source code
       1              : /**
       2              :  * @file TriggerRecordBuilderData_test.cxx Test application that tests and demonstrates
       3              :  * the functionality of the TriggerRecordBuilderData class.
       4              :  *
       5              :  * This is part of the DUNE DAQ Application Framework, copyright 2020.
       6              :  * Licensing/copyright details are in the COPYING file that you should have
       7              :  * received with this code.
       8              :  */
       9              : 
      10              : #include "opmonlib/TestOpMonManager.hpp"
      11              : #include "dfmodules/TriggerRecordBuilderData.hpp"
      12              : 
      13              : #define BOOST_TEST_MODULE TriggerRecordBuilderData_test // NOLINT
      14              : 
      15              : #include "boost/test/unit_test.hpp"
      16              : 
      17              : #include <chrono>
      18              : #include <thread>
      19              : #include <utility>
      20              : 
      21              : using namespace dunedaq::dfmodules;
      22              : 
      23              : BOOST_AUTO_TEST_SUITE(TriggerRecordBuilderData_Test)
      24              : 
      25            2 : BOOST_AUTO_TEST_CASE(CopyAndMoveSemantics)
      26              : {
      27            1 :   BOOST_REQUIRE(!std::is_copy_constructible_v<TriggerRecordBuilderData>);
      28            1 :   BOOST_REQUIRE(!std::is_copy_assignable_v<TriggerRecordBuilderData>);
      29            1 :   BOOST_REQUIRE(!std::is_move_constructible_v<TriggerRecordBuilderData>);
      30            1 :   BOOST_REQUIRE(!std::is_move_assignable_v<TriggerRecordBuilderData>);
      31            1 : }
      32              : 
      33            2 : BOOST_AUTO_TEST_CASE(Constructors)
      34              : {
      35            1 :   dunedaq::dfmessages::TriggerDecision td;
      36            1 :   td.trigger_number = 1;
      37            1 :   td.run_number = 2;
      38            1 :   td.trigger_timestamp = 3;
      39            1 :   td.trigger_type = 4;
      40            1 :   td.readout_type = dunedaq::dfmessages::ReadoutType::kLocalized;
      41              : 
      42            1 :   AssignedTriggerDecision atd(td, "test");
      43              : 
      44            1 :   BOOST_REQUIRE_EQUAL(atd.decision.trigger_number, td.trigger_number);
      45            1 :   BOOST_REQUIRE_EQUAL(atd.connection_name, "test");
      46              : 
      47              :   // TRBD must have a default constructor so that it can be used in a std::map, but a default-constructed TRBD is
      48              :   // invalid.
      49            1 :   TriggerRecordBuilderData trbd;
      50            1 :   BOOST_REQUIRE(trbd.is_in_error());
      51              : 
      52            1 :   TriggerRecordBuilderData trbd2("test", 10);
      53              : 
      54            1 :   BOOST_REQUIRE_EQUAL(trbd2.used_slots(), 0);
      55            1 :   BOOST_REQUIRE_EQUAL(trbd2.is_busy(), false);
      56            1 :   BOOST_REQUIRE(!trbd2.is_in_error());
      57              : 
      58            1 :   trbd2.set_in_error(true);
      59            1 :   BOOST_REQUIRE(trbd2.is_in_error());
      60            1 :   BOOST_REQUIRE_EQUAL(trbd2.is_busy(), true);
      61              : 
      62            1 :   trbd2.set_in_error(false);
      63            1 :   BOOST_REQUIRE_EQUAL(trbd2.used_slots(), 0);
      64            1 :   BOOST_REQUIRE_EQUAL(trbd2.is_busy(), false);
      65            1 :   BOOST_REQUIRE(!trbd2.is_in_error());
      66              : 
      67            4 :   BOOST_REQUIRE_EXCEPTION(TriggerRecordBuilderData("test", 10, 15),
      68              :                           DFOThresholdsNotConsistent,
      69              :                           [](DFOThresholdsNotConsistent const&) { return true; });
      70            1 : }
      71              : 
      72            2 : BOOST_AUTO_TEST_CASE(Assignments)
      73              : {
      74            1 :   auto start_time = std::chrono::steady_clock::now();
      75            1 :   dunedaq::dfmessages::TriggerDecision td;
      76            1 :   td.trigger_number = 1;
      77            1 :   td.run_number = 2;
      78            1 :   td.trigger_timestamp = 3;
      79            1 :   td.trigger_type = 4;
      80            1 :   td.readout_type = dunedaq::dfmessages::ReadoutType::kLocalized;
      81              : 
      82            1 :   dunedaq::opmonlib::TestOpMonManager opmgr;
      83            1 :   auto trbd_p = std::make_shared<TriggerRecordBuilderData>("test", 2);
      84            1 :   opmgr.register_node("trbd", trbd_p);
      85            1 :   BOOST_REQUIRE_EQUAL(trbd_p->used_slots(), 0);
      86            1 :   BOOST_REQUIRE(!trbd_p->is_busy());
      87              : 
      88            1 :   auto assignment = trbd_p->make_assignment(td);
      89            1 :   BOOST_REQUIRE_EQUAL(assignment->connection_name, "test");
      90            1 :   trbd_p->add_assignment(assignment);
      91              : 
      92            1 :   BOOST_REQUIRE_EQUAL(trbd_p->used_slots(), 1);
      93            1 :   auto got_assignment = trbd_p->get_assignment(1);
      94            1 :   BOOST_REQUIRE_EQUAL(got_assignment->decision.trigger_number, assignment->decision.trigger_number);
      95            1 :   BOOST_REQUIRE_EQUAL(got_assignment->decision.trigger_timestamp, assignment->decision.trigger_timestamp);
      96            1 :   BOOST_REQUIRE_EQUAL(got_assignment.get(), assignment.get());
      97            1 :   BOOST_REQUIRE_EQUAL(trbd_p->used_slots(), 1);
      98              : 
      99            1 :   auto extracted_assignment = trbd_p->extract_assignment(1);
     100            1 :   BOOST_REQUIRE_EQUAL(extracted_assignment.get(), assignment.get());
     101            1 :   BOOST_REQUIRE_EQUAL(trbd_p->used_slots(), 0);
     102            1 :   trbd_p->add_assignment(extracted_assignment);
     103            1 :   BOOST_REQUIRE_EQUAL(trbd_p->used_slots(), 1);
     104              : 
     105            1 :   std::this_thread::sleep_for(std::chrono::milliseconds(50));
     106              : 
     107            1 :   std::chrono::steady_clock::time_point complete_time;
     108            1 :   trbd_p->complete_assignment(1,
     109            2 :                               [&complete_time](nlohmann::json&) { complete_time = std::chrono::steady_clock::now(); });
     110            1 :   BOOST_REQUIRE_EQUAL(trbd_p->used_slots(), 0);
     111              : 
     112            1 :   auto latency =
     113            1 :     std::chrono::duration_cast<std::chrono::microseconds>(complete_time - assignment->assigned_time)
     114            1 :       .count();
     115              : 
     116            1 :   BOOST_REQUIRE_CLOSE(static_cast<double>(trbd_p->average_latency(start_time).count()), static_cast<double>(latency), 5);
     117              : 
     118            1 :   auto null_got_assignment = trbd_p->get_assignment(2);
     119            1 :   BOOST_REQUIRE_EQUAL(null_got_assignment, nullptr);
     120            1 :   auto null_extracted_assignment = trbd_p->extract_assignment(3);
     121            1 :   BOOST_REQUIRE_EQUAL(null_extracted_assignment, nullptr);
     122              : 
     123            1 :   trbd_p->add_assignment(assignment);
     124            1 :   BOOST_REQUIRE_EQUAL(trbd_p->used_slots(), 1);
     125            1 :   auto remnants = trbd_p->flush();
     126            1 :   BOOST_REQUIRE_EQUAL(trbd_p->used_slots(), 0);
     127            1 :   BOOST_REQUIRE_EQUAL(remnants.size(), 1);
     128              :   
     129            1 : }
     130              : 
     131            2 : BOOST_AUTO_TEST_CASE(Exceptions)
     132              : {
     133            1 :   dunedaq::dfmessages::TriggerDecision td;
     134            1 :   td.trigger_number = 1;
     135            1 :   td.run_number = 2;
     136            1 :   td.trigger_timestamp = 3;
     137            1 :   td.trigger_type = 4;
     138            1 :   td.readout_type = dunedaq::dfmessages::ReadoutType::kLocalized;
     139            1 :   dunedaq::dfmessages::TriggerDecision another_td;
     140            1 :   another_td.trigger_number = 2;
     141            1 :   another_td.run_number = 2;
     142            1 :   another_td.trigger_timestamp = 5;
     143            1 :   another_td.trigger_type = 4;
     144            1 :   another_td.readout_type = dunedaq::dfmessages::ReadoutType::kLocalized;
     145            1 :   dunedaq::dfmessages::TriggerDecision yet_another_td;
     146            1 :   yet_another_td.trigger_number = 3;
     147            1 :   yet_another_td.run_number = 2;
     148            1 :   yet_another_td.trigger_timestamp = 7;
     149            1 :   yet_another_td.trigger_type = 4;
     150            1 :   yet_another_td.readout_type = dunedaq::dfmessages::ReadoutType::kLocalized;
     151              : 
     152            1 :   TriggerRecordBuilderData trbd("test", 2);
     153            1 :   BOOST_REQUIRE_EQUAL(trbd.used_slots(), 0);
     154            1 :   BOOST_REQUIRE(!trbd.is_busy());
     155              : 
     156            1 :   auto assignment = trbd.make_assignment(td);
     157            1 :   BOOST_REQUIRE_EQUAL(assignment->connection_name, "test");
     158            1 :   trbd.add_assignment(assignment);
     159              : 
     160            1 :   auto another_assignment = trbd.make_assignment(another_td);
     161            1 :   trbd.add_assignment(another_assignment);
     162              : 
     163            1 :   BOOST_REQUIRE_EQUAL(trbd.used_slots(), 2);
     164            1 :   BOOST_REQUIRE(trbd.is_busy());
     165              : 
     166            4 :   BOOST_REQUIRE_EXCEPTION(trbd.complete_assignment(3),
     167              :                           AssignedTriggerDecisionNotFound,
     168              :                           [](AssignedTriggerDecisionNotFound const&) { return true; });
     169              : 
     170            1 :   auto yet_another_assignment = trbd.make_assignment(yet_another_td);
     171            1 :   BOOST_CHECK_NO_THROW(trbd.add_assignment(yet_another_assignment));
     172              :   // we are now above threshold but we can accept new assigments anyway because we are not in error
     173            1 :   BOOST_REQUIRE(trbd.is_busy());
     174              : 
     175            1 :   trbd.set_in_error(true);
     176            1 :   dunedaq::dfmessages::TriggerDecision err_td;
     177            1 :   err_td.trigger_number = 4;
     178            1 :   err_td.run_number = 2;
     179            1 :   err_td.trigger_timestamp = 10;
     180            1 :   err_td.trigger_type = 4;
     181            1 :   err_td.readout_type = dunedaq::dfmessages::ReadoutType::kLocalized;
     182            1 :   auto err_assignment = trbd.make_assignment(err_td);
     183              : 
     184            4 :   BOOST_REQUIRE_EXCEPTION(
     185              :     trbd.add_assignment(err_assignment), NoSlotsAvailable, [](NoSlotsAvailable const&) { return true; });
     186            1 : }
     187              : 
     188              : 
     189              : 
     190              : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1