minitest-parallel_fork 2.0.0 → 2.1.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/CHANGELOG +8 -0
- data/README.rdoc +19 -0
- data/lib/minitest/parallel_fork/fail_fast.rb +2 -54
- data/lib/minitest/parallel_fork/halt.rb +55 -0
- data/lib/minitest/parallel_fork/interrupt.rb +45 -0
- data/lib/minitest/parallel_fork.rb +34 -17
- metadata +6 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d3ea39201143c49a9886a6d8e088534321ec4083d1b1e1cbf80dbcf2a805f912
|
|
4
|
+
data.tar.gz: 8d09b179947dad7aba1db8d67db6bc4ba578e5ac2a0ece7a28645cdfffd67de6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 84070499e66a0c2b5e1fb9e4dcd9d2d773a73812f35c0c55796ced661a61af1361ab10e1825f19fba4a7ea538f02d11e9a8df50d57d4f27b48eaea5d0ff6ef05
|
|
7
|
+
data.tar.gz: 3cbd02252db159fcaeeb85f6caed1c979b36af36fc57a44c0775929f71eaf3a213d2c4457644f331214fb2433e09589933b6ec415df82da4513f601336193bdf
|
data/CHANGELOG
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
=== 2.1.1 (2025-12-18)
|
|
2
|
+
|
|
3
|
+
* Work with minitest 6+ (jeremyevans)
|
|
4
|
+
|
|
5
|
+
=== 2.1.0 (2025-07-02)
|
|
6
|
+
|
|
7
|
+
* Add minitest/parallel_fork/interrupt with support handling interrupts (stackmystack, jeremyevans) (#14)
|
|
8
|
+
|
|
1
9
|
=== 2.0.0 (2023-11-08)
|
|
2
10
|
|
|
3
11
|
* Avoid method redefined warning in verbose warning mode (jeremyevans)
|
data/README.rdoc
CHANGED
|
@@ -79,6 +79,20 @@ Note that minitest-parallel_fork uses suite-based parallelism, so tests will not
|
|
|
79
79
|
stop until one child has a failing test suite (test class that has a failing test
|
|
80
80
|
method), and other children are signaled and also stop processing.
|
|
81
81
|
|
|
82
|
+
== Interrupt Support
|
|
83
|
+
|
|
84
|
+
If you would like to run tests in parallel, but allow for shutting down children
|
|
85
|
+
when SIGINT is sent to the process, you can use:
|
|
86
|
+
|
|
87
|
+
RUBYOPT=-rminitest/parallel_fork/interrupt ruby spec_runner.rb
|
|
88
|
+
|
|
89
|
+
The first SIGINT to a process will ask the child processes to shut down gracefully
|
|
90
|
+
with SIGUSR1. The second SIGINT to a process will kill the child processes with
|
|
91
|
+
SIGKILL.
|
|
92
|
+
|
|
93
|
+
Note that if you use rake to run the specs, the second SIGINT may not be sent to
|
|
94
|
+
to the parent process, as rake does it's own SIGINT handling.
|
|
95
|
+
|
|
82
96
|
== ActiveRecord
|
|
83
97
|
|
|
84
98
|
To use this with Rails/ActiveRecord, you probably want to use hooks similar to:
|
|
@@ -105,6 +119,11 @@ specs:
|
|
|
105
119
|
spec_sqlite: 1.75x - 1.86x 2.26x - 2.65x
|
|
106
120
|
spec_postgres: 1.32x - 1.40x Untested
|
|
107
121
|
|
|
122
|
+
= Known Issues
|
|
123
|
+
|
|
124
|
+
When using with minitest 6 and minitest-hooks, reported assertion counts may be
|
|
125
|
+
inaccurate, though run, failure, and error counts should still be accurate.
|
|
126
|
+
|
|
108
127
|
= License
|
|
109
128
|
|
|
110
129
|
MIT
|
|
@@ -1,69 +1,17 @@
|
|
|
1
|
+
require_relative 'halt'
|
|
1
2
|
require_relative '../parallel_fork'
|
|
2
3
|
|
|
3
4
|
module Minitest::ParalleForkFailFast
|
|
4
|
-
|
|
5
|
-
super
|
|
6
|
-
Signal.trap(:USR1) do
|
|
7
|
-
@parallel_fork_stop = true
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def parallel_fork_data_to_marshal
|
|
12
|
-
super << @parallel_fork_stop
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def parallel_fork_data_from_marshal(data)
|
|
16
|
-
data = Marshal.load(data)
|
|
17
|
-
@parallel_fork_stop = true if data.pop
|
|
18
|
-
data
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def parallel_fork_run_test_suites(suites, reporter, options)
|
|
22
|
-
suites.each do |suite|
|
|
23
|
-
parallel_fork_run_test_suite(suite, reporter, options)
|
|
24
|
-
|
|
25
|
-
# Fail fast if this child process had a failure,
|
|
26
|
-
# Or the USR1 signal was received indicating other child processes had a failure.
|
|
27
|
-
break if @parallel_fork_stop
|
|
28
|
-
end
|
|
29
|
-
end
|
|
5
|
+
include Minitest::ParallelForkHalt
|
|
30
6
|
|
|
31
7
|
def parallel_fork_run_test_suite(suite, reporter, options)
|
|
32
8
|
super
|
|
33
9
|
|
|
34
|
-
|
|
35
10
|
if parallel_fork_stat_reporter.results.any?{|r| !r.failure.is_a?(Minitest::Skip)}
|
|
36
11
|
# At least one failure or error, mark as failing fast
|
|
37
12
|
@parallel_fork_stop = true
|
|
38
13
|
end
|
|
39
14
|
end
|
|
40
|
-
|
|
41
|
-
def parallel_fork_child_data(data)
|
|
42
|
-
threads = {}
|
|
43
|
-
data.each{|pid, read| threads[pid] = Thread.new(read, &:read)}
|
|
44
|
-
results = []
|
|
45
|
-
|
|
46
|
-
while sleep(0.01) && !threads.empty?
|
|
47
|
-
threads.to_a.each do |pid, thread|
|
|
48
|
-
unless thread.alive?
|
|
49
|
-
threads.delete(pid)
|
|
50
|
-
results << parallel_fork_data_from_marshal(thread.value)
|
|
51
|
-
|
|
52
|
-
if @parallel_fork_stop
|
|
53
|
-
# If any child failed fast, signal other children to fail fast
|
|
54
|
-
threads.each_key do |pid|
|
|
55
|
-
Process.kill(:USR1, pid)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# Set a flag indicating that all child processes have been signaled
|
|
59
|
-
@parallel_fork_stop = :FINISHED
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
results
|
|
66
|
-
end
|
|
67
15
|
end
|
|
68
16
|
|
|
69
17
|
Minitest.singleton_class.prepend(Minitest::ParalleForkFailFast)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Minitest::ParallelForkHalt
|
|
2
|
+
def run_after_parallel_fork_hook(i)
|
|
3
|
+
super
|
|
4
|
+
Signal.trap(:USR1) do
|
|
5
|
+
@parallel_fork_stop = true
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def parallel_fork_data_to_marshal
|
|
10
|
+
super << @parallel_fork_stop
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def parallel_fork_data_from_marshal(data)
|
|
14
|
+
data = Marshal.load(data)
|
|
15
|
+
@parallel_fork_stop = true if data.pop
|
|
16
|
+
data
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def parallel_fork_run_test_suites(suites, reporter, options)
|
|
20
|
+
suites.each do |suite|
|
|
21
|
+
parallel_fork_run_test_suite(suite, reporter, options)
|
|
22
|
+
|
|
23
|
+
# Halt if this child process requested an exit,
|
|
24
|
+
# Or other child processes requested an exit.
|
|
25
|
+
break if @parallel_fork_stop
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def parallel_fork_child_data(data)
|
|
30
|
+
threads = {}
|
|
31
|
+
data.each{|pid, read| threads[pid] = Thread.new(read, &:read)}
|
|
32
|
+
results = []
|
|
33
|
+
|
|
34
|
+
while sleep(0.01) && !threads.empty?
|
|
35
|
+
threads.to_a.each do |pid, thread|
|
|
36
|
+
unless thread.alive?
|
|
37
|
+
threads.delete(pid)
|
|
38
|
+
results << parallel_fork_data_from_marshal(thread.value)
|
|
39
|
+
|
|
40
|
+
if @parallel_fork_stop
|
|
41
|
+
# If halt is requested, signal other children to halt
|
|
42
|
+
threads.each_key do |pid|
|
|
43
|
+
Process.kill(:USR1, pid)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Set a flag indicating that all child processes have been signaled
|
|
47
|
+
@parallel_fork_stop = :FINISHED
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
results
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'minitest'
|
|
2
|
+
|
|
3
|
+
require_relative 'halt'
|
|
4
|
+
require_relative '../parallel_fork'
|
|
5
|
+
|
|
6
|
+
module Minitest
|
|
7
|
+
@parallel_fork_child_pids = []
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module Minitest::ParallelForkInterrupt
|
|
11
|
+
include Minitest::ParallelForkHalt
|
|
12
|
+
|
|
13
|
+
def run_before_parallel_fork_hook
|
|
14
|
+
Signal.trap(:INT) do
|
|
15
|
+
Signal.trap(:INT) do
|
|
16
|
+
parallel_fork_kill_all :KILL
|
|
17
|
+
end
|
|
18
|
+
$stderr.puts "\nInterrupted.\nExiting ...\nInterrupt again to exit immediately."
|
|
19
|
+
parallel_fork_kill_all :USR1
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def run_after_parallel_fork_hook(i)
|
|
24
|
+
super
|
|
25
|
+
Signal.trap(:INT, 'IGNORE')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def parallel_fork_fork_child(i, suites, reporter, options)
|
|
29
|
+
res = super
|
|
30
|
+
@parallel_fork_child_pids << res[0]
|
|
31
|
+
res
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def parallel_fork_kill_all(signal)
|
|
35
|
+
@parallel_fork_child_pids.each do |pid|
|
|
36
|
+
begin
|
|
37
|
+
Process.kill(signal, pid)
|
|
38
|
+
rescue Errno::ESRCH
|
|
39
|
+
# Process already terminated
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
Minitest.singleton_class.prepend(Minitest::ParallelForkInterrupt)
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
require 'minitest'
|
|
2
2
|
|
|
3
3
|
module Minitest::Unparallelize
|
|
4
|
-
|
|
4
|
+
# :nocov:
|
|
5
|
+
meth = Minitest::VERSION >= '6' ? :run : :run_one_method
|
|
6
|
+
# :nocov:
|
|
7
|
+
define_method(meth, &Minitest::Test.method(meth))
|
|
5
8
|
end
|
|
6
9
|
|
|
7
10
|
module Minitest
|
|
@@ -74,30 +77,40 @@ class << Minitest
|
|
|
74
77
|
suite.extend(Minitest::Unparallelize)
|
|
75
78
|
end
|
|
76
79
|
|
|
77
|
-
|
|
80
|
+
if Minitest::VERSION >= '6'
|
|
81
|
+
suite.run_suite(reporter, options)
|
|
82
|
+
# :nocov:
|
|
83
|
+
else
|
|
84
|
+
suite.run(reporter, options)
|
|
85
|
+
end
|
|
86
|
+
# :nocov:
|
|
78
87
|
end
|
|
79
88
|
|
|
80
89
|
def parallel_fork_setup_children(suites, reporter, options)
|
|
81
90
|
set_parallel_fork_stat_reporter(reporter)
|
|
82
91
|
run_before_parallel_fork_hook
|
|
83
92
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
93
|
+
parallel_fork_number.times.map do |i|
|
|
94
|
+
parallel_fork_fork_child(i, suites, reporter, options)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def parallel_fork_fork_child(i, suites, reporter, options)
|
|
99
|
+
read, write = IO.pipe.each{|io| io.binmode}
|
|
100
|
+
pid = Process.fork do
|
|
101
|
+
read.close
|
|
102
|
+
run_after_parallel_fork_hook(i)
|
|
90
103
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
104
|
+
p_suites = []
|
|
105
|
+
n = parallel_fork_number
|
|
106
|
+
suites.each_with_index{|s, j| p_suites << s if j % n == i}
|
|
107
|
+
parallel_fork_run_test_suites(p_suites, reporter, options)
|
|
94
108
|
|
|
95
|
-
|
|
96
|
-
write.close
|
|
97
|
-
end
|
|
109
|
+
write.write(Marshal.dump(parallel_fork_data_to_marshal))
|
|
98
110
|
write.close
|
|
99
|
-
[pid, read]
|
|
100
111
|
end
|
|
112
|
+
write.close
|
|
113
|
+
[pid, read]
|
|
101
114
|
end
|
|
102
115
|
|
|
103
116
|
def parallel_fork_child_data(data)
|
|
@@ -120,12 +133,16 @@ class << Minitest
|
|
|
120
133
|
(ENV['NCPU'] || 4).to_i
|
|
121
134
|
end
|
|
122
135
|
|
|
136
|
+
# :nocov:
|
|
137
|
+
run_method = Minitest::VERSION >= '6' ? :run_all_suites : :__run
|
|
138
|
+
# :nocov:
|
|
139
|
+
|
|
123
140
|
# Avoid method redefined verbose warning
|
|
124
|
-
|
|
141
|
+
alias_method run_method, run_method
|
|
125
142
|
|
|
126
143
|
# Override __run to use a child forks to run the speeds, which
|
|
127
144
|
# allows for parallel spec execution on MRI.
|
|
128
|
-
|
|
145
|
+
define_method(run_method) do |reporter, options|
|
|
129
146
|
parallel_fork_wait_for_children(parallel_fork_setup_children(parallel_fork_suites, reporter, options), reporter)
|
|
130
147
|
nil
|
|
131
148
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: minitest-parallel_fork
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jeremy Evans
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: minitest
|
|
@@ -63,15 +62,17 @@ email: code@jeremyevans.net
|
|
|
63
62
|
executables: []
|
|
64
63
|
extensions: []
|
|
65
64
|
extra_rdoc_files:
|
|
66
|
-
- README.rdoc
|
|
67
65
|
- CHANGELOG
|
|
68
66
|
- MIT-LICENSE
|
|
67
|
+
- README.rdoc
|
|
69
68
|
files:
|
|
70
69
|
- CHANGELOG
|
|
71
70
|
- MIT-LICENSE
|
|
72
71
|
- README.rdoc
|
|
73
72
|
- lib/minitest/parallel_fork.rb
|
|
74
73
|
- lib/minitest/parallel_fork/fail_fast.rb
|
|
74
|
+
- lib/minitest/parallel_fork/halt.rb
|
|
75
|
+
- lib/minitest/parallel_fork/interrupt.rb
|
|
75
76
|
homepage: http://github.com/jeremyevans/minitest-parallel_fork
|
|
76
77
|
licenses:
|
|
77
78
|
- MIT
|
|
@@ -80,7 +81,6 @@ metadata:
|
|
|
80
81
|
changelog_uri: https://github.com/jeremyevans/minitest-parallel_fork/blob/master/CHANGELOG
|
|
81
82
|
mailing_list_uri: https://github.com/jeremyevans/minitest-parallel_fork/discussions
|
|
82
83
|
source_code_uri: https://github.com/jeremyevans/minitest-parallel_fork
|
|
83
|
-
post_install_message:
|
|
84
84
|
rdoc_options:
|
|
85
85
|
- "--quiet"
|
|
86
86
|
- "--line-numbers"
|
|
@@ -102,8 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
102
102
|
- !ruby/object:Gem::Version
|
|
103
103
|
version: '0'
|
|
104
104
|
requirements: []
|
|
105
|
-
rubygems_version: 3.
|
|
106
|
-
signing_key:
|
|
105
|
+
rubygems_version: 3.6.9
|
|
107
106
|
specification_version: 4
|
|
108
107
|
summary: Fork-based parallelization for minitest
|
|
109
108
|
test_files: []
|