Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#define BOOST_TEST_MODULE testDeviceExceptionFlagPropagation
#include <boost/test/included/unit_test.hpp>
using namespace boost::unit_test_framework;
#include <ChimeraTK/DummyRegisterAccessor.h>
#include "Application.h"
#include "ApplicationModule.h"
#include "ControlSystemModule.h"
#include "DeviceModule.h"
#include "ExceptionDevice.h"
#include "PeriodicTrigger.h"
#include "TestFacility.h"
#include "VariableGroup.h"
namespace ctk = ChimeraTK;
constexpr char ExceptionDummyCDD1[] = "(ExceptionDummy:1?map=test3.map)";
#define CHECK_TIMEOUT(condition, maxMilliseconds) \
{ \
std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); \
while(!(condition)) { \
bool timeout_reached = (std::chrono::steady_clock::now() - t0) > std::chrono::milliseconds(maxMilliseconds); \
BOOST_CHECK(!timeout_reached); \
if(timeout_reached) break; \
usleep(1000); \
} \
}
struct TestApplication : ctk::Application {
TestApplication() : Application("testSuite") {}
~TestApplication() { shutdown(); }
void defineConnections() {}
struct : ctk::ApplicationModule {
using ctk::ApplicationModule::ApplicationModule;
struct : ctk::VariableGroup {
using ctk::VariableGroup::VariableGroup;
ctk::ScalarOutput<uint64_t> tick{this, "tick", "", ""};
} name{this, "name", ""};
void mainLoop() override {}
} name{this, "name", ""};
struct : ctk::ApplicationModule {
using ctk::ApplicationModule::ApplicationModule;
mutable int readMode{0};
struct : ctk::VariableGroup {
using ctk::VariableGroup::VariableGroup;
ctk::ScalarPushInput<uint64_t> tick{this, "tick", "", ""};
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
ctk::ScalarPollInput<int> read{this, "readBack", "", ""};
ctk::ScalarOutput<int> set{this, "actuator", "", ""};
} vars{this, "vars", "", ctk::HierarchyModifier::hideThis};
void mainLoop() override {
while(true) {
vars.tick.read();
switch(readMode) {
case 0:
vars.read.readNonBlocking();
break;
case 1:
vars.read.readLatest();
break;
case 2:
vars.read.readAsync().wait();
break;
case 3:
vars.read.read();
break;
case 5:
vars.set.write();
break;
case 6:
vars.set.write();
break;
default:
break;
}
}
}
} module{this, "module", ""};
ctk::PeriodicTrigger trigger{this, "trigger", ""};
ctk::DeviceModule dev{this, ExceptionDummyCDD1};
ctk::ControlSystemModule cs;
};
BOOST_AUTO_TEST_CASE(testDirectConnectOpen) {
TestApplication app;
boost::shared_ptr<ExceptionDummy> dummyBackend1 = boost::dynamic_pointer_cast<ExceptionDummy>(
ChimeraTK::BackendFactory::getInstance().createBackend(ExceptionDummyCDD1));
app.dev("/MyModule/readBack", typeid(int), 1) >> app.module.vars.read;
app.module.vars.set >> app.dev("/MyModule/actuator", typeid(int), 1);
app.name.name.tick >> app.module.vars.tick;
// Open
dummyBackend1->throwExceptionOpen = true;
ctk::TestFacility test(false);
CHECK_TIMEOUT(app.module.vars.read.dataValidity() == ctk::DataValidity::ok, 1000);
app.run();
// Advance through all non-blocking read methods - write will block when open fails
while(app.module.readMode < 3) {
// Check
app.name.name.tick.write();
std::cout << "Checking read mode " << app.module.readMode << "\n";
CHECK_TIMEOUT(app.module.vars.read.dataValidity() == ctk::DataValidity::faulty, 1000);
// Reset data validity
app.module.vars.read.setDataValidity();
CHECK_TIMEOUT(app.module.vars.read.dataValidity() == ctk::DataValidity::ok, 1000);
// advance to the next read
app.module.readMode++;
}
// Unblock last read()
dummyBackend1->throwExceptionOpen = false;
app.module.vars.set.write();
}
BOOST_AUTO_TEST_CASE(testDirectConnectRead) {
TestApplication app;
boost::shared_ptr<ExceptionDummy> dummyBackend1 = boost::dynamic_pointer_cast<ExceptionDummy>(
ChimeraTK::BackendFactory::getInstance().createBackend(ExceptionDummyCDD1));
app.dev("/MyModule/readBack", typeid(int), 1) >> app.module.vars.read;
app.module.vars.set >> app.dev("/MyModule/actuator", typeid(int), 1);
app.trigger.tick >> app.module.vars.tick;
ctk::TestFacility test(true);
test.runApplication();
// Advance through all non-blocking read methods
while(app.module.readMode < 4) {
// Check
app.trigger.sendTrigger();
test.stepApplication();
BOOST_CHECK(app.module.vars.read.dataValidity() == ctk::DataValidity::ok);
// Check
std::cout << "Checking read mode " << app.module.readMode << "\n";
dummyBackend1->throwExceptionRead = true;
app.trigger.sendTrigger();
test.stepApplication();
BOOST_CHECK(app.module.vars.read.dataValidity() == ctk::DataValidity::faulty);
// advance to the next read
dummyBackend1->throwExceptionRead = false;
app.module.readMode++;
// Skip readAsync(). See https://github.com/ChimeraTK/ApplicationCore/issues/48
if(app.module.readMode == 2) app.module.readMode++;
}
}
BOOST_AUTO_TEST_CASE(testDirectConnectWrite) {
TestApplication app;
boost::shared_ptr<ExceptionDummy> dummyBackend1 = boost::dynamic_pointer_cast<ExceptionDummy>(
ChimeraTK::BackendFactory::getInstance().createBackend(ExceptionDummyCDD1));
app.dev("/MyModule/readBack", typeid(int), 1) >> app.module.vars.read;
app.module.vars.set >> app.dev("/MyModule/actuator", typeid(int), 1);
app.module.readMode = 5;
app.trigger.tick >> app.module.vars.tick;
ctk::TestFacility test(true);
test.runApplication();
// Advance through all non-blocking read methods
while(app.module.readMode < 7) {
// Check
app.trigger.sendTrigger();
test.stepApplication();
BOOST_CHECK(app.module.vars.set.dataValidity() == ctk::DataValidity::ok);
// Check
dummyBackend1->throwExceptionWrite = true;
app.trigger.sendTrigger();
test.stepApplication();
// write operations failing does not invalidate data
BOOST_CHECK(app.module.vars.set.dataValidity() == ctk::DataValidity::ok);
// advance to the next read
dummyBackend1->throwExceptionWrite = false;
app.module.readMode++;
}
}