4#define BOOST_TEST_MODULE testTestFacilities
15#include <ChimeraTK/Device.h>
17#include <boost/mpl/list.hpp>
18#include <boost/thread/barrier.hpp>
23#include <boost/test/included/unit_test.hpp>
28 using namespace boost::unit_test_framework;
31 constexpr std::string_view
dummySdm{
"(dummy?map=test_readonly.map)"};
37 using ctk::ApplicationModule::ApplicationModule;
58 using ctk::ApplicationModule::ApplicationModule;
61 using ctk::VariableGroup::VariableGroup;
70 this,
"index",
"",
"The index (1..4) of the input where the last value was received"};
81 auto justRead = group.readAny();
86 else if(
inputs.
v2.getId() == justRead) {
90 else if(
inputs.
v3.getId() == justRead) {
94 else if(
inputs.
v4.getId() == justRead) {
114 using ctk::ApplicationModule::ApplicationModule;
142 push.readNonBlocking();
168 using ctk::ApplicationModule::ApplicationModule;
180 void run()
override { ApplicationModule::run(); }
207 std::cout <<
"***************************************************************"
208 "******************************************************"
210 std::cout <<
"==> testNoDecorator" << std::endl;
214 auto pvManagers = ctk::createPVManager();
215 app.setPVManager(pvManagers.second);
222 BOOST_CHECK(boost::dynamic_pointer_cast<ctk::detail::TestableMode::AccessorDecorator<int32_t>>(hlinput) ==
nullptr);
227 boost::dynamic_pointer_cast<ctk::detail::TestableMode::AccessorDecorator<int32_t>>(hloutput) ==
nullptr);
241 std::cout <<
"***************************************************************"
242 "******************************************************"
244 std::cout <<
"==> testBlockingRead" << std::endl;
249 auto pvInput = test.getScalar<int32_t>(
"/value");
250 auto pvOutput = test.getScalar<int32_t>(
"/blockingReadTestModule/someOutput");
251 test.runApplication();
255 for(
int i = 0; i < 5; ++i) {
259 BOOST_CHECK(pvOutput.readNonBlocking() ==
false);
260 test.stepApplication();
263 BOOST_CHECK(val == 120 + i);
278 std::cout <<
"***************************************************************"
279 "******************************************************"
281 std::cout <<
"==> testReadAny" << std::endl;
286 auto value = test.getScalar<int32_t>(
"/value");
287 auto index = test.getScalar<uint32_t>(
"/readAnyTestModule/index");
288 auto v1 = test.getScalar<int32_t>(
"/readAnyTestModule/inputs/v1");
289 auto v2 = test.getScalar<int32_t>(
"/REG2");
290 auto v3 = test.getScalar<int32_t>(
"/readAnyTestModule/inputs/v3");
291 auto v4 = test.getScalar<int32_t>(
"/readAnyTestModule/inputs/v4");
292 test.runApplication();
295 BOOST_CHECK(value.readNonBlocking() ==
false);
296 BOOST_CHECK(index.readNonBlocking() ==
false);
304 BOOST_CHECK(value.readNonBlocking() ==
false);
305 BOOST_CHECK(index.readNonBlocking() ==
false);
308 test.stepApplication();
309 BOOST_CHECK(value.readNonBlocking() ==
true);
310 BOOST_CHECK(index.readNonBlocking() ==
true);
311 BOOST_CHECK_EQUAL(value, 66);
312 BOOST_CHECK_EQUAL(index, 4);
320 BOOST_CHECK(value.readNonBlocking() ==
false);
321 BOOST_CHECK(index.readNonBlocking() ==
false);
324 test.stepApplication();
325 BOOST_CHECK(value.readNonBlocking() ==
true);
326 BOOST_CHECK(index.readNonBlocking() ==
true);
327 BOOST_CHECK_EQUAL(value, 33);
328 BOOST_CHECK_EQUAL(index, 1);
336 BOOST_CHECK(value.readNonBlocking() ==
false);
337 BOOST_CHECK(index.readNonBlocking() ==
false);
340 test.stepApplication();
342 BOOST_CHECK(value.readNonBlocking() ==
true);
343 BOOST_CHECK(index.readNonBlocking() ==
true);
344 BOOST_CHECK_EQUAL(value, 34);
345 BOOST_CHECK_EQUAL(index, 1);
353 BOOST_CHECK(value.readNonBlocking() ==
false);
354 BOOST_CHECK(index.readNonBlocking() ==
false);
357 test.stepApplication();
358 BOOST_CHECK(value.readNonBlocking() ==
true);
359 BOOST_CHECK(index.readNonBlocking() ==
true);
360 BOOST_CHECK_EQUAL(value, 40);
361 BOOST_CHECK_EQUAL(index, 3);
369 BOOST_CHECK(value.readNonBlocking() ==
false);
370 BOOST_CHECK(index.readNonBlocking() ==
false);
373 test.stepApplication();
374 BOOST_CHECK(value.readNonBlocking() ==
true);
375 BOOST_CHECK(index.readNonBlocking() ==
true);
376 BOOST_CHECK_EQUAL(value, 50);
377 BOOST_CHECK_EQUAL(index, 2);
382 test.stepApplication();
383 BOOST_ERROR(
"IllegalParameter exception expected.");
385 catch(ChimeraTK::logic_error&) {
390 BOOST_CHECK(value.readNonBlocking() ==
false);
391 BOOST_CHECK(index.readNonBlocking() ==
false);
399 BOOST_CHECK(value.readNonBlocking() ==
false);
400 BOOST_CHECK(index.readNonBlocking() ==
false);
403 test.stepApplication();
404 BOOST_CHECK(value.readNonBlocking() ==
true);
405 BOOST_CHECK(index.readNonBlocking() ==
true);
406 BOOST_CHECK_EQUAL(value, 35);
407 BOOST_CHECK_EQUAL(index, 1);
423 std::cout <<
"***************************************************************"
424 "******************************************************"
426 std::cout <<
"==> testChainedModules" << std::endl;
431 auto value = test.getScalar<int32_t>(
"/blockingReadTestModule/someOutput");
432 auto index = test.getScalar<uint32_t>(
"/readAnyTestModule/index");
433 auto v1 = test.getScalar<int32_t>(
"/readAnyTestModule/inputs/v1");
434 auto v2 = test.getScalar<int32_t>(
"/REG2");
435 auto v3 = test.getScalar<int32_t>(
"/readAnyTestModule/inputs/v3");
436 auto v4 = test.getScalar<int32_t>(
"/readAnyTestModule/inputs/v4");
437 test.runApplication();
441 BOOST_CHECK(value.readNonBlocking() ==
false);
442 BOOST_CHECK(index.readNonBlocking() ==
false);
450 BOOST_CHECK(value.readNonBlocking() ==
false);
451 BOOST_CHECK(index.readNonBlocking() ==
false);
454 test.stepApplication();
455 BOOST_CHECK(value.readNonBlocking() ==
true);
456 BOOST_CHECK(index.readNonBlocking() ==
true);
457 BOOST_CHECK(value == 11);
458 BOOST_CHECK(index == 2);
466 BOOST_CHECK(value.readNonBlocking() ==
false);
467 BOOST_CHECK(index.readNonBlocking() ==
false);
470 test.stepApplication();
471 BOOST_CHECK(value.readNonBlocking() ==
true);
472 BOOST_CHECK(index.readNonBlocking() ==
true);
473 BOOST_CHECK(value == 12);
474 BOOST_CHECK(index == 3);
482 BOOST_CHECK(value.readNonBlocking() ==
false);
483 BOOST_CHECK(index.readNonBlocking() ==
false);
486 test.stepApplication();
487 BOOST_CHECK(value.readNonBlocking() ==
true);
488 BOOST_CHECK(index.readNonBlocking() ==
true);
489 BOOST_CHECK(value == 13);
490 BOOST_CHECK(index == 3);
495 test.stepApplication();
496 BOOST_ERROR(
"IllegalParameter exception expected.");
498 catch(ChimeraTK::logic_error&) {
503 BOOST_CHECK(value.readNonBlocking() ==
false);
504 BOOST_CHECK(index.readNonBlocking() ==
false);
520 std::cout <<
"***************************************************************"
521 "******************************************************"
523 std::cout <<
"==> testWithTrigger" << std::endl;
530 auto valueFromBlocking = test.getScalar<int32_t>(
"/blockingReadTestModule/someOutput");
531 auto index = test.getScalar<uint32_t>(
"/readAnyTestModule/index");
532 auto trigger = test.getVoid(
"/trigger");
533 auto v2 = dev.getScalarRegisterAccessor<int32_t>(
"/REG2.DUMMY_WRITEABLE");
534 test.runApplication();
538 BOOST_CHECK(valueFromBlocking.readNonBlocking() ==
false);
539 BOOST_CHECK(index.readNonBlocking() ==
false);
548 BOOST_CHECK(valueFromBlocking.readNonBlocking() ==
false);
549 BOOST_CHECK(index.readNonBlocking() ==
false);
552 test.stepApplication();
553 BOOST_CHECK(valueFromBlocking.readNonBlocking() ==
true);
554 BOOST_CHECK(index.readNonBlocking() ==
true);
555 BOOST_CHECK(valueFromBlocking == 11);
556 BOOST_CHECK(index == 2);
565 BOOST_CHECK(valueFromBlocking.readNonBlocking() ==
false);
566 BOOST_CHECK(index.readNonBlocking() ==
false);
569 test.stepApplication();
570 BOOST_CHECK(valueFromBlocking.readNonBlocking() ==
true);
571 BOOST_CHECK(index.readNonBlocking() ==
true);
572 BOOST_CHECK(valueFromBlocking == 22);
573 BOOST_CHECK(index == 2);
578 test.stepApplication();
579 BOOST_ERROR(
"IllegalParameter exception expected.");
581 catch(ChimeraTK::logic_error&) {
586 BOOST_CHECK(valueFromBlocking.readNonBlocking() ==
false);
588 BOOST_CHECK(index.readNonBlocking() ==
false);
602 std::cout <<
"***************************************************************"
603 "******************************************************"
605 std::cout <<
"==> testConvenienceRead" << std::endl;
610 test.runApplication();
613 for(
int i = 0; i < 5; ++i) {
614 test.writeScalar<int32_t>(
"/value", 120 + i);
615 test.stepApplication();
616 CHECK_TIMEOUT(test.readScalar<int32_t>(
"/blockingReadTestModule/someOutput") == 120 + i, 10000);
620 for(
int i = 0; i < 5; ++i) {
621 std::vector<int32_t> myValue{120 + i};
622 test.writeArray<int32_t>(
"/value", myValue);
623 test.stepApplication();
625 test.readArray<int32_t>(
"/blockingReadTestModule/someOutput") == std::vector<int32_t>{120 + i}, 10000);
640 std::cout <<
"***************************************************************"
641 "******************************************************"
643 std::cout <<
"==> testPolling" << std::endl;
648 test.runApplication();
650 auto pv_push = test.getScalar<int32_t>(
"/pollingReadModule/push");
651 auto pv_push2 = test.getScalar<int32_t>(
"/pollingReadModule/push2");
652 auto pv_poll = test.getScalar<int32_t>(
"/pollingReadModule/poll");
653 auto pv_valuePush = test.getScalar<int32_t>(
"/pollingReadModule/valuePush");
654 auto pv_valuePoll = test.getScalar<int32_t>(
"/pollingReadModule/valuePoll");
655 auto pv_state = test.getScalar<
int>(
"/pollingReadModule/state");
662 test.stepApplication();
666 BOOST_CHECK_EQUAL((int32_t)pv_valuePoll, 42);
667 BOOST_CHECK_EQUAL((int32_t)pv_valuePush, 120);
668 BOOST_CHECK_EQUAL((int32_t)pv_state, 1);
679 test.stepApplication();
683 BOOST_CHECK_EQUAL((int32_t)pv_valuePoll, 45);
684 BOOST_CHECK_EQUAL((int32_t)pv_valuePush, 22);
685 BOOST_CHECK_EQUAL((int32_t)pv_state, 2);
694 test.stepApplication();
698 BOOST_CHECK_EQUAL((int32_t)pv_valuePoll, 46);
699 BOOST_CHECK_EQUAL((int32_t)pv_valuePush, 24);
700 BOOST_CHECK_EQUAL((int32_t)pv_state, 3);
705 for(
int i = 0; i < 10; ++i) {
710 test.stepApplication();
714 BOOST_CHECK_EQUAL((int32_t)pv_valuePoll, 59);
715 BOOST_CHECK_EQUAL((int32_t)pv_valuePush, 25);
716 BOOST_CHECK_EQUAL((int32_t)pv_state, 1);
732 std::cout <<
"***************************************************************"
733 "******************************************************"
735 std::cout <<
"==> testPollingThroughFanOuts" << std::endl;
742 app.
m2.
poll1 = {&app.
m2,
"/m1/out1",
"",
""};
743 app.
m2.
poll2 = {&app.
m2,
"/m1/out1",
"",
""};
744 app.
m2.
push1 = {&app.
m2,
"/m1/out2",
"",
""};
746 std::unique_lock<std::mutex> lk1(app.
m1.
mForChecking, std::defer_lock);
747 std::unique_lock<std::mutex> lk2(app.
m2.
mForChecking, std::defer_lock);
751 test.runApplication();
754 BOOST_REQUIRE(lk1.try_lock());
760 test.stepApplication();
762 BOOST_REQUIRE(lk2.try_lock());
763 BOOST_CHECK_EQUAL(app.
m2.
poll1, 123);
764 BOOST_CHECK_EQUAL(app.
m2.
poll2, 123);
768 BOOST_REQUIRE(lk1.try_lock());
769 for(
int i = 0; i < 10; ++i) {
776 test.stepApplication();
778 BOOST_REQUIRE(lk2.try_lock());
779 BOOST_CHECK_EQUAL(app.
m2.
poll1, 200);
780 BOOST_CHECK_EQUAL(app.
m2.
poll2, 200);
788 app.
m1.
poll1 = {&app.
m1,
"/REG1",
"",
""};
789 app.
m2.
push1 = {&app.
m2,
"/REG1",
"",
""};
792 std::unique_lock<std::mutex> lk1(app.
m1.
mForChecking, std::defer_lock);
793 std::unique_lock<std::mutex> lk2(app.
m2.
mForChecking, std::defer_lock);
796 auto reg1 = dev.getScalarRegisterAccessor<
int>(
"REG1.DUMMY_WRITEABLE");
799 test.runApplication();
804 BOOST_REQUIRE(lk1.try_lock());
806 BOOST_CHECK_EQUAL(app.
m1.
poll1, 42);
808 BOOST_REQUIRE(lk2.try_lock());
809 BOOST_CHECK_NE(app.
m2.
push1, 42);
812 test.stepApplication();
814 BOOST_REQUIRE(lk2.try_lock());
815 BOOST_CHECK_EQUAL(app.
m2.
push1, 42);
822 std::cout <<
"=== Case 3" << std::endl;
824 std::cout <<
" HIER 1" << std::endl;
825 app.
m1.
poll2 = {&app.
m1,
"poll1",
"",
""};
826 std::cout <<
" HIER 2" << std::endl;
827 app.
m1.
push1 = {&app.
m1,
"/m2/out2",
"",
""};
828 std::cout <<
" HIER 3" << std::endl;
830 std::unique_lock<std::mutex> lk1(app.
m1.
mForChecking, std::defer_lock);
831 std::unique_lock<std::mutex> lk2(app.
m2.
mForChecking, std::defer_lock);
835 auto var = test.getScalar<
int>(
"/m1/poll1");
837 test.runApplication();
842 BOOST_REQUIRE(lk2.try_lock());
846 test.stepApplication();
848 BOOST_REQUIRE(lk1.try_lock());
850 BOOST_CHECK_EQUAL(app.
m1.
poll1, 666);
852 BOOST_CHECK_EQUAL(app.
m1.
poll2, 666);
856 for(
int i = 0; i < 10; ++i) {
860 BOOST_REQUIRE(lk2.try_lock());
864 test.stepApplication();
866 BOOST_REQUIRE(lk1.try_lock());
868 BOOST_CHECK_EQUAL(app.
m1.
poll1, 700);
870 BOOST_CHECK_EQUAL(app.
m1.
poll2, 700);
887 std::cout <<
"***************************************************************"
888 "******************************************************"
890 std::cout <<
"==> testDevice" << std::endl;
896 auto push = test.
getScalar<int32_t>(
"/pollingReadModule/push");
897 auto push2 = test.
getScalar<int32_t>(
"/pollingReadModule/push2");
898 auto valuePoll = test.
getScalar<int32_t>(
"/pollingReadModule/valuePoll");
901 auto r1 = dev.getScalarRegisterAccessor<int32_t>(
"/REG1.DUMMY_WRITEABLE");
911 BOOST_CHECK_EQUAL(valuePoll, 42);
919 BOOST_CHECK_EQUAL(valuePoll, 43);
927 BOOST_CHECK_EQUAL(valuePoll, 44);
942 std::cout <<
"***************************************************************"
943 "******************************************************"
945 std::cout <<
"==> testInitialValues" << std::endl;
950 std::unique_lock<std::mutex> lk1(app.
m1.
mForChecking, std::defer_lock);
951 std::unique_lock<std::mutex> lk2(app.
m2.
mForChecking, std::defer_lock);
955 test.setScalarDefault<
int>(
"/m1/push1", 42);
956 test.setScalarDefault<
int>(
"/m1/poll1", 43);
957 test.setScalarDefault<
int>(
"/m2/poll2", 44);
959 test.runApplication();
961 BOOST_REQUIRE(lk1.try_lock());
963 BOOST_CHECK_EQUAL(app.
m1.
push1, 42);
964 BOOST_CHECK_EQUAL(app.
m1.
poll1, 43);
965 BOOST_CHECK_EQUAL(app.
m1.
poll2, 0);
967 BOOST_REQUIRE(lk2.try_lock());
969 BOOST_CHECK_EQUAL(app.
m2.
push1, 0);
970 BOOST_CHECK_EQUAL(app.
m2.
poll1, 0);
971 BOOST_CHECK_EQUAL(app.
m2.
poll2, 44);
991 std::cout <<
"TestableModeLockShared" << std::endl;
993 const static std::string CDD1 =
"(ExceptionDummy:1?map=recoveryGroups.map)";
994 static std::latch blockInitHandler{2};
998 using Application::Application;
999 ~MyApp() { shutdown(); }
1003 using ApplicationModule::ApplicationModule;
1006 blockInitHandler.arrive_and_wait();
1009 } myMod{
this,
"MyMod",
""};
#define CHECK_EQUAL_TIMEOUT(left, right, maxMilliseconds)
Model::RootProxy getModel()
Return the root of the application model.
void run() override
Execute the module.
void initialise() override
void shutdown() override
This will remove the global pointer to the instance and allows creating another instance afterwards.
void decrementDataFaultCounter() override
Decrement the fault counter and set the data validity flag to ok if the counter has reached 0.
void incrementDataFaultCounter() override
Set the data validity flag to fault and increment the fault counter.
void writeGraphViz(const std::string &filename, Args... args) const
Implementations of RootProxy.
ChimeraTK::ReadAnyGroup readAnyGroup()
Create a ChimeraTK::ReadAnyGroup for all readable variables in this Module.
void writeAll(bool includeReturnChannels=false)
Just call write() on all writable variables in the group.
bool write(ChimeraTK::VersionNumber versionNumber)=delete
void setAndWrite(UserType newValue, VersionNumber versionNumber)=delete
Convenience class for output scalar accessors (always UpdateMode::push)
Helper class to facilitate tests of applications based on ApplicationCore.
void stepApplication(bool waitForDeviceInitialisation=true) const
Perform a "step" of the application.
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.
InvalidityTracer application module.
BOOST_AUTO_TEST_CASE(testNoDecorator)
constexpr std::string_view dummySdm
ctk::ScalarPushInput< int32_t > someInput
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
ctk::ScalarOutput< int32_t > someOutput
void prepare() override
Prepare the execution of the module.
ctk::ScalarPollInput< int32_t > poll
ctk::ScalarOutput< int32_t > valuePush
ctk::ScalarPushInput< int32_t > push2
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
ctk::ScalarPushInput< int32_t > push
ctk::ScalarOutput< int32_t > valuePoll
ctk::ScalarOutput< int32_t > state
ctk::ScalarOutput< int > out1
ctk::ScalarOutput< int > out2
ctk::ScalarPollInput< int > poll1
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
ctk::ScalarPushInput< int > push1
void run() override
Execute the module.
void prepare() override
Prepare the execution of the module.
ctk::ScalarPollInput< int > poll2
void prepare() override
Prepare the execution of the module.
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
ctk::ScalarOutput< uint32_t > index
ctk::ScalarOutput< int32_t > value
~TestBlockingReadApplication() override
BlockingReadTestModule blockingReadTestModule
TestBlockingReadApplication()
~TestChaniedModulesApplication() override
ReadAnyTestModule readAnyTestModule
TestChaniedModulesApplication()
BlockingReadTestModule blockingReadTestModule
~TestConvenienceReadApplication() override
TestConvenienceReadApplication()
BlockingReadTestModule blockingReadTestModule
~TestDeviceApplication() override
PollingReadModule pollingReadModule
PollingThroughFanoutsModule m1
~TestInitialApplication() override
PollingThroughFanoutsModule m2
~TestNoDecoratorApplication() override
TestNoDecoratorApplication()
ReadAnyTestModule readAnyTestModule
BlockingReadTestModule blockingReadTestModule
PollingReadModule pollingReadModule
~TestPollingApplication() override
PollingThroughFanoutsModule m2
~TestPollingThroughFanOutsApplication() override
PollingThroughFanoutsModule m1
TestPollingThroughFanOutsApplication()
~TestReadAnyApplication() override
ReadAnyTestModule readAnyTestModule
~TestWithTriggerApplication() override
TestWithTriggerApplication()
ReadAnyTestModule readAnyTestModule
BlockingReadTestModule blockingReadTestModule
#define CHECK_TIMEOUT(condition, maxMilliseconds)