ChimeraTK-ApplicationCore 04.07.01
Loading...
Searching...
No Matches
testDataConsistencyAC.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
4#define BOOST_TEST_MODULE testDataConsistencyAC
5
6#include "Application.h"
7#include "ApplicationModule.h"
8#include "ArrayAccessor.h"
9#include "ScalarAccessor.h"
10#include "TestFacility.h"
11#include "VoidAccessor.h"
12
13#include <ChimeraTK/DataConsistencyGroup.h>
14#include <ChimeraTK/DataConsistencyGroupHistorizedMatcher.h>
15
16#include <boost/test/included/unit_test.hpp>
17
19
20 using namespace boost::unit_test_framework;
21
22 using MatchingMode = ChimeraTK::DataConsistencyGroup::MatchingMode;
23
24 /********************************************************************************************************************/
25
27 explicit ModuleA(ChimeraTK::ModuleGroup* owner) : ChimeraTK::ApplicationModule(owner, "modA", "") {}
28
29 ChimeraTK::VoidInput in1{this, "in1", ""};
32
35
36 void mainLoop() override {
37 auto rag = readAnyGroup();
38
39 ChimeraTK::DataConsistencyGroup dGroup{matchingMode};
40 dGroup.add(in1);
41 dGroup.add(in2);
42 dGroup.add(in3);
43
44 auto diagnostic = [&](ChimeraTK::TransferElementAbstractor& a) {
45 return dynamic_cast<const ChimeraTK::DataConsistencyGroupDetail::HistorizedMatcher&>(dGroup.getMatcher())
46 .getTargetElements()
47 .at(a.getId())
48 .lastMatchingIndex;
49 };
50
51 ChimeraTK::TransferElementID updatedId;
52 while(true) {
53 // note, in general it will be a good idea to consider initial values as consistent set; however, here
54 // we do not process them
55 if(dGroup.update(updatedId)) {
56 std::cout << "ModuleA consistent, updated " << dGroup.getElements().at(updatedId).getName();
57 if(matchingMode == MatchingMode::historized) {
58 std::cout << ", histIndex(in1,in2,in3)=" << diagnostic(in1) << "," << diagnostic(in2) << ","
59 << diagnostic(in3);
60 }
61 std::cout << std::endl;
62
63 out2 = in2 + 0;
65 }
66 updatedId = rag.readAny();
67 }
68 }
70 };
71
81
82 /********************************************************************************************************************/
83
84 /*
85 * we test that MatchingMode::historized also works with ApplicationCore.
86 * Explicit testing, in addition to DeviceAccess tests, makes sence because of MetaDataPropagatingRegisterDecorator.
87 */
88 BOOST_FIXTURE_TEST_CASE(testHistorizedMatching, TestFixture) {
89 std::cout << "testHistorizedMatching" << std::endl;
90
91 testApp.modA.matchingMode = MatchingMode::historized;
92
93 auto in1 = testFacility.getVoid("/modA/in1");
94 auto in2 = testFacility.getScalar<unsigned>("/modA/in2");
95 auto in3 = testFacility.getArray<unsigned>("/modA/in3");
96 auto out1 = testFacility.getScalar<unsigned>("/modA/out1");
97 auto out2 = testFacility.getScalar<unsigned>("/modA/out2");
98
99 testFacility.runApplication();
100
101 ChimeraTK::VersionNumber vn;
102 in1.write(vn);
103 in2 = 10;
104 in2.write(vn);
105
106 // provided data not complete yet -> outputs should not be available
107 testFacility.stepApplication();
108 BOOST_TEST(out1.readLatest() == false);
109
110 // complete provided data and check that output is available
111 in3.write(vn);
112 testFacility.stepApplication();
113 BOOST_TEST(out1.readLatest() == true);
114 out2.readLatest();
115 BOOST_TEST(out2 == 10);
116
117 // test that historizing actually helps:
118 // let VersionNumber provided to in2 overtake the other inputs.
119 ChimeraTK::VersionNumber vn2;
120 in2 = 11;
121 in2.write(vn2);
122 ChimeraTK::VersionNumber vn3;
123 in2 = 12;
124 in2.setDataValidity(ChimeraTK::DataValidity::faulty);
125 in2.write(vn3);
126 in1.write(vn2);
127 in3.write(vn2);
128 testFacility.stepApplication();
129 BOOST_TEST(out2.readLatest() == true);
130 BOOST_TEST(out2 == 11);
131
132 // Test version numbers as seen by consuming modules
133 BOOST_TEST(out2.getVersionNumber() == vn2);
134 // test whether versionNumber seen "from the inside" is correct
135 BOOST_TEST(testApp.modA.out2.getVersionNumber() == vn2);
136
137 // Test data validity as seen by consuming modules
138 BOOST_TEST(out2.dataValidity() == ChimeraTK::DataValidity::ok);
139 // "from the inside", we should also see correct VersionNumber
140 BOOST_TEST(testApp.modA.out2.dataValidity() == ChimeraTK::DataValidity::ok);
141
142 // check that clearing invalid does not cause crash
143 in2.setDataValidity(ChimeraTK::DataValidity::faulty);
144 in2.write();
145 testFacility.stepApplication();
146 }
147
148 /********************************************************************************************************************/
149
151 std::cout << "testExactMatching" << std::endl;
152 testApp.modA.matchingMode = MatchingMode::exact;
153
154 auto in1 = testFacility.getVoid("/modA/in1");
155 auto in2 = testFacility.getScalar<unsigned>("/modA/in2");
156 auto in3 = testFacility.getArray<unsigned>("/modA/in3");
157 auto out1 = testFacility.getScalar<unsigned>("/modA/out1");
158 auto out2 = testFacility.getScalar<unsigned>("/modA/out2");
159
160 testFacility.runApplication();
161
162 // with VersionNumber provided to in2 overtaking the other inputs, data should get lost.
163 ChimeraTK::VersionNumber vn10;
164 in2 = 20;
165 in2.write(vn10);
166 ChimeraTK::VersionNumber vn11;
167 in2 = 21;
168 in2.write(vn11);
169 in1.write(vn10);
170 in3.write(vn10);
171 testFacility.stepApplication();
172 BOOST_TEST(out2.readLatest() == false);
173
174 // when other inputs catch up, we should see an update
175 in1.write(vn11);
176 in3.write(vn11);
177 testFacility.stepApplication();
178 BOOST_TEST(out2.readLatest() == true);
179 }
180
181 /********************************************************************************************************************/
182
184 explicit ModuleIVProvider(ChimeraTK::ModuleGroup* owner) : ChimeraTK::ApplicationModule(owner, "modA", "") {}
185
187 ChimeraTK::ArrayOutput<unsigned> data{this, "/data", "", 10, ""};
188
189 void mainLoop() override {
190 // on initial value of trigger, do not provide data
191 while(true) {
192 trigger.read();
193 data[0] = trigger;
194 data[1] = 1;
196 }
197 }
198 };
199
201 explicit ModuleIVConsumer(ChimeraTK::ModuleGroup* owner) : ChimeraTK::ApplicationModule(owner, "modB", "") {}
202
204 ChimeraTK::ArrayPushInput<unsigned> data{this, "/data", "", 10, ""};
206
207 void mainLoop() override {
208 // on module startup, we should have inconsitent initial values
209 std::cout << "ModuleIVConsumer initial vns: data.vn=" << data.getVersionNumber()
210 << " trigger.vn=" << trigger.getVersionNumber() << std::endl;
211 auto rag = readAnyGroup();
212 ChimeraTK::DataConsistencyGroup dGroup(
213 {data, trigger}, ChimeraTK::DataConsistencyGroup::MatchingMode::historized);
214 assert(data[1] == 1);
215 assert(!dGroup.isConsistent());
216
217 ChimeraTK::TransferElementID updatedId;
218 while(true) {
219 updatedId = rag.readAny();
220 for(auto& li : this->getAccessorListRecursive()) {
221 auto& a = li.getAppAccessorNoType();
222 if(a.getId() == updatedId) {
223 std::cout << " updated=" << a.getName() << " vn=" << a.getVersionNumber()
224 << " cur.vn=" << getCurrentVersionNumber() << std::endl;
225 }
226 }
227 std::cout << "data[0,1] = " << data[0] << " " << data[1] << std::endl;
228 dGroup.update(updatedId);
229 ok = dGroup.isConsistent() && data[1] == 1;
231 }
232 }
233 };
234
243 // cannot use TestableMode here since it waits on all modules entering main loop
245 };
246
247 BOOST_FIXTURE_TEST_CASE(testHistorizedInitialVals, TestFixtureIV) {
248 std::cout << "testHistorizedInitialVals" << std::endl;
249 // this is a regression test for a bug with MatchingMode::histored and initial values
250 //
251 // Let(A, B) be set of vars that should be consistent.
252 // If initial Value A matches with value B coming in later, initial value of A might be lost.
253 // This could happen because initial value was already swapped into MetaDataRegisterDecorator.
254 auto trigger = testFacility.getScalar<unsigned>("/trigger");
255
256 testFacility.runApplication();
257
258 trigger.write();
259 auto isOk = testFacility.getScalar<ChimeraTK::Boolean>("/ok");
260 isOk.read();
261 BOOST_TEST(isOk == true);
262 }
263
264 /********************************************************************************************************************/
265
266} // namespace Tests::testDataConsistencyAC
void shutdown() override
This will remove the global pointer to the instance and allows creating another instance afterwards.
ApplicationModule()=default
Default constructor: Allows late initialisation of modules (e.g.
VersionNumber getCurrentVersionNumber() const override
Return the current version number which has been received with the last push-type read operation.
bool writeDestructively(ChimeraTK::VersionNumber versionNumber)=delete
Convenience class for output array accessors (always UpdateMode::push)
Convenience class for input array accessors with UpdateMode::push.
std::list< VariableNetworkNode > getAccessorListRecursive() const
Obtain the list of accessors/variables associated with this instance and any submodules.
friend class Application
Definition ModuleGroup.h:47
void writeAllDestructively(bool includeReturnChannels=false)
Just call writeDestructively() on all writable variables in the group.
Definition Module.cc:177
ChimeraTK::ReadAnyGroup readAnyGroup()
Create a ChimeraTK::ReadAnyGroup for all readable variables in this Module.
Definition Module.cc:54
Convenience class for output scalar accessors (always UpdateMode::push)
Convenience class for input scalar accessors with UpdateMode::push.
Helper class to facilitate tests of applications based on ApplicationCore.
Convenience class for input accessors.
InvalidityTracer application module.
ChimeraTK::DataConsistencyGroup::MatchingMode MatchingMode
BOOST_FIXTURE_TEST_CASE(testHistorizedMatching, TestFixture)
ChimeraTK::ScalarOutput< unsigned > out1
ChimeraTK::ScalarOutput< unsigned > out2
ChimeraTK::ArrayPushInput< unsigned > in3
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
ModuleA(ChimeraTK::ModuleGroup *owner)
ChimeraTK::ScalarPushInput< unsigned > in2
ChimeraTK::ScalarOutput< ChimeraTK::Boolean > ok
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
ChimeraTK::ScalarPushInput< unsigned > trigger
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
ChimeraTK::ScalarPushInput< unsigned > trigger
Tests::testDataConsistencyAC::TestFixture::Server testApp
Tests::testDataConsistencyAC::TestFixtureIV::Server testApp