Project
Loading...
Searching...
No Matches
test_ForwardInputs.cxx
Go to the documentation of this file.
1// Copyright 2019-2025 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#include <catch_amalgamated.hpp>
13#include "Headers/DataHeader.h"
18#include "Framework/Signpost.h"
21#include "Headers/Stack.h"
23#include <fairmq/TransportFactory.h>
24#include <fairmq/Channel.h>
25#include <vector>
26
28using namespace o2::framework;
29
30// Build a vector of spans over an existing vector-of-vectors for tests that
31// construct currentSetOfInputs locally (rather than via consumeAllInputsForTimeslice).
32static std::vector<std::span<fair::mq::MessagePtr>> asSpans(std::vector<std::vector<fair::mq::MessagePtr>>& vecs)
33{
34 std::vector<std::span<fair::mq::MessagePtr>> spans;
35 spans.reserve(vecs.size());
36 for (auto& v : vecs) {
37 spans.emplace_back(v);
38 }
39 return spans;
40}
41
42TEST_CASE("ForwardInputsEmpty")
43{
45 dh.dataDescription = "CLUSTERS";
46 dh.dataOrigin = "TPC";
47 dh.subSpecification = 0;
48 dh.splitPayloadIndex = 0;
49 dh.splitPayloadParts = 1;
50
52 auto transport = fair::mq::TransportFactory::CreateTransportFactory("zeromq");
53
54 bool consume = true;
55 bool copyByDefault = true;
57
58 std::vector<std::vector<fair::mq::MessagePtr>> currentSetOfInputs;
59
60 auto spans = asSpans(currentSetOfInputs);
61 auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, spans, copyByDefault, consume);
62 REQUIRE(result.empty());
63}
64
65TEST_CASE("ForwardInputsSingleMessageSingleRoute")
66{
68 dh.dataOrigin = "TST";
69 dh.dataDescription = "A";
70 dh.subSpecification = 0;
71 dh.splitPayloadIndex = 0;
72 dh.splitPayloadParts = 1;
73
75 std::vector<fair::mq::Channel> channels{
76 fair::mq::Channel("from_A_to_B")};
77
78 bool consume = true;
79 bool copyByDefault = true;
81 std::vector<ForwardRoute> routes{ForwardRoute{
82 .timeslice = 0,
83 .maxTimeslices = 1,
84 .matcher = {"binding", ConcreteDataMatcher{"TST", "A", 0}},
85 .channel = "from_A_to_B",
86 .policy = nullptr,
87 }};
88
89 auto findChannelByName = [&channels](std::string const& channelName) -> fair::mq::Channel& {
90 for (auto& channel : channels) {
91 if (channel.GetName() == channelName) {
92 return channel;
93 }
94 }
95 throw std::runtime_error("Channel not found");
96 };
97
98 proxy.bind({}, {}, routes, findChannelByName, nullptr);
99
100 std::vector<std::vector<fair::mq::MessagePtr>> currentSetOfInputs;
101 std::vector<fair::mq::MessagePtr> messageSet;
102
103 auto transport = fair::mq::TransportFactory::CreateTransportFactory("zeromq");
104 fair::mq::MessagePtr payload(transport->CreateMessage());
105 auto channelAlloc = o2::pmr::getTransportAllocator(transport.get());
106 auto header = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh, dph});
107 messageSet.emplace_back(std::move(header));
108 messageSet.emplace_back(std::move(payload));
109 REQUIRE((messageSet | count_parts{}) == 1);
110 currentSetOfInputs.emplace_back(std::move(messageSet));
111
112 auto spans = asSpans(currentSetOfInputs);
113 auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, spans, copyByDefault, consume);
114 REQUIRE(result.size() == 1); // One route
115 REQUIRE(result[0].Size() == 2); // Two messages for that route
116}
117
118TEST_CASE("ForwardInputsSingleMessageSingleRouteNoConsume")
119{
121 dh.dataOrigin = "TST";
122 dh.dataDescription = "A";
123 dh.subSpecification = 0;
124 dh.splitPayloadIndex = 0;
125 dh.splitPayloadParts = 1;
126
128 std::vector<fair::mq::Channel> channels{
129 fair::mq::Channel("from_A_to_B")};
130
131 bool copyByDefault = false;
132 FairMQDeviceProxy proxy;
133 std::vector<ForwardRoute> routes{ForwardRoute{
134 .timeslice = 0,
135 .maxTimeslices = 1,
136 .matcher = {"binding", ConcreteDataMatcher{"TST", "A", 0}},
137 .channel = "from_A_to_B",
138 .policy = nullptr,
139 }};
140
141 auto findChannelByName = [&channels](std::string const& channelName) -> fair::mq::Channel& {
142 for (auto& channel : channels) {
143 if (channel.GetName() == channelName) {
144 return channel;
145 }
146 }
147 throw std::runtime_error("Channel not found");
148 };
149
150 proxy.bind({}, {}, routes, findChannelByName, nullptr);
151
152 std::vector<std::vector<fair::mq::MessagePtr>> currentSetOfInputs;
153 std::vector<fair::mq::MessagePtr> messageSet;
154
155 auto transport = fair::mq::TransportFactory::CreateTransportFactory("zeromq");
156 fair::mq::MessagePtr payload(nullptr);
157 REQUIRE(payload.get() == nullptr);
158 auto channelAlloc = o2::pmr::getTransportAllocator(transport.get());
159 auto header = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh, dph});
160 messageSet.emplace_back(std::move(header));
161 messageSet.emplace_back(std::move(payload));
162 REQUIRE((messageSet | count_parts{}) == 1);
163 currentSetOfInputs.emplace_back(std::move(messageSet));
164
165 auto spans = asSpans(currentSetOfInputs);
166 auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, spans, copyByDefault, true);
167 REQUIRE(result.size() == 1);
168 REQUIRE(result[0].Size() == 0); // Because there is a nullptr, we do not forward this as it was already consumed.
169}
170
171TEST_CASE("ForwardInputsSingleMessageSingleRouteAtEOS")
172{
174 dh.dataOrigin = "TST";
175 dh.dataDescription = "A";
176 dh.subSpecification = 0;
177 dh.splitPayloadIndex = 0;
178 dh.splitPayloadParts = 1;
179
181
183
184 std::vector<fair::mq::Channel> channels{
185 fair::mq::Channel("from_A_to_B")};
186
187 bool consume = true;
188 bool copyByDefault = true;
189 FairMQDeviceProxy proxy;
190 std::vector<ForwardRoute> routes{ForwardRoute{
191 .timeslice = 0,
192 .maxTimeslices = 1,
193 .matcher = {"binding", ConcreteDataMatcher{"TST", "A", 0}},
194 .channel = "from_A_to_B",
195 .policy = nullptr,
196 }};
197
198 auto findChannelByName = [&channels](std::string const& channelName) -> fair::mq::Channel& {
199 for (auto& channel : channels) {
200 if (channel.GetName() == channelName) {
201 return channel;
202 }
203 }
204 throw std::runtime_error("Channel not found");
205 };
206
207 proxy.bind({}, {}, routes, findChannelByName, nullptr);
208
209 std::vector<std::vector<fair::mq::MessagePtr>> currentSetOfInputs;
210 std::vector<fair::mq::MessagePtr> messageSet;
211
212 auto transport = fair::mq::TransportFactory::CreateTransportFactory("zeromq");
213 fair::mq::MessagePtr payload(transport->CreateMessage());
214 auto channelAlloc = o2::pmr::getTransportAllocator(transport.get());
215 auto header = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh, dph, sih});
216 REQUIRE(o2::header::get<SourceInfoHeader*>(header->GetData()));
217 messageSet.emplace_back(std::move(header));
218 messageSet.emplace_back(std::move(payload));
219 REQUIRE((messageSet | count_parts{}) == 1);
220 currentSetOfInputs.emplace_back(std::move(messageSet));
221
222 auto spans = asSpans(currentSetOfInputs);
223 auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, spans, copyByDefault, consume);
224 REQUIRE(result.size() == 1); // One route
225 REQUIRE(result[0].Size() == 0); // FIXME: this is an actual error. It should be 2. However it cannot really happen.
226 // Correct behavior below:
227 // REQUIRE(result[0].Size() == 2);
228 // REQUIRE(o2::header::get<SourceInfoHeader*>(result[0].At(0)->GetData()) == nullptr);
229}
230
231TEST_CASE("ForwardInputsSingleMessageSingleRouteWithOldestPossible")
232{
234 dh.dataOrigin = "TST";
235 dh.dataDescription = "A";
236 dh.subSpecification = 0;
237 dh.splitPayloadIndex = 0;
238 dh.splitPayloadParts = 1;
239
241
243
244 std::vector<fair::mq::Channel> channels{
245 fair::mq::Channel("from_A_to_B")};
246
247 bool consume = true;
248 bool copyByDefault = true;
249 FairMQDeviceProxy proxy;
250 std::vector<ForwardRoute> routes{ForwardRoute{
251 .timeslice = 0,
252 .maxTimeslices = 1,
253 .matcher = {"binding", ConcreteDataMatcher{"TST", "A", 0}},
254 .channel = "from_A_to_B",
255 .policy = nullptr,
256 }};
257
258 auto findChannelByName = [&channels](std::string const& channelName) -> fair::mq::Channel& {
259 for (auto& channel : channels) {
260 if (channel.GetName() == channelName) {
261 return channel;
262 }
263 }
264 throw std::runtime_error("Channel not found");
265 };
266
267 proxy.bind({}, {}, routes, findChannelByName, nullptr);
268
269 std::vector<std::vector<fair::mq::MessagePtr>> currentSetOfInputs;
270 std::vector<fair::mq::MessagePtr> messageSet;
271
272 auto transport = fair::mq::TransportFactory::CreateTransportFactory("zeromq");
273 fair::mq::MessagePtr payload(transport->CreateMessage());
274 auto channelAlloc = o2::pmr::getTransportAllocator(transport.get());
275 auto header = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh, dph, dih});
276 REQUIRE(o2::header::get<DomainInfoHeader*>(header->GetData()));
277 messageSet.emplace_back(std::move(header));
278 messageSet.emplace_back(std::move(payload));
279 REQUIRE((messageSet | count_parts{}) == 1);
280 currentSetOfInputs.emplace_back(std::move(messageSet));
281
282 auto spans = asSpans(currentSetOfInputs);
283 auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, spans, copyByDefault, consume);
284 REQUIRE(result.size() == 1); // One route
285 REQUIRE(result[0].Size() == 0); // FIXME: this is actually wrong
286 // FIXME: actually correct behavior below
287 // REQUIRE(result[0].Size() == 2); // Two messages
288 // REQUIRE(o2::header::get<DomainInfoHeader*>(result[0].At(0)->GetData()) == nullptr); // it should not have the end of stream
289}
290
291TEST_CASE("ForwardInputsSingleMessageMultipleRoutes")
292{
294 dh.dataOrigin = "TST";
295 dh.dataDescription = "A";
296 dh.subSpecification = 0;
297 dh.splitPayloadIndex = 0;
298 dh.splitPayloadParts = 1;
299
301
302 std::vector<fair::mq::Channel> channels{
303 fair::mq::Channel("from_A_to_B"),
304 fair::mq::Channel("from_A_to_C"),
305 };
306
307 bool consume = true;
308 bool copyByDefault = true;
309 FairMQDeviceProxy proxy;
310 std::vector<ForwardRoute> routes{
312 .timeslice = 0,
313 .maxTimeslices = 1,
314 .matcher = {"binding", ConcreteDataMatcher{"TST", "A", 0}},
315 .channel = "from_A_to_B",
316 .policy = nullptr,
317 },
319 .timeslice = 0,
320 .maxTimeslices = 1,
321 .matcher = {"binding2", ConcreteDataMatcher{"TST", "A", 0}},
322 .channel = "from_A_to_C",
323 .policy = nullptr,
324 }};
325
326 auto findChannelByName = [&channels](std::string const& channelName) -> fair::mq::Channel& {
327 for (auto& channel : channels) {
328 if (channel.GetName() == channelName) {
329 return channel;
330 }
331 }
332 throw std::runtime_error("Channel not found");
333 };
334
335 proxy.bind({}, {}, routes, findChannelByName, nullptr);
336
337 std::vector<std::vector<fair::mq::MessagePtr>> currentSetOfInputs;
338 std::vector<fair::mq::MessagePtr> messageSet;
339
340 auto transport = fair::mq::TransportFactory::CreateTransportFactory("zeromq");
341 fair::mq::MessagePtr payload(transport->CreateMessage());
342 auto channelAlloc = o2::pmr::getTransportAllocator(transport.get());
343 auto header = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh, dph});
344 messageSet.emplace_back(std::move(header));
345 messageSet.emplace_back(std::move(payload));
346 REQUIRE((messageSet | count_parts{}) == 1);
347 currentSetOfInputs.emplace_back(std::move(messageSet));
348
349 auto spans = asSpans(currentSetOfInputs);
350 auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, spans, copyByDefault, consume);
351 REQUIRE(result.size() == 2); // Two routes
352 REQUIRE(result[0].Size() == 2); // Two messages per route
353 REQUIRE(result[1].Size() == 0); // Only the first DPL matched channel matters
354}
355
356TEST_CASE("ForwardInputsSingleMessageMultipleRoutesExternals")
357{
359 dh.dataOrigin = "TST";
360 dh.dataDescription = "A";
361 dh.subSpecification = 0;
362 dh.splitPayloadIndex = 0;
363 dh.splitPayloadParts = 1;
364
366
367 std::vector<fair::mq::Channel> channels{
368 fair::mq::Channel("external"),
369 fair::mq::Channel("from_A_to_C"),
370 };
371
372 bool consume = true;
373 bool copyByDefault = true;
374 FairMQDeviceProxy proxy;
375 std::vector<ForwardRoute> routes{
377 .timeslice = 0,
378 .maxTimeslices = 1,
379 .matcher = {"binding", ConcreteDataMatcher{"TST", "A", 0}},
380 .channel = "external",
381 .policy = nullptr,
382 },
384 .timeslice = 0,
385 .maxTimeslices = 1,
386 .matcher = {"binding2", ConcreteDataMatcher{"TST", "A", 0}},
387 .channel = "from_A_to_C",
388 .policy = nullptr,
389 }};
390
391 auto findChannelByName = [&channels](std::string const& channelName) -> fair::mq::Channel& {
392 for (auto& channel : channels) {
393 if (channel.GetName() == channelName) {
394 return channel;
395 }
396 }
397 throw std::runtime_error("Channel not found");
398 };
399
400 proxy.bind({}, {}, routes, findChannelByName, nullptr);
401
402 std::vector<std::vector<fair::mq::MessagePtr>> currentSetOfInputs;
403 std::vector<fair::mq::MessagePtr> messageSet;
404
405 auto transport = fair::mq::TransportFactory::CreateTransportFactory("zeromq");
406 fair::mq::MessagePtr payload(transport->CreateMessage());
407 auto channelAlloc = o2::pmr::getTransportAllocator(transport.get());
408 auto header = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh, dph});
409 messageSet.emplace_back(std::move(header));
410 messageSet.emplace_back(std::move(payload));
411 REQUIRE((messageSet | count_parts{}) == 1);
412 currentSetOfInputs.emplace_back(std::move(messageSet));
413
414 auto spans = asSpans(currentSetOfInputs);
415 auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, spans, copyByDefault, consume);
416 REQUIRE(result.size() == 2); // Two routes
417 REQUIRE(result[0].Size() == 2); // With external matching channels, we need to copy and then forward
418 REQUIRE(result[1].Size() == 2); //
419}
420
421TEST_CASE("ForwardInputsMultiMessageMultipleRoutes")
422{
424 dh1.dataOrigin = "TST";
425 dh1.dataDescription = "A";
426 dh1.subSpecification = 0;
427 dh1.splitPayloadIndex = 0;
428 dh1.splitPayloadParts = 1;
429
431 dh2.dataOrigin = "TST";
432 dh2.dataDescription = "B";
433 dh2.subSpecification = 0;
434 dh2.splitPayloadIndex = 0;
435 dh2.splitPayloadParts = 1;
436
438
439 std::vector<fair::mq::Channel> channels{
440 fair::mq::Channel("from_A_to_B"),
441 fair::mq::Channel("from_A_to_C"),
442 };
443
444 bool consume = true;
445 bool copyByDefault = true;
446 FairMQDeviceProxy proxy;
447 std::vector<ForwardRoute> routes{
449 .timeslice = 0,
450 .maxTimeslices = 1,
451 .matcher = {"binding", ConcreteDataMatcher{"TST", "A", 0}},
452 .channel = "from_A_to_B",
453 .policy = nullptr,
454 },
456 .timeslice = 0,
457 .maxTimeslices = 1,
458 .matcher = {"binding2", ConcreteDataMatcher{"TST", "B", 0}},
459 .channel = "from_A_to_C",
460 .policy = nullptr,
461 }};
462
463 auto findChannelByName = [&channels](std::string const& channelName) -> fair::mq::Channel& {
464 for (auto& channel : channels) {
465 if (channel.GetName() == channelName) {
466 return channel;
467 }
468 }
469 throw std::runtime_error("Channel not found");
470 };
471
472 proxy.bind({}, {}, routes, findChannelByName, nullptr);
473
474 std::vector<std::vector<fair::mq::MessagePtr>> currentSetOfInputs;
475
476 auto transport = fair::mq::TransportFactory::CreateTransportFactory("zeromq");
477 fair::mq::MessagePtr payload1(transport->CreateMessage());
478 fair::mq::MessagePtr payload2(transport->CreateMessage());
479 auto channelAlloc = o2::pmr::getTransportAllocator(transport.get());
480 auto header1 = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh1, dph});
481 std::vector<fair::mq::MessagePtr> messageSet1;
482 messageSet1.emplace_back(std::move(header1));
483 messageSet1.emplace_back(std::move(payload1));
484 REQUIRE((messageSet1 | count_parts{}) == 1);
485
486 auto header2 = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh2, dph});
487 std::vector<fair::mq::MessagePtr> messageSet2;
488 messageSet2.emplace_back(std::move(header2));
489 messageSet2.emplace_back(std::move(payload2));
490 REQUIRE((messageSet2 | count_parts{}) == 1);
491 currentSetOfInputs.emplace_back(std::move(messageSet1));
492 currentSetOfInputs.emplace_back(std::move(messageSet2));
493 REQUIRE(currentSetOfInputs.size() == 2);
494
495 auto spans = asSpans(currentSetOfInputs);
496 auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, spans, copyByDefault, consume);
497 REQUIRE(result.size() == 2); // Two routes
498 REQUIRE(result[0].Size() == 2); //
499 REQUIRE(result[1].Size() == 2); //
500}
501
502TEST_CASE("ForwardInputsSingleMessageMultipleRoutesOnlyOneMatches")
503{
505 dh.dataOrigin = "TST";
506 dh.dataDescription = "A";
507 dh.subSpecification = 0;
508 dh.splitPayloadIndex = 0;
509 dh.splitPayloadParts = 1;
510
512
513 std::vector<fair::mq::Channel> channels{
514 fair::mq::Channel("from_A_to_B"),
515 fair::mq::Channel("from_A_to_C"),
516 };
517
518 bool consume = true;
519 bool copyByDefault = true;
520 FairMQDeviceProxy proxy;
521 std::vector<ForwardRoute> routes{
523 .timeslice = 0,
524 .maxTimeslices = 1,
525 .matcher = {"binding", ConcreteDataMatcher{"TST", "B", 0}},
526 .channel = "from_A_to_B",
527 .policy = nullptr,
528 },
530 .timeslice = 0,
531 .maxTimeslices = 1,
532 .matcher = {"binding", ConcreteDataMatcher{"TST", "A", 0}},
533 .channel = "from_A_to_C",
534 .policy = nullptr,
535 }};
536
537 auto findChannelByName = [&channels](std::string const& channelName) -> fair::mq::Channel& {
538 for (auto& channel : channels) {
539 if (channel.GetName() == channelName) {
540 return channel;
541 }
542 }
543 throw std::runtime_error("Channel not found");
544 };
545
546 proxy.bind({}, {}, routes, findChannelByName, nullptr);
547
548 std::vector<std::vector<fair::mq::MessagePtr>> currentSetOfInputs;
549 std::vector<fair::mq::MessagePtr> messageSet;
550
551 auto transport = fair::mq::TransportFactory::CreateTransportFactory("zeromq");
552 fair::mq::MessagePtr payload(transport->CreateMessage());
553 auto channelAlloc = o2::pmr::getTransportAllocator(transport.get());
554 auto header = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh, dph});
555 messageSet.emplace_back(std::move(header));
556 messageSet.emplace_back(std::move(payload));
557 REQUIRE((messageSet | count_parts{}) == 1);
558 currentSetOfInputs.emplace_back(std::move(messageSet));
559
560 auto spans = asSpans(currentSetOfInputs);
561 auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, spans, copyByDefault, consume);
562 REQUIRE(result.size() == 2); // Two routes
563 REQUIRE(result[0].Size() == 0); // Two messages per route
564 REQUIRE(result[1].Size() == 2); // Two messages per route
565}
566
567TEST_CASE("ForwardInputsSplitPayload")
568{
570 dh.dataOrigin = "TST";
571 dh.dataDescription = "A";
572 dh.subSpecification = 0;
573 dh.splitPayloadIndex = 2;
574 dh.splitPayloadParts = 2;
575
577 dh2.dataOrigin = "TST";
578 dh2.dataDescription = "B";
579 dh2.subSpecification = 0;
580 dh2.splitPayloadIndex = 0;
581 dh2.splitPayloadParts = 1;
582
584
585 std::vector<fair::mq::Channel> channels{
586 fair::mq::Channel("from_A_to_B"),
587 fair::mq::Channel("from_A_to_C"),
588 };
589
590 bool consume = true;
591 bool copyByDefault = true;
592 FairMQDeviceProxy proxy;
593 std::vector<ForwardRoute> routes{
595 .timeslice = 0,
596 .maxTimeslices = 1,
597 .matcher = {"binding", ConcreteDataMatcher{"TST", "B", 0}},
598 .channel = "from_A_to_B",
599 .policy = nullptr,
600 },
602 .timeslice = 0,
603 .maxTimeslices = 1,
604 .matcher = {"binding", ConcreteDataMatcher{"TST", "A", 0}},
605 .channel = "from_A_to_C",
606 .policy = nullptr,
607 }};
608
609 auto findChannelByName = [&channels](std::string const& channelName) -> fair::mq::Channel& {
610 for (auto& channel : channels) {
611 if (channel.GetName() == channelName) {
612 return channel;
613 }
614 }
615 throw std::runtime_error("Channel not found");
616 };
617
618 proxy.bind({}, {}, routes, findChannelByName, nullptr);
619
620 std::vector<std::vector<fair::mq::MessagePtr>> currentSetOfInputs;
621 std::vector<fair::mq::MessagePtr> messageSet;
622
623 auto transport = fair::mq::TransportFactory::CreateTransportFactory("zeromq");
624 fair::mq::MessagePtr payload1(transport->CreateMessage());
625 fair::mq::MessagePtr payload2(transport->CreateMessage());
626 auto channelAlloc = o2::pmr::getTransportAllocator(transport.get());
627 auto header = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh, dph});
628 std::vector<std::unique_ptr<fair::mq::Message>> messages;
629 messages.push_back(std::move(header));
630 messages.push_back(std::move(payload1));
631 messages.push_back(std::move(payload2));
632 auto fillMessages = [&messages](size_t t) -> fair::mq::MessagePtr {
633 return std::move(messages[t]);
634 };
635 for (size_t i = 0; i < 3; ++i) {
636 messageSet.emplace_back(fillMessages(i));
637 }
638 auto header2 = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh2, dph});
639 messageSet.emplace_back(std::move(header2));
640 messageSet.emplace_back(transport->CreateMessage());
641
642 REQUIRE((messageSet | count_parts{}) == 2);
643 currentSetOfInputs.emplace_back(std::move(messageSet));
644
645 auto spans = asSpans(currentSetOfInputs);
646 auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, spans, copyByDefault, consume);
647 REQUIRE(result.size() == 2); // Two routes
648 CHECK(result[0].Size() == 2); // No messages on this route
649 CHECK(result[1].Size() == 3);
650}
651
652TEST_CASE("ForwardInputsSplitPayloadNoMessageSet")
653{
655 dh.dataOrigin = "TST";
656 dh.dataDescription = "A";
657 dh.subSpecification = 0;
658 dh.splitPayloadIndex = 2;
659 dh.splitPayloadParts = 2;
660
662 dh2.dataOrigin = "TST";
663 dh2.dataDescription = "B";
664 dh2.subSpecification = 0;
665 dh2.splitPayloadIndex = 0;
666 dh2.splitPayloadParts = 1;
667
669
670 std::vector<fair::mq::Channel> channels{
671 fair::mq::Channel("from_A_to_B"),
672 fair::mq::Channel("from_A_to_C"),
673 };
674
675 bool consume = true;
676 bool copyByDefault = true;
677 FairMQDeviceProxy proxy;
678 std::vector<ForwardRoute> routes{
680 .timeslice = 0,
681 .maxTimeslices = 1,
682 .matcher = {"binding", ConcreteDataMatcher{"TST", "B", 0}},
683 .channel = "from_A_to_B",
684 .policy = nullptr,
685 },
687 .timeslice = 0,
688 .maxTimeslices = 1,
689 .matcher = {"binding", ConcreteDataMatcher{"TST", "A", 0}},
690 .channel = "from_A_to_C",
691 .policy = nullptr,
692 }};
693
694 auto findChannelByName = [&channels](std::string const& channelName) -> fair::mq::Channel& {
695 for (auto& channel : channels) {
696 if (channel.GetName() == channelName) {
697 return channel;
698 }
699 }
700 throw std::runtime_error("Channel not found");
701 };
702
703 proxy.bind({}, {}, routes, findChannelByName, nullptr);
704
705 auto transport = fair::mq::TransportFactory::CreateTransportFactory("zeromq");
706 fair::mq::MessagePtr payload1(transport->CreateMessage());
707 fair::mq::MessagePtr payload2(transport->CreateMessage());
708 auto channelAlloc = o2::pmr::getTransportAllocator(transport.get());
709 auto header = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh, dph});
710 std::vector<std::unique_ptr<fair::mq::Message>> messages;
711 messages.push_back(std::move(header));
712 messages.push_back(std::move(payload1));
713 messages.push_back(std::move(payload2));
714 auto header2 = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh2, dph});
715 messages.push_back(std::move(header2));
716 messages.push_back(transport->CreateMessage());
717
718 std::vector<fair::mq::Parts> result(2);
719 auto span = std::span(messages);
720 o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, span, result, copyByDefault, consume);
721 REQUIRE(result.size() == 2); // Two routes
722 CHECK(result[0].Size() == 2); // No messages on this route
723 CHECK(result[1].Size() == 3);
724}
725
726TEST_CASE("ForwardInputEOSSingleRoute")
727{
729
730 std::vector<fair::mq::Channel> channels{
731 fair::mq::Channel("from_A_to_B")};
732
733 bool consume = true;
734 bool copyByDefault = true;
735 FairMQDeviceProxy proxy;
736 std::vector<ForwardRoute> routes{ForwardRoute{
737 .timeslice = 0,
738 .maxTimeslices = 1,
739 .matcher = {"binding", ConcreteDataMatcher{"TST", "A", 0}},
740 .channel = "from_A_to_B",
741 .policy = nullptr,
742 }};
743
744 auto findChannelByName = [&channels](std::string const& channelName) -> fair::mq::Channel& {
745 for (auto& channel : channels) {
746 if (channel.GetName() == channelName) {
747 return channel;
748 }
749 }
750 throw std::runtime_error("Channel not found");
751 };
752
753 proxy.bind({}, {}, routes, findChannelByName, nullptr);
754
755 std::vector<std::vector<fair::mq::MessagePtr>> currentSetOfInputs;
756 std::vector<fair::mq::MessagePtr> messageSet;
757
758 auto transport = fair::mq::TransportFactory::CreateTransportFactory("zeromq");
759 fair::mq::MessagePtr payload(transport->CreateMessage());
760 auto channelAlloc = o2::pmr::getTransportAllocator(transport.get());
761 auto header = o2::pmr::getMessage(o2::header::Stack{channelAlloc, sih});
762 messageSet.emplace_back(std::move(header));
763 messageSet.emplace_back(std::move(payload));
764 REQUIRE((messageSet | count_parts{}) == 1);
765 currentSetOfInputs.emplace_back(std::move(messageSet));
766
767 auto spans = asSpans(currentSetOfInputs);
768 auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, spans, copyByDefault, consume);
769 REQUIRE(result.size() == 1); // One route
770 REQUIRE(result[0].Size() == 0); // Oldest possible timeframe should not be forwarded
771}
772
773TEST_CASE("ForwardInputOldestPossibleSingleRoute")
774{
776
777 std::vector<fair::mq::Channel> channels{
778 fair::mq::Channel("from_A_to_B")};
779
780 bool consume = true;
781 bool copyByDefault = true;
782 FairMQDeviceProxy proxy;
783 std::vector<ForwardRoute> routes{ForwardRoute{
784 .timeslice = 0,
785 .maxTimeslices = 1,
786 .matcher = {"binding", ConcreteDataMatcher{"TST", "A", 0}},
787 .channel = "from_A_to_B",
788 .policy = nullptr,
789 }};
790
791 auto findChannelByName = [&channels](std::string const& channelName) -> fair::mq::Channel& {
792 for (auto& channel : channels) {
793 if (channel.GetName() == channelName) {
794 return channel;
795 }
796 }
797 throw std::runtime_error("Channel not found");
798 };
799
800 proxy.bind({}, {}, routes, findChannelByName, nullptr);
801
802 std::vector<std::vector<fair::mq::MessagePtr>> currentSetOfInputs;
803 std::vector<fair::mq::MessagePtr> messageSet;
804
805 auto transport = fair::mq::TransportFactory::CreateTransportFactory("zeromq");
806 fair::mq::MessagePtr payload(transport->CreateMessage());
807 auto channelAlloc = o2::pmr::getTransportAllocator(transport.get());
808 auto header = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dih});
809 messageSet.emplace_back(std::move(header));
810 messageSet.emplace_back(std::move(payload));
811 REQUIRE((messageSet | count_parts{}) == 1);
812 currentSetOfInputs.emplace_back(std::move(messageSet));
813
814 auto spans = asSpans(currentSetOfInputs);
815 auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, spans, copyByDefault, consume);
816 REQUIRE(result.size() == 1); // One route
817 REQUIRE(result[0].Size() == 0); // Oldest possible timeframe should not be forwarded
818}
std::vector< OutputRoute > routes
int32_t i
#define O2_DECLARE_DYNAMIC_LOG(name)
Definition Signpost.h:490
void bind(std::vector< OutputRoute > const &outputs, std::vector< InputRoute > const &inputs, std::vector< ForwardRoute > const &forwards, std::function< fair::mq::Channel &(std::string const &)> bindChannelByName, std::function< bool(void)> newStateRequestedCallback)
#define CHECK
GLuint64EXT * result
Definition glcorearb.h:5662
const GLdouble * v
Definition glcorearb.h:832
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
TEST_CASE("test_prepareArguments")
fair::mq::MessagePtr getMessage(ContainerT &&container, FairMQMemoryResource *targetResource=nullptr)
static std::vector< fair::mq::Parts > routeForwardedMessageSet(FairMQDeviceProxy &proxy, std::vector< std::span< fair::mq::MessagePtr > > &currentSetOfInputs, bool copy, bool consume)
Helper to route messages for forwarding.
static void routeForwardedMessages(FairMQDeviceProxy &proxy, std::span< fair::mq::MessagePtr > &currentSetOfInputs, std::vector< fair::mq::Parts > &forwardedParts, bool copy, bool consume)
Helper to route messages for forwarding.
a BaseHeader with domain information from the source
a BaseHeader with state information from the source
the main header struct
Definition DataHeader.h:620
SplitPayloadPartsType splitPayloadParts
Definition DataHeader.h:648
DataDescription dataDescription
Definition DataHeader.h:638
SubSpecificationType subSpecification
Definition DataHeader.h:658
SplitPayloadIndexType splitPayloadIndex
Definition DataHeader.h:663
a move-only header stack with serialized headers This is the flat buffer where all the headers in a m...
Definition Stack.h:33
std::vector< ChannelData > channels