parallel_tests 0.5.0 → 0.6.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.
- data/Readme.md +4 -5
- data/VERSION +1 -1
- data/bin/parallel_test +3 -3
- data/lib/parallel_tests.rb +27 -18
- data/lib/parallel_tests/tasks.rb +7 -7
- data/parallel_tests.gemspec +2 -2
- data/spec/integration_spec.rb +6 -9
- data/spec/parallel_tests_spec.rb +52 -4
- data/spec/spec_helper.rb +1 -1
- metadata +4 -4
data/Readme.md
CHANGED
@@ -61,13 +61,12 @@ OR as plugin
|
|
61
61
|
rake parallel:test --> got 4 CPUs? --> 26 seconds
|
62
62
|
...
|
63
63
|
|
64
|
-
Test
|
64
|
+
Test by pattern (e.g. use one integration server per subfolder / see if you broke any user-related tests)
|
65
65
|
|
66
|
-
rake parallel:test[
|
67
|
-
rake parallel:test[
|
66
|
+
rake parallel:test[^unit] # everything in test/unit folder (every test file matching /^unit/)
|
67
|
+
rake parallel:test[user] # run users_controller + user_helper + user tests
|
68
|
+
rake parallel:test['user|product'] # run user and product related tests
|
68
69
|
|
69
|
-
partial paths are OK too...
|
70
|
-
rake parallel:test[functional] == rake parallel:test[fun]
|
71
70
|
|
72
71
|
Example output
|
73
72
|
--------------
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.6.0
|
data/bin/parallel_test
CHANGED
@@ -17,7 +17,7 @@ Run all tests in parallel, giving each process ENV['TEST_ENV_NUMBER'] ('', '2',
|
|
17
17
|
Options are:
|
18
18
|
BANNER
|
19
19
|
opts.on("-n [PROCESSES]", Integer, "How many processes to use, default: available CPUs"){|n| options[:count] = n }
|
20
|
-
opts.on("-p", '--
|
20
|
+
opts.on("-p", '--pattern [PATTERN]', "run tests matching this pattern"){|pattern| options[:pattern] = pattern }
|
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 }
|
@@ -60,10 +60,10 @@ else
|
|
60
60
|
|
61
61
|
start = Time.now
|
62
62
|
|
63
|
-
tests_folder =
|
63
|
+
tests_folder = task
|
64
64
|
tests_folder = File.join(options[:root], tests_folder) unless options[:root].to_s.empty?
|
65
65
|
|
66
|
-
groups = klass.tests_in_groups(options[:files] || tests_folder, num_processes, :no_sort => options[:no_sort])
|
66
|
+
groups = klass.tests_in_groups(options[:files] || tests_folder, num_processes, :no_sort => options[:no_sort], :pattern => options[:pattern])
|
67
67
|
num_processes = groups.size
|
68
68
|
|
69
69
|
#adjust processes to groups
|
data/lib/parallel_tests.rb
CHANGED
@@ -5,26 +5,31 @@ require 'parallel_tests/railtie'
|
|
5
5
|
class ParallelTests
|
6
6
|
VERSION = File.read( File.join(File.dirname(__FILE__),'..','VERSION') ).strip
|
7
7
|
|
8
|
-
# parallel:spec[
|
8
|
+
# parallel:spec[:count, :pattern, :options]
|
9
9
|
def self.parse_rake_args(args)
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
10
|
+
# order as given by user
|
11
|
+
args = [args[:count], args[:pattern], args[:options]]
|
12
|
+
|
13
|
+
# count given or empty ?
|
14
|
+
# parallel:spec[2,models,options]
|
15
|
+
# parallel:spec[,models,options]
|
16
|
+
count = args.shift if args.first.to_s =~ /^\d*$/
|
17
|
+
num_processes = (count.to_s.empty? ? Parallel.processor_count : count.to_i)
|
18
|
+
|
19
|
+
pattern = args.shift
|
20
|
+
options = args.shift
|
21
|
+
|
22
|
+
[num_processes.to_i, pattern.to_s, options.to_s]
|
20
23
|
end
|
21
24
|
|
22
25
|
# finds all tests and partitions them into groups
|
23
26
|
def self.tests_in_groups(root, num_groups, options={})
|
27
|
+
tests = find_tests(root, options)
|
24
28
|
if options[:no_sort] == true
|
25
|
-
Grouper.in_groups(
|
29
|
+
Grouper.in_groups(tests, num_groups)
|
26
30
|
else
|
27
|
-
|
31
|
+
tests = with_runtime_info(tests)
|
32
|
+
Grouper.in_even_groups_by_size(tests, num_groups)
|
28
33
|
end
|
29
34
|
end
|
30
35
|
|
@@ -91,7 +96,7 @@ class ParallelTests
|
|
91
96
|
|
92
97
|
# copied from http://github.com/carlhuda/bundler Bundler::SharedHelpers#find_gemfile
|
93
98
|
def self.bundler_enabled?
|
94
|
-
return true if Object.const_defined?(:Bundler)
|
99
|
+
return true if Object.const_defined?(:Bundler)
|
95
100
|
|
96
101
|
previous = nil
|
97
102
|
current = File.expand_path(Dir.pwd)
|
@@ -113,8 +118,7 @@ class ParallelTests
|
|
113
118
|
"_test.rb"
|
114
119
|
end
|
115
120
|
|
116
|
-
def self.
|
117
|
-
tests = find_tests(root)
|
121
|
+
def self.with_runtime_info(tests)
|
118
122
|
lines = File.read(runtime_log).split("\n") rescue []
|
119
123
|
|
120
124
|
# use recorded test runtime if we got enough data
|
@@ -131,11 +135,16 @@ class ParallelTests
|
|
131
135
|
end
|
132
136
|
end
|
133
137
|
|
134
|
-
def self.find_tests(root)
|
138
|
+
def self.find_tests(root, options={})
|
135
139
|
if root.is_a?(Array)
|
136
140
|
root
|
137
141
|
else
|
138
|
-
|
142
|
+
# follow one symlink and direct children
|
143
|
+
# http://stackoverflow.com/questions/357754/can-i-traverse-symlinked-directories-in-ruby-with-a-glob
|
144
|
+
files = Dir["#{root}/**{,/*/**}/*#{test_suffix}"].uniq
|
145
|
+
files = files.map{|f| f.sub(root+'/','') }
|
146
|
+
files = files.grep(/#{options[:pattern]}/)
|
147
|
+
files.map{|f| "#{root}/#{f}" }
|
139
148
|
end
|
140
149
|
end
|
141
150
|
end
|
data/lib/parallel_tests/tasks.rb
CHANGED
@@ -43,12 +43,12 @@ namespace :parallel do
|
|
43
43
|
|
44
44
|
['test', 'spec', 'features'].each do |type|
|
45
45
|
desc "run #{type} in parallel with parallel:#{type}[num_cpus]"
|
46
|
-
task type, :count, :
|
46
|
+
task type, :count, :pattern, :options do |t,args|
|
47
47
|
$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
48
48
|
require "parallel_tests"
|
49
|
-
count,
|
49
|
+
count, pattern, options = ParallelTests.parse_rake_args(args)
|
50
50
|
executable = File.join(File.dirname(__FILE__), '..', '..', 'bin', 'parallel_test')
|
51
|
-
command = "#{executable} --type #{type} -n #{count} -p '#{
|
51
|
+
command = "#{executable} --type #{type} -n #{count} -p '#{pattern}' -r '#{Rails.root}' -o '#{options}'"
|
52
52
|
abort unless system(command) # allow to chain tasks e.g. rake parallel:spec parallel:features
|
53
53
|
end
|
54
54
|
end
|
@@ -66,15 +66,15 @@ namespace :spec do
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
-
task :parallel, :count, :
|
69
|
+
task :parallel, :count, :pattern do |t,args|
|
70
70
|
$stderr.puts "WARNING -- Deprecated! use parallel:spec"
|
71
|
-
Rake::Task['parallel:spec'].invoke(args[:count], args[:
|
71
|
+
Rake::Task['parallel:spec'].invoke(args[:count], args[:pattern])
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
75
|
namespace :test do
|
76
|
-
task :parallel, :count, :
|
76
|
+
task :parallel, :count, :pattern do |t,args|
|
77
77
|
$stderr.puts "WARNING -- Deprecated! use parallel:test"
|
78
|
-
Rake::Task['parallel:test'].invoke(args[:count], args[:
|
78
|
+
Rake::Task['parallel:test'].invoke(args[:count], args[:pattern])
|
79
79
|
end
|
80
80
|
end
|
data/parallel_tests.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{parallel_tests}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.6.0"
|
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 = %q{2011-
|
12
|
+
s.date = %q{2011-08-09}
|
13
13
|
s.email = %q{grosser.michael@gmail.com}
|
14
14
|
s.executables = ["parallel_cucumber", "parallel_test", "parallel_spec"]
|
15
15
|
s.files = [
|
data/spec/integration_spec.rb
CHANGED
@@ -59,8 +59,8 @@ describe 'CLI' do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
it "can exec given commands with ENV['TEST_ENV_NUM']" do
|
62
|
-
result = `#{executable} -e 'ruby -e "
|
63
|
-
result.
|
62
|
+
result = `#{executable} -e 'ruby -e "print ENV[:TEST_ENV_NUMBER.to_s].to_i"' -n 4`
|
63
|
+
result.gsub('"','').split('').sort.should == %w[0 2 3 4]
|
64
64
|
end
|
65
65
|
|
66
66
|
it "can exec given command non-parallel" do
|
@@ -83,14 +83,11 @@ describe 'CLI' do
|
|
83
83
|
end
|
84
84
|
|
85
85
|
it "runs faster with more processes" do
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
write 'xxx4_spec.rb', 'describe("it"){it("should"){sleep 2}}'
|
90
|
-
write 'xxx5_spec.rb', 'describe("it"){it("should"){sleep 2}}'
|
91
|
-
write 'xxx6_spec.rb', 'describe("it"){it("should"){sleep 2}}'
|
86
|
+
2.times{|i|
|
87
|
+
write "xxx#{i}_spec.rb", 'describe("it"){it("should"){sleep 5}}; $stderr.puts ENV["TEST_ENV_NUMBER"]'
|
88
|
+
}
|
92
89
|
t = Time.now
|
93
|
-
run_specs
|
90
|
+
puts run_specs(:processes => 2)
|
94
91
|
expected = 10
|
95
92
|
(Time.now - t).should <= expected
|
96
93
|
end
|
data/spec/parallel_tests_spec.rb
CHANGED
@@ -14,13 +14,13 @@ describe ParallelTests do
|
|
14
14
|
ParallelTests.parse_rake_args(args).should == [Parallel.processor_count, "models", ""]
|
15
15
|
end
|
16
16
|
|
17
|
-
it "should return the count and
|
18
|
-
args = {:count => 2, :
|
17
|
+
it "should return the count and pattern" do
|
18
|
+
args = {:count => 2, :pattern => "models"}
|
19
19
|
ParallelTests.parse_rake_args(args).should == [2, "models", ""]
|
20
20
|
end
|
21
21
|
|
22
|
-
it "should return the count,
|
23
|
-
args = {:count => 2, :
|
22
|
+
it "should return the count, pattern, and options" do
|
23
|
+
args = {:count => 2, :pattern => "plain", :options => "-p default" }
|
24
24
|
ParallelTests.parse_rake_args(args).should == [2, "plain", "-p default"]
|
25
25
|
end
|
26
26
|
end
|
@@ -136,6 +136,54 @@ EOF
|
|
136
136
|
end
|
137
137
|
end
|
138
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
|
+
|
139
187
|
it "has a version" do
|
140
188
|
ParallelTests::VERSION.should =~ /^\d+\.\d+\.\d+$/
|
141
189
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -64,7 +64,7 @@ def test_tests_in_groups(klass, folder, suffix)
|
|
64
64
|
|
65
65
|
it "groups when given an array of files" do
|
66
66
|
list_of_files = Dir["#{test_root}/**/*#{suffix}"]
|
67
|
-
found = klass.
|
67
|
+
found = klass.with_runtime_info(list_of_files)
|
68
68
|
found.should =~ list_of_files.map{ |file| [file, File.stat(file).size]}
|
69
69
|
end
|
70
70
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parallel_tests
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 7
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 6
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.6.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Michael Grosser
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-08-09 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|