ci-queue 0.82.0 → 0.83.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.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +87 -0
- data/lib/ci/queue/class_resolver.rb +38 -0
- data/lib/ci/queue/configuration.rb +62 -1
- data/lib/ci/queue/file_loader.rb +101 -0
- data/lib/ci/queue/queue_entry.rb +56 -0
- data/lib/ci/queue/redis/_entry_helpers.lua +10 -0
- data/lib/ci/queue/redis/acknowledge.lua +10 -7
- data/lib/ci/queue/redis/base.rb +33 -7
- data/lib/ci/queue/redis/build_record.rb +12 -0
- data/lib/ci/queue/redis/heartbeat.lua +9 -4
- data/lib/ci/queue/redis/monitor.rb +19 -5
- data/lib/ci/queue/redis/requeue.lua +19 -11
- data/lib/ci/queue/redis/reserve.lua +47 -8
- data/lib/ci/queue/redis/reserve_lost.lua +5 -1
- data/lib/ci/queue/redis/supervisor.rb +3 -3
- data/lib/ci/queue/redis/worker.rb +216 -23
- data/lib/ci/queue/version.rb +1 -1
- data/lib/ci/queue.rb +27 -0
- data/lib/minitest/queue/junit_reporter.rb +2 -2
- data/lib/minitest/queue/lazy_entry_resolver.rb +55 -0
- data/lib/minitest/queue/lazy_test_discovery.rb +169 -0
- data/lib/minitest/queue/local_requeue_reporter.rb +11 -0
- data/lib/minitest/queue/order_reporter.rb +9 -2
- data/lib/minitest/queue/queue_population_strategy.rb +176 -0
- data/lib/minitest/queue/runner.rb +97 -22
- data/lib/minitest/queue/test_data.rb +14 -1
- data/lib/minitest/queue/worker_profile_reporter.rb +77 -0
- data/lib/minitest/queue.rb +271 -6
- metadata +9 -1
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Minitest
|
|
4
|
+
module Queue
|
|
5
|
+
class WorkerProfileReporter
|
|
6
|
+
def initialize(supervisor, out: $stdout)
|
|
7
|
+
@supervisor = supervisor
|
|
8
|
+
@out = out
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def print_summary
|
|
12
|
+
return unless CI::Queue.debug?
|
|
13
|
+
|
|
14
|
+
expected = @supervisor.workers_count
|
|
15
|
+
profiles = {}
|
|
16
|
+
3.times do
|
|
17
|
+
profiles = @supervisor.build.worker_profiles
|
|
18
|
+
break if profiles.size >= expected
|
|
19
|
+
sleep 1
|
|
20
|
+
end
|
|
21
|
+
return if profiles.empty?
|
|
22
|
+
|
|
23
|
+
sorted = profiles.values.sort_by { |p| p['worker_id'].to_s }
|
|
24
|
+
mode = sorted.first&.dig('mode') || 'unknown'
|
|
25
|
+
|
|
26
|
+
@out.puts
|
|
27
|
+
@out.puts "Worker profile summary (#{sorted.size} workers, mode: #{mode}):"
|
|
28
|
+
@out.puts " %-12s %-12s %8s %14s %14s %14s %14s %10s" % ['Worker', 'Role', 'Tests', '1st Test', 'Wall Clock', 'Load Tests', 'File Load', 'Memory']
|
|
29
|
+
@out.puts " #{'-' * 100}"
|
|
30
|
+
|
|
31
|
+
sorted.each do |profile|
|
|
32
|
+
@out.puts format_profile_row(profile)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
print_first_test_summary(sorted)
|
|
36
|
+
rescue StandardError
|
|
37
|
+
# Don't fail the build if profile printing fails
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def format_profile_row(profile)
|
|
43
|
+
tests = profile['tests_run'] ? profile['tests_run'].to_s : 'n/a'
|
|
44
|
+
first_test = profile['time_to_first_test'] ? "#{profile['time_to_first_test']}s" : 'n/a'
|
|
45
|
+
wall = "#{profile['total_wall_clock']}s"
|
|
46
|
+
load_tests = profile['load_tests_duration'] ? "#{profile['load_tests_duration']}s" : 'n/a'
|
|
47
|
+
files = if profile['files_loaded'] && profile['total_files']
|
|
48
|
+
"#{profile['file_load_time']}s (#{profile['files_loaded']}/#{profile['total_files']})"
|
|
49
|
+
elsif profile['file_load_time']
|
|
50
|
+
"#{profile['file_load_time']}s"
|
|
51
|
+
else
|
|
52
|
+
'n/a'
|
|
53
|
+
end
|
|
54
|
+
mem = profile['memory_rss_kb'] ? "#{(profile['memory_rss_kb'] / 1024.0).round(0)} MB" : 'n/a'
|
|
55
|
+
|
|
56
|
+
" %-12s %-12s %8s %14s %14s %14s %14s %10s" % [
|
|
57
|
+
profile['worker_id'], profile['role'], tests, first_test, wall, load_tests, files, mem
|
|
58
|
+
]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def print_first_test_summary(sorted)
|
|
62
|
+
leaders = sorted.select { |p| p['role'] == 'leader' }
|
|
63
|
+
non_leaders = sorted.select { |p| p['role'] == 'non-leader' }
|
|
64
|
+
return unless leaders.any? && non_leaders.any?
|
|
65
|
+
|
|
66
|
+
leader_first = leaders.filter_map { |p| p['time_to_first_test'] }.min
|
|
67
|
+
nl_firsts = non_leaders.filter_map { |p| p['time_to_first_test'] }
|
|
68
|
+
return unless leader_first && nl_firsts.any?
|
|
69
|
+
|
|
70
|
+
avg_nl = (nl_firsts.sum / nl_firsts.size).round(2)
|
|
71
|
+
@out.puts
|
|
72
|
+
@out.puts " Leader time to 1st test: #{leader_first}s"
|
|
73
|
+
@out.puts " Avg non-leader time to 1st test: #{avg_nl}s"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
data/lib/minitest/queue.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
require 'shellwords'
|
|
3
3
|
require 'minitest'
|
|
4
4
|
require 'minitest/reporters'
|
|
5
|
+
require 'concurrent/map'
|
|
5
6
|
|
|
6
7
|
require 'minitest/queue/failure_formatter'
|
|
7
8
|
require 'minitest/queue/error_report'
|
|
@@ -106,6 +107,10 @@ module Minitest
|
|
|
106
107
|
attr_accessor :start_timestamp, :finish_timestamp
|
|
107
108
|
end
|
|
108
109
|
|
|
110
|
+
module ResultMetadata
|
|
111
|
+
attr_accessor :queue_id, :queue_entry
|
|
112
|
+
end
|
|
113
|
+
|
|
109
114
|
module Queue
|
|
110
115
|
extend ::CI::Queue::OutputHelpers
|
|
111
116
|
attr_writer :run_command_formatter, :project_root
|
|
@@ -156,19 +161,29 @@ module Minitest
|
|
|
156
161
|
|
|
157
162
|
def run(reporter, *)
|
|
158
163
|
rescue_run_errors do
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
example.
|
|
164
|
+
begin
|
|
165
|
+
queue.poll do |example|
|
|
166
|
+
result = queue.with_heartbeat(example.queue_entry) do
|
|
167
|
+
example.run
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
handle_test_result(reporter, example, result)
|
|
162
171
|
end
|
|
163
172
|
|
|
164
|
-
|
|
173
|
+
report_load_stats(queue)
|
|
174
|
+
ensure
|
|
175
|
+
store_worker_profile(queue)
|
|
176
|
+
queue.stop_heartbeat!
|
|
165
177
|
end
|
|
166
|
-
|
|
167
|
-
queue.stop_heartbeat!
|
|
168
178
|
end
|
|
169
179
|
end
|
|
170
180
|
|
|
171
181
|
def handle_test_result(reporter, example, result)
|
|
182
|
+
if result.respond_to?(:queue_id=)
|
|
183
|
+
result.queue_id = example.id
|
|
184
|
+
result.queue_entry = example.queue_entry if result.respond_to?(:queue_entry=)
|
|
185
|
+
end
|
|
186
|
+
|
|
172
187
|
failed = !(result.passed? || result.skipped?)
|
|
173
188
|
|
|
174
189
|
if example.flaky?
|
|
@@ -194,6 +209,85 @@ module Minitest
|
|
|
194
209
|
|
|
195
210
|
private
|
|
196
211
|
|
|
212
|
+
def report_load_stats(queue)
|
|
213
|
+
return unless CI::Queue.debug?
|
|
214
|
+
return unless queue.respond_to?(:file_loader)
|
|
215
|
+
return unless queue.respond_to?(:config) && queue.config.lazy_load
|
|
216
|
+
|
|
217
|
+
loader = queue.file_loader
|
|
218
|
+
return if loader.load_stats.empty?
|
|
219
|
+
|
|
220
|
+
total_time = loader.total_load_time
|
|
221
|
+
file_count = loader.load_stats.size
|
|
222
|
+
average = file_count.zero? ? 0 : (total_time / file_count)
|
|
223
|
+
|
|
224
|
+
puts
|
|
225
|
+
puts "File loading stats:"
|
|
226
|
+
puts " Total time: #{total_time.round(2)}s"
|
|
227
|
+
puts " Files loaded: #{file_count}"
|
|
228
|
+
puts " Average: #{average.round(3)}s per file"
|
|
229
|
+
|
|
230
|
+
slowest = loader.slowest_files(5)
|
|
231
|
+
return if slowest.empty?
|
|
232
|
+
|
|
233
|
+
puts " Slowest files:"
|
|
234
|
+
slowest.each do |file_path, duration|
|
|
235
|
+
puts " #{duration.round(3)}s - #{Minitest::Queue.relative_path(file_path)}"
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def store_worker_profile(queue)
|
|
240
|
+
debug = CI::Queue.debug?
|
|
241
|
+
return unless queue.respond_to?(:config)
|
|
242
|
+
config = queue.config
|
|
243
|
+
|
|
244
|
+
run_start = Minitest::Queue::Runner.run_start
|
|
245
|
+
return unless run_start
|
|
246
|
+
|
|
247
|
+
run_end = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
248
|
+
profile = {
|
|
249
|
+
'worker_id' => config.worker_id,
|
|
250
|
+
'mode' => config.lazy_load ? 'lazy' : 'eager',
|
|
251
|
+
'role' => queue.master? ? 'leader' : 'non-leader',
|
|
252
|
+
'total_wall_clock' => (run_end - run_start).round(2),
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
first_test = queue.respond_to?(:first_reserve_at) ? queue.first_reserve_at : nil
|
|
256
|
+
profile['time_to_first_test'] = (first_test - run_start).round(2) if first_test
|
|
257
|
+
|
|
258
|
+
tests_run = queue.rescue_connection_errors { queue.worker_queue_length } if queue.respond_to?(:worker_queue_length)
|
|
259
|
+
profile['tests_run'] = tests_run.to_i if tests_run
|
|
260
|
+
|
|
261
|
+
load_tests_duration = Minitest::Queue::Runner.load_tests_duration
|
|
262
|
+
profile['load_tests_duration'] = load_tests_duration.round(2) if load_tests_duration
|
|
263
|
+
|
|
264
|
+
if queue.respond_to?(:file_loader) && queue.file_loader.load_stats.any?
|
|
265
|
+
loader = queue.file_loader
|
|
266
|
+
profile['files_loaded'] = loader.load_stats.size
|
|
267
|
+
profile['file_load_time'] = loader.total_load_time.round(2)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
profile['total_files'] = Minitest::Queue::Runner.total_files if Minitest::Queue::Runner.total_files
|
|
271
|
+
|
|
272
|
+
rss_kb = begin
|
|
273
|
+
if File.exist?("/proc/#{Process.pid}/statm")
|
|
274
|
+
pages = Integer(File.read("/proc/#{Process.pid}/statm").split[1])
|
|
275
|
+
pages * 4
|
|
276
|
+
else
|
|
277
|
+
Integer(`ps -o rss= -p #{Process.pid}`.strip)
|
|
278
|
+
end
|
|
279
|
+
rescue
|
|
280
|
+
nil
|
|
281
|
+
end
|
|
282
|
+
profile['memory_rss_kb'] = rss_kb if rss_kb
|
|
283
|
+
|
|
284
|
+
queue.rescue_connection_errors do
|
|
285
|
+
queue.build.record_worker_profile(profile)
|
|
286
|
+
end
|
|
287
|
+
rescue => e
|
|
288
|
+
puts "WARNING: Failed to store worker profile: #{e.message}" if debug
|
|
289
|
+
end
|
|
290
|
+
|
|
197
291
|
def rescue_run_errors(&block)
|
|
198
292
|
block.call
|
|
199
293
|
rescue Errno::EPIPE
|
|
@@ -232,6 +326,10 @@ module Minitest
|
|
|
232
326
|
@id ||= "#{@runnable}##{@method_name}".freeze
|
|
233
327
|
end
|
|
234
328
|
|
|
329
|
+
def queue_entry
|
|
330
|
+
id
|
|
331
|
+
end
|
|
332
|
+
|
|
235
333
|
def <=>(other)
|
|
236
334
|
id <=> other.id
|
|
237
335
|
end
|
|
@@ -270,6 +368,171 @@ module Minitest
|
|
|
270
368
|
end
|
|
271
369
|
end
|
|
272
370
|
|
|
371
|
+
class LazySingleExample
|
|
372
|
+
attr_reader :class_name, :method_name, :file_path
|
|
373
|
+
|
|
374
|
+
def initialize(class_name, method_name, file_path, loader:, resolver:, load_error: nil, queue_entry: nil)
|
|
375
|
+
@class_name = class_name
|
|
376
|
+
@method_name = method_name
|
|
377
|
+
@file_path = file_path
|
|
378
|
+
@loader = loader
|
|
379
|
+
@resolver = resolver
|
|
380
|
+
@load_error = load_error
|
|
381
|
+
@queue_entry_override = queue_entry
|
|
382
|
+
@runnable = nil
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
def id
|
|
386
|
+
@id ||= "#{@class_name}##{@method_name}".freeze
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
def queue_entry
|
|
390
|
+
@queue_entry ||= @queue_entry_override || CI::Queue::QueueEntry.format(id, file_path)
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def <=>(other)
|
|
394
|
+
id <=> other.id
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
RUNNABLE_METHODS_TRIGGERED = Concurrent::Map.new # :nodoc:
|
|
398
|
+
|
|
399
|
+
def runnable
|
|
400
|
+
@runnable ||= begin
|
|
401
|
+
klass = @resolver.resolve(@class_name, file_path: @file_path, loader: @loader)
|
|
402
|
+
unless RUNNABLE_METHODS_TRIGGERED[klass]
|
|
403
|
+
klass.runnable_methods
|
|
404
|
+
RUNNABLE_METHODS_TRIGGERED[klass] = true
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
# If the method doesn't exist, the class may have been autoloaded by
|
|
408
|
+
# Zeitwerk without executing test-specific code (includes, helpers).
|
|
409
|
+
# Force load the file so all class-definition-time code executes.
|
|
410
|
+
unless klass.method_defined?(@method_name) || klass.private_method_defined?(@method_name)
|
|
411
|
+
if @file_path && @loader
|
|
412
|
+
@loader.load_file(@file_path)
|
|
413
|
+
RUNNABLE_METHODS_TRIGGERED.delete(klass)
|
|
414
|
+
klass.runnable_methods
|
|
415
|
+
RUNNABLE_METHODS_TRIGGERED[klass] = true
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
klass
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
def with_timestamps
|
|
424
|
+
start_timestamp = current_timestamp
|
|
425
|
+
result = yield
|
|
426
|
+
result
|
|
427
|
+
ensure
|
|
428
|
+
if result
|
|
429
|
+
result.start_timestamp = start_timestamp
|
|
430
|
+
result.finish_timestamp = current_timestamp
|
|
431
|
+
end
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
def run
|
|
435
|
+
with_timestamps do
|
|
436
|
+
if @load_error
|
|
437
|
+
build_error_result(@load_error)
|
|
438
|
+
elsif skip_stale_tests? && !(runnable.method_defined?(@method_name) || runnable.private_method_defined?(@method_name))
|
|
439
|
+
build_stale_skip_result
|
|
440
|
+
else
|
|
441
|
+
Minitest.run_one_method(runnable, @method_name)
|
|
442
|
+
end
|
|
443
|
+
rescue StandardError, ScriptError => error
|
|
444
|
+
build_error_result(error)
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
def flaky?
|
|
449
|
+
Minitest.queue.flaky?(self)
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
def source_location
|
|
453
|
+
return nil if @load_error
|
|
454
|
+
|
|
455
|
+
runnable.instance_method(@method_name).source_location
|
|
456
|
+
rescue NameError, NoMethodError, CI::Queue::FileLoadError, CI::Queue::ClassNotFoundError
|
|
457
|
+
nil
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
def marshal_dump
|
|
461
|
+
{
|
|
462
|
+
'class_name' => @class_name,
|
|
463
|
+
'method_name' => @method_name,
|
|
464
|
+
'file_path' => @file_path,
|
|
465
|
+
'load_error' => serialize_error(@load_error),
|
|
466
|
+
'queue_entry' => @queue_entry_override,
|
|
467
|
+
}
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
def marshal_load(payload)
|
|
471
|
+
@class_name = payload['class_name']
|
|
472
|
+
@method_name = payload['method_name']
|
|
473
|
+
@file_path = payload['file_path']
|
|
474
|
+
@load_error = deserialize_error(payload['load_error'])
|
|
475
|
+
@queue_entry_override = payload['queue_entry']
|
|
476
|
+
@loader = CI::Queue::FileLoader.new
|
|
477
|
+
@resolver = CI::Queue::ClassResolver
|
|
478
|
+
@runnable = nil
|
|
479
|
+
@id = nil
|
|
480
|
+
@queue_entry = nil
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
private
|
|
484
|
+
|
|
485
|
+
def serialize_error(error)
|
|
486
|
+
return nil unless error
|
|
487
|
+
|
|
488
|
+
{
|
|
489
|
+
'class' => error.class.name,
|
|
490
|
+
'message' => error.message,
|
|
491
|
+
'backtrace' => error.backtrace,
|
|
492
|
+
}
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
def deserialize_error(payload)
|
|
496
|
+
return nil unless payload
|
|
497
|
+
|
|
498
|
+
message = "#{payload['class']}: #{payload['message']}"
|
|
499
|
+
error = StandardError.new(message)
|
|
500
|
+
error.set_backtrace(payload['backtrace']) if payload['backtrace']
|
|
501
|
+
CI::Queue::FileLoadError.new(@file_path, error)
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
def build_error_result(error)
|
|
505
|
+
result_class = defined?(Minitest::Result) ? Minitest::Result : Minitest::Test
|
|
506
|
+
result = result_class.new(@method_name)
|
|
507
|
+
result.klass = @class_name if result.respond_to?(:klass=)
|
|
508
|
+
result.source_location = [@file_path || 'unknown', -1] if result.respond_to?(:source_location=)
|
|
509
|
+
result.failures << Minitest::UnexpectedError.new(error)
|
|
510
|
+
result
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
def skip_stale_tests?
|
|
514
|
+
Minitest.queue&.respond_to?(:config) && Minitest.queue.config.skip_stale_tests
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
def build_stale_skip_result
|
|
518
|
+
$stderr.puts "[ci-queue] Skipping stale preresolved entry: #{@class_name}##{@method_name} " \
|
|
519
|
+
"(method no longer exists in #{@file_path || 'unknown file'})"
|
|
520
|
+
|
|
521
|
+
result_class = defined?(Minitest::Result) ? Minitest::Result : Minitest::Test
|
|
522
|
+
result = result_class.new(@method_name)
|
|
523
|
+
result.klass = @class_name if result.respond_to?(:klass=)
|
|
524
|
+
result.source_location = [@file_path || 'unknown', -1] if result.respond_to?(:source_location=)
|
|
525
|
+
result.failures << Minitest::Skip.new(
|
|
526
|
+
"[ci-queue] Stale preresolved entry: #{@class_name}##{@method_name} no longer exists"
|
|
527
|
+
)
|
|
528
|
+
result
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
def current_timestamp
|
|
532
|
+
CI::Queue.time_now.to_i
|
|
533
|
+
end
|
|
534
|
+
end
|
|
535
|
+
|
|
273
536
|
attr_accessor :queue
|
|
274
537
|
|
|
275
538
|
def queue_reporters=(reporters)
|
|
@@ -310,10 +573,12 @@ if defined? Minitest::Result
|
|
|
310
573
|
Minitest::Result.prepend(Minitest::Requeueing)
|
|
311
574
|
Minitest::Result.prepend(Minitest::Flakiness)
|
|
312
575
|
Minitest::Result.prepend(Minitest::WithTimestamps)
|
|
576
|
+
Minitest::Result.prepend(Minitest::ResultMetadata)
|
|
313
577
|
else
|
|
314
578
|
Minitest::Test.prepend(Minitest::Requeueing)
|
|
315
579
|
Minitest::Test.prepend(Minitest::Flakiness)
|
|
316
580
|
Minitest::Test.prepend(Minitest::WithTimestamps)
|
|
581
|
+
Minitest::Test.prepend(Minitest::ResultMetadata)
|
|
317
582
|
|
|
318
583
|
module MinitestBackwardCompatibility
|
|
319
584
|
def source_location
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ci-queue
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.83.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jean Boussier
|
|
@@ -190,12 +190,16 @@ files:
|
|
|
190
190
|
- lib/ci/queue/bisect.rb
|
|
191
191
|
- lib/ci/queue/build_record.rb
|
|
192
192
|
- lib/ci/queue/circuit_breaker.rb
|
|
193
|
+
- lib/ci/queue/class_resolver.rb
|
|
193
194
|
- lib/ci/queue/common.rb
|
|
194
195
|
- lib/ci/queue/configuration.rb
|
|
195
196
|
- lib/ci/queue/file.rb
|
|
197
|
+
- lib/ci/queue/file_loader.rb
|
|
196
198
|
- lib/ci/queue/grind.rb
|
|
197
199
|
- lib/ci/queue/output_helpers.rb
|
|
200
|
+
- lib/ci/queue/queue_entry.rb
|
|
198
201
|
- lib/ci/queue/redis.rb
|
|
202
|
+
- lib/ci/queue/redis/_entry_helpers.lua
|
|
199
203
|
- lib/ci/queue/redis/acknowledge.lua
|
|
200
204
|
- lib/ci/queue/redis/base.rb
|
|
201
205
|
- lib/ci/queue/redis/build_record.rb
|
|
@@ -222,14 +226,18 @@ files:
|
|
|
222
226
|
- lib/minitest/queue/grind_recorder.rb
|
|
223
227
|
- lib/minitest/queue/grind_reporter.rb
|
|
224
228
|
- lib/minitest/queue/junit_reporter.rb
|
|
229
|
+
- lib/minitest/queue/lazy_entry_resolver.rb
|
|
230
|
+
- lib/minitest/queue/lazy_test_discovery.rb
|
|
225
231
|
- lib/minitest/queue/local_requeue_reporter.rb
|
|
226
232
|
- lib/minitest/queue/order_reporter.rb
|
|
233
|
+
- lib/minitest/queue/queue_population_strategy.rb
|
|
227
234
|
- lib/minitest/queue/runner.rb
|
|
228
235
|
- lib/minitest/queue/statsd.rb
|
|
229
236
|
- lib/minitest/queue/test_data.rb
|
|
230
237
|
- lib/minitest/queue/test_data_reporter.rb
|
|
231
238
|
- lib/minitest/queue/test_time_recorder.rb
|
|
232
239
|
- lib/minitest/queue/test_time_reporter.rb
|
|
240
|
+
- lib/minitest/queue/worker_profile_reporter.rb
|
|
233
241
|
- lib/minitest/reporters/bisect_reporter.rb
|
|
234
242
|
- lib/minitest/reporters/statsd_reporter.rb
|
|
235
243
|
- lib/rspec/queue.rb
|