5#define BOOST_TEST_DYN_LINK
6#define BOOST_TEST_MODULE DataConsistencyGroupTest
7#include <boost/test/unit_test.hpp>
8using namespace boost::unit_test_framework;
16BOOST_AUTO_TEST_SUITE(HistorizedDataMatchingTestSuite)
23 unsigned numDiscarded = 0;
25 while((
id = rag.readAnyNonBlocking()).isValid()) {
38 dev.
open(
"(logicalNameMap?map=historizedDataMatching.xlmap)");
48 gettimeofday(&now,
nullptr);
49 timeout.tv_sec = now.tv_sec + 1;
50 timeout.tv_nsec = now.tv_usec * 300;
51 sem_timedwait(&
sem, &timeout);
56 void updaterLoop(
unsigned nLoops,
unsigned delay,
unsigned duplicateVns = 0,
bool catchUp =
false) {
57 std::cout <<
"updaterLoop: delay=" << delay <<
", duplicateVns=" << duplicateVns << std::endl;
61 std::vector<ChimeraTK::VersionNumber> vs(nLoops);
62 for(
unsigned loopCount = 0; loopCount < nLoops; loopCount++) {
63 std::cout <<
"updaterLoop: writing value " << loopCount << std::endl;
64 accA = (int32_t)loopCount;
68 if(loopCount > 0 && duplicateVns > 0) {
69 vs[loopCount] = vs[loopCount - 1];
75 accA.write(vs[loopCount]);
76 if(loopCount >= delay) {
77 accB = (int32_t)(loopCount - delay);
78 accB.write(vs[loopCount - delay]);
80 if(loopCount == nLoops - 1 && delay > 0 && catchUp) {
82 for(
unsigned i = loopCount - delay + 1; i < nLoops; i++) {
89 std::cout <<
"updaterLoop: exception, wait and retry write.." << std::endl;
90 std::this_thread::sleep_for(std::chrono::milliseconds{500});
116 std::cout <<
"test1: no history" << std::endl;
118 const unsigned nLoops = 4;
119 for(
unsigned delay = 0; delay <= 2; delay++) {
121 unsigned nUpdates = 0;
122 unsigned nConsistentUpdates = 0;
123 std::thread updaterThread1([&]() { updaterLoop(nLoops, delay); });
127 auto id = rag.readAny();
128 auto& acc =
id == readAccA.getId() ? readAccA : readAccB;
129 std::cout <<
"readAny: seeing update for target " << acc.getName() <<
" vs " << acc.getVersionNumber()
133 if(readAccA.getVersionNumber() == readAccB.getVersionNumber()) {
134 nConsistentUpdates++;
136 if(
id == readAccA.getId()) {
141 catch(boost::thread_interrupted& e) {
142 std::cout <<
"thread interrupted" << std::endl;
144 updaterThread1.join();
146 unsigned nExpectedConsistentUpdates = (delay == 0) ? nUpdates / 2 : 0;
147 BOOST_TEST(nConsistentUpdates == nExpectedConsistentUpdates);
148 BOOST_TEST(nUpdates == nLoops + nLoops - delay);
151 std::cout <<
"test1: with history" << std::endl;
154 for(
unsigned delay = 0; delay <= 2; delay++) {
158 unsigned nUpdates = 0;
159 unsigned nConsistentUpdates = 0;
160 std::thread updaterThread1([&]() { updaterLoop(nLoops, delay); });
164 auto id = rag.readAny();
165 bool isConsistent = dg.update(
id);
167 if(readAccA.getVersionNumber() == readAccB.getVersionNumber()) {
168 nConsistentUpdates++;
171 BOOST_TEST(isConsistent);
172 BOOST_TEST(readAccA.getVersionNumber() == readAccB.getVersionNumber());
173 BOOST_TEST(readAccA == readAccB);
178 catch(boost::thread_interrupted& e) {
179 std::cout <<
"thread interrupted" << std::endl;
181 updaterThread1.join();
182 BOOST_TEST(nConsistentUpdates == nLoops - delay);
183 BOOST_TEST(nConsistentUpdates == nUpdates);
188 std::cout <<
"testDuplicateVns" << std::endl;
194 const unsigned nLoops = 4;
195 const unsigned nDuplicateVns = 1;
197 for(
unsigned delay = 0; delay <= 2; delay++) {
201 unsigned nUpdates = 0;
202 unsigned nConsistentUpdates = 0;
203 std::thread updaterThread1([&]() { updaterLoop(nLoops, delay, nDuplicateVns); });
207 auto id = rag.readAny();
209 bool isConsistent = dg.update(
id);
210 if(readAccA.getVersionNumber() == readAccB.getVersionNumber()) {
211 nConsistentUpdates++;
214 BOOST_TEST(isConsistent);
215 BOOST_TEST(readAccA.getVersionNumber() == readAccB.getVersionNumber());
220 catch(boost::thread_interrupted& e) {
221 std::cout <<
"thread interrupted" << std::endl;
223 updaterThread1.join();
224 unsigned nExpectedUpdates = nLoops - delay;
229 BOOST_TEST(nConsistentUpdates == nExpectedUpdates);
230 BOOST_TEST(nConsistentUpdates == nUpdates);
235 std::cout <<
"testExceptions" << std::endl;
240 const unsigned nLoops = 6;
241 const unsigned delay = 0;
246 unsigned nUpdates = 0;
247 unsigned nConsistentUpdates = 0;
248 std::thread updaterThread1([&]() { updaterLoop(nLoops, delay); });
253 auto id = rag.readAny();
254 auto& acc =
id == readAccA.getId() ? readAccA : readAccB;
255 std::cout <<
"readAny: seeing update for target " << acc.getName() <<
" vs " << acc.getVersionNumber()
256 <<
" values " << readAccA <<
"," << readAccB << std::endl;
258 bool isConsistent = dg.update(
id);
260 if(readAccA.getVersionNumber() == readAccB.getVersionNumber()) {
261 nConsistentUpdates++;
264 BOOST_TEST(isConsistent);
265 BOOST_TEST(readAccA.getVersionNumber() == readAccB.getVersionNumber());
266 BOOST_TEST(readAccA == readAccB);
271 dev.setException(
"exception");
273 dev.activateAsyncRead();
280 catch(boost::thread_interrupted& e) {
281 std::cout <<
"thread interrupted" << std::endl;
284 std::cout <<
"runtime error: " << e.what() << std::endl;
288 updaterThread1.join();
290 BOOST_TEST(nConsistentUpdates == nLoops - delay + 1);
291 BOOST_TEST(nConsistentUpdates == nUpdates);
296 std::cout <<
"testCatchUp" << std::endl;
301 const unsigned nLoops = 6;
302 const unsigned delay = 2;
307 unsigned nUpdates = 0;
308 unsigned nConsistentUpdates = 0;
309 std::thread updaterThread1([&]() { updaterLoop(nLoops, delay,
false,
true); });
314 auto id = rag.readAny();
315 auto& acc =
id == readAccA.getId() ? readAccA : readAccB;
316 std::cout <<
"readAny: seeing update for target " << acc.getName() <<
" vs " << acc.getVersionNumber()
317 <<
" values " << readAccA <<
"," << readAccB << std::endl;
319 bool isConsistent = dg.update(
id);
321 if(readAccA.getVersionNumber() == readAccB.getVersionNumber()) {
322 nConsistentUpdates++;
325 BOOST_TEST(isConsistent);
326 BOOST_TEST(readAccA.getVersionNumber() == readAccB.getVersionNumber());
327 BOOST_TEST(readAccA == readAccB);
333 catch(boost::thread_interrupted& e) {
334 std::cout <<
"thread interrupted" << std::endl;
337 updaterThread1.join();
338 BOOST_TEST(nConsistentUpdates == nLoops);
339 BOOST_TEST(nConsistentUpdates == nUpdates);
343 std::cout <<
"testInitialValues" << std::endl;
352 BOOST_TEST(nDiscarded == 1);
354 BOOST_TEST(readAccA.getVersionNumber() !=
VersionNumber(
nullptr));
355 BOOST_TEST(readAccB.getVersionNumber() !=
VersionNumber(
nullptr));
359 std::cout <<
"testIllegalUse" << std::endl;
368BOOST_AUTO_TEST_SUITE_END()
Group several registers (= TransferElement) which ensures data consistency across multiple variables ...
Class allows to read/write registers from device.
ScalarRegisterAccessor< UserType > getScalarRegisterAccessor(const RegisterPath ®isterPathName, size_t wordOffsetInRegister=0, const AccessModeFlags &flags=AccessModeFlags({})) const
Get a ScalarRegisterObject object for the given register.
void activateAsyncRead() noexcept
Activate asyncronous read for all transfer elements where AccessMode::wait_for_new_data is set.
void open(std::string const &aliasName)
Open a device by the given alias name from the DMAP file.
void replace(const NDRegisterAccessorAbstractor< UserType > &newAccessor)
Assign a new accessor to this NDRegisterAccessorAbstractor.
Group several registers (= TransferElement) to allow waiting for an update of any of the registers.
Accessor class to read and write scalar registers transparently by using the accessor object like a v...
void interrupt()
Return from a blocking read immediately and throw boost::thread_interrupted.
Simple class holding a unique ID for a TransferElement.
Class for generating and holding version numbers without exposing a numeric representation.
Exception thrown when a logic error has occured.
Exception thrown when a runtime error has occured.
ScalarRegisterAccessor< int32_t > readAccB
ScalarRegisterAccessor< int32_t > readAccA
void updaterLoop(unsigned nLoops, unsigned delay, unsigned duplicateVns=0, bool catchUp=false)
BOOST_FIXTURE_TEST_CASE(test1, Fixture)
auto emptyQueues(ReadAnyGroup &rag, DataConsistencyGroup *dg=nullptr)