moxiesoft_parallel_tests 0.4.12
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/.gitignore +1 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +34 -0
- data/Rakefile +21 -0
- data/Readme.md +156 -0
- data/VERSION +1 -0
- data/bin/parallel_cucumber +2 -0
- data/bin/parallel_spec +2 -0
- data/bin/parallel_test +98 -0
- data/lib/parallel_cucumber.rb +29 -0
- data/lib/parallel_specs/spec_runtime_logger.rb +49 -0
- data/lib/parallel_specs.rb +48 -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/parallel_tests.rb +122 -0
- data/lib/tasks/parallel_tests.rake +1 -0
- data/spec/integration_spec.rb +114 -0
- data/spec/parallel_cucumber_spec.rb +72 -0
- data/spec/parallel_specs_spec.rb +149 -0
- data/spec/parallel_tests_spec.rb +142 -0
- data/spec/spec_helper.rb +110 -0
- metadata +104 -0
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'parallel'
|
2
|
+
require 'parallel_tests/grouper'
|
3
|
+
require 'parallel_tests/railtie'
|
4
|
+
|
5
|
+
class ParallelTests
|
6
|
+
VERSION = File.read( File.join(File.dirname(__FILE__),'..','VERSION') ).strip
|
7
|
+
|
8
|
+
# parallel:spec[2,controller] <-> parallel:spec[controller]
|
9
|
+
def self.parse_rake_args(args)
|
10
|
+
num_processes = Parallel.processor_count
|
11
|
+
options = ""
|
12
|
+
if args[:count].to_s =~ /^\d*$/ # number or empty
|
13
|
+
num_processes = args[:count] unless args[:count].to_s.empty?
|
14
|
+
prefix = args[:path_prefix]
|
15
|
+
options = args[:options] if args[:options]
|
16
|
+
else # something stringy
|
17
|
+
prefix = args[:count]
|
18
|
+
end
|
19
|
+
[num_processes.to_i, prefix.to_s, options]
|
20
|
+
end
|
21
|
+
|
22
|
+
# finds all tests and partitions them into groups
|
23
|
+
def self.tests_in_groups(root, num_groups, options={})
|
24
|
+
if root.nil?
|
25
|
+
root = ['unit', 'functional', 'integration'].collect { |dir| File.join(Dir.pwd, 'test', dir) }
|
26
|
+
end
|
27
|
+
|
28
|
+
if options[:no_sort] == true
|
29
|
+
Grouper.in_groups(find_tests(root), num_groups)
|
30
|
+
else
|
31
|
+
Grouper.in_even_groups_by_size(tests_with_runtime(root), num_groups)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.run_tests(test_files, process_number, options)
|
36
|
+
require_list = test_files.map { |filename| "\"#{filename}\"" }.join(",")
|
37
|
+
cmd = "ruby -Itest #{options} -e '[#{require_list}].each {|f| require f }'"
|
38
|
+
execute_command(cmd, process_number)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.execute_command(cmd, process_number)
|
42
|
+
cmd = "TEST_ENV_NUMBER=#{test_env_number(process_number)} ; export TEST_ENV_NUMBER; #{cmd}"
|
43
|
+
f = open("|#{cmd}", 'r')
|
44
|
+
all = ''
|
45
|
+
while char = f.getc
|
46
|
+
char = (char.is_a?(Fixnum) ? char.chr : char) # 1.8 <-> 1.9
|
47
|
+
all << char
|
48
|
+
print char
|
49
|
+
STDOUT.flush
|
50
|
+
end
|
51
|
+
f.close
|
52
|
+
{:stdout => all, :exit_status => $?.exitstatus}
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.find_results(test_output)
|
56
|
+
test_output.split("\n").map {|line|
|
57
|
+
line = line.gsub(/\.|F|\*/,'')
|
58
|
+
next unless line_is_result?(line)
|
59
|
+
line
|
60
|
+
}.compact
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.test_env_number(process_number)
|
64
|
+
process_number == 0 ? '' : process_number + 1
|
65
|
+
end
|
66
|
+
|
67
|
+
protected
|
68
|
+
|
69
|
+
# copied from http://github.com/carlhuda/bundler Bundler::SharedHelpers#find_gemfile
|
70
|
+
def self.bundler_enabled?
|
71
|
+
return true if Object.const_defined?(:Bundler)
|
72
|
+
|
73
|
+
previous = nil
|
74
|
+
current = File.expand_path(Dir.pwd)
|
75
|
+
|
76
|
+
until !File.directory?(current) || current == previous
|
77
|
+
filename = File.join(current, "Gemfile")
|
78
|
+
return true if File.exists?(filename)
|
79
|
+
current, previous = File.expand_path("..", current), current
|
80
|
+
end
|
81
|
+
|
82
|
+
false
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.line_is_result?(line)
|
86
|
+
line =~ /\d+ failure/
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.test_suffix
|
90
|
+
"_test.rb"
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.tests_with_runtime(root)
|
94
|
+
tests = find_tests(root)
|
95
|
+
runtime_file = File.join(root,'..','tmp','parallel_profile.log')
|
96
|
+
lines = File.read(runtime_file).split("\n") rescue []
|
97
|
+
|
98
|
+
# use recorded test runtime if we got enough data
|
99
|
+
if lines.size * 1.5 > tests.size
|
100
|
+
times = Hash.new(1)
|
101
|
+
lines.each do |line|
|
102
|
+
test, time = line.split(":")
|
103
|
+
times[test] = time.to_f
|
104
|
+
end
|
105
|
+
tests.sort.map{|test| [test, times[test]] }
|
106
|
+
else # use file sizes
|
107
|
+
tests.sort.map{|test| [test, File.stat(test).size] }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.find_tests(root)
|
112
|
+
if root.is_a?(Array)
|
113
|
+
if root.first && Dir.exists?(root.first)
|
114
|
+
root.collect { |dir| find_tests(dir) }.flatten
|
115
|
+
else
|
116
|
+
root
|
117
|
+
end
|
118
|
+
else
|
119
|
+
Dir["#{root}**/**/*#{self.test_suffix}"]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "/../parallel_tests/tasks")
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe 'CLI' do
|
4
|
+
before do
|
5
|
+
`rm -rf #{folder}`
|
6
|
+
end
|
7
|
+
|
8
|
+
after do
|
9
|
+
`rm -rf #{folder}`
|
10
|
+
end
|
11
|
+
|
12
|
+
def folder
|
13
|
+
"/tmp/parallel_tests_tests"
|
14
|
+
end
|
15
|
+
|
16
|
+
def write(file, content)
|
17
|
+
path = "#{folder}/spec/#{file}"
|
18
|
+
`mkdir -p #{File.dirname(path)}` unless File.exist?(File.dirname(path))
|
19
|
+
File.open(path, 'w'){|f| f.write content }
|
20
|
+
path
|
21
|
+
end
|
22
|
+
|
23
|
+
def bin_folder
|
24
|
+
"#{File.expand_path(File.dirname(__FILE__))}/../bin"
|
25
|
+
end
|
26
|
+
|
27
|
+
def executable
|
28
|
+
"#{bin_folder}/parallel_test"
|
29
|
+
end
|
30
|
+
|
31
|
+
def run_specs(options={})
|
32
|
+
`cd #{folder} && #{executable} -t spec -n #{options[:processes]||2} #{options[:add]} 2>&1`
|
33
|
+
end
|
34
|
+
|
35
|
+
it "runs tests in parallel" do
|
36
|
+
write 'xxx_spec.rb', 'describe("it"){it("should"){puts "TEST1"}}'
|
37
|
+
write 'xxx2_spec.rb', 'describe("it"){it("should"){puts "TEST2"}}'
|
38
|
+
result = run_specs
|
39
|
+
|
40
|
+
# test ran and gave their puts
|
41
|
+
result.should include('TEST1')
|
42
|
+
result.should include('TEST2')
|
43
|
+
|
44
|
+
# all results present
|
45
|
+
result.scan('1 example, 0 failure').size.should == 4 # 2 results + 2 result summary
|
46
|
+
result.scan(/Finished in \d+\.\d+ seconds/).size.should == 2
|
47
|
+
result.scan(/Took \d+\.\d+ seconds/).size.should == 1 # parallel summary
|
48
|
+
$?.success?.should == true
|
49
|
+
end
|
50
|
+
|
51
|
+
it "fails when tests fail" do
|
52
|
+
write 'xxx_spec.rb', 'describe("it"){it("should"){puts "TEST1"}}'
|
53
|
+
write 'xxx2_spec.rb', 'describe("it"){it("should"){1.should == 2}}'
|
54
|
+
result = run_specs
|
55
|
+
|
56
|
+
result.scan('1 example, 1 failure').size.should == 2
|
57
|
+
result.scan('1 example, 0 failure').size.should == 2
|
58
|
+
$?.success?.should == false
|
59
|
+
end
|
60
|
+
|
61
|
+
it "can exec given commands with ENV['TEST_ENV_NUM']" do
|
62
|
+
result = `#{executable} -e 'ruby -e "puts ENV[:TEST_ENV_NUMBER.to_s].inspect"' -n 4`
|
63
|
+
result.split("\n").sort.should == %w["" "2" "3" "4"]
|
64
|
+
end
|
65
|
+
|
66
|
+
it "can exec given command non-parallel" do
|
67
|
+
result = `#{executable} -e 'ruby -e "sleep(rand(10)/100.0); puts ENV[:TEST_ENV_NUMBER.to_s].inspect"' -n 4 --non-parallel`
|
68
|
+
result.split("\n").should == %w["" "2" "3" "4"]
|
69
|
+
end
|
70
|
+
|
71
|
+
it "exists with success if all sub-processes returned success" do
|
72
|
+
system("#{executable} -e 'cat /dev/null' -n 4").should == true
|
73
|
+
end
|
74
|
+
|
75
|
+
it "exists with failure if any sub-processes returned failure" do
|
76
|
+
system("#{executable} -e 'test -e xxxx' -n 4").should == false
|
77
|
+
end
|
78
|
+
|
79
|
+
it "can run through parallel_spec / parallel_cucumber" do
|
80
|
+
version = `#{executable} -v`
|
81
|
+
`#{bin_folder}/parallel_spec -v`.should == version
|
82
|
+
`#{bin_folder}/parallel_cucumber -v`.should == version
|
83
|
+
end
|
84
|
+
|
85
|
+
it "runs faster with more processes" do
|
86
|
+
write 'xxx_spec.rb', 'describe("it"){it("should"){sleep 2}}'
|
87
|
+
write 'xxx2_spec.rb', 'describe("it"){it("should"){sleep 2}}'
|
88
|
+
write 'xxx3_spec.rb', 'describe("it"){it("should"){sleep 2}}'
|
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}}'
|
92
|
+
t = Time.now
|
93
|
+
run_specs :processes => 6
|
94
|
+
expected = 10
|
95
|
+
(Time.now - t).should <= expected
|
96
|
+
end
|
97
|
+
|
98
|
+
it "can can with given files" do
|
99
|
+
write "x1_spec.rb", "puts '111'"
|
100
|
+
write "x2_spec.rb", "puts '222'"
|
101
|
+
write "x3_spec.rb", "puts '333'"
|
102
|
+
result = run_specs(:add => 'spec/x1_spec.rb spec/x3_spec.rb')
|
103
|
+
result.should include('111')
|
104
|
+
result.should include('333')
|
105
|
+
result.should_not include('222')
|
106
|
+
end
|
107
|
+
|
108
|
+
it "can run with test-options" do
|
109
|
+
write "x1_spec.rb", ""
|
110
|
+
write "x2_spec.rb", ""
|
111
|
+
result = run_specs(:add => "--test-options ' --version'", :processes => 2)
|
112
|
+
result.should =~ /\d+\.\d+\.\d+.*\d+\.\d+\.\d+/m # prints version twice
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ParallelCucumber do
|
4
|
+
test_tests_in_groups(ParallelCucumber, 'features', ".feature")
|
5
|
+
|
6
|
+
describe :run_tests do
|
7
|
+
before do
|
8
|
+
ParallelCucumber.stub!(:bundler_enabled?).and_return false
|
9
|
+
File.stub!(:file?).with('.bundle/environment.rb').and_return false
|
10
|
+
File.stub!(:file?).with('script/cucumber').and_return true
|
11
|
+
end
|
12
|
+
|
13
|
+
it "uses TEST_ENV_NUMBER=blank when called for process 0" do
|
14
|
+
ParallelCucumber.should_receive(:open).with{|x,y| x=~/TEST_ENV_NUMBER= /}.and_return mocked_process
|
15
|
+
ParallelCucumber.run_tests(['xxx'],0,'')
|
16
|
+
end
|
17
|
+
|
18
|
+
it "uses TEST_ENV_NUMBER=2 when called for process 1" do
|
19
|
+
ParallelCucumber.should_receive(:open).with{|x,y| x=~/TEST_ENV_NUMBER=2/}.and_return mocked_process
|
20
|
+
ParallelCucumber.run_tests(['xxx'],1,'')
|
21
|
+
end
|
22
|
+
|
23
|
+
it "returns the output" do
|
24
|
+
io = open('spec/spec_helper.rb')
|
25
|
+
ParallelCucumber.stub!(:print)
|
26
|
+
ParallelCucumber.should_receive(:open).and_return io
|
27
|
+
ParallelCucumber.run_tests(['xxx'],1,'')[:stdout].should =~ /\$LOAD_PATH << File/
|
28
|
+
end
|
29
|
+
|
30
|
+
it "runs bundle exec cucumber when on bundler 0.9" do
|
31
|
+
ParallelCucumber.stub!(:bundler_enabled?).and_return true
|
32
|
+
ParallelCucumber.should_receive(:open).with{|x,y| x =~ %r{bundle exec cucumber}}.and_return mocked_process
|
33
|
+
ParallelCucumber.run_tests(['xxx'],1,'')
|
34
|
+
end
|
35
|
+
|
36
|
+
it "runs script/cucumber when script/cucumber is found" do
|
37
|
+
ParallelCucumber.should_receive(:open).with{|x,y| x =~ %r{script/cucumber}}.and_return mocked_process
|
38
|
+
ParallelCucumber.run_tests(['xxx'],1,'')
|
39
|
+
end
|
40
|
+
|
41
|
+
it "runs cucumber by default" do
|
42
|
+
File.stub!(:file?).with('script/cucumber').and_return false
|
43
|
+
ParallelCucumber.should_receive(:open).with{|x,y| x !~ %r{(script/cucumber)|(bundle exec cucumber)}}.and_return mocked_process
|
44
|
+
ParallelCucumber.run_tests(['xxx'],1,'')
|
45
|
+
end
|
46
|
+
|
47
|
+
it "uses options passed in" do
|
48
|
+
ParallelCucumber.should_receive(:open).with{|x,y| x =~ %r{script/cucumber -p default}}.and_return mocked_process
|
49
|
+
ParallelCucumber.run_tests(['xxx'],1,'-p default')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe :find_results do
|
54
|
+
it "finds multiple results in test output" do
|
55
|
+
output = <<EOF
|
56
|
+
And I should not see "/en/" # features/step_definitions/webrat_steps.rb:87
|
57
|
+
|
58
|
+
7 scenarios (3 failed, 4 passed)
|
59
|
+
33 steps (3 failed, 2 skipped, 28 passed)
|
60
|
+
/apps/rs/features/signup.feature:2
|
61
|
+
Given I am on "/" # features/step_definitions/common_steps.rb:12
|
62
|
+
When I click "register" # features/step_definitions/common_steps.rb:6
|
63
|
+
And I should have "2" emails # features/step_definitions/user_steps.rb:25
|
64
|
+
|
65
|
+
4 scenarios (4 passed)
|
66
|
+
40 steps (40 passed)
|
67
|
+
|
68
|
+
EOF
|
69
|
+
ParallelCucumber.find_results(output).should == ["7 scenarios (3 failed, 4 passed)", "33 steps (3 failed, 2 skipped, 28 passed)", "4 scenarios (4 passed)", "40 steps (40 passed)"]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ParallelSpecs do
|
4
|
+
test_tests_in_groups(ParallelSpecs, 'spec', '_spec.rb')
|
5
|
+
|
6
|
+
describe :run_tests do
|
7
|
+
before do
|
8
|
+
File.stub!(:file?).with('script/spec').and_return false
|
9
|
+
File.stub!(:file?).with('spec/spec.opts').and_return false
|
10
|
+
File.stub!(:file?).with('spec/parallel_spec.opts').and_return false
|
11
|
+
ParallelSpecs.stub!(:bundler_enabled?).and_return false
|
12
|
+
end
|
13
|
+
|
14
|
+
it "uses TEST_ENV_NUMBER=blank when called for process 0" do
|
15
|
+
ParallelSpecs.should_receive(:open).with{|x,y|x=~/TEST_ENV_NUMBER= /}.and_return mocked_process
|
16
|
+
ParallelSpecs.run_tests(['xxx'],0,'')
|
17
|
+
end
|
18
|
+
|
19
|
+
it "uses TEST_ENV_NUMBER=2 when called for process 1" do
|
20
|
+
ParallelSpecs.should_receive(:open).with{|x,y| x=~/TEST_ENV_NUMBER=2/}.and_return mocked_process
|
21
|
+
ParallelSpecs.run_tests(['xxx'],1,'')
|
22
|
+
end
|
23
|
+
|
24
|
+
it "runs with color when called from cmdline" do
|
25
|
+
ParallelSpecs.should_receive(:open).with{|x,y| x=~/RSPEC_COLOR=1/}.and_return mocked_process
|
26
|
+
$stdout.should_receive(:tty?).and_return true
|
27
|
+
ParallelSpecs.run_tests(['xxx'],1,'')
|
28
|
+
end
|
29
|
+
|
30
|
+
it "runs without color when not called from cmdline" do
|
31
|
+
ParallelSpecs.should_receive(:open).with{|x,y| x !~ /RSPEC_COLOR/}.and_return mocked_process
|
32
|
+
$stdout.should_receive(:tty?).and_return false
|
33
|
+
ParallelSpecs.run_tests(['xxx'],1,'')
|
34
|
+
end
|
35
|
+
|
36
|
+
it "run bundle exec spec when on bundler rspec 1" do
|
37
|
+
File.stub!(:file?).with('script/spec').and_return false
|
38
|
+
ParallelSpecs.stub!(:bundler_enabled?).and_return true
|
39
|
+
ParallelSpecs.stub!(:run).with("bundle show rspec").and_return "/foo/bar/rspec-1.0.2"
|
40
|
+
ParallelSpecs.should_receive(:open).with{|x,y| x =~ %r{bundle exec spec}}.and_return mocked_process
|
41
|
+
ParallelSpecs.run_tests(['xxx'],1,'')
|
42
|
+
end
|
43
|
+
|
44
|
+
it "run bundle exec rspec when on bundler rspec 2" do
|
45
|
+
File.stub!(:file?).with('script/spec').and_return false
|
46
|
+
ParallelSpecs.stub!(:bundler_enabled?).and_return true
|
47
|
+
ParallelSpecs.stub!(:run).with("bundle show rspec").and_return "/foo/bar/rspec-2.0.2"
|
48
|
+
ParallelSpecs.should_receive(:open).with{|x,y| x =~ %r{bundle exec rspec}}.and_return mocked_process
|
49
|
+
ParallelSpecs.run_tests(['xxx'],1,'')
|
50
|
+
end
|
51
|
+
|
52
|
+
it "runs script/spec when script/spec can be found" do
|
53
|
+
File.should_receive(:file?).with('script/spec').and_return true
|
54
|
+
ParallelSpecs.should_receive(:open).with{|x,y| x =~ %r{script/spec}}.and_return mocked_process
|
55
|
+
ParallelSpecs.run_tests(['xxx'],1,'')
|
56
|
+
end
|
57
|
+
|
58
|
+
it "runs spec when script/spec cannot be found" do
|
59
|
+
File.stub!(:file?).with('script/spec').and_return false
|
60
|
+
ParallelSpecs.should_receive(:open).with{|x,y| x !~ %r{script/spec}}.and_return mocked_process
|
61
|
+
ParallelSpecs.run_tests(['xxx'],1,'')
|
62
|
+
end
|
63
|
+
|
64
|
+
it "uses no -O when no opts where found" do
|
65
|
+
File.stub!(:file?).with('spec/spec.opts').and_return false
|
66
|
+
ParallelSpecs.should_receive(:open).with{|x,y| x !~ %r{spec/spec.opts}}.and_return mocked_process
|
67
|
+
ParallelSpecs.run_tests(['xxx'],1,'')
|
68
|
+
end
|
69
|
+
|
70
|
+
it "uses -O spec/spec.opts when found (with script/spec)" do
|
71
|
+
File.stub!(:file?).with('script/spec').and_return true
|
72
|
+
File.stub!(:file?).with('spec/spec.opts').and_return true
|
73
|
+
ParallelSpecs.should_receive(:open).with{|x,y| x =~ %r{script/spec\s+-O spec/spec.opts}}.and_return mocked_process
|
74
|
+
ParallelSpecs.run_tests(['xxx'],1,'')
|
75
|
+
end
|
76
|
+
|
77
|
+
it "uses -O spec/parallel_spec.opts when found (with script/spec)" do
|
78
|
+
File.stub!(:file?).with('script/spec').and_return true
|
79
|
+
File.should_receive(:file?).with('spec/parallel_spec.opts').and_return true
|
80
|
+
ParallelSpecs.should_receive(:open).with{|x,y| x =~ %r{script/spec\s+-O spec/parallel_spec.opts}}.and_return mocked_process
|
81
|
+
ParallelSpecs.run_tests(['xxx'],1,'')
|
82
|
+
end
|
83
|
+
|
84
|
+
it "uses -O spec/parallel_spec.opts with rspec1" do
|
85
|
+
File.should_receive(:file?).with('spec/parallel_spec.opts').and_return true
|
86
|
+
|
87
|
+
ParallelSpecs.stub!(:bundler_enabled?).and_return true
|
88
|
+
ParallelSpecs.stub!(:run).with("bundle show rspec").and_return "/foo/bar/rspec-1.0.2"
|
89
|
+
|
90
|
+
ParallelSpecs.should_receive(:open).with{|x,y| x =~ %r{spec\s+ -O spec/parallel_spec.opts}}.and_return mocked_process
|
91
|
+
ParallelSpecs.run_tests(['xxx'],1,'')
|
92
|
+
end
|
93
|
+
|
94
|
+
it "uses inline options with rspec2" do
|
95
|
+
File.should_receive(:file?).with('spec/parallel_spec.opts').and_return true
|
96
|
+
File.should_receive(:read).with('spec/parallel_spec.opts').and_return "--foo\n--bar\n"
|
97
|
+
|
98
|
+
ParallelSpecs.stub!(:bundler_enabled?).and_return true
|
99
|
+
ParallelSpecs.stub!(:run).with("bundle show rspec").and_return "/foo/bar/rspec-2.0.2"
|
100
|
+
|
101
|
+
ParallelSpecs.should_receive(:open).with{|x,y| x =~ %r{rspec\s+ --foo --bar}}.and_return mocked_process
|
102
|
+
ParallelSpecs.run_tests(['xxx'],1,'')
|
103
|
+
end
|
104
|
+
|
105
|
+
it "uses options passed in" do
|
106
|
+
ParallelSpecs.should_receive(:open).with{|x,y| x =~ %r{rspec -f n}}.and_return mocked_process
|
107
|
+
ParallelSpecs.run_tests(['xxx'],1,'-f n')
|
108
|
+
end
|
109
|
+
|
110
|
+
it "returns the output" do
|
111
|
+
io = open('spec/spec_helper.rb')
|
112
|
+
ParallelSpecs.stub!(:print)
|
113
|
+
ParallelSpecs.should_receive(:open).and_return io
|
114
|
+
ParallelSpecs.run_tests(['xxx'],1,'')[:stdout].should =~ /\$LOAD_PATH << File/
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe :find_results do
|
119
|
+
it "finds multiple results in spec output" do
|
120
|
+
output = <<EOF
|
121
|
+
....F...
|
122
|
+
..
|
123
|
+
failute fsddsfsd
|
124
|
+
...
|
125
|
+
ff.**..
|
126
|
+
0 examples, 0 failures, 0 pending
|
127
|
+
ff.**..
|
128
|
+
1 example, 1 failure, 1 pending
|
129
|
+
EOF
|
130
|
+
|
131
|
+
ParallelSpecs.find_results(output).should == ['0 examples, 0 failures, 0 pending','1 example, 1 failure, 1 pending']
|
132
|
+
end
|
133
|
+
|
134
|
+
it "is robust against scrambeled output" do
|
135
|
+
output = <<EOF
|
136
|
+
....F...
|
137
|
+
..
|
138
|
+
failute fsddsfsd
|
139
|
+
...
|
140
|
+
ff.**..
|
141
|
+
0 exFampl*es, 0 failures, 0 pend.ing
|
142
|
+
ff.**..
|
143
|
+
1 exampF.les, 1 failures, 1 pend.ing
|
144
|
+
EOF
|
145
|
+
|
146
|
+
ParallelSpecs.find_results(output).should == ['0 examples, 0 failures, 0 pending','1 examples, 1 failures, 1 pending']
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'spec/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 prefix" do
|
18
|
+
args = {:count => 2, :path_prefix => "models"}
|
19
|
+
ParallelTests.parse_rake_args(args).should == [2, "models", ""]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return the count, prefix, and options" do
|
23
|
+
args = {:count => 2, :path_prefix => "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,'-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
|
+
it "has a version" do
|
140
|
+
ParallelTests::VERSION.should =~ /^\d+\.\d+\.\d+$/
|
141
|
+
end
|
142
|
+
end
|