parallel_tests 1.3.7 → 3.7.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,54 +1,26 @@
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
- if RSPEC_3
6
- RSpec::Core::Formatters.register self, :dump_failures, :dump_summary
7
- end
8
-
9
- # RSpec 1: does not keep track of failures, so we do
10
- def example_failed(example, *args)
11
- if RSPEC_1
12
- @failed_examples ||= []
13
- @failed_examples << example
14
- else
15
- super
16
- end
17
- end
18
-
19
- if RSPEC_1
20
- def dump_failure(*args)
21
- end
6
+ if RSPEC_2
7
+ def dump_failures(*args); end
22
8
  else
23
- def dump_failures(*args)
24
- end
9
+ RSpec::Core::Formatters.register self, :dump_summary
25
10
  end
26
11
 
27
12
  def dump_summary(*args)
28
13
  lock_output do
29
- if RSPEC_1
30
- dump_commands_to_rerun_failed_examples_rspec_1
31
- elsif RSPEC_3
14
+ if RSPEC_2
15
+ dump_commands_to_rerun_failed_examples
16
+ else
32
17
  notification = args.first
33
18
  unless notification.failed_examples.empty?
34
19
  colorizer = ::RSpec::Core::Formatters::ConsoleCodes
35
20
  output.puts notification.colorized_rerun_commands(colorizer)
36
21
  end
37
- else
38
- dump_commands_to_rerun_failed_examples
39
22
  end
40
23
  end
41
24
  @output.flush
42
25
  end
43
-
44
- private
45
-
46
- def dump_commands_to_rerun_failed_examples_rspec_1
47
- (@failed_examples||[]).each do |example|
48
- file, line = example.location.to_s.split(':')
49
- next unless file and line
50
- file.gsub!(%r(^.*?/spec/), './spec/')
51
- @output.puts "#{ParallelTests::RSpec::Runner.send(:executable)} #{file}:#{line} # #{example.description}"
52
- end
53
- end
54
26
  end
@@ -1,47 +1,40 @@
1
+ # frozen_string_literal: true
1
2
  module ParallelTests
2
3
  module RSpec
3
4
  end
4
5
  end
5
6
 
6
- begin
7
- require 'rspec/core/formatters/base_text_formatter'
8
- base = RSpec::Core::Formatters::BaseTextFormatter
9
- rescue LoadError
10
- require 'spec/runner/formatter/base_text_formatter'
11
- base = Spec::Runner::Formatter::BaseTextFormatter
12
- end
13
-
14
- ParallelTests::RSpec::LoggerBaseBase = base
7
+ require 'rspec/core/formatters/base_text_formatter'
15
8
 
16
- class ParallelTests::RSpec::LoggerBase < ParallelTests::RSpec::LoggerBaseBase
17
- RSPEC_1 = !defined?(RSpec::Core::Formatters::BaseTextFormatter) # do not test for Spec, this will trigger deprecation warning in rspec 2
18
- RSPEC_3 = !RSPEC_1 && RSpec::Core::Version::STRING.start_with?('3')
9
+ class ParallelTests::RSpec::LoggerBase < RSpec::Core::Formatters::BaseTextFormatter
10
+ RSPEC_2 = RSpec::Core::Version::STRING.start_with?('2')
19
11
 
20
12
  def initialize(*args)
21
13
  super
22
14
 
23
- @output ||= args[1] || args[0] # rspec 1 has output as second argument
15
+ @output ||= args[0]
24
16
 
25
- if String === @output # a path ?
17
+ case @output
18
+ when String # a path ?
26
19
  FileUtils.mkdir_p(File.dirname(@output))
27
- File.open(@output, 'w'){} # overwrite previous results
20
+ File.open(@output, 'w') {} # overwrite previous results
28
21
  @output = File.open(@output, 'a')
29
- elsif File === @output # close and restart in append mode
22
+ when File # close and restart in append mode
30
23
  @output.close
31
24
  @output = File.open(@output.path, 'a')
32
25
  end
33
26
  end
34
27
 
35
- #stolen from Rspec
36
- def close(*args)
37
- @output.close if (IO === @output) & (@output != $stdout)
28
+ # stolen from Rspec
29
+ def close(*)
30
+ @output.close if (IO === @output) & (@output != $stdout)
38
31
  end
39
32
 
40
33
  protected
41
34
 
42
35
  # do not let multiple processes get in each others way
43
36
  def lock_output
44
- if File === @output
37
+ if @output.is_a?(File)
45
38
  begin
46
39
  @output.flock File::LOCK_EX
47
40
  yield
@@ -1,38 +1,33 @@
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
12
- version = (exe =~ /\brspec\b/ ? 2 : 1)
13
- cmd = [exe, options[:test_options], (rspec_2_color if version == 2), spec_opts, *test_files].compact.join(" ")
14
- options = options.merge(:env => rspec_1_color) if version == 1
11
+ cmd = [exe, options[:test_options], color, spec_opts, *test_files].compact.join(" ")
15
12
  execute_command(cmd, process_number, num_processes, options)
16
13
  end
17
14
 
18
15
  def determine_executable
19
- cmd = case
20
- when File.exist?("bin/rspec")
21
- WINDOWS ? "ruby bin/rspec" : "bin/rspec"
22
- when File.file?("script/spec")
23
- "script/spec"
24
- when ParallelTests.bundler_enabled?
25
- cmd = (run("bundle show rspec-core") =~ %r{Could not find gem.*} ? "spec" : "rspec")
26
- "bundle exec #{cmd}"
16
+ if File.exist?("bin/rspec")
17
+ ParallelTests.with_ruby_binary("bin/rspec")
18
+ elsif ParallelTests.bundler_enabled?
19
+ "bundle exec rspec"
27
20
  else
28
- %w[spec rspec].detect{|cmd| system "#{cmd} --version > #{DEV_NULL} 2>&1" }
21
+ "rspec"
29
22
  end
30
-
31
- cmd or raise("Can't find executables rspec or spec")
32
23
  end
33
24
 
34
25
  def runtime_log
35
- 'tmp/parallel_runtime_rspec.log'
26
+ "tmp/parallel_runtime_rspec.log"
27
+ end
28
+
29
+ def default_test_folder
30
+ "spec"
36
31
  end
37
32
 
38
33
  def test_file_name
@@ -43,6 +38,37 @@ module ParallelTests
43
38
  /_spec\.rb$/
44
39
  end
45
40
 
41
+ def line_is_result?(line)
42
+ line =~ /\d+ examples?, \d+ failures?/
43
+ end
44
+
45
+ # remove old seed and add new seed
46
+ # --seed 1234
47
+ # --order rand
48
+ # --order rand:1234
49
+ # --order random:1234
50
+ def command_with_seed(cmd, seed)
51
+ clean = cmd.sub(/\s--(seed\s+\d+|order\s+rand(om)?(:\d+)?)\b/, '')
52
+ "#{clean} --seed #{seed}"
53
+ end
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
71
+
46
72
  private
47
73
 
48
74
  # so it can be stubbed....
@@ -50,20 +76,12 @@ module ParallelTests
50
76
  `#{cmd}`
51
77
  end
52
78
 
53
- def rspec_1_color
54
- if $stdout.tty?
55
- {'RSPEC_COLOR' => "1"}
56
- else
57
- {}
58
- end
59
- end
60
-
61
- def rspec_2_color
79
+ def color
62
80
  '--color --tty' if $stdout.tty?
63
81
  end
64
82
 
65
83
  def spec_opts
66
- 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) }
67
85
  return unless options_file
68
86
  "-O #{options_file}"
69
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
 
@@ -5,52 +6,39 @@ class ParallelTests::RSpec::RuntimeLogger < ParallelTests::RSpec::LoggerBase
5
6
  def initialize(*args)
6
7
  super
7
8
  @example_times = Hash.new(0)
8
- @group_nesting = 0 unless RSPEC_1
9
+ @group_nesting = 0
9
10
  end
10
11
 
11
- if RSPEC_3
12
- RSpec::Core::Formatters.register self, :example_group_started, :example_group_finished, :start_dump
12
+ RSpec::Core::Formatters.register self, :example_group_started, :example_group_finished, :start_dump unless RSPEC_2
13
+
14
+ def example_group_started(example_group)
15
+ @time = ParallelTests.now if @group_nesting == 0
16
+ @group_nesting += 1
17
+ super
13
18
  end
14
19
 
15
- if RSPEC_1
16
- def example_started(*args)
17
- @time = ParallelTests.now
18
- super
20
+ def example_group_finished(notification)
21
+ @group_nesting -= 1
22
+ if @group_nesting == 0
23
+ path = (RSPEC_2 ? notification.file_path : notification.group.file_path)
24
+ @example_times[path] += ParallelTests.now - @time
19
25
  end
26
+ super if defined?(super)
27
+ end
20
28
 
21
- def example_passed(example)
22
- file = example.location.split(':').first
23
- @example_times[file] += ParallelTests.now - @time
24
- super
25
- end
26
- else
27
- def example_group_started(example_group)
28
- @time = ParallelTests.now if @group_nesting == 0
29
- @group_nesting += 1
30
- super
31
- end
29
+ def dump_summary(*); end
32
30
 
33
- def example_group_finished(notification)
34
- @group_nesting -= 1
35
- if @group_nesting == 0
36
- path = (RSPEC_3 ? notification.group.file_path : notification.file_path)
37
- @example_times[path] += ParallelTests.now - @time
38
- end
39
- super if defined?(super)
40
- end
41
- end
31
+ def dump_failures(*); end
32
+
33
+ def dump_failure(*); end
42
34
 
43
- def dump_summary(*args);end
44
- def dump_failures(*args);end
45
- def dump_failure(*args);end
46
- def dump_pending(*args);end
35
+ def dump_pending(*); end
47
36
 
48
- def start_dump(*args)
49
- return unless ENV['TEST_ENV_NUMBER'] #only record when running in parallel
50
- # TODO: Figure out why sometimes time can be less than 0
37
+ def start_dump(*)
38
+ return unless ENV['TEST_ENV_NUMBER'] # only record when running in parallel
51
39
  lock_output do
52
40
  @example_times.each do |file, time|
53
- relative_path = file.sub(/^#{Regexp.escape Dir.pwd}\//,'').sub(/^\.\//, "")
41
+ relative_path = file.sub(%r{^#{Regexp.escape Dir.pwd}/}, '').sub(%r{^\./}, "")
54
42
  @output.puts "#{relative_path}:#{time > 0 ? time : 0}"
55
43
  end
56
44
  end
@@ -1,19 +1,11 @@
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
- if RSPEC_3
5
- RSpec::Core::Formatters.register self, :dump_failures
6
- end
5
+ RSpec::Core::Formatters.register self, :dump_failures unless RSPEC_2
7
6
 
8
- if RSPEC_1
9
- def dump_failure(*args)
10
- lock_output { super }
11
- @output.flush
12
- end
13
- else
14
- def dump_failures(*args)
15
- lock_output { super }
16
- @output.flush
17
- end
7
+ def dump_failures(*args)
8
+ lock_output { super }
9
+ @output.flush
18
10
  end
19
11
  end
@@ -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,21 +1,45 @@
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'
8
10
  end
9
11
 
10
- def run_in_parallel(cmd, options={})
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"
18
+ end
19
+
20
+ def load_lib
21
+ $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..'))
22
+ require "parallel_tests"
23
+ end
24
+
25
+ def purge_before_load
26
+ if Gem::Version.new(Rails.version) > Gem::Version.new('4.2.0')
27
+ Rake::Task.task_defined?('db:purge') ? 'db:purge' : 'app:db:purge'
28
+ end
29
+ end
30
+
31
+ def run_in_parallel(cmd, options = {})
32
+ load_lib
11
33
  count = " -n #{options[:count]}" unless options[:count].to_s.empty?
12
- executable = File.expand_path("../../../bin/parallel_test", __FILE__)
13
- command = "#{executable} --exec '#{cmd}'#{count}#{' --non-parallel' if options[:non_parallel]}"
34
+ # Using the relative path to find the binary allow to run a specific version of it
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}"
14
38
  abort unless system(command)
15
39
  end
16
40
 
17
41
  # this is a crazy-complex solution for a very simple problem:
18
- # removing certain lines from the output without chaning the exit-status
42
+ # removing certain lines from the output without changing the exit-status
19
43
  # normally I'd not do this, but it has been lots of fun and a great learning experience :)
20
44
  #
21
45
  # - sed does not support | without -r
@@ -28,17 +52,21 @@ module ParallelTests
28
52
  # - simple system "set -o pipefail" returns nil even though set -o pipefail exists with 0
29
53
  def suppress_output(command, ignore_regex)
30
54
  activate_pipefail = "set -o pipefail"
31
- remove_ignored_lines = %Q{(grep -v "#{ignore_regex}" || test 1)}
55
+ remove_ignored_lines = %{(grep -v "#{ignore_regex}" || test 1)}
32
56
 
33
57
  if File.executable?('/bin/bash') && system('/bin/bash', '-c', "#{activate_pipefail} 2>/dev/null && test 1")
34
58
  # We need to shell escape single quotes (' becomes '"'"') because
35
59
  # run_in_parallel wraps command in single quotes
36
- %Q{/bin/bash -c '"'"'#{activate_pipefail} && (#{command}) | #{remove_ignored_lines}'"'"'}
60
+ %{/bin/bash -c '"'"'#{activate_pipefail} && (#{command}) | #{remove_ignored_lines}'"'"'}
37
61
  else
38
62
  command
39
63
  end
40
64
  end
41
65
 
66
+ def suppress_schema_load_output(command)
67
+ ParallelTests::Tasks.suppress_output(command, "^ ->\\|^-- ")
68
+ end
69
+
42
70
  def check_for_pending_migrations
43
71
  ["db:abort_if_pending_migrations", "app:db:abort_if_pending_migrations"].each do |abort_migrations|
44
72
  if Rake::Task.task_defined?(abort_migrations)
@@ -48,109 +76,147 @@ module ParallelTests
48
76
  end
49
77
  end
50
78
 
51
- # parallel:spec[:count, :pattern, :options]
79
+ # parallel:spec[:count, :pattern, :options, :pass_through]
52
80
  def parse_args(args)
53
81
  # order as given by user
54
- args = [args[:count], args[:pattern], args[:options]]
82
+ args = [args[:count], args[:pattern], args[:options], args[:pass_through]]
55
83
 
56
84
  # count given or empty ?
57
85
  # parallel:spec[2,models,options]
58
86
  # parallel:spec[,models,options]
59
87
  count = args.shift if args.first.to_s =~ /^\d*$/
60
- num_processes = count.to_i unless count.to_s.empty?
88
+ num_processes = (count.to_s.empty? ? nil : Integer(count))
61
89
  pattern = args.shift
62
90
  options = args.shift
91
+ pass_through = args.shift
63
92
 
64
- [num_processes, pattern.to_s, options.to_s]
93
+ [num_processes, pattern.to_s, options.to_s, pass_through.to_s]
65
94
  end
66
95
  end
67
96
  end
68
97
  end
69
98
 
70
99
  namespace :parallel do
71
- desc "create test databases via db:create --> parallel:create[num_cpus]"
72
- task :create, :count do |t,args|
73
- ParallelTests::Tasks.run_in_parallel("rake db:create RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
100
+ desc "Setup test databases via db:setup --> parallel:setup[num_cpus]"
101
+ task :setup, :count do |_, args|
102
+ command = "#{ParallelTests::Tasks.rake_bin} db:setup RAILS_ENV=#{ParallelTests::Tasks.rails_env}"
103
+ ParallelTests::Tasks.run_in_parallel(ParallelTests::Tasks.suppress_schema_load_output(command), args)
104
+ end
105
+
106
+ desc "Create test databases via db:create --> parallel:create[num_cpus]"
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
+ )
74
111
  end
75
112
 
76
- desc "drop test databases via db:drop --> parallel:drop[num_cpus]"
77
- task :drop, :count do |t,args|
78
- ParallelTests::Tasks.run_in_parallel("rake db:drop RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
113
+ desc "Drop test databases via db:drop --> parallel:drop[num_cpus]"
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
+ )
79
119
  end
80
120
 
81
- desc "update test databases by dumping and loading --> parallel:prepare[num_cpus]"
82
- task(:prepare, [:count]) do |t,args|
121
+ desc "Update test databases by dumping and loading --> parallel:prepare[num_cpus]"
122
+ task(:prepare, [:count]) do |_, args|
83
123
  ParallelTests::Tasks.check_for_pending_migrations
84
- if defined?(ActiveRecord) && ActiveRecord::Base.schema_format == :ruby
85
- # dump then load in parallel
86
- Rake::Task['db:schema:dump'].invoke
87
- 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])
88
139
  else
89
- # there is no separate dump / load for schema_format :sql -> do it safe and slow
90
- args = args.to_hash.merge(:non_parallel => true) # normal merge returns nil
91
- taskname = Rake::Task.task_defined?('db:test:prepare') ? 'db:test:prepare' : 'app:db:test:prepare'
92
- 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
93
145
  end
94
146
  end
95
147
 
96
148
  # when dumping/resetting takes too long
97
- desc "update test databases via db:migrate --> parallel:migrate[num_cpus]"
98
- task :migrate, :count do |t,args|
99
- ParallelTests::Tasks.run_in_parallel("rake db:migrate RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
149
+ desc "Update test databases via db:migrate --> parallel:migrate[num_cpus]"
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
+ )
154
+ end
155
+
156
+ desc "Rollback test databases via db:rollback --> parallel:rollback[num_cpus]"
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
+ )
100
161
  end
101
162
 
102
163
  # just load the schema (good for integration server <-> no development db)
103
- desc "load dumped schema for test databases via db:schema:load --> parallel:load_schema[num_cpus]"
104
- task :load_schema, :count do |t,args|
105
- command = "rake db:schema:load RAILS_ENV=#{ParallelTests::Tasks.rails_env}"
106
- ParallelTests::Tasks.run_in_parallel(ParallelTests::Tasks.suppress_output(command, "^ ->\\|^-- "), args)
164
+ desc "Load dumped schema for test databases via db:schema:load --> parallel:load_schema[num_cpus]"
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"
168
+ ParallelTests::Tasks.run_in_parallel(ParallelTests::Tasks.suppress_schema_load_output(command), args)
107
169
  end
108
170
 
109
171
  # load the structure from the structure.sql file
110
- desc "load structure for test databases via db:structure:load --> parallel:load_structure[num_cpus]"
111
- task :load_structure, :count do |t,args|
112
- ParallelTests::Tasks.run_in_parallel("rake db:structure:load RAILS_ENV=#{ParallelTests::Tasks.rails_env}", 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
+ )
113
179
  end
114
180
 
115
- desc "load the seed data from db/seeds.rb via db:seed --> parallel:seed[num_cpus]"
116
- task :seed, :count do |t,args|
117
- ParallelTests::Tasks.run_in_parallel("rake db:seed RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
181
+ desc "Load the seed data from db/seeds.rb via db:seed --> parallel:seed[num_cpus]"
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
+ )
118
186
  end
119
187
 
120
- desc "launch given rake command in parallel"
121
- task :rake, :command do |t, args|
122
- ParallelTests::Tasks.run_in_parallel("RAILS_ENV=#{ParallelTests::Tasks.rails_env} rake #{args.command}")
188
+ desc "Launch given rake command in parallel"
189
+ task :rake, :command, :count do |_, args|
190
+ ParallelTests::Tasks.run_in_parallel(
191
+ "RAILS_ENV=#{ParallelTests::Tasks.rails_env} #{ParallelTests::Tasks.rake_bin} " \
192
+ "#{args.command}", args
193
+ )
123
194
  end
124
195
 
125
196
  ['test', 'spec', 'features', 'features-spinach'].each do |type|
126
- desc "run #{type} in parallel with parallel:#{type}[num_cpus]"
127
- task type, [:count, :pattern, :options] do |t, args|
197
+ desc "Run #{type} in parallel with parallel:#{type}[num_cpus]"
198
+ task type, [:count, :pattern, :options, :pass_through] do |_t, args|
128
199
  ParallelTests::Tasks.check_for_pending_migrations
200
+ ParallelTests::Tasks.load_lib
129
201
 
130
- $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..'))
131
- require "parallel_tests"
132
-
133
- count, pattern, options = ParallelTests::Tasks.parse_args(args)
202
+ count, pattern, options, pass_through = ParallelTests::Tasks.parse_args(args)
134
203
  test_framework = {
135
204
  'spec' => 'rspec',
136
205
  'test' => 'test',
137
206
  'features' => 'cucumber',
138
- 'features-spinach' => 'spinach',
207
+ 'features-spinach' => 'spinach'
139
208
  }[type]
140
209
 
141
- if test_framework == 'spinach'
142
- type = 'features'
143
- end
210
+ type = 'features' if test_framework == 'spinach'
211
+ # Using the relative path to find the binary allow to run a specific version of it
144
212
  executable = File.join(File.dirname(__FILE__), '..', '..', 'bin', 'parallel_test')
145
213
 
146
- command = "#{executable} #{type} --type #{test_framework} " \
214
+ command = "#{ParallelTests.with_ruby_binary(Shellwords.escape(executable))} #{type} " \
215
+ "--type #{test_framework} " \
147
216
  "-n #{count} " \
148
217
  "--pattern '#{pattern}' " \
149
- "--test-options '#{options}'"
150
- if ParallelTests::WINDOWS
151
- ruby_binary = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
152
- command = "#{ruby_binary} #{command}"
153
- end
218
+ "--test-options '#{options}' " \
219
+ "#{pass_through}"
154
220
  abort unless system(command) # allow to chain tasks e.g. rake parallel:spec parallel:features
155
221
  end
156
222
  end