Project
Loading...
Searching...
No Matches
test_Services.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.
17#include <catch_amalgamated.hpp>
18#include <fairmq/ProgOptions.h>
19#include <memory>
20
21TEST_CASE("TestServiceRegistry")
22{
24 using namespace o2::framework;
25 struct InterfaceA {
26 virtual bool method() = 0;
27 };
28
29 struct ConcreteA : InterfaceA {
30 bool method() final { return true; }
31 };
32
33 struct InterfaceB {
34 virtual bool method() = 0;
35 };
36
37 struct ConcreteB : InterfaceB {
38 bool method() final { return false; }
39 };
40
41 struct InterfaceC {
42 [[nodiscard]] virtual bool method() const = 0;
43 };
44
45 struct ConcreteC : InterfaceC {
46 [[nodiscard]] bool method() const final { return false; }
47 };
48
49 ServiceRegistry registry;
50 ServiceRegistryRef ref{registry};
51 ConcreteA serviceA;
52 ConcreteB serviceB;
53 ConcreteC const serviceC;
54 ref.registerService(ServiceRegistryHelpers::handleForService<InterfaceA>(&serviceA));
55 ref.registerService(ServiceRegistryHelpers::handleForService<InterfaceB>(&serviceB));
56 ref.registerService(ServiceRegistryHelpers::handleForService<InterfaceC const>(&serviceC));
57 REQUIRE(registry.get<InterfaceA>(ServiceRegistry::globalDeviceSalt()).method() == true);
58 REQUIRE(registry.get<InterfaceB>(ServiceRegistry::globalDeviceSalt()).method() == false);
59 REQUIRE(registry.get<InterfaceC const>(ServiceRegistry::globalDeviceSalt()).method() == false);
60 REQUIRE(registry.active<InterfaceA>(ServiceRegistry::globalDeviceSalt()) == true);
61 REQUIRE(registry.active<InterfaceB>(ServiceRegistry::globalDeviceSalt()) == true);
62 REQUIRE(registry.active<InterfaceC>(ServiceRegistry::globalDeviceSalt()) == false);
63 REQUIRE_THROWS_AS(registry.get<InterfaceA const>(ServiceRegistry::globalDeviceSalt()), RuntimeErrorRef);
64 REQUIRE_THROWS_AS(registry.get<InterfaceC>(ServiceRegistry::globalDeviceSalt()), RuntimeErrorRef);
65}
66
67TEST_CASE("TestCallbackService")
68{
69 using namespace o2::framework;
70 ServiceRegistry registry;
71 ServiceRegistryRef ref{registry};
72 auto service = std::make_unique<CallbackService>();
73 ref.registerService(ServiceRegistryHelpers::handleForService<CallbackService>(service.get()));
74
75 // the callback simply sets the captured variable to indicated that it was called
76 bool cbCalled = false;
77 auto cb = [&]() { cbCalled = true; };
78 registry.get<CallbackService>(ServiceRegistry::globalDeviceSalt()).set<CallbackService::Id::Stop>(cb);
79
80 // execute and check
81 registry.get<CallbackService>(ServiceRegistry::globalDeviceSalt()).call<CallbackService::Id::Stop>();
82 REQUIRE(cbCalled);
83}
84
87};
88
89namespace o2::framework
90{
95static ServiceRegistry::Salt salt_1_1 = ServiceRegistry::Salt{1, 1};
96} // namespace o2::framework
97
98TEST_CASE("TestSerialServices")
99{
100 using namespace o2::framework;
101 ServiceRegistry registry;
102
103 DummyService t0{0};
105 registry.registerService({TypeIdHelpers::uniqueId<DummyService>()}, &t0, ServiceKind::Serial, salt_0);
106
107 auto tt0 = reinterpret_cast<DummyService*>(registry.get({TypeIdHelpers::uniqueId<DummyService>()}, salt_0, ServiceKind::Serial));
108 auto tt1 = reinterpret_cast<DummyService*>(registry.get({TypeIdHelpers::uniqueId<DummyService>()}, salt_1, ServiceKind::Serial));
109 auto tt2 = reinterpret_cast<DummyService*>(registry.get({TypeIdHelpers::uniqueId<DummyService>()}, salt_2, ServiceKind::Serial));
110 REQUIRE(tt0->threadId == 0);
111 REQUIRE(tt1->threadId == 0);
112 REQUIRE(tt2->threadId == 0);
113}
114
115TEST_CASE("TestGlobalServices")
116{
117 using namespace o2::framework;
118 ServiceRegistry registry;
119
120 DummyService t0{0};
122 registry.registerService({TypeIdHelpers::uniqueId<DummyService>()}, &t0, ServiceKind::Global, salt_0);
123
124 auto tt0 = reinterpret_cast<DummyService*>(registry.get({TypeIdHelpers::uniqueId<DummyService>()}, salt_0, ServiceKind::Serial));
125 auto tt1 = reinterpret_cast<DummyService*>(registry.get({TypeIdHelpers::uniqueId<DummyService>()}, salt_1, ServiceKind::Serial));
126 auto tt2 = reinterpret_cast<DummyService*>(registry.get({TypeIdHelpers::uniqueId<DummyService>()}, salt_2, ServiceKind::Serial));
127 REQUIRE(tt0->threadId == 0);
128 REQUIRE(tt1->threadId == 0);
129 REQUIRE(tt2->threadId == 0);
130}
131
132TEST_CASE("TestGlobalServices02")
133{
134 using namespace o2::framework;
135 ServiceRegistry registry;
136
138 fair::mq::ProgOptions options;
139 ServiceSpec spec{.name = "dummy-service",
140 .uniqueId = CommonServices::simpleServiceId<DummyService>(),
141 .init = [](ServiceRegistryRef, DeviceState&, fair::mq::ProgOptions&) -> ServiceHandle {
142 // this is needed to check we register it only once
143 static int i = 1;
144 return ServiceHandle{TypeIdHelpers::uniqueId<DummyService>(), new DummyService{i++}};
145 },
146 .configure = CommonServices::noConfiguration(),
147 .kind = ServiceKind::Global};
148
149 // If the service was not declared, we should not be able to register it from a stream context.
150 REQUIRE_THROWS_AS(registry.registerService({TypeIdHelpers::uniqueId<DummyService>()}, nullptr, ServiceKind::Global, salt_1), RuntimeErrorRef);
151 // Declare the service
152 registry.declareService(spec, state, options, ServiceRegistry::globalDeviceSalt());
153
155 try {
156 registry.registerService({TypeIdHelpers::uniqueId<DummyService>()}, nullptr, ServiceKind::Global, salt_1);
157 } catch (RuntimeErrorRef e) {
158 INFO(error_from_ref(e).what);
159 REQUIRE(false);
160 }
161
162 auto tt0 = reinterpret_cast<DummyService*>(registry.get({TypeIdHelpers::uniqueId<DummyService>()}, salt_0, ServiceKind::Global));
163 auto tt1 = reinterpret_cast<DummyService*>(registry.get({TypeIdHelpers::uniqueId<DummyService>()}, salt_1, ServiceKind::Global));
164 auto tt2 = reinterpret_cast<DummyService*>(registry.get({TypeIdHelpers::uniqueId<DummyService>()}, salt_2, ServiceKind::Global));
165 REQUIRE(tt0->threadId == 1);
166 REQUIRE(tt1->threadId == 1);
167 REQUIRE(tt2->threadId == 1);
168}
169
170TEST_CASE("TestStreamServices")
171{
172 using namespace o2::framework;
173 ServiceRegistry registry;
174
175 DummyService t1{1};
176 DummyService t2{2};
177 DummyService t3{3};
178 DummyService t2_d1{2};
179
180 ServiceSpec spec{.name = "dummy-service",
181 .uniqueId = CommonServices::simpleServiceId<DummyService>(),
182 .init = CommonServices::simpleServiceInit<DummyService, DummyService>(),
183 .configure = CommonServices::noConfiguration(),
184 .kind = ServiceKind::Stream};
185
187 fair::mq::ProgOptions options;
188 // This will raise an exception because we have not declared the service yet.
189 REQUIRE_THROWS_AS(registry.registerService({TypeIdHelpers::uniqueId<DummyService>()}, nullptr, ServiceKind::Stream, ServiceRegistry::Salt{1, 0}), RuntimeErrorRef);
190 registry.declareService(spec, state, options, ServiceRegistry::globalDeviceSalt());
191
193 registry.registerService({TypeIdHelpers::uniqueId<DummyService>()}, &t1, ServiceKind::Stream, ServiceRegistry::Salt{1, 0}, "dummy-service1", ServiceRegistry::SpecIndex{0});
194 registry.registerService({TypeIdHelpers::uniqueId<DummyService>()}, &t2, ServiceKind::Stream, ServiceRegistry::Salt{2, 0}, "dummy-service2", ServiceRegistry::SpecIndex{0});
195 registry.registerService({TypeIdHelpers::uniqueId<DummyService>()}, &t3, ServiceKind::Stream, ServiceRegistry::Salt{3, 0}, "dummy-service3", ServiceRegistry::SpecIndex{0});
196
197 auto tt1 = reinterpret_cast<DummyService*>(registry.get({TypeIdHelpers::uniqueId<DummyService>()}, salt_1, ServiceKind::Stream));
198 auto tt2 = reinterpret_cast<DummyService*>(registry.get({TypeIdHelpers::uniqueId<DummyService>()}, salt_2, ServiceKind::Stream));
199 auto tt3 = reinterpret_cast<DummyService*>(registry.get({TypeIdHelpers::uniqueId<DummyService>()}, salt_3, ServiceKind::Stream));
200 REQUIRE(tt1->threadId == 1);
201 REQUIRE(tt2->threadId == 2);
202 REQUIRE(tt3->threadId == 3);
203 // Check that Context{1,1} throws, because we registerd it for a different data processor.
204 REQUIRE_THROWS_AS(registry.get({TypeIdHelpers::uniqueId<DummyService>()}, salt_1_1, ServiceKind::Stream), RuntimeErrorRef);
205
206 // Check that Context{0,0} throws.
207 REQUIRE_THROWS_AS(registry.get({TypeIdHelpers::uniqueId<DummyService>()}, salt_0, ServiceKind::Stream), RuntimeErrorRef);
208 registry.registerService({TypeIdHelpers::uniqueId<DummyService>()}, &t2_d1, ServiceKind::Stream, ServiceRegistry::Salt{3, 1}, "dummy-service", ServiceRegistry::SpecIndex{0});
209
210 auto tt2_dp1 = reinterpret_cast<DummyService*>(registry.get({TypeIdHelpers::uniqueId<DummyService>()}, ServiceRegistry::Salt{3, 1}, ServiceKind::Stream));
211 REQUIRE(tt2_dp1->threadId == 2);
212
213 REQUIRE_THROWS_AS(registry.get({TypeIdHelpers::uniqueId<DummyService>()}, salt_1_1, ServiceKind::Stream), RuntimeErrorRef);
214}
215
216TEST_CASE("TestServiceRegistryCtor")
217{
218 using namespace o2::framework;
219 ServiceRegistry registry;
220 registry = ServiceRegistry();
221}
222
223TEST_CASE("TestServiceDeclaration")
224{
225 using namespace o2::framework;
226 ServiceRegistry registry;
228 fair::mq::ProgOptions options;
229 options.SetProperty("monitoring-backend", "no-op://");
230 options.SetProperty("infologger-mode", "no-op://");
231 options.SetProperty("infologger-severity", "info");
232 options.SetProperty("configuration", "command-line");
233
234 registry.declareService(CommonServices::callbacksSpec(), state, options);
235 REQUIRE(registry.active<CallbackService>(ServiceRegistry::globalDeviceSalt()) == true);
236 REQUIRE(registry.active<DummyService>(ServiceRegistry::globalDeviceSalt()) == false);
237}
238
239TEST_CASE("TestServiceOverride")
240{
241 using namespace o2::framework;
242 auto overrides = ServiceSpecHelpers::parseOverrides("foo:enable,bar:disable");
243 REQUIRE(overrides.size() == 2);
244 REQUIRE(overrides[0].name == "foo");
245 REQUIRE(overrides[0].active == true);
246 REQUIRE(overrides[1].name == "bar");
247 REQUIRE(overrides[1].active == false);
248
249 auto overrides2 = ServiceSpecHelpers::parseOverrides("foo:enable");
250 REQUIRE(overrides2.size() == 1);
251 REQUIRE(overrides[0].name == "foo");
252 REQUIRE(overrides[0].active == true);
253
254 REQUIRE_THROWS_AS(ServiceSpecHelpers::parseOverrides("foo:enabledisabl"), std::runtime_error);
255 REQUIRE_THROWS_AS(ServiceSpecHelpers::parseOverrides("foo"), std::runtime_error);
256 REQUIRE_THROWS_AS(ServiceSpecHelpers::parseOverrides("foo:"), std::runtime_error);
257 REQUIRE_THROWS_AS(ServiceSpecHelpers::parseOverrides("foo:a,"), std::runtime_error);
258 REQUIRE_THROWS_AS(ServiceSpecHelpers::parseOverrides("foo:,"), std::runtime_error);
259 REQUIRE(ServiceSpecHelpers::parseOverrides("").size() == 0);
260 REQUIRE(ServiceSpecHelpers::parseOverrides(nullptr).size() == 0);
261
262 auto overrides3 = ServiceSpecHelpers::parseOverrides("foo:disable,bar:enable,baz:enable");
263 ServiceSpecs originalServices{
264 {.name = "foo", .active = true},
265 {.name = "bar", .active = false},
266 };
267 REQUIRE(overrides3.size() == 3);
268 auto services = ServiceSpecHelpers::filterDisabled(originalServices, overrides3);
269 REQUIRE(services.size() == 1);
270 REQUIRE(services[0].name == "bar");
271 REQUIRE(services[0].active == true);
272}
benchmark::State & state
int32_t i
GLsizeiptr size
Definition glcorearb.h:659
GLuint const GLchar * name
Definition glcorearb.h:781
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t0
Definition glcorearb.h:5034
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
Definition glcorearb.h:5034
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
std::vector< ServiceSpec > ServiceSpecs
void clean_all_runtime_errors()
Running state information of a given device.
Definition DeviceState.h:34
void declareService(ServiceSpec const &spec, DeviceState &state, fair::mq::ProgOptions &options, ServiceRegistry::Salt salt=ServiceRegistry::globalDeviceSalt())
void registerService(ServiceTypeHash typeHash, void *service, ServiceKind kind, Salt salt, char const *name=nullptr, ServiceRegistry::SpecIndex specIndex=SpecIndex{-1}) const
bool active(Salt salt) const
Check if service of type T is currently active.
void * get(ServiceTypeHash typeHash, Salt salt, ServiceKind kind, char const *name=nullptr) const
std::string name
Name of the service.
TEST_CASE("TestServiceRegistry")