Class: Henitai::Integration::Base

Inherits:
Object
  • Object
show all
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.

Direct Known Subclasses

Minitest, Rspec

Instance Method Summary collapse

Instance Method Details

#cleanup_child_process(pid) ⇒ void

This method returns an undefined value.

Parameters:

  • (Integer)


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.

Parameters:

  • (Integer)


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

Returns:

  • (Boolean)


395
# File 'sig/henitai.rbs', line 395

def debug_child?: () -> bool

#debug_child_activation_checkvoid

This method returns an undefined value.



402
# File 'sig/henitai.rbs', line 402

def debug_child_activation_check: () -> void

#debug_child_activation_endvoid

This method returns an undefined value.

Parameters:

  • activation_result (Object)
  • test_files: (Array[String])


400
# File 'sig/henitai.rbs', line 400

def debug_child_activation_end: (untyped activation_result, test_files: Array[String]) -> void

#debug_child_activation_startvoid

This method returns an undefined value.

Parameters:

  • mutant_id (String)


399
# File 'sig/henitai.rbs', line 399

def debug_child_activation_start: (String mutant_id) -> void

#debug_child_example_countvoid

This method returns an undefined value.

Parameters:

  • (String)


403
# File 'sig/henitai.rbs', line 403

def debug_child_example_count: (String) -> void

#debug_child_mutant_metavoid

This method returns an undefined value.

Parameters:



401
# File 'sig/henitai.rbs', line 401

def debug_child_mutant_meta: (Mutant) -> void

#debug_child_putsvoid

This method returns an undefined value.

Parameters:

  • (String)


396
# File 'sig/henitai.rbs', line 396

def debug_child_puts: (String) -> void

#debug_child_rspec_exitvoid

This method returns an undefined value.

Parameters:

  • status (Object)


398
# File 'sig/henitai.rbs', line 398

def debug_child_rspec_exit: (untyped status) -> void

#debug_child_rspec_tracevoid

This method returns an undefined value.

Parameters:

  • test_files: (Array[String])
  • rspec_options: (Array[String])
  • rspec_argv: (Array[String])


397
# File 'sig/henitai.rbs', line 397

def debug_child_rspec_trace: (test_files: Array[String], rspec_options: Array[String], rspec_argv: Array[String]) -> void

#handle_timeout(pid) ⇒ Symbol

Parameters:

  • (Integer)

Returns:

  • (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

Parameters:

  • (String)

Returns:

  • (Boolean)


405
# File 'sig/henitai.rbs', line 405

def loaded_feature?: (String) -> bool

#loaded_feature_mapArray[[String, bool]]

Parameters:

  • (Array[String])

Returns:

  • (Array[[String, bool]])


404
# File 'sig/henitai.rbs', line 404

def loaded_feature_map: (Array[String]) -> Array[[String, bool]]

#pause(seconds) ⇒ void

This method returns an undefined value.

Parameters:

  • (Float)


96
97
98
# File 'lib/henitai/integration/base.rb', line 96

def pause(seconds)
  sleep(seconds)
end

#per_test_coverage_supported?Boolean

Returns:

  • (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.

Parameters:

  • (Integer)


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.

Parameters:

  • (Hash[String, String?])


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_countInteger?

Returns:

  • (Integer, nil)


406
# File 'sig/henitai.rbs', line 406

def rspec_world_example_count: () -> Integer?

#run_mutant(mutant:, test_files:, timeout:) ⇒ ScenarioExecutionResult

Run test files in a child process with the mutant active.

Parameters:

  • mutant (Mutant)
  • test_files (Array<String>)
  • timeout (Float)

    seconds

  • mutant: (Mutant)
  • test_files: (Array[String])
  • timeout: (Float)

Returns:

Raises:

  • (NotImplementedError)


36
37
38
# File 'lib/henitai/integration/base.rb', line 36

def run_mutant(mutant:, test_files:, timeout:)
  raise NotImplementedError
end

#run_suiteScenarioExecutionResult

Parameters:

  • (Array[String])
  • timeout: (Float)

Returns:



381
# File 'sig/henitai.rbs', line 381

def run_suite: (Array[String], ?timeout: Float) -> ScenarioExecutionResult

#scenario_log_supportScenarioLogSupport

Returns:



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.

Parameters:

Returns:

  • (Array<String>)

    paths to test files that cover this subject

Raises:

  • (NotImplementedError)


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.

Parameters:

  • mutant (Mutant)
  • test_files (Array<String>)
  • mutant: (Mutant)
  • test_files: (Array[String])

Returns:

  • (RspecProcessRunner::ChildHandle)

Raises:

  • (NotImplementedError)


47
48
49
# File 'lib/henitai/integration/base.rb', line 47

def spawn_mutant(mutant:, test_files:)
  raise NotImplementedError
end

#subprocess_envHash[String, String]

Returns:

  • (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.



394
# File 'sig/henitai.rbs', line 394

def suppress_coverage!: () -> void

#suppress_simplecov!void

This method returns an undefined value.



393
# File 'sig/henitai.rbs', line 393

def suppress_simplecov!: () -> void

#test_filesArray<String>

Returns all test files for the configured framework.

Returns:

  • (Array<String>)

    all test files for the configured framework

Raises:

  • (NotImplementedError)


26
27
28
# File 'lib/henitai/integration/base.rb', line 26

def test_files
  raise NotImplementedError
end

#wait_nonblocking(pid) ⇒ Object

Parameters:

  • (Integer)

Returns:

  • (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

Parameters:

  • (Integer)
  • (Float)

Returns:

  • (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

Yields:

Yield Returns:

  • (Object)

Returns:

  • (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

Yields:

Yield Returns:

  • (Object)

Returns:

  • (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