Line data Source code
1 : /**
2 : *
3 : * @file StdDeQueue_test.cxx StdDeQueue class Unit Tests
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 "iomanager/queue/StdDeQueue.hpp"
11 :
12 : #define BOOST_TEST_MODULE StdDeQueue_test // NOLINT
13 : #include "boost/test/unit_test.hpp"
14 :
15 : #include <chrono>
16 :
17 : BOOST_AUTO_TEST_SUITE(StdDeQueue_test)
18 :
19 : namespace {
20 :
21 : constexpr int max_testable_capacity = 1'000'000'000; ///< The maximum capacity this test will attempt to check
22 :
23 : constexpr double fractional_timeout_tolerance =
24 : 0.5; ///< The fraction of the timeout which the timing is allowed to be off by
25 :
26 : /**
27 : * @brief Timeout to use for tests
28 : *
29 : * Don't set the timeout to zero, otherwise the tests will fail since they'd
30 : * expect the push/pop functions to execute instananeously
31 : */
32 : constexpr auto timeout = std::chrono::milliseconds(5);
33 : /**
34 : * @brief Timeout expressed in microseconds
35 : */
36 : constexpr auto timeout_in_us = std::chrono::duration_cast<std::chrono::microseconds>(timeout).count();
37 :
38 : } // namespace ""
39 :
40 : // This test case should run first. Make sure all other test cases depend on
41 : // this.
42 :
43 2 : BOOST_AUTO_TEST_CASE(sanity_checks)
44 : {
45 :
46 1 : dunedaq::iomanager::StdDeQueue<int> queue("StdDeQueue", 10); ///< Queue instance for the test
47 1 : BOOST_REQUIRE(!queue.can_pop());
48 :
49 1 : auto start_time = std::chrono::steady_clock::now();
50 1 : try {
51 1 : queue.push(42, timeout);
52 0 : } catch (const dunedaq::iomanager::QueueTimeoutExpired& ex) {
53 0 : BOOST_TEST_REQUIRE(false, "Test failure: unexpected timeout exception throw from push");
54 0 : } catch (...) { // NOLINT
55 0 : BOOST_TEST_REQUIRE(false, "Test failure: unexpected exception (non-timeout-related) thrown");
56 0 : }
57 :
58 1 : auto push_time = std::chrono::steady_clock::now() - start_time;
59 :
60 1 : if (push_time > timeout) {
61 0 : auto push_time_in_us = std::chrono::duration_cast<std::chrono::microseconds>(push_time).count();
62 :
63 0 : BOOST_TEST_REQUIRE(false,
64 : "Test failure: pushing element onto empty Queue "
65 : "resulted in a timeout without an exception throw (function exited after "
66 : << push_time_in_us << " microseconds, timeout is " << timeout_in_us << " microseconds)");
67 : }
68 :
69 1 : BOOST_REQUIRE(queue.can_pop());
70 :
71 1 : start_time = std::chrono::steady_clock::now();
72 1 : int popped_value = -999;
73 1 : try {
74 1 : queue.pop(popped_value, timeout);
75 0 : } catch (const dunedaq::iomanager::QueueTimeoutExpired& ex) {
76 0 : BOOST_TEST_REQUIRE(false, "Test failure: unexpected timeout exception throw from pop");
77 0 : } catch (...) { // NOLINT
78 0 : BOOST_TEST_REQUIRE(false, "Test failure: unexpected exception (non-timeout-related) thrown");
79 0 : }
80 1 : auto pop_time = std::chrono::steady_clock::now() - start_time;
81 :
82 1 : if (pop_time > timeout) {
83 0 : auto pop_time_in_us = std::chrono::duration_cast<std::chrono::microseconds>(pop_time).count();
84 0 : BOOST_TEST_REQUIRE(false,
85 : "Test failure: popping element off Queue "
86 : "resulted in a timeout without an exception throw (function exited after "
87 : << pop_time_in_us << " microseconds, timeout is " << timeout_in_us << " microseconds)");
88 : }
89 :
90 1 : BOOST_REQUIRE_EQUAL(popped_value, 42);
91 1 : }
92 :
93 2 : BOOST_AUTO_TEST_CASE(empty_checks)
94 : {
95 1 : dunedaq::iomanager::StdDeQueue<int> queue("StdDeQueue", 10); ///< Queue instance for the test
96 1 : int popped_value = -999;
97 :
98 1 : while (queue.can_pop()) {
99 :
100 0 : try {
101 0 : queue.pop(popped_value, timeout);
102 0 : } catch (const dunedaq::iomanager::QueueTimeoutExpired& ex) {
103 0 : BOOST_TEST(false,
104 : "Timeout exception thrown in call to StdDeQueue::pop(); unable "
105 : "to empty the Queue");
106 0 : break;
107 0 : }
108 : }
109 :
110 1 : BOOST_REQUIRE(!queue.can_pop());
111 :
112 : // pop off of an empty Queue
113 :
114 1 : auto starttime = std::chrono::steady_clock::now();
115 :
116 2 : BOOST_CHECK_THROW(queue.pop(popped_value, timeout), dunedaq::iomanager::QueueTimeoutExpired);
117 :
118 1 : auto pop_duration = std::chrono::steady_clock::now() - starttime;
119 :
120 1 : const double fraction_of_pop_timeout_used =
121 1 : static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(pop_duration).count()) /
122 1 : std::chrono::duration_cast<std::chrono::nanoseconds>(timeout).count();
123 :
124 1 : BOOST_TEST_MESSAGE("Attempted pop_duration divided by timeout is " << fraction_of_pop_timeout_used);
125 :
126 1 : BOOST_CHECK_GT(fraction_of_pop_timeout_used, 1 - fractional_timeout_tolerance);
127 1 : BOOST_CHECK_LT(fraction_of_pop_timeout_used, 1 + fractional_timeout_tolerance);
128 1 : }
129 :
130 : BOOST_AUTO_TEST_SUITE_END()
|