ChimeraTK-DeviceAccess  03.18.00
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"
8 #include "sharedDummyHelpers.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 <algorithm>
16 #include <chrono>
17 #include <csignal>
18 #include <cstdlib>
19 #include <string>
20 #include <thread>
21 #include <unistd.h>
22 #include <utility>
23 #include <vector>
24 
25 namespace {
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 dmap-file to
35  // only use public interface here
36  static std::string instanceId{"1"};
37  static std::string mapFileName{"shareddummy.map"};
38 
39  static 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  boost::filesystem::path absPathToMapFile = boost::filesystem::absolute(mapFileName);
147 
148  std::string shmName{createExpectedShmName(instanceId, absPathToMapFile.string(), getUserName())};
149 
150  {
151  Device dev;
152  BOOST_CHECK(!dev.isOpened());
153  dev.open("SHDMEMDEV");
154  BOOST_CHECK(dev.isOpened());
155 
156  BOOST_CHECK(shm_exists(shmName));
157 
158  do {
159  ChimeraTK::OneDRegisterAccessor<int> processVarsRead = dev.getOneDRegisterAccessor<int>("FEATURE2/AREA1");
160  processVarsRead.read();
161 
162  ChimeraTK::OneDRegisterAccessor<int> processVarsWrite = dev.getOneDRegisterAccessor<int>("FEATURE2/AREA2");
163 
164  for(size_t i = 0; i < processVarsRead.getNElements(); ++i) {
165  processVarsWrite[i] = processVarsRead[i];
166  }
167  processVarsWrite.write();
168  } while(keepRunning && !terminationCaught);
169  dev.close();
170  }
171  }
172 
179  BOOST_AUTO_TEST_CASE(testWriteToReadOnly) {
180  setDMapFilePath("shareddummyTest.dmap");
181  Device dev;
182  dev.open("SHDMEMDEV");
183 
184  ScalarRegisterAccessor<int> roRegisterOne_dw{
185  dev.getScalarRegisterAccessor<int>("WORD_READ_ONLY_1.DUMMY_WRITEABLE")};
186  ScalarRegisterAccessor<int> roRegisterTwo{dev.getScalarRegisterAccessor<int>("WORD_READ_ONLY_2")};
187 
188  BOOST_CHECK(!roRegisterOne_dw.isReadOnly());
189  BOOST_CHECK(roRegisterOne_dw.isWriteable());
190  BOOST_CHECK(roRegisterTwo.isReadOnly());
191  BOOST_CHECK(!roRegisterTwo.isWriteable());
192 
193  BOOST_CHECK_THROW(roRegisterTwo.write(), ChimeraTK::logic_error);
194 
195  // Mirror to the other register
196  roRegisterTwo.read();
197  const int roRegisterTwoValue = roRegisterTwo;
198  roRegisterOne_dw = roRegisterTwoValue;
199  roRegisterOne_dw.write();
200 
201  // Check happens in the automativ test case.
202 
203  dev.close();
204  }
205 
213  BOOST_AUTO_TEST_CASE(testMakeMess) {
214  setDMapFilePath("shareddummyTest.dmap");
215 
216  Device dev;
217  dev.open("SHDMEMDEV");
218 
219  ChimeraTK::OneDRegisterAccessor<int> processVars = dev.getOneDRegisterAccessor<int>("FEATURE2/AREA1");
220 
221  int n = 0;
222  std::generate(processVars.begin(), processVars.end(), [n]() mutable { return n++; });
223  processVars.write();
224 
225  // Wait to be killed or timeout...
227 
228  dev.close();
229  }
230 
236  BOOST_AUTO_TEST_CASE(testVerifyCleanup) {
237  setDMapFilePath("shareddummyTest.dmap");
238 
239  Device dev;
240  dev.open("SHDMEMDEV");
241 
242  ChimeraTK::OneDRegisterAccessor<int> processVars = dev.getOneDRegisterAccessor<int>("FEATURE2/AREA1");
243  processVars.read();
244 
245  // Check if content is all zero
246  BOOST_CHECK(std::all_of(processVars.begin(), processVars.end(), [](int i) { return i == 0; }));
247 
248  dev.close();
249  }
250 
254  BOOST_AUTO_TEST_CASE(testVerifyMemoryDeleted) {
255  setDMapFilePath("shareddummyTest.dmap");
256 
257  boost::filesystem::path absPathToMapFile = boost::filesystem::absolute(mapFileName);
258 
259  std::string shmName{createExpectedShmName(instanceId, absPathToMapFile.string(), getUserName())};
260 
261  // Test if memory is removed
262  BOOST_CHECK(!shm_exists(shmName));
263  }
264 
265  /********************************************************************************************************************/
266  BOOST_AUTO_TEST_SUITE_END()
267 
268 
272  static void interrupt_handler(int signal) {
273  std::cout << "Caught interrupt signal (" << signal << "). Terminating..." << std::endl;
274  terminationCaught = true;
275  }
276 
277 } // anonymous namespace
ChimeraTK::OneDRegisterAccessor::end
iterator end()
Definition: OneDRegisterAccessor.h:61
ChimeraTK::Device::close
void close()
Close the device.
Definition: Device.cc:66
ChimeraTK::Device::getOneDRegisterAccessor
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:273
Utilities.h
ChimeraTK::testable_rebot_sleep::now
boost::chrono::steady_clock::time_point now()
Definition: testableRebotSleep.cc:7
ChimeraTK::OneDRegisterAccessor::getNElements
unsigned int getNElements()
Return number of elements/samples in the register.
Definition: OneDRegisterAccessor.h:51
ChimeraTK::testable_rebot_sleep::sleep_until
void sleep_until(boost::chrono::steady_clock::time_point t)
There are two implementations with the same signature: One that calls boost::thread::this_thread::sle...
Definition: testableRebotSleep.cc:16
TestFixture::TestFixture
TestFixture(uint32_t interrupt, bool activateAsyncFirst)
Definition: testGenericMuxedInterruptDistributor.cpp:90
ChimeraTK::ScalarRegisterAccessor
Accessor class to read and write scalar registers transparently by using the accessor object like a v...
Definition: ScalarRegisterAccessor.h:24
BOOST_FIXTURE_TEST_CASE
BOOST_FIXTURE_TEST_CASE(testSlowReader, DeviceFixture)
Definition: testDoubleBuffering.cpp:240
ChimeraTK::OneDRegisterAccessor
Accessor class to read and write registers transparently by using the accessor object like a vector o...
Definition: OneDRegisterAccessor.h:20
Device.h
createExpectedShmName
std::string createExpectedShmName(std::string instanceId_, std::string mapFileName_, std::string userName)
Definition: sharedDummyHelpers.h:16
sharedDummyHelpers.h
shm_exists
bool shm_exists(std::string shmName)
Definition: sharedDummyHelpers.h:24
ChimeraTK::Device
Class allows to read/write registers from device.
Definition: Device.h:39
ProcessManagement.h
ChimeraTK::Device::open
void open(std::string const &aliasName)
Open a device by the given alias name from the DMAP file.
Definition: Device.cc:58
ChimeraTK::Device::getScalarRegisterAccessor
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:263
ChimeraTK::OneDRegisterAccessor::begin
iterator begin()
Definition: OneDRegisterAccessor.h:58
ChimeraTK::Device::isOpened
bool isOpened() const
Check if the device is currently opened.
Definition: Device.cc:73
ChimeraTK::TransferElementAbstractor::write
bool write(ChimeraTK::VersionNumber versionNumber={})
Write the data to device.
Definition: TransferElementAbstractor.h:89
BOOST_AUTO_TEST_CASE
BOOST_AUTO_TEST_CASE(testSerialize)
Definition: testAccessModeFlags.cc:18
ChimeraTK::setDMapFilePath
void setDMapFilePath(std::string dmapFilePath)
Set the location of the dmap file.
Definition: Utilities.cpp:327
ChimeraTK
Definition: DummyBackend.h:16
ChimeraTK::TransferElementAbstractor::read
void read()
Read the data from the device.
Definition: TransferElementAbstractor.h:57
getUserName
std::string getUserName()
Definition: ProcessManagement.cpp:24
ChimeraTK::logic_error
Exception thrown when a logic error has occured.
Definition: Exception.h:51