Line data Source code
1 : #define BOOST_TEST_MODULE CommandableFragmentGenerator_t
2 : #include <boost/test/unit_test.hpp>
3 :
4 : #include "TRACE/tracemf.h"
5 : #define TRACE_NAME "CommandableFragmentGenerator_t"
6 :
7 : #include "artdaq-core/Data/ContainerFragment.hh"
8 : #include "artdaq-core/Data/Fragment.hh"
9 : #include "artdaq-core/Utilities/configureMessageFacility.hh"
10 : #include "artdaq/DAQdata/Globals.hh"
11 : #include "artdaq/Generators/CommandableFragmentGenerator.hh"
12 :
13 : #define TRACE_REQUIRE_EQUAL(l, r) \
14 : do \
15 : { \
16 : if ((l) == (r)) \
17 : { \
18 : TLOG(TLVL_DEBUG) << __LINE__ << ": Checking if " << #l << " (" << (l) << ") equals " << #r << " (" << (r) << ")...YES!"; \
19 : } \
20 : else \
21 : { \
22 : TLOG(TLVL_ERROR) << __LINE__ << ": Checking if " << #l << " (" << (l) << ") equals " << #r << " (" << (r) << ")...NO!"; \
23 : } \
24 : BOOST_REQUIRE_EQUAL((l), (r)); \
25 : } while (false)
26 :
27 : #define TRACE_REQUIRE(b) \
28 : do \
29 : { \
30 : if (b) \
31 : { \
32 : TLOG(TLVL_DEBUG) << __LINE__ << ": Checking if " << #b << " (" << (b) << ") is true...YES!"; \
33 : } \
34 : else \
35 : { \
36 : TLOG(TLVL_ERROR) << __LINE__ << ": Checking if " << #b << " (" << (b) << ") is true...NO!"; \
37 : } \
38 : BOOST_REQUIRE((b)); \
39 : } while (false)
40 :
41 : namespace artdaqtest {
42 : class CommandableFragmentGeneratorTest;
43 : }
44 :
45 : /**
46 : * \brief CommandableFragmentGenerator derived class for testing
47 : */
48 : class artdaqtest::CommandableFragmentGeneratorTest : public artdaq::CommandableFragmentGenerator
49 : {
50 : public:
51 : /**
52 : * \brief CommandableFragmentGeneratorTest Constructor
53 : */
54 : explicit CommandableFragmentGeneratorTest(const fhicl::ParameterSet& ps);
55 :
56 6 : ~CommandableFragmentGeneratorTest() override { joinThreads(); };
57 :
58 : private:
59 : CommandableFragmentGeneratorTest(CommandableFragmentGeneratorTest const&) = delete;
60 : CommandableFragmentGeneratorTest(CommandableFragmentGeneratorTest&&) = delete;
61 : CommandableFragmentGeneratorTest& operator=(CommandableFragmentGeneratorTest const&) = delete;
62 : CommandableFragmentGeneratorTest& operator=(CommandableFragmentGeneratorTest&&) = delete;
63 :
64 : protected:
65 : /**
66 : * \brief Generate data and return it to CommandableFragmentGenerator
67 : * \param frags FragmentPtrs list that new Fragments should be added to
68 : * \return True if data was generated
69 : *
70 : * CommandableFragmentGeneratorTest merely default-constructs Fragments, emplacing them on the frags list.
71 : */
72 : bool getNext_(artdaq::FragmentPtrs& frags) override;
73 :
74 : /**
75 : * \brief Returns whether the hwFail flag has not been set
76 : * \return If hwFail has been set, false, otherwise true
77 : */
78 4 : bool checkHWStatus_() override { return !hwFail_.load(); }
79 :
80 : /**
81 : * \brief Perform start actions. No-Op
82 : */
83 : void start() override;
84 :
85 : /**
86 : * \brief Perform immediate stop actions. No-Op
87 : */
88 : void stopNoMutex() override;
89 :
90 : /**
91 : * \brief Perform stop actions. No-Op
92 : */
93 : void stop() override;
94 :
95 : /**
96 : * \brief Perform pause actions. No-Op
97 : */
98 : void pause() override;
99 :
100 : /**
101 : * \brief Perform resume actions. No-Op
102 : */
103 : void resume() override;
104 :
105 : public:
106 : /**
107 : * \brief Have getNext_ generate count fragments
108 : * \param count Number of fragments to generate
109 : */
110 5 : void setFireCount(size_t count) { fireCount_ = count; }
111 :
112 : /**
113 : * \brief Set the hwFail flag
114 : */
115 2 : void setHwFail() { hwFail_ = true; }
116 :
117 : /**
118 : * \brief Set the enabled IDs mask for the Fragment Generator
119 : * \param bitmask Bitmask of enabled IDs for the Fragment Generator
120 : *
121 : * For testing, this bitmask allows a configured Fragment ID to not be generated by a given call to setFireCount.
122 : * This is used to create asymmetric response from the Fragment generator in the _MultipleIDs test cases
123 : */
124 1 : void setEnabledIds(uint64_t bitmask) { enabled_ids_ = bitmask; }
125 :
126 : /**
127 : * \brief Set the timestamp to be used for the next Fragment
128 : * \param ts Timestamp to be used for the next Fragment
129 : */
130 : void setTimestamp(artdaq::Fragment::timestamp_t ts) { ts_ = ts; }
131 :
132 : /**
133 : * \brief Get the timestamp that will be used for the next Fragment
134 : * \return The timestamp that will be used for the next Fragment
135 : */
136 : artdaq::Fragment::timestamp_t getTimestamp() { return ts_; }
137 :
138 : private:
139 : std::atomic<size_t> fireCount_;
140 : std::atomic<bool> hwFail_;
141 : artdaq::Fragment::timestamp_t ts_;
142 : std::atomic<bool> hw_stop_;
143 : std::atomic<uint64_t> enabled_ids_;
144 : };
145 :
146 6 : artdaqtest::CommandableFragmentGeneratorTest::CommandableFragmentGeneratorTest(const fhicl::ParameterSet& ps)
147 : : CommandableFragmentGenerator(ps)
148 6 : , fireCount_(1)
149 6 : , hwFail_(false)
150 6 : , ts_(0)
151 6 : , hw_stop_(false)
152 12 : , enabled_ids_(-1)
153 : {
154 24 : metricMan->initialize(ps.get<fhicl::ParameterSet>("metrics", fhicl::ParameterSet()));
155 6 : metricMan->do_start();
156 6 : }
157 :
158 10 : bool artdaqtest::CommandableFragmentGeneratorTest::getNext_(artdaq::FragmentPtrs& frags)
159 : {
160 19 : while (fireCount_ > 0)
161 : {
162 9 : ++ts_;
163 22 : for (auto& id : fragmentIDs())
164 : {
165 13 : if (id < 64 && ((enabled_ids_ & (0x1 << id)) != 0))
166 : {
167 36 : TLOG(TLVL_DEBUG) << "Adding Fragment with ID " << id << ", SeqID " << ev_counter() << ", and timestamp " << ts_;
168 12 : frags.emplace_back(new artdaq::Fragment(ev_counter(), id, artdaq::Fragment::FirstUserFragmentType, ts_));
169 : }
170 9 : }
171 9 : fireCount_--;
172 9 : ev_counter_inc();
173 : }
174 :
175 10 : return !hw_stop_;
176 : }
177 :
178 7 : void artdaqtest::CommandableFragmentGeneratorTest::start() { hw_stop_ = false; }
179 :
180 3 : void artdaqtest::CommandableFragmentGeneratorTest::stopNoMutex() {}
181 :
182 3 : void artdaqtest::CommandableFragmentGeneratorTest::stop() { hw_stop_ = true; }
183 :
184 1 : void artdaqtest::CommandableFragmentGeneratorTest::pause() {}
185 :
186 1 : void artdaqtest::CommandableFragmentGeneratorTest::resume() {}
187 :
188 : BOOST_AUTO_TEST_SUITE(CommandableFragmentGenerator_t)
189 :
190 2 : BOOST_AUTO_TEST_CASE(Simple)
191 : {
192 1 : artdaq::configureMessageFacility("CommandableFragmentGenerator_t");
193 3 : TLOG(TLVL_INFO) << "Simple test case BEGIN";
194 1 : fhicl::ParameterSet ps;
195 2 : ps.put<int>("fragment_id", 1);
196 1 : artdaqtest::CommandableFragmentGeneratorTest testGen(ps);
197 :
198 1 : testGen.StartCmd(1, 1, 1);
199 :
200 1 : artdaq::FragmentPtrs fps;
201 1 : auto sts = testGen.getNext(fps);
202 4 : TRACE_REQUIRE_EQUAL(sts, true);
203 4 : TRACE_REQUIRE_EQUAL(fps.size(), 1u);
204 4 : TRACE_REQUIRE_EQUAL(fps.front()->fragmentID(), 1);
205 4 : TRACE_REQUIRE_EQUAL(fps.front()->timestamp(), 1);
206 4 : TRACE_REQUIRE_EQUAL(fps.front()->sequenceID(), 1);
207 3 : TLOG(TLVL_INFO) << "Simple test case END";
208 1 : }
209 :
210 2 : BOOST_AUTO_TEST_CASE(WaitForStart)
211 : {
212 1 : artdaq::configureMessageFacility("CommandableFragmentGenerator_t");
213 3 : TLOG(TLVL_INFO) << "WaitForStart test case BEGIN";
214 1 : fhicl::ParameterSet ps;
215 2 : ps.put<int>("fragment_id", 1);
216 1 : artdaqtest::CommandableFragmentGeneratorTest testGen(ps);
217 :
218 1 : artdaq::FragmentPtrs fps;
219 1 : auto sts = testGen.getNext(fps);
220 4 : TRACE_REQUIRE_EQUAL(sts, false);
221 4 : TRACE_REQUIRE_EQUAL(fps.size(), 0u);
222 :
223 1 : usleep(10000);
224 1 : sts = testGen.getNext(fps);
225 4 : TRACE_REQUIRE_EQUAL(sts, false);
226 4 : TRACE_REQUIRE_EQUAL(fps.size(), 0u);
227 :
228 1 : testGen.StartCmd(2, 1, 1);
229 :
230 1 : sts = testGen.getNext(fps);
231 4 : TRACE_REQUIRE_EQUAL(sts, true);
232 4 : TRACE_REQUIRE_EQUAL(fps.size(), 1u);
233 4 : TRACE_REQUIRE_EQUAL(fps.front()->fragmentID(), 1);
234 4 : TRACE_REQUIRE_EQUAL(fps.front()->timestamp(), 1);
235 4 : TRACE_REQUIRE_EQUAL(fps.front()->sequenceID(), 1);
236 3 : TLOG(TLVL_INFO) << "WaitForStart test case END";
237 1 : }
238 :
239 2 : BOOST_AUTO_TEST_CASE(StateMachine)
240 : {
241 1 : artdaq::configureMessageFacility("CommandableFragmentGenerator_t");
242 3 : TLOG(TLVL_INFO) << "StateMachine test case BEGIN";
243 1 : fhicl::ParameterSet ps;
244 2 : ps.put<int>("fragment_id", 1);
245 1 : artdaqtest::CommandableFragmentGeneratorTest testGen(ps);
246 :
247 1 : artdaq::FragmentPtrs fps;
248 1 : auto sts = testGen.getNext(fps);
249 4 : TRACE_REQUIRE_EQUAL(sts, false);
250 4 : TRACE_REQUIRE_EQUAL(fps.size(), 0u);
251 :
252 1 : usleep(10000);
253 1 : sts = testGen.getNext(fps);
254 4 : TRACE_REQUIRE_EQUAL(sts, false);
255 4 : TRACE_REQUIRE_EQUAL(fps.size(), 0u);
256 :
257 1 : testGen.StartCmd(2, 1, 1);
258 :
259 1 : sts = testGen.getNext(fps);
260 4 : TRACE_REQUIRE_EQUAL(sts, true);
261 4 : TRACE_REQUIRE_EQUAL(fps.size(), 1u);
262 4 : TRACE_REQUIRE_EQUAL(fps.front()->fragmentID(), 1);
263 4 : TRACE_REQUIRE_EQUAL(fps.front()->timestamp(), 1);
264 4 : TRACE_REQUIRE_EQUAL(fps.front()->sequenceID(), 1);
265 1 : fps.clear();
266 :
267 1 : testGen.setFireCount(1);
268 1 : testGen.PauseCmd(1, 1);
269 1 : sts = testGen.getNext(fps);
270 4 : TRACE_REQUIRE_EQUAL(sts, false);
271 4 : TRACE_REQUIRE_EQUAL(fps.size(), 0u);
272 :
273 1 : testGen.ResumeCmd(1, 1);
274 :
275 1 : sts = testGen.getNext(fps);
276 4 : TRACE_REQUIRE_EQUAL(sts, true);
277 4 : TRACE_REQUIRE_EQUAL(fps.size(), 1u);
278 4 : TRACE_REQUIRE_EQUAL(fps.front()->fragmentID(), 1);
279 4 : TRACE_REQUIRE_EQUAL(fps.front()->timestamp(), 2);
280 4 : TRACE_REQUIRE_EQUAL(fps.front()->sequenceID(), 2);
281 1 : fps.clear();
282 :
283 1 : testGen.StopCmd(1, 1);
284 1 : sts = testGen.getNext(fps);
285 4 : TRACE_REQUIRE_EQUAL(sts, false);
286 4 : TRACE_REQUIRE_EQUAL(fps.size(), 0u);
287 :
288 1 : testGen.StartCmd(2, 1, 1);
289 1 : sts = testGen.getNext(fps);
290 4 : TRACE_REQUIRE_EQUAL(sts, true);
291 4 : TRACE_REQUIRE_EQUAL(fps.size(), 0u);
292 :
293 1 : testGen.setFireCount(1);
294 1 : sts = testGen.getNext(fps);
295 4 : TRACE_REQUIRE_EQUAL(sts, true);
296 4 : TRACE_REQUIRE_EQUAL(fps.size(), 1u);
297 4 : TRACE_REQUIRE_EQUAL(fps.front()->fragmentID(), 1);
298 4 : TRACE_REQUIRE_EQUAL(fps.front()->timestamp(), 3);
299 4 : TRACE_REQUIRE_EQUAL(fps.front()->sequenceID(), 1);
300 1 : fps.clear();
301 :
302 3 : TLOG(TLVL_INFO) << "StateMachine test case END";
303 1 : }
304 :
305 2 : BOOST_AUTO_TEST_CASE(MultipleIDs)
306 : {
307 1 : artdaq::configureMessageFacility("CommandableFragmentGenerator_t");
308 3 : TLOG(TLVL_INFO) << "MultipleIDs test case BEGIN";
309 1 : fhicl::ParameterSet ps;
310 4 : ps.put<std::vector<int>>("fragment_ids", {1, 2, 3});
311 2 : ps.put<int>("generated_fragments_per_event", 3);
312 :
313 1 : artdaqtest::CommandableFragmentGeneratorTest testGen(ps);
314 1 : testGen.StartCmd(3, 1, 1);
315 :
316 1 : artdaq::FragmentPtrs fps;
317 1 : auto sts = testGen.getNext(fps);
318 :
319 1 : std::map<artdaq::Fragment::fragment_id_t, size_t> ids;
320 4 : TRACE_REQUIRE_EQUAL(sts, true);
321 4 : TRACE_REQUIRE_EQUAL(fps.size(), 3u);
322 4 : while (fps.size() > 0)
323 : {
324 3 : ids[fps.front()->fragmentID()]++;
325 12 : TRACE_REQUIRE_EQUAL(fps.front()->timestamp(), 1);
326 12 : TRACE_REQUIRE_EQUAL(fps.front()->sequenceID(), 1);
327 3 : fps.pop_front();
328 : }
329 :
330 4 : TRACE_REQUIRE_EQUAL(ids[1], 1);
331 4 : TRACE_REQUIRE_EQUAL(ids[2], 1);
332 4 : TRACE_REQUIRE_EQUAL(ids[3], 1);
333 1 : ids.clear();
334 :
335 1 : fps.clear();
336 :
337 1 : testGen.setEnabledIds(0x6); // 0110b, ID 3 disabled
338 1 : testGen.setFireCount(1);
339 :
340 1 : sts = testGen.getNext(fps);
341 :
342 4 : TRACE_REQUIRE_EQUAL(sts, true);
343 4 : TRACE_REQUIRE_EQUAL(fps.size(), 2u);
344 3 : while (!fps.empty())
345 : {
346 2 : ids[fps.front()->fragmentID()]++;
347 8 : TRACE_REQUIRE_EQUAL(fps.front()->timestamp(), 2);
348 8 : TRACE_REQUIRE_EQUAL(fps.front()->sequenceID(), 2);
349 2 : fps.pop_front();
350 : }
351 4 : TRACE_REQUIRE_EQUAL(ids[1], 1);
352 4 : TRACE_REQUIRE_EQUAL(ids[2], 1);
353 4 : TRACE_REQUIRE_EQUAL(ids[3], 0);
354 :
355 3 : TLOG(TLVL_INFO) << "MultipleIDs test case END";
356 1 : }
357 :
358 2 : BOOST_AUTO_TEST_CASE(HardwareFailure_NonThreaded)
359 : {
360 1 : artdaq::configureMessageFacility("CommandableFragmentGenerator_t");
361 3 : TLOG(TLVL_INFO) << "HardwareFailure_NonThreaded test case BEGIN";
362 1 : fhicl::ParameterSet ps;
363 2 : ps.put<int>("fragment_id", 1);
364 2 : ps.put<bool>("separate_data_thread", false);
365 2 : ps.put<bool>("separate_monitoring_thread", false);
366 2 : ps.put<int64_t>("hardware_poll_interval_us", 10);
367 :
368 1 : auto buffer = std::make_shared<artdaq::RequestBuffer>();
369 1 : buffer->setRunning(true);
370 1 : artdaqtest::CommandableFragmentGeneratorTest gen(ps);
371 1 : gen.SetRequestBuffer(buffer);
372 1 : gen.StartCmd(4, 0xFFFFFFFF, 1);
373 :
374 1 : artdaq::FragmentPtrs fps;
375 1 : auto sts = gen.getNext(fps);
376 4 : TRACE_REQUIRE_EQUAL(sts, true);
377 4 : TRACE_REQUIRE_EQUAL(fps.size(), 1u);
378 4 : TRACE_REQUIRE_EQUAL(fps.front()->fragmentID(), 1);
379 4 : TRACE_REQUIRE_EQUAL(fps.front()->timestamp(), 1);
380 4 : TRACE_REQUIRE_EQUAL(fps.front()->sequenceID(), 1);
381 1 : fps.clear();
382 :
383 1 : gen.setFireCount(1);
384 1 : gen.setHwFail();
385 1 : usleep(10000);
386 1 : sts = gen.getNext(fps);
387 4 : TRACE_REQUIRE_EQUAL(sts, false);
388 4 : TRACE_REQUIRE(fps.empty());
389 :
390 1 : gen.StopCmd(0xFFFFFFFF, 1);
391 1 : gen.joinThreads();
392 3 : TLOG(TLVL_INFO) << "HardwareFailure_NonThreaded test case END";
393 1 : }
394 :
395 2 : BOOST_AUTO_TEST_CASE(HardwareFailure_Threaded)
396 : {
397 1 : artdaq::configureMessageFacility("CommandableFragmentGenerator_t");
398 3 : TLOG(TLVL_INFO) << "HardwareFailure_Threaded test case BEGIN";
399 1 : fhicl::ParameterSet ps;
400 2 : ps.put<int>("fragment_id", 1);
401 2 : ps.put<bool>("separate_monitoring_thread", true);
402 2 : ps.put<int64_t>("hardware_poll_interval_us", 750000);
403 :
404 1 : auto buffer = std::make_shared<artdaq::RequestBuffer>();
405 1 : buffer->setRunning(true);
406 1 : artdaqtest::CommandableFragmentGeneratorTest gen(ps);
407 1 : gen.SetRequestBuffer(buffer);
408 1 : gen.StartCmd(5, 0xFFFFFFFF, 1);
409 :
410 1 : artdaq::FragmentPtrs fps;
411 1 : auto sts = gen.getNext(fps);
412 4 : TRACE_REQUIRE_EQUAL(sts, true);
413 4 : TRACE_REQUIRE_EQUAL(fps.size(), 1u);
414 4 : TRACE_REQUIRE_EQUAL(fps.front()->fragmentID(), 1);
415 4 : TRACE_REQUIRE_EQUAL(fps.front()->timestamp(), 1);
416 4 : TRACE_REQUIRE_EQUAL(fps.front()->sequenceID(), 1);
417 1 : fps.clear();
418 :
419 3 : TLOG(TLVL_INFO) << "Setting failure bit";
420 1 : gen.setHwFail();
421 :
422 1 : sleep(1);
423 :
424 3 : TLOG(TLVL_INFO) << "Checking that failure is reported by getNext";
425 1 : gen.setFireCount(1);
426 1 : sts = gen.getNext(fps);
427 4 : TRACE_REQUIRE_EQUAL(sts, false);
428 4 : TRACE_REQUIRE(fps.empty());
429 :
430 1 : gen.StopCmd(0xFFFFFFFF, 1);
431 1 : gen.joinThreads();
432 3 : TLOG(TLVL_INFO) << "HardwareFailure_Threaded test case END";
433 1 : }
434 :
435 : BOOST_AUTO_TEST_SUITE_END()
|