parallel_tests 3.4.0 → 4.3.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.
- checksums.yaml +4 -4
- data/Readme.md +58 -32
- data/bin/parallel_cucumber +2 -1
- data/bin/parallel_rspec +2 -1
- data/bin/parallel_spinach +2 -1
- data/bin/parallel_test +2 -1
- data/lib/parallel_tests/cli.rb +161 -92
- data/lib/parallel_tests/cucumber/failures_logger.rb +1 -1
- data/lib/parallel_tests/cucumber/features_with_steps.rb +4 -3
- data/lib/parallel_tests/cucumber/runner.rb +10 -7
- data/lib/parallel_tests/cucumber/scenario_line_logger.rb +4 -4
- data/lib/parallel_tests/cucumber/scenarios.rb +9 -8
- data/lib/parallel_tests/gherkin/io.rb +2 -3
- data/lib/parallel_tests/gherkin/listener.rb +9 -10
- data/lib/parallel_tests/gherkin/runner.rb +29 -35
- data/lib/parallel_tests/gherkin/runtime_logger.rb +2 -1
- data/lib/parallel_tests/grouper.rb +54 -7
- data/lib/parallel_tests/pids.rb +5 -4
- data/lib/parallel_tests/railtie.rb +1 -0
- data/lib/parallel_tests/rspec/failures_logger.rb +6 -14
- data/lib/parallel_tests/rspec/logger_base.rb +9 -9
- data/lib/parallel_tests/rspec/runner.rb +21 -22
- data/lib/parallel_tests/rspec/runtime_logger.rb +14 -13
- data/lib/parallel_tests/rspec/summary_logger.rb +2 -3
- data/lib/parallel_tests/spinach/runner.rb +6 -2
- data/lib/parallel_tests/tasks.rb +130 -71
- data/lib/parallel_tests/test/runner.rb +90 -41
- data/lib/parallel_tests/test/runtime_logger.rb +19 -14
- data/lib/parallel_tests/version.rb +2 -1
- data/lib/parallel_tests.rb +13 -13
- metadata +10 -10
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ParallelTests
|
2
3
|
module Gherkin
|
3
4
|
class Listener
|
@@ -6,7 +7,8 @@ module ParallelTests
|
|
6
7
|
attr_writer :ignore_tag_pattern
|
7
8
|
|
8
9
|
def initialize
|
9
|
-
@steps
|
10
|
+
@steps = []
|
11
|
+
@uris = []
|
10
12
|
@collect = {}
|
11
13
|
@feature, @ignore_tag_pattern = nil
|
12
14
|
reset_counters!
|
@@ -16,7 +18,7 @@ module ParallelTests
|
|
16
18
|
@feature = feature
|
17
19
|
end
|
18
20
|
|
19
|
-
def background(*
|
21
|
+
def background(*)
|
20
22
|
@background = 1
|
21
23
|
end
|
22
24
|
|
@@ -31,7 +33,7 @@ module ParallelTests
|
|
31
33
|
@outline = 1
|
32
34
|
end
|
33
35
|
|
34
|
-
def step(*
|
36
|
+
def step(*)
|
35
37
|
return if @ignoring
|
36
38
|
if @background == 1
|
37
39
|
@background_steps += 1
|
@@ -51,12 +53,10 @@ module ParallelTests
|
|
51
53
|
# @param [Gherkin::Formatter::Model::Examples] examples
|
52
54
|
#
|
53
55
|
def examples(examples)
|
54
|
-
|
55
|
-
@collect[@uri] += (@outline_steps * examples.rows.size)
|
56
|
-
end
|
56
|
+
@collect[@uri] += (@outline_steps * examples.rows.size) unless examples.rows.empty?
|
57
57
|
end
|
58
58
|
|
59
|
-
def eof(*
|
59
|
+
def eof(*)
|
60
60
|
@collect[@uri] += (@background_steps * @scenarios)
|
61
61
|
reset_counters!
|
62
62
|
end
|
@@ -67,8 +67,7 @@ module ParallelTests
|
|
67
67
|
end
|
68
68
|
|
69
69
|
# ignore lots of other possible callbacks ...
|
70
|
-
def method_missing(*
|
71
|
-
end
|
70
|
+
def method_missing(*); end # rubocop:disable Style/MissingRespondToMissing
|
72
71
|
|
73
72
|
private
|
74
73
|
|
@@ -79,7 +78,7 @@ module ParallelTests
|
|
79
78
|
|
80
79
|
# Set @ignoring if we should ignore this scenario/outline based on its tags
|
81
80
|
def should_ignore(scenario)
|
82
|
-
@ignoring = @ignore_tag_pattern && all_tags(scenario).find{ |tag| @ignore_tag_pattern === tag.name }
|
81
|
+
@ignoring = @ignore_tag_pattern && all_tags(scenario).find { |tag| @ignore_tag_pattern === tag.name }
|
83
82
|
end
|
84
83
|
end
|
85
84
|
end
|
@@ -1,30 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require "parallel_tests/test/runner"
|
2
|
-
require 'shellwords'
|
3
3
|
|
4
4
|
module ParallelTests
|
5
5
|
module Gherkin
|
6
6
|
class Runner < ParallelTests::Test::Runner
|
7
|
-
|
8
7
|
class << self
|
9
8
|
def run_tests(test_files, process_number, num_processes, options)
|
10
9
|
combined_scenarios = test_files
|
11
10
|
|
12
11
|
if options[:group_by] == :scenarios
|
13
12
|
grouped = test_files.map { |t| t.split(':') }.group_by(&:first)
|
14
|
-
combined_scenarios = grouped.map
|
13
|
+
combined_scenarios = grouped.map do |file, files_and_lines|
|
14
|
+
"#{file}:#{files_and_lines.map(&:last).join(':')}"
|
15
|
+
end
|
15
16
|
end
|
16
17
|
|
17
|
-
sanitized_test_files = combined_scenarios.map { |val| WINDOWS ? "\"#{val}\"" : Shellwords.escape(val) }
|
18
|
-
|
19
18
|
options[:env] ||= {}
|
20
|
-
options[:env] = options[:env].merge({'AUTOTEST' => '1'}) if $stdout.tty?
|
21
|
-
|
22
|
-
cmd =
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
*sanitized_test_files
|
27
|
-
].compact.reject(&:empty?).join(' ')
|
19
|
+
options[:env] = options[:env].merge({ 'AUTOTEST' => '1' }) if $stdout.tty?
|
20
|
+
|
21
|
+
cmd = executable
|
22
|
+
cmd += runtime_logging if File.directory?(File.dirname(runtime_log))
|
23
|
+
cmd += combined_scenarios
|
24
|
+
cmd += cucumber_opts(options[:test_options])
|
28
25
|
execute_command(cmd, process_number, num_processes, options)
|
29
26
|
end
|
30
27
|
|
@@ -32,6 +29,10 @@ module ParallelTests
|
|
32
29
|
@test_file_name || 'feature'
|
33
30
|
end
|
34
31
|
|
32
|
+
def default_test_folder
|
33
|
+
'features'
|
34
|
+
end
|
35
|
+
|
35
36
|
def test_suffix
|
36
37
|
/\.feature$/
|
37
38
|
end
|
@@ -44,42 +45,38 @@ module ParallelTests
|
|
44
45
|
# 1 scenario (1 failed)
|
45
46
|
# 1 step (1 failed)
|
46
47
|
def summarize_results(results)
|
47
|
-
sort_order =
|
48
|
+
sort_order = ['scenario', 'step', 'failed', 'flaky', 'undefined', 'skipped', 'pending', 'passed']
|
48
49
|
|
49
|
-
|
50
|
+
['scenario', 'step'].map do |group|
|
50
51
|
group_results = results.grep(/^\d+ #{group}/)
|
51
52
|
next if group_results.empty?
|
52
53
|
|
53
54
|
sums = sum_up_results(group_results)
|
54
55
|
sums = sums.sort_by { |word, _| sort_order.index(word) || 999 }
|
55
56
|
sums.map! do |word, number|
|
56
|
-
plural = "s" if word == group
|
57
|
+
plural = "s" if (word == group) && (number != 1)
|
57
58
|
"#{number} #{word}#{plural}"
|
58
59
|
end
|
59
|
-
"#{sums[0]} (#{sums[1
|
60
|
+
"#{sums[0]} (#{sums[1..].join(", ")})"
|
60
61
|
end.compact.join("\n")
|
61
62
|
end
|
62
63
|
|
63
64
|
def cucumber_opts(given)
|
64
|
-
if given
|
65
|
+
if given&.include?('--profile') || given&.include?('-p')
|
65
66
|
given
|
66
67
|
else
|
67
|
-
[given, profile_from_config]
|
68
|
+
[*given, *profile_from_config]
|
68
69
|
end
|
69
70
|
end
|
70
71
|
|
71
72
|
def profile_from_config
|
72
73
|
# copied from https://github.com/cucumber/cucumber/blob/master/lib/cucumber/cli/profile_loader.rb#L85
|
73
74
|
config = Dir.glob("{,.config/,config/}#{name}{.yml,.yaml}").first
|
74
|
-
if config && File.read(config) =~ /^parallel:/
|
75
|
-
"--profile parallel"
|
76
|
-
end
|
75
|
+
['--profile', 'parallel'] if config && File.read(config) =~ /^parallel:/
|
77
76
|
end
|
78
77
|
|
79
|
-
def tests_in_groups(tests, num_groups, options={})
|
80
|
-
if options[:group_by] == :scenarios
|
81
|
-
@test_file_name = "scenario"
|
82
|
-
end
|
78
|
+
def tests_in_groups(tests, num_groups, options = {})
|
79
|
+
@test_file_name = "scenario" if options[:group_by] == :scenarios
|
83
80
|
method = "by_#{options[:group_by]}"
|
84
81
|
if Grouper.respond_to?(method)
|
85
82
|
Grouper.send(method, find_tests(tests, options), num_groups, options)
|
@@ -88,9 +85,8 @@ module ParallelTests
|
|
88
85
|
end
|
89
86
|
end
|
90
87
|
|
91
|
-
|
92
88
|
def runtime_logging
|
93
|
-
|
89
|
+
['--format', 'ParallelTests::Gherkin::RuntimeLogger', '--out', runtime_log]
|
94
90
|
end
|
95
91
|
|
96
92
|
def runtime_log
|
@@ -98,18 +94,16 @@ module ParallelTests
|
|
98
94
|
end
|
99
95
|
|
100
96
|
def determine_executable
|
101
|
-
|
102
|
-
when File.exist?("bin/#{name}")
|
97
|
+
if File.exist?("bin/#{name}")
|
103
98
|
ParallelTests.with_ruby_binary("bin/#{name}")
|
104
|
-
|
105
|
-
"bundle exec
|
106
|
-
|
99
|
+
elsif ParallelTests.bundler_enabled?
|
100
|
+
["bundle", "exec", name]
|
101
|
+
elsif File.file?("script/#{name}")
|
107
102
|
ParallelTests.with_ruby_binary("script/#{name}")
|
108
103
|
else
|
109
|
-
|
104
|
+
[name.to_s]
|
110
105
|
end
|
111
106
|
end
|
112
|
-
|
113
107
|
end
|
114
108
|
end
|
115
109
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'parallel_tests/gherkin/io'
|
2
3
|
|
3
4
|
module ParallelTests
|
@@ -19,7 +20,7 @@ module ParallelTests
|
|
19
20
|
|
20
21
|
config.on_event :test_run_finished do |_|
|
21
22
|
lock_output do
|
22
|
-
@io.puts
|
23
|
+
@io.puts(@example_times.map { |file, time| "#{file}:#{time}" })
|
23
24
|
end
|
24
25
|
end
|
25
26
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ParallelTests
|
2
3
|
class Grouper
|
3
4
|
class << self
|
@@ -6,13 +7,15 @@ module ParallelTests
|
|
6
7
|
in_even_groups_by_size(features_with_steps, num_groups)
|
7
8
|
end
|
8
9
|
|
9
|
-
def by_scenarios(tests, num_groups, options={})
|
10
|
+
def by_scenarios(tests, num_groups, options = {})
|
10
11
|
scenarios = group_by_scenarios(tests, options)
|
11
12
|
in_even_groups_by_size(scenarios, num_groups)
|
12
13
|
end
|
13
14
|
|
14
|
-
def in_even_groups_by_size(items, num_groups, options= {})
|
15
|
-
groups = Array.new(num_groups) { {:
|
15
|
+
def in_even_groups_by_size(items, num_groups, options = {})
|
16
|
+
groups = Array.new(num_groups) { { items: [], size: 0 } }
|
17
|
+
|
18
|
+
return specify_groups(items, num_groups, options, groups) if options[:specify_groups]
|
16
19
|
|
17
20
|
# add all files that should run in a single process to one group
|
18
21
|
single_process_patterns = options[:single_process] || []
|
@@ -24,14 +27,14 @@ module ParallelTests
|
|
24
27
|
isolate_count = isolate_count(options)
|
25
28
|
|
26
29
|
if isolate_count >= num_groups
|
27
|
-
raise 'Number of isolated processes must be
|
30
|
+
raise 'Number of isolated processes must be >= total number of processes'
|
28
31
|
end
|
29
32
|
|
30
33
|
if isolate_count >= 1
|
31
34
|
# add all files that should run in a multiple isolated processes to their own groups
|
32
35
|
group_features_by_size(items_to_group(single_items), groups[0..(isolate_count - 1)])
|
33
36
|
# group the non-isolated by size
|
34
|
-
group_features_by_size(items_to_group(items), groups[isolate_count
|
37
|
+
group_features_by_size(items_to_group(items), groups[isolate_count..])
|
35
38
|
else
|
36
39
|
# add all files that should run in a single non-isolated process to first group
|
37
40
|
single_items.each { |item, size| add_to_group(groups.first, item, size) }
|
@@ -45,6 +48,50 @@ module ParallelTests
|
|
45
48
|
|
46
49
|
private
|
47
50
|
|
51
|
+
def specify_groups(items, num_groups, options, groups)
|
52
|
+
specify_test_process_groups = options[:specify_groups].split('|')
|
53
|
+
if specify_test_process_groups.count > num_groups
|
54
|
+
raise 'Number of processes separated by pipe must be less than or equal to the total number of processes'
|
55
|
+
end
|
56
|
+
|
57
|
+
all_specified_tests = specify_test_process_groups.map { |group| group.split(',') }.flatten
|
58
|
+
specified_items_found, items = items.partition { |item, _size| all_specified_tests.include?(item) }
|
59
|
+
|
60
|
+
specified_specs_not_found = all_specified_tests - specified_items_found.map(&:first)
|
61
|
+
if specified_specs_not_found.any?
|
62
|
+
raise "Could not find #{specified_specs_not_found} from --specify-groups in the selected files & folders"
|
63
|
+
end
|
64
|
+
|
65
|
+
if specify_test_process_groups.count == num_groups && items.flatten.any?
|
66
|
+
raise(
|
67
|
+
<<~ERROR
|
68
|
+
The number of groups in --specify-groups matches the number of groups from -n but there were other specs
|
69
|
+
found in the selected files & folders not specified in --specify-groups. Make sure -n is larger than the
|
70
|
+
number of processes in --specify-groups if there are other specs that need to be run. The specs that aren't run:
|
71
|
+
#{items.map(&:first)}
|
72
|
+
ERROR
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
# First order the specify_groups into the main groups array
|
77
|
+
specify_test_process_groups.each_with_index do |specify_test_process, i|
|
78
|
+
groups[i] = specify_test_process.split(',')
|
79
|
+
end
|
80
|
+
|
81
|
+
# Return early when processed specify_groups tests exactly match the items passed in
|
82
|
+
return groups if specify_test_process_groups.count == num_groups
|
83
|
+
|
84
|
+
# Now sort the rest of the items into the main groups array
|
85
|
+
specified_range = specify_test_process_groups.count..-1
|
86
|
+
remaining_groups = groups[specified_range]
|
87
|
+
group_features_by_size(items_to_group(items), remaining_groups)
|
88
|
+
# Don't sort all the groups, only sort the ones not specified in specify_groups
|
89
|
+
sorted_groups = remaining_groups.map { |g| g[:items].sort }
|
90
|
+
groups[specified_range] = sorted_groups
|
91
|
+
|
92
|
+
groups
|
93
|
+
end
|
94
|
+
|
48
95
|
def isolate_count(options)
|
49
96
|
if options[:isolate_count] && options[:isolate_count] > 1
|
50
97
|
options[:isolate_count]
|
@@ -56,7 +103,7 @@ module ParallelTests
|
|
56
103
|
end
|
57
104
|
|
58
105
|
def largest_first(files)
|
59
|
-
files.sort_by{|_item, size| size }.reverse
|
106
|
+
files.sort_by { |_item, size| size }.reverse
|
60
107
|
end
|
61
108
|
|
62
109
|
def smallest_group(groups)
|
@@ -73,7 +120,7 @@ module ParallelTests
|
|
73
120
|
ParallelTests::Cucumber::FeaturesWithSteps.all(tests, options)
|
74
121
|
end
|
75
122
|
|
76
|
-
def group_by_scenarios(tests, options={})
|
123
|
+
def group_by_scenarios(tests, options = {})
|
77
124
|
require 'parallel_tests/cucumber/scenarios'
|
78
125
|
ParallelTests::Cucumber::Scenarios.all(tests, options)
|
79
126
|
end
|
data/lib/parallel_tests/pids.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'json'
|
2
3
|
|
3
4
|
module ParallelTests
|
@@ -42,18 +43,18 @@ module ParallelTests
|
|
42
43
|
|
43
44
|
def read
|
44
45
|
sync do
|
45
|
-
contents =
|
46
|
+
contents = File.read(file_path)
|
46
47
|
return if contents.empty?
|
47
48
|
@pids = JSON.parse(contents)
|
48
49
|
end
|
49
50
|
end
|
50
51
|
|
51
52
|
def save
|
52
|
-
sync {
|
53
|
+
sync { File.write(file_path, pids.to_json) }
|
53
54
|
end
|
54
55
|
|
55
|
-
def sync
|
56
|
-
mutex.synchronize
|
56
|
+
def sync(&block)
|
57
|
+
mutex.synchronize(&block)
|
57
58
|
end
|
58
59
|
end
|
59
60
|
end
|
@@ -1,24 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'parallel_tests/rspec/logger_base'
|
2
3
|
require 'parallel_tests/rspec/runner'
|
3
4
|
|
4
5
|
class ParallelTests::RSpec::FailuresLogger < ParallelTests::RSpec::LoggerBase
|
5
|
-
|
6
|
-
def dump_failures(*args)
|
7
|
-
end
|
8
|
-
else
|
9
|
-
RSpec::Core::Formatters.register self, :dump_summary
|
10
|
-
end
|
6
|
+
RSpec::Core::Formatters.register(self, :dump_summary)
|
11
7
|
|
12
8
|
def dump_summary(*args)
|
13
9
|
lock_output do
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
notification
|
18
|
-
unless notification.failed_examples.empty?
|
19
|
-
colorizer = ::RSpec::Core::Formatters::ConsoleCodes
|
20
|
-
output.puts notification.colorized_rerun_commands(colorizer)
|
21
|
-
end
|
10
|
+
notification = args.first
|
11
|
+
unless notification.failed_examples.empty?
|
12
|
+
colorizer = ::RSpec::Core::Formatters::ConsoleCodes
|
13
|
+
output.puts notification.colorized_rerun_commands(colorizer)
|
22
14
|
end
|
23
15
|
end
|
24
16
|
@output.flush
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ParallelTests
|
2
3
|
module RSpec
|
3
4
|
end
|
@@ -6,33 +7,32 @@ end
|
|
6
7
|
require 'rspec/core/formatters/base_text_formatter'
|
7
8
|
|
8
9
|
class ParallelTests::RSpec::LoggerBase < RSpec::Core::Formatters::BaseTextFormatter
|
9
|
-
RSPEC_2 = RSpec::Core::Version::STRING.start_with?('2')
|
10
|
-
|
11
10
|
def initialize(*args)
|
12
11
|
super
|
13
12
|
|
14
13
|
@output ||= args[0]
|
15
14
|
|
16
|
-
|
15
|
+
case @output
|
16
|
+
when String # a path ?
|
17
17
|
FileUtils.mkdir_p(File.dirname(@output))
|
18
|
-
File.open(@output, 'w'){} # overwrite previous results
|
18
|
+
File.open(@output, 'w') {} # overwrite previous results
|
19
19
|
@output = File.open(@output, 'a')
|
20
|
-
|
20
|
+
when File # close and restart in append mode
|
21
21
|
@output.close
|
22
22
|
@output = File.open(@output.path, 'a')
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
#stolen from Rspec
|
27
|
-
def close(*
|
28
|
-
@output.close
|
26
|
+
# stolen from Rspec
|
27
|
+
def close(*)
|
28
|
+
@output.close if (IO === @output) & (@output != $stdout)
|
29
29
|
end
|
30
30
|
|
31
31
|
protected
|
32
32
|
|
33
33
|
# do not let multiple processes get in each others way
|
34
34
|
def lock_output
|
35
|
-
if
|
35
|
+
if @output.is_a?(File)
|
36
36
|
begin
|
37
37
|
@output.flock File::LOCK_EX
|
38
38
|
yield
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require "parallel_tests/test/runner"
|
2
3
|
|
3
4
|
module ParallelTests
|
@@ -6,32 +7,36 @@ module ParallelTests
|
|
6
7
|
DEV_NULL = (WINDOWS ? "NUL" : "/dev/null")
|
7
8
|
class << self
|
8
9
|
def run_tests(test_files, process_number, num_processes, options)
|
9
|
-
|
10
|
-
cmd = [exe, options[:test_options], color, spec_opts, *test_files].compact.join(" ")
|
10
|
+
cmd = [*executable, *options[:test_options], *color, *spec_opts, *test_files]
|
11
11
|
execute_command(cmd, process_number, num_processes, options)
|
12
12
|
end
|
13
13
|
|
14
14
|
def determine_executable
|
15
|
-
|
16
|
-
when File.exist?("bin/rspec")
|
15
|
+
if File.exist?("bin/rspec")
|
17
16
|
ParallelTests.with_ruby_binary("bin/rspec")
|
18
|
-
|
19
|
-
"bundle exec rspec"
|
17
|
+
elsif ParallelTests.bundler_enabled?
|
18
|
+
["bundle", "exec", "rspec"]
|
20
19
|
else
|
21
|
-
"rspec"
|
20
|
+
["rspec"]
|
22
21
|
end
|
23
22
|
end
|
24
23
|
|
25
24
|
def runtime_log
|
26
|
-
|
25
|
+
"tmp/parallel_runtime_rspec.log"
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_test_folder
|
29
|
+
"spec"
|
27
30
|
end
|
28
31
|
|
29
32
|
def test_file_name
|
30
33
|
"spec"
|
31
34
|
end
|
32
35
|
|
36
|
+
# used to find all _spec.rb files
|
37
|
+
# supports also feature files used by rspec turnip extension
|
33
38
|
def test_suffix
|
34
|
-
/_spec\.rb$/
|
39
|
+
/(_spec\.rb|\.feature)$/
|
35
40
|
end
|
36
41
|
|
37
42
|
def line_is_result?(line)
|
@@ -44,8 +49,8 @@ module ParallelTests
|
|
44
49
|
# --order rand:1234
|
45
50
|
# --order random:1234
|
46
51
|
def command_with_seed(cmd, seed)
|
47
|
-
clean = cmd
|
48
|
-
|
52
|
+
clean = remove_command_arguments(cmd, '--seed', '--order')
|
53
|
+
[*clean, '--seed', seed]
|
49
54
|
end
|
50
55
|
|
51
56
|
# Summarize results from threads and colorize results based on failure and pending counts.
|
@@ -55,9 +60,9 @@ module ParallelTests
|
|
55
60
|
return text unless $stdout.tty?
|
56
61
|
sums = sum_up_results(results)
|
57
62
|
color =
|
58
|
-
if sums['failure']
|
63
|
+
if sums['failure'] > 0
|
59
64
|
31 # red
|
60
|
-
elsif sums['pending']
|
65
|
+
elsif sums['pending'] > 0
|
61
66
|
33 # yellow
|
62
67
|
else
|
63
68
|
32 # green
|
@@ -67,19 +72,13 @@ module ParallelTests
|
|
67
72
|
|
68
73
|
private
|
69
74
|
|
70
|
-
# so it can be stubbed....
|
71
|
-
def run(cmd)
|
72
|
-
`#{cmd}`
|
73
|
-
end
|
74
|
-
|
75
75
|
def color
|
76
|
-
'--color --tty' if $stdout.tty?
|
76
|
+
['--color', '--tty'] if $stdout.tty?
|
77
77
|
end
|
78
78
|
|
79
79
|
def spec_opts
|
80
|
-
options_file = ['.rspec_parallel', 'spec/parallel_spec.opts', 'spec/spec.opts'].detect{|f| File.file?(f) }
|
81
|
-
|
82
|
-
"-O #{options_file}"
|
80
|
+
options_file = ['.rspec_parallel', 'spec/parallel_spec.opts', 'spec/spec.opts'].detect { |f| File.file?(f) }
|
81
|
+
["-O", options_file] if options_file
|
83
82
|
end
|
84
83
|
end
|
85
84
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'parallel_tests'
|
2
3
|
require 'parallel_tests/rspec/logger_base'
|
3
4
|
|
@@ -8,9 +9,7 @@ class ParallelTests::RSpec::RuntimeLogger < ParallelTests::RSpec::LoggerBase
|
|
8
9
|
@group_nesting = 0
|
9
10
|
end
|
10
11
|
|
11
|
-
|
12
|
-
RSpec::Core::Formatters.register self, :example_group_started, :example_group_finished, :start_dump
|
13
|
-
end
|
12
|
+
RSpec::Core::Formatters.register(self, :example_group_started, :example_group_finished, :start_dump)
|
14
13
|
|
15
14
|
def example_group_started(example_group)
|
16
15
|
@time = ParallelTests.now if @group_nesting == 0
|
@@ -21,23 +20,25 @@ class ParallelTests::RSpec::RuntimeLogger < ParallelTests::RSpec::LoggerBase
|
|
21
20
|
def example_group_finished(notification)
|
22
21
|
@group_nesting -= 1
|
23
22
|
if @group_nesting == 0
|
24
|
-
|
25
|
-
@example_times[path] += ParallelTests.now - @time
|
23
|
+
@example_times[notification.group.file_path] += ParallelTests.now - @time
|
26
24
|
end
|
27
25
|
super if defined?(super)
|
28
26
|
end
|
29
27
|
|
30
|
-
def dump_summary(*
|
31
|
-
|
32
|
-
def
|
33
|
-
|
28
|
+
def dump_summary(*); end
|
29
|
+
|
30
|
+
def dump_failures(*); end
|
31
|
+
|
32
|
+
def dump_failure(*); end
|
33
|
+
|
34
|
+
def dump_pending(*); end
|
34
35
|
|
35
|
-
def start_dump(*
|
36
|
-
return unless ENV['TEST_ENV_NUMBER'] #only record when running in parallel
|
36
|
+
def start_dump(*)
|
37
|
+
return unless ENV['TEST_ENV_NUMBER'] # only record when running in parallel
|
37
38
|
lock_output do
|
38
39
|
@example_times.each do |file, time|
|
39
|
-
relative_path = file.sub(
|
40
|
-
@output.puts "#{relative_path}:#{time
|
40
|
+
relative_path = file.sub(%r{^#{Regexp.escape Dir.pwd}/}, '').sub(%r{^\./}, "")
|
41
|
+
@output.puts "#{relative_path}:#{[time, 0].max}"
|
41
42
|
end
|
42
43
|
end
|
43
44
|
@output.flush
|
@@ -1,9 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'parallel_tests/rspec/failures_logger'
|
2
3
|
|
3
4
|
class ParallelTests::RSpec::SummaryLogger < ParallelTests::RSpec::LoggerBase
|
4
|
-
|
5
|
-
RSpec::Core::Formatters.register self, :dump_failures
|
6
|
-
end
|
5
|
+
RSpec::Core::Formatters.register(self, :dump_failures)
|
7
6
|
|
8
7
|
def dump_failures(*args)
|
9
8
|
lock_output { super }
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require "parallel_tests/gherkin/runner"
|
2
3
|
|
3
4
|
module ParallelTests
|
@@ -8,11 +9,14 @@ module ParallelTests
|
|
8
9
|
'spinach'
|
9
10
|
end
|
10
11
|
|
12
|
+
def default_test_folder
|
13
|
+
'features'
|
14
|
+
end
|
15
|
+
|
11
16
|
def runtime_logging
|
12
|
-
#Not Yet Supported
|
17
|
+
# Not Yet Supported
|
13
18
|
""
|
14
19
|
end
|
15
|
-
|
16
20
|
end
|
17
21
|
end
|
18
22
|
end
|