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.
data/exe/spectre CHANGED
@@ -1,524 +1,516 @@
1
- #! /usr/bin/ruby
2
- # frozen_string_literal: true
3
-
4
- require 'yaml'
5
- require 'ostruct'
6
- require 'optparse'
7
- require 'fileutils'
8
- require 'ectoplasm'
9
-
10
- require_relative '../lib/spectre'
11
-
12
-
13
- class ::Hash
14
- def deep_merge!(second)
15
- merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge!(v2, &merger) : v2 }
16
- self.merge!(second, &merger)
17
- end
18
- end
19
-
20
-
21
- DEFAULT_CONFIG = {
22
- 'config_file' => './spectre.yml',
23
- 'environment' => 'default',
24
- 'specs' => [],
25
- 'tags' => [],
26
- 'colored' => true,
27
- 'verbose' => false,
28
- 'reporters' => [
29
- 'Spectre::Reporter::Console',
30
- ],
31
- 'loggers' => [
32
- 'Spectre::Logger::Console',
33
- 'Spectre::Logger::File',
34
- ],
35
- 'log_file' => './logs/spectre_<date>.log',
36
- 'log_format' => {
37
- 'console' => {
38
- 'indent' => 2,
39
- 'width' => 80,
40
- 'end_context' => nil,
41
- 'separator' => '<indent><desc>',
42
- },
43
- 'file' => {
44
- 'separator' => '-- <desc>',
45
- 'start_group' => "-- Start '<desc>'",
46
- 'end_group' => "-- End '<desc>'",
47
- }
48
- },
49
- 'debug' => false,
50
- 'out_path' => './reports',
51
- 'secure_keys' => ['password', 'secret', 'token', 'secure', 'authorization'],
52
- 'spec_patterns' => ['./specs/**/*.spec.rb'],
53
- 'mixin_patterns' => ['../common/mixins/**/*.mixin.rb', './mixins/**/*.mixin.rb'],
54
- 'env_patterns' => ['./environments/**/*.env.yml'],
55
- 'env_partial_patterns' => ['./environments/**/*.env.secret.yml'],
56
- 'resource_paths' => ['../common/resources', './resources'],
57
- 'modules' => [
58
- 'spectre/helpers',
59
- 'spectre/reporter/console',
60
- 'spectre/reporter/junit',
61
- 'spectre/logger/console',
62
- 'spectre/logger/file',
63
- 'spectre/assertion',
64
- 'spectre/diagnostic',
65
- 'spectre/environment',
66
- 'spectre/mixin',
67
- 'spectre/bag',
68
- 'spectre/http',
69
- 'spectre/http/basic_auth',
70
- 'spectre/http/keystone',
71
- 'spectre/resources',
72
- ],
73
- 'include' => [
74
-
75
- ],
76
- 'exclude' => [
77
-
78
- ]
79
- }
80
-
81
-
82
- cmd_options = {}
83
-
84
- opt_parser = OptionParser.new do |opts|
85
- opts.banner = %{Spectre #{Spectre::VERSION}
86
-
87
- Usage: spectre [command] [options]
88
-
89
- Commands:
90
- list List specs
91
- run Run specs (default)
92
- show Print current environment settings
93
- dump Dumps the given environment in YAML format to console
94
- init Initializes a new spectre project
95
-
96
- Specific options:}
97
-
98
- opts.on('-s SPEC,SPEC', '--specs SPEC,SPEC', Array, 'The specs to run') do |specs|
99
- cmd_options['specs'] = specs
100
- end
101
-
102
- opts.on('-t TAG,TAG', '--tags TAG,TAG', Array, 'Run only specs with given tags') do |tags|
103
- cmd_options['tags'] = tags
104
- end
105
-
106
- opts.on('-e NAME', '--env NAME', 'Name of the environment to load') do |env_name|
107
- cmd_options['environment'] = env_name
108
- end
109
-
110
- opts.on('-c FILE', '--config FILE', 'Config file to load') do |file_path|
111
- cmd_options['config_file'] = file_path
112
- end
113
-
114
- opts.on('--spec-pattern PATTERN', Array, 'File pattern for spec files') do |spec_pattern|
115
- cmd_options['spec_patterns'] = spec_pattern
116
- end
117
-
118
- opts.on('--env-pattern PATTERN', Array, 'File pattern for environment files') do |env_patterns|
119
- cmd_options['env_patterns'] = env_patterns
120
- end
121
-
122
- opts.on('--no-color', 'Disable colored output') do
123
- cmd_options['colored'] = false
124
- end
125
-
126
- opts.on('--ignore-failure', 'Always exit with code 0') do
127
- cmd_options['ignore_failure'] = true
128
- end
129
-
130
- opts.on('-o PATH', '--out PATH', 'Output directory path') do |path|
131
- cmd_options['out_path'] = File.absolute_path(path)
132
- end
133
-
134
- opts.on('-r NAME', '--reporters NAME', Array, "A list of reporters to use") do |reporters|
135
- cmd_options['reporters'] = reporters
136
- end
137
-
138
- opts.on('-d', '--debug', "Run in debug mode") do
139
- cmd_options['debug'] = true
140
- end
141
-
142
- opts.on('-p KEY=VAL', '--property KEY=VAL', "Override config option. Use `spectre show` to get list of available options") do |option|
143
- key, val = option.split '='
144
- val = val.split ',' if DEFAULT_CONFIG[key].is_a? Array
145
- val = ['true', '1'].include? val if [true, false].include? DEFAULT_CONFIG[key]
146
- val = val.to_i if DEFAULT_CONFIG[key].is_a? Integer
147
- cmd_options[key] = val
148
-
149
- curr_opt = cmd_options
150
- (key.split '.').each do |k|
151
- curr_opt[k] = {} if not curr_opt.key? k
152
- end
153
- curr_opt = val
154
-
155
- end
156
-
157
- opts.separator "\nCommon options:"
158
-
159
- opts.on_tail('--version', 'Print current installed version') do
160
- puts Spectre::VERSION
161
- exit
162
- end
163
-
164
- opts.on_tail('-h', '--help', 'Print this help') do
165
- puts opts
166
- exit
167
- end
168
- end.parse!
169
-
170
-
171
- action = ARGV[0] || 'run'
172
-
173
-
174
- ###########################################
175
- # Load Config
176
- ###########################################
177
-
178
-
179
- cfg = {}
180
- cfg.deep_merge! DEFAULT_CONFIG
181
-
182
- global_config_file = File.join File.expand_path('~'), '.spectre'
183
-
184
- if File.exists? global_config_file
185
- global_options = YAML.load_file(global_config_file)
186
- cfg.deep_merge! global_options if global_options
187
- end
188
-
189
- config_file = cmd_options['config_file'] || cfg['config_file']
190
-
191
- if File.exists? config_file
192
- file_options = YAML.load_file(config_file)
193
- cfg.deep_merge! file_options
194
- Dir.chdir File.dirname(config_file)
195
- end
196
-
197
- cfg.deep_merge! cmd_options
198
-
199
-
200
- ###########################################
201
- # Load Environment
202
- ###########################################
203
-
204
-
205
- envs = {}
206
- read_env_files = {}
207
- cfg['env_patterns'].each do |pattern|
208
- Dir.glob(pattern).each do|f|
209
- spec_env = YAML.load_file(f) || {}
210
-
211
- name = spec_env['name'] || 'default'
212
-
213
- if envs.key? name
214
- existing_env_file = read_env_files[name]
215
- puts "Duplicate environment definition detected with name #{name} in '#{f}'. Previously defined in '#{existing_env_file}'"
216
- exit 1
217
- end
218
-
219
- read_env_files[name] = f
220
- envs[name] = spec_env
221
- end
222
- end
223
-
224
- # Merge partial environment configs with existing environments
225
- cfg['env_partial_patterns'].each do |pattern|
226
- Dir.glob(pattern).each do|f|
227
- partial_env = YAML.load_file(f)
228
- name = partial_env.delete('name') || 'default'
229
- next if not envs.key? name
230
-
231
- envs[name].deep_merge! partial_env
232
- end
233
- end
234
-
235
- env = envs[cfg['environment']]
236
- cfg.merge! env if env
237
-
238
-
239
- String.colored! if cfg['colored']
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
-
245
-
246
- ###########################################
247
- # Load Specs
248
- ###########################################
249
-
250
-
251
- cfg['spec_patterns'].each do |pattern|
252
- Dir.glob(pattern).each do|f|
253
- require_relative File.join(Dir.pwd, f)
254
- end
255
- end
256
-
257
-
258
- ###########################################
259
- # List specs
260
- ###########################################
261
-
262
-
263
- if action == 'list'
264
- colors = [:blue, :magenta, :yellow, :green]
265
- specs = Spectre.specs(cfg['specs'], cfg['tags'])
266
-
267
- exit 1 unless specs.any?
268
-
269
- counter = 0
270
-
271
- specs.group_by { |x| x.subject }.each do |subject, spec_group|
272
- spec_group.each do |spec|
273
- tags = spec.tags.map { |x| '#' + x.to_s }.join ' '
274
- desc = subject.desc
275
- desc += ' - ' + spec.context.__desc + ' -' if spec.context.__desc
276
- desc += ' ' + spec.desc
277
- puts "[#{spec.name}]".send(colors[counter % colors.length]) + " #{desc} #{tags.cyan}"
278
- end
279
-
280
- counter += 1
281
- end
282
-
283
- exit 0
284
- end
285
-
286
-
287
- ###########################################
288
- # Run
289
- ###########################################
290
-
291
-
292
- if action == 'run'
293
- # Initialize logger
294
- now = Time.now
295
-
296
- cfg['log_file'] = cfg['log_file'].frmt({
297
- shortdate: now.strftime('%Y-%m-%d'),
298
- date: now.strftime('%Y-%m-%d_%H%M%S'),
299
- timestamp: now.strftime('%s'),
300
- subject: 'spectre',
301
- })
302
-
303
- log_dir = File.dirname cfg['log_file']
304
- FileUtils.makedirs log_dir if !Dir.exists? log_dir
305
-
306
- # Load Modules
307
-
308
- cfg['modules']
309
- .concat(cfg['include'])
310
- .select { |mod| !cfg['exclude'].include? mod }
311
- .each do |mod|
312
- begin
313
- spectre_lib_mod = File.join('../lib', mod)
314
-
315
- if File.exists? mod
316
- require_relative mod
317
-
318
- elsif File.exists? spectre_lib_mod
319
- require_relative spectre_lib_mod
320
-
321
- else
322
- require mod
323
- end
324
-
325
- rescue LoadError => e
326
- puts "Unable to load module #{mod}. Check if the module exists or remove it from your spectre config:\n#{e.message}"
327
- exit 1
328
- end
329
- end
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
-
339
- Spectre.configure(cfg)
340
-
341
- Spectre::Logger.debug! if cfg['debug']
342
-
343
- cfg['loggers'].each do |logger_name|
344
- logger = Kernel.const_get(logger_name).new(cfg)
345
- Spectre::Logger.add(logger)
346
- end if cfg['loggers']
347
-
348
- specs = Spectre.specs(cfg['specs'], cfg['tags'])
349
-
350
- if not specs.any?
351
- puts "No specs found in #{Dir.pwd}"
352
- exit 1
353
- end
354
-
355
- run_infos = Spectre::Runner.new.run(specs)
356
-
357
- cfg['reporters'].each do |reporter|
358
- reporter = Kernel.const_get(reporter).new(cfg)
359
- reporter.report(run_infos)
360
- end
361
-
362
- errors = run_infos.select { |x| x.error != nil or x.failure != nil }
363
-
364
- exit 0 if cfg['ignore_failure'] or not errors.any?
365
-
366
- exit 1
367
- end
368
-
369
-
370
- ###########################################
371
- # Envs
372
- ###########################################
373
-
374
-
375
- if action == 'envs'
376
- exit 1 unless envs.any?
377
- puts envs.pretty
378
- exit 0
379
- end
380
-
381
-
382
- ###########################################
383
- # Show
384
- ###########################################
385
-
386
-
387
- if action == 'show'
388
- puts cfg.pretty
389
- exit 0
390
- end
391
-
392
-
393
- ###########################################
394
- # Dump
395
- ###########################################
396
-
397
-
398
- if action == 'dump'
399
- puts YAML.dump(cfg)
400
- end
401
-
402
-
403
- ###########################################
404
- # Init
405
- ###########################################
406
-
407
- DEFAULT_SPECTRE_CFG = %{log_file: ./logs/spectre_<date>.log
408
- env_patterns:
409
- - './environments/**/*.env.yml'
410
- env_partial_patterns:
411
- - './environments/**/*.env.secret.yml'
412
- spec_patterns:
413
- - './specs/**/*.spec.rb'
414
- mixin_patterns:
415
- - '../common/**/*.mixin.rb'
416
- - './mixins/**/*.mixin.rb'
417
- resource_paths:
418
- - '../common/resources'
419
- - './resources'
420
- }
421
-
422
-
423
- DEFAULT_ENV_CFG = %{cert: &cert ./resources/<root_cert>.cer
424
- http:
425
- <http_client_name>:
426
- base_url: http://localhost:5000/api/v1/
427
- # basic_auth:
428
- # username: <username>
429
- # password: <password>
430
- # keystone:
431
- # url: https://<keystone_url>/main/v3/
432
- # username: <username>
433
- # password: <password>
434
- # project: <project>
435
- # domain: <domain>
436
- # cert: *cert
437
- # ssh:
438
- # <ssh_client_name>:
439
- # host: <hostname>
440
- # username: <username>
441
- # password: <password>
442
- }
443
-
444
- DEFAULT_ENV_SECRET_CFG = %{http:
445
- <http_client_name>:
446
- # basic_auth:
447
- # username: <username>
448
- # password: <password>
449
- # keystone:
450
- # username: <username>
451
- # password: <password>
452
- # ssh:
453
- # <ssh_client_name>:
454
- # username: <username>
455
- # password: <password>
456
- }
457
-
458
- SAMPLE_SPEC = %[describe '<subject>' do
459
- it 'does some http requests', tags: [:sample] do
460
- log 'doing some http request'
461
-
462
- http '<http_client_name>' do
463
- auth 'basic'
464
- # auth 'keystone'
465
- method 'GET'
466
- path 'path/to/resource'
467
- param 'id', 4295118773
468
- param 'foo', 'bar'
469
- header 'X-Correlation-Id', '4c2367b1-bfee-4cc2-bdc5-ed17a6a9dd4b'
470
- header 'Range', 'bytes=500-999'
471
- json({
472
- "message": "Hello Spectre!"
473
- })
474
- end
475
-
476
- expect 'the response code to be 200' do
477
- response.code.should_be 200
478
- end
479
-
480
- expect 'a message to exist' do
481
- response.json.message.should_not_be nil
482
- end
483
- end
484
- end
485
- ]
486
-
487
- DEFAULT_GITIGNORE = %[*.code-workspace
488
- logs/
489
- reports/
490
- **/environments/*.env.secret.yml
491
- ]
492
-
493
- DEFAULT_GEMFILE = %[source 'https://rubygems.org'
494
-
495
- gem 'spectre-core', '>= #{Spectre::VERSION}'
496
- # gem 'spectre-mysql', '>= 1.0.0'
497
- # gem 'spectre-ssh', '>= 1.0.0'
498
- # gem 'spectre-ftp', '>= 1.0.0'
499
- # gem 'spectre-curl', '>= 1.0.0'
500
- # gem 'spectre-git', '>= 0.1.0'
501
- ]
502
-
503
- if action == 'init'
504
- DEFAULT_FILES = [
505
- ['./environments/default.env.yml', DEFAULT_ENV_CFG],
506
- ['./environments/default.env.secret.yml', DEFAULT_ENV_SECRET_CFG],
507
- ['./specs/sample.spec.rb', SAMPLE_SPEC],
508
- ['./spectre.yml', DEFAULT_SPECTRE_CFG],
509
- ['./.gitignore', DEFAULT_GITIGNORE],
510
- ['./Gemfile', DEFAULT_GEMFILE],
511
- ]
512
-
513
- %w(environments logs specs).each do |dir_name|
514
- Dir.mkdir(dir_name) unless File.directory? dir_name
515
- end
516
-
517
- DEFAULT_FILES.each do |file, content|
518
- if not File.exists? file
519
- File.write(file, content)
520
- end
521
- end
522
-
523
- exit 0
524
- end
1
+ #! /usr/bin/ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'yaml'
5
+ require 'ostruct'
6
+ require 'optparse'
7
+ require 'fileutils'
8
+ require 'ectoplasm'
9
+
10
+ require_relative '../lib/spectre'
11
+
12
+
13
+ DEFAULT_CONFIG = {
14
+ 'config_file' => './spectre.yml',
15
+ 'environment' => 'default',
16
+ 'specs' => [],
17
+ 'tags' => [],
18
+ 'colored' => true,
19
+ 'verbose' => false,
20
+ 'reporters' => [
21
+ 'Spectre::Reporter::Console',
22
+ ],
23
+ 'loggers' => [
24
+ 'Spectre::Logger::Console',
25
+ 'Spectre::Logger::File',
26
+ ],
27
+ 'log_file' => './logs/spectre_<date>.log',
28
+ 'log_format' => {
29
+ 'console' => {
30
+ 'indent' => 2,
31
+ 'width' => 80,
32
+ 'end_context' => nil,
33
+ 'separator' => '<indent><desc>',
34
+ },
35
+ 'file' => {
36
+ 'separator' => '-- <desc>',
37
+ 'start_group' => "-- Start '<desc>'",
38
+ 'end_group' => "-- End '<desc>'",
39
+ },
40
+ },
41
+ 'debug' => false,
42
+ 'out_path' => './reports',
43
+ 'secure_keys' => ['password', 'secret', 'token', 'secure', 'authorization'],
44
+ 'spec_patterns' => ['./specs/**/*.spec.rb'],
45
+ 'mixin_patterns' => ['../common/mixins/**/*.mixin.rb', './mixins/**/*.mixin.rb'],
46
+ 'env_patterns' => ['./environments/**/*.env.yml'],
47
+ 'env_partial_patterns' => ['./environments/**/*.env.secret.yml'],
48
+ 'resource_paths' => ['../common/resources', './resources'],
49
+ 'modules' => [
50
+ 'spectre/helpers',
51
+ 'spectre/reporter/console',
52
+ 'spectre/reporter/junit',
53
+ 'spectre/logger/console',
54
+ 'spectre/logger/file',
55
+ 'spectre/assertion',
56
+ 'spectre/diagnostic',
57
+ 'spectre/environment',
58
+ 'spectre/mixin',
59
+ 'spectre/bag',
60
+ 'spectre/http',
61
+ 'spectre/http/basic_auth',
62
+ 'spectre/http/keystone',
63
+ 'spectre/resources',
64
+ ],
65
+ 'include' => [
66
+
67
+ ],
68
+ 'exclude' => [
69
+
70
+ ],
71
+ }
72
+
73
+
74
+ cmd_options = {}
75
+
76
+ opt_parser = OptionParser.new do |opts|
77
+ opts.banner = %{Spectre #{Spectre::VERSION}
78
+
79
+ Usage: spectre [command] [options]
80
+
81
+ Commands:
82
+ list List specs
83
+ run Run specs (default)
84
+ show Print current environment settings
85
+ dump Dumps the given environment in YAML format to console
86
+ init Initializes a new spectre project
87
+
88
+ Specific options:}
89
+
90
+ opts.on('-s SPEC,SPEC', '--specs SPEC,SPEC', Array, 'The specs to run') do |specs|
91
+ cmd_options['specs'] = specs
92
+ end
93
+
94
+ opts.on('-t TAG,TAG', '--tags TAG,TAG', Array, 'Run only specs with given tags') do |tags|
95
+ cmd_options['tags'] = tags
96
+ end
97
+
98
+ opts.on('-e NAME', '--env NAME', 'Name of the environment to load') do |env_name|
99
+ cmd_options['environment'] = env_name
100
+ end
101
+
102
+ opts.on('-c FILE', '--config FILE', 'Config file to load') do |file_path|
103
+ cmd_options['config_file'] = file_path
104
+ end
105
+
106
+ opts.on('--spec-pattern PATTERN', Array, 'File pattern for spec files') do |spec_pattern|
107
+ cmd_options['spec_patterns'] = spec_pattern
108
+ end
109
+
110
+ opts.on('--env-pattern PATTERN', Array, 'File pattern for environment files') do |env_patterns|
111
+ cmd_options['env_patterns'] = env_patterns
112
+ end
113
+
114
+ opts.on('--no-color', 'Disable colored output') do
115
+ cmd_options['colored'] = false
116
+ end
117
+
118
+ opts.on('--ignore-failure', 'Always exit with code 0') do
119
+ cmd_options['ignore_failure'] = true
120
+ end
121
+
122
+ opts.on('-o PATH', '--out PATH', 'Output directory path') do |path|
123
+ cmd_options['out_path'] = File.absolute_path(path)
124
+ end
125
+
126
+ opts.on('-r NAME', '--reporters NAME', Array, "A list of reporters to use") do |reporters|
127
+ cmd_options['reporters'] = reporters
128
+ end
129
+
130
+ opts.on('-d', '--debug', "Run in debug mode") do
131
+ cmd_options['debug'] = true
132
+ end
133
+
134
+ opts.on('-p KEY=VAL', '--property KEY=VAL', "Override config option. Use `spectre show` to get list of available options") do |option|
135
+ key, val = option.split '='
136
+ val = val.split ',' if DEFAULT_CONFIG[key].is_a? Array
137
+ val = ['true', '1'].include? val if [true, false].include? DEFAULT_CONFIG[key]
138
+ val = val.to_i if DEFAULT_CONFIG[key].is_a? Integer
139
+ cmd_options[key] = val
140
+
141
+ curr_opt = cmd_options
142
+ (key.split '.').each do |k|
143
+ curr_opt[k] = {} unless curr_opt.key? k
144
+ end
145
+ curr_opt = val
146
+ end
147
+
148
+ opts.separator "\nCommon options:"
149
+
150
+ opts.on_tail('--version', 'Print current installed version') do
151
+ puts Spectre::VERSION
152
+ exit
153
+ end
154
+
155
+ opts.on_tail('-h', '--help', 'Print this help') do
156
+ puts opts
157
+ exit
158
+ end
159
+ end.parse!
160
+
161
+
162
+ action = ARGV[0] || 'run'
163
+
164
+
165
+ ###########################################
166
+ # Load Config
167
+ ###########################################
168
+
169
+
170
+ cfg = {}
171
+ cfg.deep_merge! DEFAULT_CONFIG
172
+
173
+ global_config_file = File.join File.expand_path('~'), '.spectre'
174
+
175
+ if File.exists? global_config_file
176
+ global_options = YAML.load_file(global_config_file)
177
+ cfg.deep_merge! global_options if global_options
178
+ end
179
+
180
+ config_file = cmd_options['config_file'] || cfg['config_file']
181
+
182
+ if File.exists? config_file
183
+ file_options = YAML.load_file(config_file)
184
+ cfg.deep_merge! file_options
185
+ Dir.chdir File.dirname(config_file)
186
+ end
187
+
188
+ cfg.deep_merge! cmd_options
189
+
190
+
191
+ ###########################################
192
+ # Load Environment
193
+ ###########################################
194
+
195
+
196
+ envs = {}
197
+ read_env_files = {}
198
+ cfg['env_patterns'].each do |pattern|
199
+ Dir.glob(pattern).each do|f|
200
+ spec_env = YAML.load_file(f) || {}
201
+
202
+ name = spec_env['name'] || 'default'
203
+
204
+ if envs.key? name
205
+ existing_env_file = read_env_files[name]
206
+ puts "Duplicate environment definition detected with name #{name} in '#{f}'. Previously defined in '#{existing_env_file}'"
207
+ exit 1
208
+ end
209
+
210
+ read_env_files[name] = f
211
+ envs[name] = spec_env
212
+ end
213
+ end
214
+
215
+ # Merge partial environment configs with existing environments
216
+ cfg['env_partial_patterns'].each do |pattern|
217
+ Dir.glob(pattern).each do|f|
218
+ partial_env = YAML.load_file(f)
219
+ name = partial_env.delete('name') || 'default'
220
+ next unless envs.key? name
221
+
222
+ envs[name].deep_merge! partial_env
223
+ end
224
+ end
225
+
226
+ env = envs[cfg['environment']]
227
+ cfg.merge! env if env
228
+
229
+
230
+ String.colored! if cfg['colored']
231
+
232
+ # Load environment exlicitly before loading specs to make it available in spec definition
233
+ require_relative '../lib/spectre/environment' unless cfg['exclude'].include? 'spectre/environment'
234
+ Spectre.configure(cfg)
235
+
236
+
237
+ ###########################################
238
+ # Load Specs
239
+ ###########################################
240
+
241
+
242
+ cfg['spec_patterns'].each do |pattern|
243
+ Dir.glob(pattern).each do|f|
244
+ require_relative File.join(Dir.pwd, f)
245
+ end
246
+ end
247
+
248
+
249
+ ###########################################
250
+ # List specs
251
+ ###########################################
252
+
253
+
254
+ if 'list' == action
255
+ colors = [:blue, :magenta, :yellow, :green]
256
+ specs = Spectre.specs(cfg['specs'], cfg['tags'])
257
+
258
+ exit 1 unless specs.any?
259
+
260
+ counter = 0
261
+
262
+ specs.group_by { |x| x.subject }.each do |subject, spec_group|
263
+ spec_group.each do |spec|
264
+ tags = spec.tags.map { |x| '#' + x.to_s }.join ' '
265
+ desc = subject.desc
266
+ desc += ' - ' + spec.context.__desc + ' -' if spec.context.__desc
267
+ desc += ' ' + spec.desc
268
+ puts "[#{spec.name}]".send(colors[counter % colors.length]) + " #{desc} #{tags.cyan}"
269
+ end
270
+
271
+ counter += 1
272
+ end
273
+
274
+ exit 0
275
+ end
276
+
277
+
278
+ ###########################################
279
+ # Run
280
+ ###########################################
281
+
282
+
283
+ if 'run' == action
284
+ # Initialize logger
285
+ now = Time.now
286
+
287
+ cfg['log_file'] = cfg['log_file'].frmt(
288
+ {
289
+ shortdate: now.strftime('%Y-%m-%d'),
290
+ date: now.strftime('%Y-%m-%d_%H%M%S'),
291
+ timestamp: now.strftime('%s'),
292
+ subject: 'spectre',
293
+ })
294
+
295
+ log_dir = File.dirname cfg['log_file']
296
+ FileUtils.makedirs log_dir unless Dir.exists? log_dir
297
+
298
+ # Load Modules
299
+
300
+ cfg['modules']
301
+ .concat(cfg['include'])
302
+ .select { |mod| !cfg['exclude'].include? mod }
303
+ .each do |mod|
304
+ begin
305
+ mod_file = mod + '.rb'
306
+ spectre_lib_mod = File.join(File.dirname(__dir__), 'lib', mod_file)
307
+
308
+ if File.exists? mod_file
309
+ require_relative mod_file
310
+
311
+ elsif File.exists? spectre_lib_mod
312
+ require_relative spectre_lib_mod
313
+
314
+ else
315
+ require mod
316
+ end
317
+ rescue LoadError => e
318
+ puts "Unable to load module #{mod}. Check if the module exists or remove it from your spectre config:\n#{e.message}"
319
+ exit 1
320
+ end
321
+ end
322
+
323
+ # Load mixins
324
+
325
+ cfg['mixin_patterns'].each do |pattern|
326
+ Dir.glob(pattern).each do|f|
327
+ require_relative File.join(Dir.pwd, f)
328
+ end
329
+ end
330
+
331
+ Spectre.configure(cfg)
332
+
333
+ Spectre::Logger.debug! if cfg['debug']
334
+
335
+ cfg['loggers'].each do |logger_name|
336
+ logger = Kernel.const_get(logger_name).new(cfg)
337
+ Spectre::Logger.add(logger)
338
+ end if cfg['loggers']
339
+
340
+ specs = Spectre.specs(cfg['specs'], cfg['tags'])
341
+
342
+ unless specs.any?
343
+ puts "No specs found in #{Dir.pwd}"
344
+ exit 1
345
+ end
346
+
347
+ run_infos = Spectre::Runner.new.run(specs)
348
+
349
+ cfg['reporters'].each do |reporter|
350
+ reporter = Kernel.const_get(reporter).new(cfg)
351
+ reporter.report(run_infos)
352
+ end
353
+
354
+ errors = run_infos.select { |x| nil != x.error or nil != x.failure }
355
+
356
+ exit 0 if cfg['ignore_failure'] or not errors.any?
357
+
358
+ exit 1
359
+ end
360
+
361
+
362
+ ###########################################
363
+ # Envs
364
+ ###########################################
365
+
366
+
367
+ if 'envs' == action
368
+ exit 1 unless envs.any?
369
+ puts envs.pretty
370
+ exit 0
371
+ end
372
+
373
+
374
+ ###########################################
375
+ # Show
376
+ ###########################################
377
+
378
+
379
+ if 'show' == action
380
+ puts cfg.pretty
381
+ exit 0
382
+ end
383
+
384
+
385
+ ###########################################
386
+ # Dump
387
+ ###########################################
388
+
389
+
390
+ if 'dump' == action
391
+ puts YAML.dump(cfg)
392
+ end
393
+
394
+
395
+ ###########################################
396
+ # Init
397
+ ###########################################
398
+
399
+ DEFAULT_SPECTRE_CFG = %{log_file: ./logs/spectre_<date>.log
400
+ env_patterns:
401
+ - './environments/**/*.env.yml'
402
+ env_partial_patterns:
403
+ - './environments/**/*.env.secret.yml'
404
+ spec_patterns:
405
+ - './specs/**/*.spec.rb'
406
+ mixin_patterns:
407
+ - '../common/**/*.mixin.rb'
408
+ - './mixins/**/*.mixin.rb'
409
+ resource_paths:
410
+ - '../common/resources'
411
+ - './resources'
412
+ }
413
+
414
+
415
+ DEFAULT_ENV_CFG = %{cert: &cert ./resources/<root_cert>.cer
416
+ http:
417
+ <http_client_name>:
418
+ base_url: http://localhost:5000/api/v1/
419
+ # basic_auth:
420
+ # username: <username>
421
+ # password: <password>
422
+ # keystone:
423
+ # url: https://<keystone_url>/main/v3/
424
+ # username: <username>
425
+ # password: <password>
426
+ # project: <project>
427
+ # domain: <domain>
428
+ # cert: *cert
429
+ # ssh:
430
+ # <ssh_client_name>:
431
+ # host: <hostname>
432
+ # username: <username>
433
+ # password: <password>
434
+ }
435
+
436
+ DEFAULT_ENV_SECRET_CFG = %{http:
437
+ <http_client_name>:
438
+ # basic_auth:
439
+ # username: <username>
440
+ # password: <password>
441
+ # keystone:
442
+ # username: <username>
443
+ # password: <password>
444
+ # ssh:
445
+ # <ssh_client_name>:
446
+ # username: <username>
447
+ # password: <password>
448
+ }
449
+
450
+ SAMPLE_SPEC = %[describe '<subject>' do
451
+ it 'does some http requests', tags: [:sample] do
452
+ log 'doing some http request'
453
+
454
+ http '<http_client_name>' do
455
+ auth 'basic'
456
+ # auth 'keystone'
457
+ method 'GET'
458
+ path 'path/to/resource'
459
+ param 'id', 4295118773
460
+ param 'foo', 'bar'
461
+ header 'X-Correlation-Id', '4c2367b1-bfee-4cc2-bdc5-ed17a6a9dd4b'
462
+ header 'Range', 'bytes=500-999'
463
+ json({
464
+ "message": "Hello Spectre!"
465
+ })
466
+ end
467
+
468
+ expect 'the response code to be 200' do
469
+ response.code.should_be 200
470
+ end
471
+
472
+ expect 'a message to exist' do
473
+ response.json.message.should_not_be nil
474
+ end
475
+ end
476
+ end
477
+ ]
478
+
479
+ DEFAULT_GITIGNORE = %[*.code-workspace
480
+ logs/
481
+ reports/
482
+ **/environments/*.env.secret.yml
483
+ ]
484
+
485
+ DEFAULT_GEMFILE = %[source 'https://rubygems.org'
486
+
487
+ gem 'spectre-core', '>= #{Spectre::VERSION}'
488
+ # gem 'spectre-mysql', '>= 1.0.0'
489
+ # gem 'spectre-ssh', '>= 1.0.0'
490
+ # gem 'spectre-ftp', '>= 1.0.0'
491
+ # gem 'spectre-curl', '>= 1.0.0'
492
+ # gem 'spectre-git', '>= 0.1.0'
493
+ ]
494
+
495
+ if 'init' == action
496
+ DEFAULT_FILES = [
497
+ ['./environments/default.env.yml', DEFAULT_ENV_CFG],
498
+ ['./environments/default.env.secret.yml', DEFAULT_ENV_SECRET_CFG],
499
+ ['./specs/sample.spec.rb', SAMPLE_SPEC],
500
+ ['./spectre.yml', DEFAULT_SPECTRE_CFG],
501
+ ['./.gitignore', DEFAULT_GITIGNORE],
502
+ ['./Gemfile', DEFAULT_GEMFILE],
503
+ ]
504
+
505
+ %w(environments logs specs).each do |dir_name|
506
+ Dir.mkdir(dir_name) unless File.directory? dir_name
507
+ end
508
+
509
+ DEFAULT_FILES.each do |file, content|
510
+ unless File.exists? file
511
+ File.write(file, content)
512
+ end
513
+ end
514
+
515
+ exit 0
516
+ end