Class: Henitai::Integration::Base
- Inherits:
-
Object
- Object
- Henitai::Integration::Base
- Includes:
- ChildRuntimeControl
- Defined in:
- lib/henitai/integration/base.rb,
sig/henitai.rbs
Overview
Base class for all integrations. Provides the framework-agnostic child process lifecycle (wait, timeout handling, cleanup) and subprocess environment helpers. Concrete adapters mix in MutantRunSupport and implement #run_tests plus test selection.
Instance Method Summary collapse
-
#child_debug_log ⇒ ChildDebugLog
Child-run diagnostics.
- #cleanup_child_process(pid) ⇒ void
- #cleanup_process_group(pid) ⇒ void
- #handle_timeout(pid) ⇒ Symbol
- #pause(seconds) ⇒ void
- #per_test_coverage_supported? ⇒ Boolean
- #reap_child(pid) ⇒ void
- #restore_subprocess_env(original_env) ⇒ void
-
#run_mutant(mutant:, test_files:, timeout:) ⇒ ScenarioExecutionResult
Run test files in a child process with the mutant active.
- #run_suite ⇒ ScenarioExecutionResult
- #scenario_log_support ⇒ ScenarioLogSupport
-
#select_tests(subject) ⇒ Array<String>
Paths to test files that cover this subject.
-
#spawn_mutant(mutant:, test_files:) ⇒ RspecProcessRunner::ChildHandle
Fork a child process for the mutant without waiting for it to finish.
- #subprocess_env ⇒ Hash[String, String]
- #suppress_coverage! ⇒ void
- #suppress_simplecov! ⇒ void
-
#test_files ⇒ Array<String>
All test files for the configured framework.
- #wait_nonblocking(pid) ⇒ Object
- #wait_with_timeout(pid, timeout) ⇒ Object
- #with_non_interactive_stdin { ... } ⇒ Object
- #with_subprocess_env { ... } ⇒ Object
Instance Method Details
#child_debug_log ⇒ ChildDebugLog
Child-run diagnostics. Public so the child-side modules mixed into
concrete adapters can reach it without send.
20 21 22 |
# File 'lib/henitai/integration/base.rb', line 20 def child_debug_log @child_debug_log ||= ChildDebugLog.new end |
#cleanup_child_process(pid) ⇒ void
This method returns an undefined value.
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/henitai/integration/base.rb', line 115 def cleanup_child_process(pid) grace_period = 2.0 wakeup = Henitai.const_get(:ProcessWakeup).new.install Process.kill(:SIGTERM, pid) return if wait_nonblocking(pid) wakeup.wait(grace_period) wakeup.drain return if wait_nonblocking(pid) Process.kill(:SIGKILL, pid) rescue Errno::EPERM, Errno::ESRCH nil ensure wakeup&.close end |
#cleanup_process_group(pid) ⇒ void
This method returns an undefined value.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/henitai/integration/base.rb', line 80 def cleanup_process_group(pid) grace_period = 2.0 wakeup = Henitai.const_get(:ProcessWakeup).new.install Process.kill(:SIGTERM, -pid) return if wait_nonblocking(pid) wakeup.wait(grace_period) wakeup.drain return if wait_nonblocking(pid) Process.kill(:SIGKILL, -pid) rescue Errno::EPERM cleanup_child_process(pid) rescue Errno::ESRCH nil ensure wakeup&.close end |
#handle_timeout(pid) ⇒ Symbol
105 106 107 108 109 110 111 112 113 |
# File 'lib/henitai/integration/base.rb', line 105 def handle_timeout(pid) begin debug_child_timeout_dump(pid) cleanup_process_group(pid) ensure reap_child(pid) end :timeout end |
#pause(seconds) ⇒ void
This method returns an undefined value.
101 102 103 |
# File 'lib/henitai/integration/base.rb', line 101 def pause(seconds) sleep(seconds) end |
#per_test_coverage_supported? ⇒ Boolean
56 57 58 |
# File 'lib/henitai/integration/base.rb', line 56 def per_test_coverage_supported? false end |
#reap_child(pid) ⇒ void
This method returns an undefined value.
74 75 76 77 78 |
# File 'lib/henitai/integration/base.rb', line 74 def reap_child(pid) Process.wait(pid) rescue Errno::ECHILD, Errno::ESRCH nil end |
#restore_subprocess_env(original_env) ⇒ void
This method returns an undefined value.
157 158 159 160 161 162 163 164 165 |
# File 'lib/henitai/integration/base.rb', line 157 def restore_subprocess_env(original_env) original_env.each do |key, value| if value.nil? ENV.delete(key) else ENV[key] = value end end end |
#run_mutant(mutant:, test_files:, timeout:) ⇒ ScenarioExecutionResult
Run test files in a child process with the mutant active.
41 42 43 |
# File 'lib/henitai/integration/base.rb', line 41 def run_mutant(mutant:, test_files:, timeout:) raise NotImplementedError end |
#run_suite ⇒ ScenarioExecutionResult
400 |
# File 'sig/henitai.rbs', line 400
def run_suite: (Array[String], ?timeout: Float) -> ScenarioExecutionResult
|
#scenario_log_support ⇒ ScenarioLogSupport
142 143 144 |
# File 'lib/henitai/integration/base.rb', line 142 def scenario_log_support @scenario_log_support ||= ScenarioLogSupport.new end |
#select_tests(subject) ⇒ Array<String>
Returns paths to test files that cover this subject.
26 27 28 |
# File 'lib/henitai/integration/base.rb', line 26 def select_tests(subject) raise NotImplementedError end |
#spawn_mutant(mutant:, test_files:) ⇒ RspecProcessRunner::ChildHandle
Fork a child process for the mutant without waiting for it to finish. Returns a ChildHandle carrying the OS pid and log file paths. The caller is responsible for waiting and cleanup.
52 53 54 |
# File 'lib/henitai/integration/base.rb', line 52 def spawn_mutant(mutant:, test_files:) raise NotImplementedError end |
#subprocess_env ⇒ Hash[String, String]
132 133 134 |
# File 'lib/henitai/integration/base.rb', line 132 def subprocess_env { "PARALLEL_WORKERS" => "1" } end |
#suppress_coverage! ⇒ void
This method returns an undefined value.
414 |
# File 'sig/henitai.rbs', line 414
def suppress_coverage!: () -> void
|
#suppress_simplecov! ⇒ void
This method returns an undefined value.
413 |
# File 'sig/henitai.rbs', line 413
def suppress_simplecov!: () -> void
|
#test_files ⇒ Array<String>
Returns all test files for the configured framework.
31 32 33 |
# File 'lib/henitai/integration/base.rb', line 31 def test_files raise NotImplementedError end |
#wait_nonblocking(pid) ⇒ Object
136 137 138 139 140 |
# File 'lib/henitai/integration/base.rb', line 136 def wait_nonblocking(pid) Process.wait(pid, Process::WNOHANG) rescue Errno::ECHILD, Errno::ESRCH nil end |
#wait_with_timeout(pid, timeout) ⇒ Object
60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/henitai/integration/base.rb', line 60 def wait_with_timeout(pid, timeout) wakeup = Henitai.const_get(:ProcessWakeup).new.install return Process.last_status if wait_nonblocking(pid) wakeup.wait(timeout) wakeup.drain return Process.last_status if wait_nonblocking(pid) return Process.last_status if wait_nonblocking(pid) handle_timeout(pid) ensure wakeup&.close end |
#with_non_interactive_stdin { ... } ⇒ Object
167 168 169 170 171 172 173 |
# File 'lib/henitai/integration/base.rb', line 167 def with_non_interactive_stdin original_stdin = $stdin $stdin = StringIO.new yield ensure $stdin = original_stdin end |
#with_subprocess_env { ... } ⇒ Object
146 147 148 149 150 151 152 153 154 155 |
# File 'lib/henitai/integration/base.rb', line 146 def with_subprocess_env original_env = {} # : Hash[String, String?] subprocess_env.each do |key, value| original_env[key] = ENV.fetch(key, nil) ENV[key] = value end yield ensure restore_subprocess_env(original_env) end |