rsmp-validator 0.1.0 → 0.3.2
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 +4 -4
- data/config/cross_rs4s.yaml +6 -0
- data/config/gem_supervisor.yaml +6 -0
- data/config/gem_tlc.yaml +6 -0
- data/config/kapsch_etx.yaml +13 -6
- data/config/lightmotion_satellite.yaml +8 -2
- data/config/semaforica_cartesio.yaml +8 -2
- data/config/sus.rb +1 -1
- data/config/swarco_itc3.yaml +8 -2
- data/config/tecsen_tmacs_supervisor.yaml +6 -0
- data/exe/rsmp-validator +2 -118
- data/lib/rsmp/validator/async_context.rb +4 -3
- data/lib/rsmp/validator/auto_node.rb +5 -15
- data/lib/rsmp/validator/cli/config_cli.rb +32 -0
- data/lib/rsmp/validator/cli/entrypoint.rb +40 -0
- data/lib/rsmp/validator/cli/run_options.rb +87 -0
- data/lib/rsmp/validator/cli/runner.rb +119 -0
- data/lib/rsmp/validator/cli/tee_io.rb +30 -0
- data/lib/rsmp/validator/cli/validator_overrides.rb +28 -0
- data/lib/rsmp/validator/compliance/config_metadata.rb +31 -0
- data/lib/rsmp/validator/compliance/config_sxls.rb +24 -0
- data/lib/rsmp/validator/compliance/report.rb +70 -0
- data/lib/rsmp/validator/compliance/report_failure.rb +45 -0
- data/lib/rsmp/validator/compliance/report_metadata.rb +101 -0
- data/lib/rsmp/validator/config_check.rb +72 -0
- data/lib/rsmp/validator/configuration/loader.rb +6 -0
- data/lib/rsmp/validator/configuration/sxls_override.rb +33 -0
- data/lib/rsmp/validator/configuration/validation.rb +1 -35
- data/lib/rsmp/validator/configuration/version_normalization.rb +56 -0
- data/lib/rsmp/validator/configuration.rb +25 -22
- data/lib/rsmp/validator/helpers/alarms.rb +1 -1
- data/lib/rsmp/validator/helpers/clock.rb +2 -2
- data/lib/rsmp/validator/helpers/connection.rb +18 -8
- data/lib/rsmp/validator/helpers/handshake.rb +5 -8
- data/lib/rsmp/validator/helpers/input.rb +3 -3
- data/lib/rsmp/validator/helpers/security.rb +1 -1
- data/lib/rsmp/validator/helpers/signal_plans.rb +5 -5
- data/lib/rsmp/validator/helpers/signal_priority.rb +8 -11
- data/lib/rsmp/validator/helpers/startup.rb +6 -20
- data/lib/rsmp/validator/helpers/status.rb +1 -1
- data/lib/rsmp/validator/lifecycle.rb +11 -4
- data/lib/rsmp/validator/options/site_test_options.rb +21 -1
- data/lib/rsmp/validator/options/supervisor_test_options.rb +50 -13
- data/lib/rsmp/validator/site_tester.rb +15 -6
- data/lib/rsmp/validator/supervisor_tester.rb +11 -5
- data/lib/rsmp/validator/tester.rb +25 -29
- data/lib/rsmp/validator/version.rb +1 -1
- data/lib/rsmp/validator/version_filter.rb +1 -1
- data/lib/rsmp/validator.rb +5 -1
- data/schemas/site_test.json +0 -6
- data/test/site/core/aggregated_status_spec.rb +5 -7
- data/test/site/core/connect_spec.rb +5 -5
- data/test/site/core/disconnect_spec.rb +10 -19
- data/test/site/core/message_buffer_spec.rb +114 -0
- data/test/site/tlc/alarm_spec.rb +7 -7
- data/test/site/tlc/clock_spec.rb +26 -26
- data/test/site/tlc/detector_logics_spec.rb +6 -6
- data/test/site/tlc/emergency_routes_spec.rb +16 -16
- data/test/site/tlc/input_spec.rb +10 -10
- data/test/site/tlc/invalid_command_spec.rb +24 -20
- data/test/site/tlc/invalid_status_spec.rb +25 -20
- data/test/site/tlc/modes_spec.rb +53 -37
- data/test/site/tlc/output_spec.rb +8 -8
- data/test/site/tlc/signal_groups_spec.rb +8 -8
- data/test/site/tlc/signal_plans_spec.rb +32 -34
- data/test/site/tlc/signal_priority_spec.rb +10 -12
- data/test/site/tlc/subscribe_spec.rb +9 -9
- data/test/site/tlc/system_spec.rb +12 -10
- data/test/site/tlc/traffic_data_spec.rb +27 -16
- data/test/site/tlc/traffic_situations_spec.rb +5 -5
- data/test/supervisor/connect_spec.rb +9 -12
- metadata +35 -6
|
@@ -4,11 +4,11 @@ module RSMP
|
|
|
4
4
|
# Helpers for connecting to a site or supervisor in tests, with optional
|
|
5
5
|
# version-based skipping via sxl: and core: keyword arguments.
|
|
6
6
|
#
|
|
7
|
-
# with_site(:connected, sxl: '>=1.2') do |supervisor, site_proxy|
|
|
7
|
+
# with_site(:connected, sxl: '>=1.2.0') do |supervisor, site_proxy|
|
|
8
8
|
# ...
|
|
9
9
|
# end
|
|
10
10
|
#
|
|
11
|
-
# with_supervisor(:connected, core: '>=3.2') do |site, supervisor_proxy|
|
|
11
|
+
# with_supervisor(:connected, core: '>=3.2.0') do |site, supervisor_proxy|
|
|
12
12
|
# ...
|
|
13
13
|
# end
|
|
14
14
|
module Connection
|
|
@@ -31,10 +31,10 @@ module RSMP
|
|
|
31
31
|
else
|
|
32
32
|
RSMP::Validator::SiteTester.public_send(state, **opts) do |_task, _node, proxy|
|
|
33
33
|
block.call(proxy)
|
|
34
|
-
rescue RSMP::
|
|
35
|
-
|
|
34
|
+
rescue RSMP::OperationError => e
|
|
35
|
+
fail_test e.failure.message
|
|
36
36
|
rescue StandardError => e
|
|
37
|
-
|
|
37
|
+
error_test UncaughtException.new(e)
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
end
|
|
@@ -47,16 +47,26 @@ module RSMP
|
|
|
47
47
|
else
|
|
48
48
|
RSMP::Validator::SupervisorTester.public_send(state, **opts) do |_task, _node, proxy|
|
|
49
49
|
block.call(proxy)
|
|
50
|
-
rescue RSMP::
|
|
51
|
-
|
|
50
|
+
rescue RSMP::OperationError => e
|
|
51
|
+
fail_test e.failure.message
|
|
52
52
|
rescue StandardError => e
|
|
53
|
-
|
|
53
|
+
error_test UncaughtException.new(e)
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
private
|
|
59
59
|
|
|
60
|
+
def fail_test(message)
|
|
61
|
+
@__assertions__.assert false, message
|
|
62
|
+
throw :rsmp_validator_test_failure
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def error_test(error)
|
|
66
|
+
@__assertions__.error! error
|
|
67
|
+
throw :rsmp_validator_test_failure
|
|
68
|
+
end
|
|
69
|
+
|
|
60
70
|
def validate_state!(state)
|
|
61
71
|
return if VALID_STATES.include?(state)
|
|
62
72
|
|
|
@@ -28,17 +28,14 @@ module RSMP
|
|
|
28
28
|
|
|
29
29
|
RSMP::Validator::SiteTester.isolated(
|
|
30
30
|
'collect' => { timeout: timeout, num: length, ingoing: true, outgoing: true },
|
|
31
|
-
'sites' => { 'default' => { '
|
|
32
|
-
) do |
|
|
31
|
+
'sites' => { 'default' => { 'core_version' => core_version } }
|
|
32
|
+
) do |_task, _supervisor, site|
|
|
33
33
|
assert(site.ready?, 'expected site to be ready')
|
|
34
34
|
collector = site.collector
|
|
35
|
-
collector.
|
|
36
|
-
|
|
37
|
-
got = collector.messages.map { |message| "#{message.direction}:#{message.type}" }
|
|
35
|
+
messages = collector.wait!
|
|
36
|
+
got = messages.map { |message| "#{message.direction}:#{message.type}" }
|
|
38
37
|
end
|
|
39
38
|
got
|
|
40
|
-
rescue Async::TimeoutError
|
|
41
|
-
raise "Did not collect #{length} messages within #{timeout}s"
|
|
42
39
|
end
|
|
43
40
|
|
|
44
41
|
def check_sequence_v311_to_v313(core_version)
|
|
@@ -96,7 +93,7 @@ module RSMP
|
|
|
96
93
|
case version
|
|
97
94
|
when '3.1.1', '3.1.2', '3.1.3'
|
|
98
95
|
check_sequence_v311_to_v313 version
|
|
99
|
-
when '3.1.4', '3.1.5', '3.2', '3.2.1', '3.2.2'
|
|
96
|
+
when '3.1.4', '3.1.5', '3.2.0', '3.2.1', '3.2.2'
|
|
100
97
|
check_sequence_v314_or_later version
|
|
101
98
|
when '3.3.0'
|
|
102
99
|
check_sequence_v330 version
|
|
@@ -6,7 +6,7 @@ module RSMP
|
|
|
6
6
|
include Status
|
|
7
7
|
|
|
8
8
|
def force_input_and_confirm(site_proxy, input:, value:, within:)
|
|
9
|
-
site_proxy.tlc.force_input(input:, status: 'True', value:, within:)
|
|
9
|
+
site_proxy.tlc.force_input!(input:, status: 'True', value:, within:)
|
|
10
10
|
digit = (value == 'True' ? '1' : '0')
|
|
11
11
|
|
|
12
12
|
wait_for_status(
|
|
@@ -19,7 +19,7 @@ module RSMP
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def switch_input(site_proxy, indx, within:)
|
|
22
|
-
site_proxy.tlc.set_input(input: indx.to_s, status: 'True', within:)
|
|
22
|
+
site_proxy.tlc.set_input!(input: indx.to_s, status: 'True', within:)
|
|
23
23
|
|
|
24
24
|
wait_for_status(
|
|
25
25
|
site_proxy,
|
|
@@ -29,7 +29,7 @@ module RSMP
|
|
|
29
29
|
]
|
|
30
30
|
)
|
|
31
31
|
|
|
32
|
-
site_proxy.tlc.set_input(input: indx.to_s, status: 'False', within:)
|
|
32
|
+
site_proxy.tlc.set_input!(input: indx.to_s, status: 'False', within:)
|
|
33
33
|
wait_for_status(
|
|
34
34
|
site_proxy,
|
|
35
35
|
"input #{indx} to be False",
|
|
@@ -12,7 +12,7 @@ module RSMP
|
|
|
12
12
|
component = RSMP::Validator.get_config('components', 'detector_logic').keys[0]
|
|
13
13
|
timeout = RSMP::Validator.get_config('timeouts', 'command_response')
|
|
14
14
|
site_proxy.send_command_and_collect(command_list, component: component,
|
|
15
|
-
within: timeout)
|
|
15
|
+
within: timeout)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def require_security_codes
|
|
@@ -5,30 +5,30 @@ module RSMP
|
|
|
5
5
|
module SignalPlans
|
|
6
6
|
def with_cycle_time_extended(site_proxy, extension = 5, &block)
|
|
7
7
|
timeout = RSMP::Validator.get_config('timeouts', 'command_response')
|
|
8
|
-
plan = site_proxy.tlc.read_current_plan
|
|
8
|
+
plan = site_proxy.tlc.read_current_plan!
|
|
9
9
|
time = read_plan_cycle_time(site_proxy, plan)
|
|
10
10
|
need_to_reset = true
|
|
11
11
|
time_extended = time + extension
|
|
12
|
-
site_proxy.tlc.set_cycle_time(plan: plan, cycle_time: time_extended, within: timeout)
|
|
12
|
+
site_proxy.tlc.set_cycle_time!(plan: plan, cycle_time: time_extended, within: timeout)
|
|
13
13
|
verify_cycle_time(site_proxy, plan, time_extended)
|
|
14
14
|
block.yield
|
|
15
15
|
ensure
|
|
16
16
|
if need_to_reset
|
|
17
17
|
log 'Reset cycle time'
|
|
18
|
-
site_proxy.tlc.set_cycle_time(plan: plan, cycle_time: time, within: timeout)
|
|
18
|
+
site_proxy.tlc.set_cycle_time!(plan: plan, cycle_time: time, within: timeout)
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
private
|
|
23
23
|
|
|
24
24
|
def read_plan_cycle_time(site_proxy, plan)
|
|
25
|
-
time = site_proxy.tlc.read_cycle_times[plan]
|
|
25
|
+
time = site_proxy.tlc.read_cycle_times![plan]
|
|
26
26
|
assert(!time.nil?, 'Site returned empty cycle times list')
|
|
27
27
|
time
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def verify_cycle_time(site_proxy, plan, expected)
|
|
31
|
-
actual = site_proxy.tlc.read_cycle_times[plan]
|
|
31
|
+
actual = site_proxy.tlc.read_cycle_times![plan]
|
|
32
32
|
assert(actual == expected, "Expected cycle time #{expected}, got #{actual}")
|
|
33
33
|
end
|
|
34
34
|
end
|
|
@@ -40,15 +40,14 @@ module RSMP
|
|
|
40
40
|
class RequestHelper < RSMP::Queue
|
|
41
41
|
include RSMP::Validator::Helpers::Status
|
|
42
42
|
|
|
43
|
-
def initialize(site_proxy, component:, signal_group_id:, timeout
|
|
43
|
+
def initialize(site_proxy, component:, signal_group_id:, timeout:)
|
|
44
44
|
super(site_proxy,
|
|
45
45
|
filter: RSMP::Filter.new(
|
|
46
46
|
type: 'StatusUpdate',
|
|
47
47
|
ingoing: true,
|
|
48
48
|
outgoing: false,
|
|
49
49
|
component: component
|
|
50
|
-
)
|
|
51
|
-
task: task)
|
|
50
|
+
))
|
|
52
51
|
@site_proxy = site_proxy
|
|
53
52
|
@component = component
|
|
54
53
|
@signal_group_id = signal_group_id
|
|
@@ -76,7 +75,7 @@ module RSMP
|
|
|
76
75
|
'level' => level,
|
|
77
76
|
'eta' => eta,
|
|
78
77
|
'vehicleType' => vehicle_type).to_a
|
|
79
|
-
@site_proxy.send_command(command_list, component: @component)
|
|
78
|
+
@site_proxy.send_command!(command_list, component: @component)
|
|
80
79
|
end
|
|
81
80
|
|
|
82
81
|
def request_unrelated(level: 7, eta: 2, vehicle_type: 'car')
|
|
@@ -87,21 +86,19 @@ module RSMP
|
|
|
87
86
|
'level' => level,
|
|
88
87
|
'eta' => eta,
|
|
89
88
|
'vehicleType' => vehicle_type).to_a
|
|
90
|
-
@site_proxy.send_command(command_list, component: @component)
|
|
89
|
+
@site_proxy.send_command!(command_list, component: @component)
|
|
91
90
|
end
|
|
92
91
|
|
|
93
92
|
def cancel
|
|
94
93
|
command_list = RSMP::CommandList.new(:M0022, :requestPriority,
|
|
95
94
|
requestId: @request_id,
|
|
96
95
|
type: 'cancel').to_a
|
|
97
|
-
@site_proxy.send_command(command_list, component: @component)
|
|
96
|
+
@site_proxy.send_command!(command_list, component: @component)
|
|
98
97
|
end
|
|
99
98
|
|
|
100
99
|
def expect(state)
|
|
101
100
|
@matcher.state = state
|
|
102
|
-
wait_for_message
|
|
103
|
-
rescue RSMP::TimeoutError
|
|
104
|
-
raise RSMP::TimeoutError, "Priority request did not reach state #{state} within #{@timeout}s"
|
|
101
|
+
wait_for_message!(timeout: @timeout)
|
|
105
102
|
end
|
|
106
103
|
|
|
107
104
|
private
|
|
@@ -112,11 +109,11 @@ module RSMP
|
|
|
112
109
|
|
|
113
110
|
def start
|
|
114
111
|
start_receiving
|
|
115
|
-
@site_proxy.subscribe_to_status @subscribe_list, component: @component
|
|
112
|
+
@site_proxy.subscribe_to_status! @subscribe_list, component: @component
|
|
116
113
|
end
|
|
117
114
|
|
|
118
115
|
def stop
|
|
119
|
-
@site_proxy.unsubscribe_to_status @unsubscribe_list, component: @component
|
|
116
|
+
@site_proxy.unsubscribe_to_status! @unsubscribe_list, component: @component
|
|
120
117
|
stop_receiving
|
|
121
118
|
end
|
|
122
119
|
|
|
@@ -83,7 +83,7 @@ module RSMP
|
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
def wait_normal_control(site_proxy, timeout: RSMP::Validator.get_config('timeouts', 'startup_sequence'))
|
|
86
|
-
site_proxy.tlc.wait_for_normal_control(timeout: timeout)
|
|
86
|
+
site_proxy.tlc.wait_for_normal_control!(timeout: timeout)
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
def verify_startup_sequence(site_proxy)
|
|
@@ -94,13 +94,14 @@ module RSMP
|
|
|
94
94
|
collector = RSMP::StatusCollector.new site_proxy, status_list, timeout: timeout
|
|
95
95
|
sequencer = SignalGroupSequence.new RSMP::Validator.get_config('startup_sequence')
|
|
96
96
|
collector_task = start_sequence_collector(collector, sequencer)
|
|
97
|
-
site_proxy.subscribe_to_status subscribe_list, component: component
|
|
97
|
+
site_proxy.subscribe_to_status! subscribe_list, component: component
|
|
98
98
|
yield
|
|
99
|
-
|
|
99
|
+
collector_task.wait.value!
|
|
100
|
+
log 'Startup sequence verified'
|
|
100
101
|
wait_for_status(site_proxy, 'control mode to be startup',
|
|
101
|
-
[{ 'sCI' => 'S0020', 'n' => 'controlmode', 's' => 'control' }])
|
|
102
|
+
[{ 'sCI' => 'S0020', 'n' => 'controlmode', 's' => ['control'] }])
|
|
102
103
|
ensure
|
|
103
|
-
site_proxy.unsubscribe_to_status unsubscribe_list, component: component
|
|
104
|
+
site_proxy.unsubscribe_to_status! unsubscribe_list, component: component
|
|
104
105
|
end
|
|
105
106
|
|
|
106
107
|
private
|
|
@@ -136,21 +137,6 @@ module RSMP
|
|
|
136
137
|
log "Startup sequence #{states}: Fail"
|
|
137
138
|
collector.cancel status
|
|
138
139
|
end
|
|
139
|
-
|
|
140
|
-
def handle_startup_sequence_result(result, sequencer, collector, timeout)
|
|
141
|
-
case result
|
|
142
|
-
when :ok
|
|
143
|
-
log 'Startup sequence verified'
|
|
144
|
-
when :timeout
|
|
145
|
-
raise(
|
|
146
|
-
"Startup sequence '#{sequencer.sequence}' didn't complete in #{timeout}s, " \
|
|
147
|
-
"reached #{sequencer.latest}, #{sequencer.num_started} started, " \
|
|
148
|
-
"#{sequencer.num_done} done"
|
|
149
|
-
)
|
|
150
|
-
when :cancelled
|
|
151
|
-
raise "Startup sequence '#{sequencer.sequence}' not followed: #{collector.error}"
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
140
|
end
|
|
155
141
|
end
|
|
156
142
|
end
|
|
@@ -8,7 +8,7 @@ module RSMP
|
|
|
8
8
|
timeout = options.fetch(:timeout, RSMP::Validator.get_config('timeouts', 'command'))
|
|
9
9
|
component_id = options.fetch(:component_id, RSMP::Validator.get_config('main_component'))
|
|
10
10
|
log "Wait for #{description}"
|
|
11
|
-
site_proxy.tlc.wait_for_status(
|
|
11
|
+
site_proxy.tlc.wait_for_status!(
|
|
12
12
|
description,
|
|
13
13
|
RSMP::StatusList.new(status_list).to_a,
|
|
14
14
|
update_rate: update_rate,
|
|
@@ -51,17 +51,20 @@ module RSMP
|
|
|
51
51
|
|
|
52
52
|
# Called at sus shutdown: stops the auto node and reactor.
|
|
53
53
|
def after_suite
|
|
54
|
-
reactor.run do |_task|
|
|
55
|
-
|
|
54
|
+
task = reactor.run do |_task|
|
|
55
|
+
begin
|
|
56
|
+
auto_node&.stop
|
|
57
|
+
ensure
|
|
58
|
+
current_tester&.stop
|
|
59
|
+
end
|
|
56
60
|
ensure
|
|
57
61
|
reactor.interrupt
|
|
58
62
|
end
|
|
63
|
+
task.wait
|
|
59
64
|
# Explicitly close the reactor now, while the log stream is still open.
|
|
60
65
|
# Without this, Ruby's fiber scheduler hook fires after the File.open block
|
|
61
66
|
# has closed the log file, causing IOError when cancelled tasks try to log.
|
|
62
67
|
reactor.close
|
|
63
|
-
rescue StandardError
|
|
64
|
-
nil
|
|
65
68
|
end
|
|
66
69
|
|
|
67
70
|
# Initialize the Async reactor.
|
|
@@ -72,6 +75,10 @@ module RSMP
|
|
|
72
75
|
|
|
73
76
|
private
|
|
74
77
|
|
|
78
|
+
def current_tester
|
|
79
|
+
mode == :site ? SiteTester.instance : SupervisorTester.instance
|
|
80
|
+
end
|
|
81
|
+
|
|
75
82
|
def load_log_defaults(name)
|
|
76
83
|
path = File.expand_path("../../../config/#{name}.yaml", __dir__)
|
|
77
84
|
YAML.load_file(path)
|
|
@@ -35,17 +35,37 @@ module RSMP
|
|
|
35
35
|
value = options[key]
|
|
36
36
|
next if value.nil? || merged_default.key?(key)
|
|
37
37
|
|
|
38
|
+
value = rsmp_timeouts(value) if key == 'timeouts'
|
|
39
|
+
next if value == {}
|
|
40
|
+
|
|
38
41
|
merged_default[key] = value
|
|
39
42
|
end
|
|
40
43
|
|
|
41
44
|
merged_default
|
|
42
45
|
end
|
|
43
46
|
|
|
47
|
+
def rsmp_timeouts(value)
|
|
48
|
+
return value unless value.is_a?(Hash)
|
|
49
|
+
|
|
50
|
+
value.slice(*rsmp_timeout_keys)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def rsmp_timeout_keys
|
|
54
|
+
%w[
|
|
55
|
+
connect
|
|
56
|
+
ready
|
|
57
|
+
watchdog
|
|
58
|
+
acknowledgement
|
|
59
|
+
command
|
|
60
|
+
command_timeout
|
|
61
|
+
status_response
|
|
62
|
+
]
|
|
63
|
+
end
|
|
64
|
+
|
|
44
65
|
def site_defaults
|
|
45
66
|
%w[
|
|
46
67
|
sxls
|
|
47
68
|
core_version
|
|
48
|
-
rsmp_versions
|
|
49
69
|
intervals
|
|
50
70
|
timeouts
|
|
51
71
|
components
|
|
@@ -21,29 +21,66 @@ module RSMP
|
|
|
21
21
|
local_site = options['local_site']
|
|
22
22
|
return options unless local_site.is_a?(Hash)
|
|
23
23
|
|
|
24
|
+
merge_site_defaults(options, local_site)
|
|
25
|
+
site_options_class = site_options_class_for(local_site)
|
|
26
|
+
local_site = normalize_local_site_for_rsmp(local_site)
|
|
27
|
+
local_site = site_options_class.new(local_site).to_h
|
|
28
|
+
|
|
29
|
+
options.merge('local_site' => local_site)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def merge_site_defaults(options, local_site)
|
|
33
|
+
rsmp_site_default_keys.each do |key|
|
|
34
|
+
value = options[key]
|
|
35
|
+
next if value.nil? || local_site.key?(key)
|
|
36
|
+
|
|
37
|
+
value = rsmp_timeouts(value) if key == 'timeouts'
|
|
38
|
+
next if value == {}
|
|
39
|
+
|
|
40
|
+
local_site[key] = value
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def rsmp_site_default_keys
|
|
24
45
|
%w[
|
|
25
46
|
sxls
|
|
26
47
|
core_version
|
|
27
|
-
rsmp_versions
|
|
28
48
|
intervals
|
|
29
49
|
timeouts
|
|
30
50
|
components
|
|
31
51
|
skip_validation
|
|
32
|
-
]
|
|
33
|
-
|
|
34
|
-
next if value.nil? || local_site.key?(key)
|
|
52
|
+
]
|
|
53
|
+
end
|
|
35
54
|
|
|
36
|
-
|
|
37
|
-
|
|
55
|
+
def site_options_class_for(local_site)
|
|
56
|
+
local_site['type'] == 'tlc' ? RSMP::TLC::TrafficControllerSite::Options : RSMP::Site::Options
|
|
57
|
+
end
|
|
38
58
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
else
|
|
42
|
-
RSMP::Site::Options
|
|
43
|
-
end
|
|
44
|
-
local_site = site_options_class.new(local_site).to_h
|
|
59
|
+
def rsmp_timeouts(value)
|
|
60
|
+
return value unless value.is_a?(Hash)
|
|
45
61
|
|
|
46
|
-
|
|
62
|
+
value.slice(*rsmp_timeout_keys)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def rsmp_timeout_keys
|
|
66
|
+
%w[
|
|
67
|
+
connect
|
|
68
|
+
ready
|
|
69
|
+
watchdog
|
|
70
|
+
acknowledgement
|
|
71
|
+
command
|
|
72
|
+
command_timeout
|
|
73
|
+
status_response
|
|
74
|
+
]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def normalize_local_site_for_rsmp(local_site)
|
|
78
|
+
normalized = local_site.dup
|
|
79
|
+
if normalized['security_codes'].nil? && normalized.dig('secrets', 'security_codes').is_a?(Hash)
|
|
80
|
+
normalized['security_codes'] = normalized['secrets']['security_codes']
|
|
81
|
+
end
|
|
82
|
+
normalized.delete('secrets')
|
|
83
|
+
normalized
|
|
47
84
|
end
|
|
48
85
|
end
|
|
49
86
|
end
|
|
@@ -68,7 +68,9 @@ module RSMP
|
|
|
68
68
|
|
|
69
69
|
def build_node(options)
|
|
70
70
|
logger = create_supervisor_logger(@supervisor_config)
|
|
71
|
-
supervisor_settings = ConfigNormalizer.normalize_supervisor_settings(
|
|
71
|
+
supervisor_settings = ConfigNormalizer.normalize_supervisor_settings(
|
|
72
|
+
@supervisor_config.deep_merge(rsmp_node_options(options))
|
|
73
|
+
)
|
|
72
74
|
|
|
73
75
|
RSMP::Supervisor.new(
|
|
74
76
|
supervisor_settings: supervisor_settings,
|
|
@@ -82,20 +84,23 @@ module RSMP
|
|
|
82
84
|
return if @proxy
|
|
83
85
|
|
|
84
86
|
log 'Waiting for site to connect'
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
result = @node.wait_for_site(:any, timeout: config['timeouts']['connect'])
|
|
88
|
+
raise RSMP::ConnectionError, "Site did not connect within #{config['timeouts']['connect']}s" if result.failure?
|
|
89
|
+
|
|
90
|
+
@proxy = result.value
|
|
88
91
|
end
|
|
89
92
|
|
|
90
93
|
def wait_for_handshake
|
|
91
94
|
return if @proxy.ready?
|
|
92
95
|
|
|
93
96
|
log 'Waiting for handshake to complete'
|
|
94
|
-
@proxy.wait_for_state :ready, timeout: config['timeouts']['ready']
|
|
97
|
+
result = @proxy.wait_for_state :ready, timeout: config['timeouts']['ready']
|
|
98
|
+
raise RSMP::ConnectionError, result.failure.message if result.failure?
|
|
99
|
+
|
|
95
100
|
log 'Ready'
|
|
96
101
|
return if @initial_unsubscribe_done
|
|
97
102
|
|
|
98
|
-
@proxy.unsubscribe_from_all
|
|
103
|
+
@proxy.unsubscribe_from_all(component: RSMP::Validator.get_config('main_component')).value!
|
|
99
104
|
@initial_unsubscribe_done = true
|
|
100
105
|
end
|
|
101
106
|
|
|
@@ -108,6 +113,10 @@ module RSMP
|
|
|
108
113
|
logger_settings.delete('stream') if log_settings['path']
|
|
109
114
|
RSMP::Logger.new(logger_settings)
|
|
110
115
|
end
|
|
116
|
+
|
|
117
|
+
def rsmp_node_options(options)
|
|
118
|
+
options.except('collect')
|
|
119
|
+
end
|
|
111
120
|
end
|
|
112
121
|
end
|
|
113
122
|
end
|
|
@@ -39,7 +39,7 @@ module RSMP
|
|
|
39
39
|
else
|
|
40
40
|
RSMP::Site
|
|
41
41
|
end
|
|
42
|
-
site_settings = ConfigNormalizer.normalize_site_settings(@site_config.deep_merge(options))
|
|
42
|
+
site_settings = ConfigNormalizer.normalize_site_settings(@site_config.deep_merge(rsmp_node_options(options)))
|
|
43
43
|
logger = create_site_logger(@site_config)
|
|
44
44
|
@site = klass.new(
|
|
45
45
|
site_settings: site_settings,
|
|
@@ -51,14 +51,16 @@ module RSMP
|
|
|
51
51
|
def wait_for_connection
|
|
52
52
|
log 'Waiting for connection to supervisor'
|
|
53
53
|
@proxy = @node.find_supervisor :any
|
|
54
|
-
@proxy.wait_for_state %i[connected ready], timeout: config['timeouts']['connect']
|
|
55
|
-
|
|
54
|
+
result = @proxy.wait_for_state %i[connected ready], timeout: config['timeouts']['connect']
|
|
55
|
+
return if result.success?
|
|
56
|
+
|
|
56
57
|
raise RSMP::ConnectionError, "Could not connect to supervisor within #{config['timeouts']['connect']}s"
|
|
57
58
|
end
|
|
58
59
|
|
|
59
60
|
def wait_for_handshake
|
|
60
|
-
@proxy.wait_for_state :ready, timeout: config['timeouts']['ready']
|
|
61
|
-
|
|
61
|
+
result = @proxy.wait_for_state :ready, timeout: config['timeouts']['ready']
|
|
62
|
+
return if result.success?
|
|
63
|
+
|
|
62
64
|
raise RSMP::ConnectionError, "Handshake didn't complete within #{config['timeouts']['ready']}s"
|
|
63
65
|
end
|
|
64
66
|
|
|
@@ -71,6 +73,10 @@ module RSMP
|
|
|
71
73
|
logger_settings.delete('stream') if log_settings['path']
|
|
72
74
|
RSMP::Logger.new(logger_settings)
|
|
73
75
|
end
|
|
76
|
+
|
|
77
|
+
def rsmp_node_options(options)
|
|
78
|
+
options.except('collect')
|
|
79
|
+
end
|
|
74
80
|
end
|
|
75
81
|
end
|
|
76
82
|
end
|
|
@@ -8,10 +8,6 @@ module RSMP
|
|
|
8
8
|
class Tester
|
|
9
9
|
include RSMP::Validator::Log
|
|
10
10
|
|
|
11
|
-
def self.sentinel_errors
|
|
12
|
-
@sentinel_errors ||= []
|
|
13
|
-
end
|
|
14
|
-
|
|
15
11
|
def config
|
|
16
12
|
RSMP::Validator.config
|
|
17
13
|
end
|
|
@@ -22,7 +18,9 @@ module RSMP
|
|
|
22
18
|
def connected(options = {})
|
|
23
19
|
start options, 'Connecting'
|
|
24
20
|
wait_for_proxy
|
|
25
|
-
yield Async::Task.current, @node, @proxy
|
|
21
|
+
result = yield Async::Task.current, @node, @proxy
|
|
22
|
+
check_health
|
|
23
|
+
result
|
|
26
24
|
end
|
|
27
25
|
|
|
28
26
|
# Disconnects the site if connected, then waits until the site is connected
|
|
@@ -31,7 +29,9 @@ module RSMP
|
|
|
31
29
|
stop 'Reconnecting'
|
|
32
30
|
start options
|
|
33
31
|
wait_for_proxy
|
|
34
|
-
yield Async::Task.current, @node, @proxy
|
|
32
|
+
result = yield Async::Task.current, @node, @proxy
|
|
33
|
+
check_health
|
|
34
|
+
result
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
# Like connected, except that the connection is closed after the test.
|
|
@@ -40,6 +40,7 @@ module RSMP
|
|
|
40
40
|
start options, 'Connecting'
|
|
41
41
|
wait_for_proxy
|
|
42
42
|
yield Async::Task.current, @node, @proxy
|
|
43
|
+
ensure
|
|
43
44
|
stop 'Isolating'
|
|
44
45
|
end
|
|
45
46
|
|
|
@@ -51,42 +52,37 @@ module RSMP
|
|
|
51
52
|
|
|
52
53
|
# Stop the rsmp supervisor
|
|
53
54
|
def stop(why = nil)
|
|
54
|
-
if @node
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
end
|
|
59
|
-
end
|
|
55
|
+
log why if why && @node
|
|
56
|
+
@node&.stop
|
|
57
|
+
@node_task&.wait
|
|
58
|
+
@node_task = nil
|
|
60
59
|
@node = nil
|
|
61
60
|
@proxy = nil
|
|
62
61
|
end
|
|
63
62
|
|
|
63
|
+
def receive_event(event)
|
|
64
|
+
failure = event.failure
|
|
65
|
+
detail = failure ? "#{failure.code}: #{failure.message}" : event.type
|
|
66
|
+
log "Node event: #{detail}", level: :debug
|
|
67
|
+
end
|
|
68
|
+
|
|
64
69
|
private
|
|
65
70
|
|
|
71
|
+
def check_health
|
|
72
|
+
@node_task.wait if @node_task&.failed?
|
|
73
|
+
end
|
|
74
|
+
|
|
66
75
|
def initialize
|
|
67
76
|
parse_config
|
|
68
77
|
end
|
|
69
78
|
|
|
70
|
-
# Start the tester node
|
|
79
|
+
# Start the tester node under the shared reactor's current task.
|
|
71
80
|
def start(options = {}, _why = nil)
|
|
72
81
|
return if @node
|
|
73
82
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
@node = build_node options
|
|
78
|
-
|
|
79
|
-
RSMP::Validator.reactor.async do |sentinel|
|
|
80
|
-
sentinel.annotate 'sentinel'
|
|
81
|
-
while @node
|
|
82
|
-
e = @node.error_queue.dequeue
|
|
83
|
-
log "Sentinel warning: #{e.class}: #{e}"
|
|
84
|
-
self.class.sentinel_errors << e
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
@node.start
|
|
89
|
-
end
|
|
83
|
+
@node = build_node options
|
|
84
|
+
@node.add_event_receiver(self)
|
|
85
|
+
@node_task = @node.start(parent: Async::Task.current)
|
|
90
86
|
end
|
|
91
87
|
|
|
92
88
|
# Wait until communication has been established, and handshake completed.
|
|
@@ -11,7 +11,7 @@ module RSMP
|
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
# Check if the configured core version satisfies the given requirement.
|
|
14
|
-
# @param requirement [String] Gem::Requirement-compatible string, e.g. ">= 3.2"
|
|
14
|
+
# @param requirement [String] Gem::Requirement-compatible string, e.g. ">= 3.2.0"
|
|
15
15
|
def self.core_matches?(requirement)
|
|
16
16
|
version_satisfies?(requirement, RSMP::Validator.config['core_version'])
|
|
17
17
|
end
|