parallel_tests 0.7.4 → 0.8.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,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- parallel_tests (0.7.4)
4
+ parallel_tests (0.8.0)
5
5
  parallel
6
6
 
7
7
  GEM
data/Readme.md CHANGED
@@ -119,15 +119,19 @@ Setup for non-rails
119
119
  parallel_test test/bar test/baz/foo_text.rb
120
120
 
121
121
  Options are:
122
-
123
122
  -n [PROCESSES] How many processes to use, default: available CPUs
124
- -p, --path [PATH] run tests inside this path only
125
- --no-sort do not sort files before running them
123
+ -p, --pattern [PATTERN] run tests matching this pattern
124
+ --group-by group tests by:
125
+ found - order of finding files
126
+ steps - number of cucumber steps
127
+ default - runtime or filesize
126
128
  -m, --multiply-processes [FLOAT] use given number as a multiplier of processes to run
129
+ -s, --single [PATTERN] Run all matching files in only one process
127
130
  -e, --exec [COMMAND] execute this code parallel and with ENV['TEST_ENV_NUM']
128
131
  -o, --test-options '[OPTIONS]' execute test commands with those options
129
- -t, --type [TYPE] test(default) / spec / cucumber
132
+ -t, --type [TYPE] test(default) / rspec / cucumber
130
133
  --non-parallel execute same commands but do not in parallel, needs --exec
134
+ --chunk-timeout [TIMEOUT] timeout before re-printing the output of a child-process
131
135
  -v, --version Show Version
132
136
  -h, --help Show this.
133
137
 
@@ -151,7 +155,7 @@ TIPS
151
155
  - [Capybara + Selenium] add to env.rb: `Capybara.server_port = 8888 + ENV['TEST_ENV_NUMBER'].to_i`
152
156
  - [RSpec] add a `.rspec_parallel` to use different options, e.g. **no --drb**
153
157
  - [RSpec] delete `script/spec`
154
- - [RSpec] [spork](https://github.com/sporkrb/spork) does not work in parallel
158
+ - [[Spork](https://github.com/sporkrb/spork)] does not work with parallel_tests
155
159
  - [RSpec] remove --loadby from you spec/*.opts
156
160
  - [RSpec] Instantly see failures (instead of just a red F) with [rspec-instafail](https://github.com/grosser/rspec-instafail)
157
161
  - [Bundler] if you have a `Gemfile` then `bundle exec` will be used to run tests
@@ -2,4 +2,5 @@
2
2
  $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
3
3
  require "parallel_tests"
4
4
  require "parallel_tests/cli"
5
+
5
6
  ParallelTest::CLI.run(ARGV)
@@ -81,7 +81,13 @@ Options are:
81
81
  BANNER
82
82
  opts.on("-n [PROCESSES]", Integer, "How many processes to use, default: available CPUs") { |n| options[:count] = n }
83
83
  opts.on("-p", '--pattern [PATTERN]', "run tests matching this pattern") { |pattern| options[:pattern] = /#{pattern}/ }
84
- opts.on("--no-sort", "do not sort files before running them") { |no_sort| options[:no_sort] = no_sort }
84
+ opts.on("--group-by [TYPE]", <<-TEXT
85
+ group tests by:
86
+ found - order of finding files
87
+ steps - number of cucumber steps
88
+ default - runtime or filesize
89
+ TEXT
90
+ ) { |type| options[:group_by] = type.to_sym }
85
91
  opts.on("-m [FLOAT]", "--multiply-processes [FLOAT]", Float, "use given number as a multiplier of processes to run") { |multiply| options[:multiply] = multiply }
86
92
  opts.on("-s [PATTERN]", "--single [PATTERN]", "Run all matching files in only one process") do |pattern|
87
93
  options[:single_process] ||= []
@@ -96,7 +102,7 @@ BANNER
96
102
  opts.on("-h", "--help", "Show this.") { puts opts; exit }
97
103
  end.parse!(argv)
98
104
 
99
- raise "--no-sort and --single-process are not supported" if options[:no_sort] and options[:single_process]
105
+ raise "--group-by found and --single-process are not supported" if options[:group_by] == :found and options[:single_process]
100
106
 
101
107
  options[:files] = argv
102
108
  options
@@ -0,0 +1,60 @@
1
+ require 'gherkin'
2
+
3
+ module ParallelTests
4
+ module Cucumber
5
+ class GherkinListener
6
+ attr_reader :collect
7
+
8
+ def initialize
9
+ @steps, @uris = [], []
10
+ @collect = {}
11
+ reset_counters!
12
+ end
13
+
14
+ def background(*args)
15
+ @background = 1
16
+ end
17
+
18
+ def scenario(*args)
19
+ @scenarios += 1
20
+ @outline = @background = 0
21
+ end
22
+
23
+ def scenario_outline(*args)
24
+ @outline = 1
25
+ end
26
+
27
+ def step(*args)
28
+ if @background == 1
29
+ @background_steps += 1
30
+ elsif @outline > 0
31
+ @outline_steps += 1
32
+ else
33
+ @collect[@uri] += 1
34
+ end
35
+ end
36
+
37
+ def uri(path)
38
+ @uri = path
39
+ @collect[@uri] = 0
40
+ end
41
+
42
+ def examples(*args)
43
+ @examples += 1
44
+ end
45
+
46
+ def eof(*args)
47
+ @collect[@uri] += (@background_steps * @scenarios) + (@outline_steps * @examples)
48
+ reset_counters!
49
+ end
50
+
51
+ def reset_counters!
52
+ @examples = @outline = @outline_steps = @background = @background_steps = @scenarios = 0
53
+ end
54
+
55
+ # ignore lots of other possible callbacks ...
56
+ def method_missing(*args)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -49,6 +49,14 @@ module ParallelTests
49
49
  "--profile parallel"
50
50
  end
51
51
  end
52
+
53
+ def self.tests_in_groups(tests, num_groups, options={})
54
+ if options[:group_by] == :steps
55
+ Grouper.by_steps(find_tests(tests, options), num_groups)
56
+ else
57
+ super
58
+ end
59
+ end
52
60
  end
53
61
  end
54
62
  end
@@ -5,7 +5,9 @@ module ParallelTests
5
5
 
6
6
  until items.empty?
7
7
  num_groups.times do |group_number|
8
- groups[group_number] << items.shift
8
+ if item = items.shift
9
+ groups[group_number] << item
10
+ end
9
11
  end
10
12
  end
11
13
 
@@ -45,5 +47,20 @@ module ParallelTests
45
47
  group[:items] << item
46
48
  group[:size] += size
47
49
  end
50
+
51
+ def self.by_steps(tests, num_groups)
52
+ features_with_steps = build_features_with_steps(tests)
53
+ in_even_groups_by_size(features_with_steps, num_groups)
54
+ end
55
+
56
+ def self.build_features_with_steps(tests)
57
+ require 'parallel_tests/cucumber/gherkin_listener'
58
+ listener = Cucumber::GherkinListener.new
59
+ parser = Gherkin::Parser::Parser.new(listener, true, 'root')
60
+ tests.each{|file|
61
+ parser.parse(File.read(file), file, 0)
62
+ }
63
+ listener.collect.sort_by{|_,value| -value }
64
+ end
48
65
  end
49
66
  end
@@ -31,7 +31,7 @@ module ParallelTests
31
31
  def self.tests_in_groups(tests, num_groups, options={})
32
32
  tests = find_tests(tests, options)
33
33
 
34
- if options[:no_sort] == true
34
+ if options[:group_by] == :found
35
35
  Grouper.in_groups(tests, num_groups)
36
36
  else
37
37
  tests = with_runtime_info(tests)
@@ -1,3 +1,3 @@
1
1
  module ParallelTests
2
- VERSION = Version = '0.7.4'
2
+ VERSION = Version = '0.8.0'
3
3
  end
@@ -108,6 +108,12 @@ describe 'CLI' do
108
108
  `#{bin_folder}/parallel_cucumber -v`.should == version
109
109
  end
110
110
 
111
+ it "runs with --group-by found" do
112
+ # it only tests that it does not blow up, as it did before fixing...
113
+ write "spec/x1_spec.rb", "puts '111'"
114
+ run_tests "spec", :type => 'rspec', :add => '--group-by found'
115
+ end
116
+
111
117
  it "runs faster with more processes" do
112
118
  2.times{|i|
113
119
  write "spec/xxx#{i}_spec.rb", 'describe("it"){it("should"){sleep 5}}; $stderr.puts ENV["TEST_ENV_NUMBER"]'
@@ -0,0 +1,48 @@
1
+ require 'parallel_tests/cucumber/gherkin_listener'
2
+
3
+ describe ParallelTests::Cucumber::GherkinListener do
4
+ describe :collect do
5
+ before(:each) do
6
+ @listener = ParallelTests::Cucumber::GherkinListener.new
7
+ @listener.uri("feature_file")
8
+ end
9
+
10
+ it "returns steps count" do
11
+ 3.times {@listener.step(nil)}
12
+ @listener.collect.should == {"feature_file" => 3}
13
+ end
14
+
15
+ it "counts background steps separately" do
16
+ @listener.background("background")
17
+ 5.times {@listener.step(nil)}
18
+ @listener.collect.should == {"feature_file" => 0}
19
+
20
+ @listener.scenario("scenario")
21
+ 2.times {@listener.step(nil)}
22
+ @listener.collect.should == {"feature_file" => 2}
23
+
24
+ @listener.scenario("scenario")
25
+ @listener.collect.should == {"feature_file" => 2}
26
+
27
+ @listener.eof
28
+ @listener.collect.should == {"feature_file" => 12}
29
+ end
30
+
31
+ it "counts scenario outlines steps separately" do
32
+ @listener.scenario_outline("outline")
33
+ 5.times {@listener.step(nil)}
34
+ @listener.collect.should == {"feature_file" => 0}
35
+
36
+ @listener.scenario("scenario")
37
+ 2.times {@listener.step(nil)}
38
+ @listener.collect.should == {"feature_file" => 2}
39
+
40
+ @listener.scenario("scenario")
41
+ @listener.collect.should == {"feature_file" => 2}
42
+
43
+ 3.times {@listener.examples}
44
+ @listener.eof
45
+ @listener.collect.should == {"feature_file" => 17}
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,61 @@
1
+ require 'parallel_tests/grouper'
2
+ require 'tmpdir'
3
+
4
+ describe ParallelTests::Grouper do
5
+ describe :by_steps do
6
+ def write(file, content)
7
+ File.open(file,'w'){|f| f.write content }
8
+ end
9
+
10
+ it "sorts features by steps" do
11
+ tmpdir = nil
12
+ result = Dir.mktmpdir do |dir|
13
+ tmpdir = dir
14
+ write("#{dir}/a.feature", "Feature: xxx\n Scenario: xxx\n Given something")
15
+ write("#{dir}/b.feature", "Feature: xxx\n Scenario: xxx\n Given something\n Scenario: yyy\n Given something")
16
+ write("#{dir}/c.feature", "Feature: xxx\n Scenario: xxx\n Given something")
17
+ ParallelTests::Grouper.by_steps(["#{dir}/a.feature", "#{dir}/b.feature", "#{dir}/c.feature"],2)
18
+ end
19
+
20
+ # testing inside mktmpdir is always green
21
+ result.should =~ [
22
+ ["#{tmpdir}/a.feature", "#{tmpdir}/c.feature"],
23
+ ["#{tmpdir}/b.feature"]
24
+ ]
25
+ end
26
+ end
27
+
28
+ describe :in_even_groups_by_size do
29
+ let(:files_with_size){ {"1" => 1, "2" => 2, "3" => 3, "4" => 4, "5" => 5} }
30
+
31
+ def call(num_groups)
32
+ ParallelTests::Grouper.in_even_groups_by_size(files_with_size, num_groups)
33
+ end
34
+
35
+ it "groups 1 by 1 for same groups as size" do
36
+ call(5).should == [["5"], ["4"], ["3"], ["2"], ["1"]]
37
+ end
38
+
39
+ it "groups into even groups" do
40
+ call(2).should == [["1", "2", "5"], ["3", "4"]]
41
+ end
42
+
43
+ it "groups into a single group" do
44
+ call(1).should == [["1", "2", "3", "4", "5"]]
45
+ end
46
+
47
+ it "adds empty groups if there are more groups than feature files" do
48
+ call(6).should == [["5"], ["4"], ["3"], ["2"], ["1"], []]
49
+ end
50
+ end
51
+
52
+ describe :in_groups do
53
+ it "groups" do
54
+ ParallelTests::Grouper.in_groups([1,2,3],2).should == [[1,3],[2]]
55
+ end
56
+
57
+ it "keeps groups sorted" do
58
+ ParallelTests::Grouper.in_groups([3,2,1],2).should == [[1,3],[2]]
59
+ end
60
+ end
61
+ end
@@ -38,7 +38,7 @@ describe ParallelTests::Test::Runner do
38
38
 
39
39
  it "does not sort when passed false do_sort option" do
40
40
  ParallelTests::Test::Runner.should_not_receive(:smallest_first)
41
- call [], 1, :no_sort => true
41
+ call [], 1, :group_by => :found
42
42
  end
43
43
 
44
44
  it "does sort when not passed do_sort option" do
@@ -135,7 +135,7 @@ def test_tests_in_groups(klass, folder, suffix)
135
135
  it "partitions by round-robin when not sorting" do
136
136
  files = ["file1.rb", "file2.rb", "file3.rb", "file4.rb"]
137
137
  klass.should_receive(:find_tests).and_return(files)
138
- groups = klass.tests_in_groups(files, 2, :no_sort => true)
138
+ groups = klass.tests_in_groups(files, 2, :group_by => :found)
139
139
  groups[0].should == ["file1.rb", "file3.rb"]
140
140
  groups[1].should == ["file2.rb", "file4.rb"]
141
141
  end
@@ -143,7 +143,7 @@ def test_tests_in_groups(klass, folder, suffix)
143
143
  it "alpha-sorts partitions when not sorting by runtime" do
144
144
  files = %w[q w e r t y u i o p a s d f g h j k l z x c v b n m]
145
145
  klass.should_receive(:find_tests).and_return(files)
146
- groups = klass.tests_in_groups(files, 2, :no_sort => true)
146
+ groups = klass.tests_in_groups(files, 2, :group_by => :found)
147
147
  groups[0].should == groups[0].sort
148
148
  groups[1].should == groups[1].sort
149
149
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parallel_tests
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.4
4
+ version: 0.8.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-20 00:00:00.000000000 Z
12
+ date: 2012-04-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: parallel
16
- requirement: &14848560 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,12 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *14848560
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
25
30
  description:
26
31
  email: michael@grosser.it
27
32
  executables:
@@ -42,6 +47,7 @@ files:
42
47
  - bin/parallel_test
43
48
  - lib/parallel_tests.rb
44
49
  - lib/parallel_tests/cli.rb
50
+ - lib/parallel_tests/cucumber/gherkin_listener.rb
45
51
  - lib/parallel_tests/cucumber/runner.rb
46
52
  - lib/parallel_tests/cucumber/runtime_logger.rb
47
53
  - lib/parallel_tests/grouper.rb
@@ -57,7 +63,9 @@ files:
57
63
  - lib/parallel_tests/version.rb
58
64
  - parallel_tests.gemspec
59
65
  - spec/integration_spec.rb
66
+ - spec/parallel_tests/cucumber/gherkin_listener_spec.rb
60
67
  - spec/parallel_tests/cucumber/runner_spec.rb
68
+ - spec/parallel_tests/grouper_spec.rb
61
69
  - spec/parallel_tests/rspec/failure_logger_spec.rb
62
70
  - spec/parallel_tests/rspec/runner_spec.rb
63
71
  - spec/parallel_tests/rspec/runtime_logger_spec.rb
@@ -81,7 +89,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
81
89
  version: '0'
82
90
  segments:
83
91
  - 0
84
- hash: -3734354896089749811
92
+ hash: 1985471141696551729
85
93
  required_rubygems_version: !ruby/object:Gem::Requirement
86
94
  none: false
87
95
  requirements:
@@ -90,10 +98,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
90
98
  version: '0'
91
99
  segments:
92
100
  - 0
93
- hash: -3734354896089749811
101
+ hash: 1985471141696551729
94
102
  requirements: []
95
103
  rubyforge_project:
96
- rubygems_version: 1.8.15
104
+ rubygems_version: 1.8.24
97
105
  signing_key:
98
106
  specification_version: 3
99
107
  summary: Run Test::Unit / RSpec / Cucumber in parallel