minitest-distributed 0.2.3 → 0.2.4
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/.github/workflows/ruby.yml +18 -1
- data/.rubocop.yml +2 -0
- data/Gemfile +2 -0
- data/lib/minitest/distributed.rb +2 -2
- data/lib/minitest/distributed/configuration.rb +23 -23
- data/lib/minitest/distributed/coordinators/redis_coordinator.rb +29 -27
- data/lib/minitest/distributed/enqueued_runnable.rb +8 -8
- data/lib/minitest/distributed/reporters/distributed_progress_reporter.rb +3 -3
- data/lib/minitest/distributed/reporters/junitxml_reporter.rb +22 -22
- data/lib/minitest/distributed/test_selector.rb +1 -1
- data/lib/minitest/distributed/version.rb +1 -1
- data/lib/minitest/distributed_plugin.rb +2 -2
- data/lib/minitest/junitxml_plugin.rb +3 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3898c3d3b163b66922daf90468041da6e76e07c8c102971c8f3cc71ad20e6bd4
|
4
|
+
data.tar.gz: 19c90e644ce560e5d1981dfb6a72d99bfa98daf95997e684954e3cd4d38906ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e772261c32992207573b5e76a12ae50eb26120c4d007f013246c6058821c200900a5a914d2bf474d37ffb571b5b03ae95fcc1e95d73a7eaa5e51ccfc15dc08d4
|
7
|
+
data.tar.gz: 905aff0608a7cda2910a920bd9650a9097e9da85104795f3b9ff4c143f4d4ea4dd4608f71d8a103275e821d17b9bf3340c68d33abcc0ef44cc304cda089f79c5
|
data/.github/workflows/ruby.yml
CHANGED
@@ -10,7 +10,24 @@ name: Ruby
|
|
10
10
|
on: push
|
11
11
|
|
12
12
|
jobs:
|
13
|
-
|
13
|
+
test_30:
|
14
|
+
runs-on: ubuntu-latest
|
15
|
+
container: ruby:3.0
|
16
|
+
|
17
|
+
services:
|
18
|
+
redis:
|
19
|
+
image: redis
|
20
|
+
|
21
|
+
steps:
|
22
|
+
- uses: actions/checkout@v2
|
23
|
+
- name: Install dependencies
|
24
|
+
run: gem install bundler && bundle install
|
25
|
+
- name: Run tests
|
26
|
+
run: bin/rake test
|
27
|
+
env:
|
28
|
+
REDIS_URL: redis://redis:6379
|
29
|
+
|
30
|
+
test_26:
|
14
31
|
runs-on: ubuntu-latest
|
15
32
|
container: ruby:2.6
|
16
33
|
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
data/lib/minitest/distributed.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
4
|
+
require "uri"
|
5
|
+
require "securerandom"
|
6
6
|
|
7
7
|
module Minitest
|
8
8
|
module Distributed
|
@@ -17,13 +17,13 @@ module Minitest
|
|
17
17
|
sig { params(env: T::Hash[String, T.nilable(String)]).returns(T.attached_class) }
|
18
18
|
def from_env(env = ENV.to_h)
|
19
19
|
new(
|
20
|
-
coordinator_uri: URI(env[
|
21
|
-
run_id: env[
|
22
|
-
worker_id: env[
|
23
|
-
test_timeout_seconds: Float(env[
|
24
|
-
test_batch_size: Integer(env[
|
25
|
-
max_attempts: Integer(env[
|
26
|
-
max_failures: (max_failures_env = env[
|
20
|
+
coordinator_uri: URI(env["MINITEST_COORDINATOR"] || "memory:"),
|
21
|
+
run_id: env["MINITEST_RUN_ID"] || SecureRandom.uuid,
|
22
|
+
worker_id: env["MINITEST_WORKER_ID"] || SecureRandom.uuid,
|
23
|
+
test_timeout_seconds: Float(env["MINITEST_TEST_TIMEOUT_SECONDS"] || DEFAULT_TEST_TIMEOUT_SECONDS),
|
24
|
+
test_batch_size: Integer(env["MINITEST_TEST_BATCH_SIZE"] || DEFAULT_BATCH_SIZE),
|
25
|
+
max_attempts: Integer(env["MINITEST_MAX_ATTEMPTS"] || DEFAULT_MAX_ATTEMPTS),
|
26
|
+
max_failures: (max_failures_env = env["MINITEST_MAX_FAILURES"]) ? Integer(max_failures_env) : nil,
|
27
27
|
)
|
28
28
|
end
|
29
29
|
|
@@ -32,50 +32,50 @@ module Minitest
|
|
32
32
|
configuration = from_env
|
33
33
|
configuration.progress = options[:io].tty?
|
34
34
|
|
35
|
-
opts.on(
|
35
|
+
opts.on("--coordinator=URI", "The URI pointing to the coordinator") do |uri|
|
36
36
|
configuration.coordinator_uri = URI.parse(uri)
|
37
37
|
end
|
38
38
|
|
39
|
-
opts.on(
|
39
|
+
opts.on("--test-timeout=TIMEOUT", "The maximum run time for a single test in seconds") do |timeout|
|
40
40
|
configuration.test_timeout_seconds = Float(timeout)
|
41
41
|
end
|
42
42
|
|
43
|
-
opts.on(
|
43
|
+
opts.on("--max-attempts=ATTEMPTS", "The maximum number of attempts to run a test") do |attempts|
|
44
44
|
configuration.max_attempts = Integer(attempts)
|
45
45
|
end
|
46
46
|
|
47
|
-
opts.on(
|
47
|
+
opts.on("--test-batch-size=NUMBER", "The number of tests to process per batch") do |batch_size|
|
48
48
|
configuration.test_batch_size = Integer(batch_size)
|
49
49
|
end
|
50
50
|
|
51
|
-
opts.on(
|
51
|
+
opts.on("--max-failures=FAILURES", "The maximum allowed failure before aborting a run") do |failures|
|
52
52
|
configuration.max_failures = Integer(failures)
|
53
53
|
end
|
54
54
|
|
55
|
-
opts.on(
|
55
|
+
opts.on("--run-id=ID", "The ID for this run shared between coordinated workers") do |id|
|
56
56
|
configuration.run_id = id
|
57
57
|
end
|
58
58
|
|
59
|
-
opts.on(
|
59
|
+
opts.on("--worker-id=ID", "The unique ID for this worker") do |id|
|
60
60
|
configuration.worker_id = id
|
61
61
|
end
|
62
62
|
|
63
63
|
opts.on(
|
64
|
-
|
64
|
+
"--[no-]retry-failures", "Retry failed and errored tests from a previous run attempt " \
|
65
65
|
"with the same run ID (default: enabled)"
|
66
66
|
) do |enabled|
|
67
67
|
configuration.retry_failures = enabled
|
68
68
|
end
|
69
69
|
|
70
|
-
opts.on(
|
70
|
+
opts.on("--[no-]progress", "Show progress during the test run") do |enabled|
|
71
71
|
configuration.progress = enabled
|
72
72
|
end
|
73
73
|
|
74
|
-
opts.on(
|
74
|
+
opts.on("--exclude-file=FILE_PATH", "Specify a file of tests to be excluded from running") do |file_path|
|
75
75
|
configuration.exclude_file = file_path
|
76
76
|
end
|
77
77
|
|
78
|
-
opts.on(
|
78
|
+
opts.on("--include-file=FILE_PATH", "Specify a file of tests to be included in the test run") do |file_path|
|
79
79
|
configuration.include_file = file_path
|
80
80
|
end
|
81
81
|
|
@@ -86,7 +86,7 @@ module Minitest
|
|
86
86
|
extend T::Sig
|
87
87
|
|
88
88
|
# standard minitest options don't need to be specified
|
89
|
-
prop :coordinator_uri, URI::Generic, default: URI(
|
89
|
+
prop :coordinator_uri, URI::Generic, default: URI("memory:")
|
90
90
|
prop :run_id, String, factory: -> { SecureRandom.uuid }
|
91
91
|
prop :worker_id, String, factory: -> { SecureRandom.uuid }
|
92
92
|
prop :test_timeout_seconds, Float, default: DEFAULT_TEST_TIMEOUT_SECONDS
|
@@ -102,9 +102,9 @@ module Minitest
|
|
102
102
|
def coordinator
|
103
103
|
@coordinator = T.let(@coordinator, T.nilable(Coordinators::CoordinatorInterface))
|
104
104
|
@coordinator ||= case coordinator_uri.scheme
|
105
|
-
when
|
105
|
+
when "redis"
|
106
106
|
Coordinators::RedisCoordinator.new(configuration: self)
|
107
|
-
when
|
107
|
+
when "memory"
|
108
108
|
Coordinators::MemoryCoordinator.new(configuration: self)
|
109
109
|
else
|
110
110
|
raise NotImplementedError, "Unknown coordinator implementation: #{coordinator_uri.scheme}"
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
4
|
+
require "redis"
|
5
5
|
|
6
6
|
module Minitest
|
7
7
|
module Distributed
|
@@ -65,8 +65,8 @@ module Minitest
|
|
65
65
|
@configuration = configuration
|
66
66
|
|
67
67
|
@redis = T.let(nil, T.nilable(Redis))
|
68
|
-
@stream_key = T.let(key(
|
69
|
-
@group_name = T.let(
|
68
|
+
@stream_key = T.let(key("queue"), String)
|
69
|
+
@group_name = T.let("minitest-distributed", String)
|
70
70
|
@local_results = T.let(ResultAggregate.new, ResultAggregate)
|
71
71
|
@combined_results = T.let(nil, T.nilable(ResultAggregate))
|
72
72
|
@reclaimed_timeout_tests = T.let(Set.new, T::Set[EnqueuedRunnable])
|
@@ -82,9 +82,9 @@ module Minitest
|
|
82
82
|
sig { override.returns(ResultAggregate) }
|
83
83
|
def combined_results
|
84
84
|
@combined_results ||= begin
|
85
|
-
stats_as_string = redis.mget(key(
|
86
|
-
key(
|
87
|
-
key(
|
85
|
+
stats_as_string = redis.mget(key("runs"), key("assertions"), key("passes"),
|
86
|
+
key("failures"), key("errors"), key("skips"), key("requeues"), key("discards"),
|
87
|
+
key("acks"), key("size"))
|
88
88
|
|
89
89
|
ResultAggregate.new(
|
90
90
|
max_failures: configuration.max_failures,
|
@@ -124,13 +124,13 @@ module Minitest
|
|
124
124
|
# fails, and the DEL never gets executed for followers.
|
125
125
|
keys_deleted = redis.evalsha(
|
126
126
|
register_consumergroup_script,
|
127
|
-
keys: [stream_key, key(
|
127
|
+
keys: [stream_key, key("size"), key("acks")],
|
128
128
|
argv: [group_name],
|
129
129
|
)
|
130
130
|
keys_deleted == 0
|
131
131
|
|
132
132
|
rescue Redis::CommandError => ce
|
133
|
-
if ce.message.include?(
|
133
|
+
if ce.message.include?("BUSYGROUP")
|
134
134
|
# If Redis returns a BUSYGROUP error, it means that the consumer group already
|
135
135
|
# exists. In our case, it means that another worker managed to successfully
|
136
136
|
# run the XGROUP command, and will act as leader and publish the tests.
|
@@ -200,7 +200,9 @@ module Minitest
|
|
200
200
|
end
|
201
201
|
|
202
202
|
redis.pipelined do
|
203
|
-
tests.each
|
203
|
+
tests.each do |test|
|
204
|
+
redis.xadd(stream_key, { class_name: T.must(test.class.name), method_name: test.name })
|
205
|
+
end
|
204
206
|
end
|
205
207
|
end
|
206
208
|
|
@@ -238,7 +240,7 @@ module Minitest
|
|
238
240
|
|
239
241
|
cleanup
|
240
242
|
rescue Redis::CommandError => ce
|
241
|
-
if ce.message.start_with?(
|
243
|
+
if ce.message.start_with?("NOGROUP")
|
242
244
|
# When a redis conumer group commands fails with a NOGROUP error, we assume the
|
243
245
|
# consumer group was deleted by the first worker that detected the run is complete.
|
244
246
|
# So this worker can exit its loop as well.
|
@@ -277,7 +279,7 @@ module Minitest
|
|
277
279
|
|
278
280
|
sig { params(block: Integer).returns(T::Array[EnqueuedRunnable]) }
|
279
281
|
def claim_fresh_runnables(block:)
|
280
|
-
result = redis.xreadgroup(group_name, configuration.worker_id, stream_key,
|
282
|
+
result = redis.xreadgroup(group_name, configuration.worker_id, stream_key, ">",
|
281
283
|
block: block, count: configuration.test_batch_size)
|
282
284
|
EnqueuedRunnable.from_redis_stream_claim(result.fetch(stream_key, []), configuration: configuration)
|
283
285
|
end
|
@@ -305,7 +307,7 @@ module Minitest
|
|
305
307
|
max_idle_time_ms_with_jitter = max_idle_time_ms * rand(1.0...1.2)
|
306
308
|
|
307
309
|
# Find all the pending messages to see if we want to attenpt to claim some.
|
308
|
-
pending = redis.xpending(stream_key, group_name,
|
310
|
+
pending = redis.xpending(stream_key, group_name, "-", "+", configuration.test_batch_size)
|
309
311
|
return [] if pending.empty?
|
310
312
|
|
311
313
|
active_consumers = Set[configuration.worker_id]
|
@@ -327,9 +329,9 @@ module Minitest
|
|
327
329
|
# We can skip this if we already know that there is more than one active one.
|
328
330
|
if active_consumers.size == 1
|
329
331
|
begin
|
330
|
-
redis.xinfo(
|
331
|
-
if consumer.fetch(
|
332
|
-
active_consumers << consumer.fetch(
|
332
|
+
redis.xinfo("consumers", stream_key, group_name).each do |consumer|
|
333
|
+
if consumer.fetch("idle") < max_idle_time_ms
|
334
|
+
active_consumers << consumer.fetch("name")
|
333
335
|
end
|
334
336
|
end
|
335
337
|
rescue Redis::CommandError
|
@@ -383,7 +385,7 @@ module Minitest
|
|
383
385
|
messages_in_retry_set = {}
|
384
386
|
redis.multi do
|
385
387
|
active_messages.each do |key, message|
|
386
|
-
messages_in_retry_set[key] = redis.srem(key(
|
388
|
+
messages_in_retry_set[key] = redis.srem(key("retry_set"), message.attempt_id)
|
387
389
|
end
|
388
390
|
end
|
389
391
|
|
@@ -406,16 +408,16 @@ module Minitest
|
|
406
408
|
sig { params(results: ResultAggregate).void }
|
407
409
|
def adjust_combined_results(results)
|
408
410
|
updated = redis.multi do
|
409
|
-
redis.incrby(key(
|
410
|
-
redis.incrby(key(
|
411
|
-
redis.incrby(key(
|
412
|
-
redis.incrby(key(
|
413
|
-
redis.incrby(key(
|
414
|
-
redis.incrby(key(
|
415
|
-
redis.incrby(key(
|
416
|
-
redis.incrby(key(
|
417
|
-
redis.incrby(key(
|
418
|
-
redis.incrby(key(
|
411
|
+
redis.incrby(key("runs"), results.runs)
|
412
|
+
redis.incrby(key("assertions"), results.assertions)
|
413
|
+
redis.incrby(key("passes"), results.passes)
|
414
|
+
redis.incrby(key("failures"), results.failures)
|
415
|
+
redis.incrby(key("errors"), results.errors)
|
416
|
+
redis.incrby(key("skips"), results.skips)
|
417
|
+
redis.incrby(key("requeues"), results.requeues)
|
418
|
+
redis.incrby(key("discards"), results.discards)
|
419
|
+
redis.incrby(key("acks"), results.acks)
|
420
|
+
redis.incrby(key("size"), results.size)
|
419
421
|
end
|
420
422
|
|
421
423
|
@combined_results = ResultAggregate.new(max_failures: configuration.max_failures,
|
@@ -452,7 +454,7 @@ module Minitest
|
|
452
454
|
results.each do |enqueued_runnable, initial_result|
|
453
455
|
runnable_results << enqueued_runnable.commit_result(initial_result) do |result_to_commit|
|
454
456
|
if ResultType.of(result_to_commit) == ResultType::Requeued
|
455
|
-
sadd_future = redis.sadd(key(
|
457
|
+
sadd_future = redis.sadd(key("retry_set"), enqueued_runnable.attempt_id)
|
456
458
|
EnqueuedRunnable::Result::Commit.new { sadd_future.value }
|
457
459
|
else
|
458
460
|
xack_future = redis.xack(stream_key, group_name, enqueued_runnable.entry_id)
|
@@ -19,10 +19,10 @@ module Minitest
|
|
19
19
|
sig { params(xpending_result: T::Hash[String, T.untyped]).returns(T.attached_class) }
|
20
20
|
def self.from_xpending(xpending_result)
|
21
21
|
new(
|
22
|
-
worker_id: xpending_result.fetch(
|
23
|
-
entry_id: xpending_result.fetch(
|
24
|
-
elapsed_time_ms: xpending_result.fetch(
|
25
|
-
attempt: xpending_result.fetch(
|
22
|
+
worker_id: xpending_result.fetch("consumer"),
|
23
|
+
entry_id: xpending_result.fetch("entry_id"),
|
24
|
+
elapsed_time_ms: xpending_result.fetch("elapsed"),
|
25
|
+
attempt: xpending_result.fetch("count"),
|
26
26
|
)
|
27
27
|
end
|
28
28
|
end
|
@@ -33,7 +33,7 @@ module Minitest
|
|
33
33
|
|
34
34
|
sig { params(name: String).returns(T.class_of(Minitest::Runnable)) }
|
35
35
|
def self.find_class(name)
|
36
|
-
name.split(
|
36
|
+
name.split("::")
|
37
37
|
.reduce(Object) { |ns, const| ns.const_get(const) } # rubocop:disable Sorbet/ConstantsFromStrings
|
38
38
|
end
|
39
39
|
|
@@ -44,7 +44,7 @@ module Minitest
|
|
44
44
|
|
45
45
|
sig { params(identifier: String).returns(Minitest::Runnable) }
|
46
46
|
def self.from_identifier(identifier)
|
47
|
-
class_name, method_name = identifier.split(
|
47
|
+
class_name, method_name = identifier.split("#", 2)
|
48
48
|
find_class(T.must(class_name)).new(T.must(method_name))
|
49
49
|
end
|
50
50
|
end
|
@@ -133,8 +133,8 @@ module Minitest
|
|
133
133
|
attempt = pending_messages.key?(entry_id) ? pending_messages.fetch(entry_id).attempt + 1 : 1
|
134
134
|
|
135
135
|
new(
|
136
|
-
class_name: runnable_method_info.fetch(
|
137
|
-
method_name: runnable_method_info.fetch(
|
136
|
+
class_name: runnable_method_info.fetch("class_name"),
|
137
|
+
method_name: runnable_method_info.fetch("method_name"),
|
138
138
|
entry_id: entry_id,
|
139
139
|
attempt: attempt,
|
140
140
|
max_attempts: configuration.max_attempts,
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
4
|
+
require "io/console"
|
5
5
|
|
6
6
|
module Minitest
|
7
7
|
module Distributed
|
@@ -25,7 +25,7 @@ module Minitest
|
|
25
25
|
|
26
26
|
sig { override.void }
|
27
27
|
def start
|
28
|
-
Signal.trap(
|
28
|
+
Signal.trap("WINCH") { @window_line_width = nil }
|
29
29
|
super
|
30
30
|
end
|
31
31
|
|
@@ -74,7 +74,7 @@ module Minitest
|
|
74
74
|
|
75
75
|
sig { void }
|
76
76
|
def clear_current_line
|
77
|
-
io.print("\r" + (
|
77
|
+
io.print("\r" + (" " * window_line_width) + "\r")
|
78
78
|
end
|
79
79
|
|
80
80
|
sig { returns(Integer) }
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
4
|
+
require "rexml/document"
|
5
|
+
require "fileutils"
|
6
6
|
|
7
7
|
module Minitest
|
8
8
|
module Distributed
|
@@ -27,7 +27,7 @@ module Minitest
|
|
27
27
|
|
28
28
|
sig { params(io: IO, options: T::Hash[Symbol, T.untyped]).void }
|
29
29
|
def initialize(io, options)
|
30
|
-
|
30
|
+
super
|
31
31
|
@report_path = T.let(options.fetch(:junitxml), String)
|
32
32
|
@results = T.let(Hash.new { |hash, key| hash[key] = [] }, T::Hash[String, T::Array[Minitest::Result]])
|
33
33
|
end
|
@@ -48,7 +48,7 @@ module Minitest
|
|
48
48
|
sig { override.void }
|
49
49
|
def report
|
50
50
|
FileUtils.mkdir_p(File.dirname(@report_path))
|
51
|
-
File.open(@report_path,
|
51
|
+
File.open(@report_path, "w+") do |file|
|
52
52
|
format_document(generate_document, file)
|
53
53
|
end
|
54
54
|
end
|
@@ -56,9 +56,9 @@ module Minitest
|
|
56
56
|
sig { returns(REXML::Document) }
|
57
57
|
def generate_document
|
58
58
|
doc = REXML::Document.new(nil, prologue_quote: :quote, attribute_quote: :quote)
|
59
|
-
doc << REXML::XMLDecl.new(
|
59
|
+
doc << REXML::XMLDecl.new("1.1", "utf-8")
|
60
60
|
|
61
|
-
testsuites = doc.add_element(
|
61
|
+
testsuites = doc.add_element("testsuites")
|
62
62
|
results.each do |suite, tests|
|
63
63
|
add_tests_to(testsuites, suite, tests)
|
64
64
|
end
|
@@ -81,21 +81,21 @@ module Minitest
|
|
81
81
|
lineno = T.must(results.first).source_location.last
|
82
82
|
|
83
83
|
testsuite = testsuites.add_element(
|
84
|
-
|
85
|
-
{
|
84
|
+
"testsuite",
|
85
|
+
{ "name" => suite, "filepath" => relative_path }.merge(aggregate_suite_results(results))
|
86
86
|
)
|
87
87
|
|
88
88
|
results.each do |test|
|
89
89
|
attributes = {
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
90
|
+
"name" => test.name,
|
91
|
+
"classname" => suite,
|
92
|
+
"assertions" => test.assertions,
|
93
|
+
"time" => test.time,
|
94
94
|
# 'run-command' => ... # TODO
|
95
95
|
}
|
96
|
-
attributes[
|
96
|
+
attributes["lineno"] = lineno if lineno != -1
|
97
97
|
|
98
|
-
testcase_tag = testsuite.add_element(
|
98
|
+
testcase_tag = testsuite.add_element("testcase", attributes)
|
99
99
|
add_failure_tag_if_needed(testcase_tag, test)
|
100
100
|
end
|
101
101
|
end
|
@@ -107,9 +107,9 @@ module Minitest
|
|
107
107
|
# noop
|
108
108
|
when ResultType::Error, ResultType::Failed
|
109
109
|
failure = T.must(result.failure)
|
110
|
-
failure_tag = testcase.add_element(
|
111
|
-
|
112
|
-
|
110
|
+
failure_tag = testcase.add_element("failure",
|
111
|
+
"type" => result_type.serialize,
|
112
|
+
"message" => truncate_message(failure.message))
|
113
113
|
failure_tag.add_text(REXML::CData.new(result.to_s))
|
114
114
|
else
|
115
115
|
T.absurd(result_type)
|
@@ -118,17 +118,17 @@ module Minitest
|
|
118
118
|
|
119
119
|
sig { params(message: String).returns(String) }
|
120
120
|
def truncate_message(message)
|
121
|
-
T.must(message.lines.first).chomp.gsub(/\e\[[^m]+m/,
|
121
|
+
T.must(message.lines.first).chomp.gsub(/\e\[[^m]+m/, "")
|
122
122
|
end
|
123
123
|
|
124
124
|
sig { params(results: T::Array[Minitest::Result]).returns(T::Hash[String, Numeric]) }
|
125
125
|
def aggregate_suite_results(results)
|
126
126
|
aggregate = Hash.new(0)
|
127
127
|
results.each do |result|
|
128
|
-
aggregate[
|
129
|
-
aggregate[
|
130
|
-
aggregate[
|
131
|
-
aggregate[
|
128
|
+
aggregate["assertions"] += result.assertions
|
129
|
+
aggregate["failures"] += 1 if failure?(ResultType.of(result))
|
130
|
+
aggregate["tests"] += 1
|
131
|
+
aggregate["time"] += result.time
|
132
132
|
end
|
133
133
|
aggregate
|
134
134
|
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require_relative
|
4
|
+
require_relative "./distributed"
|
5
5
|
|
6
6
|
module Minitest
|
7
7
|
class << self
|
8
8
|
extend T::Sig
|
9
9
|
|
10
10
|
def plugin_distributed_options(opts, options)
|
11
|
-
opts.on(
|
11
|
+
opts.on("--disable-distributed", "Disable the distributed plugin") do
|
12
12
|
options[:disable_distributed] = true
|
13
13
|
end
|
14
14
|
|
@@ -4,9 +4,9 @@
|
|
4
4
|
module Minitest
|
5
5
|
class << self
|
6
6
|
def plugin_junitxml_options(opts, options)
|
7
|
-
options[:junitxml] = ENV[
|
7
|
+
options[:junitxml] = ENV["MINITEST_JUNITXML"]
|
8
8
|
|
9
|
-
opts.on(
|
9
|
+
opts.on("--junitxml=PATH", "Generate a JUnitXML report at the specified path") do |path|
|
10
10
|
options[:junitxml] = path
|
11
11
|
end
|
12
12
|
end
|
@@ -14,7 +14,7 @@ module Minitest
|
|
14
14
|
def plugin_junitxml_init(options)
|
15
15
|
return if options[:junitxml].nil?
|
16
16
|
|
17
|
-
require
|
17
|
+
require "minitest/distributed/reporters/junitxml_reporter"
|
18
18
|
reporter << Minitest::Distributed::Reporters::JUnitXMLReporter.new(options[:io], options)
|
19
19
|
end
|
20
20
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: minitest-distributed
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Willem van Bergen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|