parallel_tests 0.6.7 → 0.6.8
Sign up to get free protection for your applications and to get access to all the features.
- data/Readme.md +7 -5
- data/VERSION +1 -1
- data/bin/parallel_test +7 -1
- data/lib/parallel_tests/grouper.rb +34 -15
- data/lib/parallel_tests.rb +1 -2
- data/parallel_tests.gemspec +8 -8
- data/spec/integration_spec.rb +7 -0
- data/spec/parallel_tests_spec.rb +7 -1
- metadata +31 -51
data/Readme.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
Speedup Test::Unit + RSpec + Cucumber by running parallel on multiple CPUs (or cores).<br/>
|
2
|
-
ParallelTests splits tests into even groups and runs each group in a single process with its own database.
|
2
|
+
ParallelTests splits tests into even groups(by number of tests or runtime) and runs each group in a single process with its own database.
|
3
3
|
|
4
4
|
Setup for Rails
|
5
5
|
===============
|
@@ -87,7 +87,7 @@ Spec Loggers
|
|
87
87
|
Even process runtimes
|
88
88
|
-----------------
|
89
89
|
|
90
|
-
Log test runtime to give each process the same
|
90
|
+
Log test runtime to give each process the same runtime.
|
91
91
|
|
92
92
|
Add to your `spec/parallel_spec.opts` (or `spec/spec.opts`) :
|
93
93
|
|
@@ -102,7 +102,7 @@ Add to your `spec/parallel_spec.opts` (or `spec/spec.opts`) :
|
|
102
102
|
SpecSummaryLogger
|
103
103
|
--------------------
|
104
104
|
|
105
|
-
This logger
|
105
|
+
This logger logs the test output without the different processes overwriting each other.
|
106
106
|
|
107
107
|
Add the following to your `spec/parallel_spec.opts` (or `spec/spec.opts`) :
|
108
108
|
|
@@ -116,7 +116,7 @@ Add the following to your `spec/parallel_spec.opts` (or `spec/spec.opts`) :
|
|
116
116
|
SpecFailuresLogger
|
117
117
|
-----------------------
|
118
118
|
|
119
|
-
This logger produces command
|
119
|
+
This logger produces pasteable command-line snippets for each failed example.
|
120
120
|
|
121
121
|
E.g.
|
122
122
|
|
@@ -177,6 +177,7 @@ TIPS
|
|
177
177
|
- [RSpec] if `script/spec` is missing parallel:spec uses just `spec` (which solves some issues with double-loaded environment.rb)
|
178
178
|
- [RSpec] 'script/spec_server' or [spork](http://github.com/timcharper/spork/tree/master) do not work in parallel
|
179
179
|
- [RSpec] `./script/generate rspec` if you are running rspec from gems (this plugin uses script/spec which may fail if rspec files are outdated)
|
180
|
+
- [RSpec] remove --loadby from you spec/*.opts
|
180
181
|
- [Bundler] if you have a `Gemfile` then `bundle exec` will be used to run tests
|
181
182
|
- [Capybara setup](https://github.com/grosser/parallel_tests/wiki)
|
182
183
|
- [Sphinx setup](https://github.com/grosser/parallel_tests/wiki)
|
@@ -219,4 +220,5 @@ inspired by [pivotal labs](http://pivotallabs.com/users/miked/blog/articles/849-
|
|
219
220
|
|
220
221
|
[Michael Grosser](http://grosser.it)<br/>
|
221
222
|
michael@grosser.it<br/>
|
222
|
-
Hereby placed under public domain, do what you want, just do not hold me accountable
|
223
|
+
Hereby placed under public domain, do what you want, just do not hold me accountable...<br/>
|
224
|
+
[![Flattr](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=grosser&url=https://github.com/grosser/parallel_tests&title=parallel_tests&language=en_GB&tags=github&category=software)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.6.
|
1
|
+
0.6.8
|
data/bin/parallel_test
CHANGED
@@ -21,6 +21,10 @@ BANNER
|
|
21
21
|
opts.on("--no-sort", "do not sort files before running them"){ |no_sort| options[:no_sort] = no_sort }
|
22
22
|
opts.on("-m [FLOAT]", "--multiply-processes [FLOAT]", Float, "use given number as a multiplier of processes to run"){ |multiply| options[:multiply] = multiply }
|
23
23
|
opts.on("-r", '--root [PATH]', "execute test commands from this path"){|path| options[:root] = path }
|
24
|
+
opts.on("-s [PATTERN]", "--single [PATTERN]", "Run all matching files in only one process") do |pattern|
|
25
|
+
options[:single_process] ||= []
|
26
|
+
options[:single_process] << /#{pattern}/
|
27
|
+
end
|
24
28
|
opts.on("-e", '--exec [COMMAND]', "execute this code parallel and with ENV['TEST_ENV_NUM']"){|path| options[:execute] = path }
|
25
29
|
opts.on("-o", "--test-options '[OPTIONS]'", "execute test commands with those options"){|arg| options[:test_options] = arg }
|
26
30
|
opts.on("-t", "--type [TYPE]", "which type of tests to run? test, spec or features"){|type| options[:type] = type }
|
@@ -30,6 +34,8 @@ BANNER
|
|
30
34
|
opts.on("-h", "--help", "Show this.") { puts opts; exit }
|
31
35
|
end.parse!
|
32
36
|
|
37
|
+
raise "--no-sort and --single-process are not supported" if options[:no_sort] and options[:single_process]
|
38
|
+
|
33
39
|
# get files to run from arguments
|
34
40
|
options[:files] = ARGV if ARGV.size > 0
|
35
41
|
|
@@ -63,7 +69,7 @@ else
|
|
63
69
|
tests_folder = task
|
64
70
|
tests_folder = File.join(options[:root], tests_folder) unless options[:root].to_s.empty?
|
65
71
|
|
66
|
-
groups = klass.tests_in_groups(options[:files] || tests_folder, num_processes,
|
72
|
+
groups = klass.tests_in_groups(options[:files] || tests_folder, num_processes, options)
|
67
73
|
num_processes = groups.size
|
68
74
|
|
69
75
|
#adjust processes to groups
|
@@ -1,31 +1,50 @@
|
|
1
1
|
class ParallelTests
|
2
2
|
class Grouper
|
3
3
|
def self.in_groups(items, num_groups)
|
4
|
-
[]
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
4
|
+
groups = Array.new(num_groups){ [] }
|
5
|
+
|
6
|
+
until items.empty?
|
7
|
+
num_groups.times do |group_number|
|
8
|
+
groups[group_number] << items.shift
|
10
9
|
end
|
11
|
-
end
|
10
|
+
end
|
11
|
+
|
12
|
+
groups.map!(&:sort!)
|
12
13
|
end
|
13
14
|
|
14
|
-
def self.in_even_groups_by_size(items_with_sizes, num_groups)
|
15
|
-
items_with_size = smallest_first(items_with_sizes)
|
15
|
+
def self.in_even_groups_by_size(items_with_sizes, num_groups, options={})
|
16
16
|
groups = Array.new(num_groups){{:items => [], :size => 0}}
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
|
18
|
+
# add all files that should run in a single process to one group
|
19
|
+
(options[:single_process]||[]).each do |pattern|
|
20
|
+
matched, items_with_sizes = items_with_sizes.partition{|item, size| item =~ pattern }
|
21
|
+
puts matched.inspect
|
22
|
+
smallest = smallest_group(groups)
|
23
|
+
matched.each{|item,size| add_to_group(smallest, item, size) }
|
24
|
+
end
|
25
|
+
|
26
|
+
# add all other files
|
27
|
+
smallest_first(items_with_sizes).each do |item, size|
|
28
|
+
smallest = smallest_group(groups)
|
29
|
+
add_to_group(smallest, item, size)
|
22
30
|
end
|
23
31
|
|
24
|
-
groups.map{|g| g[:items].sort }
|
32
|
+
groups.map!{|g| g[:items].sort }
|
25
33
|
end
|
26
34
|
|
27
35
|
def self.smallest_first(files)
|
28
36
|
files.sort_by{|item, size| size }.reverse
|
29
37
|
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def self.smallest_group(groups)
|
42
|
+
groups.min_by{|g| g[:size] }
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.add_to_group(group, item, size)
|
46
|
+
group[:items] << item
|
47
|
+
group[:size] += size
|
48
|
+
end
|
30
49
|
end
|
31
50
|
end
|
data/lib/parallel_tests.rb
CHANGED
@@ -31,13 +31,12 @@ class ParallelTests
|
|
31
31
|
Grouper.in_groups(tests, num_groups)
|
32
32
|
else
|
33
33
|
tests = with_runtime_info(tests)
|
34
|
-
Grouper.in_even_groups_by_size(tests, num_groups)
|
34
|
+
Grouper.in_even_groups_by_size(tests, num_groups, options)
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
def self.run_tests(test_files, process_number, options)
|
39
39
|
require_list = test_files.map { |filename| %{"#{File.expand_path filename}"} }.join(",")
|
40
|
-
test_options = "- #{options[:test_options]}" unless RUBY_VERSION > '1.9.2' # test options passing is broken on 1.9.3 see issue #64
|
41
40
|
cmd = "ruby -Itest -e '[#{require_list}].each {|f| require f }' -- #{options[:test_options]}"
|
42
41
|
execute_command(cmd, process_number, options)
|
43
42
|
end
|
data/parallel_tests.gemspec
CHANGED
@@ -4,14 +4,14 @@
|
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
|
-
s.name =
|
8
|
-
s.version = "0.6.
|
7
|
+
s.name = "parallel_tests"
|
8
|
+
s.version = "0.6.8"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Michael Grosser"]
|
12
|
-
s.date =
|
13
|
-
s.email =
|
14
|
-
s.executables = ["parallel_cucumber", "
|
12
|
+
s.date = "2011-11-02"
|
13
|
+
s.email = "grosser.michael@gmail.com"
|
14
|
+
s.executables = ["parallel_cucumber", "parallel_spec", "parallel_test"]
|
15
15
|
s.files = [
|
16
16
|
"Gemfile",
|
17
17
|
"Gemfile.lock",
|
@@ -40,10 +40,10 @@ Gem::Specification.new do |s|
|
|
40
40
|
"spec/parallel_tests_spec.rb",
|
41
41
|
"spec/spec_helper.rb"
|
42
42
|
]
|
43
|
-
s.homepage =
|
43
|
+
s.homepage = "http://github.com/grosser/parallel_tests"
|
44
44
|
s.require_paths = ["lib"]
|
45
|
-
s.rubygems_version =
|
46
|
-
s.summary =
|
45
|
+
s.rubygems_version = "1.8.10"
|
46
|
+
s.summary = "Run tests / specs / features in parallel"
|
47
47
|
|
48
48
|
if s.respond_to? :specification_version then
|
49
49
|
s.specification_version = 3
|
data/spec/integration_spec.rb
CHANGED
@@ -49,6 +49,13 @@ describe 'CLI' do
|
|
49
49
|
$?.success?.should == true
|
50
50
|
end
|
51
51
|
|
52
|
+
it "does not run any tests if there are none" do
|
53
|
+
write 'spec/xxx.rb', 'xxx'
|
54
|
+
result = run_tests
|
55
|
+
result.should include('No examples found')
|
56
|
+
result.should include('Took')
|
57
|
+
end
|
58
|
+
|
52
59
|
it "fails when tests fail" do
|
53
60
|
write 'spec/xxx_spec.rb', 'describe("it"){it("should"){puts "TEST1"}}'
|
54
61
|
write 'spec/xxx2_spec.rb', 'describe("it"){it("should"){1.should == 2}}'
|
data/spec/parallel_tests_spec.rb
CHANGED
@@ -71,6 +71,12 @@ describe ParallelTests do
|
|
71
71
|
ParallelTests::Grouper.should_receive(:smallest_first).and_return([])
|
72
72
|
ParallelTests.tests_in_groups [], 1
|
73
73
|
end
|
74
|
+
|
75
|
+
it "groups by single_process pattern and then via size" do
|
76
|
+
ParallelTests.should_receive(:with_runtime_info).and_return([['aaa',5],['aaa2',5],['bbb',2],['ccc',1],['ddd',1]])
|
77
|
+
result = ParallelTests.tests_in_groups [], 3, :single_process => [/^a.a/]
|
78
|
+
result.should == [["aaa", "aaa2"], ["bbb"], ["ccc", "ddd"]]
|
79
|
+
end
|
74
80
|
end
|
75
81
|
|
76
82
|
describe :find_results do
|
@@ -94,7 +100,7 @@ EOF
|
|
94
100
|
ParallelTests.find_results(output).should == ['10 tests, 20 assertions, 0 failures, 0 errors','14 tests, 20 assertions, 0 failures, 0 errors']
|
95
101
|
end
|
96
102
|
|
97
|
-
it "is robust against
|
103
|
+
it "is robust against scrambled output" do
|
98
104
|
output = <<EOF
|
99
105
|
Loaded suite /opt/ruby-enterprise/lib/ruby/gems/1.8/gems/rake-0.8.4/lib/rake/rake_test_loader
|
100
106
|
Started
|
metadata
CHANGED
@@ -1,48 +1,36 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: parallel_tests
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.6.8
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 6
|
9
|
-
- 7
|
10
|
-
version: 0.6.7
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Michael Grosser
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
12
|
+
date: 2011-11-02 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: parallel
|
16
|
+
requirement: &76244280 !ruby/object:Gem::Requirement
|
23
17
|
none: false
|
24
|
-
requirements:
|
25
|
-
- -
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
|
28
|
-
segments:
|
29
|
-
- 0
|
30
|
-
version: "0"
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
31
22
|
type: :runtime
|
32
|
-
name: parallel
|
33
|
-
version_requirements: *id001
|
34
23
|
prerelease: false
|
24
|
+
version_requirements: *76244280
|
35
25
|
description:
|
36
26
|
email: grosser.michael@gmail.com
|
37
|
-
executables:
|
27
|
+
executables:
|
38
28
|
- parallel_cucumber
|
39
|
-
- parallel_test
|
40
29
|
- parallel_spec
|
30
|
+
- parallel_test
|
41
31
|
extensions: []
|
42
|
-
|
43
32
|
extra_rdoc_files: []
|
44
|
-
|
45
|
-
files:
|
33
|
+
files:
|
46
34
|
- Gemfile
|
47
35
|
- Gemfile.lock
|
48
36
|
- Rakefile
|
@@ -69,39 +57,31 @@ files:
|
|
69
57
|
- spec/parallel_specs_spec.rb
|
70
58
|
- spec/parallel_tests_spec.rb
|
71
59
|
- spec/spec_helper.rb
|
72
|
-
has_rdoc: true
|
73
60
|
homepage: http://github.com/grosser/parallel_tests
|
74
61
|
licenses: []
|
75
|
-
|
76
62
|
post_install_message:
|
77
63
|
rdoc_options: []
|
78
|
-
|
79
|
-
require_paths:
|
64
|
+
require_paths:
|
80
65
|
- lib
|
81
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
67
|
none: false
|
83
|
-
requirements:
|
84
|
-
- -
|
85
|
-
- !ruby/object:Gem::Version
|
86
|
-
|
87
|
-
segments:
|
68
|
+
requirements:
|
69
|
+
- - ! '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
segments:
|
88
73
|
- 0
|
89
|
-
|
90
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
hash: -400446063
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
76
|
none: false
|
92
|
-
requirements:
|
93
|
-
- -
|
94
|
-
- !ruby/object:Gem::Version
|
95
|
-
|
96
|
-
segments:
|
97
|
-
- 0
|
98
|
-
version: "0"
|
77
|
+
requirements:
|
78
|
+
- - ! '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
99
81
|
requirements: []
|
100
|
-
|
101
82
|
rubyforge_project:
|
102
|
-
rubygems_version: 1.
|
83
|
+
rubygems_version: 1.8.10
|
103
84
|
signing_key:
|
104
85
|
specification_version: 3
|
105
86
|
summary: Run tests / specs / features in parallel
|
106
87
|
test_files: []
|
107
|
-
|