parallel_tests-instructure 0.6.16
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 +10 -0
- data/Gemfile.lock +30 -0
- data/Rakefile +20 -0
- data/Readme.md +240 -0
- data/VERSION +1 -0
- data/bin/parallel_cucumber +2 -0
- data/bin/parallel_spec +2 -0
- data/bin/parallel_test +97 -0
- data/lib/parallel_cucumber.rb +36 -0
- data/lib/parallel_cucumber/runtime_logger.rb +57 -0
- data/lib/parallel_specs.rb +52 -0
- data/lib/parallel_specs/spec_error_count_logger.rb +30 -0
- data/lib/parallel_specs/spec_error_logger.rb +45 -0
- data/lib/parallel_specs/spec_failures_logger.rb +43 -0
- data/lib/parallel_specs/spec_logger_base.rb +48 -0
- data/lib/parallel_specs/spec_runtime_logger.rb +34 -0
- data/lib/parallel_specs/spec_start_finish_logger.rb +38 -0
- data/lib/parallel_specs/spec_summary_logger.rb +19 -0
- data/lib/parallel_tests.rb +163 -0
- data/lib/parallel_tests/grouper.rb +49 -0
- data/lib/parallel_tests/railtie.rb +10 -0
- data/lib/parallel_tests/runtime_logger.rb +78 -0
- data/lib/parallel_tests/tasks.rb +80 -0
- data/lib/tasks/parallel_tests.rake +1 -0
- data/parallel_tests-instructure.gemspec +67 -0
- data/spec/integration_spec.rb +133 -0
- data/spec/parallel_cucumber_spec.rb +72 -0
- data/spec/parallel_specs/spec_failure_logger_spec.rb +82 -0
- data/spec/parallel_specs/spec_runtime_logger_spec.rb +76 -0
- data/spec/parallel_specs/spec_summary_logger_spec.rb +33 -0
- data/spec/parallel_specs_spec.rb +165 -0
- data/spec/parallel_tests/runtime_logger_spec.rb +74 -0
- data/spec/parallel_tests_spec.rb +229 -0
- data/spec/spec_helper.rb +149 -0
- metadata +115 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
class ParallelTests
|
2
|
+
class Grouper
|
3
|
+
def self.in_groups(items, num_groups)
|
4
|
+
groups = Array.new(num_groups){ [] }
|
5
|
+
|
6
|
+
until items.empty?
|
7
|
+
num_groups.times do |group_number|
|
8
|
+
groups[group_number] << items.shift
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
groups.map!(&:sort!)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.in_even_groups_by_size(items_with_sizes, num_groups, options={})
|
16
|
+
groups = Array.new(num_groups){{:items => [], :size => 0}}
|
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
|
+
smallest = smallest_group(groups)
|
22
|
+
matched.each{|item,size| add_to_group(smallest, item, size) }
|
23
|
+
end
|
24
|
+
|
25
|
+
# add all other files
|
26
|
+
largest_first(items_with_sizes).each do |item, size|
|
27
|
+
smallest = smallest_group(groups)
|
28
|
+
add_to_group(smallest, item, size)
|
29
|
+
end
|
30
|
+
|
31
|
+
groups.map!{|g| g[:items].sort }
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.largest_first(files)
|
35
|
+
files.sort_by{|item, size| size }.reverse
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def self.smallest_group(groups)
|
41
|
+
groups.min_by{|g| g[:size] }
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.add_to_group(group, item, size)
|
45
|
+
group[:items] << item
|
46
|
+
group[:size] += size
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
class ParallelTests::RuntimeLogger
|
2
|
+
@@has_started = false
|
3
|
+
|
4
|
+
def self.log(test, start_time, end_time)
|
5
|
+
return if test.is_a? Test::Unit::TestSuite # don't log for suites-of-suites
|
6
|
+
|
7
|
+
if !@@has_started # make empty log file
|
8
|
+
File.open(ParallelTests.runtime_log, 'w') do end
|
9
|
+
@@has_started = true
|
10
|
+
end
|
11
|
+
|
12
|
+
File.open(ParallelTests.runtime_log, 'a') do |output|
|
13
|
+
begin
|
14
|
+
output.flock File::LOCK_EX
|
15
|
+
output.puts(self.message(test, start_time, end_time))
|
16
|
+
ensure
|
17
|
+
output.flock File::LOCK_UN
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.message(test, start_time, end_time)
|
23
|
+
delta="%.2f" % (end_time.to_f-start_time.to_f)
|
24
|
+
filename=class_directory(test.class) + class_to_filename(test.class) + ".rb"
|
25
|
+
message="#{filename}:#{delta}"
|
26
|
+
end
|
27
|
+
|
28
|
+
# Note: this is a best guess at conventional test directory structure, and may need
|
29
|
+
# tweaking / post-processing to match correctly for any given project
|
30
|
+
def self.class_directory(suspect)
|
31
|
+
result = "test/"
|
32
|
+
|
33
|
+
if defined?(Rails)
|
34
|
+
result += case suspect.superclass.name
|
35
|
+
when "ActionDispatch::IntegrationTest"
|
36
|
+
"integration/"
|
37
|
+
when "ActionDispatch::PerformanceTest"
|
38
|
+
"performance/"
|
39
|
+
when "ActionController::TestCase"
|
40
|
+
"functional/"
|
41
|
+
when "ActionView::TestCase"
|
42
|
+
"unit/helpers/"
|
43
|
+
else
|
44
|
+
"unit/"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
result
|
48
|
+
end
|
49
|
+
|
50
|
+
# based on https://github.com/grosser/single_test/blob/master/lib/single_test.rb#L117
|
51
|
+
def self.class_to_filename(suspect)
|
52
|
+
word = suspect.to_s.dup
|
53
|
+
return word unless word.match /^[A-Z]/ and not word.match %r{/[a-z]}
|
54
|
+
|
55
|
+
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
56
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
57
|
+
word.gsub!(/\:\:/,'/')
|
58
|
+
word.tr!("-", "_")
|
59
|
+
word.downcase!
|
60
|
+
word
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
require 'test/unit/testsuite'
|
66
|
+
class Test::Unit::TestSuite
|
67
|
+
|
68
|
+
alias :run_without_timing :run unless defined? @@timing_installed
|
69
|
+
|
70
|
+
def run(result, &progress_block)
|
71
|
+
start_time=Time.now
|
72
|
+
run_without_timing(result, &progress_block)
|
73
|
+
end_time=Time.now
|
74
|
+
ParallelTests::RuntimeLogger.log(self.tests.first, start_time, end_time)
|
75
|
+
end
|
76
|
+
@@timing_installed = true
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
namespace :parallel do
|
2
|
+
def run_in_parallel(cmd, options)
|
3
|
+
count = (options[:count] ? options[:count].to_i : nil)
|
4
|
+
executable = File.join(File.dirname(__FILE__), '..', '..', 'bin', 'parallel_test')
|
5
|
+
command = "#{executable} --exec '#{cmd}' -n #{count} #{'--non-parallel' if options[:non_parallel]}"
|
6
|
+
abort unless system(command)
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "create test databases via db:create --> parallel:create[num_cpus]"
|
10
|
+
task :create, :count do |t,args|
|
11
|
+
run_in_parallel('rake db:create RAILS_ENV=test', args)
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "drop test databases via db:drop --> parallel:drop[num_cpus]"
|
15
|
+
task :drop, :count do |t,args|
|
16
|
+
run_in_parallel('rake db:drop RAILS_ENV=test', args)
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "update test databases by dumping and loading --> parallel:prepare[num_cpus]"
|
20
|
+
task(:prepare, [:count] => 'db:abort_if_pending_migrations') do |t,args|
|
21
|
+
if defined?(ActiveRecord) && ActiveRecord::Base.schema_format == :ruby
|
22
|
+
# dump then load in parallel
|
23
|
+
Rake::Task['db:schema:dump'].invoke
|
24
|
+
Rake::Task['parallel:load_schema'].invoke(args[:count])
|
25
|
+
else
|
26
|
+
# there is no separate dump / load for schema_format :sql -> do it safe and slow
|
27
|
+
args = args.to_hash.merge(:non_parallel => true) # normal merge returns nil
|
28
|
+
run_in_parallel('rake db:test:prepare --trace', args)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# when dumping/resetting takes too long
|
33
|
+
desc "update test databases via db:migrate --> parallel:migrate[num_cpus]"
|
34
|
+
task :migrate, :count do |t,args|
|
35
|
+
run_in_parallel('rake db:migrate RAILS_ENV=test', args)
|
36
|
+
end
|
37
|
+
|
38
|
+
# just load the schema (good for integration server <-> no development db)
|
39
|
+
desc "load dumped schema for test databases via db:schema:load --> parallel:load_schema[num_cpus]"
|
40
|
+
task :load_schema, :count do |t,args|
|
41
|
+
run_in_parallel('rake db:test:load', args)
|
42
|
+
end
|
43
|
+
|
44
|
+
['test', 'spec', 'features'].each do |type|
|
45
|
+
desc "run #{type} in parallel with parallel:#{type}[num_cpus]"
|
46
|
+
task type, :count, :pattern, :options do |t,args|
|
47
|
+
$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
48
|
+
require "parallel_tests"
|
49
|
+
count, pattern, options = ParallelTests.parse_rake_args(args)
|
50
|
+
executable = File.join(File.dirname(__FILE__), '..', '..', 'bin', 'parallel_test')
|
51
|
+
command = "#{executable} --type #{type} -n #{count} -p '#{pattern}' -r '#{Rails.root}' -o '#{options}'"
|
52
|
+
abort unless system(command) # allow to chain tasks e.g. rake parallel:spec parallel:features
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
#backwards compatability
|
58
|
+
#spec:parallel:prepare
|
59
|
+
#spec:parallel
|
60
|
+
#test:parallel
|
61
|
+
namespace :spec do
|
62
|
+
namespace :parallel do
|
63
|
+
task :prepare, :count do |t,args|
|
64
|
+
$stderr.puts "WARNING -- Deprecated! use parallel:prepare"
|
65
|
+
Rake::Task['parallel:prepare'].invoke(args[:count])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
task :parallel, :count, :pattern do |t,args|
|
70
|
+
$stderr.puts "WARNING -- Deprecated! use parallel:spec"
|
71
|
+
Rake::Task['parallel:spec'].invoke(args[:count], args[:pattern])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
namespace :test do
|
76
|
+
task :parallel, :count, :pattern do |t,args|
|
77
|
+
$stderr.puts "WARNING -- Deprecated! use parallel:test"
|
78
|
+
Rake::Task['parallel:test'].invoke(args[:count], args[:pattern])
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "/../parallel_tests/tasks")
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "parallel_tests-instructure"
|
8
|
+
s.version = "0.6.16"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Michael Grosser, Bryan Madsen"]
|
12
|
+
s.date = "2012-02-27"
|
13
|
+
s.executables = ["parallel_cucumber", "parallel_test", "parallel_spec"]
|
14
|
+
s.files = [
|
15
|
+
"Gemfile",
|
16
|
+
"Gemfile.lock",
|
17
|
+
"Rakefile",
|
18
|
+
"Readme.md",
|
19
|
+
"VERSION",
|
20
|
+
"bin/parallel_cucumber",
|
21
|
+
"bin/parallel_spec",
|
22
|
+
"bin/parallel_test",
|
23
|
+
"lib/parallel_cucumber.rb",
|
24
|
+
"lib/parallel_cucumber/runtime_logger.rb",
|
25
|
+
"lib/parallel_specs.rb",
|
26
|
+
"lib/parallel_specs/spec_failures_logger.rb",
|
27
|
+
"lib/parallel_specs/spec_logger_base.rb",
|
28
|
+
"lib/parallel_specs/spec_runtime_logger.rb",
|
29
|
+
"lib/parallel_specs/spec_summary_logger.rb",
|
30
|
+
"lib/parallel_specs/spec_error_count_logger.rb",
|
31
|
+
"lib/parallel_specs/spec_error_logger.rb",
|
32
|
+
"lib/parallel_specs/spec_start_finish_logger.rb",
|
33
|
+
"lib/parallel_tests.rb",
|
34
|
+
"lib/parallel_tests/grouper.rb",
|
35
|
+
"lib/parallel_tests/railtie.rb",
|
36
|
+
"lib/parallel_tests/runtime_logger.rb",
|
37
|
+
"lib/parallel_tests/tasks.rb",
|
38
|
+
"lib/tasks/parallel_tests.rake",
|
39
|
+
"parallel_tests-instructure.gemspec",
|
40
|
+
"spec/integration_spec.rb",
|
41
|
+
"spec/parallel_cucumber_spec.rb",
|
42
|
+
"spec/parallel_specs/spec_failure_logger_spec.rb",
|
43
|
+
"spec/parallel_specs/spec_runtime_logger_spec.rb",
|
44
|
+
"spec/parallel_specs/spec_summary_logger_spec.rb",
|
45
|
+
"spec/parallel_specs_spec.rb",
|
46
|
+
"spec/parallel_tests/runtime_logger_spec.rb",
|
47
|
+
"spec/parallel_tests_spec.rb",
|
48
|
+
"spec/spec_helper.rb"
|
49
|
+
]
|
50
|
+
s.homepage = "http://github.com/bmad/parallel_tests-instructure"
|
51
|
+
s.require_paths = ["lib"]
|
52
|
+
s.rubygems_version = "1.8.15"
|
53
|
+
s.summary = "Run tests / specs / features in parallel"
|
54
|
+
|
55
|
+
if s.respond_to? :specification_version then
|
56
|
+
s.specification_version = 3
|
57
|
+
|
58
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
59
|
+
s.add_runtime_dependency(%q<parallel>, [">= 0"])
|
60
|
+
else
|
61
|
+
s.add_dependency(%q<parallel>, [">= 0"])
|
62
|
+
end
|
63
|
+
else
|
64
|
+
s.add_dependency(%q<parallel>, [">= 0"])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require '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}/#{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_tests(options={})
|
32
|
+
`cd #{folder} && #{executable} --chunk-timeout 999 -t #{options[:type] || 'spec'} -n #{options[:processes]||2} #{options[:add]} 2>&1`
|
33
|
+
end
|
34
|
+
|
35
|
+
it "runs tests in parallel" do
|
36
|
+
write 'spec/xxx_spec.rb', 'describe("it"){it("should"){puts "TEST1"}}'
|
37
|
+
write 'spec/xxx2_spec.rb', 'describe("it"){it("should"){puts "TEST2"}}'
|
38
|
+
result = run_tests
|
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 == 2 # 2 results
|
46
|
+
result.scan('2 examples, 0 failures').size.should == 1 # 1 summary
|
47
|
+
result.scan(/Finished in \d+\.\d+ seconds/).size.should == 2
|
48
|
+
result.scan(/Took \d+\.\d+ seconds/).size.should == 1 # parallel summary
|
49
|
+
$?.success?.should == true
|
50
|
+
end
|
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
|
+
|
59
|
+
it "fails when tests fail" do
|
60
|
+
write 'spec/xxx_spec.rb', 'describe("it"){it("should"){puts "TEST1"}}'
|
61
|
+
write 'spec/xxx2_spec.rb', 'describe("it"){it("should"){1.should == 2}}'
|
62
|
+
result = run_tests
|
63
|
+
|
64
|
+
result.scan('1 example, 1 failure').size.should == 1
|
65
|
+
result.scan('1 example, 0 failure').size.should == 1
|
66
|
+
result.scan('2 examples, 1 failure').size.should == 1
|
67
|
+
$?.success?.should == false
|
68
|
+
end
|
69
|
+
|
70
|
+
it "can exec given commands with ENV['TEST_ENV_NUM']" do
|
71
|
+
result = `#{executable} -e 'ruby -e "print ENV[:TEST_ENV_NUMBER.to_s].to_i"' -n 4`
|
72
|
+
result.gsub('"','').split('').sort.should == %w[0 2 3 4]
|
73
|
+
end
|
74
|
+
|
75
|
+
it "can exec given command non-parallel" do
|
76
|
+
result = `#{executable} -e 'ruby -e "sleep(rand(10)/100.0); puts ENV[:TEST_ENV_NUMBER.to_s].inspect"' -n 4 --non-parallel`
|
77
|
+
result.split("\n").should == %w["" "2" "3" "4"]
|
78
|
+
end
|
79
|
+
|
80
|
+
it "exists with success if all sub-processes returned success" do
|
81
|
+
system("#{executable} -e 'cat /dev/null' -n 4").should == true
|
82
|
+
end
|
83
|
+
|
84
|
+
it "exists with failure if any sub-processes returned failure" do
|
85
|
+
system("#{executable} -e 'test -e xxxx' -n 4").should == false
|
86
|
+
end
|
87
|
+
|
88
|
+
it "can run through parallel_spec / parallel_cucumber" do
|
89
|
+
version = `#{executable} -v`
|
90
|
+
`#{bin_folder}/parallel_spec -v`.should == version
|
91
|
+
`#{bin_folder}/parallel_cucumber -v`.should == version
|
92
|
+
end
|
93
|
+
|
94
|
+
it "runs faster with more processes" do
|
95
|
+
2.times{|i|
|
96
|
+
write "spec/xxx#{i}_spec.rb", 'describe("it"){it("should"){sleep 5}}; $stderr.puts ENV["TEST_ENV_NUMBER"]'
|
97
|
+
}
|
98
|
+
t = Time.now
|
99
|
+
run_tests(:processes => 2)
|
100
|
+
expected = 10
|
101
|
+
(Time.now - t).should <= expected
|
102
|
+
end
|
103
|
+
|
104
|
+
it "can can with given files" do
|
105
|
+
write "spec/x1_spec.rb", "puts '111'"
|
106
|
+
write "spec/x2_spec.rb", "puts '222'"
|
107
|
+
write "spec/x3_spec.rb", "puts '333'"
|
108
|
+
result = run_tests(:add => 'spec/x1_spec.rb spec/x3_spec.rb')
|
109
|
+
result.should include('111')
|
110
|
+
result.should include('333')
|
111
|
+
result.should_not include('222')
|
112
|
+
end
|
113
|
+
|
114
|
+
it "can run with test-options" do
|
115
|
+
write "spec/x1_spec.rb", ""
|
116
|
+
write "spec/x2_spec.rb", ""
|
117
|
+
result = run_tests(:add => "--test-options ' --version'", :processes => 2)
|
118
|
+
result.should =~ /\d+\.\d+\.\d+.*\d+\.\d+\.\d+/m # prints version twice
|
119
|
+
end
|
120
|
+
|
121
|
+
it "runs with test::unit" do
|
122
|
+
write "test/x1_test.rb", "require 'test/unit'; class XTest < Test::Unit::TestCase; def test_xxx; end; end"
|
123
|
+
result = run_tests(:type => :test)
|
124
|
+
result.should include('1 test')
|
125
|
+
$?.success?.should == true
|
126
|
+
end
|
127
|
+
|
128
|
+
it "passes test options to test::unit" do
|
129
|
+
write "test/x1_test.rb", "require 'test/unit'; class XTest < Test::Unit::TestCase; def test_xxx; end; end"
|
130
|
+
result = run_tests(:type => :test, :add => '--test-options "-v"')
|
131
|
+
result.should include('test_xxx') # verbose output of every test
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require '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,:test_options => '-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
|