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,413 @@
1
+ require "spec_helper"
2
+ require "parallel_tests/test/runner"
3
+
4
+ describe ParallelTests::Test::Runner do
5
+ test_tests_in_groups(ParallelTests::Test::Runner, 'test', '_test.rb')
6
+
7
+ describe ".run_tests" do
8
+ def call(*args)
9
+ ParallelTests::Test::Runner.run_tests(*args)
10
+ end
11
+
12
+ it "allows to override runner executable via PARALLEL_TESTS_EXECUTABLE" do
13
+ begin
14
+ ENV['PARALLEL_TESTS_EXECUTABLE'] = 'script/custom_rspec'
15
+ ParallelTests::Test::Runner.should_receive(:execute_command).with{|a,b,c,d| a.include?("script/custom_rspec") }
16
+ call(['xxx'], 1, 22, {})
17
+ ensure
18
+ ENV.delete('PARALLEL_TESTS_EXECUTABLE')
19
+ end
20
+ end
21
+
22
+ it "uses options" do
23
+ ParallelTests::Test::Runner.should_receive(:execute_command).with{|a,b,c,d| a =~ %r{ruby -Itest .* -- -v}}
24
+ call(['xxx'], 1, 22, :test_options => '-v')
25
+ end
26
+
27
+ it "returns the output" do
28
+ ParallelTests::Test::Runner.should_receive(:execute_command).and_return({:x => 1})
29
+ call(['xxx'], 1, 22, {}).should == {:x => 1}
30
+ end
31
+ end
32
+
33
+ describe ".test_in_groups" do
34
+ def call(*args)
35
+ ParallelTests::Test::Runner.tests_in_groups(*args)
36
+ end
37
+
38
+ it "does not sort when passed false do_sort option" do
39
+ ParallelTests::Test::Runner.should_not_receive(:smallest_first)
40
+ call([], 1, :group_by => :found)
41
+ end
42
+
43
+ it "does sort when not passed do_sort option" do
44
+ ParallelTests::Test::Runner.stub!(:tests_with_runtime).and_return([])
45
+ ParallelTests::Grouper.should_receive(:largest_first).and_return([])
46
+ call([], 1)
47
+ end
48
+
49
+ it "groups by single_process pattern and then via size" do
50
+ ParallelTests::Test::Runner.should_receive(:with_runtime_info).
51
+ and_return([
52
+ ['aaa', 5],
53
+ ['aaa2', 5],
54
+ ['bbb', 2],
55
+ ['ccc', 1],
56
+ ['ddd', 1]
57
+ ])
58
+ result = call([], 3, :single_process => [/^a.a/])
59
+ result.should == [["aaa", "aaa2"], ["bbb"], ["ccc", "ddd"]]
60
+ end
61
+
62
+ it "groups by size and adds isolated separately" do
63
+ pending if RUBY_PLATFORM == "java"
64
+ ParallelTests::Test::Runner.should_receive(:with_runtime_info).
65
+ and_return([
66
+ ['aaa', 0],
67
+ ['bbb', 3],
68
+ ['ccc', 1],
69
+ ['ddd', 2],
70
+ ['eee', 1]
71
+ ])
72
+
73
+ result = call([], 3, :isolate => true, :single_process => [/^aaa/])
74
+ result.should == [["aaa"], ["bbb", "eee"], ["ccc", "ddd"]]
75
+ end
76
+ end
77
+
78
+ describe ".find_results" do
79
+ def call(*args)
80
+ ParallelTests::Test::Runner.find_results(*args)
81
+ end
82
+
83
+ it "finds multiple results in test output" do
84
+ output = <<EOF
85
+ Loaded suite /opt/ruby-enterprise/lib/ruby/gems/1.8/gems/rake-0.8.4/lib/rake/rake_test_loader
86
+ Started
87
+ ..............
88
+ Finished in 0.145069 seconds.
89
+
90
+ 10 tests, 20 assertions, 0 failures, 0 errors
91
+ Loaded suite /opt/ruby-enterprise/lib/ruby/gems/1.8/gems/rake-0.8.4/lib/rake/rake_test_loader
92
+ Started
93
+ ..............
94
+ Finished in 0.145069 seconds.
95
+
96
+ 14 tests, 20 assertions, 0 failures, 0 errors
97
+
98
+ EOF
99
+
100
+ call(output).should == ['10 tests, 20 assertions, 0 failures, 0 errors','14 tests, 20 assertions, 0 failures, 0 errors']
101
+ end
102
+
103
+ it "is robust against scrambled output" do
104
+ output = <<EOF
105
+ Loaded suite /opt/ruby-enterprise/lib/ruby/gems/1.8/gems/rake-0.8.4/lib/rake/rake_test_loader
106
+ Started
107
+ ..............
108
+ Finished in 0.145069 seconds.
109
+
110
+ 10 tests, 20 assertions, 0 failures, 0 errors
111
+ Loaded suite /opt/ruby-enterprise/lib/ruby/gems/1.8/gems/rake-0.8.4/lib/rake/rake_test_loader
112
+ Started
113
+ ..............
114
+ Finished in 0.145069 seconds.
115
+
116
+ 14 te.dsts, 20 assertions, 0 failures, 0 errors
117
+ EOF
118
+
119
+ call(output).should == ['10 tests, 20 assertions, 0 failures, 0 errors','14 tedsts, 20 assertions, 0 failures, 0 errors']
120
+ end
121
+
122
+ it "ignores color-codes" do
123
+ output = <<EOF
124
+ 10 tests, 20 assertions, 0 \e[31mfailures, 0 errors
125
+ EOF
126
+ call(output).should == ['10 tests, 20 assertions, 0 failures, 0 errors']
127
+ end
128
+ end
129
+
130
+ describe ".find_tests" do
131
+ def call(*args)
132
+ ParallelTests::Test::Runner.send(:find_tests, *args)
133
+ end
134
+
135
+ def with_files(files)
136
+ begin
137
+ root = "/tmp/test-find_tests-#{rand(999)}"
138
+ `mkdir #{root}`
139
+ files.each do |file|
140
+ parent = "#{root}/#{File.dirname(file)}"
141
+ `mkdir -p #{parent}` unless File.exist?(parent)
142
+ `touch #{root}/#{file}`
143
+ end
144
+ yield root
145
+ ensure
146
+ `rm -rf #{root}`
147
+ end
148
+ end
149
+
150
+ def inside_dir(dir)
151
+ old = Dir.pwd
152
+ Dir.chdir dir
153
+ yield
154
+ ensure
155
+ Dir.chdir old
156
+ end
157
+
158
+ it "finds test in folders with appended /" do
159
+ with_files(['b/a_test.rb']) do |root|
160
+ call(["#{root}/"]).sort.should == [
161
+ "#{root}/b/a_test.rb",
162
+ ]
163
+ end
164
+ end
165
+
166
+ it "finds test files nested in symlinked folders" do
167
+ with_files(['a/a_test.rb','b/b_test.rb']) do |root|
168
+ `ln -s #{root}/a #{root}/b/link`
169
+ call(["#{root}/b"]).sort.should == [
170
+ "#{root}/b/b_test.rb",
171
+ "#{root}/b/link/a_test.rb",
172
+ ]
173
+ end
174
+ end
175
+
176
+ it "finds test files but ignores those in symlinked folders" do
177
+ pending if RUBY_PLATFORM == "java"
178
+ with_files(['a/a_test.rb','b/b_test.rb']) do |root|
179
+ `ln -s #{root}/a #{root}/b/link`
180
+ call(["#{root}/b"], :symlinks => false).sort.should == [
181
+ "#{root}/b/b_test.rb",
182
+ ]
183
+ end
184
+ end
185
+
186
+ it "finds test files nested in different folders" do
187
+ with_files(['a/a_test.rb','b/b_test.rb', 'c/c_test.rb']) do |root|
188
+ call(["#{root}/a", "#{root}/b"]).sort.should == [
189
+ "#{root}/a/a_test.rb",
190
+ "#{root}/b/b_test.rb",
191
+ ]
192
+ end
193
+ end
194
+
195
+ it "only finds tests in folders" do
196
+ with_files(['a/a_test.rb', 'a/test.rb', 'a/test_helper.rb']) do |root|
197
+ call(["#{root}/a"]).sort.should == [
198
+ "#{root}/a/a_test.rb"
199
+ ]
200
+ end
201
+ end
202
+
203
+ it "finds tests in nested folders" do
204
+ with_files(['a/b/c/d/a_test.rb']) do |root|
205
+ call(["#{root}/a"]).sort.should == [
206
+ "#{root}/a/b/c/d/a_test.rb"
207
+ ]
208
+ end
209
+ end
210
+
211
+ it "does not expand paths" do
212
+ with_files(['a/x_test.rb']) do |root|
213
+ inside_dir root do
214
+ call(['a']).sort.should == [
215
+ "a/x_test.rb"
216
+ ]
217
+ end
218
+ end
219
+ end
220
+
221
+ it "finds test files in folders by pattern" do
222
+ with_files(['a/x_test.rb','a/y_test.rb','a/z_test.rb']) do |root|
223
+ inside_dir root do
224
+ call(["a"], :pattern => /^a\/(y|z)_test/).sort.should == [
225
+ "a/y_test.rb",
226
+ "a/z_test.rb",
227
+ ]
228
+ end
229
+ end
230
+ end
231
+
232
+ it "finds nothing if I pass nothing" do
233
+ call(nil).should == []
234
+ end
235
+
236
+ it "finds nothing if I pass nothing (empty array)" do
237
+ call([]).should == []
238
+ end
239
+
240
+ it "keeps invalid files" do
241
+ call(['baz']).should == ['baz']
242
+ end
243
+
244
+ it "discards duplicates" do
245
+ call(['baz','baz']).should == ['baz']
246
+ end
247
+ end
248
+
249
+ describe ".summarize_results" do
250
+ def call(*args)
251
+ ParallelTests::Test::Runner.summarize_results(*args)
252
+ end
253
+
254
+ it "adds results" do
255
+ call(['1 foo 3 bar','2 foo 5 bar']).should == '8 bars, 3 foos'
256
+ end
257
+
258
+ it "adds results with braces" do
259
+ call(['1 foo(s) 3 bar(s)','2 foo 5 bar']).should == '8 bars, 3 foos'
260
+ end
261
+
262
+ it "adds same results with plurals" do
263
+ call(['1 foo 3 bar','2 foos 5 bar']).should == '8 bars, 3 foos'
264
+ end
265
+
266
+ it "adds non-similar results" do
267
+ call(['1 xxx 2 yyy','1 xxx 2 zzz']).should == '2 xxxs, 2 yyys, 2 zzzs'
268
+ end
269
+
270
+ it "does not pluralize 1" do
271
+ call(['1 xxx 2 yyy']).should == '1 xxx, 2 yyys'
272
+ end
273
+ end
274
+
275
+ describe ".execute_command" do
276
+ def call(*args)
277
+ ParallelTests::Test::Runner.execute_command(*args)
278
+ end
279
+
280
+ def capture_output
281
+ $stdout, $stderr = StringIO.new, StringIO.new
282
+ yield
283
+ [$stdout.string, $stderr.string]
284
+ ensure
285
+ $stdout, $stderr = STDOUT, STDERR
286
+ end
287
+
288
+ def run_with_file(content)
289
+ capture_output do
290
+ Tempfile.open("xxx") do |f|
291
+ f.write(content)
292
+ f.flush
293
+ yield f.path
294
+ end
295
+ end
296
+ end
297
+
298
+ it "sets process number to 2 for 1" do
299
+ run_with_file("puts ENV['TEST_ENV_NUMBER']") do |path|
300
+ result = call("ruby #{path}", 1, 4, {})
301
+ result.should == {
302
+ :stdout => "2\n",
303
+ :exit_status => 0
304
+ }
305
+ end
306
+ end
307
+
308
+ it "sets process number to '' for 0" do
309
+ run_with_file("puts ENV['TEST_ENV_NUMBER'].inspect") do |path|
310
+ result = call("ruby #{path}", 0, 4, {})
311
+ result.should == {
312
+ :stdout => "\"\"\n",
313
+ :exit_status => 0
314
+ }
315
+ end
316
+ end
317
+
318
+ it 'sets PARALLEL_TEST_GROUPS so child processes know that they are being run under parallel_tests' do
319
+ run_with_file("puts ENV['PARALLEL_TEST_GROUPS']") do |path|
320
+ result = call("ruby #{path}", 1, 4, {})
321
+ result.should == {
322
+ :stdout => "4\n",
323
+ :exit_status => 0
324
+ }
325
+ end
326
+ end
327
+
328
+ it "skips reads from stdin" do
329
+ pending "hangs on normal ruby, works on jruby" unless RUBY_PLATFORM == "java"
330
+ run_with_file("$stdin.read; puts 123") do |path|
331
+ result = call("ruby #{path}", 1, 2, {})
332
+ result.should == {
333
+ :stdout => "123\n",
334
+ :exit_status => 0
335
+ }
336
+ end
337
+ end
338
+
339
+ it "waits for process to finish" do
340
+ run_with_file("sleep 0.5; puts 123; sleep 0.5; puts 345") do |path|
341
+ result = call("ruby #{path}", 1, 4, {})
342
+ result.should == {
343
+ :stdout => "123\n345\n",
344
+ :exit_status => 0
345
+ }
346
+ end
347
+ end
348
+
349
+ it "prints output while running" do
350
+ pending "too slow" if RUBY_PLATFORM == " java"
351
+ run_with_file("$stdout.sync = true; puts 123; sleep 0.1; print 345; sleep 0.1; puts 567") do |path|
352
+ received = ""
353
+ $stdout.stub(:print).with{|x| received << x.strip }
354
+ result = call("ruby #{path}", 1, 4, {})
355
+ received.should == "123345567"
356
+ result.should == {
357
+ :stdout => "123\n345567\n",
358
+ :exit_status => 0
359
+ }
360
+ end
361
+ end
362
+
363
+ it "works with synced stdout" do
364
+ run_with_file("$stdout.sync = true; puts 123; sleep 0.1; puts 345") do |path|
365
+ result = call("ruby #{path}", 1, 4, {})
366
+ result.should == {
367
+ :stdout => "123\n345\n",
368
+ :exit_status => 0
369
+ }
370
+ end
371
+ end
372
+
373
+ it "does not print to stdout with :serialize_stdout" do
374
+ run_with_file("puts 123") do |path|
375
+ $stdout.should_not_receive(:print)
376
+ result = call("ruby #{path}", 1, 4, :serialize_stdout => true)
377
+ result.should == {
378
+ :stdout => "123\n",
379
+ :exit_status => 0
380
+ }
381
+ end
382
+ end
383
+
384
+ it "returns correct exit status" do
385
+ run_with_file("puts 123; exit 5") do |path|
386
+ result = call("ruby #{path}", 1, 4, {})
387
+ result.should == {
388
+ :stdout => "123\n",
389
+ :exit_status => 5
390
+ }
391
+ end
392
+ end
393
+
394
+ it "prints each stream to the correct stream" do
395
+ pending "open3"
396
+ out, err = run_with_file("puts 123 ; $stderr.puts 345 ; exit 5") do |path|
397
+ result = call("ruby #{path}", 1, 4, {})
398
+ result.should == {
399
+ :stdout => "123\n",
400
+ :exit_status => 5
401
+ }
402
+ end
403
+ err.should == "345\n"
404
+ end
405
+
406
+ it "uses a lower priority process when the nice option is used" do
407
+ priority_cmd = "puts Process.getpriority(Process::PRIO_PROCESS, 0)"
408
+ priority_without_nice = run_with_file(priority_cmd){ |cmd| call("ruby #{cmd}", 1, 4, {}) }.first.to_i
409
+ priority_with_nice = run_with_file(priority_cmd){ |cmd| call("ruby #{cmd}", 1, 4, :nice => true) }.first.to_i
410
+ priority_without_nice.should < priority_with_nice
411
+ end
412
+ end
413
+ end
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+
3
+ describe ParallelTests::Test::RuntimeLogger do
4
+ describe :writing do
5
+ around do |example|
6
+ use_temporary_directory_for do
7
+ FileUtils.mkdir_p(File.dirname(log))
8
+ example.call
9
+ end
10
+ end
11
+
12
+ let(:log) { ParallelTests::Test::Runner.runtime_log }
13
+
14
+ it "overwrites the runtime_log file on first log invocation" do
15
+ class FakeTest
16
+ end
17
+ test = FakeTest.new
18
+ time = Time.now
19
+ File.open(log, 'w'){ |f| f.puts("FooBar") }
20
+ ParallelTests::Test::RuntimeLogger.send(:class_variable_set,:@@has_started, false)
21
+ ParallelTests::Test::RuntimeLogger.log(test, time, Time.at(time.to_f+2.00))
22
+ result = File.read(log)
23
+ result.should_not include('FooBar')
24
+ result.should include('test/fake_test.rb:2.00')
25
+ end
26
+
27
+ it "appends to the runtime_log file after first log invocation" do
28
+ class FakeTest
29
+ end
30
+ test = FakeTest.new
31
+ class OtherFakeTest
32
+ end
33
+ other_test = OtherFakeTest.new
34
+
35
+ time = Time.now
36
+ File.open(log, 'w'){ |f| f.puts("FooBar") }
37
+ ParallelTests::Test::RuntimeLogger.send(:class_variable_set,:@@has_started, false)
38
+ ParallelTests::Test::RuntimeLogger.log(test, time, Time.at(time.to_f+2.00))
39
+ ParallelTests::Test::RuntimeLogger.log(other_test, time, Time.at(time.to_f+2.00))
40
+ result = File.read(log)
41
+ result.should_not include('FooBar')
42
+ result.should include('test/fake_test.rb:2.00')
43
+ result.should include('test/other_fake_test.rb:2.00')
44
+ end
45
+ end
46
+
47
+ describe "formatting" do
48
+ def with_rails_defined
49
+ Object.const_set(:Rails, Module.new)
50
+ yield
51
+ Object.send(:remove_const, :Rails)
52
+ end
53
+
54
+ def call(*args)
55
+ ParallelTests::Test::RuntimeLogger.send(:message, *args)
56
+ end
57
+
58
+ it "formats results for simple test names" do
59
+ class FakeTest
60
+ end
61
+ test = FakeTest.new
62
+ time = Time.now
63
+ call(test, time, Time.at(time.to_f+2.00)).should == 'test/fake_test.rb:2.00'
64
+ end
65
+
66
+ it "formats results for complex test names" do
67
+ class AVeryComplex
68
+ class FakeTest
69
+ end
70
+ end
71
+ test = AVeryComplex::FakeTest.new
72
+ time = Time.now
73
+ call(test, time, Time.at(time.to_f+2.00)).should == 'test/a_very_complex/fake_test.rb:2.00'
74
+ end
75
+
76
+ it "guesses subdirectory structure for rails test classes" do
77
+ with_rails_defined do
78
+ class ActionController
79
+ class TestCase
80
+ end
81
+ end
82
+ class FakeControllerTest < ActionController::TestCase
83
+ end
84
+ test = FakeControllerTest.new
85
+ time = Time.now
86
+ call(test, time, Time.at(time.to_f+2.00)).should == 'test/functional/fake_controller_test.rb:2.00'
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,137 @@
1
+ require "spec_helper"
2
+
3
+ describe ParallelTests do
4
+ describe ".determine_number_of_processes" do
5
+ before do
6
+ ENV.delete('PARALLEL_TEST_PROCESSORS')
7
+ Parallel.stub(:processor_count).and_return 20
8
+ end
9
+
10
+ def call(count)
11
+ ParallelTests.determine_number_of_processes(count)
12
+ end
13
+
14
+ it "uses the given count if set" do
15
+ call('5').should == 5
16
+ end
17
+
18
+ it "uses the processor count from Parallel" do
19
+ call(nil).should == 20
20
+ end
21
+
22
+ it "uses the processor count from ENV before Parallel" do
23
+ ENV['PARALLEL_TEST_PROCESSORS'] = '22'
24
+ call(nil).should == 22
25
+ end
26
+
27
+ it "does not use blank count" do
28
+ call(' ').should == 20
29
+ end
30
+
31
+ it "does not use blank env" do
32
+ ENV['PARALLEL_TEST_PROCESSORS'] = ' '
33
+ call(nil).should == 20
34
+ end
35
+ end
36
+
37
+ describe ".bundler_enabled?" do
38
+ before do
39
+ Object.stub!(:const_defined?).with(:Bundler).and_return false
40
+ end
41
+
42
+ it "should return false" do
43
+ use_temporary_directory_for do
44
+ ParallelTests.send(:bundler_enabled?).should == false
45
+ end
46
+ end
47
+
48
+ it "should return true when there is a constant called Bundler" do
49
+ use_temporary_directory_for do
50
+ Object.stub!(:const_defined?).with(:Bundler).and_return true
51
+ ParallelTests.send(:bundler_enabled?).should == true
52
+ end
53
+ end
54
+
55
+ it "should be true when there is a Gemfile" do
56
+ use_temporary_directory_for do
57
+ FileUtils.touch("Gemfile")
58
+ ParallelTests.send(:bundler_enabled?).should == true
59
+ end
60
+ end
61
+
62
+ it "should be true when there is a Gemfile in the parent directory" do
63
+ use_temporary_directory_for do
64
+ FileUtils.touch(File.join("..", "Gemfile"))
65
+ ParallelTests.send(:bundler_enabled?).should == true
66
+ end
67
+ end
68
+ end
69
+
70
+ describe ".wait_for_other_processes_to_finish" do
71
+ def with_running_processes(count, wait=0.2)
72
+ count.times { Thread.new{ `TEST_ENV_NUMBER=1; sleep #{wait}` } }
73
+ sleep 0.1
74
+ yield
75
+ ensure
76
+ sleep wait # make sure the threads have finished
77
+ end
78
+
79
+ it "does not wait if not run in parallel" do
80
+ ParallelTests.should_not_receive(:sleep)
81
+ ParallelTests.wait_for_other_processes_to_finish
82
+ end
83
+
84
+ it "stops if only itself is running" do
85
+ ENV["TEST_ENV_NUMBER"] = "2"
86
+ ParallelTests.should_not_receive(:sleep)
87
+ with_running_processes(1) do
88
+ ParallelTests.wait_for_other_processes_to_finish
89
+ end
90
+ end
91
+
92
+ it "waits for other processes to finish" do
93
+ pending if RUBY_PLATFORM == "java"
94
+ ENV["TEST_ENV_NUMBER"] = "2"
95
+ counter = 0
96
+ ParallelTests.stub(:sleep).with{ sleep 0.1; counter += 1 }
97
+ with_running_processes(2, 0.4) do
98
+ ParallelTests.wait_for_other_processes_to_finish
99
+ end
100
+ counter.should == 3
101
+ end
102
+ end
103
+
104
+ describe ".number_of_running_processes" do
105
+ it "is 0 for nothing" do
106
+ ParallelTests.number_of_running_processes.should == 0
107
+ end
108
+
109
+ it "is 2 when 2 are running" do
110
+ wait = 0.2
111
+ 2.times { Thread.new { `TEST_ENV_NUMBER=1; sleep #{wait}` } }
112
+ sleep wait / 2
113
+ ParallelTests.number_of_running_processes.should == 2
114
+ sleep wait
115
+ end
116
+ end
117
+
118
+ describe ".first_process?" do
119
+ it "is first if no env is set" do
120
+ ParallelTests.first_process?.should == true
121
+ end
122
+
123
+ it "is first if env is set to blank" do
124
+ ENV["TEST_ENV_NUMBER"] = ""
125
+ ParallelTests.first_process?.should == true
126
+ end
127
+
128
+ it "is not first if env is set to something" do
129
+ ENV["TEST_ENV_NUMBER"] = "2"
130
+ ParallelTests.first_process?.should == false
131
+ end
132
+ end
133
+
134
+ it "has a version" do
135
+ ParallelTests::VERSION.should =~ /^\d+\.\d+\.\d+/
136
+ end
137
+ end