ci-queue 0.7.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.
- checksums.yaml +4 -4
- data/README.md +7 -1
- data/lib/ci/queue.rb +1 -0
- data/lib/ci/queue/bisect.rb +59 -0
- data/lib/ci/queue/configuration.rb +1 -1
- data/lib/ci/queue/file.rb +2 -1
- data/lib/ci/queue/version.rb +1 -1
- data/lib/minitest/queue.rb +2 -1
- data/lib/minitest/queue/runner.rb +74 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d71f2dd528eeda6758bc37bb9142cac9814150ea
|
4
|
+
data.tar.gz: 3042fc3632751cc3ef1834dd749978dff2c628a6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bc012267f7470bc5527ae5081ebfe2e268acf6d777db6c8c50d218e9aa21fa7a3dba46e2f1af467a9f7fcbf5ca98512322128dea0115ce4a047cd6a09aa09253
|
7
|
+
data.tar.gz: 80445ac4bb1f43a2a930269708c7f97178921d5da60b198af42ffdeecf07e0e0c3242cb4c065c6b220ee4ef19b6a7935716330875df1aa1b62b665f891641ae9
|
data/README.md
CHANGED
@@ -39,10 +39,16 @@ Additionally you can configure the requeue settings (see main README) with `--ma
|
|
39
39
|
|
40
40
|
If you'd like to centralize the error reporting you can do so with:
|
41
41
|
|
42
|
-
```
|
42
|
+
```bash
|
43
43
|
minitest-queue --queue redis://example.com --timeout 600 report
|
44
44
|
```
|
45
45
|
|
46
|
+
The runner also comes with a tool to investigate leaky tests:
|
47
|
+
|
48
|
+
```bash
|
49
|
+
minitest-queue --queue path/to/test_order.log --failing-test 'SomeTest#test_something' bisect -Itest test/**/*_test.rb
|
50
|
+
```
|
51
|
+
|
46
52
|
### RSpec
|
47
53
|
|
48
54
|
The RSpec integration is not implemented yet.
|
data/lib/ci/queue.rb
CHANGED
@@ -0,0 +1,59 @@
|
|
1
|
+
module CI
|
2
|
+
module Queue
|
3
|
+
class Bisect
|
4
|
+
def initialize(path, config)
|
5
|
+
@tests = ::File.readlines(path).map(&:strip).reject(&:empty?).take_while { |t| t != config.failing_test }
|
6
|
+
@config = config
|
7
|
+
end
|
8
|
+
|
9
|
+
def size
|
10
|
+
@tests.size
|
11
|
+
end
|
12
|
+
|
13
|
+
def populate(all_tests, &test_indexer)
|
14
|
+
@all_tests = all_tests
|
15
|
+
@test_indexer = test_indexer
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_a
|
19
|
+
@tests + [config.failing_test]
|
20
|
+
end
|
21
|
+
|
22
|
+
def suspects_left
|
23
|
+
@tests.size
|
24
|
+
end
|
25
|
+
|
26
|
+
def failing_test
|
27
|
+
Static.new([config.failing_test], config).populate(@all_tests, &@test_indexer)
|
28
|
+
end
|
29
|
+
|
30
|
+
def candidates
|
31
|
+
Static.new(first_half + [config.failing_test], config).populate(@all_tests, &@test_indexer)
|
32
|
+
end
|
33
|
+
|
34
|
+
def failed!
|
35
|
+
@tests = first_half
|
36
|
+
end
|
37
|
+
|
38
|
+
def succeeded!
|
39
|
+
@tests = second_half
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
attr_reader :config
|
45
|
+
|
46
|
+
def slices
|
47
|
+
@tests.each_slice((@tests.size / 2.0).ceil).to_a
|
48
|
+
end
|
49
|
+
|
50
|
+
def first_half
|
51
|
+
slices.first
|
52
|
+
end
|
53
|
+
|
54
|
+
def second_half
|
55
|
+
slices.last
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module CI
|
2
2
|
module Queue
|
3
3
|
class Configuration
|
4
|
-
attr_accessor :timeout, :build_id, :worker_id, :max_requeues, :requeue_tolerance, :namespace, :seed
|
4
|
+
attr_accessor :timeout, :build_id, :worker_id, :max_requeues, :requeue_tolerance, :namespace, :seed, :failing_test
|
5
5
|
|
6
6
|
class << self
|
7
7
|
def from_env(env)
|
data/lib/ci/queue/file.rb
CHANGED
data/lib/ci/queue/version.rb
CHANGED
data/lib/minitest/queue.rb
CHANGED
@@ -58,7 +58,8 @@ module Minitest
|
|
58
58
|
|
59
59
|
def queue_reporters=(reporters)
|
60
60
|
@queue_reporters ||= []
|
61
|
-
Reporters.
|
61
|
+
Reporters.use!(((Reporters.reporters || []) - @queue_reporters) + reporters)
|
62
|
+
Minitest.backtrace_filter.add_filter(%r{exe/minitest-queue|lib/ci/queue/})
|
62
63
|
@queue_reporters = reporters
|
63
64
|
end
|
64
65
|
|
@@ -49,6 +49,52 @@ module Minitest
|
|
49
49
|
# Let minitest's at_exit hook trigger
|
50
50
|
end
|
51
51
|
|
52
|
+
def bisect_command
|
53
|
+
invalid_usage! "Missing the FAILING_TEST argument." unless queue_config.failing_test
|
54
|
+
|
55
|
+
@queue = CI::Queue::Bisect.new(queue_url, queue_config)
|
56
|
+
Minitest.queue = queue
|
57
|
+
set_load_path
|
58
|
+
load_tests
|
59
|
+
populate_queue
|
60
|
+
|
61
|
+
step("Testing the failing test in isolation")
|
62
|
+
unless run_tests_in_fork(queue.failing_test)
|
63
|
+
puts reopen_previous_step
|
64
|
+
puts red("The test fail when run alone, no need to bisect.")
|
65
|
+
exit! 0
|
66
|
+
end
|
67
|
+
|
68
|
+
run_index = 0
|
69
|
+
while queue.suspects_left > 1
|
70
|
+
run_index += 1
|
71
|
+
step("Run ##{run_index}, #{queue.suspects_left} suspects left")
|
72
|
+
if run_tests_in_fork(queue.candidates)
|
73
|
+
queue.succeeded!
|
74
|
+
else
|
75
|
+
queue.failed!
|
76
|
+
end
|
77
|
+
puts
|
78
|
+
end
|
79
|
+
|
80
|
+
failing_order = queue.candidates
|
81
|
+
step("Final validation")
|
82
|
+
status = if run_tests_in_fork(failing_order)
|
83
|
+
step(yellow("The bisection was inconclusive, there might not be any leaky test here."))
|
84
|
+
exit! 1
|
85
|
+
else
|
86
|
+
step(green('The following command should reproduce the leak on your machine:'), collapsed: false)
|
87
|
+
command = %w(bundle exec minitest-queue --queue - run)
|
88
|
+
command << "-I#{load_paths}" if load_paths
|
89
|
+
command += argv
|
90
|
+
|
91
|
+
puts
|
92
|
+
puts "cat <<EOF |\n#{failing_order.to_a.join("\n")}\nEOF\n#{command.join(' ')}"
|
93
|
+
puts
|
94
|
+
exit! 0
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
52
98
|
def report_command
|
53
99
|
supervisor = begin
|
54
100
|
queue.supervisor
|
@@ -73,7 +119,6 @@ module Minitest
|
|
73
119
|
reporter.report
|
74
120
|
end
|
75
121
|
|
76
|
-
STDOUT.flush
|
77
122
|
exit! success ? 0 : 1
|
78
123
|
end
|
79
124
|
|
@@ -82,6 +127,17 @@ module Minitest
|
|
82
127
|
attr_reader :queue_config, :options, :command, :argv
|
83
128
|
attr_accessor :queue, :queue_url, :load_paths
|
84
129
|
|
130
|
+
def run_tests_in_fork(queue)
|
131
|
+
child_pid = fork do
|
132
|
+
Minitest.queue = queue
|
133
|
+
Minitest::Reporters.use!([Minitest::Reporters::SpecReporter.new])
|
134
|
+
exit # let minitest excute its at_exit
|
135
|
+
end
|
136
|
+
|
137
|
+
_, status = Process.wait2(child_pid)
|
138
|
+
return status.success?
|
139
|
+
end
|
140
|
+
|
85
141
|
def populate_queue
|
86
142
|
Minitest.queue.populate(shuffle(Minitest.loaded_tests), &:to_s) # TODO: stop serializing
|
87
143
|
end
|
@@ -210,6 +266,16 @@ module Minitest
|
|
210
266
|
|
211
267
|
opts.separator ""
|
212
268
|
opts.separator " report: Wait for all workers to complete and summarize the test failures."
|
269
|
+
|
270
|
+
opts.separator ""
|
271
|
+
opts.separator " bisect: bisect a test suite to find global state leaks."
|
272
|
+
help = split_heredoc(<<-EOS)
|
273
|
+
The identifier of the failing test.
|
274
|
+
EOS
|
275
|
+
opts.separator ""
|
276
|
+
opts.on('--failing-test TEST_IDENTIFIER') do |identifier|
|
277
|
+
queue_config.failing_test = identifier
|
278
|
+
end
|
213
279
|
end
|
214
280
|
end
|
215
281
|
|
@@ -218,6 +284,7 @@ module Minitest
|
|
218
284
|
end
|
219
285
|
|
220
286
|
def shuffle(tests)
|
287
|
+
return tests unless queue_config.seed
|
221
288
|
random = Random.new(Digest::MD5.hexdigest(queue_config.seed).to_i(16))
|
222
289
|
tests.shuffle(random: random)
|
223
290
|
end
|
@@ -233,6 +300,12 @@ module Minitest
|
|
233
300
|
exit! 1 # exit! is required to avoid minitest at_exit callback
|
234
301
|
end
|
235
302
|
|
303
|
+
def exit!(*)
|
304
|
+
STDOUT.flush
|
305
|
+
STDERR.flush
|
306
|
+
super
|
307
|
+
end
|
308
|
+
|
236
309
|
def abort!(message)
|
237
310
|
reopen_previous_step
|
238
311
|
puts red(message)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ci-queue
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean Boussier
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-11-
|
11
|
+
date: 2017-11-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -114,6 +114,7 @@ files:
|
|
114
114
|
- dev.yml
|
115
115
|
- exe/minitest-queue
|
116
116
|
- lib/ci/queue.rb
|
117
|
+
- lib/ci/queue/bisect.rb
|
117
118
|
- lib/ci/queue/configuration.rb
|
118
119
|
- lib/ci/queue/file.rb
|
119
120
|
- lib/ci/queue/index.rb
|
@@ -155,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
156
|
version: '0'
|
156
157
|
requirements: []
|
157
158
|
rubyforge_project:
|
158
|
-
rubygems_version: 2.6.
|
159
|
+
rubygems_version: 2.6.13
|
159
160
|
signing_key:
|
160
161
|
specification_version: 4
|
161
162
|
summary: Distribute tests over many workers using a queue
|