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.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.rspec +2 -0
- data/.travis.yml +6 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +48 -0
- data/Rakefile +6 -0
- data/Readme.md +293 -0
- data/ReadmeRails2.md +48 -0
- data/bin/parallel_cucumber +5 -0
- data/bin/parallel_rspec +5 -0
- data/bin/parallel_test +5 -0
- data/lib/parallel_tests/cli.rb +187 -0
- data/lib/parallel_tests/cucumber/failures_logger.rb +25 -0
- data/lib/parallel_tests/cucumber/gherkin_listener.rb +82 -0
- data/lib/parallel_tests/cucumber/io.rb +41 -0
- data/lib/parallel_tests/cucumber/runner.rb +98 -0
- data/lib/parallel_tests/cucumber/runtime_logger.rb +28 -0
- data/lib/parallel_tests/grouper.rb +56 -0
- data/lib/parallel_tests/railtie.rb +8 -0
- data/lib/parallel_tests/rspec/failures_logger.rb +44 -0
- data/lib/parallel_tests/rspec/logger_base.rb +52 -0
- data/lib/parallel_tests/rspec/runner.rb +72 -0
- data/lib/parallel_tests/rspec/runtime_logger.rb +54 -0
- data/lib/parallel_tests/rspec/summary_logger.rb +19 -0
- data/lib/parallel_tests/tasks.rb +139 -0
- data/lib/parallel_tests/test/runner.rb +168 -0
- data/lib/parallel_tests/test/runtime_logger.rb +97 -0
- data/lib/parallel_tests/version.rb +3 -0
- data/lib/parallel_tests.rb +61 -0
- data/parallel_tests.gemspec +14 -0
- data/spec/integration_spec.rb +285 -0
- data/spec/parallel_tests/cli_spec.rb +71 -0
- data/spec/parallel_tests/cucumber/failure_logger_spec.rb +43 -0
- data/spec/parallel_tests/cucumber/gherkin_listener_spec.rb +97 -0
- data/spec/parallel_tests/cucumber/runner_spec.rb +179 -0
- data/spec/parallel_tests/grouper_spec.rb +52 -0
- data/spec/parallel_tests/rspec/failures_logger_spec.rb +82 -0
- data/spec/parallel_tests/rspec/runner_spec.rb +187 -0
- data/spec/parallel_tests/rspec/runtime_logger_spec.rb +126 -0
- data/spec/parallel_tests/rspec/summary_logger_spec.rb +37 -0
- data/spec/parallel_tests/tasks_spec.rb +151 -0
- data/spec/parallel_tests/test/runner_spec.rb +413 -0
- data/spec/parallel_tests/test/runtime_logger_spec.rb +90 -0
- data/spec/parallel_tests_spec.rb +137 -0
- data/spec/spec_helper.rb +157 -0
- 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
|