综合平台编程器项目的远程存储
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 

121 líneas
4.4 KiB

  1. #include "domain/project_storage.h"
  2. #include "domain/register_repository.h"
  3. #include "services/alarm_editor_service.h"
  4. #include "services/alarm_service.h"
  5. #include "services/project_service.h"
  6. #include "support/test_support.h"
  7. #include <algorithm>
  8. #include <exception>
  9. #include <iostream>
  10. #include <stdexcept>
  11. #include <string>
  12. namespace {
  13. using TestProjectStorage = TestSupport::InMemoryProjectStorage;
  14. using TestSupport::require;
  15. const AlarmRecord *findRecord(
  16. const AlarmService &service, const std::string &definition_id)
  17. {
  18. const auto &records = service.records();
  19. const auto record = std::find_if(
  20. records.cbegin(), records.cend(),
  21. [&definition_id](const AlarmRecord &candidate)
  22. {
  23. return candidate.definitionId == definition_id;
  24. });
  25. return record == records.cend() ? nullptr : &*record;
  26. }
  27. void testAlarmDefinitionsAndRuntimeLifecycle()
  28. {
  29. TestProjectStorage storage;
  30. ProjectService project_service(storage);
  31. AlarmEditorService editor_service(project_service);
  32. VirtualRegisterRepository repository;
  33. AlarmService alarm_service(project_service, repository);
  34. AlarmDefinition m_alarm;
  35. m_alarm.address = RegisterAddress{RegisterArea::M, 0};
  36. m_alarm.condition = AlarmCondition::MOn;
  37. m_alarm.message = "Emergency stop";
  38. const AlarmEditorResult m_result = editor_service.addDefinition(m_alarm);
  39. AlarmDefinition high_alarm;
  40. high_alarm.address = RegisterAddress{RegisterArea::D, 0};
  41. high_alarm.condition = AlarmCondition::DHigh;
  42. high_alarm.threshold = 80;
  43. high_alarm.message = "Temperature high";
  44. const AlarmEditorResult high_result = editor_service.addDefinition(high_alarm);
  45. AlarmDefinition low_alarm;
  46. low_alarm.address = RegisterAddress{RegisterArea::D, 1};
  47. low_alarm.condition = AlarmCondition::DLow;
  48. low_alarm.threshold = 10;
  49. low_alarm.message = "Pressure low";
  50. const AlarmEditorResult low_result = editor_service.addDefinition(low_alarm);
  51. require(m_result.succeeded && high_result.succeeded && low_result.succeeded,
  52. "M, D high and D low alarm definitions must be accepted");
  53. AlarmDefinition invalid = high_alarm;
  54. invalid.address = RegisterAddress{RegisterArea::M, 2};
  55. require(editor_service.addDefinition(invalid).error
  56. == AlarmEditorError::InvalidDefinition,
  57. "D alarm conditions must reject M addresses");
  58. repository.writeWord(RegisterAddress{RegisterArea::D, 1}, 20);
  59. alarm_service.refresh();
  60. require(alarm_service.records().empty(),
  61. "inactive alarm conditions must not create records");
  62. repository.writeBit(RegisterAddress{RegisterArea::M, 0}, true);
  63. repository.writeWord(RegisterAddress{RegisterArea::D, 0}, 80);
  64. repository.writeWord(RegisterAddress{RegisterArea::D, 1}, 10);
  65. alarm_service.refresh();
  66. require(findRecord(alarm_service, m_result.id) != nullptr
  67. && findRecord(alarm_service, high_result.id) != nullptr
  68. && findRecord(alarm_service, low_result.id) != nullptr,
  69. "all three alarm conditions must create active records");
  70. require(alarm_service.acknowledge(m_result.id)
  71. && findRecord(alarm_service, m_result.id)->acknowledged,
  72. "an active alarm must be locally acknowledged");
  73. repository.writeBit(RegisterAddress{RegisterArea::M, 0}, false);
  74. repository.writeWord(RegisterAddress{RegisterArea::D, 0}, 79);
  75. repository.writeWord(RegisterAddress{RegisterArea::D, 1}, 11);
  76. alarm_service.refresh();
  77. require(alarm_service.records().empty(),
  78. "cleared conditions must immediately remove active alarms");
  79. repository.writeBit(RegisterAddress{RegisterArea::M, 0}, true);
  80. alarm_service.refresh();
  81. require(findRecord(alarm_service, m_result.id) != nullptr
  82. && alarm_service.records().size() == 1
  83. && !alarm_service.records().front().acknowledged,
  84. "a repeated alarm must create a new unacknowledged occurrence");
  85. alarm_service.reset();
  86. require(alarm_service.records().empty(),
  87. "leaving runtime must clear session alarm records");
  88. }
  89. } // namespace
  90. int main()
  91. {
  92. try
  93. {
  94. testAlarmDefinitionsAndRuntimeLifecycle();
  95. }
  96. catch (const std::exception &error)
  97. {
  98. std::cerr << "alarm service tests failed: " << error.what() << '\n';
  99. return 1;
  100. }
  101. std::cout << "alarm service tests passed\n";
  102. return 0;
  103. }