test-queue 0.4.0 → 0.4.1
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 +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
|