test-queue 0.6.0 → 0.8.0

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +42 -42
  3. data/exe/cucumber-queue +2 -1
  4. data/exe/minitest-queue +3 -2
  5. data/exe/rspec-queue +2 -1
  6. data/exe/testunit-queue +2 -1
  7. data/lib/test-queue.rb +2 -0
  8. data/lib/test_queue/iterator.rb +23 -15
  9. data/lib/test_queue/runner/cucumber.rb +3 -0
  10. data/lib/test_queue/runner/{sample.rb → example.rb} +30 -9
  11. data/lib/test_queue/runner/minitest.rb +5 -3
  12. data/lib/test_queue/runner/minitest4.rb +12 -7
  13. data/lib/test_queue/runner/minitest5.rb +37 -22
  14. data/lib/test_queue/runner/puppet_lint.rb +6 -4
  15. data/lib/test_queue/runner/rspec.rb +15 -4
  16. data/lib/test_queue/runner/rspec2.rb +24 -24
  17. data/lib/test_queue/runner/rspec3.rb +11 -11
  18. data/lib/test_queue/runner/testunit.rb +6 -3
  19. data/lib/test_queue/runner.rb +93 -103
  20. data/lib/test_queue/stats.rb +17 -13
  21. data/lib/test_queue/test_framework.rb +2 -0
  22. data/lib/test_queue/version.rb +5 -0
  23. data/lib/test_queue.rb +1 -5
  24. metadata +7 -42
  25. data/.github/workflows/test.yml +0 -93
  26. data/.gitignore +0 -6
  27. data/Appraisals +0 -35
  28. data/Gemfile +0 -7
  29. data/Rakefile +0 -14
  30. data/gemfiles/cucumber1_3.gemfile +0 -9
  31. data/gemfiles/cucumber2_4.gemfile +0 -9
  32. data/gemfiles/minitest4.gemfile +0 -7
  33. data/gemfiles/minitest5.gemfile +0 -7
  34. data/gemfiles/rspec2.gemfile +0 -8
  35. data/gemfiles/rspec3.gemfile +0 -7
  36. data/gemfiles/testunit.gemfile +0 -7
  37. data/script/bootstrap +0 -13
  38. data/spec/stats_spec.rb +0 -79
  39. data/test/cucumber.bats +0 -57
  40. data/test/minitest4.bats +0 -34
  41. data/test/minitest5.bats +0 -194
  42. data/test/rspec2.bats +0 -46
  43. data/test/rspec3.bats +0 -56
  44. data/test/samples/features/bad.feature +0 -5
  45. data/test/samples/features/sample.feature +0 -25
  46. data/test/samples/features/sample2.feature +0 -29
  47. data/test/samples/features/step_definitions/common.rb +0 -19
  48. data/test/samples/sample_minispec.rb +0 -37
  49. data/test/samples/sample_minitest4.rb +0 -25
  50. data/test/samples/sample_minitest5.rb +0 -33
  51. data/test/samples/sample_rspec_helper.rb +0 -1
  52. data/test/samples/sample_shared_examples_for_spec.rb +0 -5
  53. data/test/samples/sample_spec.rb +0 -25
  54. data/test/samples/sample_split_spec.rb +0 -17
  55. data/test/samples/sample_testunit.rb +0 -25
  56. data/test/samples/sample_use_shared_example1_spec.rb +0 -8
  57. data/test/samples/sample_use_shared_example2_spec.rb +0 -8
  58. data/test/sleepy_runner.rb +0 -16
  59. data/test/testlib.bash +0 -89
  60. data/test/testunit.bats +0 -20
  61. data/test-queue.gemspec +0 -21
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ::RSpec::Core::ExampleGroup
2
4
  def self.failure_count
3
- examples.map {|e| e.execution_result[:status] == "failed"}.length
5
+ examples.map { |e| e.execution_result[:status] == 'failed' }.length
4
6
  end
5
7
  end
6
8
 
@@ -14,30 +16,28 @@ module RSpec::Core
14
16
 
15
17
  def run_each(iterator)
16
18
  @configuration.reporter.report(0, @configuration.randomize? ? @configuration.seed : nil) do |reporter|
17
- begin
18
- @configuration.run_hook(:before, :suite)
19
- iterator.map {|g|
20
- if g.is_a? ::RSpec::Core::Example
21
- print " #{g.full_description}: "
22
- example = g
23
- g = example.example_group
24
- ::RSpec.world.filtered_examples.clear
25
- examples = [example]
26
- examples.extend(::RSpec::Core::Extensions::Ordered::Examples)
27
- ::RSpec.world.filtered_examples[g] = examples
28
- else
29
- print " #{g.description}: "
30
- end
31
- start = Time.now
32
- ret = g.run(reporter)
33
- diff = Time.now-start
34
- puts(" <%.3f>" % diff)
19
+ @configuration.run_hook(:before, :suite)
20
+ iterator.map { |g|
21
+ if g.is_a? ::RSpec::Core::Example
22
+ print " #{g.full_description}: "
23
+ example = g
24
+ g = example.example_group
25
+ ::RSpec.world.filtered_examples.clear
26
+ examples = [example]
27
+ examples.extend(::RSpec::Core::Extensions::Ordered::Examples)
28
+ ::RSpec.world.filtered_examples[g] = examples
29
+ else
30
+ print " #{g.description}: "
31
+ end
32
+ start = Time.now
33
+ ret = g.run(reporter)
34
+ diff = Time.now - start
35
+ puts(' <%.3f>' % diff)
35
36
 
36
- ret
37
- }.all? ? 0 : @configuration.failure_exit_code
38
- ensure
39
- @configuration.run_hook(:after, :suite)
40
- end
37
+ ret
38
+ }.all? ? 0 : @configuration.failure_exit_code
39
+ ensure
40
+ @configuration.run_hook(:after, :suite)
41
41
  end
42
42
  end
43
43
  end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ::RSpec::Core::ExampleGroup
2
4
  def self.failure_count
3
- examples.map {|e| e.execution_result.status == "failed"}.length
5
+ examples.map { |e| e.execution_result.status == 'failed' }.length
4
6
  end
5
7
  end
6
8
 
@@ -9,13 +11,11 @@ module RSpec::Core
9
11
  unless Configuration.method_defined?(:with_suite_hooks)
10
12
  class Configuration
11
13
  def with_suite_hooks
12
- begin
13
- hook_context = SuiteHookContext.new
14
- hooks.run(:before, :suite, hook_context)
15
- yield
16
- ensure
17
- hooks.run(:after, :suite, hook_context)
18
- end
14
+ hook_context = SuiteHookContext.new
15
+ hooks.run(:before, :suite, hook_context)
16
+ yield
17
+ ensure
18
+ hooks.run(:after, :suite, hook_context)
19
19
  end
20
20
  end
21
21
  end
@@ -41,14 +41,14 @@ module RSpec::Core
41
41
  print " #{g.description}: "
42
42
  end
43
43
  ret = g.run(reporter)
44
- diff = Time.now-start
45
- puts(" <%.3f>" % diff)
44
+ diff = Time.now - start
45
+ puts(' <%.3f>' % diff)
46
46
 
47
47
  ret
48
48
  }.all? ? 0 : @configuration.failure_exit_code
49
49
  end
50
50
  end
51
51
  end
52
- alias_method :run_each, :run_specs
52
+ alias run_each run_specs
53
53
  end
54
54
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../runner'
2
4
 
3
5
  gem 'test-unit'
@@ -28,7 +30,7 @@ class Test::Unit::TestSuite
28
30
  end
29
31
 
30
32
  def failure_count
31
- (@iterator || @tests).map {|t| t.instance_variable_get(:@_result).failure_count}.inject(0, :+)
33
+ (@iterator || @tests).sum { |t| t.instance_variable_get(:@_result).failure_count }
32
34
  end
33
35
  end
34
36
 
@@ -37,13 +39,14 @@ module TestQueue
37
39
  class TestUnit < Runner
38
40
  def initialize
39
41
  if Test::Unit::Collector::Descendant.new.collect.tests.any?
40
- fail "Do not `require` test files. Pass them via ARGV instead and they will be required as needed."
42
+ raise 'Do not `require` test files. Pass them via ARGV instead and they will be required as needed.'
41
43
  end
44
+
42
45
  super(TestFramework::TestUnit.new)
43
46
  end
44
47
 
45
48
  def run_worker(iterator)
46
- @suite = Test::Unit::TestSuite.new("specified by test-queue master")
49
+ @suite = Test::Unit::TestSuite.new('specified by test-queue master')
47
50
  @suite.iterator = iterator
48
51
  res = Test::Unit::UI::Console::TestRunner.new(@suite).start
49
52
  res.run_count - res.pass_count
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
2
4
  require 'socket'
3
5
  require 'fileutils'
@@ -31,9 +33,9 @@ module TestQueue
31
33
  attr_accessor :concurrency, :exit_when_done
32
34
  attr_reader :stats
33
35
 
34
- TOKEN_REGEX = /^TOKEN=(\w+)/
36
+ TOKEN_REGEX = /\ATOKEN=(\w+)/
35
37
 
36
- def initialize(test_framework, concurrency=nil, socket=nil, relay=nil)
38
+ def initialize(test_framework, concurrency = nil, socket = nil, relay = nil)
37
39
  @test_framework = test_framework
38
40
  @stats = Stats.new(stats_file)
39
41
 
@@ -48,7 +50,7 @@ module TestQueue
48
50
 
49
51
  @procline = $0
50
52
 
51
- @allowlist = if forced = ENV['TEST_QUEUE_FORCE']
53
+ @allowlist = if (forced = ENV['TEST_QUEUE_FORCE'])
52
54
  forced.split(/\s*,\s*/)
53
55
  else
54
56
  []
@@ -57,13 +59,13 @@ module TestQueue
57
59
 
58
60
  all_files = @test_framework.all_suite_files.to_set
59
61
  @queue = @stats.all_suites
60
- .select { |suite| all_files.include?(suite.path) }
61
- .sort_by { |suite| -suite.duration }
62
- .map { |suite| [suite.name, suite.path] }
62
+ .select { |suite| all_files.include?(suite.path) }
63
+ .sort_by { |suite| -suite.duration }
64
+ .map { |suite| [suite.name, suite.path] }
63
65
 
64
66
  if @allowlist.any?
65
- @queue.select! { |suite_name, path| @allowlist.include?(suite_name) }
66
- @queue.sort_by! { |suite_name, path| @allowlist.index(suite_name) }
67
+ @queue.select! { |suite_name, _path| @allowlist.include?(suite_name) }
68
+ @queue.sort_by! { |suite_name, _path| @allowlist.index(suite_name) }
67
69
  end
68
70
 
69
71
  @awaited_suites = Set.new(@allowlist)
@@ -72,44 +74,32 @@ module TestQueue
72
74
  @workers = {}
73
75
  @completed = []
74
76
 
75
- @concurrency =
76
- concurrency ||
77
- (ENV['TEST_QUEUE_WORKERS'] && ENV['TEST_QUEUE_WORKERS'].to_i) ||
78
- if File.exist?('/proc/cpuinfo')
79
- File.read('/proc/cpuinfo').split("\n").grep(/processor/).size
80
- elsif RUBY_PLATFORM =~ /darwin/
81
- `/usr/sbin/sysctl -n hw.activecpu`.to_i
82
- else
83
- 2
84
- end
77
+ @concurrency = concurrency || ENV['TEST_QUEUE_WORKERS']&.to_i ||
78
+ if File.exist?('/proc/cpuinfo')
79
+ File.read('/proc/cpuinfo').split("\n").grep(/processor/).size
80
+ elsif RUBY_PLATFORM.include?('darwin')
81
+ `/usr/sbin/sysctl -n hw.activecpu`.to_i
82
+ else
83
+ 2
84
+ end
85
85
  unless @concurrency > 0
86
86
  raise ArgumentError, "Worker count (#{@concurrency}) must be greater than 0"
87
87
  end
88
88
 
89
- @relay_connection_timeout =
90
- (ENV['TEST_QUEUE_RELAY_TIMEOUT'] && ENV['TEST_QUEUE_RELAY_TIMEOUT'].to_i) ||
91
- 30
92
-
89
+ @relay_connection_timeout = ENV['TEST_QUEUE_RELAY_TIMEOUT']&.to_i || 30
93
90
  @run_token = ENV['TEST_QUEUE_RELAY_TOKEN'] || SecureRandom.hex(8)
94
-
95
- @socket =
96
- socket ||
97
- ENV['TEST_QUEUE_SOCKET'] ||
98
- "/tmp/test_queue_#{$$}_#{object_id}.sock"
99
-
100
- @relay =
101
- relay ||
102
- ENV['TEST_QUEUE_RELAY']
103
-
104
- @remote_master_message = if ENV.has_key?("TEST_QUEUE_REMOTE_MASTER_MESSAGE")
105
- ENV["TEST_QUEUE_REMOTE_MASTER_MESSAGE"]
106
- elsif ENV.has_key?("TEST_QUEUE_SLAVE_MESSAGE")
107
- warn("`TEST_QUEUE_SLAVE_MESSAGE` is deprecated. Use `TEST_QUEUE_REMOTE_MASTER_MESSAGE` instead.")
108
- ENV["TEST_QUEUE_SLAVE_MESSAGE"]
91
+ @socket = socket || ENV['TEST_QUEUE_SOCKET'] || "/tmp/test_queue_#{$$}_#{object_id}.sock"
92
+ @relay = relay || ENV['TEST_QUEUE_RELAY']
93
+
94
+ @remote_master_message = if ENV.key?('TEST_QUEUE_REMOTE_MASTER_MESSAGE')
95
+ ENV['TEST_QUEUE_REMOTE_MASTER_MESSAGE']
96
+ elsif ENV.key?('TEST_QUEUE_SLAVE_MESSAGE')
97
+ warn('`TEST_QUEUE_SLAVE_MESSAGE` is deprecated. Use `TEST_QUEUE_REMOTE_MASTER_MESSAGE` instead.')
98
+ ENV['TEST_QUEUE_SLAVE_MESSAGE']
109
99
  end
110
100
 
111
101
  if @relay == @socket
112
- STDERR.puts "*** Detected TEST_QUEUE_RELAY == TEST_QUEUE_SOCKET. Disabling relay mode."
102
+ warn '*** Detected TEST_QUEUE_RELAY == TEST_QUEUE_SOCKET. Disabling relay mode.'
113
103
  @relay = nil
114
104
  elsif @relay
115
105
  @queue = []
@@ -144,7 +134,7 @@ module TestQueue
144
134
 
145
135
  def summarize_internal
146
136
  puts
147
- puts "==> Summary (#{@completed.size} workers in %.4fs)" % (Time.now-@start_time)
137
+ puts "==> Summary (#{@completed.size} workers in %.4fs)" % (Time.now - @start_time)
148
138
  puts
149
139
 
150
140
  estatus = 0
@@ -167,9 +157,9 @@ module TestQueue
167
157
 
168
158
  summarize_worker(worker)
169
159
 
170
- @failures << worker.failure_output if worker.failure_output
160
+ @failures += worker.failure_output if worker.failure_output
171
161
 
172
- puts " [%2d] %60s %4d suites in %.4fs (%s %s)" % [
162
+ puts ' [%2d] %60s %4d suites in %.4fs (%s %s)' % [
173
163
  worker.num,
174
164
  worker.summary,
175
165
  worker.suites.size,
@@ -181,16 +171,16 @@ module TestQueue
181
171
 
182
172
  unless @failures.empty?
183
173
  puts
184
- puts "==> Failures"
174
+ puts '==> Failures'
185
175
  puts
186
176
  puts @failures
187
177
  end
188
178
 
189
- if !relay?
179
+ unless relay?
190
180
  unless @discovered_suites.empty?
191
181
  estatus += 1
192
182
  puts
193
- puts "The following suites were discovered but were not run:"
183
+ puts 'The following suites were discovered but were not run:'
194
184
  puts
195
185
 
196
186
  @discovered_suites.sort.each do |suite_name, path|
@@ -200,7 +190,7 @@ module TestQueue
200
190
  unless unassigned_suites.empty?
201
191
  estatus += 1
202
192
  puts
203
- puts "The following suites were not discovered but were run anyway:"
193
+ puts 'The following suites were not discovered but were run anyway:'
204
194
  puts
205
195
  unassigned_suites.sort.each do |suite_name, path|
206
196
  puts "#{suite_name} - #{path}"
@@ -209,7 +199,7 @@ module TestQueue
209
199
  unless misrun_suites.empty?
210
200
  estatus += 1
211
201
  puts
212
- puts "The following suites were run on the wrong workers:"
202
+ puts 'The following suites were run on the wrong workers:'
213
203
  puts
214
204
  misrun_suites.each do |suite_name, path, target_host, target_pid, actual_host, actual_pid|
215
205
  puts "#{suite_name} - #{path}: #{actual_host} (#{actual_pid}) - assigned to #{target_host} (#{target_pid})"
@@ -223,7 +213,7 @@ module TestQueue
223
213
 
224
214
  summarize
225
215
 
226
- estatus = @completed.inject(0){ |s, worker| s + (worker.status.exitstatus || 1)}
216
+ estatus = @completed.inject(0) { |s, worker| s + (worker.status.exitstatus || 1) }
227
217
  [estatus, 255].min
228
218
  end
229
219
 
@@ -231,8 +221,7 @@ module TestQueue
231
221
  end
232
222
 
233
223
  def stats_file
234
- ENV['TEST_QUEUE_STATS'] ||
235
- '.test_queue_stats'
224
+ ENV['TEST_QUEUE_STATS'] || '.test_queue_stats'
236
225
  end
237
226
 
238
227
  def execute_internal
@@ -250,19 +239,19 @@ module TestQueue
250
239
  end
251
240
 
252
241
  def start_master
253
- if !relay?
254
- if @socket =~ /^(?:(.+):)?(\d+)$/
242
+ unless relay?
243
+ if @socket =~ /\A(?:(.+):)?(\d+)\z/
255
244
  address = $1 || '0.0.0.0'
256
245
  port = $2.to_i
257
- @socket = "#$1:#$2"
246
+ @socket = "#{$1}:#{$2}"
258
247
  @server = TCPServer.new(address, port)
259
248
  else
260
- FileUtils.rm(@socket) if File.exist?(@socket)
249
+ FileUtils.rm_f(@socket)
261
250
  @server = UNIXServer.new(@socket)
262
251
  end
263
252
  end
264
253
 
265
- desc = "test-queue master (#{relay?? "relaying to #{@relay}" : @socket})"
254
+ desc = "test-queue master (#{relay? ? "relaying to #{@relay}" : @socket})"
266
255
  puts "Starting #{desc}"
267
256
  $0 = "#{desc} - #{@procline}"
268
257
  end
@@ -271,19 +260,19 @@ module TestQueue
271
260
  return unless relay?
272
261
 
273
262
  sock = connect_to_relay
274
- message = @remote_master_message ? " #{@remote_master_message}" : ""
275
- message.gsub!(/(\r|\n)/, "") # Our "protocol" is newline-separated
263
+ message = @remote_master_message ? " #{@remote_master_message}" : ''
264
+ message = message.gsub(/(\r|\n)/, '') # Our "protocol" is newline-separated
276
265
  sock.puts("TOKEN=#{@run_token}")
277
266
  sock.puts("REMOTE MASTER #{@concurrency} #{Socket.gethostname} #{message}")
278
267
  response = sock.gets.strip
279
- unless response == "OK"
280
- STDERR.puts "*** Got non-OK response from master: #{response}"
268
+ unless response == 'OK'
269
+ warn "*** Got non-OK response from master: #{response}"
281
270
  sock.close
282
271
  exit! 1
283
272
  end
284
273
  sock.close
285
274
  rescue Errno::ECONNREFUSED
286
- STDERR.puts "*** Unable to connect to relay #{@relay}. Aborting.."
275
+ warn "*** Unable to connect to relay #{@relay}. Aborting..."
287
276
  exit! 1
288
277
  end
289
278
 
@@ -297,12 +286,12 @@ module TestQueue
297
286
 
298
287
  def spawn_workers
299
288
  @concurrency.times do |i|
300
- num = i+1
289
+ num = i + 1
301
290
 
302
291
  pid = fork do
303
- @server.close if @server
292
+ @server&.close
304
293
 
305
- iterator = Iterator.new(@test_framework, relay?? @relay : @socket, method(:around_filter), early_failure_limit: @early_failure_limit, run_token: @run_token)
294
+ iterator = Iterator.new(@test_framework, relay? ? @relay : @socket, method(:around_filter), early_failure_limit: @early_failure_limit, run_token: @run_token)
306
295
  after_fork_internal(num, iterator)
307
296
  ret = run_worker(iterator) || 0
308
297
  cleanup_worker
@@ -324,12 +313,12 @@ module TestQueue
324
313
 
325
314
  @discovering_suites_pid = fork do
326
315
  terminate = false
327
- Signal.trap("INT") { terminate = true }
316
+ Signal.trap('INT') { terminate = true }
328
317
 
329
- $0 = "test-queue suite discovery process"
318
+ $0 = 'test-queue suite discovery process'
330
319
 
331
320
  @test_framework.all_suite_files.each do |path|
332
- @test_framework.suites_from_file(path).each do |suite_name, suite|
321
+ @test_framework.suites_from_file(path).each do |suite_name, _suite|
333
322
  Kernel.exit!(0) if terminate
334
323
 
335
324
  @server.connect_address.connect do |sock|
@@ -344,13 +333,9 @@ module TestQueue
344
333
  end
345
334
 
346
335
  def awaiting_suites?
347
- case
348
- when @awaited_suites.any?
349
- # We're waiting to find all the allowlisted suites so we can run them
350
- # in the correct order.
351
- true
352
- when @queue.empty? && !!@discovering_suites_pid
353
- # We don't have any suites yet, but we're working on it.
336
+ # We're waiting to find all the allowlisted suites so we can run them in the correct order.
337
+ # Or we don't have any suites yet, but we're working on it.
338
+ if @awaited_suites.any? || @queue.empty? && !!@discovering_suites_pid
354
339
  true
355
340
  else
356
341
  # It's fine to run any queued suites now.
@@ -379,9 +364,9 @@ module TestQueue
379
364
  if @awaited_suites.delete?(suite_name) && @awaited_suites.empty?
380
365
  # We've found all the allowlisted suites. Sort the queue to match the
381
366
  # allowlist.
382
- @queue.sort_by! { |suite_name, path| @allowlist.index(suite_name) }
367
+ @queue.sort_by! { |queued_suite_name, _path| @allowlist.index(queued_suite_name) }
383
368
 
384
- kill_suite_discovery_process("INT")
369
+ kill_suite_discovery_process('INT')
385
370
  end
386
371
  end
387
372
 
@@ -396,7 +381,7 @@ module TestQueue
396
381
 
397
382
  $0 = "test-queue worker [#{num}]"
398
383
  puts
399
- puts "==> Starting #$0 (#{Process.pid} on #{Socket.gethostname}) - iterating over #{iterator.sock}"
384
+ puts "==> Starting #{$0} (#{Process.pid} on #{Socket.gethostname}) - iterating over #{iterator.sock}"
400
385
  puts
401
386
 
402
387
  after_fork(num)
@@ -408,7 +393,7 @@ module TestQueue
408
393
  def prepare(concurrency)
409
394
  end
410
395
 
411
- def around_filter(suite)
396
+ def around_filter(_suite)
412
397
  yield
413
398
  end
414
399
 
@@ -425,7 +410,7 @@ module TestQueue
425
410
  puts " #{item.inspect}"
426
411
  end
427
412
 
428
- return 0 # exit status
413
+ 0 # exit status
429
414
  end
430
415
 
431
416
  def cleanup_worker
@@ -436,7 +421,7 @@ module TestQueue
436
421
  worker.failure_output = ''
437
422
  end
438
423
 
439
- def reap_workers(blocking=true)
424
+ def reap_workers(blocking = true)
440
425
  @workers.delete_if do |_, worker|
441
426
  if Process.waitpid(worker.pid, blocking ? 0 : Process::WNOHANG).nil?
442
427
  next false
@@ -455,35 +440,37 @@ module TestQueue
455
440
 
456
441
  def collect_worker_data(worker)
457
442
  if File.exist?(file = "/tmp/test_queue_worker_#{worker.pid}_output")
458
- worker.output = IO.binread(file)
443
+ worker.output = File.binread(file)
459
444
  FileUtils.rm(file)
460
445
  end
461
446
 
462
447
  if File.exist?(file = "/tmp/test_queue_worker_#{worker.pid}_suites")
463
- worker.suites.replace(Marshal.load(IO.binread(file)))
448
+ worker.suites.replace(Marshal.load(File.binread(file)))
464
449
  FileUtils.rm(file)
465
450
  end
466
451
  end
467
452
 
468
453
  def worker_completed(worker)
469
454
  return if @aborting
455
+
470
456
  @completed << worker
471
457
  puts worker.output if ENV['TEST_QUEUE_VERBOSE'] || worker.status.exitstatus != 0
472
458
  end
473
459
 
474
460
  def distribute_queue
475
461
  return if relay?
462
+
476
463
  remote_workers = 0
477
464
 
478
465
  until !awaiting_suites? && @queue.empty? && remote_workers == 0
479
466
  queue_status(@start_time, @queue.size, @workers.size, remote_workers)
480
467
 
481
- if status = reap_suite_discovery_process(false)
482
- abort("Discovering suites failed.") unless status.success?
483
- abort("Failed to discover #{@awaited_suites.sort.join(", ")} specified in TEST_QUEUE_FORCE") if @awaited_suites.any?
468
+ if (status = reap_suite_discovery_process(false))
469
+ abort('Discovering suites failed.') unless status.success?
470
+ abort("Failed to discover #{@awaited_suites.sort.join(', ')} specified in TEST_QUEUE_FORCE") if @awaited_suites.any?
484
471
  end
485
472
 
486
- if IO.select([@server], nil, nil, 0.1).nil?
473
+ if @server.wait_readable(0.1).nil?
487
474
  reap_workers(false) # check for worker deaths
488
475
  else
489
476
  sock = @server.accept
@@ -493,24 +480,24 @@ module TestQueue
493
480
  token = token[TOKEN_REGEX, 1]
494
481
  # If we have a remote master from a different test run, respond with "WRONG RUN", and it will consider the test run done.
495
482
  if token != @run_token
496
- message = token.nil? ? "Worker sent no token to master" : "Worker from run #{token} connected to master"
497
- STDERR.puts "*** #{message} for run #{@run_token}; ignoring."
483
+ message = token.nil? ? 'Worker sent no token to master' : "Worker from run #{token} connected to master"
484
+ warn "*** #{message} for run #{@run_token}; ignoring."
498
485
  sock.write("WRONG RUN\n")
499
486
  next
500
487
  end
501
488
 
502
489
  case cmd
503
- when /^POP (\S+) (\d+)/
490
+ when /\APOP (\S+) (\d+)/
504
491
  hostname = $1
505
492
  pid = Integer($2)
506
493
  if awaiting_suites?
507
- sock.write(Marshal.dump("WAIT"))
508
- elsif obj = @queue.shift
494
+ sock.write(Marshal.dump('WAIT'))
495
+ elsif (obj = @queue.shift)
509
496
  data = Marshal.dump(obj)
510
497
  sock.write(data)
511
498
  @assignments[obj] = [hostname, pid]
512
499
  end
513
- when /^REMOTE MASTER (\d+) ([\w\.-]+)(?: (.+))?/
500
+ when /\AREMOTE MASTER (\d+) ([\w.-]+)(?: (.+))?/
514
501
  num = $1.to_i
515
502
  remote_master = $2
516
503
  remote_master_message = $3
@@ -518,23 +505,23 @@ module TestQueue
518
505
  sock.write("OK\n")
519
506
  remote_workers += num
520
507
 
521
- message = "*** #{num} workers connected from #{remote_master} after #{Time.now-@start_time}s"
522
- message << " " + remote_master_message if remote_master_message
523
- STDERR.puts message
524
- when /^WORKER (\d+)/
508
+ message = "*** #{num} workers connected from #{remote_master} after #{Time.now - @start_time}s"
509
+ message += " #{remote_master_message}" if remote_master_message
510
+ warn message
511
+ when /\AWORKER (\d+)/
525
512
  data = sock.read($1.to_i)
526
513
  worker = Marshal.load(data)
527
514
  worker_completed(worker)
528
515
  remote_workers -= 1
529
- when /^NEW SUITE (.+)/
516
+ when /\ANEW SUITE (.+)/
530
517
  suite_name, path = Marshal.load($1)
531
518
  enqueue_discovered_suite(suite_name, path)
532
- when /^KABOOM/
519
+ when /\AKABOOM/
533
520
  # worker reporting an abnormal number of test failures;
534
521
  # stop everything immediately and report the results.
535
522
  break
536
523
  else
537
- STDERR.puts("Ignoring unrecognized command: \"#{cmd}\"")
524
+ warn("Ignoring unrecognized command: \"#{cmd}\"")
538
525
  end
539
526
  sock.close
540
527
  end
@@ -557,7 +544,8 @@ module TestQueue
557
544
  sock = TCPSocket.new(*@relay.split(':'))
558
545
  rescue Errno::ECONNREFUSED => e
559
546
  raise e if Time.now - start > @relay_connection_timeout
560
- puts "Master not yet available, sleeping..."
547
+
548
+ puts 'Master not yet available, sleeping...'
561
549
  sleep 0.5
562
550
  end
563
551
  end
@@ -573,7 +561,7 @@ module TestQueue
573
561
  sock.puts("WORKER #{data.bytesize}")
574
562
  sock.write(data)
575
563
  ensure
576
- sock.close if sock
564
+ sock&.close
577
565
  end
578
566
 
579
567
  def kill_subprocesses
@@ -582,21 +570,23 @@ module TestQueue
582
570
  end
583
571
 
584
572
  def kill_workers
585
- @workers.each do |pid, worker|
573
+ @workers.each do |pid, _worker|
586
574
  Process.kill 'KILL', pid
587
575
  end
588
576
 
589
577
  reap_workers
590
578
  end
591
579
 
592
- def kill_suite_discovery_process(signal="KILL")
580
+ def kill_suite_discovery_process(signal = 'KILL')
593
581
  return unless @discovering_suites_pid
582
+
594
583
  Process.kill signal, @discovering_suites_pid
595
584
  reap_suite_discovery_process
596
585
  end
597
586
 
598
- def reap_suite_discovery_process(blocking=true)
587
+ def reap_suite_discovery_process(blocking = true)
599
588
  return unless @discovering_suites_pid
589
+
600
590
  _, status = Process.waitpid2(@discovering_suites_pid, blocking ? 0 : Process::WNOHANG)
601
591
  return unless status
602
592
 
@@ -612,7 +602,7 @@ module TestQueue
612
602
  def abort(message)
613
603
  @aborting = true
614
604
  kill_subprocesses
615
- Kernel::abort("Aborting: #{message}")
605
+ Kernel.abort("Aborting: #{message}")
616
606
  end
617
607
 
618
608
  # Subclasses can override to monitor the status of the queue.