rsmp-validator 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/config/cross_rs4s.yaml +55 -0
- data/config/gem_supervisor.yaml +56 -0
- data/config/gem_tlc.yaml +56 -0
- data/config/gem_tlc_secrets.yaml +3 -0
- data/config/kapsch_etx.yaml +54 -0
- data/config/lightmotion_satellite.yaml +56 -0
- data/config/secrets.yaml +3 -0
- data/config/secrets_example.yaml +6 -0
- data/config/semaforica_cartesio.yaml +56 -0
- data/config/simulator/node_log.yaml +17 -0
- data/config/simulator/supervisor.yaml +11 -0
- data/config/simulator/tlc.yaml +56 -0
- data/config/sus.rb +13 -0
- data/config/swarco_itc3.yaml +55 -0
- data/config/tecsen_tmacs_supervisor.yaml +57 -0
- data/config/validator.rb +37 -0
- data/config/validator.yaml +5 -0
- data/config/validator_example.yaml +23 -0
- data/config/validator_log.yaml +19 -0
- data/exe/rsmp-validator +121 -0
- data/lib/doc_gen/parser.rb +276 -0
- data/lib/doc_gen/renderer.rb +153 -0
- data/lib/rsmp/validator/async_context.rb +15 -0
- data/lib/rsmp/validator/auto_node.rb +82 -0
- data/lib/rsmp/validator/auto_site.rb +30 -0
- data/lib/rsmp/validator/auto_supervisor.rb +23 -0
- data/lib/rsmp/validator/config_normalizer.rb +103 -0
- data/lib/rsmp/validator/configuration/loader.rb +79 -0
- data/lib/rsmp/validator/configuration/secrets.rb +54 -0
- data/lib/rsmp/validator/configuration/validation.rb +115 -0
- data/lib/rsmp/validator/configuration.rb +129 -0
- data/lib/rsmp/validator/helpers/alarms.rb +66 -0
- data/lib/rsmp/validator/helpers/clock.rb +16 -0
- data/lib/rsmp/validator/helpers/connection.rb +73 -0
- data/lib/rsmp/validator/helpers/handshake.rb +110 -0
- data/lib/rsmp/validator/helpers/input.rb +42 -0
- data/lib/rsmp/validator/helpers/security.rb +26 -0
- data/lib/rsmp/validator/helpers/signal_plans.rb +37 -0
- data/lib/rsmp/validator/helpers/signal_priority.rb +130 -0
- data/lib/rsmp/validator/helpers/startup.rb +157 -0
- data/lib/rsmp/validator/helpers/status.rb +22 -0
- data/lib/rsmp/validator/lifecycle.rb +99 -0
- data/lib/rsmp/validator/log.rb +11 -0
- data/lib/rsmp/validator/mode_detection.rb +84 -0
- data/lib/rsmp/validator/options/site_test_options.rb +58 -0
- data/lib/rsmp/validator/options/supervisor_test_options.rb +51 -0
- data/lib/rsmp/validator/site_tester.rb +113 -0
- data/lib/rsmp/validator/supervisor_tester.rb +76 -0
- data/lib/rsmp/validator/tester.rb +101 -0
- data/lib/rsmp/validator/version.rb +5 -0
- data/lib/rsmp/validator/version_filter.rb +44 -0
- data/lib/rsmp/validator.rb +50 -0
- data/schemas/site_test.json +36 -0
- data/schemas/supervisor_test.json +28 -0
- data/test/site/core/aggregated_status_spec.rb +43 -0
- data/test/site/core/connect_spec.rb +104 -0
- data/test/site/core/core_spec.rb +9 -0
- data/test/site/core/disconnect_spec.rb +54 -0
- data/test/site/site_spec.rb +5 -0
- data/test/site/tlc/alarm_spec.rb +134 -0
- data/test/site/tlc/clock_spec.rb +252 -0
- data/test/site/tlc/detector_logics_spec.rb +76 -0
- data/test/site/tlc/emergency_routes_spec.rb +106 -0
- data/test/site/tlc/input_spec.rb +102 -0
- data/test/site/tlc/invalid_command_spec.rb +103 -0
- data/test/site/tlc/invalid_status_spec.rb +70 -0
- data/test/site/tlc/modes_spec.rb +260 -0
- data/test/site/tlc/output_spec.rb +58 -0
- data/test/site/tlc/signal_groups_spec.rb +96 -0
- data/test/site/tlc/signal_plans_spec.rb +287 -0
- data/test/site/tlc/signal_priority_spec.rb +144 -0
- data/test/site/tlc/subscribe_spec.rb +71 -0
- data/test/site/tlc/system_spec.rb +76 -0
- data/test/site/tlc/tlc_spec.rb +7 -0
- data/test/site/tlc/traffic_data_spec.rb +151 -0
- data/test/site/tlc/traffic_situations_spec.rb +50 -0
- data/test/supervisor/aggregated_status_spec.rb +18 -0
- data/test/supervisor/connect_spec.rb +219 -0
- data/test/supervisor/supervisor_spec.rb +11 -0
- metadata +190 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
describe 'Site::Core' do
|
|
2
|
+
describe 'Aggregated Status' do
|
|
3
|
+
# Verify that the controller responds to an aggregated status request.
|
|
4
|
+
#
|
|
5
|
+
# 1. Given the site is connected
|
|
6
|
+
# 2. When we request aggregated status
|
|
7
|
+
# 3. Then we should receive an aggregated status
|
|
8
|
+
it 'can be requested' do
|
|
9
|
+
with_site(:connected, core: '>=3.1.5') do |site_proxy|
|
|
10
|
+
log 'Request aggregated status'
|
|
11
|
+
site_proxy.request_aggregated_status_and_collect(
|
|
12
|
+
RSMP::Validator.get_config('main_component'),
|
|
13
|
+
within: RSMP::Validator.get_config('timeouts', 'status_response')
|
|
14
|
+
).ok!
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Verify that aggregated status uses null for unused attributes, from SXL 1.1
|
|
19
|
+
# For SXL versions before 1.1 empty strings "" is also allowed.
|
|
20
|
+
#
|
|
21
|
+
# 1. Given the is reconnected
|
|
22
|
+
# 2. When we receive an aggregated status
|
|
23
|
+
# 3. Then fP and fS should be null
|
|
24
|
+
it 'uses null for functional position/state' do
|
|
25
|
+
with_site(:isolated, sxl: '>=1.1',
|
|
26
|
+
'collect' => {
|
|
27
|
+
filter: RSMP::Filter.new(type: 'AggregatedStatus'),
|
|
28
|
+
timeout: RSMP::Validator.get_config('timeouts', 'ready'),
|
|
29
|
+
num: 1,
|
|
30
|
+
ingoing: true
|
|
31
|
+
}) do |site_proxy|
|
|
32
|
+
collector = site_proxy.collector
|
|
33
|
+
collector.use_task Async::Task.current
|
|
34
|
+
collector.wait!
|
|
35
|
+
aggregated_status = site_proxy.collector.messages.first
|
|
36
|
+
|
|
37
|
+
expect(aggregated_status).to be_a(RSMP::AggregatedStatus)
|
|
38
|
+
expect(aggregated_status.attribute('fP')).to be_nil
|
|
39
|
+
expect(aggregated_status.attribute('fS')).to be_nil
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
describe 'Site::Core' do
|
|
2
|
+
describe 'Connection Sequence' do
|
|
3
|
+
include RSMP::Validator::Helpers::Handshake
|
|
4
|
+
|
|
5
|
+
# Verify the connection sequence when using rsmp core 3.1.1
|
|
6
|
+
#
|
|
7
|
+
# 1. Given the site is connected and using core 3.1.1
|
|
8
|
+
# 2. When handshake messages are sent and received
|
|
9
|
+
# 3. Then the handshake messages should be in the specified sequence corresponding to version 3.1.1
|
|
10
|
+
# 4. And the connection sequence should be complete
|
|
11
|
+
it 'is correct for rsmp version 3.1.1' do
|
|
12
|
+
skip 'requires core == 3.1.1' unless RSMP::Validator.core_matches?('3.1.1')
|
|
13
|
+
check_sequence '3.1.1'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Verify the connection sequence when using rsmp core 3.1.2
|
|
17
|
+
#
|
|
18
|
+
# 1. Given the site is connected and using core 3.1.2
|
|
19
|
+
# 2. When handshake messages are sent and received
|
|
20
|
+
# 3. Then the handshake messages should be in the specified sequence corresponding to version 3.1.2
|
|
21
|
+
# 4. And the connection sequence should be complete
|
|
22
|
+
it 'is correct for rsmp version 3.1.2' do
|
|
23
|
+
skip 'requires core == 3.1.2' unless RSMP::Validator.core_matches?('3.1.2')
|
|
24
|
+
check_sequence '3.1.2'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Verify the connection sequence when using rsmp core 3.1.3
|
|
28
|
+
#
|
|
29
|
+
# 1. Given the site is connected and using core 3.1.3
|
|
30
|
+
# 2. When handshake messages are sent and received
|
|
31
|
+
# 3. Then the handshake messages should be in the specified sequence corresponding to version 3.1.3
|
|
32
|
+
# 4. And the connection sequence should be complete
|
|
33
|
+
it 'is correct for rsmp version 3.1.3' do
|
|
34
|
+
skip 'requires core == 3.1.3' unless RSMP::Validator.core_matches?('3.1.3')
|
|
35
|
+
check_sequence '3.1.3'
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Verify the connection sequence when using rsmp core 3.1.4
|
|
39
|
+
#
|
|
40
|
+
# 1. Given the site is connected and using core 3.1.4
|
|
41
|
+
# 2. When handshake messages are sent and received
|
|
42
|
+
# 3. Then the handshake messages should be in the specified sequence corresponding to version 3.1.4
|
|
43
|
+
# 4. And the connection sequence should be complete
|
|
44
|
+
it 'is correct for rsmp version 3.1.4' do
|
|
45
|
+
skip 'requires core == 3.1.4' unless RSMP::Validator.core_matches?('3.1.4')
|
|
46
|
+
check_sequence '3.1.4'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Verify the connection sequence when using rsmp core 3.1.5
|
|
50
|
+
#
|
|
51
|
+
# 1. Given the site is connected and using core 3.1.5
|
|
52
|
+
# 2. When handshake messages are sent and received
|
|
53
|
+
# 3. Then the handshake messages should be in the specified sequence corresponding to version 3.1.5
|
|
54
|
+
# 4. And the connection sequence should be complete
|
|
55
|
+
it 'is correct for rsmp version 3.1.5' do
|
|
56
|
+
skip 'requires core == 3.1.5' unless RSMP::Validator.core_matches?('3.1.5')
|
|
57
|
+
check_sequence '3.1.5'
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Verify the connection sequence when using rsmp core 3.2
|
|
61
|
+
#
|
|
62
|
+
# 1. Given the site is connected and using core 3.2
|
|
63
|
+
# 2. When handshake messages are sent and received
|
|
64
|
+
# 3. Then the handshake messages should be in the specified sequence corresponding to version 3.1.5
|
|
65
|
+
# 4. And the connection sequence should be complete
|
|
66
|
+
it 'is correct for rsmp version 3.2' do
|
|
67
|
+
skip 'requires core == 3.2' unless RSMP::Validator.core_matches?('3.2')
|
|
68
|
+
check_sequence '3.2'
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Verify the connection sequence when using rsmp core 3.2.1
|
|
72
|
+
#
|
|
73
|
+
# 1. Given the site is connected and using core 3.2.1
|
|
74
|
+
# 2. When handshake messages are sent and received
|
|
75
|
+
# 3. Then the handshake messages should be in the specified sequence corresponding to version 3.1.5
|
|
76
|
+
# 4. And the connection sequence should be complete
|
|
77
|
+
it 'is correct for rsmp version 3.2.1' do
|
|
78
|
+
skip 'requires core == 3.2.1' unless RSMP::Validator.core_matches?('3.2.1')
|
|
79
|
+
check_sequence '3.2.1'
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Verify the connection sequence when using rsmp core 3.2.2
|
|
83
|
+
#
|
|
84
|
+
# 1. Given the site is connected and using core 3.2.2
|
|
85
|
+
# 2. When handshake messages are sent and received
|
|
86
|
+
# 3. Then the handshake messages should be in the specified sequence corresponding to version 3.1.5
|
|
87
|
+
# 4. And the connection sequence should be complete
|
|
88
|
+
it 'is correct for rsmp version 3.2.2' do
|
|
89
|
+
skip 'requires core == 3.2.2' unless RSMP::Validator.core_matches?('3.2.2')
|
|
90
|
+
check_sequence '3.2.2'
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Verify the connection sequence when using rsmp core 3.3.0
|
|
94
|
+
#
|
|
95
|
+
# 1. Given the site is connected and using core 3.3.0
|
|
96
|
+
# 2. When handshake messages are sent and received
|
|
97
|
+
# 3. Then ComponentList should be exchanged before application traffic
|
|
98
|
+
# 4. And the connection sequence should be complete
|
|
99
|
+
it 'is correct for rsmp version 3.3.0' do
|
|
100
|
+
skip 'requires core == 3.3.0' unless RSMP::Validator.core_matches?('3.3.0')
|
|
101
|
+
check_sequence '3.3.0'
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
describe 'Site' do
|
|
2
|
+
# Tests covering the core specification for sites.
|
|
3
|
+
#
|
|
4
|
+
# These tests are generic and can be used to test all types of RSMP sites.
|
|
5
|
+
|
|
6
|
+
describe 'Core' do
|
|
7
|
+
# This group is intentionally empty, but exist so for documentation generation purposes.
|
|
8
|
+
end
|
|
9
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
describe 'Site::Core' do
|
|
2
|
+
# Check that the site closed the connection as required when faced with
|
|
3
|
+
# various types of incorrect behaviour from our side.
|
|
4
|
+
#
|
|
5
|
+
# The site object passed by RSMP::Validator::SiteTester a SiteProxy object. We can redefine methods
|
|
6
|
+
# on this object to modify behaviour after the connection has been established. To ensure
|
|
7
|
+
# that the modfid SityProxy is not reused in later tests, we use RSMP::Validator::SiteTester.isolate,
|
|
8
|
+
# rather than the more common RSMP::Validator::SiteTester.connect.
|
|
9
|
+
|
|
10
|
+
describe 'Connection' do
|
|
11
|
+
# 1. Given the site has just connected
|
|
12
|
+
# 2. When our supervisor does not acknowledge watchdogs
|
|
13
|
+
# 3. Then the site should disconnect
|
|
14
|
+
it 'is closed if watchdogs are not acknowledged' do
|
|
15
|
+
with_site(:isolated, sxl: '>=1.0.7') do |site_proxy|
|
|
16
|
+
timeout = RSMP::Validator.get_config('timeouts', 'disconnect')
|
|
17
|
+
site_proxy.node.ignore_errors RSMP::DisconnectError do
|
|
18
|
+
log 'Disabling watchdog acknowledgements, site should disconnect'
|
|
19
|
+
def site_proxy.acknowledge(original)
|
|
20
|
+
if original.is_a? RSMP::Watchdog
|
|
21
|
+
log 'Not acknowledgning watchdog', message: original
|
|
22
|
+
else
|
|
23
|
+
super
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
site_proxy.wait_for_state :disconnected, timeout: timeout
|
|
27
|
+
end
|
|
28
|
+
rescue RSMP::TimeoutError
|
|
29
|
+
raise "Site did not disconnect within #{timeout}s"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# 1. Given the site has just connected
|
|
34
|
+
# 2. When our supervisor stops sending watchdogs
|
|
35
|
+
# 3. Then the site should not disconnect
|
|
36
|
+
it 'is not closed if watchdogs are not received' do
|
|
37
|
+
with_site(:isolated, sxl: '>=1.0.7') do |site_proxy|
|
|
38
|
+
timeout = RSMP::Validator.get_config('timeouts', 'disconnect')
|
|
39
|
+
|
|
40
|
+
wait_task = Async::Task.current.async do
|
|
41
|
+
site_proxy.wait_for_state :disconnected, timeout: timeout
|
|
42
|
+
raise RSMP::DisconnectError
|
|
43
|
+
rescue RSMP::TimeoutError
|
|
44
|
+
# ok, no disconnect happened
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
log 'Stop sending watchdogs, site should not disconnect'
|
|
48
|
+
site_proxy.with_watchdog_disabled do
|
|
49
|
+
wait_task.wait
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
describe 'Site::Tlc::Alarm' do
|
|
2
|
+
include RSMP::Validator::Helpers::Alarms
|
|
3
|
+
|
|
4
|
+
# Testing alarms require a reliable way of rainsing them.
|
|
5
|
+
#
|
|
6
|
+
# There's no way to trigger alarms directly via RSMP yet,
|
|
7
|
+
# but often you can program the equipment to raise an alarm
|
|
8
|
+
# when a specific input is activated. If that's the case,
|
|
9
|
+
# set the `alarm_activcation` item in the validator config to
|
|
10
|
+
# specify which input activates which alarm. See docs for details.
|
|
11
|
+
#
|
|
12
|
+
# Triggered alarms manually on the equipment is not used,
|
|
13
|
+
# because validator is meant for automated testing.
|
|
14
|
+
|
|
15
|
+
# Validate that a detector logic fault A0302 is raises and cleared.
|
|
16
|
+
#
|
|
17
|
+
# The test requires that the device is programmed so that the alarm
|
|
18
|
+
# is raise when a specific input is activated, as specified in the
|
|
19
|
+
# test configuration.
|
|
20
|
+
#
|
|
21
|
+
# 1. Given the site is connected
|
|
22
|
+
# 2. When we force the input to True
|
|
23
|
+
# 3. Then an alarm should be raised, with a timestamp close to now
|
|
24
|
+
# 4. When we force the input to False
|
|
25
|
+
# 5. Then the alarm issue should become inactive, with a timestamp close to now
|
|
26
|
+
|
|
27
|
+
it 'raises A0302 when input is activated' do
|
|
28
|
+
with_site(:connected, sxl: '>=1.0.7') do |site_proxy|
|
|
29
|
+
alarm_code_id = 'A0302'
|
|
30
|
+
def verify_timestamp(alarm, duration = 1.minute)
|
|
31
|
+
alarm_time = Time.parse(alarm.attributes['aTs'])
|
|
32
|
+
expect(alarm_time).to be_within(duration).of(Time.now.utc)
|
|
33
|
+
end
|
|
34
|
+
# Raise alarm by activating input
|
|
35
|
+
deactivated, component_id = with_alarm_activated(site_proxy, alarm_code_id) do |alarm, component_id|
|
|
36
|
+
verify_timestamp alarm
|
|
37
|
+
log "Alarm #{alarm_code_id} is now Active on component #{component_id}"
|
|
38
|
+
end
|
|
39
|
+
verify_timestamp deactivated
|
|
40
|
+
log "Alarm #{alarm_code_id} is now Inactive on component #{component_id}"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Validate that an alarm can be acknowledged.
|
|
45
|
+
#
|
|
46
|
+
# The test expects that the TLC is programmed so that an detector logic fault
|
|
47
|
+
# alarm A0302 is raised and can be acknowledged when a specific input is activated.
|
|
48
|
+
# The alarm code and input nr is read from the test configuration.
|
|
49
|
+
#
|
|
50
|
+
# 1. Given the site is connected
|
|
51
|
+
# 2. When we trigger an alarm
|
|
52
|
+
# 3. Then we should receive an unacknowledged alarm issue
|
|
53
|
+
# 4. When we acknowledge the alarm
|
|
54
|
+
# 5. Then we should receive an acknowledged alarm issue
|
|
55
|
+
|
|
56
|
+
it 'can acknowledge A0302' do
|
|
57
|
+
with_site(:connected, sxl: '>=1.0.7') do |site_proxy|
|
|
58
|
+
alarm_code_id = 'A0302' # what alarm to expect
|
|
59
|
+
timeout = RSMP::Validator.get_config('timeouts', 'alarm')
|
|
60
|
+
|
|
61
|
+
log "Activating alarm #{alarm_code_id}"
|
|
62
|
+
with_alarm_activated(site_proxy, alarm_code_id) do |alarm, component_id| # raise alarm, by activating input
|
|
63
|
+
log "Alarm #{alarm_code_id} is now active on component #{component_id}"
|
|
64
|
+
|
|
65
|
+
# verify timestamp
|
|
66
|
+
alarm_time = Time.parse(alarm.attributes['aTs'])
|
|
67
|
+
expect(alarm_time).to be_within(1.minute).of(Time.now.utc)
|
|
68
|
+
|
|
69
|
+
# verify that the alarm is not acknowledged when initially raised
|
|
70
|
+
ack_message = "Alarm should not be acknowledged when raised, got: #{alarm.attributes['ack']}"
|
|
71
|
+
assert(alarm.attributes['ack'].match?(/notAcknowledged/i), ack_message)
|
|
72
|
+
log "Verified alarm #{alarm_code_id} is correctly not acknowledged when raised"
|
|
73
|
+
|
|
74
|
+
# test acknowledge and confirm
|
|
75
|
+
log "Acknowledge alarm #{alarm_code_id}"
|
|
76
|
+
|
|
77
|
+
collect_task = Async::Task.current.async do
|
|
78
|
+
RSMP::AlarmCollector.new(site_proxy,
|
|
79
|
+
num: 1,
|
|
80
|
+
matcher: {
|
|
81
|
+
'aCId' => alarm_code_id,
|
|
82
|
+
'aSp' => /Acknowledge/i,
|
|
83
|
+
'ack' => /Acknowledged/i,
|
|
84
|
+
'aS' => /Active/i
|
|
85
|
+
},
|
|
86
|
+
timeout: timeout).collect!
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
site_proxy.send_message RSMP::AlarmAcknowledge.new(
|
|
90
|
+
'cId' => component_id,
|
|
91
|
+
'aTs' => site_proxy.clock.to_s,
|
|
92
|
+
'aCId' => alarm_code_id
|
|
93
|
+
)
|
|
94
|
+
messages = collect_task.wait
|
|
95
|
+
expect(messages).to be_a(Array)
|
|
96
|
+
expect(messages.first).to be_a(RSMP::Alarm)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Validate that alarms can be suspended. We're using A0302 in this test.
|
|
102
|
+
#
|
|
103
|
+
# 1. Given the site is connected
|
|
104
|
+
# 2. And the alarm is resumed
|
|
105
|
+
# 3. When we suspend the alarm
|
|
106
|
+
# 4. Then we should received an alarm suspended messsage
|
|
107
|
+
# 5. When we resume the alarm
|
|
108
|
+
# 6. Then we should receive an alarm resumed message
|
|
109
|
+
|
|
110
|
+
it 'can suspende and resume A0302' do
|
|
111
|
+
with_site(:connected) do |site_proxy|
|
|
112
|
+
alarm_code_id = 'A0302'
|
|
113
|
+
_, component_id = find_alarm_programming(alarm_code_id)
|
|
114
|
+
|
|
115
|
+
# first resume alarm to make sure something happens when we suspend
|
|
116
|
+
site_proxy.resume_alarm Async::Task.current, c_id: component_id, a_c_id: alarm_code_id, collect: false
|
|
117
|
+
|
|
118
|
+
begin
|
|
119
|
+
# suspend alarm
|
|
120
|
+
_, response = site_proxy.suspend_alarm Async::Task.current, c_id: component_id, a_c_id: alarm_code_id,
|
|
121
|
+
collect: true
|
|
122
|
+
expect(response).to be_a(RSMP::AlarmSuspended)
|
|
123
|
+
|
|
124
|
+
# resume alarm
|
|
125
|
+
_, response = site_proxy.resume_alarm Async::Task.current, c_id: component_id, a_c_id: alarm_code_id,
|
|
126
|
+
collect: true
|
|
127
|
+
expect(response).to be_a(RSMP::AlarmResumed)
|
|
128
|
+
ensure
|
|
129
|
+
# always end with resuming alarm
|
|
130
|
+
site_proxy.resume_alarm Async::Task.current, c_id: component_id, a_c_id: alarm_code_id, collect: false
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
describe 'Site::Tlc::Clock' do
|
|
2
|
+
include RSMP::Validator::Helpers::Clock
|
|
3
|
+
include RSMP::Validator::Helpers::Alarms
|
|
4
|
+
|
|
5
|
+
# Tests related to the clock.
|
|
6
|
+
# When you set the clock, the adjusted time should be used
|
|
7
|
+
# everywhere you get back a timestamp.
|
|
8
|
+
# Note that watchdog messages can be used to synchronize the clock,
|
|
9
|
+
# which can interfere with our tests. So we disable sending watchdogs
|
|
10
|
+
# during tests.
|
|
11
|
+
|
|
12
|
+
let(:clock) { Time.new(2020, 9, 29, 17, 29, 51, '+00:00') }
|
|
13
|
+
|
|
14
|
+
# Verify status 0096 current date and time
|
|
15
|
+
#
|
|
16
|
+
# 1. Given the site_proxy is connected
|
|
17
|
+
# 2. Request status
|
|
18
|
+
# 3. Expect status response before timeout
|
|
19
|
+
it 'can be read with S0096' do
|
|
20
|
+
with_site(:connected, sxl: '>=1.0.7') do |site_proxy|
|
|
21
|
+
site_proxy.request_status_and_collect({ S0096: %i[year month day hour minute second] },
|
|
22
|
+
within: RSMP::Validator.get_config('timeouts', 'status_response')).ok!
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Verify that the controller responds to M0104
|
|
27
|
+
#
|
|
28
|
+
# 1. Given the site_proxy is connected
|
|
29
|
+
# 2. Send command
|
|
30
|
+
# 3. Expect status response before timeout
|
|
31
|
+
it 'can be set with M0104' do
|
|
32
|
+
with_site(:connected, sxl: '>=1.0.7') do |site_proxy|
|
|
33
|
+
timeout = RSMP::Validator.get_config('timeouts', 'command_response')
|
|
34
|
+
site_proxy.tlc.set_clock(clock, within: timeout)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Verify status S0096 clock after changing clock
|
|
39
|
+
#
|
|
40
|
+
# 1. Given the site_proxy is connected
|
|
41
|
+
# 2. Send control command to set_clock
|
|
42
|
+
# 3. Request status S0096
|
|
43
|
+
# 4. Compare set_clock and status timestamp
|
|
44
|
+
# 5. Expect the difference to be within max_diff
|
|
45
|
+
it 'is used for S0096 status response' do
|
|
46
|
+
with_site(:connected, sxl: '>=1.0.7') do |site_proxy|
|
|
47
|
+
site_proxy.with_watchdog_disabled do # avoid time synchronization by disabling watchdogs
|
|
48
|
+
command_timeout = RSMP::Validator.get_config('timeouts', 'command_response')
|
|
49
|
+
with_clock_set site_proxy, clock, within: command_timeout do
|
|
50
|
+
status_list = { S0096: %i[
|
|
51
|
+
year
|
|
52
|
+
month
|
|
53
|
+
day
|
|
54
|
+
hour
|
|
55
|
+
minute
|
|
56
|
+
second
|
|
57
|
+
] }
|
|
58
|
+
timeout = RSMP::Validator.get_config('timeouts', 'status_update')
|
|
59
|
+
collector = site_proxy.request_status_and_collect(
|
|
60
|
+
status_list,
|
|
61
|
+
within: timeout
|
|
62
|
+
)
|
|
63
|
+
collector.ok!
|
|
64
|
+
status = status_list.keys.first.to_s
|
|
65
|
+
|
|
66
|
+
received = Time.new(
|
|
67
|
+
collector.matcher_result({ 'sCI' => status, 'n' => 'year' })['s'],
|
|
68
|
+
collector.matcher_result({ 'sCI' => status, 'n' => 'month' })['s'],
|
|
69
|
+
collector.matcher_result({ 'sCI' => status, 'n' => 'day' })['s'],
|
|
70
|
+
collector.matcher_result({ 'sCI' => status, 'n' => 'hour' })['s'],
|
|
71
|
+
collector.matcher_result({ 'sCI' => status, 'n' => 'minute' })['s'],
|
|
72
|
+
collector.matcher_result({ 'sCI' => status, 'n' => 'second' })['s'],
|
|
73
|
+
'UTC'
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
max_diff = RSMP::Validator.get_config('timeouts', 'command_response') +
|
|
77
|
+
RSMP::Validator.get_config('timeouts', 'status_response')
|
|
78
|
+
|
|
79
|
+
diff = received - clock
|
|
80
|
+
diff = diff.round
|
|
81
|
+
assert(diff.abs <= max_diff,
|
|
82
|
+
"Clock reported by S0096 is off by #{diff}s, should be within #{max_diff}s")
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Verify status response timestamp after changing clock
|
|
89
|
+
#
|
|
90
|
+
# 1. Given the site_proxy is connected
|
|
91
|
+
# 2. Send control command to set_clock
|
|
92
|
+
# 3. Request status S0096
|
|
93
|
+
# 4. Compare set_clock and response timestamp
|
|
94
|
+
# 5. Expect the difference to be within max_diff
|
|
95
|
+
it 'is used for S0096 response timestamp' do
|
|
96
|
+
with_site(:connected, sxl: '>=1.0.7') do |site_proxy|
|
|
97
|
+
site_proxy.with_watchdog_disabled do # avoid time synchronization by disabling watchdogs
|
|
98
|
+
with_clock_set site_proxy, clock, within: RSMP::Validator.get_config('timeouts', 'command_response') do
|
|
99
|
+
status_list = { S0096: %i[
|
|
100
|
+
year
|
|
101
|
+
month
|
|
102
|
+
day
|
|
103
|
+
hour
|
|
104
|
+
minute
|
|
105
|
+
second
|
|
106
|
+
] }
|
|
107
|
+
|
|
108
|
+
timeout = RSMP::Validator.get_config('timeouts', 'status_response')
|
|
109
|
+
collector = site_proxy.request_status_and_collect(status_list,
|
|
110
|
+
within: timeout)
|
|
111
|
+
collector.ok!
|
|
112
|
+
|
|
113
|
+
max_diff = RSMP::Validator.get_config('timeouts', 'command_response') + timeout
|
|
114
|
+
diff = Time.parse(collector.messages.first.attributes['sTs']) - clock
|
|
115
|
+
diff = diff.round
|
|
116
|
+
assert(diff.abs <= max_diff,
|
|
117
|
+
"Timestamp of S0096 is off by #{diff}s, should be within #{max_diff}s")
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Verify aggregated status response timestamp after changing clock
|
|
124
|
+
#
|
|
125
|
+
# 1. Given the site_proxy is connected
|
|
126
|
+
# 2. Send control command to set clock
|
|
127
|
+
# 3. Wait for status = true
|
|
128
|
+
# 4. Request aggregated status
|
|
129
|
+
# 5. Compare set_clock and response timestamp
|
|
130
|
+
# 6. Expect the difference to be within max_diff
|
|
131
|
+
it 'is used for aggregated status timestamp' do
|
|
132
|
+
skip 'requires core >= 3.1.5' unless RSMP::Validator.core_matches?('>=3.1.5')
|
|
133
|
+
with_site(:connected, sxl: '>=1.0.7') do |site_proxy|
|
|
134
|
+
site_proxy.with_watchdog_disabled do # avoid time synchronization by disabling watchdogs
|
|
135
|
+
with_clock_set site_proxy, clock, within: RSMP::Validator.get_config('timeouts', 'command_response') do
|
|
136
|
+
component = RSMP::Validator.get_config('main_component')
|
|
137
|
+
timeout = RSMP::Validator.get_config('timeouts', 'status_response')
|
|
138
|
+
collector = site_proxy.request_aggregated_status_and_collect(component, within: timeout)
|
|
139
|
+
max_diff = RSMP::Validator.get_config('timeouts', 'command_response') + timeout
|
|
140
|
+
diff = Time.parse(collector.messages.first.attributes['aSTS']) - clock
|
|
141
|
+
diff = diff.round
|
|
142
|
+
assert(diff.abs <= max_diff,
|
|
143
|
+
"Timestamp of aggregated status is off by #{diff}s, should be within #{max_diff}s")
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Verify command response timestamp after changing clock
|
|
150
|
+
#
|
|
151
|
+
# 1. Given the site_proxy is connected
|
|
152
|
+
# 2. Send control command to set clock
|
|
153
|
+
# 3. Send command to set functional position
|
|
154
|
+
# 4. Compare set_clock and response timestamp
|
|
155
|
+
# 5. Expect the difference to be within max_diff
|
|
156
|
+
it 'is used for M0001 response timestamp' do
|
|
157
|
+
with_site(:connected, sxl: '>=1.0.7') do |site_proxy|
|
|
158
|
+
site_proxy.with_watchdog_disabled do # avoid time synchronization by disabling watchdogs
|
|
159
|
+
timeout = RSMP::Validator.get_config('timeouts', 'command_response')
|
|
160
|
+
with_clock_set site_proxy, clock, within: timeout do
|
|
161
|
+
result = site_proxy.tlc.set_functional_position('NormalControl', within: timeout)
|
|
162
|
+
collector = result[:collector]
|
|
163
|
+
max_diff = timeout * 2
|
|
164
|
+
diff = Time.parse(collector.messages.first.attributes['cTS']) - clock
|
|
165
|
+
diff = diff.round
|
|
166
|
+
assert(diff.abs <= max_diff,
|
|
167
|
+
"Timestamp of command response is off by #{diff}s, should be within #{max_diff}s")
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Verify command response timestamp after changing clock
|
|
174
|
+
#
|
|
175
|
+
# 1. Given the site_proxy is connected
|
|
176
|
+
# 2. Send control command to set clock
|
|
177
|
+
# 3. Send command to set functional position
|
|
178
|
+
# 4. Compare set_clock and response timestamp
|
|
179
|
+
# 5. Expect the difference to be within max_diff
|
|
180
|
+
it 'is used for M0104 response timestamp' do
|
|
181
|
+
with_site(:connected, sxl: '>=1.0.7') do |site_proxy|
|
|
182
|
+
site_proxy.with_watchdog_disabled do # avoid time synchronization by disabling watchdogs
|
|
183
|
+
timeout = RSMP::Validator.get_config('timeouts', 'command_response')
|
|
184
|
+
with_clock_set site_proxy, clock, within: timeout do
|
|
185
|
+
result = site_proxy.tlc.set_functional_position('NormalControl', within: timeout)
|
|
186
|
+
collector = result[:collector]
|
|
187
|
+
max_diff = timeout
|
|
188
|
+
diff = Time.parse(collector.messages.first.attributes['cTS']) - clock
|
|
189
|
+
diff = diff.round
|
|
190
|
+
assert(diff.abs <= max_diff,
|
|
191
|
+
"Timestamp of command response is off by #{diff}s, should be within #{max_diff}s")
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Verify timestamp of alarm after changing clock
|
|
198
|
+
# The test requires the device to be programmed so that
|
|
199
|
+
# a A0302 alarm can be raise by activating a specific input, as
|
|
200
|
+
# configuted in the test config.
|
|
201
|
+
#
|
|
202
|
+
# 1. Given the site_proxy is connected
|
|
203
|
+
# 2. When we send a command to change the clock
|
|
204
|
+
# 3. And we raise an alarm, by acticate an input
|
|
205
|
+
# 4. Then we should receive an alarm
|
|
206
|
+
# 5. And the alarm timestamp should be close to the time set the clock to
|
|
207
|
+
|
|
208
|
+
it 'is used for alarm timestamp' do
|
|
209
|
+
with_site(:connected, sxl: '>=1.0.7') do |site_proxy|
|
|
210
|
+
site_proxy.with_watchdog_disabled do # avoid time synchronization by disabling watchdogs
|
|
211
|
+
command_timeout = RSMP::Validator.get_config('timeouts', 'command_response')
|
|
212
|
+
with_clock_set site_proxy, clock, within: command_timeout do # set clock
|
|
213
|
+
with_alarm_activated(site_proxy, 'A0302') do |alarm| # raise alarm, by activating input
|
|
214
|
+
alarm_time = Time.parse(alarm.attributes['aTs'])
|
|
215
|
+
max_diff = RSMP::Validator.get_config('timeouts', 'command_response') +
|
|
216
|
+
RSMP::Validator.get_config('timeouts', 'status_response')
|
|
217
|
+
diff = alarm_time - clock
|
|
218
|
+
assert(diff.round.abs <= max_diff,
|
|
219
|
+
"Timestamp of alarm is off by #{diff}s, should be within #{max_diff}s")
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Verify timestamp of watchdog after changing clock
|
|
227
|
+
#
|
|
228
|
+
# 1. Given the site_proxy is connected
|
|
229
|
+
# 2. Send control command to setset_clock
|
|
230
|
+
# 3. Wait for Watchdog
|
|
231
|
+
# 4. Compare set_clock and alarm response timestamp
|
|
232
|
+
# 5. Expect the difference to be within max_diff
|
|
233
|
+
it 'is used for watchdog timestamp' do
|
|
234
|
+
with_site(:connected, sxl: '>=1.0.7') do |site_proxy|
|
|
235
|
+
site_proxy.with_watchdog_disabled do # avoid time synchronization by disabling watchdogs
|
|
236
|
+
with_clock_set site_proxy, clock, within: RSMP::Validator.get_config('timeouts', 'command_response') do
|
|
237
|
+
log 'Checking watchdog timestamp'
|
|
238
|
+
watchdog_timeout = RSMP::Validator.get_config('timeouts', 'watchdog')
|
|
239
|
+
collector = RSMP::Collector.new(site_proxy, task: Async::Task.current, type: 'Watchdog', num: 1,
|
|
240
|
+
timeout: watchdog_timeout)
|
|
241
|
+
collector.collect!
|
|
242
|
+
max_diff = RSMP::Validator.get_config('timeouts', 'command_response') +
|
|
243
|
+
RSMP::Validator.get_config('timeouts', 'status_response')
|
|
244
|
+
diff = Time.parse(collector.messages.first.attributes['wTs']) - clock
|
|
245
|
+
diff = diff.round
|
|
246
|
+
assert(diff.abs <= max_diff,
|
|
247
|
+
"Timestamp of watchdog is off by #{diff}s, should be within #{max_diff}s")
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
describe 'Site::Tlc::DetectorLogics' do
|
|
2
|
+
include RSMP::Validator::Helpers::Status
|
|
3
|
+
include RSMP::Validator::Helpers::Input
|
|
4
|
+
|
|
5
|
+
# Verify status S0016 number of detector logics
|
|
6
|
+
#
|
|
7
|
+
# 1. Given the site_proxy is connected
|
|
8
|
+
# 2. Request status
|
|
9
|
+
# 3. Expect status response before timeout
|
|
10
|
+
it 'list size is read with S0016' do
|
|
11
|
+
with_site(:connected, sxl: '>=1.0.7') do |site_proxy|
|
|
12
|
+
site_proxy.request_status_and_collect({ S0016: [:number] },
|
|
13
|
+
within: RSMP::Validator.get_config('timeouts', 'status_response')).ok!
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Verify status S0002 detector logic status
|
|
18
|
+
#
|
|
19
|
+
# 1. Given the site_proxy is connected
|
|
20
|
+
# 2. Request status
|
|
21
|
+
# 3. Expect status response before timeout
|
|
22
|
+
it 'status is read with S0002' do
|
|
23
|
+
with_site(:connected, sxl: '>=1.0.7') do |site_proxy|
|
|
24
|
+
site_proxy.request_status_and_collect({ S0002: [:detectorlogicstatus] },
|
|
25
|
+
within: RSMP::Validator.get_config('timeouts', 'status_response')).ok!
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Verify status S0021 manually set detector logic
|
|
30
|
+
#
|
|
31
|
+
# 1. Given the site_proxy is connected
|
|
32
|
+
# 2. Request status
|
|
33
|
+
# 3. Expect status response before timeout
|
|
34
|
+
it 'forcing is read with S0021' do
|
|
35
|
+
with_site(:connected, sxl: '>=1.0.7') do |site_proxy|
|
|
36
|
+
site_proxy.request_status_and_collect({ S0021: [:detectorlogics] },
|
|
37
|
+
within: RSMP::Validator.get_config('timeouts', 'status_response')).ok!
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# 1. Verify connection
|
|
42
|
+
# 2. Send control command to switch detector_logic= true
|
|
43
|
+
# 3. Wait for status = true
|
|
44
|
+
it 'forcing is set with M0008' do
|
|
45
|
+
with_site(:connected, sxl: '>=1.0.7') do |site_proxy|
|
|
46
|
+
RSMP::Validator.get_config('components', 'detector_logic').keys.each_with_index do |component, indx|
|
|
47
|
+
timeout = RSMP::Validator.get_config('timeouts', 'command_response')
|
|
48
|
+
site_proxy.tlc.force_detector_logic(component, status: 'True', mode: 'True', within: timeout)
|
|
49
|
+
wait_for_status(
|
|
50
|
+
site_proxy,
|
|
51
|
+
"detector logic #{component} to be True",
|
|
52
|
+
[{ 'sCI' => 'S0002', 'n' => 'detectorlogicstatus', 's' => /^.{#{indx}}1/ }]
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
site_proxy.tlc.force_detector_logic(component, status: 'True', mode: 'False', within: timeout)
|
|
56
|
+
wait_for_status(
|
|
57
|
+
site_proxy,
|
|
58
|
+
"detector logic #{component} to be False",
|
|
59
|
+
[{ 'sCI' => 'S0002', 'n' => 'detectorlogicstatus', 's' => /^.{#{indx}}0/ }]
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Verify status S0031 trigger level sensitivity for loop detector
|
|
66
|
+
#
|
|
67
|
+
# 1. Given the site_proxy is connected
|
|
68
|
+
# 2. Request status
|
|
69
|
+
# 3. Expect status response before timeout
|
|
70
|
+
it 'sensitivity is read with S0031' do
|
|
71
|
+
with_site(:connected, sxl: '>=1.0.15') do |site_proxy|
|
|
72
|
+
site_proxy.request_status_and_collect({ S0031: [:status] },
|
|
73
|
+
within: RSMP::Validator.get_config('timeouts', 'status_response')).ok!
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|