parallel_tests 0.6.7 → 0.6.8
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.
- 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
|
+
[](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
|
-
|