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;
744 app.
m2.
poll1 = {&app.
m2,
"/m1/out1",
"",
""};
745 app.
m2.
poll2 = {&app.
m2,
"/m1/out1",
"",
""};
746 app.
m2.
push1 = {&app.
m2,
"/m1/out2",
"",
""};
748 std::unique_lock<std::mutex> lk1(app.
m1.
mForChecking, std::defer_lock);
749 std::unique_lock<std::mutex> lk2(app.
m2.
mForChecking, std::defer_lock);
753 test.runApplication();
756 BOOST_REQUIRE(lk1.try_lock());
762 test.stepApplication();
764 BOOST_REQUIRE(lk2.try_lock());
765 BOOST_CHECK_EQUAL(app.
m2.
poll1, 123);
766 BOOST_CHECK_EQUAL(app.
m2.
poll2, 123);
770 BOOST_REQUIRE(lk1.try_lock());
771 for(
int i = 0; i < 10; ++i) {
778 test.stepApplication();
780 BOOST_REQUIRE(lk2.try_lock());
781 BOOST_CHECK_EQUAL(app.
m2.
poll1, 200);
782 BOOST_CHECK_EQUAL(app.
m2.
poll2, 200);
790 app.
m1.
poll1 = {&app.
m1,
"/REG1",
"",
""};
791 app.
m2.
push1 = {&app.
m2,
"/REG1",
"",
""};
794 std::unique_lock<std::mutex> lk1(app.
m1.
mForChecking, std::defer_lock);
795 std::unique_lock<std::mutex> lk2(app.
m2.
mForChecking, std::defer_lock);
798 auto reg1 = dev.getScalarRegisterAccessor<
int>(
"REG1.DUMMY_WRITEABLE");
801 test.runApplication();
806 BOOST_REQUIRE(lk1.try_lock());
808 BOOST_CHECK_EQUAL(app.
m1.
poll1, 42);
810 BOOST_REQUIRE(lk2.try_lock());
811 BOOST_CHECK_NE(app.
m2.
push1, 42);
814 test.stepApplication();
816 BOOST_REQUIRE(lk2.try_lock());
817 BOOST_CHECK_EQUAL(app.
m2.
push1, 42);
824 std::cout <<
"=== Case 3" << std::endl;
826 std::cout <<
" HIER 1" << std::endl;
827 app.
m1.
poll2 = {&app.
m1,
"poll1",
"",
""};
828 std::cout <<
" HIER 2" << std::endl;
829 app.
m1.
push1 = {&app.
m1,
"/m2/out2",
"",
""};
830 std::cout <<
" HIER 3" << std::endl;
832 std::unique_lock<std::mutex> lk1(app.
m1.
mForChecking, std::defer_lock);
833 std::unique_lock<std::mutex> lk2(app.
m2.
mForChecking, std::defer_lock);
837 auto var = test.getScalar<
int>(
"/m1/poll1");
839 test.runApplication();
844 BOOST_REQUIRE(lk2.try_lock());
848 test.stepApplication();
850 BOOST_REQUIRE(lk1.try_lock());
852 BOOST_CHECK_EQUAL(app.
m1.
poll1, 666);
854 BOOST_CHECK_EQUAL(app.
m1.
poll2, 666);
858 for(
int i = 0; i < 10; ++i) {
862 BOOST_REQUIRE(lk2.try_lock());
866 test.stepApplication();
868 BOOST_REQUIRE(lk1.try_lock());
870 BOOST_CHECK_EQUAL(app.
m1.
poll1, 700);
872 BOOST_CHECK_EQUAL(app.
m1.
poll2, 700);
889 std::cout <<
"***************************************************************"
890 "******************************************************"
892 std::cout <<
"==> testDevice" << std::endl;
898 auto push = test.
getScalar<int32_t>(
"/pollingReadModule/push");
899 auto push2 = test.
getScalar<int32_t>(
"/pollingReadModule/push2");
900 auto valuePoll = test.
getScalar<int32_t>(
"/pollingReadModule/valuePoll");
903 auto r1 = dev.getScalarRegisterAccessor<int32_t>(
"/REG1.DUMMY_WRITEABLE");
913 BOOST_CHECK_EQUAL(valuePoll, 42);
921 BOOST_CHECK_EQUAL(valuePoll, 43);
929 BOOST_CHECK_EQUAL(valuePoll, 44);
944 std::cout <<
"***************************************************************"
945 "******************************************************"
947 std::cout <<
"==> testInitialValues" << std::endl;
952 std::unique_lock<std::mutex> lk1(app.
m1.
mForChecking, std::defer_lock);
953 std::unique_lock<std::mutex> lk2(app.
m2.
mForChecking, std::defer_lock);
957 test.setScalarDefault<
int>(
"/m1/push1", 42);
958 test.setScalarDefault<
int>(
"/m1/poll1", 43);
959 test.setScalarDefault<
int>(
"/m2/poll2", 44);
961 test.runApplication();
963 BOOST_REQUIRE(lk1.try_lock());
965 BOOST_CHECK_EQUAL(app.
m1.
push1, 42);
966 BOOST_CHECK_EQUAL(app.
m1.
poll1, 43);
967 BOOST_CHECK_EQUAL(app.
m1.
poll2, 0);
969 BOOST_REQUIRE(lk2.try_lock());
971 BOOST_CHECK_EQUAL(app.
m2.
push1, 0);
972 BOOST_CHECK_EQUAL(app.
m2.
poll1, 0);
973 BOOST_CHECK_EQUAL(app.
m2.
poll2, 44);
993 std::cout <<
"TestableModeLockShared" << std::endl;
995 const static std::string CDD1 =
"(ExceptionDummy:1?map=recoveryGroups.map)";
996 static std::latch blockInitHandler{2};
1000 using Application::Application;
1001 ~MyApp() { shutdown(); }
1005 using ApplicationModule::ApplicationModule;
1008 blockInitHandler.arrive_and_wait();
1011 } 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 debugMakeConnections()
Enable debug output for the ConnectionMaker.
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
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
Convenience class for output scalar accessors (always UpdateMode::push)
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)