parallel_tests 0.13.3 → 0.14.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.
Files changed (33) hide show
  1. data/Gemfile +1 -0
  2. data/Gemfile.lock +8 -2
  3. data/Rakefile +5 -1
  4. data/Readme.md +5 -2
  5. data/bin/parallel_spinach +5 -0
  6. data/lib/parallel_tests.rb +40 -38
  7. data/lib/parallel_tests/cli.rb +2 -2
  8. data/lib/parallel_tests/cucumber/failures_logger.rb +2 -2
  9. data/lib/parallel_tests/cucumber/runner.rb +5 -88
  10. data/lib/parallel_tests/{cucumber → gherkin}/io.rb +1 -1
  11. data/lib/parallel_tests/{cucumber/gherkin_listener.rb → gherkin/listener.rb} +2 -2
  12. data/lib/parallel_tests/gherkin/runner.rb +102 -0
  13. data/lib/parallel_tests/{cucumber → gherkin}/runtime_logger.rb +2 -2
  14. data/lib/parallel_tests/grouper.rb +41 -41
  15. data/lib/parallel_tests/rspec/failures_logger.rb +1 -1
  16. data/lib/parallel_tests/rspec/runner.rb +50 -48
  17. data/lib/parallel_tests/spinach/runner.rb +19 -0
  18. data/lib/parallel_tests/tasks.rb +7 -3
  19. data/lib/parallel_tests/test/runner.rb +125 -123
  20. data/lib/parallel_tests/test/runtime_logger.rb +57 -53
  21. data/lib/parallel_tests/version.rb +1 -1
  22. data/parallel_tests.gemspec +2 -2
  23. data/spec/integration_spec.rb +61 -0
  24. data/spec/parallel_tests/cucumber/failure_logger_spec.rb +1 -1
  25. data/spec/parallel_tests/cucumber/runner_spec.rb +5 -172
  26. data/spec/parallel_tests/{cucumber/gherkin_listener_spec.rb → gherkin/listener_spec.rb} +3 -3
  27. data/spec/parallel_tests/gherkin/runner_behaviour.rb +177 -0
  28. data/spec/parallel_tests/rspec/{failure_logger_spec.rb → failures_logger_spec.rb} +0 -0
  29. data/spec/parallel_tests/spinach/runner_spec.rb +12 -0
  30. data/spec/parallel_tests/test/runtime_logger_spec.rb +1 -1
  31. data/spec/parallel_tests_spec.rb +2 -2
  32. data/spec/spec_helper.rb +1 -1
  33. metadata +16 -10
data/Gemfile CHANGED
@@ -5,4 +5,5 @@ gem 'bump'
5
5
  gem 'test-unit'
6
6
  gem 'rspec', '>=2.4'
7
7
  gem 'cucumber'
8
+ gem 'spinach'
8
9
  gem 'rake'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- parallel_tests (0.13.3)
4
+ parallel_tests (0.14.0)
5
5
  parallel
6
6
 
7
7
  GEM
@@ -9,6 +9,7 @@ GEM
9
9
  specs:
10
10
  builder (3.0.0)
11
11
  bump (0.3.8)
12
+ colorize (0.5.8)
12
13
  cucumber (1.1.4)
13
14
  builder (>= 2.1.2)
14
15
  diff-lcs (>= 1.1.2)
@@ -20,9 +21,10 @@ GEM
20
21
  json (>= 1.4.6)
21
22
  gherkin (2.7.6-java)
22
23
  json (>= 1.4.6)
24
+ gherkin-ruby (0.3.0)
23
25
  json (1.7.5)
24
26
  json (1.7.5-java)
25
- parallel (0.6.5)
27
+ parallel (0.7.0)
26
28
  rake (10.0.3)
27
29
  rspec (2.13.0)
28
30
  rspec-core (~> 2.13.0)
@@ -32,6 +34,9 @@ GEM
32
34
  rspec-expectations (2.13.0)
33
35
  diff-lcs (>= 1.1.3, < 2.0)
34
36
  rspec-mocks (2.13.1)
37
+ spinach (0.8.3)
38
+ colorize (= 0.5.8)
39
+ gherkin-ruby (~> 0.3.0)
35
40
  term-ansicolor (1.0.7)
36
41
  test-unit (2.4.4)
37
42
 
@@ -45,4 +50,5 @@ DEPENDENCIES
45
50
  parallel_tests!
46
51
  rake
47
52
  rspec (>= 2.4)
53
+ spinach
48
54
  test-unit
data/Rakefile CHANGED
@@ -2,5 +2,9 @@ require 'bump/tasks'
2
2
  require 'bundler/gem_tasks'
3
3
 
4
4
  task :default do
5
- sh "rspec spec/"
5
+ if RUBY_VERSION < "1.9.0"
6
+ sh "rspec --tag ~fails_on_ruby_187 spec/"
7
+ else
8
+ sh "rspec spec/"
9
+ end
6
10
  end
data/Readme.md CHANGED
@@ -9,7 +9,7 @@ Setup for Rails
9
9
  [still using Rails 2?](https://github.com/grosser/parallel_tests/blob/master/ReadmeRails2.md)
10
10
 
11
11
  ### Install
12
- If you use RSpec: ensure you got >= 2.4
12
+ If you use RSpec: ensure you have >= 2.4
13
13
 
14
14
  As gem
15
15
 
@@ -48,6 +48,7 @@ test:
48
48
  rake parallel:test # Test::Unit
49
49
  rake parallel:spec # RSpec
50
50
  rake parallel:features # Cucumber
51
+ rake parallel:features-spinach # Spinach
51
52
 
52
53
  rake parallel:test[1] --> force 1 CPU --> 86 seconds
53
54
  rake parallel:test --> got 2 CPUs? --> 47 seconds
@@ -164,6 +165,7 @@ Setup for non-rails
164
165
  parallel_test test/
165
166
  parallel_rspec spec/
166
167
  parallel_cucumber features/
168
+ parallel_spinach features/
167
169
 
168
170
  - use ENV['TEST_ENV_NUMBER'] inside your tests to select separate db/memcache/etc.
169
171
  - Only run selected files & folders:
@@ -183,7 +185,7 @@ Options are:
183
185
  -i, --isolate Do not run any other tests in the group used by --single(-s)
184
186
  -e, --exec [COMMAND] execute this code parallel and with ENV['TEST_ENV_NUM']
185
187
  -o, --test-options '[OPTIONS]' execute test commands with those options
186
- -t, --type [TYPE] test(default) / rspec / cucumber
188
+ -t, --type [TYPE] test(default) / rspec / cucumber / spinach
187
189
  --serialize-stdout Serialize stdout output, nothing will be written until everything is done
188
190
  --non-parallel execute same commands but do not in parallel, needs --exec
189
191
  --no-symlinks Do not traverse symbolic links to find test files
@@ -286,6 +288,7 @@ inspired by [pivotal labs](http://pivotallabs.com/users/miked/blog/articles/849-
286
288
  - [Iain Beeston](https://github.com/iainbeeston)
287
289
  - [Alejandro Pulver](https://github.com/alepulver)
288
290
  - [Felix Clack](https://github.com/felixclack)
291
+ - [Izaak Alpert](https://github.com/karlhungus)
289
292
 
290
293
  [Michael Grosser](http://grosser.it)<br/>
291
294
  michael@grosser.it<br/>
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH << File.expand_path("../../lib", __FILE__)
3
+ require "parallel_tests"
4
+
5
+ ParallelTests::CLI.new.run(["--type", "spinach"] + ARGV)
@@ -8,52 +8,54 @@ module ParallelTests
8
8
  autoload :VERSION, "parallel_tests/version"
9
9
  autoload :Grouper, "parallel_tests/grouper"
10
10
 
11
- def self.determine_number_of_processes(count)
12
- [
13
- count,
14
- ENV["PARALLEL_TEST_PROCESSORS"],
15
- Parallel.processor_count
16
- ].detect{|c| not c.to_s.strip.empty? }.to_i
17
- end
11
+ class << self
12
+ def determine_number_of_processes(count)
13
+ [
14
+ count,
15
+ ENV["PARALLEL_TEST_PROCESSORS"],
16
+ Parallel.processor_count
17
+ ].detect{|c| not c.to_s.strip.empty? }.to_i
18
+ end
18
19
 
19
- # copied from http://github.com/carlhuda/bundler Bundler::SharedHelpers#find_gemfile
20
- def self.bundler_enabled?
21
- return true if Object.const_defined?(:Bundler)
20
+ # copied from http://github.com/carlhuda/bundler Bundler::SharedHelpers#find_gemfile
21
+ def bundler_enabled?
22
+ return true if Object.const_defined?(:Bundler)
22
23
 
23
- previous = nil
24
- current = File.expand_path(Dir.pwd)
24
+ previous = nil
25
+ current = File.expand_path(Dir.pwd)
25
26
 
26
- until !File.directory?(current) || current == previous
27
- filename = File.join(current, "Gemfile")
28
- return true if File.exists?(filename)
29
- current, previous = File.expand_path("..", current), current
30
- end
27
+ until !File.directory?(current) || current == previous
28
+ filename = File.join(current, "Gemfile")
29
+ return true if File.exists?(filename)
30
+ current, previous = File.expand_path("..", current), current
31
+ end
31
32
 
32
- false
33
- end
33
+ false
34
+ end
34
35
 
35
- def self.first_process?
36
- !ENV["TEST_ENV_NUMBER"] || ENV["TEST_ENV_NUMBER"].to_i == 0
37
- end
36
+ def first_process?
37
+ !ENV["TEST_ENV_NUMBER"] || ENV["TEST_ENV_NUMBER"].to_i == 0
38
+ end
38
39
 
39
- def self.wait_for_other_processes_to_finish
40
- return unless ENV["TEST_ENV_NUMBER"]
41
- sleep 1 until number_of_running_processes <= 1
42
- end
40
+ def wait_for_other_processes_to_finish
41
+ return unless ENV["TEST_ENV_NUMBER"]
42
+ sleep 1 until number_of_running_processes <= 1
43
+ end
43
44
 
44
- # Fun fact: this includes the current process if it's run via parallel_tests
45
- def self.number_of_running_processes
46
- result = `#{GREP_PROCESSES_COMMAND}`
47
- raise "Could not grep for processes -> #{result}" if result.strip != "" && !$?.success?
48
- result.split("\n").size
49
- end
45
+ # Fun fact: this includes the current process if it's run via parallel_tests
46
+ def number_of_running_processes
47
+ result = `#{GREP_PROCESSES_COMMAND}`
48
+ raise "Could not grep for processes -> #{result}" if result.strip != "" && !$?.success?
49
+ result.split("\n").size
50
+ end
50
51
 
51
- # real time even if someone messed with timecop in tests
52
- def self.now
53
- if Time.respond_to?(:now_without_mock_time) # Timecop
54
- Time.now_without_mock_time
55
- else
56
- Time.now
52
+ # real time even if someone messed with timecop in tests
53
+ def now
54
+ if Time.respond_to?(:now_without_mock_time) # Timecop
55
+ Time.now_without_mock_time
56
+ else
57
+ Time.now
58
+ end
57
59
  end
58
60
  end
59
61
  end
@@ -96,7 +96,7 @@ BANNER
96
96
  opts.on("--group-by [TYPE]", <<-TEXT
97
97
  group tests by:
98
98
  found - order of finding files
99
- steps - number of cucumber steps
99
+ steps - number of cucumber/spinach steps
100
100
  default - runtime or filesize
101
101
  TEXT
102
102
  ) { |type| options[:group_by] = type.to_sym }
@@ -117,7 +117,7 @@ TEXT
117
117
 
118
118
  opts.on("-e", "--exec [COMMAND]", "execute this code parallel and with ENV['TEST_ENV_NUM']") { |path| options[:execute] = path }
119
119
  opts.on("-o", "--test-options '[OPTIONS]'", "execute test commands with those options") { |arg| options[:test_options] = arg }
120
- opts.on("-t", "--type [TYPE]", "test(default) / rspec / cucumber") do |type|
120
+ opts.on("-t", "--type [TYPE]", "test(default) / rspec / cucumber / spinach") do |type|
121
121
  begin
122
122
  @runner = load_runner(type)
123
123
  rescue NameError, LoadError => e
@@ -1,10 +1,10 @@
1
1
  require 'cucumber/formatter/rerun'
2
- require 'parallel_tests/cucumber/io'
2
+ require 'parallel_tests/gherkin/io'
3
3
 
4
4
  module ParallelTests
5
5
  module Cucumber
6
6
  class FailuresLogger < ::Cucumber::Formatter::Rerun
7
- include Io
7
+ include ParallelTests::Gherkin::Io
8
8
 
9
9
  def initialize(runtime, path_or_io, options)
10
10
  @io = prepare_io(path_or_io)
@@ -1,94 +1,11 @@
1
- require "parallel_tests/test/runner"
2
- require 'shellwords'
1
+ require "parallel_tests/gherkin/runner"
3
2
 
4
3
  module ParallelTests
5
4
  module Cucumber
6
- class Runner < ParallelTests::Test::Runner
7
- NAME = 'Cucumber'
8
-
9
- def self.run_tests(test_files, process_number, num_processes, options)
10
- sanitized_test_files = test_files.map { |val| Shellwords.escape(val) }
11
- options = options.merge(:env => {"AUTOTEST" => "1"}) if $stdout.tty? # display color when we are in a terminal
12
- runtime_logging = " --format ParallelTests::Cucumber::RuntimeLogger --out #{runtime_log}"
13
- cmd = [
14
- executable,
15
- (runtime_logging if File.directory?(File.dirname(runtime_log))),
16
- cucumber_opts(options[:test_options]),
17
- *sanitized_test_files
18
- ].compact.join(" ")
19
- execute_command(cmd, process_number, num_processes, options)
20
- end
21
-
22
- def self.determine_executable
23
- case
24
- when File.exists?("bin/cucumber")
25
- "bin/cucumber"
26
- when ParallelTests.bundler_enabled?
27
- "bundle exec cucumber"
28
- when File.file?("script/cucumber")
29
- "script/cucumber"
30
- else
31
- "cucumber"
32
- end
33
- end
34
-
35
- def self.runtime_log
36
- 'tmp/parallel_runtime_cucumber.log'
37
- end
38
-
39
- def self.test_file_name
40
- "feature"
41
- end
42
-
43
- def self.test_suffix
44
- ".feature"
45
- end
46
-
47
- def self.line_is_result?(line)
48
- line =~ /^\d+ (steps?|scenarios?)/
49
- end
50
-
51
- # cucumber has 2 result lines per test run, that cannot be added
52
- # 1 scenario (1 failed)
53
- # 1 step (1 failed)
54
- def self.summarize_results(results)
55
- sort_order = %w[scenario step failed undefined skipped pending passed]
56
-
57
- %w[scenario step].map do |group|
58
- group_results = results.grep /^\d+ #{group}/
59
- next if group_results.empty?
60
-
61
- sums = sum_up_results(group_results)
62
- sums = sums.sort_by { |word, _| sort_order.index(word) || 999 }
63
- sums.map! do |word, number|
64
- plural = "s" if word == group and number != 1
65
- "#{number} #{word}#{plural}"
66
- end
67
- "#{sums[0]} (#{sums[1..-1].join(", ")})"
68
- end.compact.join("\n")
69
- end
70
-
71
- def self.cucumber_opts(given)
72
- if given =~ /--profile/ or given =~ /(^|\s)-p /
73
- given
74
- else
75
- [given, profile_from_config].compact.join(" ")
76
- end
77
- end
78
-
79
- def self.profile_from_config
80
- # copied from https://github.com/cucumber/cucumber/blob/master/lib/cucumber/cli/profile_loader.rb#L85
81
- config = Dir.glob('{,.config/,config/}cucumber{.yml,.yaml}').first
82
- if config && File.read(config) =~ /^parallel:/
83
- "--profile parallel"
84
- end
85
- end
86
-
87
- def self.tests_in_groups(tests, num_groups, options={})
88
- if options[:group_by] == :steps
89
- Grouper.by_steps(find_tests(tests, options), num_groups, options)
90
- else
91
- super
5
+ class Runner < ParallelTests::Gherkin::Runner
6
+ class << self
7
+ def name
8
+ 'cucumber'
92
9
  end
93
10
  end
94
11
  end
@@ -1,7 +1,7 @@
1
1
  require 'parallel_tests'
2
2
 
3
3
  module ParallelTests
4
- module Cucumber
4
+ module Gherkin
5
5
  module Io
6
6
 
7
7
  def prepare_io(path_or_io)
@@ -1,8 +1,8 @@
1
1
  require 'gherkin'
2
2
 
3
3
  module ParallelTests
4
- module Cucumber
5
- class GherkinListener
4
+ module Gherkin
5
+ class Listener
6
6
  attr_reader :collect
7
7
 
8
8
  attr_writer :ignore_tag_pattern
@@ -0,0 +1,102 @@
1
+ require "parallel_tests/test/runner"
2
+ require 'shellwords'
3
+
4
+ module ParallelTests
5
+ module Gherkin
6
+ class Runner < ParallelTests::Test::Runner
7
+
8
+ class << self
9
+ def run_tests(test_files, process_number, num_processes, options)
10
+ sanitized_test_files = test_files.map { |val| Shellwords.escape(val) }
11
+ options = options.merge(:env => {"AUTOTEST" => "1"}) if $stdout.tty? # display color when we are in a terminal
12
+ cmd = [
13
+ executable,
14
+ (runtime_logging if File.directory?(File.dirname(runtime_log))),
15
+ cucumber_opts(options[:test_options]),
16
+ *sanitized_test_files
17
+ ].compact.join(" ")
18
+ execute_command(cmd, process_number, num_processes, options)
19
+ end
20
+
21
+ def test_file_name
22
+ "feature"
23
+ end
24
+
25
+ def test_suffix
26
+ ".feature"
27
+ end
28
+
29
+ def line_is_result?(line)
30
+ line =~ /^\d+ (steps?|scenarios?)/
31
+ end
32
+
33
+ # cucumber has 2 result lines per test run, that cannot be added
34
+ # 1 scenario (1 failed)
35
+ # 1 step (1 failed)
36
+ def summarize_results(results)
37
+ sort_order = %w[scenario step failed undefined skipped pending passed]
38
+
39
+ %w[scenario step].map do |group|
40
+ group_results = results.grep /^\d+ #{group}/
41
+ next if group_results.empty?
42
+
43
+ sums = sum_up_results(group_results)
44
+ sums = sums.sort_by { |word, _| sort_order.index(word) || 999 }
45
+ sums.map! do |word, number|
46
+ plural = "s" if word == group and number != 1
47
+ "#{number} #{word}#{plural}"
48
+ end
49
+ "#{sums[0]} (#{sums[1..-1].join(", ")})"
50
+ end.compact.join("\n")
51
+ end
52
+
53
+ def cucumber_opts(given)
54
+ if given =~ /--profile/ or given =~ /(^|\s)-p /
55
+ given
56
+ else
57
+ [given, profile_from_config].compact.join(" ")
58
+ end
59
+ end
60
+
61
+ def profile_from_config
62
+ # copied from https://github.com/cucumber/cucumber/blob/master/lib/cucumber/cli/profile_loader.rb#L85
63
+ config = Dir.glob("{,.config/,config/}#{name}{.yml,.yaml}").first
64
+ if config && File.read(config) =~ /^parallel:/
65
+ "--profile parallel"
66
+ end
67
+ end
68
+
69
+ def tests_in_groups(tests, num_groups, options={})
70
+ if options[:group_by] == :steps
71
+ Grouper.by_steps(find_tests(tests, options), num_groups, options)
72
+ else
73
+ super
74
+ end
75
+ end
76
+
77
+
78
+ def runtime_logging
79
+ " --format ParallelTests::Gherkin::RuntimeLogger --out #{runtime_log}"
80
+ end
81
+
82
+ def runtime_log
83
+ "tmp/parallel_runtime_#{name}.log"
84
+ end
85
+
86
+ def determine_executable
87
+ case
88
+ when File.exists?("bin/#{name}")
89
+ "bin/#{name}"
90
+ when ParallelTests.bundler_enabled?
91
+ "bundle exec #{name}"
92
+ when File.file?("script/#{name}")
93
+ "script/#{name}"
94
+ else
95
+ "#{name}"
96
+ end
97
+ end
98
+
99
+ end
100
+ end
101
+ end
102
+ end