Skip to content
Snippets Groups Projects
testScriptedInitialisationHandler.cc 5.27 KiB
Newer Older
#define BOOST_TEST_MODULE testExceptionHandling
#include <boost/test/included/unit_test.hpp>

#include "ScriptedInitialisationHandler.h"
#include "Application.h"
#include "DeviceModule.h"
#include "TestFacility.h"
#include "ControlSystemModule.h"
#include "check_timeout.h"

#include <filesystem>
#include <fstream>

using namespace ChimeraTK;

struct DMapSetter {
  DMapSetter() { setDMapFilePath("test.dmap"); }
};

struct TestApp : public Application {
  using Application::Application;
  ~TestApp() { shutdown(); }

  ConnectingDeviceModule dev1{this, "Dummy0",
      "/MyModule/actuator"}; // pick one of the writable variables to AC knows that data type for the trigger

  // default name for the output variable (initScriptOutput)
  ScriptedInitHandler initHandler1{
      this, "InitHander1", "description", "./deviceInitScript1.bash", dev1.getDeviceModule()};
  // change the name of the output variable in case a second script is needed. Shorten the error grace time to 1 second
  ScriptedInitHandler initHandler2{this, "InitHander2", "description", "./deviceInitScript2.bash",
      dev1.getDeviceModule(), "secondInitScriptOutput", 1};
};

struct Fixture {
  DMapSetter dmapSetter;
  TestApp testApp{"ScriptedInitApp"};
  TestFacility testFacility{false};
};

BOOST_FIXTURE_TEST_CASE(testSuccess, Fixture) {
  (void)std::filesystem::remove("device1Init.success");
  (void)std::filesystem::remove("continueDevice1Init");
  (void)std::filesystem::remove("produceDevice1InitError");
  testFacility.runApplication();
  //testApp.dumpConnections();
  auto initMessage = testFacility.getScalar<std::string>("/Devices/Dummy0/initScriptOutput");

  initMessage.read();
  std::string referenceString; // currently emtpy
  BOOST_CHECK_EQUAL(static_cast<std::string>(initMessage), referenceString);

  initMessage.read();
  referenceString += "starting device1 init\n";
  BOOST_CHECK_EQUAL(static_cast<std::string>(initMessage), referenceString);

  // no more messages, script waiting for continue file
  BOOST_CHECK(initMessage.readLatest() == false);

  // let the script finish
  std::ofstream continueFile;
  continueFile.open("continueDevice1Init", std::ios::out);

  initMessage.read();
  referenceString += "device1 init successful\n";
  BOOST_CHECK_EQUAL(static_cast<std::string>(initMessage), referenceString);

  initMessage.read();
  referenceString += "Dummy0 initialisation SUCCESS!";
  BOOST_CHECK_EQUAL(static_cast<std::string>(initMessage), referenceString);

  BOOST_CHECK(std::filesystem::exists("device1Init.success"));

  auto secondInitMessage = testFacility.getScalar<std::string>("/Devices/Dummy0/secondInitScriptOutput");
  secondInitMessage.read(); // empty
  secondInitMessage.read(); // script message
  secondInitMessage.read(); // success message
  BOOST_CHECK_EQUAL(
      static_cast<std::string>(secondInitMessage), "just a second script\nDummy0 initialisation SUCCESS!");

  // cleanup
  (void)std::filesystem::remove("device1Init.success");
  (void)std::filesystem::remove("continueDevice1Init");
}

BOOST_FIXTURE_TEST_CASE(testError, Fixture) {
  std::ofstream produceErrorFile; // If the file exists, the script produces an error
  produceErrorFile.open("produceDevice2InitError", std::ios::out);

  // let script1 finish
  std::ofstream continueFile;
  continueFile.open("continueDevice1Init", std::ios::out);

  testFacility.runApplication();

  //testApp.dumpConnections();
  auto secondInitMessage = testFacility.getScalar<std::string>("/Devices/Dummy0/secondInitScriptOutput");

  // let the script run three times. Afterwards manually check that there is only one printout on the console
  auto startTime = std::chrono::steady_clock::now();
  for(int i = 0; i < 3; ++i) {
    secondInitMessage.read();
    std::string referenceString; // currently emtpy
    BOOST_CHECK_EQUAL(static_cast<std::string>(secondInitMessage), referenceString);

    secondInitMessage.read();
    referenceString += "Simulating error in second script\n";
    BOOST_CHECK_EQUAL(static_cast<std::string>(secondInitMessage), referenceString);

    secondInitMessage.read();
    referenceString += "!!! Dummy0 initialisation FAILED!";
    BOOST_CHECK_EQUAL(static_cast<std::string>(secondInitMessage), referenceString);
  }

  (void)std::filesystem::remove("produceDevice2InitError");

  // recovery
  secondInitMessage.read(); // empty
  secondInitMessage.read(); // script message
  secondInitMessage.read(); // success message
  BOOST_CHECK_EQUAL(
      static_cast<std::string>(secondInitMessage), "just a second script\nDummy0 initialisation SUCCESS!");
  // at least three failure grace periods
  auto stopTime = std::chrono::steady_clock::now();
  BOOST_CHECK(std::chrono::duration_cast<std::chrono::seconds>(stopTime - startTime).count() >= 3);

  (void)std::filesystem::remove("device1Init.success");
  (void)std::filesystem::remove("continueDevice1Init");
}

BOOST_AUTO_TEST_CASE(testBoostException) {
  BOOST_CHECK(false);
  std::filesystem::rename("deviceInitScript1.bash", "deviceInitScript1.bash.dontuse");
  try {
    DMapSetter dmapSetter;
    TestApp testApp{"ScriptedInitApp"};
    TestFacility testFacility{false};
    testFacility.runApplication();
    sleep(10);
  }
  catch(ChimeraTK::logic_error& e) {
    std::cout << "I caught the exception!" << std::endl;
  }
  std::filesystem::rename("deviceInitScript1.bash.dontuse", "deviceInitScript1.bash");
}