phene-parallel_tests 0.6.2
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/Gemfile +9 -0
- data/Gemfile.lock +28 -0
- data/Rakefile +20 -0
- data/Readme.md +219 -0
- data/VERSION +1 -0
- data/bin/parallel_cucumber +2 -0
- data/bin/parallel_spec +2 -0
- data/bin/parallel_test +91 -0
- data/lib/parallel_cucumber.rb +36 -0
- data/lib/parallel_cucumber/runtime_logger.rb +57 -0
- data/lib/parallel_specs.rb +51 -0
- data/lib/parallel_specs/spec_failures_logger.rb +25 -0
- data/lib/parallel_specs/spec_logger_base.rb +72 -0
- data/lib/parallel_specs/spec_runtime_logger.rb +28 -0
- data/lib/parallel_specs/spec_summary_logger.rb +47 -0
- data/lib/parallel_tests.rb +160 -0
- data/lib/parallel_tests/grouper.rb +31 -0
- data/lib/parallel_tests/railtie.rb +10 -0
- data/lib/parallel_tests/tasks.rb +80 -0
- data/lib/tasks/parallel_tests.rake +1 -0
- data/parallel_tests.gemspec +60 -0
- data/spec/integration_spec.rb +113 -0
- data/spec/parallel_cucumber_spec.rb +72 -0
- data/spec/parallel_specs_spec.rb +264 -0
- data/spec/parallel_tests_spec.rb +212 -0
- data/spec/spec_helper.rb +115 -0
- metadata +106 -0
@@ -0,0 +1,212 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ParallelTests do
|
4
|
+
test_tests_in_groups(ParallelTests, 'test', '_test.rb')
|
5
|
+
|
6
|
+
describe :parse_rake_args do
|
7
|
+
it "should return the count" do
|
8
|
+
args = {:count => 2}
|
9
|
+
ParallelTests.parse_rake_args(args).should == [2, '', ""]
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should default to the prefix" do
|
13
|
+
args = {:count => "models"}
|
14
|
+
ParallelTests.parse_rake_args(args).should == [Parallel.processor_count, "models", ""]
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should return the count and pattern" do
|
18
|
+
args = {:count => 2, :pattern => "models"}
|
19
|
+
ParallelTests.parse_rake_args(args).should == [2, "models", ""]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return the count, pattern, and options" do
|
23
|
+
args = {:count => 2, :pattern => "plain", :options => "-p default" }
|
24
|
+
ParallelTests.parse_rake_args(args).should == [2, "plain", "-p default"]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe :run_tests do
|
29
|
+
it "uses TEST_ENV_NUMBER=blank when called for process 0" do
|
30
|
+
ParallelTests.should_receive(:open).with{|x,y|x=~/TEST_ENV_NUMBER= /}.and_return mocked_process
|
31
|
+
ParallelTests.run_tests(['xxx'],0,{})
|
32
|
+
end
|
33
|
+
|
34
|
+
it "uses TEST_ENV_NUMBER=2 when called for process 1" do
|
35
|
+
ParallelTests.should_receive(:open).with{|x,y| x=~/TEST_ENV_NUMBER=2/}.and_return mocked_process
|
36
|
+
ParallelTests.run_tests(['xxx'],1,{})
|
37
|
+
end
|
38
|
+
|
39
|
+
it "uses options" do
|
40
|
+
ParallelTests.should_receive(:open).with{|x,y| x=~ %r{ruby -Itest .* - -v}}.and_return mocked_process
|
41
|
+
ParallelTests.run_tests(['xxx'],1,:test_options => '-v')
|
42
|
+
end
|
43
|
+
|
44
|
+
it "returns the output" do
|
45
|
+
io = open('spec/spec_helper.rb')
|
46
|
+
ParallelTests.stub!(:print)
|
47
|
+
ParallelTests.should_receive(:open).and_return io
|
48
|
+
ParallelTests.run_tests(['xxx'],1,{})[:stdout].should =~ /\$LOAD_PATH << File/
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe :test_in_groups do
|
53
|
+
it "does not sort when passed false do_sort option" do
|
54
|
+
ParallelTests.should_not_receive(:smallest_first)
|
55
|
+
ParallelTests.tests_in_groups [], 1, :no_sort => true
|
56
|
+
end
|
57
|
+
|
58
|
+
it "does sort when not passed do_sort option" do
|
59
|
+
ParallelTests.stub!(:tests_with_runtime).and_return([])
|
60
|
+
ParallelTests::Grouper.should_receive(:smallest_first).and_return([])
|
61
|
+
ParallelTests.tests_in_groups [], 1
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe :find_results do
|
66
|
+
it "finds multiple results in test output" do
|
67
|
+
output = <<EOF
|
68
|
+
Loaded suite /opt/ruby-enterprise/lib/ruby/gems/1.8/gems/rake-0.8.4/lib/rake/rake_test_loader
|
69
|
+
Started
|
70
|
+
..............
|
71
|
+
Finished in 0.145069 seconds.
|
72
|
+
|
73
|
+
10 tests, 20 assertions, 0 failures, 0 errors
|
74
|
+
Loaded suite /opt/ruby-enterprise/lib/ruby/gems/1.8/gems/rake-0.8.4/lib/rake/rake_test_loader
|
75
|
+
Started
|
76
|
+
..............
|
77
|
+
Finished in 0.145069 seconds.
|
78
|
+
|
79
|
+
14 tests, 20 assertions, 0 failures, 0 errors
|
80
|
+
|
81
|
+
EOF
|
82
|
+
|
83
|
+
ParallelTests.find_results(output).should == ['10 tests, 20 assertions, 0 failures, 0 errors','14 tests, 20 assertions, 0 failures, 0 errors']
|
84
|
+
end
|
85
|
+
|
86
|
+
it "is robust against scrambeled output" do
|
87
|
+
output = <<EOF
|
88
|
+
Loaded suite /opt/ruby-enterprise/lib/ruby/gems/1.8/gems/rake-0.8.4/lib/rake/rake_test_loader
|
89
|
+
Started
|
90
|
+
..............
|
91
|
+
Finished in 0.145069 seconds.
|
92
|
+
|
93
|
+
10 tests, 20 assertions, 0 failures, 0 errors
|
94
|
+
Loaded suite /opt/ruby-enterprise/lib/ruby/gems/1.8/gems/rake-0.8.4/lib/rake/rake_test_loader
|
95
|
+
Started
|
96
|
+
..............
|
97
|
+
Finished in 0.145069 seconds.
|
98
|
+
|
99
|
+
14 te.dsts, 20 assertions, 0 failures, 0 errors
|
100
|
+
EOF
|
101
|
+
|
102
|
+
ParallelTests.find_results(output).should == ['10 tests, 20 assertions, 0 failures, 0 errors','14 tedsts, 20 assertions, 0 failures, 0 errors']
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe :bundler_enabled? do
|
107
|
+
before do
|
108
|
+
Object.stub!(:const_defined?).with(:Bundler).and_return false
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should return false" do
|
112
|
+
use_temporary_directory_for do
|
113
|
+
ParallelTests.send(:bundler_enabled?).should == false
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should return true when there is a constant called Bundler" do
|
118
|
+
use_temporary_directory_for do
|
119
|
+
Object.stub!(:const_defined?).with(:Bundler).and_return true
|
120
|
+
ParallelTests.send(:bundler_enabled?).should == true
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should be true when there is a Gemfile" do
|
125
|
+
use_temporary_directory_for do
|
126
|
+
FileUtils.touch("Gemfile")
|
127
|
+
ParallelTests.send(:bundler_enabled?).should == true
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should be true when there is a Gemfile in the parent directory" do
|
132
|
+
use_temporary_directory_for do
|
133
|
+
FileUtils.touch(File.join("..", "Gemfile"))
|
134
|
+
ParallelTests.send(:bundler_enabled?).should == true
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe :find_tests do
|
140
|
+
it "returns if root is an array" do
|
141
|
+
ParallelTests.send(:find_tests, [1]).should == [1]
|
142
|
+
end
|
143
|
+
|
144
|
+
it "finds all test files" do
|
145
|
+
begin
|
146
|
+
root = "/tmp/test-find_tests-#{rand(999)}"
|
147
|
+
`mkdir #{root}`
|
148
|
+
`mkdir #{root}/a`
|
149
|
+
`mkdir #{root}/b`
|
150
|
+
`touch #{root}/x_test.rb`
|
151
|
+
`touch #{root}/a/x_test.rb`
|
152
|
+
`touch #{root}/a/test.rb`
|
153
|
+
`touch #{root}/b/y_test.rb`
|
154
|
+
`touch #{root}/b/test.rb`
|
155
|
+
`ln -s #{root}/b #{root}/c`
|
156
|
+
`ln -s #{root}/b #{root}/a/`
|
157
|
+
ParallelTests.send(:find_tests, root).sort.should == [
|
158
|
+
"#{root}/a/b/y_test.rb",
|
159
|
+
"#{root}/a/x_test.rb",
|
160
|
+
"#{root}/b/y_test.rb",
|
161
|
+
"#{root}/c/y_test.rb",
|
162
|
+
"#{root}/x_test.rb"
|
163
|
+
]
|
164
|
+
ensure
|
165
|
+
`rm -rf #{root}`
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
it "finds files by pattern" do
|
170
|
+
begin
|
171
|
+
root = "/tmp/test-find_tests-#{rand(999)}"
|
172
|
+
`mkdir #{root}`
|
173
|
+
`mkdir #{root}/a`
|
174
|
+
`touch #{root}/a/x_test.rb`
|
175
|
+
`touch #{root}/a/y_test.rb`
|
176
|
+
`touch #{root}/a/z_test.rb`
|
177
|
+
ParallelTests.send(:find_tests, root, :pattern => '^a/(y|z)_test').sort.should == [
|
178
|
+
"#{root}/a/y_test.rb",
|
179
|
+
"#{root}/a/z_test.rb",
|
180
|
+
]
|
181
|
+
ensure
|
182
|
+
`rm -rf #{root}`
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe :summarize_results do
|
188
|
+
it "adds results" do
|
189
|
+
ParallelTests.summarize_results(['1 foo 3 bar','2 foo 5 bar']).should == '8 bars, 3 foos'
|
190
|
+
end
|
191
|
+
|
192
|
+
it "adds results with braces" do
|
193
|
+
ParallelTests.summarize_results(['1 foo(s) 3 bar(s)','2 foo 5 bar']).should == '8 bars, 3 foos'
|
194
|
+
end
|
195
|
+
|
196
|
+
it "adds same results with plurals" do
|
197
|
+
ParallelTests.summarize_results(['1 foo 3 bar','2 foos 5 bar']).should == '8 bars, 3 foos'
|
198
|
+
end
|
199
|
+
|
200
|
+
it "adds non-similar results" do
|
201
|
+
ParallelTests.summarize_results(['1 xxx 2 yyy','1 xxx 2 zzz']).should == '2 xxxs, 2 yyys, 2 zzzs'
|
202
|
+
end
|
203
|
+
|
204
|
+
it "does not pluralize 1" do
|
205
|
+
ParallelTests.summarize_results(['1 xxx 2 yyy']).should == '1 xxx, 2 yyys'
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
it "has a version" do
|
210
|
+
ParallelTests::VERSION.should =~ /^\d+\.\d+\.\d+$/
|
211
|
+
end
|
212
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
# ---- requirements
|
2
|
+
$LOAD_PATH << File.expand_path("../lib", File.dirname(__FILE__))
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
FAKE_RAILS_ROOT = '/tmp/pspecs/fixtures'
|
6
|
+
|
7
|
+
require 'parallel_specs'
|
8
|
+
require 'parallel_cucumber'
|
9
|
+
|
10
|
+
def mocked_process
|
11
|
+
open('|cat /dev/null')
|
12
|
+
end
|
13
|
+
|
14
|
+
def size_of(group)
|
15
|
+
group.inject(0) { |sum, test| sum += File.stat(test).size }
|
16
|
+
end
|
17
|
+
|
18
|
+
# Uses /tmp/parallel_tests/application as the cwd so we can create and remove
|
19
|
+
# files as we want to. After execution it changes cwd back to the original one.
|
20
|
+
def use_temporary_directory_for
|
21
|
+
require 'fileutils'
|
22
|
+
|
23
|
+
dir = File.join("/tmp", "parallel_tests")
|
24
|
+
new_dir = File.join(dir, "application")
|
25
|
+
|
26
|
+
begin
|
27
|
+
# just in case the temporary dir already exists
|
28
|
+
FileUtils.rm_rf(dir) if File.exists?(dir)
|
29
|
+
|
30
|
+
# create the temporary directory
|
31
|
+
FileUtils.mkdir_p(new_dir)
|
32
|
+
|
33
|
+
# chdir changes cwd back to the original one after it is done
|
34
|
+
Dir.chdir(new_dir) do
|
35
|
+
yield
|
36
|
+
end
|
37
|
+
ensure
|
38
|
+
FileUtils.rm_rf(dir) if File.exists?(dir)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_tests_in_groups(klass, folder, suffix)
|
43
|
+
test_root = "#{FAKE_RAILS_ROOT}/#{folder}"
|
44
|
+
|
45
|
+
describe :tests_in_groups do
|
46
|
+
before :all do
|
47
|
+
system "rm -rf #{FAKE_RAILS_ROOT}; mkdir -p #{test_root}/temp"
|
48
|
+
|
49
|
+
@files = [0,1,2,3,4,5,6,7].map do |i|
|
50
|
+
size = 99
|
51
|
+
file = "#{test_root}/temp/x#{i}#{suffix}"
|
52
|
+
File.open(file, 'w') { |f| f.puts 'x' * size }
|
53
|
+
file
|
54
|
+
end
|
55
|
+
|
56
|
+
@log = klass.runtime_log
|
57
|
+
`mkdir -p #{File.dirname(@log)}`
|
58
|
+
`rm -f #{@log}`
|
59
|
+
end
|
60
|
+
|
61
|
+
after :all do
|
62
|
+
`rm -f #{klass.runtime_log}`
|
63
|
+
end
|
64
|
+
|
65
|
+
it "groups when given an array of files" do
|
66
|
+
list_of_files = Dir["#{test_root}/**/*#{suffix}"]
|
67
|
+
found = klass.with_runtime_info(list_of_files)
|
68
|
+
found.should =~ list_of_files.map{ |file| [file, File.stat(file).size]}
|
69
|
+
end
|
70
|
+
|
71
|
+
it "finds all tests" do
|
72
|
+
found = klass.tests_in_groups(test_root, 1)
|
73
|
+
all = [ Dir["#{test_root}/**/*#{suffix}"] ]
|
74
|
+
(found.flatten - all.flatten).should == []
|
75
|
+
end
|
76
|
+
|
77
|
+
it "partitions them into groups by equal size" do
|
78
|
+
groups = klass.tests_in_groups(test_root, 2)
|
79
|
+
groups.map{|g| size_of(g)}.should == [400, 400]
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should partition correctly with a group size of 4' do
|
83
|
+
groups = klass.tests_in_groups(test_root, 4)
|
84
|
+
groups.map{|g| size_of(g)}.should == [200, 200, 200, 200]
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should partition correctly with an uneven group size' do
|
88
|
+
groups = klass.tests_in_groups(test_root, 3)
|
89
|
+
groups.map{|g| size_of(g)}.should =~ [300, 300, 200]
|
90
|
+
end
|
91
|
+
|
92
|
+
it "partitions by runtime when runtime-data is available" do
|
93
|
+
klass.stub!(:puts)
|
94
|
+
File.open(@log,'w') do |f|
|
95
|
+
@files[1..-1].each{|file| f.puts "#{file}:#{@files.index(file)}"}
|
96
|
+
f.puts "#{@files[0]}:10"
|
97
|
+
end
|
98
|
+
|
99
|
+
groups = klass.tests_in_groups(test_root, 2)
|
100
|
+
groups.size.should == 2
|
101
|
+
# 10 + 5 + 3 + 1 = 19
|
102
|
+
groups[0].should == [@files[0],@files[5],@files[3],@files[1]]
|
103
|
+
# 7 + 6 + 4 + 2 = 19
|
104
|
+
groups[1].should == [@files[7],@files[6],@files[4],@files[2]]
|
105
|
+
end
|
106
|
+
|
107
|
+
it "partitions by round-robin when not sorting" do
|
108
|
+
files = ["file1.rb", "file2.rb", "file3.rb", "file4.rb"]
|
109
|
+
klass.should_receive(:find_tests).and_return(files)
|
110
|
+
groups = klass.tests_in_groups(files, 2, :no_sort => true)
|
111
|
+
groups[0].should == ["file1.rb", "file3.rb"]
|
112
|
+
groups[1].should == ["file2.rb", "file4.rb"]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: phene-parallel_tests
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 3
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 6
|
9
|
+
- 2
|
10
|
+
version: 0.6.2
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Michael Grosser
|
14
|
+
- Geoffrey Hichborn
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2011-08-14 00:00:00 Z
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: parallel
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
description:
|
36
|
+
email: grosser.michael@gmail.com
|
37
|
+
executables:
|
38
|
+
- parallel_cucumber
|
39
|
+
- parallel_test
|
40
|
+
- parallel_spec
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files: []
|
44
|
+
|
45
|
+
files:
|
46
|
+
- Gemfile
|
47
|
+
- Gemfile.lock
|
48
|
+
- Rakefile
|
49
|
+
- Readme.md
|
50
|
+
- VERSION
|
51
|
+
- bin/parallel_cucumber
|
52
|
+
- bin/parallel_spec
|
53
|
+
- bin/parallel_test
|
54
|
+
- lib/parallel_cucumber.rb
|
55
|
+
- lib/parallel_cucumber/runtime_logger.rb
|
56
|
+
- lib/parallel_specs.rb
|
57
|
+
- lib/parallel_specs/spec_failures_logger.rb
|
58
|
+
- lib/parallel_specs/spec_logger_base.rb
|
59
|
+
- lib/parallel_specs/spec_runtime_logger.rb
|
60
|
+
- lib/parallel_specs/spec_summary_logger.rb
|
61
|
+
- lib/parallel_tests.rb
|
62
|
+
- lib/parallel_tests/grouper.rb
|
63
|
+
- lib/parallel_tests/railtie.rb
|
64
|
+
- lib/parallel_tests/tasks.rb
|
65
|
+
- lib/tasks/parallel_tests.rake
|
66
|
+
- parallel_tests.gemspec
|
67
|
+
- spec/integration_spec.rb
|
68
|
+
- spec/parallel_cucumber_spec.rb
|
69
|
+
- spec/parallel_specs_spec.rb
|
70
|
+
- spec/parallel_tests_spec.rb
|
71
|
+
- spec/spec_helper.rb
|
72
|
+
homepage: http://github.com/grosser/parallel_tests
|
73
|
+
licenses: []
|
74
|
+
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
hash: 3
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
version: "0"
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
hash: 3
|
95
|
+
segments:
|
96
|
+
- 0
|
97
|
+
version: "0"
|
98
|
+
requirements: []
|
99
|
+
|
100
|
+
rubyforge_project:
|
101
|
+
rubygems_version: 1.8.10
|
102
|
+
signing_key:
|
103
|
+
specification_version: 3
|
104
|
+
summary: Run tests / specs / features in parallel
|
105
|
+
test_files: []
|
106
|
+
|