vinted-parallel_tests 0.13.3

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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +6 -0
  5. data/Gemfile +8 -0
  6. data/Gemfile.lock +48 -0
  7. data/Rakefile +6 -0
  8. data/Readme.md +293 -0
  9. data/ReadmeRails2.md +48 -0
  10. data/bin/parallel_cucumber +5 -0
  11. data/bin/parallel_rspec +5 -0
  12. data/bin/parallel_test +5 -0
  13. data/lib/parallel_tests/cli.rb +187 -0
  14. data/lib/parallel_tests/cucumber/failures_logger.rb +25 -0
  15. data/lib/parallel_tests/cucumber/gherkin_listener.rb +82 -0
  16. data/lib/parallel_tests/cucumber/io.rb +41 -0
  17. data/lib/parallel_tests/cucumber/runner.rb +98 -0
  18. data/lib/parallel_tests/cucumber/runtime_logger.rb +28 -0
  19. data/lib/parallel_tests/grouper.rb +56 -0
  20. data/lib/parallel_tests/railtie.rb +8 -0
  21. data/lib/parallel_tests/rspec/failures_logger.rb +44 -0
  22. data/lib/parallel_tests/rspec/logger_base.rb +52 -0
  23. data/lib/parallel_tests/rspec/runner.rb +72 -0
  24. data/lib/parallel_tests/rspec/runtime_logger.rb +54 -0
  25. data/lib/parallel_tests/rspec/summary_logger.rb +19 -0
  26. data/lib/parallel_tests/tasks.rb +139 -0
  27. data/lib/parallel_tests/test/runner.rb +168 -0
  28. data/lib/parallel_tests/test/runtime_logger.rb +97 -0
  29. data/lib/parallel_tests/version.rb +3 -0
  30. data/lib/parallel_tests.rb +61 -0
  31. data/parallel_tests.gemspec +14 -0
  32. data/spec/integration_spec.rb +285 -0
  33. data/spec/parallel_tests/cli_spec.rb +71 -0
  34. data/spec/parallel_tests/cucumber/failure_logger_spec.rb +43 -0
  35. data/spec/parallel_tests/cucumber/gherkin_listener_spec.rb +97 -0
  36. data/spec/parallel_tests/cucumber/runner_spec.rb +179 -0
  37. data/spec/parallel_tests/grouper_spec.rb +52 -0
  38. data/spec/parallel_tests/rspec/failures_logger_spec.rb +82 -0
  39. data/spec/parallel_tests/rspec/runner_spec.rb +187 -0
  40. data/spec/parallel_tests/rspec/runtime_logger_spec.rb +126 -0
  41. data/spec/parallel_tests/rspec/summary_logger_spec.rb +37 -0
  42. data/spec/parallel_tests/tasks_spec.rb +151 -0
  43. data/spec/parallel_tests/test/runner_spec.rb +413 -0
  44. data/spec/parallel_tests/test/runtime_logger_spec.rb +90 -0
  45. data/spec/parallel_tests_spec.rb +137 -0
  46. data/spec/spec_helper.rb +157 -0
  47. metadata +110 -0
@@ -0,0 +1,285 @@
1
+ #encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'CLI' do
6
+ before do
7
+ `rm -rf #{folder}`
8
+ end
9
+
10
+ after do
11
+ `rm -rf #{folder}`
12
+ end
13
+
14
+ def folder
15
+ "/tmp/parallel_tests_tests"
16
+ end
17
+
18
+ def write(file, content)
19
+ path = "#{folder}/#{file}"
20
+ ensure_folder File.dirname(path)
21
+ File.open(path, 'w'){|f| f.write content }
22
+ path
23
+ end
24
+
25
+ def read(file)
26
+ File.read "#{folder}/#{file}"
27
+ end
28
+
29
+ def bin_folder
30
+ "#{File.expand_path(File.dirname(__FILE__))}/../bin"
31
+ end
32
+
33
+ def executable(options={})
34
+ "#{bin_folder}/parallel_#{options[:type] || 'test'}"
35
+ end
36
+
37
+ def ensure_folder(folder)
38
+ `mkdir -p #{folder}` unless File.exist?(folder)
39
+ end
40
+
41
+ def run_tests(test_folder, options={})
42
+ ensure_folder folder
43
+ processes = "-n #{options[:processes]||2}" unless options[:processes] == false
44
+ command = "cd #{folder} && #{options[:export]} #{executable(options)} #{test_folder} #{processes} #{options[:add]} 2>&1"
45
+ result = `#{command}`
46
+ raise "FAILED #{command}\n#{result}" if $?.success? == !!options[:fail]
47
+ result
48
+ end
49
+
50
+ it "runs tests in parallel" do
51
+ write 'spec/xxx_spec.rb', 'describe("it"){it("should"){puts "TEST1"}}'
52
+ write 'spec/xxx2_spec.rb', 'describe("it"){it("should"){puts "TEST2"}}'
53
+ result = run_tests "spec", :type => 'rspec'
54
+
55
+ # test ran and gave their puts
56
+ result.should include('TEST1')
57
+ result.should include('TEST2')
58
+
59
+ # all results present
60
+ result.scan('1 example, 0 failure').size.should == 2 # 2 results
61
+ result.scan('2 examples, 0 failures').size.should == 1 # 1 summary
62
+ result.scan(/Finished in \d+\.\d+ seconds/).size.should == 2
63
+ result.scan(/Took \d+\.\d+ seconds/).size.should == 1 # parallel summary
64
+ end
65
+
66
+ it "runs tests which outputs accented characters" do
67
+ write "spec/xxx_spec.rb", "#encoding: utf-8\ndescribe('it'){it('should'){puts 'Byłem tu'}}"
68
+ result = run_tests "spec", :type => 'rspec'
69
+ # test ran and gave their puts
70
+ result.should include('Byłem tu')
71
+ end
72
+
73
+ it "does not run any tests if there are none" do
74
+ write 'spec/xxx_spec.rb', '1'
75
+ result = run_tests "spec", :type => 'rspec'
76
+ result.should include('No examples found')
77
+ result.should include('Took')
78
+ end
79
+
80
+ it "fails when tests fail" do
81
+ write 'spec/xxx_spec.rb', 'describe("it"){it("should"){puts "TEST1"}}'
82
+ write 'spec/xxx2_spec.rb', 'describe("it"){it("should"){1.should == 2}}'
83
+ result = run_tests "spec", :fail => true, :type => 'rspec'
84
+
85
+ result.scan('1 example, 1 failure').size.should == 1
86
+ result.scan('1 example, 0 failure').size.should == 1
87
+ result.scan('2 examples, 1 failure').size.should == 1
88
+ end
89
+
90
+ it "can serialize stdout" do
91
+ write 'spec/xxx_spec.rb', '5.times{describe("it"){it("should"){sleep 0.01; puts "TEST1"}}}'
92
+ write 'spec/xxx2_spec.rb', 'sleep 0.01; 5.times{describe("it"){it("should"){sleep 0.01; puts "TEST2"}}}'
93
+ result = run_tests "spec", :type => 'rspec', :add => "--serialize-stdout"
94
+
95
+ result.should_not =~ /TEST1.*TEST2.*TEST1/m
96
+ result.should_not =~ /TEST2.*TEST1.*TEST2/m
97
+ end
98
+
99
+ context "with given commands" do
100
+ it "can exec given commands with ENV['TEST_ENV_NUM']" do
101
+ result = `#{executable} -e 'ruby -e "print ENV[:TEST_ENV_NUMBER.to_s].to_i"' -n 4`
102
+ result.gsub('"','').split('').sort.should == %w[0 2 3 4]
103
+ end
104
+
105
+ it "can exec given command non-parallel" do
106
+ result = `#{executable} -e 'ruby -e "sleep(rand(10)/100.0); puts ENV[:TEST_ENV_NUMBER.to_s].inspect"' -n 4 --non-parallel`
107
+ result.split("\n").should == %w["" "2" "3" "4"]
108
+ end
109
+
110
+ it "can serialize stdout" do
111
+ result = `#{executable} -e 'ruby -e "5.times{sleep 0.01;puts ENV[:TEST_ENV_NUMBER.to_s].to_i;STDOUT.flush}"' -n 2 --serialize-stdout`
112
+ result.should_not =~ /0.*2.*0/m
113
+ result.should_not =~ /2.*0.*2/m
114
+ end
115
+
116
+ it "exists with success if all sub-processes returned success" do
117
+ system("#{executable} -e 'cat /dev/null' -n 4").should == true
118
+ end
119
+
120
+ it "exists with failure if any sub-processes returned failure" do
121
+ system("#{executable} -e 'test -e xxxx' -n 4").should == false
122
+ end
123
+ end
124
+
125
+ it "runs through parallel_rspec" do
126
+ version = `#{executable} -v`
127
+ `#{bin_folder}/parallel_rspec -v`.should == version
128
+ end
129
+
130
+ it "runs through parallel_cucumber" do
131
+ version = `#{executable} -v`
132
+ `#{bin_folder}/parallel_cucumber -v`.should == version
133
+ end
134
+
135
+ it "runs with --group-by found" do
136
+ # it only tests that it does not blow up, as it did before fixing...
137
+ write "spec/x1_spec.rb", "puts '111'"
138
+ run_tests "spec", :type => 'rspec', :add => '--group-by found'
139
+ end
140
+
141
+ it "runs faster with more processes" do
142
+ pending if RUBY_PLATFORM == "java" # just too slow ...
143
+ 2.times{|i|
144
+ write "spec/xxx#{i}_spec.rb", 'describe("it"){it("should"){sleep 5}}; $stderr.puts ENV["TEST_ENV_NUMBER"]'
145
+ }
146
+ t = Time.now
147
+ run_tests("spec", :processes => 2, :type => 'rspec')
148
+ expected = 10
149
+ (Time.now - t).should <= expected
150
+ end
151
+
152
+ it "can run with given files" do
153
+ write "spec/x1_spec.rb", "puts '111'"
154
+ write "spec/x2_spec.rb", "puts '222'"
155
+ write "spec/x3_spec.rb", "puts '333'"
156
+ result = run_tests "spec/x1_spec.rb spec/x3_spec.rb", :type => 'rspec'
157
+ result.should include('111')
158
+ result.should include('333')
159
+ result.should_not include('222')
160
+ end
161
+
162
+ it "runs successfully without any files" do
163
+ results = run_tests "", :type => 'rspec'
164
+ results.should include("2 processes for 0 specs")
165
+ results.should include("Took")
166
+ end
167
+
168
+ it "can run with test-options" do
169
+ write "spec/x1_spec.rb", "111"
170
+ write "spec/x2_spec.rb", "111"
171
+ result = run_tests "spec",
172
+ :add => "--test-options ' --version'",
173
+ :processes => 2,
174
+ :type => 'rspec'
175
+ result.should =~ /\d+\.\d+\.\d+.*\d+\.\d+\.\d+/m # prints version twice
176
+ end
177
+
178
+ it "runs with PARALLEL_TEST_PROCESSORS processes" do
179
+ processes = 5
180
+ processes.times{|i|
181
+ write "spec/x#{i}_spec.rb", "puts %{ENV-\#{ENV['TEST_ENV_NUMBER']}-}"
182
+ }
183
+ result = run_tests "spec",
184
+ :export => "PARALLEL_TEST_PROCESSORS=#{processes}",
185
+ :processes => processes,
186
+ :type => 'rspec'
187
+ result.scan(/ENV-.?-/).should =~ ["ENV--", "ENV-2-", "ENV-3-", "ENV-4-", "ENV-5-"]
188
+ end
189
+
190
+ it "filters test by given pattern and relative paths" do
191
+ write "spec/x_spec.rb", "puts 'XXX'"
192
+ write "spec/y_spec.rb", "puts 'YYY'"
193
+ write "spec/z_spec.rb", "puts 'ZZZ'"
194
+ result = run_tests "spec", :add => "-p '^spec/(x|z)'", :type => "rspec"
195
+ result.should include('XXX')
196
+ result.should_not include('YYY')
197
+ result.should include('ZZZ')
198
+ end
199
+
200
+ it "can wait_for_other_processes_to_finish" do
201
+ pending if RUBY_PLATFORM == "java" # just too slow ...
202
+ write "test/a_test.rb", "require 'parallel_tests'; sleep 0.5 ; ParallelTests.wait_for_other_processes_to_finish; puts 'a'"
203
+ write "test/b_test.rb", "sleep 1; puts 'b'"
204
+ write "test/c_test.rb", "sleep 1.5; puts 'c'"
205
+ write "test/d_test.rb", "sleep 2; puts 'd'"
206
+ run_tests("test", :processes => 4).should include("b\nc\nd\na\n")
207
+ end
208
+
209
+ context "Test::Unit" do
210
+ it "runs" do
211
+ write "test/x1_test.rb", "require 'test/unit'; class XTest < Test::Unit::TestCase; def test_xxx; end; end"
212
+ result = run_tests("test")
213
+ result.should include('1 test')
214
+ end
215
+
216
+ it "passes test options" do
217
+ write "test/x1_test.rb", "require 'test/unit'; class XTest < Test::Unit::TestCase; def test_xxx; end; end"
218
+ result = run_tests("test", :add => '--test-options "-v"')
219
+ result.should include('test_xxx') # verbose output of every test
220
+ end
221
+
222
+ it "runs successfully without any files" do
223
+ results = run_tests("")
224
+ results.should include("2 processes for 0 tests")
225
+ results.should include("Took")
226
+ end
227
+ end
228
+
229
+ context "Cucumber" do
230
+ before do
231
+ write "features/steps/a.rb", "
232
+ Given('I print TEST_ENV_NUMBER'){ puts \"YOUR TEST ENV IS \#{ENV['TEST_ENV_NUMBER']}!\" }
233
+ And('I sleep a bit'){ sleep 0.2 }
234
+ "
235
+ end
236
+
237
+ it "runs tests which outputs accented characters" do
238
+ write "features/good1.feature", "Feature: xxx\n Scenario: xxx\n Given I print accented characters"
239
+ write "features/steps/a.rb", "#encoding: utf-8\nGiven('I print accented characters'){ puts \"I tu też\" }"
240
+ result = run_tests "features", :type => "cucumber", :add => '--pattern good'
241
+ result.should include('I tu też')
242
+ end
243
+
244
+ it "passes TEST_ENV_NUMBER when running with pattern (issue #86)" do
245
+ write "features/good1.feature", "Feature: xxx\n Scenario: xxx\n Given I print TEST_ENV_NUMBER"
246
+ write "features/good2.feature", "Feature: xxx\n Scenario: xxx\n Given I print TEST_ENV_NUMBER"
247
+ write "features/b.feature", "Feature: xxx\n Scenario: xxx\n Given I FAIL"
248
+ write "features/steps/a.rb", "Given('I print TEST_ENV_NUMBER'){ puts \"YOUR TEST ENV IS \#{ENV['TEST_ENV_NUMBER']}!\" }"
249
+
250
+ result = run_tests "features", :type => "cucumber", :add => '--pattern good'
251
+
252
+ result.should include('YOUR TEST ENV IS 2!')
253
+ result.should include('YOUR TEST ENV IS !')
254
+ result.should_not include('I FAIL')
255
+ end
256
+
257
+ it "writes a runtime log" do
258
+ log = "tmp/parallel_runtime_cucumber.log"
259
+ write(log, "x")
260
+ 2.times{|i|
261
+ # needs sleep so that runtime loggers dont overwrite each other initially
262
+ write "features/good#{i}.feature", "Feature: xxx\n Scenario: xxx\n Given I print TEST_ENV_NUMBER\n And I sleep a bit"
263
+ }
264
+ run_tests "features", :type => "cucumber"
265
+ read(log).gsub(/\.\d+/,'').split("\n").should =~ [
266
+ "features/good0.feature:0",
267
+ "features/good1.feature:0"
268
+ ]
269
+ end
270
+
271
+ it "runs each feature once when there are more processes then features (issue #89)" do
272
+ 2.times{|i|
273
+ write "features/good#{i}.feature", "Feature: xxx\n Scenario: xxx\n Given I print TEST_ENV_NUMBER"
274
+ }
275
+ result = run_tests "features", :type => "cucumber", :add => '-n 3'
276
+ result.scan(/YOUR TEST ENV IS \d?!/).sort.should == ["YOUR TEST ENV IS !", "YOUR TEST ENV IS 2!"]
277
+ end
278
+
279
+ it "runs successfully without any files" do
280
+ results = run_tests("", :type => "cucumber")
281
+ results.should include("2 processes for 0 features")
282
+ results.should include("Took")
283
+ end
284
+ end
285
+ end
@@ -0,0 +1,71 @@
1
+ require "spec_helper"
2
+ require "parallel_tests/cli"
3
+ require "parallel_tests/rspec/runner"
4
+
5
+
6
+ describe ParallelTests::CLI do
7
+ subject { ParallelTests::CLI.new }
8
+
9
+ describe "#parse_options" do
10
+ let(:defaults){ {:files => []} }
11
+
12
+ def call(*args)
13
+ subject.send(:parse_options!, *args)
14
+ end
15
+
16
+ it "parses regular count" do
17
+ call(["-n3"]).should == defaults.merge(:count => 3)
18
+ end
19
+
20
+ it "parses count 0 as non-parallel" do
21
+ call(["-n0"]).should == defaults.merge(:non_parallel => true)
22
+ end
23
+
24
+ it "parses non-parallel as non-parallel" do
25
+ call(["--non-parallel"]).should == defaults.merge(:non_parallel => true)
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
32
+
33
+ it "parses nice as nice" do
34
+ call(["--nice"]).should == defaults.merge(:nice => true)
35
+ end
36
+ end
37
+
38
+ describe "#load_runner" do
39
+ it "requires and loads default runner" do
40
+ subject.should_receive(:require).with("parallel_tests/test/runner")
41
+ subject.send(:load_runner, "test").should == ParallelTests::Test::Runner
42
+ end
43
+
44
+ it "requires and loads rspec runner" do
45
+ subject.should_receive(:require).with("parallel_tests/rspec/runner")
46
+ subject.send(:load_runner, "rspec").should == ParallelTests::RSpec::Runner
47
+ end
48
+
49
+ it "fails to load unfindable runner" do
50
+ expect{
51
+ subject.send(:load_runner, "foo").should == ParallelTests::RSpec::Runner
52
+ }.to raise_error(LoadError)
53
+ end
54
+ end
55
+
56
+ describe "#final_fail_message" do
57
+ before do
58
+ subject.instance_variable_set(:@runner, ParallelTests::Test::Runner)
59
+ end
60
+
61
+ it 'returns a plain fail message if colors are nor supported' do
62
+ subject.should_receive(:use_colors?).and_return(false)
63
+ subject.send(:final_fail_message).should == "Tests Failed"
64
+ end
65
+
66
+ it 'returns a colorized fail message if colors are supported' do
67
+ subject.should_receive(:use_colors?).and_return(true)
68
+ subject.send(:final_fail_message).should == "\e[31mTests Failed\e[0m"
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require 'parallel_tests/cucumber/io'
3
+ require 'parallel_tests/cucumber/failures_logger'
4
+
5
+ describe ParallelTests::Cucumber::FailuresLogger do
6
+
7
+ before do
8
+ @output = OutputLogger.new([])
9
+ @output.stub(:write)
10
+
11
+ @logger1 = ParallelTests::Cucumber::FailuresLogger.new(nil, @output, nil)
12
+ @logger2 = ParallelTests::Cucumber::FailuresLogger.new(nil, @output, nil)
13
+ @logger3 = ParallelTests::Cucumber::FailuresLogger.new(nil, @output, nil)
14
+
15
+ @feature1 = mock('feature', :file => "feature/path/to/feature1.feature")
16
+ @feature2 = mock('feature', :file => "feature/path/to/feature2.feature")
17
+ @feature3 = mock('feature', :file => "feature/path/to/feature3.feature")
18
+
19
+ @logger1.instance_variable_set("@lines", [1, 2, 3])
20
+ @logger2.instance_variable_set("@lines", [2, 4, 6])
21
+ @logger3.instance_variable_set("@lines", [3, 6, 9])
22
+ end
23
+
24
+ it "should produce a list of lines for failing scenarios" do
25
+ @logger1.after_feature(@feature1)
26
+ @logger2.after_feature(@feature2)
27
+ @logger3.after_feature(@feature3)
28
+
29
+ output_file_contents = @output.output.join("\n").concat("\n")
30
+
31
+ output_file_contents.should == <<END
32
+ feature/path/to/feature1.feature:1
33
+ feature/path/to/feature1.feature:2
34
+ feature/path/to/feature1.feature:3
35
+ feature/path/to/feature2.feature:2
36
+ feature/path/to/feature2.feature:4
37
+ feature/path/to/feature2.feature:6
38
+ feature/path/to/feature3.feature:3
39
+ feature/path/to/feature3.feature:6
40
+ feature/path/to/feature3.feature:9
41
+ END
42
+ end
43
+ end
@@ -0,0 +1,97 @@
1
+ require 'parallel_tests/cucumber/gherkin_listener'
2
+
3
+ describe ParallelTests::Cucumber::GherkinListener do
4
+ describe :collect do
5
+ before(:each) do
6
+ @listener = ParallelTests::Cucumber::GherkinListener.new
7
+ @listener.uri("feature_file")
8
+ end
9
+
10
+ it "returns steps count" do
11
+ 3.times {@listener.step(nil)}
12
+ @listener.collect.should == {"feature_file" => 3}
13
+ end
14
+
15
+ it "counts background steps separately" do
16
+ @listener.background("background")
17
+ 5.times {@listener.step(nil)}
18
+ @listener.collect.should == {"feature_file" => 0}
19
+
20
+ @listener.scenario("scenario")
21
+ 2.times {@listener.step(nil)}
22
+ @listener.collect.should == {"feature_file" => 2}
23
+
24
+ @listener.scenario("scenario")
25
+ @listener.collect.should == {"feature_file" => 2}
26
+
27
+ @listener.eof
28
+ @listener.collect.should == {"feature_file" => 12}
29
+ end
30
+
31
+ it "counts scenario outlines steps separately" do
32
+ @listener.scenario_outline("outline")
33
+ 5.times {@listener.step(nil)}
34
+ @listener.collect.should == {"feature_file" => 0}
35
+
36
+ @listener.scenario("scenario")
37
+ 2.times {@listener.step(nil)}
38
+ @listener.collect.should == {"feature_file" => 2}
39
+
40
+ @listener.scenario("scenario")
41
+ @listener.collect.should == {"feature_file" => 2}
42
+
43
+ 3.times {@listener.examples}
44
+ @listener.eof
45
+ @listener.collect.should == {"feature_file" => 17}
46
+ end
47
+
48
+ it 'counts scenarios that should not be ignored' do
49
+ @listener.ignore_tag_pattern = nil
50
+ @listener.scenario( stub('scenario', :tags =>[ stub('tag', :name => '@WIP' )]) )
51
+ @listener.step(nil)
52
+ @listener.eof
53
+ @listener.collect.should == {"feature_file" => 1}
54
+
55
+ @listener.ignore_tag_pattern = /@something_other_than_WIP/
56
+ @listener.scenario( stub('scenario', :tags =>[ stub('tag', :name => '@WIP' )]) )
57
+ @listener.step(nil)
58
+ @listener.eof
59
+ @listener.collect.should == {"feature_file" => 2}
60
+ end
61
+
62
+ it 'does not count scenarios that should be ignored' do
63
+ @listener.ignore_tag_pattern = /@WIP/
64
+ @listener.scenario( stub('scenario', :tags =>[ stub('tag', :name => '@WIP' )]))
65
+ @listener.step(nil)
66
+ @listener.eof
67
+ @listener.collect.should == {"feature_file" => 0}
68
+ end
69
+
70
+ it 'counts outlines that should not be ignored' do
71
+ @listener.ignore_tag_pattern = nil
72
+ @listener.scenario_outline( stub('scenario', :tags =>[ stub('tag', :name => '@WIP' )]) )
73
+ @listener.step(nil)
74
+ 3.times {@listener.examples}
75
+ @listener.eof
76
+ @listener.collect.should == {"feature_file" => 3}
77
+
78
+
79
+ @listener.ignore_tag_pattern = /@something_other_than_WIP/
80
+ @listener.scenario_outline( stub('scenario', :tags =>[ stub('tag', :name => '@WIP' )]) )
81
+ @listener.step(nil)
82
+ 3.times {@listener.examples}
83
+ @listener.eof
84
+ @listener.collect.should == {"feature_file" => 6}
85
+ end
86
+
87
+ it 'does not count outlines that should be ignored' do
88
+ @listener.ignore_tag_pattern = /@WIP/
89
+ @listener.scenario_outline( stub('scenario', :tags =>[ stub('tag', :name => '@WIP' )]) )
90
+ @listener.step(nil)
91
+ 3.times {@listener.examples}
92
+ @listener.eof
93
+ @listener.collect.should == {"feature_file" => 0}
94
+ end
95
+
96
+ end
97
+ end
@@ -0,0 +1,179 @@
1
+ require "spec_helper"
2
+ require "parallel_tests/cucumber/runner"
3
+
4
+ describe ParallelTests::Cucumber do
5
+ test_tests_in_groups(ParallelTests::Cucumber::Runner, 'features', ".feature")
6
+
7
+ describe :run_tests do
8
+ before do
9
+ ParallelTests.stub!(:bundler_enabled?).and_return false
10
+ File.stub!(:file?).with('.bundle/environment.rb').and_return false
11
+ File.stub!(:file?).with('script/cucumber').and_return true
12
+ end
13
+
14
+ def call(*args)
15
+ ParallelTests::Cucumber::Runner.run_tests(*args)
16
+ end
17
+
18
+ def should_run_with(regex)
19
+ ParallelTests::Test::Runner.should_receive(:execute_command).with{|a,b,c,d| a =~ regex}
20
+ end
21
+
22
+ it "allows to override runner executable via PARALLEL_TESTS_EXECUTABLE" do
23
+ ENV['PARALLEL_TESTS_EXECUTABLE'] = 'script/custom_rspec'
24
+ should_run_with /script\/custom_rspec/
25
+ call(['xxx'],1,22,{})
26
+ ENV.delete('PARALLEL_TESTS_EXECUTABLE')
27
+ end
28
+
29
+ it "runs bundle exec cucumber when on bundler 0.9" do
30
+ ParallelTests.stub!(:bundler_enabled?).and_return true
31
+ should_run_with %r{bundle exec cucumber}
32
+ call(['xxx'],1,22,{})
33
+ end
34
+
35
+ it "runs script/cucumber when script/cucumber is found" do
36
+ should_run_with %r{script/cucumber}
37
+ call(['xxx'],1,22,{})
38
+ end
39
+
40
+ it "runs cucumber by default" do
41
+ File.stub!(:file?).with('script/cucumber').and_return false
42
+ should_run_with %r{^cucumber}
43
+ call(['xxx'],1,22,{})
44
+ end
45
+
46
+ it "uses bin/cucumber when present" do
47
+ File.stub(:exists?).with("bin/cucumber").and_return true
48
+ should_run_with %r{bin/cucumber}
49
+ call(['xxx'],1,22,{})
50
+ end
51
+
52
+ it "uses options passed in" do
53
+ should_run_with %r{script/cucumber .* -p default}
54
+ call(['xxx'],1,22,:test_options => '-p default')
55
+ end
56
+
57
+ it "sanitizes dangerous file names" do
58
+ should_run_with %r{xx\\ x}
59
+ call(['xx x'],1,22,{})
60
+ end
61
+
62
+ context "with parallel profile in config/cucumber.yml" do
63
+ before do
64
+ file_contents = 'parallel: -f progress'
65
+ Dir.stub(:glob).and_return ['config/cucumber.yml']
66
+ File.stub(:read).with('config/cucumber.yml').and_return file_contents
67
+ end
68
+
69
+ it "uses parallel profile" do
70
+ should_run_with %r{script/cucumber .* foo bar --profile parallel xxx}
71
+ call(['xxx'],1,22, :test_options => 'foo bar')
72
+ end
73
+
74
+ it "uses given profile via --profile" do
75
+ should_run_with %r{script/cucumber .* --profile foo xxx$}
76
+ call(['xxx'],1,22, :test_options => '--profile foo')
77
+ end
78
+
79
+ it "uses given profile via -p" do
80
+ should_run_with %r{script/cucumber .* -p foo xxx$}
81
+ call(['xxx'],1,22, :test_options => '-p foo')
82
+ end
83
+ end
84
+
85
+ it "does not use parallel profile if config/cucumber.yml does not contain it" do
86
+ file_contents = 'blob: -f progress'
87
+ should_run_with %r{script/cucumber .* foo bar}
88
+ Dir.should_receive(:glob).and_return ['config/cucumber.yml']
89
+ File.should_receive(:read).with('config/cucumber.yml').and_return file_contents
90
+ call(['xxx'],1,22,:test_options => 'foo bar')
91
+ end
92
+
93
+ it "does not use the parallel profile if config/cucumber.yml does not exist" do
94
+ should_run_with %r{script/cucumber} # TODO this test looks useless...
95
+ Dir.should_receive(:glob).and_return []
96
+ call(['xxx'],1,22,{})
97
+ end
98
+ end
99
+
100
+ describe :line_is_result? do
101
+ it "should match lines with only one scenario" do
102
+ line = "1 scenario (1 failed)"
103
+ ParallelTests::Cucumber::Runner.line_is_result?(line).should be_true
104
+ end
105
+
106
+ it "should match lines with multiple scenarios" do
107
+ line = "2 scenarios (1 failed, 1 passed)"
108
+ ParallelTests::Cucumber::Runner.line_is_result?(line).should be_true
109
+ end
110
+
111
+ it "should match lines with only one step" do
112
+ line = "1 step (1 failed)"
113
+ ParallelTests::Cucumber::Runner.line_is_result?(line).should be_true
114
+ end
115
+
116
+ it "should match lines with multiple steps" do
117
+ line = "5 steps (1 failed, 4 passed)"
118
+ ParallelTests::Cucumber::Runner.line_is_result?(line).should be_true
119
+ end
120
+
121
+ it "should not match other lines" do
122
+ line = ' And I should have "2" emails # features/step_definitions/user_steps.rb:25'
123
+ ParallelTests::Cucumber::Runner.line_is_result?(line).should be_false
124
+ end
125
+ end
126
+
127
+ describe :find_results do
128
+ it "finds multiple results in test output" do
129
+ output = <<EOF
130
+ And I should not see "/en/" # features/step_definitions/webrat_steps.rb:87
131
+
132
+ 7 scenarios (3 failed, 4 passed)
133
+ 33 steps (3 failed, 2 skipped, 28 passed)
134
+ /apps/rs/features/signup.feature:2
135
+ Given I am on "/" # features/step_definitions/common_steps.rb:12
136
+ When I click "register" # features/step_definitions/common_steps.rb:6
137
+ And I should have "2" emails # features/step_definitions/user_steps.rb:25
138
+
139
+ 4 scenarios (4 passed)
140
+ 40 steps (40 passed)
141
+
142
+ And I should not see "foo" # features/step_definitions/webrat_steps.rb:87
143
+
144
+ 1 scenario (1 passed)
145
+ 1 step (1 passed)
146
+
147
+ EOF
148
+ ParallelTests::Cucumber::Runner.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)", "1 scenario (1 passed)", "1 step (1 passed)"]
149
+ end
150
+ end
151
+
152
+ describe :summarize_results do
153
+ def call(*args)
154
+ ParallelTests::Cucumber::Runner.summarize_results(*args)
155
+ end
156
+
157
+ it "sums up results for scenarios and steps separately from each other" do
158
+ results = ["7 scenarios (3 failed, 4 passed)", "33 steps (3 failed, 2 skipped, 28 passed)", "4 scenarios (4 passed)",
159
+ "40 steps (40 passed)", "1 scenario (1 passed)", "1 step (1 passed)"]
160
+ call(results).should == "12 scenarios (3 failed, 9 passed)\n74 steps (3 failed, 2 skipped, 69 passed)"
161
+ end
162
+
163
+ it "adds same results with plurals" do
164
+ results = ["1 scenario (1 passed)", "2 steps (2 passed)",
165
+ "2 scenarios (2 passed)", "7 steps (7 passed)"]
166
+ call(results).should == "3 scenarios (3 passed)\n9 steps (9 passed)"
167
+ end
168
+
169
+ it "adds non-similar results" do
170
+ results = ["1 scenario (1 passed)", "1 step (1 passed)",
171
+ "2 scenarios (1 failed, 1 pending)", "2 steps (1 failed, 1 pending)"]
172
+ call(results).should == "3 scenarios (1 failed, 1 pending, 1 passed)\n3 steps (1 failed, 1 pending, 1 passed)"
173
+ end
174
+
175
+ it "does not pluralize 1" do
176
+ call(["1 scenario (1 passed)", "1 step (1 passed)"]).should == "1 scenario (1 passed)\n1 step (1 passed)"
177
+ end
178
+ end
179
+ end