LCOV - code coverage report
Current view: top level - utilities/unittest - TimestampEstimatorSystem_test.cxx (source / functions) Coverage Total Hit
Test: code.result Lines: 96.6 % 59 57
Test Date: 2025-12-21 13:07:08 Functions: 85.7 % 7 6

            Line data    Source code
       1              : /**
       2              :  * @file TimestampEstimatorSystem_test.cxx  TimestampEstimatorSystem class Unit Tests
       3              :  *
       4              :  * This is part of the DUNE DAQ Application Framework, copyright 2020.
       5              :  * Licensing/copyright details are in the COPYING file that you should have
       6              :  * received with this code.
       7              :  */
       8              : 
       9              : #include "utilities/TimestampEstimatorSystem.hpp"
      10              : 
      11              : /**
      12              :  * @brief Name of this test module
      13              :  */
      14              : #define BOOST_TEST_MODULE TimestampEstimatorSystem_test // NOLINT
      15              : 
      16              : #include "boost/test/unit_test.hpp"
      17              : #include <boost/test/tools/old/interface.hpp>
      18              : #include <chrono>
      19              : #include <future>
      20              : 
      21              : using namespace dunedaq;
      22              : 
      23              : BOOST_AUTO_TEST_SUITE(BOOST_TEST_MODULE)
      24              : 
      25            2 : BOOST_AUTO_TEST_CASE(Basics)
      26              : {
      27            1 :   const uint64_t clock_frequency_hz = 62'500'000; // NOLINT(build/unsigned)
      28            1 :   std::atomic<bool> continue_flag{ true };
      29            1 :   dunedaq::utilities::TimestampEstimatorSystem tes(clock_frequency_hz);
      30              : 
      31            1 :   BOOST_CHECK_EQUAL(tes.wait_for_valid_timestamp(continue_flag), dunedaq::utilities::TimestampEstimatorBase::kFinished);
      32              : 
      33            1 :   std::atomic<bool> do_not_continue_flag{ false };
      34            1 :   BOOST_CHECK_EQUAL(tes.wait_for_valid_timestamp(do_not_continue_flag),
      35              :                     dunedaq::utilities::TimestampEstimatorBase::kFinished);
      36              : 
      37            1 :   auto ts_now = tes.get_timestamp_estimate();
      38            1 :   BOOST_CHECK_EQUAL(tes.wait_for_requested_timestamp(ts_now + clock_frequency_hz, continue_flag),
      39              :                     dunedaq::utilities::TimestampEstimatorBase::kFinished);
      40              : 
      41            1 :   ts_now = tes.get_timestamp_estimate();
      42            1 :   BOOST_CHECK_EQUAL(tes.wait_for_requested_timestamp(ts_now + clock_frequency_hz, do_not_continue_flag),
      43              :                     dunedaq::utilities::TimestampEstimatorBase::kInterrupted);
      44              : 
      45              :   // Check that the timestamp doesn't go backwards
      46            1 :   auto ts1 = tes.get_timestamp_estimate();
      47            1 :   auto ts2 = tes.get_timestamp_estimate();
      48            1 :   BOOST_CHECK_GE(ts2, ts1);
      49            1 : }
      50              : 
      51              : // 27-May-2025, KAB: this test case is intended to verify that an instance of
      52              : // the TimestampEstimatorSystem behaves as expected when it first starts up.
      53            2 : BOOST_AUTO_TEST_CASE(StartupBehavior)
      54              : {
      55            1 :   using namespace std::chrono;
      56            1 :   using namespace std::chrono_literals;
      57              : 
      58            1 :   const uint64_t clock_frequency_hz = 62'500'000; // NOLINT(build/unsigned)
      59            1 :   const double clock_frequency_Mhz = 62.5;
      60              : 
      61            1 :   utilities::TimestampEstimatorSystem te(clock_frequency_hz);
      62              : 
      63            1 :   auto system_time_start =
      64            1 :     static_cast<uint64_t>(duration_cast<microseconds>(system_clock::now().time_since_epoch()).count()); // NOLINT
      65            1 :   auto steady_time_start =
      66            1 :     static_cast<uint64_t>(duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count()); // NOLINT
      67            1 :   auto daq_time_start =
      68            1 :     static_cast<uint64_t>((clock_frequency_Mhz) * static_cast<double>(system_time_start)); // NOLINT(build/unsigned)
      69              : 
      70            1 :   std::atomic<bool> do_not_continue_flag{ false };
      71            1 :   std::atomic<bool> do_continue_flag{ true };
      72            1 :   std::atomic<bool> continue_flag_for_thread{ true };
      73            1 :   std::atomic<bool> thread_has_finished{ false };
      74            1 :   std::atomic<utilities::TimestampEstimatorBase::WaitStatus> return_code_from_thread_wait{
      75              :     dunedaq::utilities::TimestampEstimatorBase::kInterrupted
      76              :   };
      77              : 
      78              :   // spawn a thread that waits until the TSE can provide a valid timestamp
      79            3 :   std::function<void()> valid_timestamp_wait_func = [&]() {
      80            1 :     return_code_from_thread_wait = te.wait_for_valid_timestamp(continue_flag_for_thread);
      81            1 :     thread_has_finished = true;
      82            2 :   };
      83            1 :   auto wait_ftr = std::async(std::launch::async, valid_timestamp_wait_func);
      84              : 
      85              :   // TimestampEstimatorSystem always provides valid timestamps
      86            1 :   std::this_thread::sleep_for(100ms);
      87            1 :   BOOST_CHECK_EQUAL(thread_has_finished, true);
      88              : 
      89              :   // TimestampEstimatorSystem always should return kFinished
      90            1 :   BOOST_CHECK_EQUAL(te.wait_for_valid_timestamp(do_not_continue_flag),
      91              :                     dunedaq::utilities::TimestampEstimatorBase::kFinished);
      92            1 :   BOOST_CHECK_EQUAL(thread_has_finished, true);
      93              : 
      94              :   // verify that the wait thread has finished and it received the expected return code
      95            1 :   BOOST_CHECK_EQUAL(thread_has_finished, true);
      96            1 :   BOOST_CHECK_EQUAL(return_code_from_thread_wait, dunedaq::utilities::TimestampEstimatorBase::kFinished);
      97              :   // if the thread has not finished, tell it to finish now
      98            1 :   if (!thread_has_finished) {
      99            0 :     continue_flag_for_thread.store(false);
     100              :   }
     101              : 
     102              :   // verify that the TSE instance provides valid timestamps and those
     103              :   // timestamp track closely to wallclock time (computer system time)
     104           11 :   for (size_t i = 0; i < 10; ++i) {
     105              : 
     106           10 :     std::this_thread::sleep_for(100ms);
     107           10 :     auto steady_now =
     108           10 :       static_cast<uint64_t>(duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count()); // NOLINT
     109           10 :     uint64_t te_now = te.get_timestamp_estimate(); // NOLINT(build/unsigned)
     110           10 :     auto steady_diff = static_cast<int64_t>(steady_now - steady_time_start);
     111           10 :     auto te_diff = static_cast<int64_t>(te_now - daq_time_start);
     112           10 :     auto dd = static_cast<int64_t>(te_diff - (steady_diff * clock_frequency_hz / 1'000'000));
     113              : 
     114           10 :     BOOST_CHECK_LT(abs(dd), 1'000);
     115              :   }
     116              : 
     117              :   // now the TSE instance "wait" method should return immediately with a status
     118              :   // that indicates that it *does* have a valid timestamp, independent of whether
     119              :   // we tell it to wait for a valid timestamp or not
     120            1 :   BOOST_CHECK_EQUAL(te.wait_for_valid_timestamp(do_not_continue_flag),
     121              :                     dunedaq::utilities::TimestampEstimatorBase::kFinished);
     122            1 :   BOOST_CHECK_EQUAL(te.wait_for_valid_timestamp(do_continue_flag),
     123              :                     dunedaq::utilities::TimestampEstimatorBase::kFinished);
     124            1 : }
     125              : 
     126            1 : BOOST_AUTO_TEST_CASE(AdditionalTestIdeas)
     127              : {
     128              :   // slow clock
     129              :   // fast clock
     130              :   // non-standard clock frequency
     131              :   // bursts and delays
     132            0 : }
     133              : 
     134              : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1