综合平台编程器项目的远程存储
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

148 rivejä
5.8 KiB

  1. #include "domain/project_storage.h"
  2. #include "domain/register_repository.h"
  3. #include "domain/virtual_register_repository.h"
  4. #include "services/alarm_editor_service.h"
  5. #include "services/alarm_service.h"
  6. #include "services/project_service.h"
  7. #include "support/test_support.h"
  8. #include <algorithm>
  9. #include <exception>
  10. #include <iostream>
  11. #include <stdexcept>
  12. #include <string>
  13. namespace {
  14. using TestProjectStorage = TestSupport::InMemoryProjectStorage;
  15. using TestSupport::require;
  16. const AlarmRecord *findRecord(
  17. const AlarmService &service, const std::string &definition_id)
  18. {
  19. const auto &records = service.records();
  20. const auto record = std::find_if(
  21. records.cbegin(), records.cend(),
  22. [&definition_id](const AlarmRecord &candidate)
  23. {
  24. return candidate.definitionId == definition_id;
  25. });
  26. return record == records.cend() ? nullptr : &*record;
  27. }
  28. void testAlarmDefinitionsAndRuntimeLifecycle()
  29. {
  30. TestProjectStorage storage;
  31. ProjectService project_service(storage, defaultProjectLimitSettings());
  32. AlarmEditorService editor_service(project_service);
  33. VirtualRegisterRepository repository;
  34. AlarmService alarm_service(project_service, repository);
  35. AlarmDefinition m_alarm;
  36. m_alarm.address = RegisterAddress{RegisterArea::M, 0};
  37. m_alarm.condition = AlarmCondition::MOn;
  38. m_alarm.message = "Emergency stop";
  39. const AlarmEditorResult m_result = editor_service.addDefinition(m_alarm);
  40. AlarmDefinition m_off_alarm;
  41. m_off_alarm.address = RegisterAddress{RegisterArea::M, 1};
  42. m_off_alarm.condition = AlarmCondition::MOff;
  43. m_off_alarm.message = "Safety circuit open";
  44. const AlarmEditorResult m_off_result = editor_service.addDefinition(
  45. m_off_alarm);
  46. AlarmDefinition high_alarm;
  47. high_alarm.address = RegisterAddress{RegisterArea::D, 0};
  48. high_alarm.condition = AlarmCondition::DHigh;
  49. high_alarm.threshold = 80;
  50. high_alarm.message = "Temperature high";
  51. const AlarmEditorResult high_result = editor_service.addDefinition(high_alarm);
  52. AlarmDefinition low_alarm;
  53. low_alarm.address = RegisterAddress{RegisterArea::D, 1};
  54. low_alarm.condition = AlarmCondition::DLow;
  55. low_alarm.threshold = 10;
  56. low_alarm.message = "Pressure low";
  57. const AlarmEditorResult low_result = editor_service.addDefinition(low_alarm);
  58. require(m_result.succeeded && m_off_result.succeeded
  59. && high_result.succeeded && low_result.succeeded,
  60. "M ON, M OFF, D high and D low alarms must be accepted");
  61. AlarmDefinition invalid = high_alarm;
  62. invalid.address = RegisterAddress{RegisterArea::M, 2};
  63. require(editor_service.addDefinition(invalid).error
  64. == AlarmEditorError::InvalidDefinition,
  65. "D alarm conditions must reject M addresses");
  66. invalid = m_off_alarm;
  67. invalid.address = RegisterAddress{RegisterArea::D, 2};
  68. require(editor_service.addDefinition(invalid).error
  69. == AlarmEditorError::InvalidDefinition,
  70. "M OFF alarm conditions must reject D addresses");
  71. repository.writeBit(RegisterAddress{RegisterArea::M, 1}, true);
  72. repository.writeWord(RegisterAddress{RegisterArea::D, 1}, 20);
  73. alarm_service.refresh();
  74. require(alarm_service.records().empty(),
  75. "inactive alarm conditions must not create records");
  76. repository.writeBit(RegisterAddress{RegisterArea::M, 0}, true);
  77. repository.writeBit(RegisterAddress{RegisterArea::M, 1}, false);
  78. repository.writeWord(RegisterAddress{RegisterArea::D, 0}, 80);
  79. repository.writeWord(RegisterAddress{RegisterArea::D, 1}, 10);
  80. alarm_service.refresh();
  81. require(findRecord(alarm_service, m_result.id) != nullptr
  82. && findRecord(alarm_service, m_off_result.id) != nullptr
  83. && findRecord(alarm_service, high_result.id) != nullptr
  84. && findRecord(alarm_service, low_result.id) != nullptr,
  85. "all four alarm conditions must create active records");
  86. require(alarm_service.acknowledge(m_result.id)
  87. && findRecord(alarm_service, m_result.id)->acknowledged,
  88. "an active alarm must be locally acknowledged");
  89. repository.writeBit(RegisterAddress{RegisterArea::M, 0}, false);
  90. repository.writeBit(RegisterAddress{RegisterArea::M, 1}, true);
  91. repository.writeWord(RegisterAddress{RegisterArea::D, 0}, 79);
  92. repository.writeWord(RegisterAddress{RegisterArea::D, 1}, 11);
  93. alarm_service.refresh();
  94. require(alarm_service.records().empty(),
  95. "cleared conditions must immediately remove active alarms");
  96. repository.writeBit(RegisterAddress{RegisterArea::M, 0}, true);
  97. alarm_service.refresh();
  98. require(findRecord(alarm_service, m_result.id) != nullptr
  99. && alarm_service.records().size() == 1
  100. && !alarm_service.records().front().acknowledged,
  101. "a repeated alarm must create a new unacknowledged occurrence");
  102. alarm_service.reset();
  103. require(alarm_service.records().empty(),
  104. "leaving runtime must clear session alarm records");
  105. }
  106. void testConfiguredAlarmLimit()
  107. {
  108. TestProjectStorage storage;
  109. ProjectLimitSettings limits;
  110. limits.maximumAlarmDefinitions = 0U;
  111. ProjectService project_service(storage, limits);
  112. AlarmEditorService editor_service(project_service);
  113. AlarmDefinition definition;
  114. definition.address = RegisterAddress{RegisterArea::M, 0};
  115. definition.condition = AlarmCondition::MOn;
  116. definition.message = "Disabled by configuration";
  117. require(!editor_service.addDefinition(definition).succeeded,
  118. "the alarm editor must use the configured definition limit");
  119. }
  120. } // namespace
  121. int main()
  122. {
  123. return TestSupport::runTestSuite("alarm service tests", {
  124. {"testAlarmDefinitionsAndRuntimeLifecycle", testAlarmDefinitionsAndRuntimeLifecycle},
  125. {"testConfiguredAlarmLimit", testConfiguredAlarmLimit},
  126. });
  127. }