ChimeraTK-ApplicationCore 04.06.00
Loading...
Searching...
No Matches
testDeviceExceptionFlagPropagation.cc
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#define BOOST_TEST_MODULE testDeviceExceptionFlagPropagation
4
5#include "Application.h"
6#include "ApplicationModule.h"
7#include "check_timeout.h"
8#include "DeviceModule.h"
9#include "PeriodicTrigger.h"
10#include "TestFacility.h"
11#include "VariableGroup.h"
12
13#include <ChimeraTK/DummyRegisterAccessor.h>
14#include <ChimeraTK/ExceptionDummyBackend.h>
15
16#define BOOST_NO_EXCEPTIONS
17#include <boost/test/included/unit_test.hpp>
18#undef BOOST_NO_EXCEPTIONS
19using namespace boost::unit_test_framework;
20
21namespace ctk = ChimeraTK;
22
24
25 constexpr std::string_view ExceptionDummyCDD1{"(ExceptionDummy:1?map=test3.map)"};
26
27 /********************************************************************************************************************/
28
30 TestApplication() : Application("testSuite") {}
31 ~TestApplication() override { shutdown(); }
32
34 using ctk::ApplicationModule::ApplicationModule;
35
37 using ctk::VariableGroup::VariableGroup;
38 ctk::ScalarOutput<uint64_t> tick{this, "tick", "", ""};
39 } name{(this), "name", ""}; // extra parentheses are for doxygen...
40
41 void prepare() override { name.tick.write(); /* send initial value */ }
42 void mainLoop() override {}
43 } name{this, "name", ""};
44
46 using ctk::ApplicationModule::ApplicationModule;
47
48 mutable int readMode{0};
49
51 using ctk::VariableGroup::VariableGroup;
52 ctk::ScalarPushInput<uint64_t> tick{this, "/trigger/tick", "", ""};
53 ctk::ScalarPollInput<int> read{this, "/MyModule/readBack", "", ""};
54 ctk::ScalarOutput<int> set{this, "/MyModule/actuator", "", ""};
55 } vars{this, ".", ""};
56
57 std::atomic<ctk::DataValidity> readDataValidity{ctk::DataValidity::ok};
58
59 void prepare() override {
60 readDataValidity = vars.read.dataValidity();
61 // The receiving end of all accessor implementations should be constructed with faulty (Initial value
62 // propagation spec, D.1)
63 BOOST_CHECK(readDataValidity == ctk::DataValidity::faulty);
64 vars.set.write(); /* send initial value */
65 }
66
67 void mainLoop() override {
68 readDataValidity = vars.read.dataValidity();
69 while(true) {
70 vars.tick.read();
71 readDataValidity = vars.read.dataValidity();
72 switch(readMode) {
73 case 0:
74 vars.read.readNonBlocking();
75 break;
76 case 1:
77 vars.read.readLatest();
78 break;
79 case 2:
80 vars.read.read();
81 break;
82 case 3:
83 vars.set.write();
84 break;
85 case 4:
86 vars.set.writeDestructively();
87 break;
88 default:
89 break;
90 }
91 }
92 }
93
94 } module{this, "module", ""};
95
96 ctk::DeviceModule dev{this, ExceptionDummyCDD1.data(), "/fakeTriggerToMakeUnusedPollRegsHappy"};
97 };
98
99 /********************************************************************************************************************/
100
101 BOOST_AUTO_TEST_CASE(testDirectConnectOpen) {
102 for(int readMode = 0; readMode < 2; ++readMode) {
103 std::cout << "testDirectConnectOpen (readMode = " << readMode << ")" << std::endl;
104
105 TestApplication app;
106
107 boost::shared_ptr<ctk::ExceptionDummy> dummyBackend1 = boost::dynamic_pointer_cast<ctk::ExceptionDummy>(
108 ChimeraTK::BackendFactory::getInstance().createBackend(ExceptionDummyCDD1.data()));
109
110 ctk::TestFacility test(app, false);
111
112 // Throw on device open and check if DataValidity::faulty gets propagated
113 dummyBackend1->throwExceptionOpen = true;
114 // set the read mode
115 app.module.readMode = readMode;
116 std::cout << "Read mode is: " << app.module.readMode << ". Run application.\n";
117
118 // app.run();
119 test.runApplication();
120
122 test.readScalar<int>("Devices/" + ctk::Utilities::escapeName(ExceptionDummyCDD1.data(), false) + "/status"),
123 1, 10000);
124
125 // Trigger and check
126 test.writeScalar<uint64_t>("/trigger/tick", 1);
127 usleep(10000);
128 BOOST_CHECK(app.module.readDataValidity == ctk::DataValidity::faulty);
129
130 // recover from error state
131 dummyBackend1->throwExceptionOpen = false;
132 CHECK_TIMEOUT(app.module.readDataValidity == ctk::DataValidity::ok, 10000);
133 }
134 }
135
136 /********************************************************************************************************************/
137
138 BOOST_AUTO_TEST_CASE(testDirectConnectRead) {
139 std::cout << "testDirectConnectRead" << std::endl;
140 TestApplication app;
141 boost::shared_ptr<ctk::ExceptionDummy> dummyBackend1 = boost::dynamic_pointer_cast<ctk::ExceptionDummy>(
142 ChimeraTK::BackendFactory::getInstance().createBackend(ExceptionDummyCDD1.data()));
143
144 app.module.vars.tick = {&app.module.vars, "/trigger/tick", "", ""};
145
146 app.getModel().writeGraphViz("testDirectConnectRead.dot");
147
149
150 ctk::TestFacility test(app);
151 test.runApplication();
152
153 // Advance through all read methods
154 while(app.module.readMode < 3) {
155 // Check
156 test.writeScalar<uint64_t>("/trigger/tick", 1);
157 test.stepApplication();
158 BOOST_CHECK(app.module.vars.read.dataValidity() == ctk::DataValidity::ok);
159
160 // Check
161 std::cout << "Checking read mode " << app.module.readMode << "\n";
162 dummyBackend1->throwExceptionRead = true;
163 test.writeScalar<uint64_t>("/trigger/tick", 1);
164 test.stepApplication(false);
165 BOOST_CHECK(app.module.vars.read.dataValidity() == ctk::DataValidity::faulty);
166
167 // Reset throwing and let the device recover
168 dummyBackend1->throwExceptionRead = false;
169 test.stepApplication(true);
170
171 // advance to the next read
172 app.module.readMode++;
173 }
174 }
175
176 /********************************************************************************************************************/
177
178 BOOST_AUTO_TEST_CASE(testDirectConnectWrite) {
179 std::cout << "testDirectConnectWrite" << std::endl;
180 TestApplication app;
181 boost::shared_ptr<ctk::ExceptionDummy> dummyBackend1 = boost::dynamic_pointer_cast<ctk::ExceptionDummy>(
182 ChimeraTK::BackendFactory::getInstance().createBackend(ExceptionDummyCDD1.data()));
183
184 app.module.readMode = 3;
185
186 ctk::TestFacility test(app);
187 test.runApplication();
188
189 // Advance through all non-blocking read methods
190 while(app.module.readMode < 5) {
191 // Check
192 test.writeScalar<uint64_t>("/trigger/tick", 1);
193 test.stepApplication();
194 BOOST_CHECK(app.module.vars.set.dataValidity() == ctk::DataValidity::ok);
195
196 // Check
197 dummyBackend1->throwExceptionWrite = true;
198 test.writeScalar<uint64_t>("/trigger/tick", 1);
199 test.stepApplication(false);
200 // write operations failing does not invalidate data
201 BOOST_CHECK(app.module.vars.set.dataValidity() == ctk::DataValidity::ok);
202
203 // advance to the next read
204 dummyBackend1->throwExceptionWrite = false;
205 app.module.readMode++;
206 }
207 }
208
209 /********************************************************************************************************************/
210
211} // namespace Tests::testDeviceExceptionFlagPropagation
#define CHECK_EQUAL_TIMEOUT(left, right, maxMilliseconds)
Model::RootProxy getModel()
Return the root of the application model.
Definition Application.h:75
void debugMakeConnections()
Enable debug output for the ConnectionMaker.
void shutdown() override
This will remove the global pointer to the instance and allows creating another instance afterwards.
void writeGraphViz(const std::string &filename, Args... args) const
Implementations of RootProxy.
Definition Model.h:1789
friend class Application
Definition ModuleGroup.h:47
bool write(ChimeraTK::VersionNumber versionNumber)=delete
Convenience class for input scalar accessors with UpdateMode::push.
Helper class to facilitate tests of applications based on ApplicationCore.
TYPE readScalar(const std::string &name)
Convenience function to read the latest value of a scalar process variable in a single call.
void writeScalar(const std::string &name, TYPE value)
Convenience function to write a scalar process variable in a single call.
void stepApplication(bool waitForDeviceInitialisation=true) const
Perform a "step" of the application.
void runApplication() const
Start the application in testable mode.
InvalidityTracer application module.
Convenience class for output scalar accessors (always UpdateMode::push)
Convenience class for input scalar accessors with UpdateMode::poll.
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
Tests::testDeviceExceptionFlagPropagation::TestApplication::Name::Name2 ctk::VariableGroup name
Tests::testDeviceExceptionFlagPropagation::TestApplication::Name::Name2 ctk::VariableGroup void prepare() override
Prepare the execution of the module.
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
Tests::testDeviceExceptionFlagPropagation::TestApplication::Module module
Tests::testDeviceExceptionFlagPropagation::TestApplication::Name name
#define CHECK_TIMEOUT(condition, maxMilliseconds)