spectre-core 1.11.0 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
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