ChimeraTK-DeviceAccess 03.25.00
Loading...
Searching...
No Matches
testSharedDummyBackendExt.cpp
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
4#define BOOST_TEST_DYN_LINK
5#define BOOST_TEST_MODULE SharedDummyBackendTest
6#include "Device.h"
7#include "ProcessManagement.h"
9#include "Utilities.h"
10
11#include <boost/filesystem.hpp>
12#include <boost/interprocess/managed_shared_memory.hpp>
13#include <boost/test/unit_test.hpp>
14
15#include <unistd.h>
16
17#include <algorithm>
18#include <chrono>
19#include <csignal>
20#include <cstdlib>
21#include <string>
22#include <thread>
23#include <vector>
24
25namespace {
26
27 using namespace ChimeraTK;
28 using namespace boost::unit_test_framework;
29
30 // Static function prototypes
31 static void interrupt_handler(int);
32
33 // Static variables
34 // Use hardcoded information from the shareddummyTest.dmap to only use public interface here.
35 std::string mapFileName{"shareddummy.map"};
36 std::size_t instanceIdHash = Utilities::shmDummyInstanceIdHash("1", {{"map", mapFileName}});
37 std::string shmName{Utilities::createShmName(instanceIdHash, mapFileName, getUserName())};
38
39 bool terminationCaught = false;
40
41 BOOST_AUTO_TEST_SUITE(SharedDummyBackendTestSuite)
42
43 struct TestFixture {
44 TestFixture() : argc(framework::master_test_suite().argc), argv(framework::master_test_suite().argv) {}
45
46 int argc;
47 char** argv;
48 };
49
50 /********************************************************************************************************************/
51
52 BOOST_FIXTURE_TEST_CASE(testRobustnessMain, TestFixture) {
53 unsigned nIterations = 0;
54 if(argc != 2) {
55 std::cout << "Illegal number of arguments. Test case must be called with "
56 "the number of read/write cycles!"
57 << std::endl;
58 }
59 else {
60 nIterations = atoi(argv[1]);
61 }
62
63 setDMapFilePath("shareddummyTest.dmap");
64
65 bool readbackCorrect = false;
66 bool waitingForResponse = true;
67 const unsigned maxIncorrectIterations = 20; /* Timeout while waiting for 2nd application */
68 unsigned iterations = 0;
69 unsigned incorrectIterations = 0;
70
71 Device dev;
72 BOOST_CHECK(!dev.isOpened());
73 dev.open("SHDMEMDEV");
74 BOOST_CHECK(dev.isOpened());
75
76 ChimeraTK::OneDRegisterAccessor<int> processVarsWrite = dev.getOneDRegisterAccessor<int>("FEATURE2/AREA1");
77 std::vector<int> processVarsOld(processVarsWrite.getNElements(), 0);
78
79 do {
80 // Write some values to the shared memory
81 for(size_t i = 0; i < processVarsWrite.getNElements(); ++i) {
82 processVarsWrite[i] = i + iterations;
83 }
84 processVarsWrite.write();
85
86 // Check if values have been written back by the other application
87 ChimeraTK::OneDRegisterAccessor<int> processVarsRead = dev.getOneDRegisterAccessor<int>("FEATURE2/AREA2");
88 // Read as long as the readback from last iteration has been overwritten
89 do {
90 processVarsRead.read();
91 } while((std::vector<int>)processVarsRead == (std::vector<int>)processVarsOld && !waitingForResponse);
92
93 if((std::vector<int>)processVarsWrite == (std::vector<int>)processVarsRead) {
94 if(waitingForResponse) {
95 waitingForResponse = false;
96 }
97 readbackCorrect = true;
98 }
99 else {
100 readbackCorrect = false;
101 if(!waitingForResponse) {
102 std::cout << "Corrupted data detected:" << std::endl;
103 for(const auto pvr : processVarsRead) {
104 std::cout << " " << pvr << std::endl;
105 }
106 }
107 }
108
109 if(waitingForResponse) {
110 incorrectIterations++;
111 }
112 else {
113 iterations++;
114 }
115 processVarsOld = processVarsWrite;
116 } while((readbackCorrect || waitingForResponse) && incorrectIterations != maxIncorrectIterations &&
117 iterations != nIterations);
118
119 BOOST_CHECK(readbackCorrect);
120 std::cout << "Finished test after " << iterations << " of " << nIterations << " Iterations." << std::endl;
121 if(incorrectIterations == maxIncorrectIterations) {
122 std::cout << "Test cancelled because echoing process did not respond!" << std::endl;
123 }
124
125 dev.close();
126 }
127
135 BOOST_FIXTURE_TEST_CASE(testReadWrite, TestFixture) {
136 signal(SIGINT, interrupt_handler);
137
138 bool keepRunning = false;
139
140 if(argc >= 2 && !strcmp(argv[1], "KEEP_RUNNING")) {
141 keepRunning = true;
142 }
143
144 setDMapFilePath("shareddummyTest.dmap");
145
146 {
147 Device dev;
148 BOOST_CHECK(!dev.isOpened());
149 dev.open("SHDMEMDEV");
150 BOOST_CHECK(dev.isOpened());
151
152 BOOST_CHECK(shm_exists(shmName));
153
154 do {
155 ChimeraTK::OneDRegisterAccessor<int> processVarsRead = dev.getOneDRegisterAccessor<int>("FEATURE2/AREA1");
156 processVarsRead.read();
157
158 ChimeraTK::OneDRegisterAccessor<int> processVarsWrite = dev.getOneDRegisterAccessor<int>("FEATURE2/AREA2");
159
160 for(size_t i = 0; i < processVarsRead.getNElements(); ++i) {
161 processVarsWrite[i] = processVarsRead[i];
162 }
163 processVarsWrite.write();
164 } while(keepRunning && !terminationCaught);
165 dev.close();
166 }
167 }
168
175 BOOST_AUTO_TEST_CASE(testWriteToReadOnly) {
176 setDMapFilePath("shareddummyTest.dmap");
177 Device dev;
178 dev.open("SHDMEMDEV");
179
180 ScalarRegisterAccessor<int> roRegisterOne_dw{
181 dev.getScalarRegisterAccessor<int>("WORD_READ_ONLY_1.DUMMY_WRITEABLE")};
182 ScalarRegisterAccessor<int> roRegisterTwo{dev.getScalarRegisterAccessor<int>("WORD_READ_ONLY_2")};
183
184 BOOST_CHECK(!roRegisterOne_dw.isReadOnly());
185 BOOST_CHECK(roRegisterOne_dw.isWriteable());
186 BOOST_CHECK(roRegisterTwo.isReadOnly());
187 BOOST_CHECK(!roRegisterTwo.isWriteable());
188
189 BOOST_CHECK_THROW(roRegisterTwo.write(), ChimeraTK::logic_error);
190
191 // Mirror to the other register
192 roRegisterTwo.read();
193 const int roRegisterTwoValue = roRegisterTwo;
194 roRegisterOne_dw = roRegisterTwoValue;
195 roRegisterOne_dw.write();
196
197 // Check happens in the automativ test case.
198
199 dev.close();
200 }
201
209 BOOST_AUTO_TEST_CASE(testMakeMess) {
210 setDMapFilePath("shareddummyTest.dmap");
211
212 Device dev;
213 dev.open("SHDMEMDEV");
214
215 ChimeraTK::OneDRegisterAccessor<int> processVars = dev.getOneDRegisterAccessor<int>("FEATURE2/AREA1");
216
217 int n = 0;
218 std::generate(processVars.begin(), processVars.end(), [n]() mutable { return n++; });
219 processVars.write();
220
221 // Wait to be killed or timeout...
222 std::this_thread::sleep_until(std::chrono::system_clock::now() + std::chrono::seconds(20));
223
224 dev.close();
225 }
226
232 BOOST_AUTO_TEST_CASE(testVerifyCleanup) {
233 setDMapFilePath("shareddummyTest.dmap");
234
235 Device dev;
236 dev.open("SHDMEMDEV");
237
238 ChimeraTK::OneDRegisterAccessor<int> processVars = dev.getOneDRegisterAccessor<int>("FEATURE2/AREA1");
239 processVars.read();
240
241 // Check if content is all zero
242 BOOST_CHECK(std::all_of(processVars.begin(), processVars.end(), [](int i) { return i == 0; }));
243
244 dev.close();
245 }
246
250 BOOST_AUTO_TEST_CASE(testVerifyMemoryDeleted) {
251 setDMapFilePath("shareddummyTest.dmap");
252
253 // Test if memory is removed
254 BOOST_CHECK(!shm_exists(shmName));
255 }
256
257 /********************************************************************************************************************/
258 BOOST_AUTO_TEST_SUITE_END()
259
260
264 static void interrupt_handler(int signal) {
265 std::cout << "Caught interrupt signal (" << signal << "). Terminating..." << std::endl;
266 terminationCaught = true;
267 }
268
269} // anonymous namespace
std::string getUserName()
Class allows to read/write registers from device.
Definition Device.h:39
bool isOpened() const
Check if the device is currently opened.
Definition Device.cc:73
void close()
Close the device.
Definition Device.cc:66
ScalarRegisterAccessor< UserType > getScalarRegisterAccessor(const RegisterPath &registerPathName, size_t wordOffsetInRegister=0, const AccessModeFlags &flags=AccessModeFlags({})) const
Get a ScalarRegisterObject object for the given register.
Definition Device.h:266
OneDRegisterAccessor< UserType > getOneDRegisterAccessor(const RegisterPath &registerPathName, size_t numberOfWords=0, size_t wordOffsetInRegister=0, const AccessModeFlags &flags=AccessModeFlags({})) const
Get a OneDRegisterAccessor object for the given register.
Definition Device.h:276
void open(std::string const &aliasName)
Open a device by the given alias name from the DMAP file.
Definition Device.cc:58
Accessor class to read and write registers transparently by using the accessor object like a vector o...
unsigned int getNElements()
Return number of elements/samples in the register.
Accessor class to read and write scalar registers transparently by using the accessor object like a v...
bool write(ChimeraTK::VersionNumber versionNumber={})
Write the data to device.
void read()
Read the data from the device.
Exception thrown when a logic error has occured.
Definition Exception.h:51
std::size_t shmDummyInstanceIdHash(const std::string &address, const std::map< std::string, std::string > &parameters)
Generates shm dummy instanceId hash from address and parameter map, Intended for use with parseDevice...
std::string createShmName(std::size_t instanceIdHash, const std::string &mapFileName, const std::string &userName)
Generates shm dummy name from parameter hashes.
void setDMapFilePath(std::string dmapFilePath)
Set the location of the dmap file.
bool shm_exists(std::string shmName)
BOOST_AUTO_TEST_CASE(testSerialize)
BOOST_FIXTURE_TEST_CASE(testSlowReader, DeviceFixture)