parallel_cucumber 0.2.17 → 0.2.22
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.
- checksums.yaml +4 -4
- data/lib/parallel_cucumber/cli.rb +0 -12
- data/lib/parallel_cucumber/dsl.rb +8 -0
- data/lib/parallel_cucumber/helper/cucumber/cucumber.rb +27 -20
- data/lib/parallel_cucumber/helper/cucumber/json_status_formatter.rb +7 -1
- data/lib/parallel_cucumber/hooks.rb +29 -5
- data/lib/parallel_cucumber/main.rb +7 -3
- data/lib/parallel_cucumber/version.rb +1 -1
- data/lib/parallel_cucumber/worker.rb +7 -26
- data/lib/parallel_cucumber/worker_manager.rb +8 -3
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4d312aab611528ffc08d935c5871ba120f18e27364de8ab2bd5ea42183e4ce46
|
4
|
+
data.tar.gz: 9c5f960b08d8b2f03fc937387bb735ca447791b49381c803f9d34811eb35ee9e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c79e25152a7f1f991b8dbc407904b8421e0eca3cc8fc45cf2217d5f0e3d39fff716310b38f77380b0d91c46bc3819002a37b735dcb8bcd0c894628827bdf4a8c
|
7
|
+
data.tar.gz: f4a846cf322989b8c60d95b23e3b744408c73729aecb8f12919479c21c636f35868060aaa7afb20e1d2b54472df06f022f22529ac97f874cae8d0741c804518a
|
@@ -8,7 +8,6 @@ module ParallelCucumber
|
|
8
8
|
batch_size: 1,
|
9
9
|
batch_timeout: 600,
|
10
10
|
setup_timeout: 30,
|
11
|
-
precheck_timeout: 30,
|
12
11
|
batch_error_timeout: 30,
|
13
12
|
cucumber_options: '',
|
14
13
|
debug: false,
|
@@ -90,10 +89,6 @@ module ParallelCucumber
|
|
90
89
|
options[:test_command] = test_command
|
91
90
|
end
|
92
91
|
|
93
|
-
opts.on('--pre-batch-check COMMAND', 'Command causing worker to quit on exit failure') do |pre_check|
|
94
|
-
options[:pre_check] = pre_check
|
95
|
-
end
|
96
|
-
|
97
92
|
opts.on('--log-dir DIR', 'Directory for worker logfiles') do |log_dir|
|
98
93
|
options[:log_dir] = log_dir
|
99
94
|
end
|
@@ -173,13 +168,6 @@ module ParallelCucumber
|
|
173
168
|
options[:batch_timeout] = batch_timeout
|
174
169
|
end
|
175
170
|
|
176
|
-
help_message = <<-TEXT.gsub(/\s+/, ' ').strip
|
177
|
-
Timeout for each test precheck. Default is #{DEFAULTS[:batch_timeout]}
|
178
|
-
TEXT
|
179
|
-
opts.on('--precheck-timeout SECONDS', Float, help_message) do |timeout|
|
180
|
-
options[:precheck_timeout] = timeout
|
181
|
-
end
|
182
|
-
|
183
171
|
help_message = <<-TEXT.gsub(/\s+/, ' ').strip
|
184
172
|
Timeout for each batch_error script. Default is #{DEFAULTS[:batch_error_timeout]}
|
185
173
|
TEXT
|
@@ -23,6 +23,10 @@ module ParallelCucumber
|
|
23
23
|
Hooks.register_after_batch(proc)
|
24
24
|
end
|
25
25
|
|
26
|
+
def worker_health_check(&proc)
|
27
|
+
Hooks.register_worker_health_check(proc)
|
28
|
+
end
|
29
|
+
|
26
30
|
def before_workers(&proc)
|
27
31
|
Hooks.register_before_workers(proc)
|
28
32
|
end
|
@@ -34,6 +38,10 @@ module ParallelCucumber
|
|
34
38
|
def on_batch_error(&proc)
|
35
39
|
Hooks.register_on_batch_error(proc)
|
36
40
|
end
|
41
|
+
|
42
|
+
def on_dry_run_error(&proc)
|
43
|
+
Hooks.register_on_dry_run_error(proc)
|
44
|
+
end
|
37
45
|
end
|
38
46
|
end
|
39
47
|
end
|
@@ -26,25 +26,32 @@ module ParallelCucumber
|
|
26
26
|
|
27
27
|
def parse_json_report(json_report)
|
28
28
|
report = JSON.parse(json_report, symbolize_names: true)
|
29
|
-
report.
|
30
|
-
status = case
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
29
|
+
report.each do |scenario, details|
|
30
|
+
report[scenario][:status] = case details[:status]
|
31
|
+
when 'failed'
|
32
|
+
Status::FAILED
|
33
|
+
when 'passed'
|
34
|
+
Status::PASSED
|
35
|
+
when 'pending'
|
36
|
+
Status::PENDING
|
37
|
+
when 'skipped'
|
38
|
+
Status::SKIPPED
|
39
|
+
when 'undefined'
|
40
|
+
Status::UNDEFINED
|
41
|
+
when 'unknown'
|
42
|
+
Status::UNKNOWN
|
43
|
+
else
|
44
|
+
Status::UNKNOWN
|
45
|
+
end
|
46
|
+
end
|
47
|
+
report
|
48
|
+
end
|
49
|
+
|
50
|
+
def unknown_result(tests)
|
51
|
+
res = tests.map do |test|
|
52
|
+
[test.to_sym, {status: ::ParallelCucumber::Status::UNKNOWN}]
|
53
|
+
end
|
54
|
+
res.to_h
|
48
55
|
end
|
49
56
|
|
50
57
|
private
|
@@ -57,7 +64,7 @@ module ParallelCucumber
|
|
57
64
|
options = remove_strict_flag(options)
|
58
65
|
content = nil
|
59
66
|
|
60
|
-
Tempfile.open(%w
|
67
|
+
Tempfile.open(%w[dry-run .json]) do |f|
|
61
68
|
dry_run_options = "--dry-run --format ParallelCucumber::Helper::Cucumber::JsonStatusFormatter --out #{f.path}"
|
62
69
|
|
63
70
|
cmd = "cucumber #{options} #{dry_run_options} #{args_string}"
|
@@ -15,7 +15,13 @@ module ParallelCucumber
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def on_after_test_case(event)
|
18
|
-
|
18
|
+
details = {status: event.result.to_sym}
|
19
|
+
if event.result.respond_to?(:exception)
|
20
|
+
details[:exception_classname] = event.result.exception.class.to_s
|
21
|
+
details[:exception_message] = event.result.exception.message
|
22
|
+
end
|
23
|
+
details[:finish_time] = Time.now.to_i
|
24
|
+
@result[event.test_case.location.to_s] = details
|
19
25
|
end
|
20
26
|
|
21
27
|
def on_finished_testing(*)
|
@@ -1,12 +1,19 @@
|
|
1
1
|
module ParallelCucumber
|
2
2
|
class Hooks
|
3
|
-
@
|
4
|
-
@
|
5
|
-
@
|
6
|
-
@
|
7
|
-
@
|
3
|
+
@worker_health_check ||= []
|
4
|
+
@before_batch_hooks ||= []
|
5
|
+
@after_batch_hooks ||= []
|
6
|
+
@before_workers ||= []
|
7
|
+
@after_workers ||= []
|
8
|
+
@on_batch_error ||= []
|
9
|
+
@on_dry_run_error ||= []
|
8
10
|
|
9
11
|
class << self
|
12
|
+
def register_worker_health_check(proc)
|
13
|
+
raise(ArgumentError, 'Please provide a valid callback') unless proc.respond_to?(:call)
|
14
|
+
@worker_health_check << proc
|
15
|
+
end
|
16
|
+
|
10
17
|
def register_before_batch(proc)
|
11
18
|
raise(ArgumentError, 'Please provide a valid callback') unless proc.respond_to?(:call)
|
12
19
|
@before_batch_hooks << proc
|
@@ -32,6 +39,17 @@ module ParallelCucumber
|
|
32
39
|
@on_batch_error << proc
|
33
40
|
end
|
34
41
|
|
42
|
+
def register_on_dry_run_error(proc)
|
43
|
+
raise(ArgumentError, 'Please provide a valid callback') unless proc.respond_to?(:call)
|
44
|
+
@on_dry_run_error << proc
|
45
|
+
end
|
46
|
+
|
47
|
+
def fire_worker_health_check(*args)
|
48
|
+
@worker_health_check.each do |hook|
|
49
|
+
hook.call(*args)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
35
53
|
def fire_before_batch_hooks(*args)
|
36
54
|
@before_batch_hooks.each do |hook|
|
37
55
|
hook.call(*args)
|
@@ -61,6 +79,12 @@ module ParallelCucumber
|
|
61
79
|
hook.call(*args)
|
62
80
|
end
|
63
81
|
end
|
82
|
+
|
83
|
+
def fire_on_dry_run_error(error)
|
84
|
+
@on_dry_run_error.each do |hook|
|
85
|
+
hook.call(error)
|
86
|
+
end
|
87
|
+
end
|
64
88
|
end
|
65
89
|
end
|
66
90
|
end
|
@@ -30,8 +30,12 @@ module ParallelCucumber
|
|
30
30
|
exit(1)
|
31
31
|
end
|
32
32
|
|
33
|
-
|
34
|
-
|
33
|
+
begin
|
34
|
+
all_tests = Helper::Cucumber.selected_tests(@options[:cucumber_options], @options[:cucumber_args])
|
35
|
+
rescue StandardError => error
|
36
|
+
Hooks.fire_on_dry_run_error(error)
|
37
|
+
raise error
|
38
|
+
end
|
35
39
|
if all_tests.empty?
|
36
40
|
@logger.info('There is no tests to run, exiting...')
|
37
41
|
exit(0)
|
@@ -98,7 +102,7 @@ module ParallelCucumber
|
|
98
102
|
|
99
103
|
status_totals = Status.constants.map do |status|
|
100
104
|
status = Status.const_get(status)
|
101
|
-
tests_with_status = results.select { |_t, s| s == status }.keys
|
105
|
+
tests_with_status = results.select { |_t, s| s[:status] == status }.keys
|
102
106
|
[status, tests_with_status]
|
103
107
|
end.to_h
|
104
108
|
|
@@ -10,11 +10,9 @@ module ParallelCucumber
|
|
10
10
|
@group_by = options[:group_by]
|
11
11
|
@batch_timeout = options[:batch_timeout]
|
12
12
|
@batch_error_timeout = options[:batch_error_timeout]
|
13
|
-
@precheck_timeout = options[:precheck_timeout]
|
14
13
|
@setup_timeout = options[:setup_timeout]
|
15
14
|
@cucumber_options = options[:cucumber_options]
|
16
15
|
@test_command = options[:test_command]
|
17
|
-
@pre_check = options[:pre_check]
|
18
16
|
@index = index
|
19
17
|
@name = "W#{@index}"
|
20
18
|
@setup_worker = options[:setup_worker]
|
@@ -99,12 +97,7 @@ module ParallelCucumber
|
|
99
97
|
job = @jobs_queue.pop(false)
|
100
98
|
case job.type
|
101
99
|
when Job::PRECHECK
|
102
|
-
|
103
|
-
if (m = precmd.match(/precmd:retry-after-(\d+)-seconds/))
|
104
|
-
@manager.inform_idle(@name)
|
105
|
-
sleep(1 + m[1].to_i)
|
106
|
-
next
|
107
|
-
end
|
100
|
+
Hooks.fire_worker_health_check(env)
|
108
101
|
@manager.inform_healthy(@name)
|
109
102
|
when Job::RUN_TESTS
|
110
103
|
run_batch(env, results, running_total, job.details)
|
@@ -161,22 +154,10 @@ module ParallelCucumber
|
|
161
154
|
@logger.update_into(@stdout_logger)
|
162
155
|
end
|
163
156
|
|
164
|
-
def precheck(env)
|
165
|
-
return 'default no-op pre_check' unless @pre_check
|
166
|
-
begin
|
167
|
-
return Helper::Command.exec_command(
|
168
|
-
env, 'precheck', @pre_check, @logger, @log_decoration, timeout: @precheck_timeout, capture: true
|
169
|
-
)
|
170
|
-
rescue
|
171
|
-
@logger.error('Pre-check failed: quitting immediately')
|
172
|
-
raise 'Pre-check failed: quitting immediately'
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
157
|
def running_totals(batch_results, running_total)
|
177
158
|
batch_info = Status.constants.map do |status|
|
178
159
|
status = Status.const_get(status)
|
179
|
-
[status, batch_results.select { |_t, s| s == status }.keys]
|
160
|
+
[status, batch_results.select { |_t, s| s[:status] == status }.keys]
|
180
161
|
end.to_h
|
181
162
|
batch_info.each do |s, tt|
|
182
163
|
@logger.info("#{s.to_s.upcase} #{tt.count} tests: #{tt.join(' ')}") unless tt.empty?
|
@@ -191,7 +172,7 @@ module ParallelCucumber
|
|
191
172
|
test_syms = tests.map(&:to_sym)
|
192
173
|
unrun = test_syms - batch_keys
|
193
174
|
surfeit = batch_keys - test_syms
|
194
|
-
unrun.each { |test| batch_results[test] = Status::UNKNOWN }
|
175
|
+
unrun.each { |test| batch_results[test][:status] = Status::UNKNOWN }
|
195
176
|
surfeit.each { |test| batch_results.delete(test) }
|
196
177
|
@logger.error("Did not run #{unrun.count}/#{tests.count}: #{unrun.join(' ')}") unless unrun.empty?
|
197
178
|
@logger.error("Extraneous runs (#{surfeit.count}): #{surfeit.join(' ')}") unless surfeit.empty?
|
@@ -232,7 +213,7 @@ module ParallelCucumber
|
|
232
213
|
@logger.warn("There was exception in on_batch_error hook #{exc.message} \n #{trace}")
|
233
214
|
end
|
234
215
|
|
235
|
-
return
|
216
|
+
return Helper::Cucumber.unknown_result(tests)
|
236
217
|
end
|
237
218
|
parse_results(test_state, tests)
|
238
219
|
ensure
|
@@ -291,18 +272,18 @@ module ParallelCucumber
|
|
291
272
|
def parse_results(f, tests)
|
292
273
|
unless File.file?(f)
|
293
274
|
@logger.error("Results file does not exist: #{f}")
|
294
|
-
return
|
275
|
+
return Helper::Cucumber.unknown_result(tests)
|
295
276
|
end
|
296
277
|
json_report = File.read(f)
|
297
278
|
if json_report.empty?
|
298
279
|
@logger.error("Results file is empty: #{f}")
|
299
|
-
return
|
280
|
+
return Helper::Cucumber.unknown_result(tests)
|
300
281
|
end
|
301
282
|
Helper::Cucumber.parse_json_report(json_report)
|
302
283
|
rescue => e
|
303
284
|
trace = e.backtrace.join("\n\t").sub("\n\t", ": #{$ERROR_INFO}#{e.class ? " (#{e.class})" : ''}\n\t")
|
304
285
|
@logger.error("Threw: JSON parse of results caused #{trace}")
|
305
|
-
|
286
|
+
Helper::Cucumber.unknown_result(tests)
|
306
287
|
end
|
307
288
|
end
|
308
289
|
end
|
@@ -39,7 +39,7 @@ module ParallelCucumber
|
|
39
39
|
def create_workers(number_of_workers)
|
40
40
|
number_of_workers.times do |index|
|
41
41
|
@workers["W#{index}"] =
|
42
|
-
|
42
|
+
ParallelCucumber::Worker.new(options: @options, index: index, stdout_logger: @logger, manager: self)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
@@ -51,11 +51,11 @@ module ParallelCucumber
|
|
51
51
|
give_job_to_healthy_worker
|
52
52
|
elsif any_worker_busy?
|
53
53
|
kill_surplus_workers
|
54
|
-
sleep 0.5
|
55
54
|
else
|
56
55
|
kill_all_workers
|
57
56
|
break
|
58
57
|
end
|
58
|
+
sleep 0.5
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
@@ -67,10 +67,15 @@ module ParallelCucumber
|
|
67
67
|
puts "Starting W#{index}"
|
68
68
|
@workers["W#{index}"].start(env_for_worker(@options[:env_variables], index))
|
69
69
|
end
|
70
|
-
@results.inject
|
70
|
+
@results.inject do |seed, result|
|
71
|
+
seed.merge(result) do |_key, oldval, newval|
|
72
|
+
(newval[:finish_time] > oldval[:finish_time]) ? newval : oldval
|
73
|
+
end
|
74
|
+
end
|
71
75
|
end
|
72
76
|
|
73
77
|
def kill_all_workers
|
78
|
+
@logger.info('=== Killing All Workers')
|
74
79
|
@workers.values.each { |w| w.assign_job(Job.new(Job::DIE)) }
|
75
80
|
end
|
76
81
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parallel_cucumber
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.22
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Bayandin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-10-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cucumber
|
@@ -127,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
127
|
- !ruby/object:Gem::Version
|
128
128
|
version: '0'
|
129
129
|
requirements: []
|
130
|
-
rubygems_version: 3.0.
|
130
|
+
rubygems_version: 3.0.3
|
131
131
|
signing_key:
|
132
132
|
specification_version: 4
|
133
133
|
summary: Run cucumber in parallel
|