minitest-fork_executor 1.0.3 → 1.1.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/lib/minitest/fork_executor.rb +93 -69
- metadata +20 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6bd1e593335a149a422ff23630519000bd5f84e04bb8855682bd98511b07c6d1
|
|
4
|
+
data.tar.gz: 35f0d39d2498bd157e547ba852680a82fe3b5566616a7cdd28fa81b947cb160b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fc6a7ebe2f72cd6214469d3755325839289b0c65e05fa32544981bd2badbf865822ca62c07eeb731e39ce3f9267971b1426d092d37a68e6ec993083e4757b7b6
|
|
7
|
+
data.tar.gz: de20c9433516f9bfd89275e9d08802aa0ae50c2ffe5de60676dc148898012f000532328a67126a77600243452f297ea74c656bdbf5a9cba7ccb22568ceca1fcb
|
|
@@ -7,82 +7,106 @@ module Minitest
|
|
|
7
7
|
# offered by more modern Rubies.
|
|
8
8
|
|
|
9
9
|
class ForkExecutor
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
def
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
10
|
+
# Run a fork-based test case. The block passed to the method should actually
|
|
11
|
+
# run the test using the original code from Minitest.
|
|
12
|
+
def self.run
|
|
13
|
+
# Set up a binary pipe for transporting test results from the child
|
|
14
|
+
# to the parent process.
|
|
15
|
+
read_io, write_io = IO.pipe
|
|
16
|
+
read_io.binmode
|
|
17
|
+
write_io.binmode
|
|
18
|
+
|
|
19
|
+
if Process.fork
|
|
20
|
+
# The parent process responsible for collecting results.
|
|
21
|
+
|
|
22
|
+
# The parent process doesn't write anything.
|
|
23
|
+
write_io.close
|
|
24
|
+
|
|
25
|
+
# Load the result object passed by the child process.
|
|
26
|
+
result = Marshal.load(read_io)
|
|
27
|
+
|
|
28
|
+
# Unwrap all failures from FailureTransport so that they can be
|
|
29
|
+
# safely presented to the user.
|
|
30
|
+
result.failures.map!(&:failure)
|
|
31
|
+
|
|
32
|
+
# We're done reading results from the child so it's safe to close the
|
|
33
|
+
# IO object now.
|
|
34
|
+
read_io.close
|
|
35
|
+
|
|
36
|
+
# Wait for the child process to finish before returning the result.
|
|
37
|
+
Process.wait
|
|
38
|
+
else
|
|
39
|
+
# The child process responsible for running the test case.
|
|
40
|
+
|
|
41
|
+
# Run the test case method via the original .run_one_method.
|
|
42
|
+
result = yield
|
|
43
|
+
|
|
44
|
+
# Wrap failures in FailureTransport to avoid issue when marshalling.
|
|
45
|
+
# Some failures correspond to exceptions referencing unmarshallable
|
|
46
|
+
# objects. For example, a PostgreSQL exception may reference
|
|
47
|
+
# PG::Connection that cannot be marshalled. In those case, we replace
|
|
48
|
+
# the original error with UnmarshallableError retaining as much
|
|
49
|
+
# detail as possible.
|
|
50
|
+
result.failures.map! { |failure| FailureTransport.new(failure) }
|
|
51
|
+
|
|
52
|
+
# The child process doesn't read anything.
|
|
53
|
+
read_io.close
|
|
54
|
+
|
|
55
|
+
# Dump the result object to the write IO object so that it can be
|
|
56
|
+
# read by the parent process.
|
|
57
|
+
Marshal.dump(result, write_io)
|
|
58
|
+
|
|
59
|
+
# We're done sending results to the parent so it's safe to close the
|
|
60
|
+
# IO object now.
|
|
61
|
+
write_io.close
|
|
62
|
+
|
|
63
|
+
# Exit the child process as its job is now done.
|
|
64
|
+
exit
|
|
21
65
|
end
|
|
22
66
|
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
# the test method name (e.g. :test_email_must_be_unique).
|
|
28
|
-
Minitest.define_singleton_method(:run_one_method) do |klass, method_name|
|
|
29
|
-
# Set up a binary pipe for transporting test results from the child
|
|
30
|
-
# to the parent process.
|
|
31
|
-
read_io, write_io = IO.pipe
|
|
32
|
-
read_io.binmode
|
|
33
|
-
write_io.binmode
|
|
34
|
-
|
|
35
|
-
if Process.fork
|
|
36
|
-
# The parent process responsible for collecting results.
|
|
37
|
-
|
|
38
|
-
# The parent process doesn't write anything.
|
|
39
|
-
write_io.close
|
|
40
|
-
|
|
41
|
-
# Load the result object passed by the child process.
|
|
42
|
-
result = Marshal.load(read_io)
|
|
43
|
-
|
|
44
|
-
# Unwrap all failures from FailureTransport so that they can be
|
|
45
|
-
# safely presented to the user.
|
|
46
|
-
result.failures.map!(&:failure)
|
|
47
|
-
|
|
48
|
-
# We're done reading results from the child so it's safe to close the
|
|
49
|
-
# IO object now.
|
|
50
|
-
read_io.close
|
|
51
|
-
|
|
52
|
-
# Wait for the child process to finish before returning the result.
|
|
53
|
-
Process.wait
|
|
54
|
-
else
|
|
55
|
-
# The child process responsible for running the test case.
|
|
56
|
-
|
|
57
|
-
# Run the test case method via the original .run_one_method.
|
|
58
|
-
result = original_run_one_method.call(klass, method_name)
|
|
59
|
-
|
|
60
|
-
# Wrap failures in FailureTransport to avoid issue when marshalling.
|
|
61
|
-
# Some failures correspond to exceptions referencing unmarshallable
|
|
62
|
-
# objects. For example, a PostgreSQL exception may reference
|
|
63
|
-
# PG::Connection that cannot be marshalled. In those case, we replace
|
|
64
|
-
# the original error with UnmarshallableError retaining as much
|
|
65
|
-
# detail as possible.
|
|
66
|
-
result.failures.map! { |failure| FailureTransport.new(failure) }
|
|
67
|
-
|
|
68
|
-
# The child process doesn't read anything.
|
|
69
|
-
read_io.close
|
|
67
|
+
# This value is returned ONLY in the parent process, not in the child
|
|
68
|
+
# process.
|
|
69
|
+
result
|
|
70
|
+
end
|
|
70
71
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
# #start is called by Minitest when initializing the executor. This is where
|
|
73
|
+
# we override some Minitest internals to implement fork-based execution.
|
|
74
|
+
def start
|
|
75
|
+
if Minitest.respond_to?(:run_one_method)
|
|
76
|
+
# Minitest 5
|
|
74
77
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
+
# Store the reference to the original run_one_method method in order to
|
|
79
|
+
# use it to actually run the test case.
|
|
80
|
+
original_run_one_method = Minitest.method(:run_one_method)
|
|
78
81
|
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
# Remove the original singleton method from Minitest in order to avoid
|
|
83
|
+
# method redefinition warnings when patching it in the next step.
|
|
84
|
+
class << Minitest
|
|
85
|
+
remove_method(:run_one_method)
|
|
81
86
|
end
|
|
82
87
|
|
|
83
|
-
#
|
|
84
|
-
# process
|
|
85
|
-
|
|
88
|
+
# Define a new version of run_one_method that forks, calls the original
|
|
89
|
+
# run_one_method in the child process, and sends results back to the
|
|
90
|
+
# parent. klass and method_name are the two parameters accepted by the
|
|
91
|
+
# original run_one_method - they're the test class (e.g. UserTest) and
|
|
92
|
+
# the test method name (e.g. :test_email_must_be_unique).
|
|
93
|
+
Minitest.define_singleton_method(:run_one_method) do |klass, method_name|
|
|
94
|
+
ForkExecutor.run do
|
|
95
|
+
original_run_one_method.call(klass, method_name)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
else
|
|
99
|
+
# Minitest 6
|
|
100
|
+
|
|
101
|
+
Runnable.runnables.each do |runnable_class|
|
|
102
|
+
original_run_method = runnable_class.instance_method(:run)
|
|
103
|
+
runnable_class.define_method(:run) do
|
|
104
|
+
bound_original_run_method = original_run_method.bind(self)
|
|
105
|
+
ForkExecutor.run do
|
|
106
|
+
bound_original_run_method.call
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
86
110
|
end
|
|
87
111
|
end
|
|
88
112
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: minitest-fork_executor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Greg Navis
|
|
@@ -28,16 +28,30 @@ dependencies:
|
|
|
28
28
|
name: rake
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- -
|
|
31
|
+
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
33
|
+
version: 13.0.0
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- -
|
|
38
|
+
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
40
|
+
version: 13.0.0
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: ostruct
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
41
55
|
description: Run each test_* method in a separate process thus eliminating test case
|
|
42
56
|
interference.
|
|
43
57
|
email: contact@gregnavis.com
|
|
@@ -67,7 +81,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
67
81
|
- !ruby/object:Gem::Version
|
|
68
82
|
version: '0'
|
|
69
83
|
requirements: []
|
|
70
|
-
rubygems_version: 3.
|
|
84
|
+
rubygems_version: 3.4.19
|
|
71
85
|
signing_key:
|
|
72
86
|
specification_version: 4
|
|
73
87
|
summary: Near-perfect process-level test case isolation.
|