parallel_tests 2.29.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 68ba592f56ce42eab34cf1c1691bfde23de8ded652d9b171880bdadb1573a92e
4
- data.tar.gz: f5438fa50a6e072b0074dc25724e9533912f120bc8d8537ccd76fd83e15988ec
3
+ metadata.gz: 0c8f92fb8fb19ff4348080358222c4984bcc5721ddd4779433ad4b8beead46a0
4
+ data.tar.gz: e3fb4beed5a5391401e8fcd729a5308c274ac2ddc61b3cd548e655a25009ba5d
5
5
  SHA512:
6
- metadata.gz: bc8d70e18409b6dc5d67065e0854f9873c63c8097d64f8d81237e896a9878e614c1eed741a4f2235f85553af42745509d7d4b7f3a4c044b8f057aef1bcddd0d7
7
- data.tar.gz: 4626db276c737f3daee5b37837bdee6466791ec440c267a6781eb1341d52db8afba19e56e2c8c212cbe58d994d47a88a53d534645313bd717a7e3f88878b5f7a
6
+ metadata.gz: bff5dfd53ba1acc4bb654d17f49d9d9deb1c86eff894232fc698dd3100fd2fbb7dd15ad11c1ebdc501438003ce62b2f65a7befcbc970e15d2b3e340f47ebf928
7
+ data.tar.gz: a5ded77e36a14a8bebea03777666e6de95f787edaf79dcf27b8d99d91c69b4779cb43e5ba5daf13f7940b2b262ad49eede907e8c9482749e30e2b272cf965245
data/Readme.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/parallel_tests.svg)](https://rubygems.org/gems/parallel_tests)
4
4
  [![Build Status](https://travis-ci.org/grosser/parallel_tests.svg)](https://travis-ci.org/grosser/parallel_tests/builds)
5
- [![Build status](https://ci.appveyor.com/api/projects/status/708b1up4pqc34x3y?svg=true)](https://ci.appveyor.com/project/grosser/parallel-tests)
5
+ [![Build status](https://github.com/grosser/parallel_tests/workflows/windows/badge.svg)](https://github.com/grosser/parallel_tests/actions?query=workflow%3Awindows)
6
6
 
7
7
  Speedup Test::Unit + RSpec + Cucumber + Spinach by running parallel on multiple CPU cores.<br/>
8
8
  ParallelTests splits tests into even groups (by number of lines or runtime) and runs each group in a single process with its own database.
@@ -256,7 +256,8 @@ TIPS
256
256
  - Instantly see failures (instead of just a red F) with [rspec-instafail](https://github.com/grosser/rspec-instafail)
257
257
  - Use [rspec-retry](https://github.com/NoRedInk/rspec-retry) (not rspec-rerun) to rerun failed tests.
258
258
  - [JUnit formatter configuration](https://github.com/grosser/parallel_tests/wiki#with-rspec_junit_formatter----by-jgarber)
259
-
259
+ - Use [parallel_split_test](https://github.com/grosser/parallel_split_test) to run multiple scenarios in a single spec file, concurrently. (`parallel_tests` [works at the file-level and intends to stay that way](https://github.com/grosser/parallel_tests/issues/747#issuecomment-580216980))
260
+
260
261
  ### Cucumber
261
262
 
262
263
  - Add a `parallel: foo` profile to your `config/cucumber.yml` and it will be used to run parallel tests
@@ -266,14 +267,13 @@ TIPS
266
267
  - Builds a HTML report from JSON with support for debug msgs & embedded Base64 images.
267
268
 
268
269
  ### General
269
- - [SQL schema format] use :ruby schema format to get faster parallel:prepare`
270
270
  - [ZSH] use quotes to use rake arguments `rake "parallel:prepare[3]"`
271
271
  - [Memcached] use different namespaces<br/>
272
272
  e.g. `config.cache_store = ..., namespace: "test_#{ENV['TEST_ENV_NUMBER']}"`
273
273
  - Debug errors that only happen with multiple files using `--verbose` and [cleanser](https://github.com/grosser/cleanser)
274
274
  - `export PARALLEL_TEST_PROCESSORS=13` to override default processor count
275
275
  - Shell alias: `alias prspec='parallel_rspec -m 2 --'`
276
- - [Spring] to use spring you have to [patch it](https://github.com/grosser/parallel_tests/wiki/Spring)
276
+ - [Spring] Add the [spring-commands-parallel-tests](https://github.com/DocSpring/spring-commands-parallel-tests) gem to your `Gemfile` to get `parallel_tests` working with Spring.
277
277
  - `--first-is-1` will make the first environment be `1`, so you can test while running your full suite.<br/>
278
278
  `export PARALLEL_TEST_FIRST_IS_1=true` will provide the same result
279
279
  - [email_spec and/or action_mailer_cache_delivery](https://github.com/grosser/parallel_tests/wiki)
@@ -373,6 +373,7 @@ inspired by [pivotal labs](https://blog.pivotal.io/labs/labs/parallelize-your-rs
373
373
  - [Sandeep Singh](https://github.com/sandeepnagra)
374
374
  - [Calaway](https://github.com/calaway)
375
375
  - [alboyadjian](https://github.com/alboyadjian)
376
+ - [Nathan Broadbent](https://github.com/ndbroadbent)
376
377
 
377
378
  [Michael Grosser](http://grosser.it)<br/>
378
379
  michael@grosser.it<br/>
@@ -2,6 +2,7 @@ require 'optparse'
2
2
  require 'tempfile'
3
3
  require 'parallel_tests'
4
4
  require 'shellwords'
5
+ require 'pathname'
5
6
 
6
7
  module ParallelTests
7
8
  class CLI
@@ -239,7 +240,7 @@ module ParallelTests
239
240
  files, remaining = extract_file_paths(argv)
240
241
  unless options[:execute]
241
242
  abort "Pass files or folders to run" unless files.any?
242
- options[:files] = files
243
+ options[:files] = files.map { |file_path| Pathname.new(file_path).cleanpath.to_s }
243
244
  end
244
245
 
245
246
  append_test_options(options, remaining)
@@ -315,9 +316,8 @@ module ParallelTests
315
316
  end
316
317
 
317
318
  def final_fail_message
318
- fail_message = "#{@runner.name}s Failed"
319
+ fail_message = "Tests Failed"
319
320
  fail_message = "\e[31m#{fail_message}\e[0m" if use_colors?
320
-
321
321
  fail_message
322
322
  end
323
323
 
@@ -0,0 +1,31 @@
1
+ begin
2
+ gem "cuke_modeler", "~> 3.0"
3
+ require 'cuke_modeler'
4
+ rescue LoadError
5
+ raise 'Grouping by number of cucumber steps requires the `cuke_modeler` modeler gem with requirement `~> 3.0`. Add `gem "cuke_modeler", "~> 3.0"` to your `Gemfile`, run `bundle install` and try again.'
6
+ end
7
+
8
+ module ParallelTests
9
+ module Cucumber
10
+ class FeaturesWithSteps
11
+ class << self
12
+ def all(tests, options)
13
+ ignore_tag_pattern = options[:ignore_tag_pattern].nil? ? nil : Regexp.compile(options[:ignore_tag_pattern])
14
+ # format of hash will be FILENAME => NUM_STEPS
15
+ steps_per_file = tests.each_with_object({}) do |file,steps|
16
+ feature = ::CukeModeler::FeatureFile.new(file).feature
17
+
18
+ # skip feature if it matches tag regex
19
+ next if feature.tags.grep(ignore_tag_pattern).any?
20
+
21
+ # count the number of steps in the file
22
+ # will only include a feature if the regex does not match
23
+ all_steps = feature.scenarios.map{|a| a.steps.count if a.tags.grep(ignore_tag_pattern).empty? }.compact
24
+ steps[file] = all_steps.inject(0,:+)
25
+ end
26
+ steps_per_file.sort_by { |_, value| -value }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,37 +1,33 @@
1
- require 'cucumber/tag_expressions/parser'
2
- require 'cucumber/core/gherkin/tag_expression'
3
-
4
1
  module ParallelTests
5
2
  module Cucumber
6
3
  module Formatters
7
4
  class ScenarioLineLogger
8
5
  attr_reader :scenarios
9
6
 
10
- def initialize(tag_expression = ::Cucumber::Core::Gherkin::TagExpression.new([]))
7
+ def initialize(tag_expression = nil)
11
8
  @scenarios = []
12
9
  @tag_expression = tag_expression
13
10
  end
14
11
 
15
12
  def visit_feature_element(uri, feature_element, feature_tags, line_numbers: [])
16
- scenario_tags = feature_element[:tags].map { |tag| tag[:name] }
13
+ scenario_tags = feature_element.tags.map { |tag| tag.name }
17
14
  scenario_tags = feature_tags + scenario_tags
18
- if feature_element[:examples].nil? # :Scenario
19
- test_line = feature_element[:location][:line]
15
+ if feature_element.is_a?(CukeModeler::Scenario) # :Scenario
16
+ test_line = feature_element.source_line
20
17
 
21
18
  # We don't accept the feature_element if the current tags are not valid
22
- return unless @tag_expression.evaluate(scenario_tags)
19
+ return unless matches_tags?(scenario_tags)
23
20
  # or if it is not at the correct location
24
21
  return if line_numbers.any? && !line_numbers.include?(test_line)
25
22
 
26
- @scenarios << [uri, feature_element[:location][:line]].join(":")
23
+ @scenarios << [uri, feature_element.source_line].join(":")
27
24
  else # :ScenarioOutline
28
- feature_element[:examples].each do |example|
29
- example_tags = example[:tags].map { |tag| tag[:name] }
25
+ feature_element.examples.each do |example|
26
+ example_tags = example.tags.map(&:name)
30
27
  example_tags = scenario_tags + example_tags
31
- next unless @tag_expression.evaluate(example_tags)
32
- rows = example[:tableBody].select { |body| body[:type] == :TableRow }
33
- rows.each do |row|
34
- test_line = row[:location][:line]
28
+ next unless matches_tags?(example_tags)
29
+ example.rows[1..-1].each do |row|
30
+ test_line = row.source_line
35
31
  next if line_numbers.any? && !line_numbers.include?(test_line)
36
32
 
37
33
  @scenarios << [uri, test_line].join(':')
@@ -42,6 +38,12 @@ module ParallelTests
42
38
 
43
39
  def method_missing(*args)
44
40
  end
41
+
42
+ private
43
+
44
+ def matches_tags?(tags)
45
+ @tag_expression.nil? || @tag_expression.evaluate(tags)
46
+ end
45
47
  end
46
48
  end
47
49
  end
@@ -1,12 +1,17 @@
1
1
  require 'cucumber/tag_expressions/parser'
2
- require 'cucumber/core/gherkin/tag_expression'
3
2
  require 'cucumber/runtime'
4
3
  require 'cucumber'
5
4
  require 'parallel_tests/cucumber/scenario_line_logger'
6
5
  require 'parallel_tests/gherkin/listener'
7
- require 'gherkin/errors'
8
6
  require 'shellwords'
9
7
 
8
+ begin
9
+ gem "cuke_modeler", "~> 3.0"
10
+ require 'cuke_modeler'
11
+ rescue LoadError
12
+ raise 'Grouping by individual cucumber scenarios requires the `cuke_modeler` modeler gem with requirement `~> 3.0`. Add `gem "cuke_modeler", "~> 3.0"` to your `Gemfile`, run `bundle install` and try again.'
13
+ end
14
+
10
15
  module ParallelTests
11
16
  module Cucumber
12
17
  class Scenarios
@@ -40,32 +45,17 @@ module ParallelTests
40
45
  path, *test_lines = path.split(/:(?=\d+)/)
41
46
  test_lines.map!(&:to_i)
42
47
 
43
- # We encode the file and get the content of it
44
- source = ::Cucumber::Runtime::NormalisedEncodingFile.read(path)
45
48
  # We create a Gherkin document, this will be used to decode the details of each scenario
46
- document = ::Cucumber::Core::Gherkin::Document.new(path, source)
47
-
48
- # We create a parser for the gherkin document
49
- parser = ::Gherkin::Parser.new()
50
- scanner = ::Gherkin::TokenScanner.new(document.body)
51
-
52
- begin
53
- # We make an attempt to parse the gherkin document, this could be failed if the document is not well formatted
54
- result = parser.parse(scanner)
55
- feature_tags = result[:feature][:tags].map { |tag| tag[:name] }
56
-
57
- # We loop on each children of the feature
58
- result[:feature][:children].each do |feature_element|
59
- # If the type of the child is not a scenario or scenario outline, we continue, we are only interested by the name of the scenario here
60
- next unless /Scenario/.match(feature_element[:type])
49
+ document = ::CukeModeler::FeatureFile.new(path)
50
+ feature = document.feature
61
51
 
62
- # It's a scenario, we add it to the scenario_line_logger
63
- scenario_line_logger.visit_feature_element(document.uri, feature_element, feature_tags, line_numbers: test_lines)
64
- end
52
+ # We make an attempt to parse the gherkin document, this could be failed if the document is not well formatted
53
+ feature_tags = feature.tags.map(&:name)
65
54
 
66
- rescue StandardError => e
67
- # Exception if the document is no well formated or error in the tags
68
- raise ::Cucumber::Core::Gherkin::ParseError.new("#{document.uri}: #{e.message}")
55
+ # We loop on each children of the feature
56
+ feature.tests.each do |test|
57
+ # It's a scenario, we add it to the scenario_line_logger
58
+ scenario_line_logger.visit_feature_element(document.path, test, feature_tags, line_numbers: test_lines)
69
59
  end
70
60
  end
71
61
 
@@ -1,5 +1,3 @@
1
- require 'gherkin/parser'
2
-
3
1
  module ParallelTests
4
2
  module Gherkin
5
3
  class Listener
@@ -14,7 +14,7 @@ module ParallelTests
14
14
  end
15
15
 
16
16
  config.on_event :test_case_finished do |event|
17
- @example_times[event.test_case.feature.file] += ParallelTests.now.to_f - @start_at
17
+ @example_times[event.test_case.location.file] += ParallelTests.now.to_f - @start_at
18
18
  end
19
19
 
20
20
  config.on_event :test_run_finished do |_|
@@ -2,7 +2,7 @@ module ParallelTests
2
2
  class Grouper
3
3
  class << self
4
4
  def by_steps(tests, num_groups, options)
5
- features_with_steps = build_features_with_steps(tests, options)
5
+ features_with_steps = group_by_features_with_steps(tests, options)
6
6
  in_even_groups_by_size(features_with_steps, num_groups)
7
7
  end
8
8
 
@@ -41,23 +41,9 @@ module ParallelTests
41
41
  group[:size] += size
42
42
  end
43
43
 
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 }
44
+ def group_by_features_with_steps(tests, options)
45
+ require 'parallel_tests/cucumber/features_with_steps'
46
+ ParallelTests::Cucumber::FeaturesWithSteps.all(tests, options)
61
47
  end
62
48
 
63
49
  def group_by_scenarios(tests, options={})
@@ -4,8 +4,6 @@ module ParallelTests
4
4
  module RSpec
5
5
  class Runner < ParallelTests::Test::Runner
6
6
  DEV_NULL = (WINDOWS ? "NUL" : "/dev/null")
7
- NAME = 'RSpec'
8
-
9
7
  class << self
10
8
  def run_tests(test_files, process_number, num_processes, options)
11
9
  exe = executable # expensive, so we cache
@@ -14,17 +12,14 @@ module ParallelTests
14
12
  end
15
13
 
16
14
  def determine_executable
17
- cmd = case
15
+ case
18
16
  when File.exist?("bin/rspec")
19
17
  ParallelTests.with_ruby_binary("bin/rspec")
20
18
  when ParallelTests.bundler_enabled?
21
- cmd = (run("bundle show rspec-core") =~ %r{Could not find gem.*} ? "spec" : "rspec")
22
- "bundle exec #{cmd}"
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
@@ -8,6 +8,14 @@ module ParallelTests
8
8
  ENV['RAILS_ENV'] || 'test'
9
9
  end
10
10
 
11
+ def rake_bin
12
+ # Prevent 'Exec format error' Errno::ENOEXEC on Windows
13
+ return "rake" if RUBY_PLATFORM =~ /mswin|mingw|cygwin/
14
+ binstub_path = File.join('bin', 'rake')
15
+ return binstub_path if File.exist?(binstub_path)
16
+ "rake"
17
+ end
18
+
11
19
  def load_lib
12
20
  $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..'))
13
21
  require "parallel_tests"
@@ -89,67 +97,84 @@ end
89
97
  namespace :parallel do
90
98
  desc "Setup test databases via db:setup --> parallel:setup[num_cpus]"
91
99
  task :setup, :count do |_,args|
92
- command = "rake db:setup RAILS_ENV=#{ParallelTests::Tasks.rails_env}"
100
+ command = "#{ParallelTests::Tasks.rake_bin} db:setup RAILS_ENV=#{ParallelTests::Tasks.rails_env}"
93
101
  ParallelTests::Tasks.run_in_parallel(ParallelTests::Tasks.suppress_schema_load_output(command), args)
94
102
  end
95
103
 
96
104
  desc "Create test databases via db:create --> parallel:create[num_cpus]"
97
105
  task :create, :count do |_,args|
98
- ParallelTests::Tasks.run_in_parallel("rake db:create RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
106
+ ParallelTests::Tasks.run_in_parallel(
107
+ "#{ParallelTests::Tasks.rake_bin} db:create RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
99
108
  end
100
109
 
101
110
  desc "Drop test databases via db:drop --> parallel:drop[num_cpus]"
102
111
  task :drop, :count do |_,args|
103
- ParallelTests::Tasks.run_in_parallel("rake db:drop RAILS_ENV=#{ParallelTests::Tasks.rails_env} DISABLE_DATABASE_ENVIRONMENT_CHECK=1", args)
112
+ ParallelTests::Tasks.run_in_parallel(
113
+ "#{ParallelTests::Tasks.rake_bin} db:drop RAILS_ENV=#{ParallelTests::Tasks.rails_env} " \
114
+ "DISABLE_DATABASE_ENVIRONMENT_CHECK=1", args)
104
115
  end
105
116
 
106
117
  desc "Update test databases by dumping and loading --> parallel:prepare[num_cpus]"
107
118
  task(:prepare, [:count]) do |_,args|
108
119
  ParallelTests::Tasks.check_for_pending_migrations
109
- if defined?(ActiveRecord) && ActiveRecord::Base.schema_format == :ruby
110
- # dump then load in parallel
111
- Rake::Task['db:schema:dump'].invoke
112
- Rake::Task['parallel:load_schema'].invoke(args[:count])
120
+ if defined?(ActiveRecord::Base) && [:ruby, :sql].include?(ActiveRecord::Base.schema_format)
121
+ # fast: dump once, load in parallel
122
+ type = (ActiveRecord::Base.schema_format == :ruby ? "schema" : "structure")
123
+ Rake::Task["db:#{type}:dump"].invoke
124
+
125
+ # remove database connection to prevent "database is being accessed by other users"
126
+ ActiveRecord::Base.remove_connection if ActiveRecord::Base.configurations.any?
127
+
128
+ Rake::Task["parallel:load_#{type}"].invoke(args[:count])
113
129
  else
114
- # there is no separate dump / load for schema_format :sql -> do it safe and slow
130
+ # slow: dump and load in in serial
115
131
  args = args.to_hash.merge(:non_parallel => true) # normal merge returns nil
116
- taskname = Rake::Task.task_defined?('db:test:prepare') ? 'db:test:prepare' : 'app:db:test:prepare'
117
- ParallelTests::Tasks.run_in_parallel("rake #{taskname}", args)
132
+ task_name = Rake::Task.task_defined?('db:test:prepare') ? 'db:test:prepare' : 'app:db:test:prepare'
133
+ ParallelTests::Tasks.run_in_parallel("#{ParallelTests::Tasks.rake_bin} #{task_name}", args)
134
+ next
118
135
  end
119
136
  end
120
137
 
121
138
  # when dumping/resetting takes too long
122
139
  desc "Update test databases via db:migrate --> parallel:migrate[num_cpus]"
123
140
  task :migrate, :count do |_,args|
124
- ParallelTests::Tasks.run_in_parallel("rake db:migrate RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
141
+ ParallelTests::Tasks.run_in_parallel(
142
+ "#{ParallelTests::Tasks.rake_bin} db:migrate RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
125
143
  end
126
144
 
127
145
  desc "Rollback test databases via db:rollback --> parallel:rollback[num_cpus]"
128
146
  task :rollback, :count do |_,args|
129
- ParallelTests::Tasks.run_in_parallel("rake db:rollback RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
147
+ ParallelTests::Tasks.run_in_parallel(
148
+ "#{ParallelTests::Tasks.rake_bin} db:rollback RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
130
149
  end
131
150
 
132
151
  # just load the schema (good for integration server <-> no development db)
133
152
  desc "Load dumped schema for test databases via db:schema:load --> parallel:load_schema[num_cpus]"
134
153
  task :load_schema, :count do |_,args|
135
- command = "rake #{ParallelTests::Tasks.purge_before_load} db:schema:load RAILS_ENV=#{ParallelTests::Tasks.rails_env} DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
154
+ command = "#{ParallelTests::Tasks.rake_bin} #{ParallelTests::Tasks.purge_before_load} " \
155
+ "db:schema:load RAILS_ENV=#{ParallelTests::Tasks.rails_env} DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
136
156
  ParallelTests::Tasks.run_in_parallel(ParallelTests::Tasks.suppress_schema_load_output(command), args)
137
157
  end
138
158
 
139
159
  # load the structure from the structure.sql file
140
160
  desc "Load structure for test databases via db:structure:load --> parallel:load_structure[num_cpus]"
141
161
  task :load_structure, :count do |_,args|
142
- 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)
162
+ ParallelTests::Tasks.run_in_parallel(
163
+ "#{ParallelTests::Tasks.rake_bin} #{ParallelTests::Tasks.purge_before_load} " \
164
+ "db:structure:load RAILS_ENV=#{ParallelTests::Tasks.rails_env} DISABLE_DATABASE_ENVIRONMENT_CHECK=1", args)
143
165
  end
144
166
 
145
167
  desc "Load the seed data from db/seeds.rb via db:seed --> parallel:seed[num_cpus]"
146
168
  task :seed, :count do |_,args|
147
- ParallelTests::Tasks.run_in_parallel("rake db:seed RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
169
+ ParallelTests::Tasks.run_in_parallel(
170
+ "#{ParallelTests::Tasks.rake_bin} db:seed RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
148
171
  end
149
172
 
150
173
  desc "Launch given rake command in parallel"
151
174
  task :rake, :command, :count do |_, args|
152
- ParallelTests::Tasks.run_in_parallel("RAILS_ENV=#{ParallelTests::Tasks.rails_env} rake #{args.command}", args)
175
+ ParallelTests::Tasks.run_in_parallel(
176
+ "RAILS_ENV=#{ParallelTests::Tasks.rails_env} #{ParallelTests::Tasks.rake_bin} " \
177
+ "#{args.command}", args)
153
178
  end
154
179
 
155
180
  ['test', 'spec', 'features', 'features-spinach'].each do |type|
@@ -172,7 +197,8 @@ namespace :parallel do
172
197
  # Using the relative path to find the binary allow to run a specific version of it
173
198
  executable = File.join(File.dirname(__FILE__), '..', '..', 'bin', 'parallel_test')
174
199
 
175
- command = "#{ParallelTests.with_ruby_binary(Shellwords.escape(executable))} #{type} --type #{test_framework} " \
200
+ command = "#{ParallelTests.with_ruby_binary(Shellwords.escape(executable))} #{type} " \
201
+ "--type #{test_framework} " \
176
202
  "-n #{count} " \
177
203
  "--pattern '#{pattern}' " \
178
204
  "--test-options '#{options}' " \
@@ -3,15 +3,9 @@ require 'parallel_tests'
3
3
  module ParallelTests
4
4
  module Test
5
5
  class Runner
6
- NAME = 'Test'
7
-
8
6
  class << self
9
7
  # --- usually overwritten by other runners
10
8
 
11
- def name
12
- NAME
13
- end
14
-
15
9
  def runtime_log
16
10
  'tmp/parallel_runtime_test.log'
17
11
  end
@@ -188,11 +182,7 @@ module ParallelTests
188
182
  puts "Runtime found for #{tests.count(&:last)} of #{tests.size} tests"
189
183
  end
190
184
 
191
- # fill gaps with unknown-runtime if given, average otherwise
192
- known, unknown = tests.partition(&:last)
193
- average = (known.any? ? known.map!(&:last).inject(:+) / known.size : 1)
194
- unknown_runtime = options[:unknown_runtime] || average
195
- unknown.each { |set| set[1] = unknown_runtime }
185
+ set_unknown_runtime tests, options
196
186
  end
197
187
 
198
188
  def runtimes(tests, options)
@@ -240,6 +230,16 @@ module ParallelTests
240
230
 
241
231
  private
242
232
 
233
+ # fill gaps with unknown-runtime if given, average otherwise
234
+ # NOTE: an optimization could be doing runtime by average runtime per file size, but would need file checks
235
+ def set_unknown_runtime(tests, options)
236
+ known, unknown = tests.partition(&:last)
237
+ return if unknown.empty?
238
+ unknown_runtime = options[:unknown_runtime] ||
239
+ (known.empty? ? 1 : known.map!(&:last).inject(:+) / known.size) # average
240
+ unknown.each { |set| set[1] = unknown_runtime }
241
+ end
242
+
243
243
  def report_process_command?(options)
244
244
  options[:verbose] || options[:verbose_process_command]
245
245
  end
@@ -1,3 +1,3 @@
1
1
  module ParallelTests
2
- VERSION = Version = '2.29.2'
2
+ VERSION = Version = '3.0.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parallel_tests
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.29.2
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Grosser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-06 00:00:00.000000000 Z
11
+ date: 2020-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parallel
@@ -42,6 +42,7 @@ files:
42
42
  - lib/parallel_tests.rb
43
43
  - lib/parallel_tests/cli.rb
44
44
  - lib/parallel_tests/cucumber/failures_logger.rb
45
+ - lib/parallel_tests/cucumber/features_with_steps.rb
45
46
  - lib/parallel_tests/cucumber/runner.rb
46
47
  - lib/parallel_tests/cucumber/scenario_line_logger.rb
47
48
  - lib/parallel_tests/cucumber/scenarios.rb
@@ -62,10 +63,14 @@ files:
62
63
  - lib/parallel_tests/test/runner.rb
63
64
  - lib/parallel_tests/test/runtime_logger.rb
64
65
  - lib/parallel_tests/version.rb
65
- homepage: http://github.com/grosser/parallel_tests
66
+ homepage: https://github.com/grosser/parallel_tests
66
67
  licenses:
67
68
  - MIT
68
- metadata: {}
69
+ metadata:
70
+ bug_tracker_uri: https://github.com/grosser/parallel_tests/issues
71
+ documentation_uri: https://github.com/grosser/parallel_tests/blob/v3.0.0/Readme.md
72
+ source_code_uri: https://github.com/grosser/parallel_tests/tree/v3.0.0
73
+ wiki_uri: https://github.com/grosser/parallel_tests/wiki
69
74
  post_install_message:
70
75
  rdoc_options: []
71
76
  require_paths:
@@ -74,14 +79,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
74
79
  requirements:
75
80
  - - ">="
76
81
  - !ruby/object:Gem::Version
77
- version: 2.2.0
82
+ version: 2.4.0
78
83
  required_rubygems_version: !ruby/object:Gem::Requirement
79
84
  requirements:
80
85
  - - ">="
81
86
  - !ruby/object:Gem::Version
82
87
  version: '0'
83
88
  requirements: []
84
- rubygems_version: 3.0.3
89
+ rubygems_version: 3.1.3
85
90
  signing_key:
86
91
  specification_version: 4
87
92
  summary: Run Test::Unit / RSpec / Cucumber / Spinach in parallel