test-queue 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile-cucumber1-3.lock +1 -1
- data/Gemfile-cucumber2-4.lock +1 -1
- data/Gemfile-minitest4.lock +1 -1
- data/Gemfile-minitest5.lock +1 -1
- data/Gemfile-rspec2-1.lock +1 -1
- data/Gemfile-rspec3-0.lock +1 -1
- data/Gemfile-rspec3-1.lock +1 -1
- data/Gemfile-rspec3-2.lock +1 -1
- data/Gemfile-testunit.lock +1 -1
- data/Gemfile.lock +1 -1
- data/lib/test_queue/iterator.rb +4 -2
- data/lib/test_queue/runner.rb +89 -22
- data/lib/test_queue/stats.rb +1 -1
- data/test-queue.gemspec +1 -1
- data/test/minitest5.bats +35 -6
- data/test/rspec.bats +1 -1
- data/test/samples/sample_use_shared_example1_spec.rb +1 -1
- data/test/samples/sample_use_shared_example2_spec.rb +1 -1
- data/test/sleepy_runner.rb +14 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14379da7829bc7f9e40a46dce33c344ff0bd434a
|
4
|
+
data.tar.gz: 7b21acc430c9bcada801f9aa48352afffdd78708
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac7142497a109a2c40ce726e74f32d5f86c18c21d6618820f85b3d13986c39214f4b6a1feeb3eb73d53ec4d93bb382a7b68e123ebb7502a0a6f2e49fe6062258
|
7
|
+
data.tar.gz: 3a9bfaee682cbde11361547ce43d4a7b6c61f60a8f31b8be9ea2081aec533741281fc6eec4ddcb9b3eb7c7186bfede9f5ea4bbcdaba2f27cbccda2fb785e51fa
|
data/Gemfile-cucumber1-3.lock
CHANGED
data/Gemfile-cucumber2-4.lock
CHANGED
data/Gemfile-minitest4.lock
CHANGED
data/Gemfile-minitest5.lock
CHANGED
data/Gemfile-rspec2-1.lock
CHANGED
data/Gemfile-rspec3-0.lock
CHANGED
data/Gemfile-rspec3-1.lock
CHANGED
data/Gemfile-rspec3-2.lock
CHANGED
data/Gemfile-testunit.lock
CHANGED
data/Gemfile.lock
CHANGED
data/lib/test_queue/iterator.rb
CHANGED
@@ -2,7 +2,7 @@ module TestQueue
|
|
2
2
|
class Iterator
|
3
3
|
attr_reader :sock
|
4
4
|
|
5
|
-
def initialize(test_framework, sock, filter=nil, early_failure_limit: nil)
|
5
|
+
def initialize(test_framework, sock, filter=nil, run_token:, early_failure_limit: nil)
|
6
6
|
@test_framework = test_framework
|
7
7
|
@done = false
|
8
8
|
@suite_stats = []
|
@@ -14,6 +14,7 @@ module TestQueue
|
|
14
14
|
end
|
15
15
|
@failures = 0
|
16
16
|
@early_failure_limit = early_failure_limit
|
17
|
+
@run_token = run_token
|
17
18
|
end
|
18
19
|
|
19
20
|
def each
|
@@ -29,7 +30,7 @@ module TestQueue
|
|
29
30
|
connect_to_master("KABOOM")
|
30
31
|
break
|
31
32
|
else
|
32
|
-
client = connect_to_master(
|
33
|
+
client = connect_to_master("POP #{Socket.gethostname} #{Process.pid}")
|
33
34
|
end
|
34
35
|
break if client.nil?
|
35
36
|
_r, _w, e = IO.select([client], nil, [client], nil)
|
@@ -79,6 +80,7 @@ module TestQueue
|
|
79
80
|
else
|
80
81
|
UNIXSocket.new(@sock)
|
81
82
|
end
|
83
|
+
sock.puts("TOKEN=#{@run_token}")
|
82
84
|
sock.puts(cmd)
|
83
85
|
sock
|
84
86
|
rescue Errno::EPIPE
|
data/lib/test_queue/runner.rb
CHANGED
@@ -31,6 +31,8 @@ module TestQueue
|
|
31
31
|
attr_accessor :concurrency, :exit_when_done
|
32
32
|
attr_reader :stats
|
33
33
|
|
34
|
+
TOKEN_REGEX = /^TOKEN=(\w+)/
|
35
|
+
|
34
36
|
def initialize(test_framework, concurrency=nil, socket=nil, relay=nil)
|
35
37
|
@test_framework = test_framework
|
36
38
|
@stats = Stats.new(stats_file)
|
@@ -63,7 +65,7 @@ module TestQueue
|
|
63
65
|
@queue.sort_by! { |suite_name, path| @whitelist.index(suite_name) }
|
64
66
|
end
|
65
67
|
|
66
|
-
@awaited_suites = Set.new(@whitelist
|
68
|
+
@awaited_suites = Set.new(@whitelist)
|
67
69
|
@original_queue = Set.new(@queue).freeze
|
68
70
|
|
69
71
|
@workers = {}
|
@@ -72,7 +74,7 @@ module TestQueue
|
|
72
74
|
@concurrency =
|
73
75
|
concurrency ||
|
74
76
|
(ENV['TEST_QUEUE_WORKERS'] && ENV['TEST_QUEUE_WORKERS'].to_i) ||
|
75
|
-
if File.
|
77
|
+
if File.exist?('/proc/cpuinfo')
|
76
78
|
File.read('/proc/cpuinfo').split("\n").grep(/processor/).size
|
77
79
|
elsif RUBY_PLATFORM =~ /darwin/
|
78
80
|
`/usr/sbin/sysctl -n hw.activecpu`.to_i
|
@@ -107,7 +109,12 @@ module TestQueue
|
|
107
109
|
@queue = []
|
108
110
|
end
|
109
111
|
|
112
|
+
@discovered_suites = Set.new
|
113
|
+
@assignments = {}
|
114
|
+
|
110
115
|
@exit_when_done = true
|
116
|
+
|
117
|
+
@aborting = false
|
111
118
|
end
|
112
119
|
|
113
120
|
# Run the tests.
|
@@ -134,9 +141,23 @@ module TestQueue
|
|
134
141
|
puts "==> Summary (#{@completed.size} workers in %.4fs)" % (Time.now-@start_time)
|
135
142
|
puts
|
136
143
|
|
144
|
+
estatus = 0
|
145
|
+
misrun_suites = []
|
146
|
+
unassigned_suites = []
|
137
147
|
@failures = ''
|
138
148
|
@completed.each do |worker|
|
149
|
+
estatus += worker.status.exitstatus
|
139
150
|
@stats.record_suites(worker.suites)
|
151
|
+
worker.suites.each do |suite|
|
152
|
+
assignment = @assignments.delete([suite.name, suite.path])
|
153
|
+
host = worker.host || Socket.gethostname
|
154
|
+
if assignment.nil?
|
155
|
+
unassigned_suites << [suite.name, suite.path]
|
156
|
+
elsif assignment != [host, worker.pid]
|
157
|
+
misrun_suites << [suite.name, suite.path] + assignment + [host, worker.pid]
|
158
|
+
end
|
159
|
+
@discovered_suites.delete([suite.name, suite.path])
|
160
|
+
end
|
140
161
|
|
141
162
|
summarize_worker(worker)
|
142
163
|
|
@@ -160,15 +181,44 @@ module TestQueue
|
|
160
181
|
puts @failures
|
161
182
|
end
|
162
183
|
|
184
|
+
if !relay?
|
185
|
+
unless @discovered_suites.empty?
|
186
|
+
estatus += 1
|
187
|
+
puts
|
188
|
+
puts "The following suites were discovered but were not run:"
|
189
|
+
puts
|
190
|
+
|
191
|
+
@discovered_suites.sort.each do |suite_name, path|
|
192
|
+
puts "#{suite_name} - #{path}"
|
193
|
+
end
|
194
|
+
end
|
195
|
+
unless unassigned_suites.empty?
|
196
|
+
estatus += 1
|
197
|
+
puts
|
198
|
+
puts "The following suites were not discovered but were run anyway:"
|
199
|
+
puts
|
200
|
+
unassigned_suites.sort.each do |suite_name, path|
|
201
|
+
puts "#{suite_name} - #{path}"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
unless misrun_suites.empty?
|
205
|
+
estatus += 1
|
206
|
+
puts
|
207
|
+
puts "The following suites were run on the wrong workers:"
|
208
|
+
puts
|
209
|
+
misrun_suites.each do |suite_name, path, target_host, target_pid, actual_host, actual_pid|
|
210
|
+
puts "#{suite_name} - #{path}: #{actual_host} (#{actual_pid}) - assigned to #{target_host} (#{target_pid})"
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
163
215
|
puts
|
164
216
|
|
165
217
|
@stats.save
|
166
218
|
|
167
219
|
summarize
|
168
220
|
|
169
|
-
estatus
|
170
|
-
estatus = 255 if estatus > 255
|
171
|
-
estatus
|
221
|
+
[estatus, 255].min
|
172
222
|
end
|
173
223
|
|
174
224
|
def summarize
|
@@ -201,7 +251,7 @@ module TestQueue
|
|
201
251
|
@socket = "#$1:#$2"
|
202
252
|
@server = TCPServer.new(address, port)
|
203
253
|
else
|
204
|
-
FileUtils.rm(@socket) if File.
|
254
|
+
FileUtils.rm(@socket) if File.exist?(@socket)
|
205
255
|
@server = UNIXServer.new(@socket)
|
206
256
|
end
|
207
257
|
end
|
@@ -217,7 +267,8 @@ module TestQueue
|
|
217
267
|
sock = connect_to_relay
|
218
268
|
message = @slave_message ? " #{@slave_message}" : ""
|
219
269
|
message.gsub!(/(\r|\n)/, "") # Our "protocol" is newline-separated
|
220
|
-
sock.puts("
|
270
|
+
sock.puts("TOKEN=#{@run_token}")
|
271
|
+
sock.puts("SLAVE #{@concurrency} #{Socket.gethostname} #{message}")
|
221
272
|
response = sock.gets.strip
|
222
273
|
unless response == "OK"
|
223
274
|
STDERR.puts "*** Got non-OK response from master: #{response}"
|
@@ -245,7 +296,7 @@ module TestQueue
|
|
245
296
|
pid = fork do
|
246
297
|
@server.close if @server
|
247
298
|
|
248
|
-
iterator = Iterator.new(@test_framework, relay?? @relay : @socket, method(:around_filter), early_failure_limit: @early_failure_limit)
|
299
|
+
iterator = Iterator.new(@test_framework, relay?? @relay : @socket, method(:around_filter), early_failure_limit: @early_failure_limit, run_token: @run_token)
|
249
300
|
after_fork_internal(num, iterator)
|
250
301
|
ret = run_worker(iterator) || 0
|
251
302
|
cleanup_worker
|
@@ -276,6 +327,7 @@ module TestQueue
|
|
276
327
|
Kernel.exit!(0) if terminate
|
277
328
|
|
278
329
|
@server.connect_address.connect do |sock|
|
330
|
+
sock.puts("TOKEN=#{@run_token}")
|
279
331
|
sock.puts("NEW SUITE #{Marshal.dump([suite_name, path])}")
|
280
332
|
end
|
281
333
|
end
|
@@ -305,8 +357,11 @@ module TestQueue
|
|
305
357
|
return
|
306
358
|
end
|
307
359
|
|
360
|
+
@discovered_suites << [suite_name, path]
|
361
|
+
|
308
362
|
if @original_queue.include?([suite_name, path])
|
309
363
|
# This suite was already added to the queue some other way.
|
364
|
+
@awaited_suites.delete(suite_name)
|
310
365
|
return
|
311
366
|
end
|
312
367
|
|
@@ -393,12 +448,12 @@ module TestQueue
|
|
393
448
|
end
|
394
449
|
|
395
450
|
def collect_worker_data(worker)
|
396
|
-
if File.
|
451
|
+
if File.exist?(file = "/tmp/test_queue_worker_#{worker.pid}_output")
|
397
452
|
worker.output = IO.binread(file)
|
398
453
|
FileUtils.rm(file)
|
399
454
|
end
|
400
455
|
|
401
|
-
if File.
|
456
|
+
if File.exist?(file = "/tmp/test_queue_worker_#{worker.pid}_suites")
|
402
457
|
worker.suites.replace(Marshal.load(IO.binread(file)))
|
403
458
|
FileUtils.rm(file)
|
404
459
|
end
|
@@ -426,29 +481,38 @@ module TestQueue
|
|
426
481
|
reap_workers(false) # check for worker deaths
|
427
482
|
else
|
428
483
|
sock = @server.accept
|
484
|
+
token = sock.gets.strip
|
429
485
|
cmd = sock.gets.strip
|
486
|
+
|
487
|
+
token = token[TOKEN_REGEX, 1]
|
488
|
+
# If we have a slave from a different test run, respond with "WRONG RUN", and it will consider the test run done.
|
489
|
+
if token != @run_token
|
490
|
+
message = token.nil? ? "Worker sent no token to master" : "Worker from run #{token} connected to master"
|
491
|
+
STDERR.puts "*** #{message} for run #{@run_token}; ignoring."
|
492
|
+
sock.write("WRONG RUN\n")
|
493
|
+
next
|
494
|
+
end
|
495
|
+
|
430
496
|
case cmd
|
431
|
-
when /^POP/
|
497
|
+
when /^POP (\S+) (\d+)/
|
432
498
|
# If we have a slave from a different test run, don't respond, and it will consider the test run done.
|
499
|
+
hostname = $1
|
500
|
+
pid = Integer($2)
|
433
501
|
if awaiting_suites?
|
434
502
|
sock.write(Marshal.dump("WAIT"))
|
435
503
|
elsif obj = @queue.shift
|
436
504
|
data = Marshal.dump(obj)
|
437
505
|
sock.write(data)
|
506
|
+
@assignments[obj] = [hostname, pid]
|
438
507
|
end
|
439
|
-
when /^SLAVE (\d+) ([\w\.-]+)
|
508
|
+
when /^SLAVE (\d+) ([\w\.-]+)(?: (.+))?/
|
440
509
|
num = $1.to_i
|
441
510
|
slave = $2
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
remote_workers += num
|
448
|
-
else
|
449
|
-
STDERR.puts "*** Worker from run #{run_token} connected to master for run #{@run_token}; ignoring."
|
450
|
-
sock.write("WRONG RUN\n")
|
451
|
-
end
|
511
|
+
slave_message = $3
|
512
|
+
|
513
|
+
sock.write("OK\n")
|
514
|
+
remote_workers += num
|
515
|
+
|
452
516
|
message = "*** #{num} workers connected from #{slave} after #{Time.now-@start_time}s"
|
453
517
|
message << " " + slave_message if slave_message
|
454
518
|
STDERR.puts message
|
@@ -464,6 +528,8 @@ module TestQueue
|
|
464
528
|
# worker reporting an abnormal number of test failures;
|
465
529
|
# stop everything immediately and report the results.
|
466
530
|
break
|
531
|
+
else
|
532
|
+
STDERR.puts("Ignoring unrecognized command: \"#{cmd}\"")
|
467
533
|
end
|
468
534
|
sock.close
|
469
535
|
end
|
@@ -498,6 +564,7 @@ module TestQueue
|
|
498
564
|
data = Marshal.dump(worker)
|
499
565
|
|
500
566
|
sock = connect_to_relay
|
567
|
+
sock.puts("TOKEN=#{@run_token}")
|
501
568
|
sock.puts("WORKER #{data.bytesize}")
|
502
569
|
sock.write(data)
|
503
570
|
ensure
|
data/lib/test_queue/stats.rb
CHANGED
@@ -74,7 +74,7 @@ module TestQueue
|
|
74
74
|
def load
|
75
75
|
data = begin
|
76
76
|
File.open(@path, "rb") { |f| Marshal.load(f) }
|
77
|
-
rescue Errno::ENOENT, EOFError, TypeError
|
77
|
+
rescue Errno::ENOENT, EOFError, TypeError, ArgumentError
|
78
78
|
end
|
79
79
|
return unless data && data.is_a?(Hash) && data[:version] == CURRENT_VERSION
|
80
80
|
data[:suites].each do |suite_hash|
|
data/test-queue.gemspec
CHANGED
data/test/minitest5.bats
CHANGED
@@ -74,23 +74,52 @@ assert_test_queue_force_ordering() {
|
|
74
74
|
assert_output_contains "Failed to discover DoesNotExist specified in TEST_QUEUE_FORCE"
|
75
75
|
}
|
76
76
|
|
77
|
-
@test "multi-master succeeds when all tests pass" {
|
77
|
+
@test "multi-master central master succeeds when all tests pass" {
|
78
78
|
export TEST_QUEUE_RELAY_TOKEN=$(date | cksum | cut -d' ' -f1)
|
79
|
-
|
79
|
+
export SLEEP_AS_RELAY=1
|
80
|
+
TEST_QUEUE_RELAY=0.0.0.0:12345 bundle exec ruby ./test/sleepy_runner.rb ./test/samples/sample_minitest5.rb || true &
|
80
81
|
sleep 0.1
|
81
|
-
TEST_QUEUE_SOCKET=0.0.0.0:12345 run bundle exec
|
82
|
+
TEST_QUEUE_SOCKET=0.0.0.0:12345 run bundle exec ruby ./test/sleepy_runner.rb ./test/samples/sample_minitest5.rb
|
82
83
|
wait
|
83
84
|
|
84
85
|
assert_status 0
|
85
86
|
assert_output_contains "Starting test-queue master"
|
86
87
|
}
|
87
88
|
|
88
|
-
@test "multi-master
|
89
|
+
@test "multi-master remote master succeeds when all tests pass" {
|
90
|
+
export TEST_QUEUE_RELAY_TOKEN=$(date | cksum | cut -d' ' -f1)
|
91
|
+
export SLEEP_AS_MASTER=1
|
92
|
+
TEST_QUEUE_SOCKET=0.0.0.0:12345 bundle exec ruby ./test/sleepy_runner.rb ./test/samples/sample_minitest5.rb || true &
|
93
|
+
sleep 0.1
|
94
|
+
TEST_QUEUE_RELAY=0.0.0.0:12345 run bundle exec ruby ./test/sleepy_runner.rb ./test/samples/sample_minitest5.rb
|
95
|
+
wait
|
96
|
+
|
97
|
+
assert_status 0
|
98
|
+
assert_output_contains "Starting test-queue master"
|
99
|
+
}
|
100
|
+
|
101
|
+
@test "multi-master central master fails when a test fails" {
|
102
|
+
export FAIL=1
|
103
|
+
export SLEEP_AS_RELAY=1
|
104
|
+
export TEST_QUEUE_RELAY_TOKEN=$(date | cksum | cut -d' ' -f1)
|
105
|
+
TEST_QUEUE_RELAY=0.0.0.0:12345 bundle exec ruby ./test/sleepy_runner.rb ./test/samples/sample_minitest5.rb || true &
|
106
|
+
sleep 0.1
|
107
|
+
TEST_QUEUE_SOCKET=0.0.0.0:12345 run bundle exec ruby ./test/sleepy_runner.rb ./test/samples/sample_minitest5.rb
|
108
|
+
wait
|
109
|
+
|
110
|
+
assert_status 1
|
111
|
+
assert_output_contains "Starting test-queue master"
|
112
|
+
assert_output_contains "1) Failure:"
|
113
|
+
assert_output_contains "MiniTestFailure#test_fail"
|
114
|
+
}
|
115
|
+
|
116
|
+
@test "multi-master remote master fails when a test fails" {
|
89
117
|
export FAIL=1
|
118
|
+
export SLEEP_AS_MASTER=1
|
90
119
|
export TEST_QUEUE_RELAY_TOKEN=$(date | cksum | cut -d' ' -f1)
|
91
|
-
|
120
|
+
TEST_QUEUE_SOCKET=0.0.0.0:12345 bundle exec ruby ./test/sleepy_runner.rb ./test/samples/sample_minitest5.rb || true &
|
92
121
|
sleep 0.1
|
93
|
-
|
122
|
+
TEST_QUEUE_RELAY=0.0.0.0:12345 run bundle exec ruby ./test/sleepy_runner.rb ./test/samples/sample_minitest5.rb
|
94
123
|
wait
|
95
124
|
|
96
125
|
assert_status 1
|
data/test/rspec.bats
CHANGED
@@ -37,7 +37,7 @@ setup() {
|
|
37
37
|
assert_output_contains "0 examples, 0 failures"
|
38
38
|
}
|
39
39
|
|
40
|
-
@test "
|
40
|
+
@test "rspec-queue supports shared example groups" {
|
41
41
|
run bundle exec rspec-queue ./test/samples/sample_use_shared_example1_spec.rb \
|
42
42
|
./test/samples/sample_use_shared_example2_spec.rb
|
43
43
|
assert_status 0
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'test_queue'
|
2
|
+
require 'test_queue/runner/minitest'
|
3
|
+
|
4
|
+
class SleepyTestRunner < TestQueue::Runner::MiniTest
|
5
|
+
def after_fork(num)
|
6
|
+
if ENV['SLEEP_AS_RELAY'] && relay?
|
7
|
+
sleep 5
|
8
|
+
elsif ENV['SLEEP_AS_MASTER'] && !relay?
|
9
|
+
sleep 5
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
SleepyTestRunner.new.execute
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: test-queue
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aman Gupta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-01-06 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: minitest/rspec parallel test runner for CI environments
|
14
14
|
email: ruby@tmm1.net
|
@@ -86,6 +86,7 @@ files:
|
|
86
86
|
- test/samples/sample_testunit.rb
|
87
87
|
- test/samples/sample_use_shared_example1_spec.rb
|
88
88
|
- test/samples/sample_use_shared_example2_spec.rb
|
89
|
+
- test/sleepy_runner.rb
|
89
90
|
- test/testlib.bash
|
90
91
|
- test/testunit.bats
|
91
92
|
homepage: http://github.com/tmm1/test-queue
|