spectre-core 1.11.0 → 1.12.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 +4 -4
- data/exe/spectre +516 -524
- data/lib/spectre/assertion.rb +33 -14
- data/lib/spectre/bag.rb +21 -19
- data/lib/spectre/curl.rb +397 -391
- data/lib/spectre/diagnostic.rb +39 -29
- data/lib/spectre/environment.rb +30 -26
- data/lib/spectre/helpers.rb +133 -134
- data/lib/spectre/http/basic_auth.rb +5 -2
- data/lib/spectre/http/keystone.rb +76 -73
- data/lib/spectre/http.rb +82 -76
- data/lib/spectre/logger/console.rb +143 -142
- data/lib/spectre/logger/file.rb +1 -1
- data/lib/spectre/logger.rb +3 -1
- data/lib/spectre/mixin.rb +58 -34
- data/lib/spectre/reporter/console.rb +102 -104
- data/lib/spectre/reporter/junit.rb +100 -100
- data/lib/spectre/resources.rb +49 -46
- data/lib/spectre.rb +440 -438
- metadata +3 -3
data/lib/spectre/mixin.rb
CHANGED
@@ -1,34 +1,58 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
def
|
10
|
-
|
11
|
-
end
|
12
|
-
|
13
|
-
def
|
14
|
-
|
15
|
-
Spectre::Logger.log_debug
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
1
|
+
require_relative '../spectre'
|
2
|
+
require_relative 'logger'
|
3
|
+
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
module Spectre
|
7
|
+
module Mixin
|
8
|
+
class MixinContext < Spectre::DslClass
|
9
|
+
def initialize desc
|
10
|
+
@__desc = desc
|
11
|
+
end
|
12
|
+
|
13
|
+
def required params, *keys
|
14
|
+
missing_keys = keys.select { |x| !params.to_h.key? x }
|
15
|
+
Spectre::Logger.log_debug("required parameters for '#{@__desc}': #{keys.join ', '}")
|
16
|
+
raise ArgumentError, "mixin '#{@__desc}' requires #{keys.join ', '}, but only has #{missing_keys.join ', '} given" unless missing_keys.empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
def optional params, *keys
|
20
|
+
Spectre::Logger.log_debug("optional parameters for '#{@__desc}': #{keys.join ', '}")
|
21
|
+
params
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class << self
|
26
|
+
@@mixins = {}
|
27
|
+
|
28
|
+
def mixin desc, &block
|
29
|
+
@@mixins[desc] = block
|
30
|
+
end
|
31
|
+
|
32
|
+
def run desc, with: []
|
33
|
+
raise "no mixin with desc '#{desc}' defined" unless @@mixins.key? desc
|
34
|
+
|
35
|
+
Spectre::Logger.log_debug "running mixin '#{desc}'"
|
36
|
+
|
37
|
+
params = with || {}
|
38
|
+
|
39
|
+
ctx = MixinContext.new(desc)
|
40
|
+
|
41
|
+
if params.is_a? Array
|
42
|
+
return_val = ctx._execute(*params, &@@mixins[desc])
|
43
|
+
elsif params.is_a? Hash
|
44
|
+
return_val = ctx._execute(OpenStruct.new(params), &@@mixins[desc])
|
45
|
+
else
|
46
|
+
return_val = ctx._execute(params, &@@mixins[desc])
|
47
|
+
end
|
48
|
+
|
49
|
+
return_val.is_a?(Hash) ? OpenStruct.new(return_val) : return_val
|
50
|
+
end
|
51
|
+
|
52
|
+
alias_method :also, :run
|
53
|
+
alias_method :step, :run
|
54
|
+
end
|
55
|
+
|
56
|
+
Spectre.delegate :mixin, :run, :also, :step, to: self
|
57
|
+
end
|
58
|
+
end
|
@@ -1,104 +1,102 @@
|
|
1
|
-
module Spectre::Reporter
|
2
|
-
class Console
|
3
|
-
def initialize config
|
4
|
-
@config = config
|
5
|
-
end
|
6
|
-
|
7
|
-
def report run_infos
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
.
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
report_str += "
|
25
|
-
|
26
|
-
report_str += "
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
summary
|
53
|
-
summary += "#{
|
54
|
-
summary += "#{
|
55
|
-
summary += "#{
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
summary
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
title
|
73
|
-
title +=
|
74
|
-
title
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
non_spectre_files
|
81
|
-
|
82
|
-
|
83
|
-
causing_file =
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
str
|
96
|
-
str += "
|
97
|
-
str += "
|
98
|
-
str += "
|
99
|
-
str
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
end
|
104
|
-
end
|
1
|
+
module Spectre::Reporter
|
2
|
+
class Console
|
3
|
+
def initialize config
|
4
|
+
@config = config
|
5
|
+
end
|
6
|
+
|
7
|
+
def report run_infos
|
8
|
+
report_str = ''
|
9
|
+
|
10
|
+
errors = 0
|
11
|
+
failures = 0
|
12
|
+
skipped = run_infos.select { |x| x.skipped? }.count
|
13
|
+
|
14
|
+
run_infos
|
15
|
+
.select { |x| x.error != nil or x.failure != nil }
|
16
|
+
.each_with_index do |run_info, index|
|
17
|
+
spec = run_info.spec
|
18
|
+
|
19
|
+
report_str += "\n#{index+1}) #{format_title(run_info)}\n"
|
20
|
+
|
21
|
+
if run_info.failure
|
22
|
+
report_str += " Expected #{run_info.failure.expectation}"
|
23
|
+
report_str += " with #{run_info.data}" if run_info.data
|
24
|
+
report_str += " during #{spec.context.__desc}" if spec.context.__desc
|
25
|
+
|
26
|
+
report_str += " but it failed"
|
27
|
+
|
28
|
+
if run_info.failure.cause
|
29
|
+
report_str += "\n with an unexpected error:\n"
|
30
|
+
report_str += format_exception(run_info.failure.cause)
|
31
|
+
|
32
|
+
elsif run_info.failure.message and not run_info.failure.message.empty?
|
33
|
+
report_str += " with:\n #{run_info.failure.message}"
|
34
|
+
|
35
|
+
else
|
36
|
+
report_str += '.'
|
37
|
+
end
|
38
|
+
|
39
|
+
report_str += "\n"
|
40
|
+
failures += 1
|
41
|
+
|
42
|
+
else
|
43
|
+
report_str += " but an unexpected error occured during run\n"
|
44
|
+
report_str += format_exception(run_info.error)
|
45
|
+
errors += 1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
if failures + errors > 0
|
50
|
+
summary = ''
|
51
|
+
summary += "#{run_infos.length - failures - errors - skipped} succeeded "
|
52
|
+
summary += "#{failures} failures " if failures > 0
|
53
|
+
summary += "#{errors} errors " if errors > 0
|
54
|
+
summary += "#{skipped} skipped " if skipped > 0
|
55
|
+
summary += "#{run_infos.length} total"
|
56
|
+
print "\n#{summary}\n".red
|
57
|
+
else
|
58
|
+
summary = ''
|
59
|
+
summary = "\nRun finished successfully"
|
60
|
+
summary += " (#{skipped} skipped)" if skipped > 0
|
61
|
+
print "#{summary}\n".green
|
62
|
+
end
|
63
|
+
|
64
|
+
puts report_str.red
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def format_title run_info
|
70
|
+
title = run_info.spec.subject.desc
|
71
|
+
title += ' ' + run_info.spec.desc
|
72
|
+
title += " (#{'%.3f' % run_info.duration}s)"
|
73
|
+
title += " [#{run_info.spec.name}]"
|
74
|
+
title
|
75
|
+
end
|
76
|
+
|
77
|
+
def format_exception error
|
78
|
+
non_spectre_files = error.backtrace.select { |x| !x.include? 'lib/spectre' }
|
79
|
+
|
80
|
+
if non_spectre_files.count > 0
|
81
|
+
causing_file = non_spectre_files.first
|
82
|
+
else
|
83
|
+
causing_file = error.backtrace[0]
|
84
|
+
end
|
85
|
+
|
86
|
+
matches = causing_file.match(/(.*\.rb):(\d+)/)
|
87
|
+
|
88
|
+
return '' unless matches
|
89
|
+
|
90
|
+
file, line = matches.captures
|
91
|
+
file.slice!(Dir.pwd + '/')
|
92
|
+
|
93
|
+
str = ''
|
94
|
+
str += " file.....: #{file}\n"
|
95
|
+
str += " line.....: #{line}\n"
|
96
|
+
str += " type.....: #{error.class}\n"
|
97
|
+
str += " message..: #{error.message}\n"
|
98
|
+
str += " backtrace: \n #{error.backtrace.join("\n ")}\n" if @config['debug']
|
99
|
+
str
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -1,100 +1,100 @@
|
|
1
|
-
# https://llg.cubic.org/docs/junit/
|
2
|
-
# Azure mappings: https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/test/publish-test-results?view=azure-devops&tabs=junit%2Cyaml
|
3
|
-
|
4
|
-
module Spectre::Reporter
|
5
|
-
class JUnit
|
6
|
-
def initialize config
|
7
|
-
@config = config
|
8
|
-
end
|
9
|
-
|
10
|
-
def report run_infos
|
11
|
-
now = Time.now.getutc
|
12
|
-
timestamp = now.strftime('%s')
|
13
|
-
datetime = now.strftime('%FT%T%:z')
|
14
|
-
|
15
|
-
xml_str = '<?xml version="1.0" encoding="UTF-8" ?>'
|
16
|
-
xml_str += '<testsuites>'
|
17
|
-
|
18
|
-
suite_id = 0
|
19
|
-
|
20
|
-
run_infos.group_by { |x| x.spec.subject }.each do |subject, run_infos|
|
21
|
-
failures = run_infos.select { |x| x.failure != nil }
|
22
|
-
errors = run_infos.select { |x| x.error != nil }
|
23
|
-
skipped = run_infos.select { |x| x.skipped? }
|
24
|
-
|
25
|
-
xml_str += '<testsuite package="' + subject.desc + '" id="' + suite_id.to_s + '" name="' + subject.desc + '" timestamp="' + datetime + '" tests="' + run_infos.count.to_s + '" failures="' + failures.count.to_s + '" errors="' + errors.count.to_s + '" skipped="' + skipped.count.to_s + '">'
|
26
|
-
suite_id += 1
|
27
|
-
|
28
|
-
run_infos.each do |run_info|
|
29
|
-
xml_str += '<testcase classname="' + run_info.spec.file.to_s + '" name="' + run_info.spec.desc + '" timestamp="' + run_info.started.to_s + '" time="' + ('%.3f' % run_info.duration) + '">'
|
30
|
-
|
31
|
-
if run_info.failure and !run_info.failure.cause
|
32
|
-
failure_message = "Expected #{run_info.failure.expectation}"
|
33
|
-
failure_message += " with #{run_info.data}" if run_info.data
|
34
|
-
|
35
|
-
if run_info.failure.message
|
36
|
-
failure_message += " but it failed with #{run_info.failure.message}"
|
37
|
-
else
|
38
|
-
failure_message += " but it failed"
|
39
|
-
end
|
40
|
-
|
41
|
-
xml_str += '<failure message="' + failure_message.gsub('"', '`') + '"></failure>'
|
42
|
-
end
|
43
|
-
|
44
|
-
|
45
|
-
if run_info.error or (run_info.failure and run_info.failure.cause)
|
46
|
-
error = run_info.error || run_info.failure.cause
|
47
|
-
|
48
|
-
type = error.class.name
|
49
|
-
failure_message = error.message
|
50
|
-
text = error.backtrace.join "\n"
|
51
|
-
|
52
|
-
xml_str += '<error message="' + failure_message.gsub('"', '`') + '" type="' + type + '">'
|
53
|
-
xml_str += '<![CDATA[' + text + ']]>'
|
54
|
-
xml_str += '</error>'
|
55
|
-
end
|
56
|
-
|
57
|
-
|
58
|
-
if run_info.log.count > 0 or run_info.properties.count > 0 or run_info.data
|
59
|
-
xml_str += '<system-out>'
|
60
|
-
xml_str += '<![CDATA['
|
61
|
-
|
62
|
-
if
|
63
|
-
run_info.properties.each do |key, val|
|
64
|
-
xml_str += "#{key}: #{val}\n"
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
if run_info.data
|
69
|
-
data_str = run_info.data
|
70
|
-
data_str = run_info.data.inspect unless run_info.data.is_a? String or run_info.data.is_a? Integer
|
71
|
-
xml_str += "data: #{data_str}\n"
|
72
|
-
end
|
73
|
-
|
74
|
-
if run_info.log.count > 0
|
75
|
-
messages = run_info.log.map { |x| "[#{x[0].strftime('%F %T')}] #{x[1]}" }
|
76
|
-
xml_str += messages.join("\n")
|
77
|
-
end
|
78
|
-
|
79
|
-
xml_str += ']]>'
|
80
|
-
xml_str += '</system-out>'
|
81
|
-
end
|
82
|
-
|
83
|
-
xml_str += '</testcase>'
|
84
|
-
end
|
85
|
-
|
86
|
-
xml_str += '</testsuite>'
|
87
|
-
end
|
88
|
-
|
89
|
-
xml_str += '</testsuites>'
|
90
|
-
|
91
|
-
Dir.mkdir @config['out_path']
|
92
|
-
|
93
|
-
file_path = File.join(@config['out_path'], "spectre-junit_#{timestamp}.xml")
|
94
|
-
|
95
|
-
File.open(file_path, 'w') do |file|
|
96
|
-
file.write(xml_str)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
1
|
+
# https://llg.cubic.org/docs/junit/
|
2
|
+
# Azure mappings: https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/test/publish-test-results?view=azure-devops&tabs=junit%2Cyaml
|
3
|
+
|
4
|
+
module Spectre::Reporter
|
5
|
+
class JUnit
|
6
|
+
def initialize config
|
7
|
+
@config = config
|
8
|
+
end
|
9
|
+
|
10
|
+
def report run_infos
|
11
|
+
now = Time.now.getutc
|
12
|
+
timestamp = now.strftime('%s')
|
13
|
+
datetime = now.strftime('%FT%T%:z')
|
14
|
+
|
15
|
+
xml_str = '<?xml version="1.0" encoding="UTF-8" ?>'
|
16
|
+
xml_str += '<testsuites>'
|
17
|
+
|
18
|
+
suite_id = 0
|
19
|
+
|
20
|
+
run_infos.group_by { |x| x.spec.subject }.each do |subject, run_infos|
|
21
|
+
failures = run_infos.select { |x| x.failure != nil }
|
22
|
+
errors = run_infos.select { |x| x.error != nil }
|
23
|
+
skipped = run_infos.select { |x| x.skipped? }
|
24
|
+
|
25
|
+
xml_str += '<testsuite package="' + subject.desc + '" id="' + suite_id.to_s + '" name="' + subject.desc + '" timestamp="' + datetime + '" tests="' + run_infos.count.to_s + '" failures="' + failures.count.to_s + '" errors="' + errors.count.to_s + '" skipped="' + skipped.count.to_s + '">'
|
26
|
+
suite_id += 1
|
27
|
+
|
28
|
+
run_infos.each do |run_info|
|
29
|
+
xml_str += '<testcase classname="' + run_info.spec.file.to_s + '" name="' + run_info.spec.desc + '" timestamp="' + run_info.started.to_s + '" time="' + ('%.3f' % run_info.duration) + '">'
|
30
|
+
|
31
|
+
if run_info.failure and !run_info.failure.cause
|
32
|
+
failure_message = "Expected #{run_info.failure.expectation}"
|
33
|
+
failure_message += " with #{run_info.data}" if run_info.data
|
34
|
+
|
35
|
+
if run_info.failure.message
|
36
|
+
failure_message += " but it failed with #{run_info.failure.message}"
|
37
|
+
else
|
38
|
+
failure_message += " but it failed"
|
39
|
+
end
|
40
|
+
|
41
|
+
xml_str += '<failure message="' + failure_message.gsub('"', '`') + '"></failure>'
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
if run_info.error or (run_info.failure and run_info.failure.cause)
|
46
|
+
error = run_info.error || run_info.failure.cause
|
47
|
+
|
48
|
+
type = error.class.name
|
49
|
+
failure_message = error.message
|
50
|
+
text = error.backtrace.join "\n"
|
51
|
+
|
52
|
+
xml_str += '<error message="' + failure_message.gsub('"', '`') + '" type="' + type + '">'
|
53
|
+
xml_str += '<![CDATA[' + text + ']]>'
|
54
|
+
xml_str += '</error>'
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
if run_info.log.count > 0 or run_info.properties.count > 0 or run_info.data
|
59
|
+
xml_str += '<system-out>'
|
60
|
+
xml_str += '<![CDATA['
|
61
|
+
|
62
|
+
if run_info.properties.count > 0
|
63
|
+
run_info.properties.each do |key, val|
|
64
|
+
xml_str += "#{key}: #{val}\n"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
if run_info.data
|
69
|
+
data_str = run_info.data
|
70
|
+
data_str = run_info.data.inspect unless run_info.data.is_a? String or run_info.data.is_a? Integer
|
71
|
+
xml_str += "data: #{data_str}\n"
|
72
|
+
end
|
73
|
+
|
74
|
+
if run_info.log.count > 0
|
75
|
+
messages = run_info.log.map { |x| "[#{x[0].strftime('%F %T')}] #{x[1]}" }
|
76
|
+
xml_str += messages.join("\n")
|
77
|
+
end
|
78
|
+
|
79
|
+
xml_str += ']]>'
|
80
|
+
xml_str += '</system-out>'
|
81
|
+
end
|
82
|
+
|
83
|
+
xml_str += '</testcase>'
|
84
|
+
end
|
85
|
+
|
86
|
+
xml_str += '</testsuite>'
|
87
|
+
end
|
88
|
+
|
89
|
+
xml_str += '</testsuites>'
|
90
|
+
|
91
|
+
Dir.mkdir @config['out_path'] unless Dir.exist? @config['out_path']
|
92
|
+
|
93
|
+
file_path = File.join(@config['out_path'], "spectre-junit_#{timestamp}.xml")
|
94
|
+
|
95
|
+
File.open(file_path, 'w') do |file|
|
96
|
+
file.write(xml_str)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/lib/spectre/resources.rb
CHANGED
@@ -1,46 +1,49 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
1
|
+
require_relative '../spectre'
|
2
|
+
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
module Spectre
|
6
|
+
module Resources
|
7
|
+
class ResourceCollection
|
8
|
+
def initialize
|
9
|
+
@items = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def add name, path
|
13
|
+
@items[name] = path
|
14
|
+
end
|
15
|
+
|
16
|
+
def [] name
|
17
|
+
raise "Resource with name '#{name}' does not exist" unless @items.key? name
|
18
|
+
|
19
|
+
@items[name]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class << self
|
24
|
+
@@resources = ResourceCollection.new
|
25
|
+
|
26
|
+
def resources
|
27
|
+
@@resources
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Spectre.register do |config|
|
32
|
+
return unless config.key? 'resource_paths'
|
33
|
+
|
34
|
+
config['resource_paths'].each do |resource_path|
|
35
|
+
resource_files = Dir.glob File.join(resource_path, '**/*')
|
36
|
+
|
37
|
+
resource_files.each do |file|
|
38
|
+
file.slice! resource_path
|
39
|
+
file = file[1..-1]
|
40
|
+
@@resources.add file, File.expand_path(File.join resource_path, file)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
@@resources.freeze
|
45
|
+
end
|
46
|
+
|
47
|
+
Spectre.delegate :resources, to: self
|
48
|
+
end
|
49
|
+
end
|