Project
Loading...
Searching...
No Matches
test_InputRecord.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 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>
14#include "Framework/InputSpan.h"
16#include "Headers/DataHeader.h"
17#include "Headers/Stack.h"
18
19using namespace o2::framework;
22
23bool any_exception(RuntimeErrorRef const&) { return true; }
24
25TEST_CASE("TestInputRecord")
26{
27 // Create the routes we want for the InputRecord
28 InputSpec spec1{"x", "TPC", "CLUSTERS", 0, Lifetime::Timeframe};
29 InputSpec spec2{"y", "ITS", "CLUSTERS", 0, Lifetime::Timeframe};
30 InputSpec spec3{"z", "TST", "EMPTY", 0, Lifetime::Timeframe};
31
32 size_t i = 0;
33 auto createRoute = [&i](const char* source, InputSpec& spec) {
34 return InputRoute{
35 spec,
36 i++,
37 source,
38 0,
39 std::nullopt};
40 };
41
43 std::vector<InputRoute> schema = {
44 createRoute("x_source", spec1),
45 createRoute("y_source", spec2),
46 createRoute("z_source", spec3)};
47 // First of all we test if an empty registry behaves as expected, raising a
48 // bunch of exceptions.
49 InputSpan span{
50 [](size_t) -> size_t { return 0; },
51 nullptr,
52 [](size_t, DataRefIndices) { return DataRef{nullptr, nullptr, nullptr}; },
53 [](size_t, DataRefIndices) -> DataRefIndices { return {size_t(-1), size_t(-1)}; },
54 0};
55 ServiceRegistry registry;
56 InputRecord emptyRecord(schema, span, registry);
57
58 REQUIRE_THROWS_AS(emptyRecord.get("x"), RuntimeErrorRef);
59 REQUIRE_THROWS_AS(emptyRecord.get("y"), RuntimeErrorRef);
60 REQUIRE_THROWS_AS(emptyRecord.get("z"), RuntimeErrorRef);
61 REQUIRE_THROWS_AS((void)emptyRecord.getByPos(0), RuntimeErrorRef);
62 REQUIRE_THROWS_AS((void)emptyRecord.getByPos(1), RuntimeErrorRef);
63 REQUIRE_THROWS_AS((void)emptyRecord.getByPos(2), RuntimeErrorRef);
64 // Then we actually check with a real set of inputs.
65
66 std::vector<void*> inputs;
67
68 auto createMessage = [&inputs](DataHeader& dh, int value) {
69 DataProcessingHeader dph{0, 1};
70 Stack stack{dh, dph};
71 void* header = malloc(stack.size());
72 void* payload = malloc(sizeof(int));
73 memcpy(header, stack.data(), stack.size());
74 memcpy(payload, &value, sizeof(int));
75 inputs.emplace_back(header);
76 inputs.emplace_back(payload);
77 };
78
79 auto createEmpty = [&inputs]() {
80 inputs.emplace_back(nullptr);
81 inputs.emplace_back(nullptr);
82 };
83
84 DataHeader dh1;
85 dh1.dataDescription = "CLUSTERS";
86 dh1.dataOrigin = "TPC";
87 dh1.subSpecification = 0;
89 DataHeader dh2;
90 dh2.dataDescription = "CLUSTERS";
91 dh2.dataOrigin = "ITS";
92 dh2.subSpecification = 0;
94 createMessage(dh1, 1);
95 createMessage(dh2, 2);
96 createEmpty();
97 InputSpan span2{
98 [](size_t) -> size_t { return 1; },
99 nullptr,
100 [&inputs](size_t i, DataRefIndices idx) { return DataRef{nullptr, static_cast<char const*>(inputs[2 * i + idx.headerIdx]), static_cast<char const*>(inputs[2 * i + idx.payloadIdx])}; },
101 [](size_t, DataRefIndices) -> DataRefIndices { return {size_t(-1), size_t(-1)}; },
102 inputs.size() / 2};
103 InputRecord record{schema, span2, registry};
104
105 // Checking we can get the whole ref by name
106 REQUIRE_NOTHROW(record.get("x"));
107 REQUIRE_NOTHROW(record.get("y"));
108 REQUIRE_NOTHROW(record.get("z"));
109 auto ref00 = record.get("x");
110 auto ref10 = record.get("y");
111 REQUIRE_THROWS_AS(record.get("err"), RuntimeErrorRef);
112
113 // Or we can get it positionally
114 REQUIRE_NOTHROW(record.get("x"));
115 auto ref01 = record.getByPos(0);
116 auto ref11 = record.getByPos(1);
117 REQUIRE_THROWS_AS((void)record.getByPos(10), RuntimeErrorRef);
118
119 // This should be exactly the same pointers
120 REQUIRE(ref00.header == ref01.header);
121 REQUIRE(ref00.payload == ref01.payload);
122 REQUIRE(ref10.header == ref11.header);
123 REQUIRE(ref10.payload == ref11.payload);
124
125 REQUIRE(record.isValid("x") == true);
126 REQUIRE(record.isValid("y") == true);
127 REQUIRE(record.isValid("z") == false);
128 REQUIRE(record.size() == 3);
129 REQUIRE(record.countValidInputs() == 2);
130
131 REQUIRE(record.isValid(0) == true);
132 REQUIRE(record.isValid(1) == true);
133 REQUIRE(record.isValid(2) == false);
134 // This by default is a shortcut for
135 //
136 // *static_cast<int const *>(record.get("x").payload);
137 //
138 REQUIRE(record.get<int>("x") == 1);
139 REQUIRE(record.get<int>("y") == 2);
140 // A few more time just to make sure we are not stateful..
141 REQUIRE(record.get<int>("x") == 1);
142 REQUIRE(record.get<int>("x") == 1);
143
144 // test the iterator
145 int position = 0;
146 for (auto input = record.begin(), end = record.end(); input != end; input++, position++) {
147 if (position == 0) {
148 REQUIRE(input.matches("TPC") == true);
149 REQUIRE(input.matches("TPC", "CLUSTERS") == true);
150 REQUIRE(input.matches("ITS", "CLUSTERS") == false);
151 }
152 if (position == 1) {
153 REQUIRE(input.matches("ITS") == true);
154 REQUIRE(input.matches("ITS", "CLUSTERS") == true);
155 REQUIRE(input.matches("TPC", "CLUSTERS") == false);
156 }
157 // check if invalid slots are filtered out by the iterator
158 REQUIRE(position != 2);
159 }
160
161 // the 2-level iterator to access inputs and their parts
162 // all inputs have 1 part, we check the first input
163 REQUIRE(record.begin().size() == 1);
164 // the end-instance of the inputs has no parts
165 REQUIRE(record.end().size() == 0);
166 // thus there is no element and begin == end
167 REQUIRE(record.end().begin() == record.end().end());
168}
169
170// TODO:
171// - test all `get` implementations
172// - create a list of supported types and check that the API compiles
173// - test return value optimization for vectors, unique_ptr
174// - check objects which work directly on the payload for zero-copy
std::shared_ptr< arrow::Schema > schema
int32_t i
uint32_t stack
Definition RawData.h:1
The input API of the Data Processing Layer This class holds the inputs which are valid for processing...
decltype(auto) get(R binding, int part=0) const
static DataRef getByPos(std::vector< InputRoute > const &routes, InputSpan const &span, int pos, int part=0)
GLuint GLuint end
Definition glcorearb.h:469
GLsizei GLsizei GLchar * source
Definition glcorearb.h:798
GLsizei const GLfloat * value
Definition glcorearb.h:819
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
TEST_CASE("test_prepareArguments")
constexpr o2::header::SerializationMethod gSerializationMethodNone
Definition DataHeader.h:327
the main header struct
Definition DataHeader.h:620
SerializationMethod payloadSerializationMethod
Definition DataHeader.h:653
DataDescription dataDescription
Definition DataHeader.h:638
SubSpecificationType subSpecification
Definition DataHeader.h:658
a move-only header stack with serialized headers This is the flat buffer where all the headers in a m...
Definition Stack.h:33
bool any_exception(RuntimeErrorRef const &)