parallel_tests 0.9.4 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +4 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +2 -2
- data/Readme.md +5 -1
- data/bin/parallel_cucumber +4 -1
- data/bin/parallel_rspec +4 -1
- data/bin/parallel_test +2 -3
- data/lib/parallel_tests.rb +7 -5
- data/lib/parallel_tests/cli.rb +37 -32
- data/lib/parallel_tests/cucumber/runner.rb +3 -1
- data/lib/parallel_tests/rspec/runner.rb +3 -1
- data/lib/parallel_tests/test/runner.rb +6 -0
- data/lib/parallel_tests/version.rb +1 -1
- data/spec/parallel_tests/cli_spec.rb +41 -10
- data/spec/parallel_tests/cucumber/runner_spec.rb +2 -1
- data/spec/parallel_tests/rspec/runner_spec.rb +2 -1
- data/spec/parallel_tests/test/runner_spec.rb +2 -1
- data/spec/spec_helper.rb +4 -7
- metadata +5 -4
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/Readme.md
CHANGED
@@ -26,7 +26,11 @@ gem "parallel", :group => :development
|
|
26
26
|
```
|
27
27
|
|
28
28
|
### Add to `config/database.yml`
|
29
|
-
ParallelTests uses 1 database per test-process
|
29
|
+
ParallelTests uses 1 database per test-process.
|
30
|
+
<table>
|
31
|
+
<tr><td>Process number</td><td>1</td><td>2</td><td>3</td></tr>
|
32
|
+
<tr><td>`ENV['TEST_ENV_NUMBER']`</td><td>''</td><td>'2'</td><td>'3'</td></tr>
|
33
|
+
</table>
|
30
34
|
|
31
35
|
```yaml
|
32
36
|
test:
|
data/bin/parallel_cucumber
CHANGED
@@ -1,2 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
2
|
+
$LOAD_PATH << File.expand_path("../../lib", __FILE__)
|
3
|
+
require "parallel_tests"
|
4
|
+
|
5
|
+
ParallelTests::CLI.new.run(["--type", "cucumber"] + ARGV)
|
data/bin/parallel_rspec
CHANGED
data/bin/parallel_test
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
$LOAD_PATH << File.
|
2
|
+
$LOAD_PATH << File.expand_path("../../lib", __FILE__)
|
3
3
|
require "parallel_tests"
|
4
|
-
require "parallel_tests/cli"
|
5
4
|
|
6
|
-
|
5
|
+
ParallelTests::CLI.new.run(["--type", "test"] + ARGV)
|
data/lib/parallel_tests.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require 'parallel_tests/grouper'
|
4
|
-
require 'parallel_tests/railtie' if defined? Rails::Railtie
|
1
|
+
require "parallel"
|
2
|
+
require "parallel_tests/railtie" if defined? Rails::Railtie
|
5
3
|
|
6
4
|
module ParallelTests
|
7
5
|
GREP_PROCESSES_COMMAND = "ps -ef | grep [T]EST_ENV_NUMBER= 2>&1"
|
8
6
|
|
7
|
+
autoload :CLI, "parallel_tests/cli"
|
8
|
+
autoload :VERSION, "parallel_tests/version"
|
9
|
+
autoload :Grouper, "parallel_tests/grouper"
|
10
|
+
|
9
11
|
def self.determine_number_of_processes(count)
|
10
12
|
[
|
11
13
|
count,
|
12
|
-
ENV[
|
14
|
+
ENV["PARALLEL_TEST_PROCESSORS"],
|
13
15
|
Parallel.processor_count
|
14
16
|
].detect{|c| not c.to_s.strip.empty? }.to_i
|
15
17
|
end
|
data/lib/parallel_tests/cli.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
require 'optparse'
|
2
|
-
require 'parallel_tests/test/runner'
|
3
2
|
|
4
|
-
module
|
5
|
-
|
6
|
-
def
|
3
|
+
module ParallelTests
|
4
|
+
class CLI
|
5
|
+
def run(argv)
|
7
6
|
options = parse_options!(argv)
|
8
7
|
|
9
8
|
num_processes = ParallelTests.determine_number_of_processes(options[:count])
|
@@ -18,57 +17,50 @@ module ParallelTest
|
|
18
17
|
|
19
18
|
private
|
20
19
|
|
21
|
-
def
|
20
|
+
def run_tests_in_parallel(num_processes, options)
|
22
21
|
test_results = nil
|
23
|
-
lib = options[:type] || 'test'
|
24
|
-
runner = load_runner_for(lib)
|
25
22
|
|
26
23
|
report_time_taken do
|
27
|
-
groups = runner.tests_in_groups(options[:files], num_processes, options)
|
28
|
-
report_number_of_tests(
|
24
|
+
groups = @runner.tests_in_groups(options[:files], num_processes, options)
|
25
|
+
report_number_of_tests(groups)
|
29
26
|
|
30
27
|
test_results = Parallel.map(groups, :in_processes => groups.size) do |group|
|
31
|
-
run_tests(
|
28
|
+
run_tests(group, groups.index(group), num_processes, options)
|
32
29
|
end
|
33
30
|
|
34
|
-
report_results(
|
31
|
+
report_results(test_results)
|
35
32
|
end
|
36
33
|
|
37
|
-
abort final_fail_message
|
34
|
+
abort final_fail_message if any_test_failed?(test_results)
|
38
35
|
end
|
39
36
|
|
40
|
-
def
|
37
|
+
def run_tests(group, process_number, num_processes, options)
|
41
38
|
if group.empty?
|
42
39
|
{:stdout => '', :exit_status => 0}
|
43
40
|
else
|
44
|
-
runner.run_tests(group, process_number, num_processes, options)
|
41
|
+
@runner.run_tests(group, process_number, num_processes, options)
|
45
42
|
end
|
46
43
|
end
|
47
44
|
|
48
|
-
def
|
49
|
-
results = runner.find_results(test_results.map { |result| result[:stdout] }*"")
|
45
|
+
def report_results(test_results)
|
46
|
+
results = @runner.find_results(test_results.map { |result| result[:stdout] }*"")
|
50
47
|
puts ""
|
51
|
-
puts runner.summarize_results(results)
|
48
|
+
puts @runner.summarize_results(results)
|
52
49
|
end
|
53
50
|
|
54
|
-
def
|
55
|
-
name = runner.test_file_name
|
51
|
+
def report_number_of_tests(groups)
|
52
|
+
name = @runner.test_file_name
|
56
53
|
num_processes = groups.size
|
57
54
|
num_tests = groups.map(&:size).inject(:+)
|
58
55
|
puts "#{num_processes} processes for #{num_tests} #{name}s, ~ #{num_tests / groups.size} #{name}s per process"
|
59
56
|
end
|
60
57
|
|
61
58
|
#exit with correct status code so rake parallel:test && echo 123 works
|
62
|
-
def
|
59
|
+
def any_test_failed?(test_results)
|
63
60
|
test_results.any? { |result| result[:exit_status] != 0 }
|
64
61
|
end
|
65
62
|
|
66
|
-
def
|
67
|
-
require "parallel_tests/#{lib}/runner"
|
68
|
-
eval("ParallelTests::#{lib.capitalize.sub('Rspec','RSpec')}::Runner")
|
69
|
-
end
|
70
|
-
|
71
|
-
def self.parse_options!(argv)
|
63
|
+
def parse_options!(argv)
|
72
64
|
options = {}
|
73
65
|
OptionParser.new do |opts|
|
74
66
|
opts.banner = <<BANNER
|
@@ -105,7 +97,14 @@ TEXT
|
|
105
97
|
|
106
98
|
opts.on("-e", "--exec [COMMAND]", "execute this code parallel and with ENV['TEST_ENV_NUM']") { |path| options[:execute] = path }
|
107
99
|
opts.on("-o", "--test-options '[OPTIONS]'", "execute test commands with those options") { |arg| options[:test_options] = arg }
|
108
|
-
opts.on("-t", "--type [TYPE]", "test(default) / rspec / cucumber")
|
100
|
+
opts.on("-t", "--type [TYPE]", "test(default) / rspec / cucumber") do |type|
|
101
|
+
begin
|
102
|
+
@runner = load_runner(type)
|
103
|
+
rescue NameError, LoadError => e
|
104
|
+
puts "Runner for `#{type}` type has not been found! (#{e})"
|
105
|
+
abort
|
106
|
+
end
|
107
|
+
end
|
109
108
|
opts.on("--non-parallel", "execute same commands but do not in parallel, needs --exec") { options[:non_parallel] = true }
|
110
109
|
opts.on("--no-symlinks", "Do not traverse symbolic links to find test files") { options[:symlinks] = false }
|
111
110
|
opts.on('--ignore-tags [PATTERN]', 'When counting steps ignore scenarios with tags that match this pattern') { |arg| options[:ignore_tag_pattern] = arg }
|
@@ -124,7 +123,13 @@ TEXT
|
|
124
123
|
options
|
125
124
|
end
|
126
125
|
|
127
|
-
def
|
126
|
+
def load_runner(type)
|
127
|
+
require "parallel_tests/#{type}/runner"
|
128
|
+
klass_name = "ParallelTests::#{type.capitalize.sub("Rspec", "RSpec")}::Runner"
|
129
|
+
klass_name.split('::').inject(Object) { |x, y| x.const_get(y) }
|
130
|
+
end
|
131
|
+
|
132
|
+
def execute_shell_command_in_parallel(command, num_processes, options)
|
128
133
|
runs = (0...num_processes).to_a
|
129
134
|
results = if options[:non_parallel]
|
130
135
|
runs.map do |i|
|
@@ -139,20 +144,20 @@ TEXT
|
|
139
144
|
abort if results.any? { |r| r[:exit_status] != 0 }
|
140
145
|
end
|
141
146
|
|
142
|
-
def
|
147
|
+
def report_time_taken
|
143
148
|
start = Time.now
|
144
149
|
yield
|
145
150
|
puts "\nTook #{Time.now - start} seconds"
|
146
151
|
end
|
147
152
|
|
148
|
-
def
|
149
|
-
fail_message = "#{
|
153
|
+
def final_fail_message
|
154
|
+
fail_message = "#{@runner.name}s Failed"
|
150
155
|
fail_message = "\e[31m#{fail_message}\e[0m" if use_colors?
|
151
156
|
|
152
157
|
fail_message
|
153
158
|
end
|
154
159
|
|
155
|
-
def
|
160
|
+
def use_colors?
|
156
161
|
$stdout.tty?
|
157
162
|
end
|
158
163
|
end
|
@@ -1,8 +1,10 @@
|
|
1
|
-
require
|
1
|
+
require "parallel_tests/test/runner"
|
2
2
|
|
3
3
|
module ParallelTests
|
4
4
|
module Cucumber
|
5
5
|
class Runner < ParallelTests::Test::Runner
|
6
|
+
NAME = 'Cucumber'
|
7
|
+
|
6
8
|
def self.run_tests(test_files, process_number, num_processes, options)
|
7
9
|
color = ($stdout.tty? ? 'AUTOTEST=1 ; export AUTOTEST ;' : '')#display color when we are in a terminal
|
8
10
|
runtime_logging = " --format ParallelTests::Cucumber::RuntimeLogger --out #{runtime_log}"
|
@@ -1,8 +1,10 @@
|
|
1
|
-
require
|
1
|
+
require "parallel_tests/test/runner"
|
2
2
|
|
3
3
|
module ParallelTests
|
4
4
|
module RSpec
|
5
5
|
class Runner < ParallelTests::Test::Runner
|
6
|
+
NAME = 'RSpec'
|
7
|
+
|
6
8
|
def self.run_tests(test_files, process_number, num_processes, options)
|
7
9
|
exe = executable # expensive, so we cache
|
8
10
|
version = (exe =~ /\brspec\b/ ? 2 : 1)
|
@@ -1,12 +1,16 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "spec_helper"
|
2
|
+
require "parallel_tests/cli"
|
3
|
+
require "parallel_tests/rspec/runner"
|
3
4
|
|
4
|
-
|
5
|
-
|
5
|
+
|
6
|
+
describe ParallelTests::CLI do
|
7
|
+
subject { ParallelTests::CLI.new }
|
8
|
+
|
9
|
+
describe "#parse_options" do
|
6
10
|
let(:defaults){ {:files => []} }
|
7
11
|
|
8
12
|
def call(*args)
|
9
|
-
|
13
|
+
subject.send(:parse_options!, *args)
|
10
14
|
end
|
11
15
|
|
12
16
|
it "parses regular count" do
|
@@ -20,17 +24,44 @@ describe ParallelTest::CLI do
|
|
20
24
|
it "parses non-parallel as non-parallel" do
|
21
25
|
call(["--non-parallel"]).should == defaults.merge(:non_parallel => true)
|
22
26
|
end
|
27
|
+
|
28
|
+
it "finds the correct type when multiple are given" do
|
29
|
+
call(["--type", "test", "-t", "rspec"])
|
30
|
+
subject.instance_variable_get(:@runner).should == ParallelTests::RSpec::Runner
|
31
|
+
end
|
23
32
|
end
|
24
33
|
|
25
|
-
describe "
|
34
|
+
describe "#load_runner" do
|
35
|
+
it "requires and loads default runner" do
|
36
|
+
subject.should_receive(:require).with("parallel_tests/test/runner")
|
37
|
+
subject.send(:load_runner, "test").should == ParallelTests::Test::Runner
|
38
|
+
end
|
39
|
+
|
40
|
+
it "requires and loads rspec runner" do
|
41
|
+
subject.should_receive(:require).with("parallel_tests/rspec/runner")
|
42
|
+
subject.send(:load_runner, "rspec").should == ParallelTests::RSpec::Runner
|
43
|
+
end
|
44
|
+
|
45
|
+
it "fails to load unfindable runner" do
|
46
|
+
expect{
|
47
|
+
subject.send(:load_runner, "foo").should == ParallelTests::RSpec::Runner
|
48
|
+
}.to raise_error(LoadError)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#final_fail_message" do
|
53
|
+
before do
|
54
|
+
subject.instance_variable_set(:@runner, ParallelTests::Test::Runner)
|
55
|
+
end
|
56
|
+
|
26
57
|
it 'returns a plain fail message if colors are nor supported' do
|
27
|
-
|
28
|
-
|
58
|
+
subject.should_receive(:use_colors?).and_return(false)
|
59
|
+
subject.send(:final_fail_message).should == "Tests Failed"
|
29
60
|
end
|
30
61
|
|
31
62
|
it 'returns a colorized fail message if colors are supported' do
|
32
|
-
|
33
|
-
|
63
|
+
subject.should_receive(:use_colors?).and_return(true)
|
64
|
+
subject.send(:final_fail_message).should == "\e[31mTests Failed\e[0m"
|
34
65
|
end
|
35
66
|
end
|
36
67
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -3,15 +3,12 @@ $LOAD_PATH << File.expand_path("../lib", File.dirname(__FILE__))
|
|
3
3
|
FAKE_RAILS_ROOT = './tmp/pspecs/fixtures'
|
4
4
|
|
5
5
|
require 'tempfile'
|
6
|
+
|
6
7
|
require 'parallel_tests'
|
7
|
-
require 'parallel_tests/test/runner'
|
8
8
|
require 'parallel_tests/test/runtime_logger'
|
9
|
-
|
10
|
-
require 'parallel_tests/rspec/runner'
|
11
9
|
require 'parallel_tests/rspec/runtime_logger'
|
12
10
|
require 'parallel_tests/rspec/summary_logger'
|
13
11
|
|
14
|
-
require 'parallel_tests/cucumber/runner'
|
15
12
|
|
16
13
|
OutputLogger = Struct.new(:output) do
|
17
14
|
attr_reader :flock, :flush
|
@@ -62,7 +59,7 @@ def test_tests_in_groups(klass, folder, suffix)
|
|
62
59
|
test_root = "#{FAKE_RAILS_ROOT}/#{folder}"
|
63
60
|
|
64
61
|
describe :tests_in_groups do
|
65
|
-
before
|
62
|
+
before do
|
66
63
|
system "rm -rf #{FAKE_RAILS_ROOT}; mkdir -p #{test_root}/temp"
|
67
64
|
|
68
65
|
@files = [0,1,2,3,4,5,6,7].map do |i|
|
@@ -77,8 +74,8 @@ def test_tests_in_groups(klass, folder, suffix)
|
|
77
74
|
`rm -f #{@log}`
|
78
75
|
end
|
79
76
|
|
80
|
-
after
|
81
|
-
`rm -f #{
|
77
|
+
after do
|
78
|
+
`rm -f #{@log}`
|
82
79
|
end
|
83
80
|
|
84
81
|
def setup_runtime_log
|
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.
|
4
|
+
version: 0.10.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
12
|
+
date: 2013-02-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: parallel
|
@@ -38,6 +38,7 @@ extra_rdoc_files: []
|
|
38
38
|
files:
|
39
39
|
- .gitignore
|
40
40
|
- .rspec
|
41
|
+
- .travis.yml
|
41
42
|
- Gemfile
|
42
43
|
- Gemfile.lock
|
43
44
|
- Rakefile
|
@@ -92,7 +93,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
92
93
|
version: '0'
|
93
94
|
segments:
|
94
95
|
- 0
|
95
|
-
hash:
|
96
|
+
hash: 1708090776445772692
|
96
97
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
98
|
none: false
|
98
99
|
requirements:
|
@@ -101,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
102
|
version: '0'
|
102
103
|
segments:
|
103
104
|
- 0
|
104
|
-
hash:
|
105
|
+
hash: 1708090776445772692
|
105
106
|
requirements: []
|
106
107
|
rubyforge_project:
|
107
108
|
rubygems_version: 1.8.24
|