parallel_tests 0.7.4 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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