ChimeraTK-ApplicationCore 04.06.00
Loading...
Searching...
No Matches
testPython.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 testPython
4
5#include "Application.h"
6#include "DeviceModule.h"
7#include "TestFacility.h"
8
9// #define BOOST_NO_EXCEPTIONS
10#include <boost/test/included/unit_test.hpp>
11// #undef BOOST_NO_EXCEPTIONS
12
13using namespace boost::unit_test_framework;
14namespace ctk = ChimeraTK;
15
17
18 /********************************************************************************************************************/
19
20 struct TestApp : public ctk::Application {
21 explicit TestApp(const std::string& name) : ctk::Application(name) {}
22 ~TestApp() override { shutdown(); }
23 };
24
25 /********************************************************************************************************************/
26 /* Very simple test with single Python module and nothing else */
27
28 BOOST_AUTO_TEST_CASE(testPythonModule) {
29 std::cout << "***************************************************************************************" << std::endl;
30 std::cout << "==> testPythonModule" << std::endl;
31
32 TestApp app("testPythonSimpleApp");
33 ctk::TestFacility tf(app);
34
35 auto var1 = tf.getScalar<float>("/Var1");
36 auto var2 = tf.getScalar<int32_t>("/Var2");
37
38 tf.runApplication();
39
40 var2.setAndWrite(42);
41 tf.stepApplication();
42 BOOST_TEST(var1.readNonBlocking());
43 BOOST_TEST(float(var1) == 42.5, boost::test_tools::tolerance(0.001));
44 }
45
46 /********************************************************************************************************************/
47 /* Test initial values */
48
49 BOOST_AUTO_TEST_CASE(testInitialValues) {
50 std::cout << "***************************************************************************************" << std::endl;
51 std::cout << "==> testInitialValues" << std::endl;
52
53 TestApp app("testPythonSimpleApp");
54 ctk::TestFacility tf(app);
55
56 auto var1 = tf.getScalar<float>("/Var1");
57 auto var2 = tf.getScalar<int32_t>("/Var2");
58
59 tf.setScalarDefault<int32_t>("/Var2", 10);
60
61 tf.runApplication();
62
63 BOOST_TEST(float(var1) == 0.5, boost::test_tools::tolerance(0.001));
64 }
65
66 /********************************************************************************************************************/
67 /* Test arrays */
68
70 std::vector<int32_t> ref(10);
71
72 std::cout << "***************************************************************************************" << std::endl;
73 std::cout << "==> testArrays" << std::endl;
74
75 TestApp app("testPythonWithArray");
76 ctk::TestFacility tf(app);
77
78 auto ArrayIn1 = tf.getArray<int32_t>("/SomeName/ArrayIn1");
79 auto ArrayIn2 = tf.getArray<int32_t>("/SomeName/ArrayIn2");
80 auto ArrayInPoll = tf.getArray<int32_t>("/SomeName/ArrayInPOLL");
81 auto ArrayInWB = tf.getArray<int32_t>("/SomeName/ArrayInWB");
82 auto ArrayOut1 = tf.getArray<int32_t>("/SomeName/ArrayOut1");
83 auto ArrayOut2 = tf.getArray<int32_t>("/SomeName/ArrayOut2");
84 auto error = tf.getScalar<std::string>("/SomeName/TestError");
85 auto error2 = tf.getScalar<std::string>("/Foo/TestError");
86
87 // set initial value
88 tf.setArrayDefault<int32_t>("/SomeName/ArrayIn1", {50, 5});
89
90 tf.runApplication();
91
92 ArrayInPoll = {42, 1};
93 ArrayInPoll.write();
94 ArrayInPoll = {43, 2};
95 ArrayInPoll.write();
96
97 ArrayInWB = {15};
98 ArrayInWB.write();
99
100 // check initial value
101 for(int i = 0; i < 10; ++i) ref[i] = 50 + 5 + i;
102 BOOST_TEST(std::vector<int32_t>(ArrayOut1) == ref, boost::test_tools::per_element());
103 // test readAndGet()
104 ArrayIn2 = {2, 3, 4, 5, 6};
105 ArrayIn2.write();
106 tf.stepApplication();
107 BOOST_TEST(ArrayOut2.readNonBlocking());
108 for(int i = 0; i < 10; ++i) ref[i] = 2 + 3 + 4 + 5 + 6 + i;
109 BOOST_TEST(std::vector<int32_t>(ArrayOut2) == ref, boost::test_tools::per_element());
110
111 BOOST_TEST(ArrayInWB.readNonBlocking());
112 BOOST_TEST(std::vector<int32_t>(ArrayInWB) == std::vector<int32_t>({28}));
113
114 // test read() -> get()
115 ArrayIn1 = {100, 20};
116 ArrayIn1.write();
117 tf.stepApplication();
118 BOOST_TEST(ArrayOut1.readNonBlocking());
119 for(int i = 0; i < 10; ++i) ref[i] = 100 + 20 + i;
120 BOOST_TEST(std::vector<int32_t>(ArrayOut1) == ref, boost::test_tools::per_element());
121
122 // check result of the Python-side tests
123 BOOST_TEST(error.readNonBlocking() == false);
124 BOOST_TEST(std::string(error) == "");
125 BOOST_TEST(error2.readNonBlocking() == false);
126 BOOST_TEST(std::string(error2) == "");
127 }
128
129 /********************************************************************************************************************/
130 /* Test scalars */
131
132 BOOST_AUTO_TEST_CASE(testScalars) {
133 std::cout << "***************************************************************************************" << std::endl;
134 std::cout << "==> testScalars" << std::endl;
135
136 TestApp app("testPythonScalarAccessors");
137 ctk::TestFacility tf(app);
138
139 auto result = tf.getScalar<std::string>("/Test/Result");
140
141 tf.runApplication();
142
143 result.readNonBlocking();
144 BOOST_TEST(std::string(result) == "Scalar test did not produce any Python Errors");
145 }
146
147 /********************************************************************************************************************/
148 /* Test appConfig group */
149
150 BOOST_AUTO_TEST_CASE(testAppConfig) {
151 std::cout << "***************************************************************************************" << std::endl;
152 std::cout << "==> testAppConfig" << std::endl;
153
154 TestApp app("testPythonAppConfig");
155 ctk::TestFacility tf(app);
156 auto result = tf.getScalar<std::string>("/UserModule/testError");
157
158 tf.runApplication();
159 result.readLatest();
160 BOOST_TEST(std::string(result) == "");
161 }
162
163 /********************************************************************************************************************/
164 /* Test variable group */
165
166 BOOST_AUTO_TEST_CASE(testVariableGroup) {
167 std::cout << "***************************************************************************************" << std::endl;
168 std::cout << "==> testVariableGroup" << std::endl;
169
170 TestApp app("testPythonVariableGroup");
171 ctk::TestFacility tf(app);
172
173 auto in1 = tf.getArray<int32_t>("/UserModule/VG/in1");
174 auto out1 = tf.getScalar<int32_t>("/UserModule/VG/out1");
175 auto out2 = tf.getArray<int32_t>("/UserModule/VG2/out2");
176 auto out3 = tf.getArray<int32_t>("/UserModule/VG2/VG3/out3");
177 auto result = tf.getScalar<std::string>("/UserModule/testError");
178
179 tf.runApplication();
180
181 out1.readLatest();
182 BOOST_TEST(out1 == 1);
183
184 in1 = {2, 3};
185 in1.write();
186 tf.stepApplication();
187 out2.readLatest();
188 BOOST_TEST(std::vector<int32_t>(out2) == std::vector<int32_t>(in1), boost::test_tools::per_element());
189 out3.readLatest();
190 BOOST_TEST(std::vector<int32_t>(out3) == std::vector<int32_t>(in1), boost::test_tools::per_element());
191 result.readLatest();
192 BOOST_TEST(std::string(result) == "");
193 }
194
195 /********************************************************************************************************************/
196 /* Test module group */
197
198 BOOST_AUTO_TEST_CASE(testModuleGroup) {
199 std::cout << "***************************************************************************************" << std::endl;
200 std::cout << "==> testModuleGroup" << std::endl;
201
202 TestApp app("testPythonVariableGroup");
203 ctk::TestFacility tf(app);
204
205 auto in1 = tf.getArray<int32_t>("/SomeGroup/UserModuleInGroup/VG/in1");
206 auto out1 = tf.getScalar<int32_t>("/SomeGroup/UserModuleInGroup/VG/out1");
207 auto out2 = tf.getArray<int32_t>("/SomeGroup/UserModuleInGroup/VG2/out2");
208 auto out3 = tf.getArray<int32_t>("/SomeGroup/UserModuleInGroup/VG2/VG3/out3");
209 auto result = tf.getScalar<std::string>("/SomeGroup/UserModuleInGroup/testError");
210
211 tf.runApplication();
212
213 out1.readLatest();
214 BOOST_TEST(out1 == 1);
215
216 in1 = {2, 3};
217 in1.write();
218 tf.stepApplication();
219 out2.readLatest();
220 BOOST_TEST(std::vector<int32_t>(out2) == std::vector<int32_t>(in1), boost::test_tools::per_element());
221 out3.readLatest();
222 BOOST_TEST(std::vector<int32_t>(out3) == std::vector<int32_t>(in1), boost::test_tools::per_element());
223 result.readLatest();
224 BOOST_TEST(std::string(result) == "");
225 }
226
227 /********************************************************************************************************************/
228 /* Test ApplicationModule */
229
230 BOOST_AUTO_TEST_CASE(testApplicationModule) {
231 std::cout << "***************************************************************************************" << std::endl;
232 std::cout << "==> testApplicationModule" << std::endl;
233
234 TestApp app("testPythonApplicationModule");
235 ctk::TestFacility tf(app);
236
237 auto result = tf.getScalar<std::string>("/UserModule/testError");
238
239 tf.runApplication();
240
241 auto list = app.getSubmoduleList();
242 for(auto* mod : list) {
243 if(mod->getName() == "DisabledMod") {
244 // This was disabled in python and should not show up here at all
245 BOOST_CHECK(false);
246 }
247 }
248
249 BOOST_CHECK(!result.readNonBlocking());
250 BOOST_TEST(std::string(result) == "");
251 }
252
253 /********************************************************************************************************************/
254 /* Test DataConsistencyGroup */
255
256 BOOST_AUTO_TEST_CASE(testDataConsistencyGroup) {
257 std::cout << "***************************************************************************************" << std::endl;
258 std::cout << "==> testDataConsistencyGroup" << std::endl;
259
260 TestApp app("testPythonDataConsistencyGroup");
261
262 ctk::TestFacility tf(app);
263
264 auto result = tf.getScalar<std::string>("/UserModule/testError");
265
266 tf.runApplication();
267
268 result.readLatest();
269 BOOST_TEST(std::string(result) == "ok");
270 }
271
272 /********************************************************************************************************************/
273
275 TestAppReadAny(const std::string& name) : ctk::Application(name) {}
276 ~TestAppReadAny() override { shutdown(); }
277 };
278
279 BOOST_AUTO_TEST_CASE(testReadAnyGroup) {
280 std::cout << "***************************************************************************************" << std::endl;
281 std::cout << "==> testReadAnyGroup" << std::endl;
282
283 TestAppReadAny app("testPythonReadAnyGroup");
284 ctk::TestFacility tf(app);
285
286 auto result = tf.getScalar<std::string>("/UserModule/testError");
287 auto in1 = tf.getScalar<int32_t>("/UserModule/in1");
288 auto in2 = tf.getArray<int32_t>("/UserModule/in2");
289 auto in3 = tf.getScalar<int32_t>("/UserModule/in3");
290 auto out = tf.getScalar<std::string>("/UserModule/output");
291
292 tf.runApplication();
293
294 in1.setAndWrite(12);
295 tf.stepApplication();
296 BOOST_CHECK(out.readNonBlocking());
297 BOOST_TEST(std::string(out) == "step1");
298
299 in2 = {24, 24, 24, 24};
300 in2.write();
301 tf.stepApplication();
302 BOOST_CHECK(out.readNonBlocking());
303 BOOST_CHECK(std::string(out) == "step2");
304
305 in3.setAndWrite(36);
306 tf.stepApplication();
307 BOOST_CHECK(out.readNonBlocking());
308 BOOST_CHECK(std::string(out) == "step3");
309
310 in1.setAndWrite(8);
311 tf.stepApplication();
312 BOOST_CHECK(out.readNonBlocking());
313 BOOST_CHECK(std::string(out) == "step4");
314
315 in2 = {16, 16, 16, 16};
316 in2.write();
317 tf.stepApplication();
318 BOOST_CHECK(out.readNonBlocking());
319 BOOST_CHECK(std::string(out) == "step5");
320
321 in1.setAndWrite(13);
322 tf.stepApplication();
323 BOOST_CHECK(!out.readNonBlocking());
324
325 in2 = {26, 26, 26, 26};
326 in2.write();
327 tf.stepApplication();
328 BOOST_CHECK(out.readNonBlocking());
329 BOOST_CHECK(std::string(out) == "step6");
330
331 in1.setAndWrite(42);
332 tf.stepApplication();
333 BOOST_CHECK(out.readNonBlocking());
334 BOOST_CHECK(std::string(out) == "step7");
335
336 BOOST_CHECK(!result.readNonBlocking());
337 BOOST_TEST(std::string(result) == "");
338 }
339
340 /********************************************************************************************************************/
341
343 explicit TestAppVersionNumber(const std::string& name) : ctk::Application(name) {}
345 };
346
347 /********************************************************************************************************************/
348 /* Very simple test with single Python module and nothing else */
349
351 std::cout << "***************************************************************************************" << std::endl;
352 std::cout << "==> testPythonVersionNumber" << std::endl;
353
354 TestAppVersionNumber app("testPythonVersionNumber");
355 ctk::TestFacility tf(app);
356
357 tf.runApplication();
358
359 // check result of the Python-side tests
360 auto error = tf.getScalar<std::string>("/VersionTestRunner/TestError");
361 BOOST_TEST(error.readNonBlocking() == false);
362 BOOST_TEST(std::string(error) == "");
363 }
364
365 /********************************************************************************************************************/
366
368 explicit TestAppUserInputValiador(const std::string& name) : ctk::Application(name) {}
370 };
371
372 /********************************************************************************************************************/
373
375 std::cout << "***************************************************************************************" << std::endl;
376 std::cout << "==> testPythonUserInputValidator" << std::endl;
377
378 TestAppUserInputValiador app("testPythonUserInputValidator");
379 ctk::TestFacility tf(app);
380
381 tf.setScalarDefault("/UserInputValidatorTestRunner/in1", 12);
382 tf.setArrayDefault("/UserInputValidatorTestRunner/in2", std::vector<int>{10, 10, 10, 10, 10});
383
384 auto input = tf.getScalar<int>("/UserInputValidatorTestRunner/in1");
385 auto input2 = tf.getArray<int>("/UserInputValidatorTestRunner/in2");
386 auto errorFunctionCalled = tf.getVoid("/UserInputValidatorTestRunner/errorFunctionCalled");
387
388 tf.runApplication();
389
390 // The initial values were wrong and were corrected
391 auto error = tf.getScalar<std::string>("/UserInputValidatorTestRunner/TestError");
392 // Should have two values in queue because both two validators failed
393 BOOST_TEST(errorFunctionCalled.readNonBlocking() == true);
394 BOOST_TEST(errorFunctionCalled.readNonBlocking() == true);
395 BOOST_TEST(error.readNonBlocking() == false);
396 BOOST_TEST(std::string(error) == "");
397
398 input.setAndWrite(8);
399 tf.stepApplication();
400 BOOST_TEST(!input.readLatest());
401 BOOST_TEST(error.readNonBlocking() == false);
402 BOOST_TEST(std::string(error) == "");
403
404 input.setAndWrite(10);
405 tf.stepApplication();
406 BOOST_TEST(input.readLatest());
407 BOOST_TEST(input == 8);
408 BOOST_TEST(errorFunctionCalled.readNonBlocking() == true);
409 BOOST_TEST(error.readNonBlocking() == false);
410 BOOST_TEST(std::string(error) == "");
411
412 input2 = std::vector{2, 2, 2, 2, 1};
413 input2.write();
414 tf.stepApplication();
415 BOOST_TEST(!input2.readLatest());
416 BOOST_TEST(errorFunctionCalled.readNonBlocking() == false);
417 BOOST_CHECK(static_cast<const std::vector<int>&>(input2) == std::vector<int>({2, 2, 2, 2, 1}));
418 BOOST_TEST(error.readNonBlocking() == false);
419 BOOST_TEST(std::string(error) == "");
420
421 input2 = std::vector{1, 2, 3, 4, 5};
422 input2.write();
423 tf.stepApplication();
424 BOOST_TEST(input2.readLatest());
425 BOOST_TEST(errorFunctionCalled.readNonBlocking() == true);
426 BOOST_CHECK(static_cast<const std::vector<int>&>(input2) == std::vector<int>({2, 2, 2, 2, 1}));
427 BOOST_TEST(error.readNonBlocking() == false);
428 BOOST_TEST(std::string(error) == "");
429
430 input2 = std::vector{9, 0, 0, 0, 0};
431 input2.write();
432 tf.stepApplication();
433 BOOST_TEST(input2.readLatest());
434 BOOST_TEST(errorFunctionCalled.readNonBlocking() == true);
435 BOOST_CHECK(static_cast<const std::vector<int>&>(input2) == std::vector<int>({2, 2, 2, 2, 1}));
436 BOOST_TEST(error.readNonBlocking() == false);
437 BOOST_TEST(std::string(error) == "");
438 }
439
440 /********************************************************************************************************************/
441
442} // namespace Tests::testPython
void shutdown() override
This will remove the global pointer to the instance and allows creating another instance afterwards.
std::list< Module * > getSubmoduleList() const
Obtain the list of submodules associated with this instance.
Definition EntityOwner.h:80
friend class Application
Definition ModuleGroup.h:47
Helper class to facilitate tests of applications based on ApplicationCore.
ChimeraTK::OneDRegisterAccessor< T > getArray(const ChimeraTK::RegisterPath &name) const
Obtain an array-type process variable from the application, which is published to the control system.
void stepApplication(bool waitForDeviceInitialisation=true) const
Perform a "step" of the application.
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.
void setArrayDefault(const ChimeraTK::RegisterPath &name, const std::vector< T > &value)
Set default value for array process variable.
void setScalarDefault(const ChimeraTK::RegisterPath &name, const T &value)
Set default value for scalar process variable.
InvalidityTracer application module.
BOOST_AUTO_TEST_CASE(testPythonModule)
Definition testPython.cc:28
TestApp(const std::string &name)
Definition testPython.cc:21
TestAppReadAny(const std::string &name)
TestAppUserInputValiador(const std::string &name)
TestAppVersionNumber(const std::string &name)