rsmp-validator 0.1.1 → 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 -117
- 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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bf28fcdaff9ccf8df4f107cbe2f045e55316f81285c21520da2ef63a19f9f94f
|
|
4
|
+
data.tar.gz: 5c7614286acbcb9dce4abb36b66fb48a94493b072a7f88432b598e3249d0b6df
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3e31a7dd63d4143b7804f04026d090a1936e3918a6bd2f060c6e6dd8ae81ad74600ac76cac553a17a89daad2bf769efeaf293f0c6f73d5ca049dbcc756f99e06
|
|
7
|
+
data.tar.gz: 4abbb6813ee551793997e18e680f131f15680f2a2a16361d524607baf9068807e4f7a663e5d136e2941b9dad8c9601a3ba995dcf80dcc778fef365702e34aa01
|
data/config/cross_rs4s.yaml
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# Config for testing Cross RS4S traffic light controller.
|
|
2
2
|
# The settings are used for starting a local supervisor listening for the site tested
|
|
3
3
|
# See https://rsmp-nordic.github.io/rsmp_validator/config/
|
|
4
|
+
compliance:
|
|
5
|
+
id: cross-rs4s
|
|
6
|
+
kind: site
|
|
7
|
+
name: Cross RS4S/RS4T/RS5
|
|
8
|
+
product_url: https://www.cross-traffic.com/en/traffic-light-controllers/
|
|
9
|
+
|
|
4
10
|
local_supervisor:
|
|
5
11
|
ips: all
|
|
6
12
|
max_sites: 1
|
data/config/gem_supervisor.yaml
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Config for testing a supervisor running on localhost (e.g. one from the rsmp gem)
|
|
2
2
|
# The settings are used for starting a local site connecting to the supervisor tested
|
|
3
|
+
compliance:
|
|
4
|
+
id: gem-supervisor
|
|
5
|
+
kind: supervisor
|
|
6
|
+
name: RSMP Nordic CLI supervisor
|
|
7
|
+
product_url: https://github.com/rsmp-nordic/rsmp
|
|
8
|
+
|
|
3
9
|
local_site:
|
|
4
10
|
type: tlc
|
|
5
11
|
site_id: RN+SI0001
|
data/config/gem_tlc.yaml
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# Config for testing RSMP Nordic traffic light controller emulator.
|
|
2
2
|
# The settings are used for starting a local supervisor listening for the site tested
|
|
3
3
|
# See https://rsmp-nordic.github.io/rsmp_validator/config/
|
|
4
|
+
compliance:
|
|
5
|
+
id: gem-tlc
|
|
6
|
+
kind: site
|
|
7
|
+
name: RSMP Nordic CLI TLC
|
|
8
|
+
product_url: https://github.com/rsmp-nordic/rsmp
|
|
9
|
+
|
|
4
10
|
local_supervisor:
|
|
5
11
|
port: 13111
|
|
6
12
|
ips: all
|
data/config/kapsch_etx.yaml
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
# Config for testing Kapsch ETX traffic light controller.
|
|
2
2
|
# The settings are used for starting a local supervisor listening for the site tested
|
|
3
3
|
# See https://rsmp-nordic.github.io/rsmp_validator/config/
|
|
4
|
+
compliance:
|
|
5
|
+
id: kapsch-etx
|
|
6
|
+
kind: site
|
|
7
|
+
name: Kapsch EcoTrafiX
|
|
8
|
+
product_url: https://www.kapsch.net/_Resources/Persistent/f9e0a0525985dc4a9d0b3cb6b67476c0b1257b1c/Kapsch_EcoTrafiX-Controller-16_Datasheet-EN.pdf
|
|
9
|
+
|
|
4
10
|
local_supervisor:
|
|
5
11
|
ips: all
|
|
6
12
|
max_sites: 1
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
13
|
+
sites:
|
|
14
|
+
default:
|
|
15
|
+
intervals:
|
|
16
|
+
timer: 1 # main validator timer resolution in seconds
|
|
17
|
+
watchdog: 60 # send watchdog every x seconds
|
|
11
18
|
sxls:
|
|
12
19
|
tlc: "1.2.1"
|
|
13
20
|
timeouts: # Timeouts used when waiting for messages from site.
|
|
@@ -50,5 +57,5 @@ alarm_triggers:
|
|
|
50
57
|
component: KTT+TC=101DL004
|
|
51
58
|
secrets:
|
|
52
59
|
security_codes:
|
|
53
|
-
1:
|
|
54
|
-
2:
|
|
60
|
+
1: '1111'
|
|
61
|
+
2: '2222'
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# Configuration for testing Lightmotion Satellite RSMP proxy software
|
|
2
2
|
# The settings are used for starting a local supervisor listening for the site tested
|
|
3
3
|
# See https://rsmp-nordic.github.io/rsmp_validator/config/
|
|
4
|
+
compliance:
|
|
5
|
+
id: lightmotion-satellite
|
|
6
|
+
kind: site
|
|
7
|
+
name: Lightmotion Satellite
|
|
8
|
+
product_url: https://lightmotion.fi/
|
|
9
|
+
|
|
4
10
|
local_supervisor:
|
|
5
11
|
ips: all
|
|
6
12
|
max_sites: 1
|
|
@@ -52,5 +58,5 @@ alarm_triggers:
|
|
|
52
58
|
component: AA+BBCCC=DDDDL001
|
|
53
59
|
secrets:
|
|
54
60
|
security_codes:
|
|
55
|
-
1:
|
|
56
|
-
2:
|
|
61
|
+
1: '1234'
|
|
62
|
+
2: '4321'
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# Config for testing Cross RS4S traffic light controller.
|
|
2
2
|
# The settings are used for starting a local supervisor listening for the site tested
|
|
3
3
|
# See https://rsmp-nordic.github.io/rsmp_validator/config/
|
|
4
|
+
compliance:
|
|
5
|
+
id: semaforica-cartesio
|
|
6
|
+
kind: site
|
|
7
|
+
name: La Semaforica TECSEN Cartesio
|
|
8
|
+
product_url: https://lasemaforica.com/en/products/cartesio-highest-processing-power-interactive-traffic-controllers/
|
|
9
|
+
|
|
4
10
|
local_supervisor:
|
|
5
11
|
ips: all
|
|
6
12
|
max_sites: 1
|
|
@@ -52,5 +58,5 @@ alarm_triggers:
|
|
|
52
58
|
component: CAR_DL_016
|
|
53
59
|
secrets:
|
|
54
60
|
security_codes:
|
|
55
|
-
1: 1234
|
|
56
|
-
2: 12341234
|
|
61
|
+
1: '1234'
|
|
62
|
+
2: '12341234'
|
data/config/sus.rb
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# bundle exec sus test/validator
|
|
7
7
|
#
|
|
8
8
|
# To run conformance tests against real equipment, use the rsmp-validator executable:
|
|
9
|
-
# bundle exec rsmp-validator
|
|
9
|
+
# bundle exec rsmp-validator run test/site
|
|
10
10
|
|
|
11
11
|
def test_paths
|
|
12
12
|
Dir.glob('test/validator/**/*.rb', base: @root)
|
data/config/swarco_itc3.yaml
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# Config for testing Swarco ITC-3 traffic light controller.
|
|
2
2
|
# The settings are used for starting a local supervisor listening for the site tested
|
|
3
3
|
# See https://rsmp-nordic.github.io/rsmp_validator/config/
|
|
4
|
+
compliance:
|
|
5
|
+
id: swarco-itc3
|
|
6
|
+
kind: site
|
|
7
|
+
name: Swarco ITC-3
|
|
8
|
+
product_url: https://www.swarco.com/products/traffic-light-controllers/itc-3-traffic-controller
|
|
9
|
+
|
|
4
10
|
local_supervisor:
|
|
5
11
|
ips: all
|
|
6
12
|
max_sites: 1
|
|
@@ -51,5 +57,5 @@ alarm_triggers:
|
|
|
51
57
|
component: AA+BBCCC=DDDDL002
|
|
52
58
|
secrets:
|
|
53
59
|
security_codes:
|
|
54
|
-
1: default
|
|
55
|
-
2: default
|
|
60
|
+
1: 'default'
|
|
61
|
+
2: 'default'
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# The settings are used for starting a local tlc emulator connecting to the supervisor system to be tested
|
|
2
2
|
|
|
3
|
+
compliance:
|
|
4
|
+
id: tecsen-tmacs
|
|
5
|
+
kind: supervisor
|
|
6
|
+
name: TECSEN TMacs
|
|
7
|
+
product_url: https://www.tmacs.it/en/
|
|
8
|
+
|
|
3
9
|
local_site:
|
|
4
10
|
type: tlc
|
|
5
11
|
site_id: CAR_TC_001
|
data/exe/rsmp-validator
CHANGED
|
@@ -1,120 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
require 'sus/config'
|
|
3
|
+
require_relative '../lib/rsmp/validator/cli/entrypoint'
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
puts <<~HELP
|
|
8
|
-
RSMP Validator runs conformance tests against RSMP sites and supervisors.
|
|
9
|
-
Full documentation: https://rsmp-nordic.github.io/rsmp_validator/
|
|
10
|
-
|
|
11
|
-
Usage:
|
|
12
|
-
rsmp-validator [OPTIONS] PATH...
|
|
13
|
-
|
|
14
|
-
Examples:
|
|
15
|
-
rsmp-validator test/site
|
|
16
|
-
rsmp-validator test/site/core
|
|
17
|
-
rsmp-validator test/supervisor/connect_spec.rb
|
|
18
|
-
|
|
19
|
-
Options:
|
|
20
|
-
--verbose Show detailed sus output.
|
|
21
|
-
--log Print RSMP log output to stdout.
|
|
22
|
-
--log PATH Write RSMP log output to PATH.
|
|
23
|
-
-h, --help Show this help.
|
|
24
|
-
|
|
25
|
-
Environment:
|
|
26
|
-
SITE_CONFIG Path to site test configuration.
|
|
27
|
-
SUPERVISOR_CONFIG Path to supervisor test configuration.
|
|
28
|
-
AUTO_SITE_CONFIG Path to local site configuration to start automatically.
|
|
29
|
-
HELP
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
if ARGV.first == 'help' || ARGV.include?('--help') || ARGV.include?('-h')
|
|
33
|
-
print_help
|
|
34
|
-
exit 0
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Parse --log [path] from ARGV before Sus::Config.load consumes remaining args.
|
|
38
|
-
# --log => RSMP logs to $stdout
|
|
39
|
-
# --log <path> => RSMP logs to file, sus output to console (brief)
|
|
40
|
-
# + --verbose => sus output also goes to file (interleaved, perfectly ordered)
|
|
41
|
-
# (no --log) => RSMP logs suppressed
|
|
42
|
-
log_index = ARGV.index('--log')
|
|
43
|
-
log_path = nil
|
|
44
|
-
log_to_stdout = false
|
|
45
|
-
if log_index
|
|
46
|
-
ARGV.delete_at(log_index)
|
|
47
|
-
if ARGV[log_index] && !ARGV[log_index].start_with?('-')
|
|
48
|
-
log_path = ARGV.delete_at(log_index)
|
|
49
|
-
else
|
|
50
|
-
log_to_stdout = true
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# Writes to two IOs simultaneously through a single object, so both RSMP messages
|
|
55
|
-
# and Sus verbose output share one file descriptor and are perfectly interleaved.
|
|
56
|
-
class TeeIO
|
|
57
|
-
def initialize(primary, secondary)
|
|
58
|
-
@primary = primary
|
|
59
|
-
@secondary = secondary
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def write(*args)
|
|
63
|
-
@primary.write(*args)
|
|
64
|
-
@secondary.write(*args)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def puts(*args)
|
|
68
|
-
@primary.puts(*args)
|
|
69
|
-
@secondary.puts(*args)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def flush
|
|
73
|
-
@primary.flush
|
|
74
|
-
@secondary.flush
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def isatty = @primary.isatty
|
|
78
|
-
def tty? = @primary.tty?
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
# Load config/validator.rb instead of config/sus.rb so that conformance tests
|
|
82
|
-
# live in valid/site/ and valid/supervisor/, keeping them separate from the
|
|
83
|
-
# internal tests in test/ that plain `sus` runs.
|
|
84
|
-
validator_config_class = Class.new(Sus::Config) do
|
|
85
|
-
attr_accessor :log_to_stdout, :log_path, :log_file_io
|
|
86
|
-
|
|
87
|
-
def self.path(root)
|
|
88
|
-
path = File.join(root, 'config/validator.rb')
|
|
89
|
-
File.exist?(path) ? path : nil
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
config = validator_config_class.load
|
|
94
|
-
config.log_to_stdout = log_to_stdout
|
|
95
|
-
config.log_path = log_path
|
|
96
|
-
|
|
97
|
-
registry = config.registry
|
|
98
|
-
|
|
99
|
-
def run_suite(config, registry, output, verbose)
|
|
100
|
-
assertions = Sus::Assertions.default(output: output, verbose: verbose)
|
|
101
|
-
config.before_tests(assertions)
|
|
102
|
-
registry.call(assertions)
|
|
103
|
-
config.after_tests(assertions)
|
|
104
|
-
exit(1) unless assertions.passed?
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
# When --log <path> and --verbose are both given, open the file once and share
|
|
108
|
-
# the handle: Sus writes via TeeIO (terminal + file), RSMP writes to the same
|
|
109
|
-
# File object directly. One fd => serialized writes => perfect ordering.
|
|
110
|
-
if log_path && config.verbose?
|
|
111
|
-
File.open(log_path, 'w') do |log_file|
|
|
112
|
-
config.log_path = nil
|
|
113
|
-
config.log_file_io = log_file
|
|
114
|
-
output = Sus::Output.default(TeeIO.new($stderr, log_file))
|
|
115
|
-
run_suite(config, registry, output, true)
|
|
116
|
-
end
|
|
117
|
-
else
|
|
118
|
-
output = config.verbose? ? config.output : Sus::Output::Null.new
|
|
119
|
-
run_suite(config, registry, output, config.verbose?)
|
|
120
|
-
end
|
|
5
|
+
RSMP::Validator::CLI.start(ARGV)
|
|
@@ -3,12 +3,13 @@ module RSMP
|
|
|
3
3
|
# Sus fixture module that runs each test inside the shared Async reactor.
|
|
4
4
|
# Include this in the sus base class to ensure all tests run within the reactor context.
|
|
5
5
|
module AsyncContext
|
|
6
|
-
def around
|
|
7
|
-
RSMP::Validator.reactor.run do |_task|
|
|
8
|
-
|
|
6
|
+
def around(&block)
|
|
7
|
+
task = RSMP::Validator.reactor.run do |_task|
|
|
8
|
+
catch(:rsmp_validator_test_failure, &block)
|
|
9
9
|
ensure
|
|
10
10
|
RSMP::Validator.reactor.interrupt
|
|
11
11
|
end
|
|
12
|
+
task.wait
|
|
12
13
|
end
|
|
13
14
|
end
|
|
14
15
|
end
|
|
@@ -19,25 +19,15 @@ module RSMP
|
|
|
19
19
|
return if @node
|
|
20
20
|
|
|
21
21
|
@node = build_node
|
|
22
|
-
|
|
23
|
-
@task = Async
|
|
24
|
-
task.annotate "auto_#{node_type}"
|
|
25
|
-
log("Starting auto #{node_type}")
|
|
26
|
-
@node.start
|
|
27
|
-
rescue Async::TimeoutError
|
|
28
|
-
raise RSMP::TimeoutError, "Timeout while starting auto #{node_type}"
|
|
29
|
-
end
|
|
22
|
+
log("Starting auto #{node_type}")
|
|
23
|
+
@task = @node.start(parent: Async::Task.current)
|
|
30
24
|
end
|
|
31
25
|
|
|
32
26
|
# Stop the auto node
|
|
33
27
|
def stop
|
|
34
|
-
if @node
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
@node.stop
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
@task&.stop
|
|
28
|
+
log("Stopping auto #{node_type}") if @node
|
|
29
|
+
@node&.stop
|
|
30
|
+
@task&.wait
|
|
41
31
|
ensure
|
|
42
32
|
@task = nil
|
|
43
33
|
@node = nil
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'thor'
|
|
2
|
+
require_relative '../config_check'
|
|
3
|
+
|
|
4
|
+
module RSMP
|
|
5
|
+
module Validator
|
|
6
|
+
# CLI subcommands for validator configuration.
|
|
7
|
+
class ConfigCLI < Thor
|
|
8
|
+
namespace :config
|
|
9
|
+
desc 'check PATH...', 'Validate rsmp-validator config files'
|
|
10
|
+
method_option :mode, type: :string, aliases: '-m', default: 'auto',
|
|
11
|
+
enum: %w[auto site supervisor],
|
|
12
|
+
banner: 'Validator config mode: auto, site or supervisor'
|
|
13
|
+
def check(*paths)
|
|
14
|
+
if paths.empty?
|
|
15
|
+
puts 'Error: config check requires at least one path'
|
|
16
|
+
exit 1
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
valid = true
|
|
20
|
+
paths.each do |path|
|
|
21
|
+
RSMP::Validator::ConfigCheck.check_file(path, mode: options[:mode])
|
|
22
|
+
puts 'OK'
|
|
23
|
+
rescue RSMP::ConfigurationError => e
|
|
24
|
+
valid = false
|
|
25
|
+
puts "Error: #{e.message}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
exit 1 unless valid
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'thor'
|
|
2
|
+
require_relative '../../validator'
|
|
3
|
+
require_relative 'config_cli'
|
|
4
|
+
require_relative 'run_options'
|
|
5
|
+
require_relative 'runner'
|
|
6
|
+
|
|
7
|
+
module RSMP
|
|
8
|
+
module Validator
|
|
9
|
+
# Thor entrypoint for validator commands.
|
|
10
|
+
class CLI < Thor
|
|
11
|
+
desc 'run PATH...', 'Run validator conformance tests'
|
|
12
|
+
method_option :verbose, type: :boolean, aliases: '-v', desc: 'Show detailed sus output'
|
|
13
|
+
method_option :log, type: :boolean, desc: 'Print RSMP log output to stdout'
|
|
14
|
+
method_option :log_path, type: :string, desc: 'Write RSMP log output to PATH'
|
|
15
|
+
method_option :report_json, type: :string, desc: 'Write a machine-readable compliance report to PATH'
|
|
16
|
+
method_option :core, type: :string, desc: 'Override RSMP Core version for this run'
|
|
17
|
+
method_option :sxls, type: :string, desc: 'Override SXL versions as name:version,...'
|
|
18
|
+
method_option :site_config, type: :string, desc: 'Use PATH as the site test config'
|
|
19
|
+
method_option :supervisor_config, type: :string, desc: 'Use PATH as the supervisor test config'
|
|
20
|
+
method_option :auto_site_config, type: :string, desc: 'Use PATH as the auto site config'
|
|
21
|
+
method_option :auto_supervisor_config, type: :string, desc: 'Use PATH as the auto supervisor config'
|
|
22
|
+
def run_tests(*paths)
|
|
23
|
+
run_options = RunOptions.parse(paths, thor_options: options)
|
|
24
|
+
if run_options[:log_to_stdout] && run_options[:log_path]
|
|
25
|
+
raise Thor::Error, '--log and --log-path cannot be used together'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
status = Runner.new(run_options).run
|
|
29
|
+
exit status
|
|
30
|
+
end
|
|
31
|
+
map 'run' => :run_tests
|
|
32
|
+
|
|
33
|
+
register ConfigCLI, 'config', 'config COMMAND', 'Configuration commands'
|
|
34
|
+
|
|
35
|
+
def self.exit_on_failure?
|
|
36
|
+
true
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
require 'thor'
|
|
2
|
+
|
|
3
|
+
module RSMP
|
|
4
|
+
module Validator
|
|
5
|
+
# Parses run options that Thor leaves in the path list when options appear
|
|
6
|
+
# after variadic test paths.
|
|
7
|
+
class RunOptions
|
|
8
|
+
FLAG_OPTIONS = {
|
|
9
|
+
'--verbose' => :verbose,
|
|
10
|
+
'-v' => :verbose,
|
|
11
|
+
'--log' => :log_to_stdout
|
|
12
|
+
}.freeze
|
|
13
|
+
|
|
14
|
+
VALUE_OPTIONS = {
|
|
15
|
+
'--log-path' => :log_path,
|
|
16
|
+
'--report-json' => :report_json_path,
|
|
17
|
+
'--core' => :core_version,
|
|
18
|
+
'--sxls' => :sxls,
|
|
19
|
+
'--site-config' => :site_config_path,
|
|
20
|
+
'--supervisor-config' => :supervisor_config_path,
|
|
21
|
+
'--auto-site-config' => :auto_site_config_path,
|
|
22
|
+
'--auto-supervisor-config' => :auto_supervisor_config_path
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
def self.parse(args, thor_options:)
|
|
26
|
+
new(args, thor_options).parse
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def initialize(args, thor_options)
|
|
30
|
+
@args = args
|
|
31
|
+
@parsed = {
|
|
32
|
+
paths: [],
|
|
33
|
+
verbose: thor_options[:verbose],
|
|
34
|
+
log_to_stdout: thor_options[:log],
|
|
35
|
+
log_path: thor_options[:log_path],
|
|
36
|
+
report_json_path: thor_options[:report_json],
|
|
37
|
+
core_version: thor_options[:core],
|
|
38
|
+
sxls: thor_options[:sxls],
|
|
39
|
+
site_config_path: thor_options[:site_config],
|
|
40
|
+
supervisor_config_path: thor_options[:supervisor_config],
|
|
41
|
+
auto_site_config_path: thor_options[:auto_site_config],
|
|
42
|
+
auto_supervisor_config_path: thor_options[:auto_supervisor_config]
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def parse
|
|
47
|
+
remaining = @args.dup
|
|
48
|
+
remaining.shift if remaining.first == 'run'
|
|
49
|
+
parse_remaining(remaining)
|
|
50
|
+
@parsed
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def parse_remaining(remaining)
|
|
56
|
+
parse_arg(remaining.shift, remaining) until remaining.empty?
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def parse_arg(arg, remaining)
|
|
60
|
+
flag_key = FLAG_OPTIONS[arg]
|
|
61
|
+
return @parsed[flag_key] = true if flag_key
|
|
62
|
+
|
|
63
|
+
option_key = VALUE_OPTIONS[arg]
|
|
64
|
+
return @parsed[option_key] = required_option_value(arg, remaining) if option_key
|
|
65
|
+
|
|
66
|
+
return parse_inline_value(arg) if arg.start_with?('--') && arg.include?('=')
|
|
67
|
+
|
|
68
|
+
@parsed[:paths] << arg
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def parse_inline_value(arg)
|
|
72
|
+
option, value = arg.split('=', 2)
|
|
73
|
+
option_key = VALUE_OPTIONS[option]
|
|
74
|
+
return @parsed[option_key] = value if option_key
|
|
75
|
+
|
|
76
|
+
@parsed[:paths] << arg
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def required_option_value(option, remaining)
|
|
80
|
+
value = remaining.shift
|
|
81
|
+
raise Thor::Error, "#{option} requires a value" if value.nil? || value.start_with?('-')
|
|
82
|
+
|
|
83
|
+
value
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
require 'sus'
|
|
2
|
+
require 'sus/config'
|
|
3
|
+
require_relative '../compliance/report'
|
|
4
|
+
require_relative 'tee_io'
|
|
5
|
+
require_relative 'validator_overrides'
|
|
6
|
+
|
|
7
|
+
module RSMP
|
|
8
|
+
module Validator
|
|
9
|
+
# Runs the conformance test suite through Sus while preserving validator
|
|
10
|
+
# specific options that Sus does not know about.
|
|
11
|
+
class Runner
|
|
12
|
+
include ValidatorOverrides
|
|
13
|
+
|
|
14
|
+
def initialize(options)
|
|
15
|
+
@paths = options[:paths]
|
|
16
|
+
@verbose = options[:verbose]
|
|
17
|
+
@log_to_stdout = options[:log_to_stdout]
|
|
18
|
+
@log_path = options[:log_path]
|
|
19
|
+
@report_json_path = options[:report_json_path]
|
|
20
|
+
@overrides = options.slice(
|
|
21
|
+
:core_version,
|
|
22
|
+
:sxls,
|
|
23
|
+
:site_config_path,
|
|
24
|
+
:supervisor_config_path,
|
|
25
|
+
:auto_site_config_path,
|
|
26
|
+
:auto_supervisor_config_path
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def run
|
|
31
|
+
with_argv(sus_args) { run_with_args }
|
|
32
|
+
rescue RSMP::ConnectionError
|
|
33
|
+
1
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def run_with_args
|
|
39
|
+
apply_overrides(@overrides)
|
|
40
|
+
config = validator_config_class.load
|
|
41
|
+
config.log_to_stdout = @log_to_stdout
|
|
42
|
+
config.log_path = @log_path
|
|
43
|
+
|
|
44
|
+
registry = config.registry
|
|
45
|
+
return run_with_log_file(config, registry) if @log_path && config.verbose?
|
|
46
|
+
|
|
47
|
+
run_with_default_output(config, registry)
|
|
48
|
+
ensure
|
|
49
|
+
clear_overrides(@overrides)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def sus_args
|
|
53
|
+
args = @paths.dup
|
|
54
|
+
args << '--verbose' if @verbose
|
|
55
|
+
args
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def with_argv(args)
|
|
59
|
+
original = ARGV.dup
|
|
60
|
+
ARGV.replace(args)
|
|
61
|
+
yield
|
|
62
|
+
ensure
|
|
63
|
+
ARGV.replace(original)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def validator_config_class
|
|
67
|
+
Class.new(Sus::Config) do
|
|
68
|
+
attr_accessor :log_to_stdout, :log_path, :log_file_io
|
|
69
|
+
|
|
70
|
+
def self.path(root)
|
|
71
|
+
path = File.join(root, 'config/validator.rb')
|
|
72
|
+
File.exist?(path) ? path : nil
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def run_with_log_file(config, registry)
|
|
78
|
+
File.open(@log_path, 'w') do |log_file|
|
|
79
|
+
config.log_path = nil
|
|
80
|
+
config.log_file_io = log_file
|
|
81
|
+
output = Sus::Output.default(TeeIO.new($stderr, log_file))
|
|
82
|
+
run_suite(config, registry, output, true)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def run_with_default_output(config, registry)
|
|
87
|
+
output = config.verbose? ? config.output : Sus::Output::Null.new
|
|
88
|
+
run_suite(config, registry, output, config.verbose?)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def run_suite(config, registry, output, verbose)
|
|
92
|
+
assertions = Sus::Assertions.default(output: output, verbose: verbose)
|
|
93
|
+
begin
|
|
94
|
+
config.before_tests(assertions)
|
|
95
|
+
registry.call(assertions)
|
|
96
|
+
ensure
|
|
97
|
+
config.after_tests(assertions)
|
|
98
|
+
end
|
|
99
|
+
write_report(assertions)
|
|
100
|
+
assertions.passed? ? 0 : 1
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def write_report(assertions)
|
|
104
|
+
return unless @report_json_path
|
|
105
|
+
|
|
106
|
+
RSMP::Validator::Compliance::Report.write(
|
|
107
|
+
@report_json_path,
|
|
108
|
+
assertions: assertions,
|
|
109
|
+
env: ENV,
|
|
110
|
+
args: @paths,
|
|
111
|
+
config: RSMP::Validator.config,
|
|
112
|
+
config_path: RSMP::Validator.config_path,
|
|
113
|
+
log_path: @log_path,
|
|
114
|
+
report_json_path: @report_json_path
|
|
115
|
+
)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
module Validator
|
|
3
|
+
# Writes to two IOs simultaneously through a single object, so both RSMP
|
|
4
|
+
# messages and Sus verbose output can share one file descriptor.
|
|
5
|
+
class TeeIO
|
|
6
|
+
def initialize(primary, secondary)
|
|
7
|
+
@primary = primary
|
|
8
|
+
@secondary = secondary
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def write(*args)
|
|
12
|
+
@primary.write(*args)
|
|
13
|
+
@secondary.write(*args)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def puts(*args)
|
|
17
|
+
@primary.puts(*args)
|
|
18
|
+
@secondary.puts(*args)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def flush
|
|
22
|
+
@primary.flush
|
|
23
|
+
@secondary.flush
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def isatty = @primary.isatty
|
|
27
|
+
def tty? = @primary.tty?
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
module Validator
|
|
3
|
+
# Applies CLI overrides to global validator settings for a single run.
|
|
4
|
+
module ValidatorOverrides
|
|
5
|
+
OVERRIDE_ACCESSORS = {
|
|
6
|
+
core_version: :core_version_override,
|
|
7
|
+
sxls: :sxls_override,
|
|
8
|
+
site_config_path: :site_config_path,
|
|
9
|
+
supervisor_config_path: :supervisor_config_path,
|
|
10
|
+
auto_site_config_path: :auto_site_config_path,
|
|
11
|
+
auto_supervisor_config_path: :auto_supervisor_config_path
|
|
12
|
+
}.freeze
|
|
13
|
+
|
|
14
|
+
def apply_overrides(overrides)
|
|
15
|
+
overrides.each do |name, value|
|
|
16
|
+
RSMP::Validator.public_send("#{OVERRIDE_ACCESSORS.fetch(name)}=", value)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def clear_overrides(overrides)
|
|
21
|
+
overrides.each_key do |name|
|
|
22
|
+
RSMP::Validator.public_send("#{OVERRIDE_ACCESSORS.fetch(name)}=", nil)
|
|
23
|
+
end
|
|
24
|
+
RSMP::Validator.config_path = nil
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|