spectre-core 1.8.0

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