spectre-core 1.15.2 → 2.0.1

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.
metadata CHANGED
@@ -1,43 +1,84 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spectre-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.15.2
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christian Neubauer
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2025-02-19 00:00:00.000000000 Z
10
+ date: 2025-03-21 00:00:00.000000000 Z
12
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: debug
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '1.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '1.0'
13
26
  - !ruby/object:Gem::Dependency
14
27
  name: ectoplasm
15
28
  requirement: !ruby/object:Gem::Requirement
16
29
  requirements:
17
- - - ">="
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.4'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.4'
40
+ - !ruby/object:Gem::Dependency
41
+ name: logger
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: ostruct
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
18
59
  - !ruby/object:Gem::Version
19
- version: '0'
60
+ version: '0.1'
20
61
  type: :runtime
21
62
  prerelease: false
22
63
  version_requirements: !ruby/object:Gem::Requirement
23
64
  requirements:
24
- - - ">="
65
+ - - "~>"
25
66
  - !ruby/object:Gem::Version
26
- version: '0'
67
+ version: '0.1'
27
68
  - !ruby/object:Gem::Dependency
28
- name: jsonpath
69
+ name: stringio
29
70
  requirement: !ruby/object:Gem::Requirement
30
71
  requirements:
31
- - - ">="
72
+ - - "~>"
32
73
  - !ruby/object:Gem::Version
33
- version: '0'
74
+ version: '3.0'
34
75
  type: :runtime
35
76
  prerelease: false
36
77
  version_requirements: !ruby/object:Gem::Requirement
37
78
  requirements:
38
- - - ">="
79
+ - - "~>"
39
80
  - !ruby/object:Gem::Version
40
- version: '0'
81
+ version: '3.0'
41
82
  description: A DSL and command line tool to describe and run automated tests
42
83
  email:
43
84
  - christian.neubauer@ionos.com
@@ -49,30 +90,15 @@ files:
49
90
  - exe/spectre
50
91
  - lib/spectre.rb
51
92
  - lib/spectre/assertion.rb
52
- - lib/spectre/async.rb
53
- - lib/spectre/bag.rb
54
- - lib/spectre/curl.rb
55
- - lib/spectre/diagnostic.rb
56
- - lib/spectre/environment.rb
93
+ - lib/spectre/expectation.rb
57
94
  - lib/spectre/helpers.rb
58
- - lib/spectre/http.rb
59
- - lib/spectre/http/basic_auth.rb
60
- - lib/spectre/http/keystone.rb
61
- - lib/spectre/logging.rb
62
- - lib/spectre/logging/console.rb
63
- - lib/spectre/logging/file.rb
64
- - lib/spectre/mixin.rb
65
- - lib/spectre/reporter.rb
66
- - lib/spectre/reporter/console.rb
67
- - lib/spectre/resources.rb
95
+ - lib/spectre/version.rb
68
96
  homepage: https://github.com/ionos-spectre/spectre-core
69
97
  licenses:
70
98
  - GPL-3.0-or-later
71
99
  metadata:
72
- homepage_uri: https://github.com/ionos-spectre/spectre-core
73
100
  source_code_uri: https://github.com/ionos-spectre/spectre-core
74
101
  changelog_uri: https://github.com/ionos-spectre/spectre-core/blob/master/CHANGELOG.md
75
- post_install_message:
76
102
  rdoc_options: []
77
103
  require_paths:
78
104
  - lib
@@ -80,15 +106,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
80
106
  requirements:
81
107
  - - ">="
82
108
  - !ruby/object:Gem::Version
83
- version: 3.0.0
109
+ version: '3.4'
84
110
  required_rubygems_version: !ruby/object:Gem::Requirement
85
111
  requirements:
86
112
  - - ">="
87
113
  - !ruby/object:Gem::Version
88
114
  version: '0'
89
115
  requirements: []
90
- rubygems_version: 3.3.27
91
- signing_key:
116
+ rubygems_version: 3.6.2
92
117
  specification_version: 4
93
118
  summary: Describe and run automated tests
94
119
  test_files: []
data/lib/spectre/async.rb DELETED
@@ -1,31 +0,0 @@
1
- require_relative '../spectre'
2
-
3
- Thread.abort_on_exception = true
4
-
5
- module Spectre
6
- module Async
7
- class << self
8
- @@threads = {}
9
-
10
- def async name='default', &block
11
- unless @@threads.key? name
12
- @@threads[name] = []
13
- end
14
-
15
- @@threads[name] << Thread.new(&block)
16
- end
17
-
18
- def await name='default'
19
- return unless @@threads.key? name
20
-
21
- threads = @@threads[name].map { |x| x.join() }
22
-
23
- @@threads.delete(name)
24
-
25
- threads.map { |x| x.value }
26
- end
27
- end
28
-
29
- Spectre.delegate :async, :await, to: self
30
- end
31
- end
data/lib/spectre/bag.rb DELETED
@@ -1,17 +0,0 @@
1
- require_relative '../spectre'
2
-
3
- require 'ostruct'
4
-
5
- module Spectre
6
- module Bag
7
- class << self
8
- @@bag = OpenStruct.new
9
-
10
- def bag
11
- @@bag
12
- end
13
- end
14
-
15
- Spectre.delegate :bag, to: self
16
- end
17
- end
data/lib/spectre/curl.rb DELETED
@@ -1,398 +0,0 @@
1
- require_relative '../spectre'
2
-
3
- require 'open3'
4
- require 'ostruct'
5
-
6
-
7
- module Spectre::Curl
8
- class SpectreHttpRequest < Spectre::DslClass
9
- def initialize request
10
- @__req = request
11
- end
12
-
13
- def method method_name
14
- @__req['method'] = method_name.upcase
15
- end
16
-
17
- def url base_url
18
- @__req['base_url'] = base_url
19
- end
20
-
21
- def path url_path
22
- @__req['path'] = url_path
23
- end
24
-
25
- def header name, value
26
- @__req['headers'] = [] unless @__req['headers']
27
- @__req['headers'].append [name, value.to_s.strip]
28
- end
29
-
30
- def param name, value
31
- @__req['query'] = [] unless @__req['query']
32
- @__req['query'].append [name, value.to_s.strip]
33
- end
34
-
35
- def content_type media_type
36
- @__req['headers'] = [] unless @__req['headers']
37
- @__req['headers'].append ['Content-Type', media_type]
38
- end
39
-
40
- def json data
41
- body JSON.pretty_generate(data)
42
- content_type 'application/json'
43
- end
44
-
45
- def body body_content
46
- @__req['body'] = body_content
47
- end
48
-
49
- def ensure_success!
50
- @__req['ensure_success'] = true
51
- end
52
-
53
- def ensure_success?
54
- @__req['ensure_success']
55
- end
56
-
57
- def authenticate method
58
- @__req['auth'] = method
59
- end
60
-
61
- def certificate path
62
- @__req['cert'] = path
63
- use_ssl!
64
- end
65
-
66
- def use_ssl!
67
- @__req['use_ssl'] = true
68
- end
69
-
70
- alias_method :auth, :authenticate
71
- alias_method :cert, :certificate
72
- alias_method :media_type, :content_type
73
- end
74
-
75
- class SpectreHttpHeader
76
- def initialize headers
77
- @headers = headers || {}
78
- end
79
-
80
- def [] key
81
- @headers[key.downcase]
82
- end
83
- end
84
-
85
- class SpectreHttpResponse
86
- def initialize res
87
- @res = res
88
- @data = nil
89
- end
90
-
91
- def code
92
- @res[:code]
93
- end
94
-
95
- def message
96
- @res[:message]
97
- end
98
-
99
- def protocol
100
- @res[:protocol]
101
- end
102
-
103
- def version
104
- @res[:version]
105
- end
106
-
107
- def headers
108
- SpectreHttpHeader.new @res[:headers]
109
- end
110
-
111
- def body
112
- @res[:body]
113
- end
114
-
115
- def json
116
- return nil unless @res[:body]
117
-
118
- if @data == nil
119
- begin
120
- @data = JSON.parse(@res[:body], object_class: OpenStruct)
121
- rescue
122
- raise 'invalid json'
123
- end
124
- end
125
-
126
- @data
127
- end
128
-
129
- def success?
130
- @res[:code] < 400
131
- end
132
-
133
- def pretty
134
- @res.pretty
135
- end
136
- end
137
-
138
- # DEFAULT_HTTP_REQUEST = {
139
- # 'method' => 'GET', # -X, --request <cmd>
140
- # 'base_url' => nil,
141
- # 'path' => nil,
142
- # 'headers' => nil, # -H, --header <header/@file>
143
- # 'query' => nil,
144
- # 'body' => nil, # -d, --data <data>
145
- # 'cert' => nil, # --cacert
146
- # 'follow' => false, # -L, --location
147
- # 'username' => nil, # -u, --user <user:password>
148
- # 'password' => nil,
149
- # 'use_ssl' => false, # -k
150
- # }
151
-
152
-
153
- class << self
154
- @@http_cfg = {}
155
- @@response = nil
156
- @@request = nil
157
- @@modules = []
158
-
159
- def curl name, secure: false, &block
160
- req = {
161
- 'use_ssl' => secure,
162
- }
163
-
164
- if @@http_cfg.key? name
165
- req.merge! @@http_cfg[name]
166
- raise "No `base_url' set for HTTP client '#{name}'. Check your HTTP config in your environment." unless req['base_url']
167
- else
168
- req['base_url'] = name
169
- end
170
-
171
- SpectreHttpRequest.new(req)._evaluate(&block) if block_given?
172
-
173
- invoke(req)
174
- end
175
-
176
- def curl_request
177
- raise 'No request has been invoked yet' unless @@request
178
-
179
- @@request
180
- end
181
-
182
- def curl_response
183
- raise 'There is no response. No request has been invoked yet.' unless @@response
184
-
185
- @@response
186
- end
187
-
188
- def register mod
189
- raise 'Module must not be nil' unless mod
190
-
191
- @@modules << mod
192
- end
193
-
194
- private
195
-
196
- def try_format_json str, pretty: false
197
- return str unless str or str.empty?
198
-
199
- begin
200
- json = JSON.parse(str)
201
- json.obfuscate!(@@secure_keys) unless @@debug
202
-
203
- if pretty
204
- str = JSON.pretty_generate(json)
205
- else
206
- str = JSON.dump(json)
207
- end
208
- rescue
209
- # do nothing
210
- end
211
-
212
- str
213
- end
214
-
215
- def secure? key
216
- @@secure_keys.any? { |x| key.to_s.downcase.include? x.downcase }
217
- end
218
-
219
- def header_to_s headers
220
- s = ''
221
-
222
- return s unless headers
223
-
224
- headers.each do |header|
225
- key = header[0].to_s
226
- value = header[1].to_s
227
- value = '*****' if secure?(key) and not @@debug
228
- s += "#{key.ljust(30, '.')}: #{value}\n"
229
- end
230
-
231
- s
232
- end
233
-
234
- def invoke req
235
- cmd = [@@curl_path]
236
-
237
- if req['cert'] or req['use_ssl']
238
- scheme = 'https'
239
- else
240
- scheme = 'http'
241
- end
242
-
243
- uri = req['base_url']
244
-
245
- unless uri.match /http(?:s)?:\/\//
246
- uri = scheme + '://' + uri
247
- end
248
-
249
- if req['path']
250
- uri += '/' unless uri.end_with? '/'
251
- uri += req['path']
252
- end
253
-
254
- if req['query']
255
- uri += '?'
256
- uri += req['query']
257
- .map { |x| x.join '='}
258
- .join('&')
259
- end
260
-
261
- cmd.append('"' + uri + '"')
262
- cmd.append('-X', req['method']) unless req['method'] == 'GET' or (req['body'] and req['method'] == 'POST')
263
-
264
- # Call all registered modules
265
- @@modules.each do |mod|
266
- mod.on_req(req, cmd) if mod.respond_to? :on_req
267
- end
268
-
269
- # Add headers to curl command
270
- req['headers'].each do |header|
271
- cmd.append('-H', '"' + header.join(':') + '"')
272
- end if req['headers']
273
-
274
- # Add request body
275
- if req['body'] != nil and not req['body'].empty?
276
- req_body = try_format_json(req['body']).gsub(/"/, '\\"')
277
- cmd.append('-d', '"' + req_body + '"')
278
- elsif ['POST', 'PUT', 'PATCH'].include? req['method'].upcase
279
- cmd.append('-d', '"\n"')
280
- end
281
-
282
- # Add certificate path if one is given
283
- if req['cert']
284
- raise "Certificate '#{req['cert']}' does not exist" unless File.exist? req['cert']
285
-
286
- cmd.append('--cacert', req['cert'])
287
- elsif req['use_ssl'] or uri.start_with? 'https'
288
- cmd.append('-k')
289
- end
290
-
291
- cmd.append('-i')
292
- cmd.append('-v')
293
-
294
- @@request = OpenStruct.new(req)
295
-
296
- sys_cmd = cmd.join(' ')
297
-
298
- @@logger.debug(sys_cmd)
299
-
300
- req_id = SecureRandom.uuid()[0..5]
301
-
302
- req_log = "[>] #{req_id} #{req['method']} #{uri}\n"
303
- req_log += header_to_s(req['headers'])
304
-
305
- if req[:body] != nil and not req[:body].empty?
306
- req_log += try_format_json(req['body'], pretty: true)
307
- end
308
-
309
- @@logger.info(req_log)
310
-
311
- start_time = Time.now
312
-
313
- _, stdout, stderr, wait_thr = Open3.popen3(sys_cmd)
314
-
315
- end_time = Time.now
316
-
317
- output = stdout.gets(nil)
318
- stdout.close
319
-
320
- debug_log = stderr.gets(nil)
321
- stderr.close
322
-
323
- # debug_log.lines.each { |x| @@logger.debug x unless x.empty? }
324
-
325
- raise "Unable to request #{uri}. Please check if this URL is correctly configured and reachable." unless output
326
-
327
- @@logger.debug("[<] #{req_id} stdout:\n#{output}")
328
-
329
- header, body = output.split /\r?\n\r?\n/
330
-
331
- result = header.lines.first
332
-
333
- exit_code = wait_thr.value.exitstatus
334
-
335
- raise Exception.new "An error occurred while executing curl:\n#{debug_log.lines.map { |x| not x.empty? }}" unless exit_code == 0
336
-
337
- # Parse protocol, version, status code and status message from response
338
- match = /^(?<protocol>[A-Za-z0-9]+)\/(?<version>\d+\.?\d*) (?<code>\d+) (?<message>.*)/.match result
339
-
340
- raise "Unexpected result from curl request:\n#{result}" unless match
341
-
342
- res_headers = header.lines[1..-1]
343
- .map { |x| /^(?<key>[A-Za-z0-9-]+):\s*(?<value>.*)$/.match x }
344
- .select { |x| x != nil }
345
- .map { |x| [x[:key].downcase, x[:value]] }
346
-
347
- res = {
348
- protocol: match[:protocol],
349
- version: match[:version],
350
- code: match[:code].to_i,
351
- message: match[:message],
352
- headers: Hash[res_headers],
353
- body: body,
354
- }
355
-
356
- # Call all registered modules
357
- @@modules.each do |mod|
358
- mod.on_res(res, output) if mod.respond_to? :on_res
359
- end
360
-
361
- res_log = "[<] #{req_id} #{res[:code]} #{res[:message]} (#{end_time - start_time}s)\n"
362
- res_headers.each do |http_header|
363
- res_log += "#{http_header[0].to_s.ljust(30, '.')}: #{http_header[1].to_s}\n"
364
- end
365
-
366
- if res[:body] != nil and not res[:body].empty?
367
- res_log += try_format_json(res[:body], pretty: true)
368
- end
369
-
370
- @@logger.info res_log
371
-
372
- @@response = SpectreHttpResponse.new(res)
373
-
374
- raise "Response did not indicate success: #{@@response.code} #{@@response.message}" if req['ensure_success'] and not @@response.success?
375
-
376
- @@response
377
- end
378
- end
379
-
380
- Spectre.register do |config|
381
- @@debug = config['debug']
382
-
383
- @@logger = Spectre::Logging::ModuleLogger.new(config, 'spectre/curl')
384
-
385
- @@secure_keys = config['secure_keys'] || []
386
- @@curl_path = config['curl_path'] || 'curl'
387
-
388
- if config.key? 'http'
389
- @@http_cfg = {}
390
-
391
- config['http'].each do |name, cfg|
392
- @@http_cfg[name] = cfg
393
- end
394
- end
395
- end
396
-
397
- Spectre.delegate :curl, :curl_response, :curl_request, to: self
398
- end
@@ -1,39 +0,0 @@
1
- require_relative '../spectre'
2
-
3
- module Spectre
4
- module Diagnostic
5
- module Stopwatch
6
- @@duration = 0.0
7
-
8
- class << self
9
- def start_watch
10
- @@start_time = Time.now
11
- end
12
-
13
- def stop_watch
14
- @@end_time = Time.now
15
- end
16
-
17
- def measure
18
- start_watch
19
- yield
20
- stop_watch
21
- end
22
-
23
- def duration
24
- @@end_time - @@start_time
25
- end
26
-
27
- def started_at
28
- @@start_time
29
- end
30
-
31
- def finished_at
32
- @@end_time
33
- end
34
- end
35
-
36
- Spectre.delegate :start_watch, :stop_watch, :duration, :measure, to: self
37
- end
38
- end
39
- end
@@ -1,30 +0,0 @@
1
- require_relative '../spectre'
2
-
3
- require 'ostruct'
4
-
5
- def to_recursive_ostruct(hash)
6
- OpenStruct.new(
7
- hash.each_with_object({}) do |(key, val), memo|
8
- memo[key] = val.is_a?(Hash) ? to_recursive_ostruct(val) : val
9
- end
10
- )
11
- end
12
-
13
- module Spectre
14
- module Environment
15
- class << self
16
- @@environment = OpenStruct.new
17
-
18
- def env
19
- @@environment
20
- end
21
- end
22
-
23
- Spectre.register do |config|
24
- @@environment = to_recursive_ostruct(config)
25
- @@environment.freeze
26
- end
27
-
28
- Spectre.delegate :env, to: self
29
- end
30
- end
@@ -1,25 +0,0 @@
1
- require_relative '../http'
2
-
3
- module Spectre::Http
4
- class SpectreHttpRequest
5
- def basic_auth username, password
6
- @__req['basic_auth'] = {} unless @__req.key? 'basic_auth'
7
-
8
- @__req['basic_auth']['username'] = username
9
- @__req['basic_auth']['password'] = password
10
-
11
- @__req['auth'] = 'basic_auth'
12
- end
13
- end
14
-
15
- module BasicAuth
16
- def self.on_req _http, net_req, req
17
- return unless req.key? 'basic_auth' and req['auth'] == 'basic_auth'
18
-
19
- basic_auth_cfg = req['basic_auth']
20
- net_req.basic_auth(basic_auth_cfg['username'], basic_auth_cfg['password'])
21
- end
22
-
23
- Spectre::Http.register(self)
24
- end
25
- end