parallel_tests 2.28.0 → 3.7.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.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'parallel_tests/gherkin/io'
2
3
 
3
4
  module ParallelTests
@@ -14,12 +15,12 @@ module ParallelTests
14
15
  end
15
16
 
16
17
  config.on_event :test_case_finished do |event|
17
- @example_times[event.test_case.feature.file] += ParallelTests.now.to_f - @start_at
18
+ @example_times[event.test_case.location.file] += ParallelTests.now.to_f - @start_at
18
19
  end
19
20
 
20
21
  config.on_event :test_run_finished do |_|
21
22
  lock_output do
22
- @io.puts @example_times.map { |file, time| "#{file}:#{time}" }
23
+ @io.puts(@example_times.map { |file, time| "#{file}:#{time}" })
23
24
  end
24
25
  end
25
26
  end
@@ -1,35 +1,113 @@
1
+ # frozen_string_literal: true
1
2
  module ParallelTests
2
3
  class Grouper
3
4
  class << self
4
5
  def by_steps(tests, num_groups, options)
5
- features_with_steps = build_features_with_steps(tests, options)
6
+ features_with_steps = group_by_features_with_steps(tests, options)
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) { {:items => [], :size => 0} }
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
- (options[:single_process] || []).each do |pattern|
19
- matched, items = items.partition { |item, _size| item =~ pattern }
20
- matched.each { |item, size| add_to_group(groups.first, item, size) }
21
+ single_process_patterns = options[:single_process] || []
22
+
23
+ single_items, items = items.partition do |item, _size|
24
+ single_process_patterns.any? { |pattern| item =~ pattern }
25
+ end
26
+
27
+ isolate_count = isolate_count(options)
28
+
29
+ if isolate_count >= num_groups
30
+ raise 'Number of isolated processes must be less than total the number of processes'
31
+ end
32
+
33
+ if isolate_count >= num_groups
34
+ raise 'Number of isolated processes must be >= total number of processes'
21
35
  end
22
36
 
23
- groups_to_fill = (options[:isolate] ? groups[1..-1] : groups)
24
- group_features_by_size(items_to_group(items), groups_to_fill)
37
+ if isolate_count >= 1
38
+ # add all files that should run in a multiple isolated processes to their own groups
39
+ group_features_by_size(items_to_group(single_items), groups[0..(isolate_count - 1)])
40
+ # group the non-isolated by size
41
+ group_features_by_size(items_to_group(items), groups[isolate_count..-1])
42
+ else
43
+ # add all files that should run in a single non-isolated process to first group
44
+ single_items.each { |item, size| add_to_group(groups.first, item, size) }
45
+
46
+ # group all by size
47
+ group_features_by_size(items_to_group(items), groups)
48
+ end
25
49
 
26
50
  groups.map! { |g| g[:items].sort }
27
51
  end
28
52
 
29
53
  private
30
54
 
55
+ def specify_groups(items, num_groups, options, groups)
56
+ specify_test_process_groups = options[:specify_groups].split('|')
57
+ if specify_test_process_groups.count > num_groups
58
+ raise 'Number of processes separated by pipe must be less than or equal to the total number of processes'
59
+ end
60
+
61
+ all_specified_tests = specify_test_process_groups.map { |group| group.split(',') }.flatten
62
+ specified_items_found, items = items.partition { |item, _size| all_specified_tests.include?(item) }
63
+
64
+ specified_specs_not_found = all_specified_tests - specified_items_found.map(&:first)
65
+ if specified_specs_not_found.any?
66
+ raise "Could not find #{specified_specs_not_found} from --specify-groups in the selected files & folders"
67
+ end
68
+
69
+ if specify_test_process_groups.count == num_groups && items.flatten.any?
70
+ raise(
71
+ <<~ERROR
72
+ The number of groups in --specify-groups matches the number of groups from -n but there were other specs
73
+ found in the selected files & folders not specified in --specify-groups. Make sure -n is larger than the
74
+ number of processes in --specify-groups if there are other specs that need to be run. The specs that aren't run:
75
+ #{items.map(&:first)}
76
+ ERROR
77
+ )
78
+ end
79
+
80
+ # First order the specify_groups into the main groups array
81
+ specify_test_process_groups.each_with_index do |specify_test_process, i|
82
+ groups[i] = specify_test_process.split(',')
83
+ end
84
+
85
+ # Return early when processed specify_groups tests exactly match the items passed in
86
+ return groups if specify_test_process_groups.count == num_groups
87
+
88
+ # Now sort the rest of the items into the main groups array
89
+ specified_range = specify_test_process_groups.count..-1
90
+ remaining_groups = groups[specified_range]
91
+ group_features_by_size(items_to_group(items), remaining_groups)
92
+ # Don't sort all the groups, only sort the ones not specified in specify_groups
93
+ sorted_groups = remaining_groups.map { |g| g[:items].sort }
94
+ groups[specified_range] = sorted_groups
95
+
96
+ groups
97
+ end
98
+
99
+ def isolate_count(options)
100
+ if options[:isolate_count] && options[:isolate_count] > 1
101
+ options[:isolate_count]
102
+ elsif options[:isolate]
103
+ 1
104
+ else
105
+ 0
106
+ end
107
+ end
108
+
31
109
  def largest_first(files)
32
- files.sort_by{|_item, size| size }.reverse
110
+ files.sort_by { |_item, size| size }.reverse
33
111
  end
34
112
 
35
113
  def smallest_group(groups)
@@ -41,26 +119,12 @@ module ParallelTests
41
119
  group[:size] += size
42
120
  end
43
121
 
44
- def build_features_with_steps(tests, options)
45
- require 'gherkin/parser'
46
- ignore_tag_pattern = options[:ignore_tag_pattern].nil? ? nil : Regexp.compile(options[:ignore_tag_pattern])
47
- parser = ::Gherkin::Parser.new
48
- # format of hash will be FILENAME => NUM_STEPS
49
- steps_per_file = tests.each_with_object({}) do |file,steps|
50
- feature = parser.parse(File.read(file)).fetch(:feature)
51
-
52
- # skip feature if it matches tag regex
53
- next if feature[:tags].grep(ignore_tag_pattern).any?
54
-
55
- # count the number of steps in the file
56
- # will only include a feature if the regex does not match
57
- all_steps = feature[:children].map{|a| a[:steps].count if a[:tags].grep(ignore_tag_pattern).empty? }.compact
58
- steps[file] = all_steps.inject(0,:+)
59
- end
60
- steps_per_file.sort_by { |_, value| -value }
122
+ def group_by_features_with_steps(tests, options)
123
+ require 'parallel_tests/cucumber/features_with_steps'
124
+ ParallelTests::Cucumber::FeaturesWithSteps.all(tests, options)
61
125
  end
62
126
 
63
- def group_by_scenarios(tests, options={})
127
+ def group_by_scenarios(tests, options = {})
64
128
  require 'parallel_tests/cucumber/scenarios'
65
129
  ParallelTests::Cucumber::Scenarios.all(tests, options)
66
130
  end
@@ -1,8 +1,9 @@
1
+ # frozen_string_literal: true
1
2
  require 'json'
2
3
 
3
4
  module ParallelTests
4
5
  class Pids
5
- attr_reader :pids, :file_path, :mutex
6
+ attr_reader :file_path, :mutex
6
7
 
7
8
  def initialize(file_path)
8
9
  @file_path = file_path
@@ -52,8 +53,8 @@ module ParallelTests
52
53
  sync { IO.write(file_path, pids.to_json) }
53
54
  end
54
55
 
55
- def sync
56
- mutex.synchronize { yield }
56
+ def sync(&block)
57
+ mutex.synchronize(&block)
57
58
  end
58
59
  end
59
60
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  # rake tasks for Rails 3+
2
3
  module ParallelTests
3
4
  class Railtie < ::Rails::Railtie
@@ -1,10 +1,10 @@
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
  if RSPEC_2
6
- def dump_failures(*args)
7
- end
7
+ def dump_failures(*args); end
8
8
  else
9
9
  RSpec::Core::Formatters.register self, :dump_summary
10
10
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module ParallelTests
2
3
  module RSpec
3
4
  end
@@ -13,26 +14,27 @@ class ParallelTests::RSpec::LoggerBase < RSpec::Core::Formatters::BaseTextFormat
13
14
 
14
15
  @output ||= args[0]
15
16
 
16
- if String === @output # a path ?
17
+ case @output
18
+ when String # a path ?
17
19
  FileUtils.mkdir_p(File.dirname(@output))
18
- File.open(@output, 'w'){} # overwrite previous results
20
+ File.open(@output, 'w') {} # overwrite previous results
19
21
  @output = File.open(@output, 'a')
20
- elsif File === @output # close and restart in append mode
22
+ when File # close and restart in append mode
21
23
  @output.close
22
24
  @output = File.open(@output.path, 'a')
23
25
  end
24
26
  end
25
27
 
26
- #stolen from Rspec
27
- def close(*args)
28
- @output.close if (IO === @output) & (@output != $stdout)
28
+ # stolen from Rspec
29
+ def close(*)
30
+ @output.close if (IO === @output) & (@output != $stdout)
29
31
  end
30
32
 
31
33
  protected
32
34
 
33
35
  # do not let multiple processes get in each others way
34
36
  def lock_output
35
- if File === @output
37
+ if @output.is_a?(File)
36
38
  begin
37
39
  @output.flock File::LOCK_EX
38
40
  yield
@@ -1,11 +1,10 @@
1
+ # frozen_string_literal: true
1
2
  require "parallel_tests/test/runner"
2
3
 
3
4
  module ParallelTests
4
5
  module RSpec
5
6
  class Runner < ParallelTests::Test::Runner
6
7
  DEV_NULL = (WINDOWS ? "NUL" : "/dev/null")
7
- NAME = 'RSpec'
8
-
9
8
  class << self
10
9
  def run_tests(test_files, process_number, num_processes, options)
11
10
  exe = executable # expensive, so we cache
@@ -14,21 +13,21 @@ module ParallelTests
14
13
  end
15
14
 
16
15
  def determine_executable
17
- cmd = case
18
- when File.exist?("bin/rspec")
16
+ if File.exist?("bin/rspec")
19
17
  ParallelTests.with_ruby_binary("bin/rspec")
20
- when ParallelTests.bundler_enabled?
21
- cmd = (run("bundle show rspec-core") =~ %r{Could not find gem.*} ? "spec" : "rspec")
22
- "bundle exec #{cmd}"
18
+ elsif ParallelTests.bundler_enabled?
19
+ "bundle exec rspec"
23
20
  else
24
- %w[spec rspec].detect{|cmd| system "#{cmd} --version > #{DEV_NULL} 2>&1" }
21
+ "rspec"
25
22
  end
26
-
27
- cmd or raise("Can't find executables rspec or spec")
28
23
  end
29
24
 
30
25
  def runtime_log
31
- 'tmp/parallel_runtime_rspec.log'
26
+ "tmp/parallel_runtime_rspec.log"
27
+ end
28
+
29
+ def default_test_folder
30
+ "spec"
32
31
  end
33
32
 
34
33
  def test_file_name
@@ -53,6 +52,22 @@ module ParallelTests
53
52
  "#{clean} --seed #{seed}"
54
53
  end
55
54
 
55
+ # Summarize results from threads and colorize results based on failure and pending counts.
56
+ #
57
+ def summarize_results(results)
58
+ text = super
59
+ return text unless $stdout.tty?
60
+ sums = sum_up_results(results)
61
+ color =
62
+ if sums['failure'] > 0
63
+ 31 # red
64
+ elsif sums['pending'] > 0
65
+ 33 # yellow
66
+ else
67
+ 32 # green
68
+ end
69
+ "\e[#{color}m#{text}\e[0m"
70
+ end
56
71
 
57
72
  private
58
73
 
@@ -66,7 +81,7 @@ module ParallelTests
66
81
  end
67
82
 
68
83
  def spec_opts
69
- options_file = ['.rspec_parallel', 'spec/parallel_spec.opts', 'spec/spec.opts'].detect{|f| File.file?(f) }
84
+ options_file = ['.rspec_parallel', 'spec/parallel_spec.opts', 'spec/spec.opts'].detect { |f| File.file?(f) }
70
85
  return unless options_file
71
86
  "-O #{options_file}"
72
87
  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
- unless RSPEC_2
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 unless RSPEC_2
14
13
 
15
14
  def example_group_started(example_group)
16
15
  @time = ParallelTests.now if @group_nesting == 0
@@ -27,16 +26,19 @@ class ParallelTests::RSpec::RuntimeLogger < ParallelTests::RSpec::LoggerBase
27
26
  super if defined?(super)
28
27
  end
29
28
 
30
- def dump_summary(*args);end
31
- def dump_failures(*args);end
32
- def dump_failure(*args);end
33
- def dump_pending(*args);end
29
+ def dump_summary(*); end
30
+
31
+ def dump_failures(*); end
32
+
33
+ def dump_failure(*); end
34
+
35
+ def dump_pending(*); end
34
36
 
35
- def start_dump(*args)
36
- return unless ENV['TEST_ENV_NUMBER'] #only record when running in parallel
37
+ def start_dump(*)
38
+ return unless ENV['TEST_ENV_NUMBER'] # only record when running in parallel
37
39
  lock_output do
38
40
  @example_times.each do |file, time|
39
- relative_path = file.sub(/^#{Regexp.escape Dir.pwd}\//,'').sub(/^\.\//, "")
41
+ relative_path = file.sub(%r{^#{Regexp.escape Dir.pwd}/}, '').sub(%r{^\./}, "")
40
42
  @output.puts "#{relative_path}:#{time > 0 ? time : 0}"
41
43
  end
42
44
  end
@@ -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
- unless RSPEC_2
5
- RSpec::Core::Formatters.register self, :dump_failures
6
- end
5
+ RSpec::Core::Formatters.register self, :dump_failures unless RSPEC_2
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
@@ -1,10 +1,20 @@
1
+ # frozen_string_literal: true
1
2
  require 'rake'
3
+ require 'shellwords'
2
4
 
3
5
  module ParallelTests
4
6
  module Tasks
5
7
  class << self
6
8
  def rails_env
7
- ENV['RAILS_ENV'] || 'test'
9
+ 'test'
10
+ end
11
+
12
+ def rake_bin
13
+ # Prevent 'Exec format error' Errno::ENOEXEC on Windows
14
+ return "rake" if RUBY_PLATFORM =~ /mswin|mingw|cygwin/
15
+ binstub_path = File.join('bin', 'rake')
16
+ return binstub_path if File.exist?(binstub_path)
17
+ "rake"
8
18
  end
9
19
 
10
20
  def load_lib
@@ -18,12 +28,13 @@ module ParallelTests
18
28
  end
19
29
  end
20
30
 
21
- def run_in_parallel(cmd, options={})
31
+ def run_in_parallel(cmd, options = {})
22
32
  load_lib
23
33
  count = " -n #{options[:count]}" unless options[:count].to_s.empty?
24
34
  # Using the relative path to find the binary allow to run a specific version of it
25
- executable = File.expand_path("../../../bin/parallel_test", __FILE__)
26
- command = "#{ParallelTests.with_ruby_binary(Shellwords.escape(executable))} --exec '#{cmd}'#{count}#{' --non-parallel' if options[:non_parallel]}"
35
+ executable = File.expand_path('../../bin/parallel_test', __dir__)
36
+ non_parallel = (options[:non_parallel] ? ' --non-parallel' : '')
37
+ command = "#{ParallelTests.with_ruby_binary(Shellwords.escape(executable))} --exec '#{cmd}'#{count}#{non_parallel}"
27
38
  abort unless system(command)
28
39
  end
29
40
 
@@ -41,12 +52,12 @@ module ParallelTests
41
52
  # - simple system "set -o pipefail" returns nil even though set -o pipefail exists with 0
42
53
  def suppress_output(command, ignore_regex)
43
54
  activate_pipefail = "set -o pipefail"
44
- remove_ignored_lines = %Q{(grep -v "#{ignore_regex}" || test 1)}
55
+ remove_ignored_lines = %{(grep -v "#{ignore_regex}" || test 1)}
45
56
 
46
57
  if File.executable?('/bin/bash') && system('/bin/bash', '-c', "#{activate_pipefail} 2>/dev/null && test 1")
47
58
  # We need to shell escape single quotes (' becomes '"'"') because
48
59
  # run_in_parallel wraps command in single quotes
49
- %Q{/bin/bash -c '"'"'#{activate_pipefail} && (#{command}) | #{remove_ignored_lines}'"'"'}
60
+ %{/bin/bash -c '"'"'#{activate_pipefail} && (#{command}) | #{remove_ignored_lines}'"'"'}
50
61
  else
51
62
  command
52
63
  end
@@ -74,7 +85,7 @@ module ParallelTests
74
85
  # parallel:spec[2,models,options]
75
86
  # parallel:spec[,models,options]
76
87
  count = args.shift if args.first.to_s =~ /^\d*$/
77
- num_processes = count.to_i unless count.to_s.empty?
88
+ num_processes = (count.to_s.empty? ? nil : Integer(count))
78
89
  pattern = args.shift
79
90
  options = args.shift
80
91
  pass_through = args.shift
@@ -87,73 +98,104 @@ end
87
98
 
88
99
  namespace :parallel do
89
100
  desc "Setup test databases via db:setup --> parallel:setup[num_cpus]"
90
- task :setup, :count do |_,args|
91
- command = "rake db:setup RAILS_ENV=#{ParallelTests::Tasks.rails_env}"
101
+ task :setup, :count do |_, args|
102
+ command = "#{ParallelTests::Tasks.rake_bin} db:setup RAILS_ENV=#{ParallelTests::Tasks.rails_env}"
92
103
  ParallelTests::Tasks.run_in_parallel(ParallelTests::Tasks.suppress_schema_load_output(command), args)
93
104
  end
94
105
 
95
106
  desc "Create test databases via db:create --> parallel:create[num_cpus]"
96
- task :create, :count do |_,args|
97
- ParallelTests::Tasks.run_in_parallel("rake db:create RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
107
+ task :create, :count do |_, args|
108
+ ParallelTests::Tasks.run_in_parallel(
109
+ "#{ParallelTests::Tasks.rake_bin} db:create RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args
110
+ )
98
111
  end
99
112
 
100
113
  desc "Drop test databases via db:drop --> parallel:drop[num_cpus]"
101
- task :drop, :count do |_,args|
102
- ParallelTests::Tasks.run_in_parallel("rake db:drop RAILS_ENV=#{ParallelTests::Tasks.rails_env} DISABLE_DATABASE_ENVIRONMENT_CHECK=1", args)
114
+ task :drop, :count do |_, args|
115
+ ParallelTests::Tasks.run_in_parallel(
116
+ "#{ParallelTests::Tasks.rake_bin} db:drop RAILS_ENV=#{ParallelTests::Tasks.rails_env} " \
117
+ "DISABLE_DATABASE_ENVIRONMENT_CHECK=1", args
118
+ )
103
119
  end
104
120
 
105
121
  desc "Update test databases by dumping and loading --> parallel:prepare[num_cpus]"
106
- task(:prepare, [:count]) do |_,args|
122
+ task(:prepare, [:count]) do |_, args|
107
123
  ParallelTests::Tasks.check_for_pending_migrations
108
- if defined?(ActiveRecord) && ActiveRecord::Base.schema_format == :ruby
109
- # dump then load in parallel
110
- Rake::Task['db:schema:dump'].invoke
111
- Rake::Task['parallel:load_schema'].invoke(args[:count])
124
+ if defined?(ActiveRecord::Base) && [:ruby, :sql].include?(ActiveRecord::Base.schema_format)
125
+ # fast: dump once, load in parallel
126
+ type =
127
+ if Gem::Version.new(Rails.version) >= Gem::Version.new('6.1.0')
128
+ "schema"
129
+ else
130
+ ActiveRecord::Base.schema_format == :ruby ? "schema" : "structure"
131
+ end
132
+
133
+ Rake::Task["db:#{type}:dump"].invoke
134
+
135
+ # remove database connection to prevent "database is being accessed by other users"
136
+ ActiveRecord::Base.remove_connection if ActiveRecord::Base.configurations.any?
137
+
138
+ Rake::Task["parallel:load_#{type}"].invoke(args[:count])
112
139
  else
113
- # there is no separate dump / load for schema_format :sql -> do it safe and slow
114
- args = args.to_hash.merge(:non_parallel => true) # normal merge returns nil
115
- taskname = Rake::Task.task_defined?('db:test:prepare') ? 'db:test:prepare' : 'app:db:test:prepare'
116
- ParallelTests::Tasks.run_in_parallel("rake #{taskname}", args)
140
+ # slow: dump and load in in serial
141
+ args = args.to_hash.merge(non_parallel: true) # normal merge returns nil
142
+ task_name = Rake::Task.task_defined?('db:test:prepare') ? 'db:test:prepare' : 'app:db:test:prepare'
143
+ ParallelTests::Tasks.run_in_parallel("#{ParallelTests::Tasks.rake_bin} #{task_name}", args)
144
+ next
117
145
  end
118
146
  end
119
147
 
120
148
  # when dumping/resetting takes too long
121
149
  desc "Update test databases via db:migrate --> parallel:migrate[num_cpus]"
122
- task :migrate, :count do |_,args|
123
- ParallelTests::Tasks.run_in_parallel("rake db:migrate RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
150
+ task :migrate, :count do |_, args|
151
+ ParallelTests::Tasks.run_in_parallel(
152
+ "#{ParallelTests::Tasks.rake_bin} db:migrate RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args
153
+ )
124
154
  end
125
155
 
126
156
  desc "Rollback test databases via db:rollback --> parallel:rollback[num_cpus]"
127
- task :rollback, :count do |_,args|
128
- ParallelTests::Tasks.run_in_parallel("rake db:rollback RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
157
+ task :rollback, :count do |_, args|
158
+ ParallelTests::Tasks.run_in_parallel(
159
+ "#{ParallelTests::Tasks.rake_bin} db:rollback RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args
160
+ )
129
161
  end
130
162
 
131
163
  # just load the schema (good for integration server <-> no development db)
132
164
  desc "Load dumped schema for test databases via db:schema:load --> parallel:load_schema[num_cpus]"
133
- task :load_schema, :count do |_,args|
134
- command = "rake #{ParallelTests::Tasks.purge_before_load} db:schema:load RAILS_ENV=#{ParallelTests::Tasks.rails_env} DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
165
+ task :load_schema, :count do |_, args|
166
+ command = "#{ParallelTests::Tasks.rake_bin} #{ParallelTests::Tasks.purge_before_load} " \
167
+ "db:schema:load RAILS_ENV=#{ParallelTests::Tasks.rails_env} DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
135
168
  ParallelTests::Tasks.run_in_parallel(ParallelTests::Tasks.suppress_schema_load_output(command), args)
136
169
  end
137
170
 
138
171
  # load the structure from the structure.sql file
139
- desc "Load structure for test databases via db:structure:load --> parallel:load_structure[num_cpus]"
140
- task :load_structure, :count do |_,args|
141
- ParallelTests::Tasks.run_in_parallel("rake #{ParallelTests::Tasks.purge_before_load} db:structure:load RAILS_ENV=#{ParallelTests::Tasks.rails_env} DISABLE_DATABASE_ENVIRONMENT_CHECK=1", args)
172
+ # (faster for rails < 6.1, deprecated after and only configured by `ActiveRecord::Base.schema_format`)
173
+ desc "Load structure for test databases via db:schema:load --> parallel:load_structure[num_cpus]"
174
+ task :load_structure, :count do |_, args|
175
+ ParallelTests::Tasks.run_in_parallel(
176
+ "#{ParallelTests::Tasks.rake_bin} #{ParallelTests::Tasks.purge_before_load} " \
177
+ "db:structure:load RAILS_ENV=#{ParallelTests::Tasks.rails_env} DISABLE_DATABASE_ENVIRONMENT_CHECK=1", args
178
+ )
142
179
  end
143
180
 
144
181
  desc "Load the seed data from db/seeds.rb via db:seed --> parallel:seed[num_cpus]"
145
- task :seed, :count do |_,args|
146
- ParallelTests::Tasks.run_in_parallel("rake db:seed RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
182
+ task :seed, :count do |_, args|
183
+ ParallelTests::Tasks.run_in_parallel(
184
+ "#{ParallelTests::Tasks.rake_bin} db:seed RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args
185
+ )
147
186
  end
148
187
 
149
188
  desc "Launch given rake command in parallel"
150
189
  task :rake, :command, :count do |_, args|
151
- ParallelTests::Tasks.run_in_parallel("RAILS_ENV=#{ParallelTests::Tasks.rails_env} rake #{args.command}", args)
190
+ ParallelTests::Tasks.run_in_parallel(
191
+ "RAILS_ENV=#{ParallelTests::Tasks.rails_env} #{ParallelTests::Tasks.rake_bin} " \
192
+ "#{args.command}", args
193
+ )
152
194
  end
153
195
 
154
196
  ['test', 'spec', 'features', 'features-spinach'].each do |type|
155
197
  desc "Run #{type} in parallel with parallel:#{type}[num_cpus]"
156
- task type, [:count, :pattern, :options, :pass_through] do |t, args|
198
+ task type, [:count, :pattern, :options, :pass_through] do |_t, args|
157
199
  ParallelTests::Tasks.check_for_pending_migrations
158
200
  ParallelTests::Tasks.load_lib
159
201
 
@@ -162,16 +204,15 @@ namespace :parallel do
162
204
  'spec' => 'rspec',
163
205
  'test' => 'test',
164
206
  'features' => 'cucumber',
165
- 'features-spinach' => 'spinach',
207
+ 'features-spinach' => 'spinach'
166
208
  }[type]
167
209
 
168
- if test_framework == 'spinach'
169
- type = 'features'
170
- end
210
+ type = 'features' if test_framework == 'spinach'
171
211
  # Using the relative path to find the binary allow to run a specific version of it
172
212
  executable = File.join(File.dirname(__FILE__), '..', '..', 'bin', 'parallel_test')
173
213
 
174
- command = "#{ParallelTests.with_ruby_binary(Shellwords.escape(executable))} #{type} --type #{test_framework} " \
214
+ command = "#{ParallelTests.with_ruby_binary(Shellwords.escape(executable))} #{type} " \
215
+ "--type #{test_framework} " \
175
216
  "-n #{count} " \
176
217
  "--pattern '#{pattern}' " \
177
218
  "--test-options '#{options}' " \