ChimeraTK-ApplicationCore 04.08.00
Loading...
Searching...
No Matches
fixtures.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2// SPDX-License-Identifier: LGPL-3.0-or-later
3#pragma once
4
5#include "Application.h"
6#include "ApplicationModule.h"
7#include "DeviceManager.h"
8#include "DeviceModule.h"
9#include "ScalarAccessor.h"
10#include "TestFacility.h"
11
12#include <ChimeraTK/BackendFactory.h>
13#include <ChimeraTK/Device.h>
14#include <ChimeraTK/DummyRegisterAccessor.h>
15#include <ChimeraTK/ExceptionDummyBackend.h>
16#include <ChimeraTK/NDRegisterAccessor.h>
17
18#include <future>
19
20/**********************************************************************************************************************/
21/**********************************************************************************************************************/
22
27 std::promise<void> p;
28 void mainLoop() override { p.set_value(); }
29};
30
31/**********************************************************************************************************************/
32
37 ChimeraTK::ScalarPushInput<int> pushInput{this, "../REG1_PUSHED", "", ""};
38 } reg1{this, "PushModule", ""};
39
40 std::promise<void> p;
41 void mainLoop() override { p.set_value(); }
42};
43
44/**********************************************************************************************************************/
45
50 ChimeraTK::ScalarPushInput<int> pushInput{this, "../REG1_PUSHED", "", ""};
51 ChimeraTK::ScalarPushInput<int> pushInputCopy{this, "../REG1_PUSHED", "", ""};
52 } reg1{this, "PushModuleForFanOut", ""};
53
54 std::promise<void> p;
55 void mainLoop() override { p.set_value(); }
56};
57
58/**********************************************************************************************************************/
59
66 } reg1{this, "PushModuleForTrigger", ""};
67
68 std::promise<void> p;
69 void mainLoop() override { p.set_value(); }
70};
71
72/**********************************************************************************************************************/
73
76 // Note: REG1 is not writeable. REG1.DUMMY_WRITEABLE is not part of the catalogue and hence cannot be used.
79 ChimeraTK::ScalarOutput<int> trigger{this, "trigger", "", ""}; // must not be connected to any device
81 std::promise<void> p;
82 void prepare() override { writeAll(); }
83 void mainLoop() override { p.set_value(); }
84};
85
86/**********************************************************************************************************************/
87
89 constexpr static const char* ExceptionDummyCDD1 = "(ExceptionDummy:1?map=test_with_push.map)";
90 constexpr static const char* ExceptionDummyCDD2 = "(ExceptionDummy:2?map=test_with_push.map)";
91 constexpr static const char* ExceptionDummyCDD3 = "(ExceptionDummy:3?map=test_with_push.map)";
92
93 DummyApplication() : Application("DummyApplication") {}
94 ~DummyApplication() override { shutdown(); }
95
103
107 PushModuleForTrigger pushModule2{this, ".", "With TriggerFanOut"};
108 PushModuleForFanOut pushModule3{this, ".", "With ThreadedFanOut"};
109 // PollModule pollModule2{this, ".", ""};
111 } group2{this, "Group2", ""};
112
118};
119
120/**********************************************************************************************************************/
121/**********************************************************************************************************************/
122
123template<bool enableTestFacility, bool addInitHandlers = false, bool breakSecondDeviceAtStart = false>
126
128
129 template<typename T>
130 auto read(ChimeraTK::DummyRegisterRawAccessor& accessor);
131
132 template<typename T>
133 auto read(ChimeraTK::DummyRegisterRawAccessor&& accessor);
134
135 template<typename T>
136 void write(ChimeraTK::DummyRegisterRawAccessor& accessor, T value);
137
138 template<typename T>
139 void write(ChimeraTK::DummyRegisterRawAccessor&& accessor, T value);
140
141 bool isDeviceInError();
142
143 boost::shared_ptr<ChimeraTK::ExceptionDummy> deviceBackend;
144 boost::shared_ptr<ChimeraTK::ExceptionDummy> deviceBackend2;
145 boost::shared_ptr<ChimeraTK::ExceptionDummy> deviceBackend3;
148
149 ChimeraTK::ScalarRegisterAccessor<int> status, status2;
150 ChimeraTK::VoidRegisterAccessor deviceBecameFunctional;
151 ChimeraTK::ScalarRegisterAccessor<std::string> message;
152 ChimeraTK::DummyRegisterRawAccessor exceptionDummyRegister;
153 ChimeraTK::DummyRegisterRawAccessor exceptionDummyRegister2;
154 ChimeraTK::DummyRegisterRawAccessor exceptionDummyRegister3;
155 ChimeraTK::DummyRegisterRawAccessor exceptionDummy2Register;
156
157 ChimeraTK::ScalarPushInput<int>& pushVariable{application.group1.pushModule.reg1.pushInput};
160 ChimeraTK::ScalarOutput<int>& outputVariable2{application.group1.outputModule.deviceRegister2};
161 ChimeraTK::ScalarOutput<int>& outputVariable3{application.group1.outputModule.deviceRegister3};
162 ChimeraTK::VoidOutput& outputVariableV{application.group1.outputModule.deviceRegisterV};
163
164 ChimeraTK::ScalarPushInput<int>& triggeredInput{application.group2.pushModule2.reg1.pushInput};
165
166 ChimeraTK::ScalarPushInput<int>& pushVariable3{application.group2.pushModule3.reg1.pushInput};
167 ChimeraTK::ScalarPushInput<int>& pushVariable3copy{application.group2.pushModule3.reg1.pushInputCopy};
169
170 ChimeraTK::VoidRegisterAccessor interrupt;
171
172 std::atomic<bool> initHandler1Throws{false};
173 std::atomic<bool> initHandler2Throws{false};
174 std::atomic<bool> initHandler1Called{false};
175 std::atomic<bool> initHandler2Called{false};
176};
177
178/**********************************************************************************************************************/
179
180template<bool enableTestFacility, bool addInitHandlers, bool breakSecondDeviceAtStart>
181FixtureWithPollAndPushInput<enableTestFacility, addInitHandlers,
182 breakSecondDeviceAtStart>::FixtureWithPollAndPushInput()
183: deviceBackend(boost::dynamic_pointer_cast<ChimeraTK::ExceptionDummy>(
184 ChimeraTK::BackendFactory::getInstance().createBackend(DummyApplication::ExceptionDummyCDD1))),
185 deviceBackend2(boost::dynamic_pointer_cast<ChimeraTK::ExceptionDummy>(
186 ChimeraTK::BackendFactory::getInstance().createBackend(DummyApplication::ExceptionDummyCDD2))),
187 deviceBackend3(boost::dynamic_pointer_cast<ChimeraTK::ExceptionDummy>(
188 ChimeraTK::BackendFactory::getInstance().createBackend(DummyApplication::ExceptionDummyCDD3))),
189 exceptionDummyRegister(deviceBackend->getRawAccessor("", "REG1.DUMMY_WRITEABLE")),
190 exceptionDummyRegister2(deviceBackend->getRawAccessor("", "REG2")),
191 exceptionDummyRegister3(deviceBackend->getRawAccessor("", "REG3")),
192 exceptionDummy2Register(deviceBackend2->getRawAccessor("", "REG1.DUMMY_WRITEABLE")) {
193 try {
194 deviceBackend2->throwExceptionOpen = breakSecondDeviceAtStart;
195
196 if constexpr(addInitHandlers) {
197 auto initHandler1 = [this](ChimeraTK::Device& dev) {
198 if(&dev == &application.group1.device.getDeviceManager().getDevice()) {
199 initHandler1Called = true;
201 throw ChimeraTK::runtime_error("Init handler 1 throws by request");
202 }
203 }
204 };
205 auto initHandler2 = [this](ChimeraTK::Device& dev) {
206 if(&dev == &application.group1.device.getDeviceManager().getDevice()) {
207 initHandler2Called = true;
209 throw ChimeraTK::runtime_error("Init handler 2 throws by request");
210 }
211 }
212 };
213 application.group1.device.addInitialisationHandler(initHandler1);
214 application.group1.device.addInitialisationHandler(initHandler2);
215 }
216
217 // Make sure that some variables are not connected to the control system, to allow testing direct device-to-app
218 // connections without a ThreadedFanOut in between:
219 // "/Group1/REG1_PUSHED" aka "application.group1.pushModule.reg1.pushInput" aka "pushVariable"
220 // "/Group1/REG1_WRITE" aka "application.group1.outputModule.deviceRegister" aka "outputVariable"
221 application.optimiseUnmappedVariables({"/Group1/REG1_PUSHED", "/Group1/REG2"});
222
224
227 status.replace(testFacitiy.getScalar<int>(ChimeraTK::RegisterPath("/Devices") / dm1 / "status"));
228 message.replace(testFacitiy.getScalar<std::string>(ChimeraTK::RegisterPath("/Devices") / dm1 / "status_message"));
230 testFacitiy.getVoid(ChimeraTK::RegisterPath("/Devices") / dm1 / "deviceBecameFunctional"));
231
232 status2.replace(testFacitiy.getScalar<int>(ChimeraTK::RegisterPath("/Devices") / dm2 / "status"));
233
235 interrupt.replace(dev.getVoidRegisterAccessor("DUMMY_INTERRUPT_1"));
236
237 // wait until all modules have been properly started, to ensure the initial value propagation is complete
238 application.group1.pollModule.p.get_future().wait();
239 application.group1.pushModule.p.get_future().wait();
240 application.group1.outputModule.p.get_future().wait();
241 if(!breakSecondDeviceAtStart) {
242 application.group2.outputModule2.p.get_future().wait();
243 // application.group2.pollModule2.p.get_future().wait();
244 application.group2.pushModule2.p.get_future().wait();
245 application.group2.pushModule3.p.get_future().wait();
246 }
247 application.group3.pollModule3.p.get_future().wait();
249 }
250 catch(std::exception& e) {
251 std::cout << "Exception caught in constructor: " << e.what() << std::endl;
252 throw;
253 }
254}
255
256/**********************************************************************************************************************/
257
258template<bool enableTestFacility, bool addInitHandlers, bool breakSecondDeviceAtStart>
259FixtureWithPollAndPushInput<enableTestFacility, addInitHandlers,
260 breakSecondDeviceAtStart>::~FixtureWithPollAndPushInput() {
261 // make sure no exception throwing is still enabled from previous test
262 deviceBackend->throwExceptionOpen = false;
263 deviceBackend->throwExceptionRead = false;
264 deviceBackend->throwExceptionWrite = false;
265 deviceBackend2->throwExceptionOpen = false;
266 deviceBackend2->throwExceptionRead = false;
267 deviceBackend2->throwExceptionWrite = false;
268 deviceBackend3->throwExceptionOpen = false;
269 deviceBackend3->throwExceptionRead = false;
270 deviceBackend3->throwExceptionWrite = false;
271}
272
273/**********************************************************************************************************************/
274
275template<bool enableTestFacility, bool addInitHandlers, bool breakSecondDeviceAtStart>
277 // By definition, the DeviceModule has finished the recovery procedure when the status is 0 again.
278 status.readLatest();
279 return static_cast<int>(status);
280}
281
282/**********************************************************************************************************************/
283
284template<bool enableTestFacility, bool addInitHandlers, bool breakSecondDeviceAtStart>
285template<typename T>
287 ChimeraTK::DummyRegisterRawAccessor& accessor) {
288 auto lock = accessor.getBufferLock();
289 return static_cast<T>(accessor);
290}
291
292/**********************************************************************************************************************/
293
294template<bool enableTestFacility, bool addInitHandlers, bool breakSecondDeviceAtStart>
295template<typename T>
297 ChimeraTK::DummyRegisterRawAccessor&& accessor) {
298 read<T>(accessor);
299}
300
301/**********************************************************************************************************************/
302
303template<bool enableTestFacility, bool addInitHandlers, bool breakSecondDeviceAtStart>
304template<typename T>
306 ChimeraTK::DummyRegisterRawAccessor& accessor, T value) {
307 auto lock = accessor.getBufferLock();
308 accessor = static_cast<int32_t>(value);
309}
310
311/**********************************************************************************************************************/
312
313template<bool enableTestFacility, bool addInitHandlers, bool breakSecondDeviceAtStart>
314template<typename T>
316 ChimeraTK::DummyRegisterRawAccessor&& accessor, T value) {
317 write(accessor, value);
318}
319
320/**********************************************************************************************************************/
321/**********************************************************************************************************************/
boost::shared_ptr< DeviceManager > getDeviceManager(const std::string &aliasOrCDD)
Return the DeviceManager for the given alias name or CDD.
void optimiseUnmappedVariables(const std::set< std::string > &names) override
void shutdown() override
This will remove the global pointer to the instance and allows creating another instance afterwards.
ApplicationModule()=default
Default constructor: Allows late initialisation of modules (e.g.
friend class Application
Definition ModuleGroup.h:47
ModuleGroup()=default
Default constructor to allow late initialisation of module groups.
void writeAll(bool includeReturnChannels=false)
Just call write() on all writable variables in the group.
Definition Module.cc:157
Convenience class for output scalar accessors (always UpdateMode::push)
Convenience class for input scalar accessors with UpdateMode::poll.
Convenience class for input scalar accessors with UpdateMode::push.
Helper class to facilitate tests of applications based on ApplicationCore.
ChimeraTK::VoidRegisterAccessor getVoid(const ChimeraTK::RegisterPath &name) const
Obtain a void process variable from the application, which is published to the control system.
ChimeraTK::ScalarRegisterAccessor< T > getScalar(const ChimeraTK::RegisterPath &name) const
Obtain a scalar process variable from the application, which is published to the control system.
void runApplication() const
Start the application in testable mode.
VariableGroup()=default
Default constructor: Allows late initialisation of VariableGroups (e.g.
Convenience class for output void (always UpdateMode::push)
std::string escapeName(const std::string &name, bool allowDotsAndSlashes)
Convert all characters which are not allowed in variable or module names into underscores followed by...
Definition Utilities.cc:45
InvalidityTracer application module.
ChimeraTK::DeviceModule device
Definition fixtures.h:98
OutputModule outputModule
Definition fixtures.h:101
PushModuleForFanOut pushModule3
Definition fixtures.h:108
ChimeraTK::DeviceModule device2
Definition fixtures.h:106
PushModuleForTrigger pushModule2
Definition fixtures.h:107
OutputModule outputModule2
Definition fixtures.h:110
ChimeraTK::DeviceModule device3
Definition fixtures.h:115
static constexpr const char * ExceptionDummyCDD2
Definition fixtures.h:90
~DummyApplication() override
Definition fixtures.h:94
static constexpr const char * ExceptionDummyCDD1
Definition fixtures.h:89
static constexpr const char * ExceptionDummyCDD3
Definition fixtures.h:91
ChimeraTK::ScalarRegisterAccessor< int > status2
Definition fixtures.h:149
ChimeraTK::ScalarRegisterAccessor< std::string > message
Definition fixtures.h:151
ChimeraTK::TestFacility testFacitiy
Definition fixtures.h:147
ChimeraTK::DummyRegisterRawAccessor exceptionDummy2Register
Definition fixtures.h:155
boost::shared_ptr< ChimeraTK::ExceptionDummy > deviceBackend3
Definition fixtures.h:145
ChimeraTK::DummyRegisterRawAccessor exceptionDummyRegister2
Definition fixtures.h:153
ChimeraTK::ScalarOutput< int > & outputVariable3
Definition fixtures.h:161
std::atomic< bool > initHandler2Called
Definition fixtures.h:175
ChimeraTK::ScalarPushInput< int > & pushVariable3copy
Definition fixtures.h:167
ChimeraTK::ScalarPollInput< int > & pollVariable2
Definition fixtures.h:159
DummyApplication application
Definition fixtures.h:146
void write(ChimeraTK::DummyRegisterRawAccessor &accessor, T value)
Definition fixtures.h:305
std::atomic< bool > initHandler1Called
Definition fixtures.h:174
ChimeraTK::ScalarPushInput< int > & pushVariable3
Definition fixtures.h:166
ChimeraTK::ScalarPushInput< int > & triggeredInput
Definition fixtures.h:164
ChimeraTK::ScalarRegisterAccessor< int > status
Definition fixtures.h:149
std::atomic< bool > initHandler1Throws
Definition fixtures.h:172
boost::shared_ptr< ChimeraTK::ExceptionDummy > deviceBackend2
Definition fixtures.h:144
ChimeraTK::ScalarOutput< int > & outputVariable2
Definition fixtures.h:160
ChimeraTK::VoidRegisterAccessor deviceBecameFunctional
Definition fixtures.h:150
ChimeraTK::DummyRegisterRawAccessor exceptionDummyRegister3
Definition fixtures.h:154
std::atomic< bool > initHandler2Throws
Definition fixtures.h:173
ChimeraTK::ScalarPushInput< int > & pushVariable
Definition fixtures.h:157
ChimeraTK::ScalarPollInput< int > & pollVariable3
Definition fixtures.h:168
boost::shared_ptr< ChimeraTK::ExceptionDummy > deviceBackend
Definition fixtures.h:143
ChimeraTK::VoidRegisterAccessor interrupt
Definition fixtures.h:170
ChimeraTK::VoidOutput & outputVariableV
Definition fixtures.h:162
ChimeraTK::DummyRegisterRawAccessor exceptionDummyRegister
Definition fixtures.h:152
auto read(ChimeraTK::DummyRegisterRawAccessor &accessor)
Definition fixtures.h:286
ChimeraTK::ScalarPollInput< int > & pollVariable
Definition fixtures.h:158
void prepare() override
Prepare the execution of the module.
Definition fixtures.h:82
ChimeraTK::ScalarOutput< int > deviceRegister3
Definition fixtures.h:78
ChimeraTK::ScalarOutput< int > deviceRegister2
Definition fixtures.h:77
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
Definition fixtures.h:83
ChimeraTK::VoidOutput deviceRegisterV
Definition fixtures.h:80
ChimeraTK::ScalarOutput< int > trigger
Definition fixtures.h:79
std::promise< void > p
Definition fixtures.h:81
std::promise< void > p
Definition fixtures.h:27
ChimeraTK::ScalarPollInput< int > pollInput2
Definition fixtures.h:26
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
Definition fixtures.h:28
ChimeraTK::ScalarPollInput< int > pollInput
Definition fixtures.h:25
std::promise< void > p
Definition fixtures.h:54
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
Definition fixtures.h:55
ChimeraTK::ScalarPushInput< int > pushInputCopy
Definition fixtures.h:51
ChimeraTK::ScalarPushInput< int > pushInput
Definition fixtures.h:50
ChimeraTK::ScalarPushInput< int > pushInput
Definition fixtures.h:64
std::promise< void > p
Definition fixtures.h:68
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
Definition fixtures.h:69
ChimeraTK::ScalarPushInput< int > pushInputCopy
Definition fixtures.h:65
std::promise< void > p
Definition fixtures.h:40
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
Definition fixtures.h:41
ChimeraTK::ScalarPushInput< int > pushInput
Definition fixtures.h:37