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