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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/minitest/fork_executor.rb +93 -69
  3. metadata +20 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e166bd6d5d09dc03b3888c59beb8a30ba259c7cef826f0bcfa373375b232151c
4
- data.tar.gz: caadad6c3971b6acafbe50fc0e1a3f76f7062d8c03bfe27ba11a578ecd91920e
3
+ metadata.gz: 6bd1e593335a149a422ff23630519000bd5f84e04bb8855682bd98511b07c6d1
4
+ data.tar.gz: 35f0d39d2498bd157e547ba852680a82fe3b5566616a7cdd28fa81b947cb160b
5
5
  SHA512:
6
- metadata.gz: 5775181f930796a6b81c36cf265a0fe562f216e21fa6ae16c42b0dc1318c5ceacd078d580071d8d8a6f8c511d8f78b5fe7af52258930bea6787bb015a172bffc
7
- data.tar.gz: 9a683822a4dd87af11d56088854e2cc10caf537388644f5f0ddabe8612b5ea92196b0b6f277a64758914fd0bc6712e33c3f90511d42d29bf707b40bc55c8dc69
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
- # #start is called by Minitest when initializing the executor. This is where
11
- # we override some Minitest internals to implement fork-based execution.
12
- def start
13
- # Store the reference to the original run_one_method method in order to
14
- # use it to actually run the test case.
15
- original_run_one_method = Minitest.method(:run_one_method)
16
-
17
- # Remove the original singleton method from Minitest in order to avoid
18
- # method redefinition warnings when patching it in the next step.
19
- class << Minitest
20
- remove_method(:run_one_method)
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
- # Define a new version of run_one_method that forks, calls the original
24
- # run_one_method in the child process, and sends results back to the
25
- # parent. klass and method_name are the two parameters accepted by the
26
- # original run_one_method - they're the test class (e.g. UserTest) and
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
- # Dump the result object to the write IO object so that it can be
72
- # read by the parent process.
73
- Marshal.dump(result, write_io)
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
- # We're done sending results to the parent so it's safe to close the
76
- # IO object now.
77
- write_io.close
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
- # Exit the child process as its job is now done.
80
- exit
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
- # This value is returned ONLY in the parent process, not in the child
84
- # process.
85
- result
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.3
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: 12.2.1
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: 12.2.1
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.2.22
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.