spectre-core 1.10.0 → 1.11.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 +17 -4
- data/lib/spectre/assertion.rb +3 -3
- data/lib/spectre/curl.rb +45 -22
- data/lib/spectre/helpers.rb +65 -23
- data/lib/spectre/mixin.rb +9 -16
- data/lib/spectre/reporter/junit.rb +2 -0
- data/lib/spectre.rb +16 -12
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8333942c6050c7adf1bb9c238538b5364b5648514264612aefc161f715c48e58
|
4
|
+
data.tar.gz: 34ca46ef693108549a69c754bc3b22d5be33e642d9a6dfde040b664af47cfe58
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a840c8d9afd7010e0873cf273400a8a5d82b28ad05941d1c4562c03a8aed60fabc7ed704dc2538c5960a940440204df0228d0ce77b6ee11ec68f820c3deb6954
|
7
|
+
data.tar.gz: f6913fa578a938341fbd15455c1e122a4c425bacb68d1353ce7c5f0c8ed96b206eba2625d28d1d8df91fec4161343a28b15db5535c3785000c88cbee914c0f2b
|
data/exe/spectre
CHANGED
@@ -238,6 +238,10 @@ cfg.merge! env if env
|
|
238
238
|
|
239
239
|
String.colored! if cfg['colored']
|
240
240
|
|
241
|
+
# Load environment exlicitly before loading specs to make it available in spec definition
|
242
|
+
require_relative '../lib/spectre/environment' unless cfg['exclude'].include? 'spectre/environment'
|
243
|
+
Spectre.configure(cfg)
|
244
|
+
|
241
245
|
|
242
246
|
###########################################
|
243
247
|
# Load Specs
|
@@ -260,7 +264,7 @@ if action == 'list'
|
|
260
264
|
colors = [:blue, :magenta, :yellow, :green]
|
261
265
|
specs = Spectre.specs(cfg['specs'], cfg['tags'])
|
262
266
|
|
263
|
-
exit 1
|
267
|
+
exit 1 unless specs.any?
|
264
268
|
|
265
269
|
counter = 0
|
266
270
|
|
@@ -300,6 +304,7 @@ if action == 'run'
|
|
300
304
|
FileUtils.makedirs log_dir if !Dir.exists? log_dir
|
301
305
|
|
302
306
|
# Load Modules
|
307
|
+
|
303
308
|
cfg['modules']
|
304
309
|
.concat(cfg['include'])
|
305
310
|
.select { |mod| !cfg['exclude'].include? mod }
|
@@ -323,6 +328,14 @@ if action == 'run'
|
|
323
328
|
end
|
324
329
|
end
|
325
330
|
|
331
|
+
# Load mixins
|
332
|
+
|
333
|
+
cfg['mixin_patterns'].each do |pattern|
|
334
|
+
Dir.glob(pattern).each do|f|
|
335
|
+
require_relative File.join(Dir.pwd, f)
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
326
339
|
Spectre.configure(cfg)
|
327
340
|
|
328
341
|
Spectre::Logger.debug! if cfg['debug']
|
@@ -334,7 +347,7 @@ if action == 'run'
|
|
334
347
|
|
335
348
|
specs = Spectre.specs(cfg['specs'], cfg['tags'])
|
336
349
|
|
337
|
-
if specs.
|
350
|
+
if not specs.any?
|
338
351
|
puts "No specs found in #{Dir.pwd}"
|
339
352
|
exit 1
|
340
353
|
end
|
@@ -348,7 +361,7 @@ if action == 'run'
|
|
348
361
|
|
349
362
|
errors = run_infos.select { |x| x.error != nil or x.failure != nil }
|
350
363
|
|
351
|
-
exit 0 if cfg['ignore_failure'] or errors.
|
364
|
+
exit 0 if cfg['ignore_failure'] or not errors.any?
|
352
365
|
|
353
366
|
exit 1
|
354
367
|
end
|
@@ -360,7 +373,7 @@ end
|
|
360
373
|
|
361
374
|
|
362
375
|
if action == 'envs'
|
363
|
-
exit 1
|
376
|
+
exit 1 unless envs.any?
|
364
377
|
puts envs.pretty
|
365
378
|
exit 0
|
366
379
|
end
|
data/lib/spectre/assertion.rb
CHANGED
@@ -10,7 +10,7 @@ module Spectre
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def should_be_empty
|
13
|
-
raise AssertionFailure.new("The value '#{self.to_s.trim}' should be empty", nil, self) unless self
|
13
|
+
raise AssertionFailure.new("The value '#{self.to_s.trim}' should be empty", nil, self) unless self.nil?
|
14
14
|
end
|
15
15
|
|
16
16
|
def should_not_be(val)
|
@@ -91,11 +91,11 @@ module Spectre
|
|
91
91
|
end
|
92
92
|
|
93
93
|
def should_be_empty
|
94
|
-
raise AssertionFailure.new('empty list', self) unless self.
|
94
|
+
raise AssertionFailure.new('empty list', self) unless self.empty?
|
95
95
|
end
|
96
96
|
|
97
97
|
def should_not_be_empty
|
98
|
-
raise AssertionFailure.new('no empty list', self)
|
98
|
+
raise AssertionFailure.new('no empty list', self) if self.empty?
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
data/lib/spectre/curl.rb
CHANGED
@@ -192,7 +192,8 @@ module Spectre::Curl
|
|
192
192
|
return str unless str or str.empty?
|
193
193
|
|
194
194
|
begin
|
195
|
-
json = JSON.parse
|
195
|
+
json = JSON.parse(str)
|
196
|
+
json.obfuscate!(@@secure_keys) if not @@debug
|
196
197
|
|
197
198
|
if pretty
|
198
199
|
str = JSON.pretty_generate(json)
|
@@ -206,6 +207,25 @@ module Spectre::Curl
|
|
206
207
|
str
|
207
208
|
end
|
208
209
|
|
210
|
+
def is_secure? key
|
211
|
+
@@secure_keys.any? { |x| key.to_s.downcase.include? x.downcase }
|
212
|
+
end
|
213
|
+
|
214
|
+
def header_to_s headers
|
215
|
+
s = ''
|
216
|
+
|
217
|
+
return s unless headers
|
218
|
+
|
219
|
+
headers.each do |header|
|
220
|
+
key = header[0].to_s
|
221
|
+
value = header[1].to_s
|
222
|
+
value = '*****' if is_secure?(key) and not @@debug
|
223
|
+
s += "#{key.ljust(30, '.')}: #{value}\n"
|
224
|
+
end
|
225
|
+
|
226
|
+
s
|
227
|
+
end
|
228
|
+
|
209
229
|
def invoke req
|
210
230
|
cmd = [@@curl_path]
|
211
231
|
|
@@ -230,11 +250,11 @@ module Spectre::Curl
|
|
230
250
|
uri += '?'
|
231
251
|
uri += req['query']
|
232
252
|
.map { |x| x.join '='}
|
233
|
-
.join
|
253
|
+
.join('&')
|
234
254
|
end
|
235
255
|
|
236
|
-
cmd.append
|
237
|
-
cmd.append
|
256
|
+
cmd.append('"' + uri + '"')
|
257
|
+
cmd.append('-X', req['method']) unless req['method'] == 'GET' or (req['body'] and req['method'] == 'POST')
|
238
258
|
|
239
259
|
# Call all registered modules
|
240
260
|
@@modules.each do |mod|
|
@@ -243,43 +263,41 @@ module Spectre::Curl
|
|
243
263
|
|
244
264
|
# Add headers to curl command
|
245
265
|
req['headers'].each do |header|
|
246
|
-
cmd.append
|
266
|
+
cmd.append('-H', '"' + header.join(':') + '"')
|
247
267
|
end if req['headers']
|
248
268
|
|
249
269
|
# Add request body
|
250
270
|
if req['body'] != nil and not req['body'].empty?
|
251
271
|
req_body = try_format_json(req['body']).gsub(/"/, '\\"')
|
252
|
-
cmd.append
|
272
|
+
cmd.append('-d', '"' + req_body + '"')
|
253
273
|
elsif ['POST', 'PUT', 'PATCH'].include? req['method'].upcase
|
254
|
-
cmd.append
|
274
|
+
cmd.append('-d', '"\n"')
|
255
275
|
end
|
256
276
|
|
257
277
|
# Add certificate path if one if given
|
258
278
|
if req['cert']
|
259
279
|
raise "Certificate '#{req['cert']}' does not exist" unless File.exists? req['cert']
|
260
|
-
cmd.append
|
280
|
+
cmd.append('--cacert', req['cert'])
|
261
281
|
elsif req['use_ssl'] or uri.start_with? 'https'
|
262
|
-
cmd.append
|
282
|
+
cmd.append('-k')
|
263
283
|
end
|
264
284
|
|
265
|
-
cmd.append
|
266
|
-
cmd.append
|
285
|
+
cmd.append('-i')
|
286
|
+
cmd.append('-v')
|
267
287
|
|
268
|
-
@@request = OpenStruct.new
|
288
|
+
@@request = OpenStruct.new(req)
|
269
289
|
|
270
|
-
sys_cmd = cmd.join
|
290
|
+
sys_cmd = cmd.join(' ')
|
271
291
|
|
272
|
-
@@logger.debug
|
292
|
+
@@logger.debug(sys_cmd)
|
273
293
|
|
274
294
|
req_id = SecureRandom.uuid()[0..5]
|
275
295
|
|
276
296
|
req_log = "[>] #{req_id} #{req['method']} #{uri}\n"
|
277
|
-
req['headers']
|
278
|
-
|
279
|
-
end if req['headers']
|
280
|
-
req_log += req['body'] if req['body'] != nil and not req['body'].empty?
|
297
|
+
req_log += header_to_s(req['headers'])
|
298
|
+
req_log += try_format_json(req['body'], pretty: true)
|
281
299
|
|
282
|
-
@@logger.info
|
300
|
+
@@logger.info(req_log)
|
283
301
|
|
284
302
|
start_time = Time.now
|
285
303
|
|
@@ -297,7 +315,7 @@ module Spectre::Curl
|
|
297
315
|
|
298
316
|
raise "Unable to request #{uri}. Please check if this service is reachable." unless output
|
299
317
|
|
300
|
-
@@logger.debug
|
318
|
+
@@logger.debug("[<] #{req_id} stdout:\n#{output}")
|
301
319
|
|
302
320
|
header, body = output.split /\r?\n\r?\n/
|
303
321
|
|
@@ -342,7 +360,7 @@ module Spectre::Curl
|
|
342
360
|
|
343
361
|
@@logger.info res_log
|
344
362
|
|
345
|
-
@@response = SpectreHttpResponse.new
|
363
|
+
@@response = SpectreHttpResponse.new(res)
|
346
364
|
|
347
365
|
raise "Response did not indicate success: #{@@response.code} #{@@response.message}" if req['ensure_success'] and not @@response.success?
|
348
366
|
|
@@ -351,7 +369,12 @@ module Spectre::Curl
|
|
351
369
|
end
|
352
370
|
|
353
371
|
Spectre.register do |config|
|
354
|
-
@@
|
372
|
+
@@debug = config['debug']
|
373
|
+
|
374
|
+
@@logger = ::Logger.new(config['log_file'], progname: 'spectre/curl')
|
375
|
+
@@logger.level = @@debug ? Logger::DEBUG : Logger::INFO
|
376
|
+
|
377
|
+
@@secure_keys = config['secure_keys'] || []
|
355
378
|
|
356
379
|
@@curl_path = config['curl_path'] || 'curl'
|
357
380
|
|
data/lib/spectre/helpers.rb
CHANGED
@@ -13,15 +13,8 @@ class ::String
|
|
13
13
|
DateTime.parse(self)
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
|
18
|
-
file_content = File.read(self)
|
19
|
-
|
20
|
-
if with
|
21
|
-
file_content.with(with)
|
22
|
-
else
|
23
|
-
file_content
|
24
|
-
end
|
16
|
+
def as_timestamp
|
17
|
+
DateTime.parse(self).to_time.to_i
|
25
18
|
end
|
26
19
|
|
27
20
|
def with mapping
|
@@ -30,25 +23,15 @@ class ::String
|
|
30
23
|
new_string = self
|
31
24
|
|
32
25
|
mapping.each do |key, value|
|
33
|
-
new_string = new_string.gsub
|
26
|
+
new_string = new_string.gsub('#{' + key.to_s + '}', value.to_s)
|
34
27
|
end
|
35
28
|
|
36
29
|
new_string
|
37
30
|
end
|
38
31
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
def remove!
|
44
|
-
fail "'#{self}' is not a file path, or the file does not exist." if !File.exists? self
|
45
|
-
|
46
|
-
File.delete self
|
47
|
-
end
|
48
|
-
|
49
|
-
def trim count = 50
|
50
|
-
if (self.length + 3) > count
|
51
|
-
return self[0..count-4] + '...'
|
32
|
+
def trim size = 50
|
33
|
+
if (self.length + 3) > size
|
34
|
+
return self[0..size-4] + '...'
|
52
35
|
end
|
53
36
|
|
54
37
|
self
|
@@ -64,6 +47,33 @@ class ::String
|
|
64
47
|
# do nothing and return nil
|
65
48
|
end
|
66
49
|
end
|
50
|
+
|
51
|
+
# File helpers
|
52
|
+
|
53
|
+
def content with: nil
|
54
|
+
fail "'#{self}' is not a file path, or the file does not exist." if !File.exists? self
|
55
|
+
file_content = File.read(self)
|
56
|
+
|
57
|
+
if with
|
58
|
+
file_content.with(with)
|
59
|
+
else
|
60
|
+
file_content
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def file_size
|
65
|
+
fail "'#{self}' is not a file path, or the file does not exist." if !File.exists? self
|
66
|
+
File.size(self)
|
67
|
+
end
|
68
|
+
|
69
|
+
def exists?
|
70
|
+
File.exists? self
|
71
|
+
end
|
72
|
+
|
73
|
+
def remove!
|
74
|
+
fail "'#{self}' is not a file path, or the file does not exist." if !File.exists? self
|
75
|
+
File.delete self
|
76
|
+
end
|
67
77
|
end
|
68
78
|
|
69
79
|
|
@@ -77,6 +87,16 @@ class ::OpenStruct
|
|
77
87
|
|
78
88
|
JsonPath.on(self, path)
|
79
89
|
end
|
90
|
+
|
91
|
+
def default_to! defaults
|
92
|
+
defaults.each_key do |key|
|
93
|
+
if not self[key] != nil
|
94
|
+
self[key] = defaults[key]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
alias :defaults_to! :default_to!
|
80
100
|
end
|
81
101
|
|
82
102
|
|
@@ -84,9 +104,31 @@ class ::Hash
|
|
84
104
|
def symbolize_keys
|
85
105
|
self.inject({}) { |memo, (k,v)| memo[k.to_sym] = v; memo }
|
86
106
|
end
|
107
|
+
|
108
|
+
def default_to! defaults
|
109
|
+
defaults.each_key do |key|
|
110
|
+
if not self[key] != nil
|
111
|
+
self[key] = defaults[key]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
alias :defaults_to! :default_to!
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
class ::Array
|
121
|
+
def last
|
122
|
+
self[-1]
|
123
|
+
end
|
87
124
|
end
|
88
125
|
|
89
126
|
|
90
127
|
def uuid length = 5
|
91
128
|
SecureRandom.uuid().gsub('-', '')[0..length-1]
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
def now
|
133
|
+
Time.now
|
92
134
|
end
|
data/lib/spectre/mixin.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'ostruct'
|
2
|
+
require 'spectre/logger'
|
2
3
|
|
3
4
|
module Spectre
|
4
5
|
module Mixin
|
@@ -11,12 +12,16 @@ module Spectre
|
|
11
12
|
|
12
13
|
def run desc, with: []
|
13
14
|
raise "no mixin with desc '#{desc}' defined" unless @@mixins.key? desc
|
14
|
-
Logger.log_debug "running mixin '#{desc}'"
|
15
|
+
Spectre::Logger.log_debug "running mixin '#{desc}'"
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
params = with || {}
|
18
|
+
|
19
|
+
if params.is_a? Array
|
20
|
+
@@mixins[desc].call *params
|
21
|
+
elsif params.is_a? Hash
|
22
|
+
@@mixins[desc].call OpenStruct.new(params)
|
18
23
|
else
|
19
|
-
@@mixins[desc].call
|
24
|
+
@@mixins[desc].call params
|
20
25
|
end
|
21
26
|
end
|
22
27
|
|
@@ -24,18 +29,6 @@ module Spectre
|
|
24
29
|
alias_method :step, :run
|
25
30
|
end
|
26
31
|
|
27
|
-
Spectre.register do |config|
|
28
|
-
if not config.key? 'mixin_patterns'
|
29
|
-
return
|
30
|
-
end
|
31
|
-
|
32
|
-
config['mixin_patterns'].each do |pattern|
|
33
|
-
Dir.glob(pattern).each do|f|
|
34
|
-
require_relative File.join(Dir.pwd, f)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
32
|
Spectre.delegate :mixin, :run, :also, :step, to: Mixin
|
40
33
|
end
|
41
34
|
end
|
@@ -57,6 +57,7 @@ module Spectre::Reporter
|
|
57
57
|
|
58
58
|
if run_info.log.count > 0 or run_info.properties.count > 0 or run_info.data
|
59
59
|
xml_str += '<system-out>'
|
60
|
+
xml_str += '<![CDATA['
|
60
61
|
|
61
62
|
if run_info.properties.count > 0
|
62
63
|
run_info.properties.each do |key, val|
|
@@ -75,6 +76,7 @@ module Spectre::Reporter
|
|
75
76
|
xml_str += messages.join("\n")
|
76
77
|
end
|
77
78
|
|
79
|
+
xml_str += ']]>'
|
78
80
|
xml_str += '</system-out>'
|
79
81
|
end
|
80
82
|
|
data/lib/spectre.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Spectre
|
2
2
|
module Version
|
3
3
|
MAJOR = 1
|
4
|
-
MINOR =
|
4
|
+
MINOR = 11
|
5
5
|
TINY = 0
|
6
6
|
end
|
7
7
|
|
@@ -31,20 +31,20 @@ module Spectre
|
|
31
31
|
# https://www.dan-manges.com/blog/ruby-dsls-instance-eval-with-delegation
|
32
32
|
class DslClass
|
33
33
|
def _evaluate &block
|
34
|
-
@__bound_self__ = eval
|
34
|
+
@__bound_self__ = eval('self', block.binding)
|
35
35
|
instance_eval(&block)
|
36
36
|
end
|
37
37
|
|
38
38
|
def _execute args, &block
|
39
|
-
@__bound_self__ = eval
|
39
|
+
@__bound_self__ = eval('self', block.binding)
|
40
40
|
instance_exec(args, &block)
|
41
41
|
end
|
42
42
|
|
43
43
|
def method_missing method, *args, **kwargs, &block
|
44
44
|
if @__bound_self__.respond_to? method
|
45
|
-
@__bound_self__.send
|
45
|
+
@__bound_self__.send(method, *args, **kwargs, &block)
|
46
46
|
else
|
47
|
-
Delegator.redirect
|
47
|
+
Delegator.redirect(method, *args, **kwargs, &block)
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
@@ -151,7 +151,7 @@ module Spectre
|
|
151
151
|
|
152
152
|
begin
|
153
153
|
specs.each do |spec|
|
154
|
-
if spec.data.
|
154
|
+
if spec.data.any?
|
155
155
|
spec.data.each do |data|
|
156
156
|
Logger.log_spec(spec, data) do
|
157
157
|
runs << run_spec(spec, data)
|
@@ -208,7 +208,7 @@ module Spectre
|
|
208
208
|
end
|
209
209
|
|
210
210
|
def run_spec spec, data=nil
|
211
|
-
run_info = RunInfo.new
|
211
|
+
run_info = RunInfo.new(spec, data)
|
212
212
|
|
213
213
|
@@current = run_info
|
214
214
|
|
@@ -216,16 +216,16 @@ module Spectre
|
|
216
216
|
|
217
217
|
begin
|
218
218
|
if spec.context.__before_blocks.count > 0
|
219
|
-
before_ctx = SpecContext.new
|
219
|
+
before_ctx = SpecContext.new(spec.subject, 'before')
|
220
220
|
|
221
221
|
Logger.log_context before_ctx do
|
222
222
|
spec.context.__before_blocks.each do |block|
|
223
|
-
block.call
|
223
|
+
block.call(data)
|
224
224
|
end
|
225
225
|
end
|
226
226
|
end
|
227
227
|
|
228
|
-
spec.block.call
|
228
|
+
spec.block.call(data)
|
229
229
|
|
230
230
|
rescue ExpectationFailure => e
|
231
231
|
run_info.failure = e
|
@@ -240,7 +240,7 @@ module Spectre
|
|
240
240
|
|
241
241
|
ensure
|
242
242
|
if spec.context.__after_blocks.count > 0
|
243
|
-
after_ctx = SpecContext.new
|
243
|
+
after_ctx = SpecContext.new(spec.subject, 'after')
|
244
244
|
|
245
245
|
Logger.log_context after_ctx do
|
246
246
|
begin
|
@@ -306,7 +306,11 @@ module Spectre
|
|
306
306
|
.first
|
307
307
|
end
|
308
308
|
|
309
|
-
|
309
|
+
raise "`with' has to be an Array" unless with.is_a? Array
|
310
|
+
|
311
|
+
data = with.map { |x| x.is_a?(Hash) ? OpenStruct.new(x) : x }
|
312
|
+
|
313
|
+
@__subject.add_spec(desc, tags, data, block, self, spec_file)
|
310
314
|
end
|
311
315
|
|
312
316
|
def before &block
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spectre-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christian Neubauer
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ectoplasm
|