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 nullptr,
55 0};
56 ServiceRegistry registry;
57 InputRecord emptyRecord(schema, span, registry);
58
59 REQUIRE_THROWS_AS(emptyRecord.get("x"), RuntimeErrorRef);
60 REQUIRE_THROWS_AS(emptyRecord.get("y"), RuntimeErrorRef);
61 REQUIRE_THROWS_AS(emptyRecord.get("z"), RuntimeErrorRef);
62 REQUIRE_THROWS_AS((void)emptyRecord.getByPos(0), RuntimeErrorRef);
63 REQUIRE_THROWS_AS((void)emptyRecord.getByPos(1), RuntimeErrorRef);
64 REQUIRE_THROWS_AS((void)emptyRecord.getByPos(2), RuntimeErrorRef);
65 // Then we actually check with a real set of inputs.
66
67 std::vector<void*> inputs;
68
69 auto createMessage = [&inputs](DataHeader& dh, int value) {
70 DataProcessingHeader dph{0, 1};
71 Stack stack{dh, dph};
72 void* header = malloc(stack.size());
73 void* payload = malloc(sizeof(int));
74 memcpy(header, stack.data(), stack.size());
75 memcpy(payload, &value, sizeof(int));
76 inputs.emplace_back(header);
77 inputs.emplace_back(payload);
78 };
79
80 auto createEmpty = [&inputs]() {
81 inputs.emplace_back(nullptr);
82 inputs.emplace_back(nullptr);
83 };
84
85 DataHeader dh1;
86 dh1.dataDescription = "CLUSTERS";
87 dh1.dataOrigin = "TPC";
88 dh1.subSpecification = 0;
90 DataHeader dh2;
91 dh2.dataDescription = "CLUSTERS";
92 dh2.dataOrigin = "ITS";
93 dh2.subSpecification = 0;
95 createMessage(dh1, 1);
96 createMessage(dh2, 2);
97 createEmpty();
98 InputSpan span2{
99 [](size_t) -> size_t { return 1; },
100 nullptr,
101 [&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])}; },
102 [](size_t, DataRefIndices) -> DataRefIndices { return {size_t(-1), size_t(-1)}; },
103 nullptr,
104 inputs.size() / 2};
105 InputRecord record{schema, span2, registry};
106
107 // Checking we can get the whole ref by name
108 REQUIRE_NOTHROW(record.get("x"));
109 REQUIRE_NOTHROW(record.get("y"));
110 REQUIRE_NOTHROW(record.get("z"));
111 auto ref00 = record.get("x");
112 auto ref10 = record.get("y");
113 REQUIRE_THROWS_AS(record.get("err"), RuntimeErrorRef);
114
115 // Or we can get it positionally
116 REQUIRE_NOTHROW(record.get("x"));
117 auto ref01 = record.getByPos(0);
118 auto ref11 = record.getByPos(1);
119 REQUIRE_THROWS_AS((void)record.getByPos(10), RuntimeErrorRef);
120
121 // This should be exactly the same pointers
122 REQUIRE(ref00.header == ref01.header);
123 REQUIRE(ref00.payload == ref01.payload);
124 REQUIRE(ref10.header == ref11.header);
125 REQUIRE(ref10.payload == ref11.payload);
126
127 REQUIRE(record.isValid("x") == true);
128 REQUIRE(record.isValid("y") == true);
129 REQUIRE(record.isValid("z") == false);
130 REQUIRE(record.size() == 3);
131 REQUIRE(record.countValidInputs() == 2);
132
133 REQUIRE(record.isValid(0) == true);
134 REQUIRE(record.isValid(1) == true);
135 REQUIRE(record.isValid(2) == false);
136 // This by default is a shortcut for
137 //
138 // *static_cast<int const *>(record.get("x").payload);
139 //
140 REQUIRE(record.get<int>("x") == 1);
141 REQUIRE(record.get<int>("y") == 2);
142 // A few more time just to make sure we are not stateful..
143 REQUIRE(record.get<int>("x") == 1);
144 REQUIRE(record.get<int>("x") == 1);
145
146 // test the iterator
147 int position = 0;
148 for (auto input = record.begin(), end = record.end(); input != end; input++, position++) {
149 if (position == 0) {
150 REQUIRE(input.matches("TPC") == true);
151 REQUIRE(input.matches("TPC", "CLUSTERS") == true);
152 REQUIRE(input.matches("ITS", "CLUSTERS") == false);
153 }
154 if (position == 1) {
155 REQUIRE(input.matches("ITS") == true);
156 REQUIRE(input.matches("ITS", "CLUSTERS") == true);
157 REQUIRE(input.matches("TPC", "CLUSTERS") == false);
158 }
159 // check if invalid slots are filtered out by the iterator
160 REQUIRE(position != 2);
161 }
162
163 // the 2-level iterator to access inputs and their parts
164 // all inputs have 1 part, we check the first input
165 REQUIRE(record.begin().parts().size() == 1);
166 // the end-instance of the inputs has no parts
167 REQUIRE(record.end().parts().size() == 0);
168 // thus there is no element and begin == end
169 REQUIRE(record.end().parts().begin() == record.end().parts().end());
170}
171
172// TODO:
173// - test all `get` implementations
174// - create a list of supported types and check that the API compiles
175// - test return value optimization for vectors, unique_ptr
176// - 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 &)