spectre-core 1.12.0 → 1.12.3

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,516 +1,545 @@
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
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
+ property_overrides = {}
76
+
77
+ opt_parser = OptionParser.new do |opts|
78
+ opts.banner = %{Spectre #{Spectre::VERSION}
79
+
80
+ Usage: spectre [command] [options]
81
+
82
+ Commands:
83
+ list List specs
84
+ run Run specs (default)
85
+ show Print current environment settings
86
+ dump Dumps the given environment in YAML format to console
87
+ cleanup Will remove all generated files (e.g. logs and reports)
88
+ init Initializes a new spectre project
89
+
90
+ Specific options:}
91
+
92
+ opts.on('-s SPEC,SPEC', '--specs SPEC,SPEC', Array, 'The specs to run') do |specs|
93
+ cmd_options['specs'] = specs
94
+ end
95
+
96
+ opts.on('-t TAG,TAG', '--tags TAG,TAG', Array, 'Run only specs with given tags') do |tags|
97
+ cmd_options['tags'] = tags
98
+ end
99
+
100
+ opts.on('-e NAME', '--env NAME', 'Name of the environment to load') do |env_name|
101
+ cmd_options['environment'] = env_name
102
+ end
103
+
104
+ opts.on('-c FILE', '--config FILE', 'Config file to load') do |file_path|
105
+ cmd_options['config_file'] = file_path
106
+ end
107
+
108
+ opts.on('--spec-pattern PATTERN', Array, 'File pattern for spec files') do |spec_pattern|
109
+ cmd_options['spec_patterns'] = spec_pattern
110
+ end
111
+
112
+ opts.on('--env-pattern PATTERN', Array, 'File pattern for environment files') do |env_patterns|
113
+ cmd_options['env_patterns'] = env_patterns
114
+ end
115
+
116
+ opts.on('--no-color', 'Disable colored output') do
117
+ cmd_options['colored'] = false
118
+ end
119
+
120
+ opts.on('--ignore-failure', 'Always exit with code 0') do
121
+ cmd_options['ignore_failure'] = true
122
+ end
123
+
124
+ opts.on('-o PATH', '--out PATH', 'Output directory path') do |path|
125
+ cmd_options['out_path'] = File.absolute_path(path)
126
+ end
127
+
128
+ opts.on('-r NAME', '--reporters NAME', Array, "A list of reporters to use") do |reporters|
129
+ cmd_options['reporters'] = reporters
130
+ end
131
+
132
+ opts.on('-d', '--debug', "Run in debug mode") do
133
+ cmd_options['debug'] = true
134
+ end
135
+
136
+ opts.on('-p KEY=VAL', '--property KEY=VAL', "Override config option. Use `spectre show` to get list of available options") do |option|
137
+ key, val = option.split('=')
138
+ val = val.split(',') if DEFAULT_CONFIG[key].is_a? Array
139
+ val = ['true', '1'].include? val if [true, false].include?(DEFAULT_CONFIG[key])
140
+ val = val.to_i if DEFAULT_CONFIG[key].is_a? Integer
141
+
142
+ opt_path = key.split('.')
143
+
144
+ curr_opt = property_overrides
145
+
146
+ opt_path.each_with_index do |part, i|
147
+ if i == opt_path.count-1
148
+ curr_opt[part] = val
149
+ break
150
+ end
151
+
152
+ curr_opt[part] = {} unless curr_opt.key?(part)
153
+ curr_opt = curr_opt[part]
154
+ end
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
+ # Load Environment
201
+ ###########################################
202
+
203
+
204
+ envs = {}
205
+ read_env_files = {}
206
+ cfg['env_patterns'].each do |pattern|
207
+ Dir.glob(pattern).each do|f|
208
+ spec_env = YAML.load_file(f) || {}
209
+
210
+ name = spec_env['name'] || 'default'
211
+
212
+ if envs.key? name
213
+ existing_env_file = read_env_files[name]
214
+ puts "Duplicate environment definition detected with name #{name} in '#{f}'. Previously defined in '#{existing_env_file}'"
215
+ exit 1
216
+ end
217
+
218
+ read_env_files[name] = f
219
+ envs[name] = spec_env
220
+ end
221
+ end
222
+
223
+ # Merge partial environment configs with existing environments
224
+ cfg['env_partial_patterns'].each do |pattern|
225
+ Dir.glob(pattern).each do|f|
226
+ partial_env = YAML.load_file(f)
227
+ name = partial_env.delete('name') || 'default'
228
+ next unless envs.key? name
229
+
230
+ envs[name].deep_merge! partial_env
231
+ end
232
+ end
233
+
234
+ env = envs[cfg['environment']]
235
+ cfg.deep_merge! env if env
236
+
237
+ # Merge property overrides after environment load to give it higher priority
238
+ cfg.deep_merge! property_overrides
239
+
240
+
241
+ String.colored! if cfg['colored']
242
+
243
+ # Load environment exlicitly before loading specs to make it available in spec definition
244
+ require_relative '../lib/spectre/environment' unless cfg['exclude'].include? 'spectre/environment'
245
+ Spectre.configure(cfg)
246
+
247
+
248
+ ###########################################
249
+ # Load Specs
250
+ ###########################################
251
+
252
+
253
+ cfg['spec_patterns'].each do |pattern|
254
+ Dir.glob(pattern).each do|f|
255
+ require_relative File.join(Dir.pwd, f)
256
+ end
257
+ end
258
+
259
+
260
+ ###########################################
261
+ # List specs
262
+ ###########################################
263
+
264
+
265
+ if 'list' == action
266
+ colors = [:blue, :magenta, :yellow, :green]
267
+ specs = Spectre.specs(cfg['specs'], cfg['tags'])
268
+
269
+ exit 1 unless specs.any?
270
+
271
+ counter = 0
272
+
273
+ specs.group_by { |x| x.subject }.each do |subject, spec_group|
274
+ spec_group.each do |spec|
275
+ tags = spec.tags.map { |x| '#' + x.to_s }.join ' '
276
+ desc = subject.desc
277
+ desc += ' - ' + spec.context.__desc + ' -' if spec.context.__desc
278
+ desc += ' ' + spec.desc
279
+ puts "[#{spec.name}]".send(colors[counter % colors.length]) + " #{desc} #{tags.cyan}"
280
+ end
281
+
282
+ counter += 1
283
+ end
284
+
285
+ exit 0
286
+ end
287
+
288
+
289
+ ###########################################
290
+ # Run
291
+ ###########################################
292
+
293
+
294
+ if 'run' == action
295
+ # Initialize logger
296
+ now = Time.now
297
+
298
+ cfg['log_file'] = cfg['log_file'].frmt(
299
+ {
300
+ shortdate: now.strftime('%Y-%m-%d'),
301
+ date: now.strftime('%Y-%m-%d_%H%M%S'),
302
+ timestamp: now.strftime('%s'),
303
+ subject: 'spectre',
304
+ })
305
+
306
+ log_dir = File.dirname cfg['log_file']
307
+ FileUtils.makedirs log_dir unless Dir.exists? log_dir
308
+
309
+ # Load Modules
310
+
311
+ cfg['modules']
312
+ .concat(cfg['include'])
313
+ .select { |mod| !cfg['exclude'].include? mod }
314
+ .each do |mod|
315
+ begin
316
+ mod_file = mod + '.rb'
317
+ spectre_lib_mod = File.join(File.dirname(__dir__), 'lib', mod_file)
318
+
319
+ if File.exists? mod_file
320
+ require_relative mod_file
321
+
322
+ elsif File.exists? spectre_lib_mod
323
+ require_relative spectre_lib_mod
324
+
325
+ else
326
+ require mod
327
+ end
328
+ rescue LoadError => e
329
+ puts "Unable to load module #{mod}. Check if the module exists or remove it from your spectre config:\n#{e.message}"
330
+ exit 1
331
+ end
332
+ end
333
+
334
+ # Load mixins
335
+
336
+ cfg['mixin_patterns'].each do |pattern|
337
+ Dir.glob(pattern).each do|f|
338
+ require_relative File.join(Dir.pwd, f)
339
+ end
340
+ end
341
+
342
+ Spectre.configure(cfg)
343
+
344
+ Spectre::Logger.debug! if cfg['debug']
345
+
346
+ cfg['loggers'].each do |logger_name|
347
+ logger = Kernel.const_get(logger_name).new(cfg)
348
+ Spectre::Logger.add(logger)
349
+ end if cfg['loggers']
350
+
351
+ specs = Spectre.specs(cfg['specs'], cfg['tags'])
352
+
353
+ unless specs.any?
354
+ puts "No specs found in #{Dir.pwd}"
355
+ exit 1
356
+ end
357
+
358
+ run_infos = Spectre::Runner.new.run(specs)
359
+
360
+ cfg['reporters'].each do |reporter|
361
+ reporter = Kernel.const_get(reporter).new(cfg)
362
+ reporter.report(run_infos)
363
+ end
364
+
365
+ errors = run_infos.select { |x| nil != x.error or nil != x.failure }
366
+
367
+ exit 0 if cfg['ignore_failure'] or not errors.any?
368
+
369
+ exit 1
370
+ end
371
+
372
+
373
+ ###########################################
374
+ # Envs
375
+ ###########################################
376
+
377
+
378
+ if 'envs' == action
379
+ exit 1 unless envs.any?
380
+ puts envs.pretty
381
+ exit 0
382
+ end
383
+
384
+
385
+ ###########################################
386
+ # Show
387
+ ###########################################
388
+
389
+
390
+ if 'show' == action
391
+ puts cfg.pretty
392
+ exit 0
393
+ end
394
+
395
+
396
+ ###########################################
397
+ # Dump
398
+ ###########################################
399
+
400
+
401
+ if 'dump' == action
402
+ puts YAML.dump(cfg)
403
+ end
404
+
405
+
406
+ ###########################################
407
+ # Cleanup
408
+ ###########################################
409
+
410
+
411
+ if 'cleanup' == action
412
+ log_file_pattern = cfg['log_file'].gsub('<date>', '*')
413
+
414
+ Dir.glob(log_file_pattern).each do |log_file|
415
+ File.delete(log_file)
416
+ end
417
+
418
+ Dir.glob(File.join cfg['out_path'], '/*').each do |out_file|
419
+ File.delete(out_file)
420
+ end
421
+ end
422
+
423
+
424
+ ###########################################
425
+ # Init
426
+ ###########################################
427
+
428
+ DEFAULT_SPECTRE_CFG = %{log_file: ./logs/spectre_<date>.log
429
+ env_patterns:
430
+ - './environments/**/*.env.yml'
431
+ env_partial_patterns:
432
+ - './environments/**/*.env.secret.yml'
433
+ spec_patterns:
434
+ - './specs/**/*.spec.rb'
435
+ mixin_patterns:
436
+ - '../common/**/*.mixin.rb'
437
+ - './mixins/**/*.mixin.rb'
438
+ resource_paths:
439
+ - '../common/resources'
440
+ - './resources'
441
+ }
442
+
443
+
444
+ DEFAULT_ENV_CFG = %{cert: &cert ./resources/<root_cert>.cer
445
+ http:
446
+ <http_client_name>:
447
+ base_url: http://localhost:5000/api/v1/
448
+ # basic_auth:
449
+ # username: <username>
450
+ # password: <password>
451
+ # keystone:
452
+ # url: https://<keystone_url>/main/v3/
453
+ # username: <username>
454
+ # password: <password>
455
+ # project: <project>
456
+ # domain: <domain>
457
+ # cert: *cert
458
+ # ssh:
459
+ # <ssh_client_name>:
460
+ # host: <hostname>
461
+ # username: <username>
462
+ # password: <password>
463
+ }
464
+
465
+ DEFAULT_ENV_SECRET_CFG = %{http:
466
+ <http_client_name>:
467
+ # basic_auth:
468
+ # username: <username>
469
+ # password: <password>
470
+ # keystone:
471
+ # username: <username>
472
+ # password: <password>
473
+ # ssh:
474
+ # <ssh_client_name>:
475
+ # username: <username>
476
+ # password: <password>
477
+ }
478
+
479
+ SAMPLE_SPEC = %[describe '<subject>' do
480
+ it 'does some http requests', tags: [:sample] do
481
+ log 'doing some http request'
482
+
483
+ http '<http_client_name>' do
484
+ auth 'basic'
485
+ # auth 'keystone'
486
+ method 'GET'
487
+ path 'path/to/resource'
488
+ param 'id', 4295118773
489
+ param 'foo', 'bar'
490
+ header 'X-Correlation-Id', '4c2367b1-bfee-4cc2-bdc5-ed17a6a9dd4b'
491
+ header 'Range', 'bytes=500-999'
492
+ json({
493
+ "message": "Hello Spectre!"
494
+ })
495
+ end
496
+
497
+ expect 'the response code to be 200' do
498
+ response.code.should_be 200
499
+ end
500
+
501
+ expect 'a message to exist' do
502
+ response.json.message.should_not_be nil
503
+ end
504
+ end
505
+ end
506
+ ]
507
+
508
+ DEFAULT_GITIGNORE = %[*.code-workspace
509
+ logs/
510
+ reports/
511
+ **/environments/*.env.secret.yml
512
+ ]
513
+
514
+ DEFAULT_GEMFILE = %[source 'https://rubygems.org'
515
+
516
+ gem 'spectre-core', '>= #{Spectre::VERSION}'
517
+ # gem 'spectre-mysql', '>= 1.0.0'
518
+ # gem 'spectre-ssh', '>= 1.0.0'
519
+ # gem 'spectre-ftp', '>= 1.0.0'
520
+ # gem 'spectre-curl', '>= 1.0.0'
521
+ # gem 'spectre-git', '>= 0.1.0'
522
+ ]
523
+
524
+ if 'init' == action
525
+ DEFAULT_FILES = [
526
+ ['./environments/default.env.yml', DEFAULT_ENV_CFG],
527
+ ['./environments/default.env.secret.yml', DEFAULT_ENV_SECRET_CFG],
528
+ ['./specs/sample.spec.rb', SAMPLE_SPEC],
529
+ ['./spectre.yml', DEFAULT_SPECTRE_CFG],
530
+ ['./.gitignore', DEFAULT_GITIGNORE],
531
+ ['./Gemfile', DEFAULT_GEMFILE],
532
+ ]
533
+
534
+ %w(environments logs specs).each do |dir_name|
535
+ Dir.mkdir(dir_name) unless File.directory? dir_name
536
+ end
537
+
538
+ DEFAULT_FILES.each do |file, content|
539
+ unless File.exists? file
540
+ File.write(file, content)
541
+ end
542
+ end
543
+
544
+ exit 0
545
+ end