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()
|