Class: Henitai::Integration::Base
- Inherits:
-
Object
- Object
- Henitai::Integration::Base
- Includes:
- ChildDebugSupport, 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
- #cleanup_child_process(pid) ⇒ void
- #cleanup_process_group(pid) ⇒ void
- #debug_child? ⇒ Boolean
- #debug_child_activation_check ⇒ void
- #debug_child_activation_end ⇒ void
- #debug_child_activation_start ⇒ void
- #debug_child_example_count ⇒ void
- #debug_child_mutant_meta ⇒ void
- #debug_child_puts ⇒ void
- #debug_child_rspec_exit ⇒ void
- #debug_child_rspec_trace ⇒ void
- #handle_timeout(pid) ⇒ Symbol
- #loaded_feature? ⇒ Boolean
- #loaded_feature_map ⇒ Array[[String, bool]]
- #pause(seconds) ⇒ void
- #per_test_coverage_supported? ⇒ Boolean
- #reap_child(pid) ⇒ void
- #restore_subprocess_env(original_env) ⇒ void
- #rspec_world_example_count ⇒ Integer?
-
#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
#cleanup_child_process(pid) ⇒ void
This method returns an undefined value.
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/henitai/integration/base.rb', line 110 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.
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/henitai/integration/base.rb', line 75 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 |
#debug_child? ⇒ Boolean
393 |
# File 'sig/henitai.rbs', line 393
def debug_child?: () -> bool
|
#debug_child_activation_check ⇒ void
This method returns an undefined value.
400 |
# File 'sig/henitai.rbs', line 400
def debug_child_activation_check: () -> void
|
#debug_child_activation_end ⇒ void
This method returns an undefined value.
398 |
# File 'sig/henitai.rbs', line 398
def debug_child_activation_end: (untyped activation_result, test_files: Array[String]) -> void
|
#debug_child_activation_start ⇒ void
This method returns an undefined value.
397 |
# File 'sig/henitai.rbs', line 397
def debug_child_activation_start: (String mutant_id) -> void
|
#debug_child_example_count ⇒ void
This method returns an undefined value.
401 |
# File 'sig/henitai.rbs', line 401
def debug_child_example_count: (String) -> void
|
#debug_child_mutant_meta ⇒ void
This method returns an undefined value.
399 |
# File 'sig/henitai.rbs', line 399
def debug_child_mutant_meta: (Mutant) -> void
|
#debug_child_puts ⇒ void
This method returns an undefined value.
394 |
# File 'sig/henitai.rbs', line 394
def debug_child_puts: (String) -> void
|
#debug_child_rspec_exit ⇒ void
This method returns an undefined value.
396 |
# File 'sig/henitai.rbs', line 396
def debug_child_rspec_exit: (untyped status) -> void
|
#debug_child_rspec_trace ⇒ void
This method returns an undefined value.
395 |
# File 'sig/henitai.rbs', line 395
def debug_child_rspec_trace: (test_files: Array[String], rspec_options: Array[String], rspec_argv: Array[String]) -> void
|
#handle_timeout(pid) ⇒ Symbol
100 101 102 103 104 105 106 107 108 |
# File 'lib/henitai/integration/base.rb', line 100 def handle_timeout(pid) begin debug_child_timeout_dump(pid) cleanup_process_group(pid) ensure reap_child(pid) end :timeout end |
#loaded_feature? ⇒ Boolean
403 |
# File 'sig/henitai.rbs', line 403
def loaded_feature?: (String) -> bool
|
#loaded_feature_map ⇒ Array[[String, bool]]
402 |
# File 'sig/henitai.rbs', line 402
def loaded_feature_map: (Array[String]) -> Array[[String, bool]]
|
#pause(seconds) ⇒ void
This method returns an undefined value.
96 97 98 |
# File 'lib/henitai/integration/base.rb', line 96 def pause(seconds) sleep(seconds) end |
#per_test_coverage_supported? ⇒ Boolean
51 52 53 |
# File 'lib/henitai/integration/base.rb', line 51 def per_test_coverage_supported? false end |
#reap_child(pid) ⇒ void
This method returns an undefined value.
69 70 71 72 73 |
# File 'lib/henitai/integration/base.rb', line 69 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.
152 153 154 155 156 157 158 159 160 |
# File 'lib/henitai/integration/base.rb', line 152 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 |
#rspec_world_example_count ⇒ Integer?
404 |
# File 'sig/henitai.rbs', line 404
def rspec_world_example_count: () -> Integer?
|
#run_mutant(mutant:, test_files:, timeout:) ⇒ ScenarioExecutionResult
Run test files in a child process with the mutant active.
36 37 38 |
# File 'lib/henitai/integration/base.rb', line 36 def run_mutant(mutant:, test_files:, timeout:) raise NotImplementedError end |
#run_suite ⇒ ScenarioExecutionResult
379 |
# File 'sig/henitai.rbs', line 379
def run_suite: (Array[String], ?timeout: Float) -> ScenarioExecutionResult
|
#scenario_log_support ⇒ ScenarioLogSupport
137 138 139 |
# File 'lib/henitai/integration/base.rb', line 137 def scenario_log_support @scenario_log_support ||= ScenarioLogSupport.new end |
#select_tests(subject) ⇒ Array<String>
Returns paths to test files that cover this subject.
21 22 23 |
# File 'lib/henitai/integration/base.rb', line 21 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.
47 48 49 |
# File 'lib/henitai/integration/base.rb', line 47 def spawn_mutant(mutant:, test_files:) raise NotImplementedError end |
#subprocess_env ⇒ Hash[String, String]
127 128 129 |
# File 'lib/henitai/integration/base.rb', line 127 def subprocess_env { "PARALLEL_WORKERS" => "1" } end |
#suppress_coverage! ⇒ void
This method returns an undefined value.
392 |
# File 'sig/henitai.rbs', line 392
def suppress_coverage!: () -> void
|
#suppress_simplecov! ⇒ void
This method returns an undefined value.
391 |
# File 'sig/henitai.rbs', line 391
def suppress_simplecov!: () -> void
|
#test_files ⇒ Array<String>
Returns all test files for the configured framework.
26 27 28 |
# File 'lib/henitai/integration/base.rb', line 26 def test_files raise NotImplementedError end |
#wait_nonblocking(pid) ⇒ Object
131 132 133 134 135 |
# File 'lib/henitai/integration/base.rb', line 131 def wait_nonblocking(pid) Process.wait(pid, Process::WNOHANG) rescue Errno::ECHILD, Errno::ESRCH nil end |
#wait_with_timeout(pid, timeout) ⇒ Object
55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/henitai/integration/base.rb', line 55 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
162 163 164 165 166 167 168 |
# File 'lib/henitai/integration/base.rb', line 162 def with_non_interactive_stdin original_stdin = $stdin $stdin = StringIO.new yield ensure $stdin = original_stdin end |
#with_subprocess_env { ... } ⇒ Object
141 142 143 144 145 146 147 148 149 150 |
# File 'lib/henitai/integration/base.rb', line 141 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 |