henitai 0.2.0 → 0.3.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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +105 -1
  3. data/README.md +138 -5
  4. data/assets/schema/henitai.schema.json +41 -0
  5. data/lib/henitai/available_cpu_count.rb +16 -23
  6. data/lib/henitai/canonical_report_merger.rb +107 -0
  7. data/lib/henitai/canonical_report_writer.rb +22 -0
  8. data/lib/henitai/checkpoint_reporter.rb +79 -0
  9. data/lib/henitai/cli/clean_command.rb +54 -0
  10. data/lib/henitai/cli/command_support.rb +52 -0
  11. data/lib/henitai/cli/init_command.rb +64 -0
  12. data/lib/henitai/cli/operator_command.rb +96 -0
  13. data/lib/henitai/cli/options.rb +84 -0
  14. data/lib/henitai/cli/run_command.rb +136 -0
  15. data/lib/henitai/cli/run_options.rb +108 -0
  16. data/lib/henitai/cli.rb +27 -407
  17. data/lib/henitai/composite_progress_reporter.rb +42 -0
  18. data/lib/henitai/configuration.rb +42 -9
  19. data/lib/henitai/configuration_validator/rules.rb +161 -0
  20. data/lib/henitai/configuration_validator/scalars.rb +169 -0
  21. data/lib/henitai/configuration_validator.rb +20 -240
  22. data/lib/henitai/coverage_bootstrapper.rb +54 -5
  23. data/lib/henitai/coverage_formatter.rb +5 -1
  24. data/lib/henitai/coverage_report_reader.rb +28 -5
  25. data/lib/henitai/eager_load.rb +36 -5
  26. data/lib/henitai/execution_engine/env_scope.rb +67 -0
  27. data/lib/henitai/execution_engine.rb +115 -53
  28. data/lib/henitai/generated_artifacts.rb +58 -0
  29. data/lib/henitai/incremental_filter.rb +100 -0
  30. data/lib/henitai/integration/base.rb +171 -0
  31. data/lib/henitai/integration/child_debug_support.rb +119 -0
  32. data/lib/henitai/integration/child_runtime_control.rb +50 -0
  33. data/lib/henitai/integration/coverage_suppression.rb +52 -0
  34. data/lib/henitai/integration/minitest.rb +101 -0
  35. data/lib/henitai/integration/minitest_load_path.rb +14 -0
  36. data/lib/henitai/integration/minitest_suite_command.rb +17 -0
  37. data/lib/henitai/integration/minitest_test_runner.rb +39 -0
  38. data/lib/henitai/integration/mutant_run_support.rb +77 -0
  39. data/lib/henitai/integration/rails_environment_preloader.rb +14 -0
  40. data/lib/henitai/integration/rspec_child_runner.rb +61 -0
  41. data/lib/henitai/integration/rspec_test_selection.rb +138 -0
  42. data/lib/henitai/integration/scenario_log_support.rb +160 -0
  43. data/lib/henitai/integration.rb +22 -846
  44. data/lib/henitai/minitest_coverage_reporter.rb +4 -1
  45. data/lib/henitai/mutant/activator.rb +15 -79
  46. data/lib/henitai/mutant/parameter_source.rb +98 -0
  47. data/lib/henitai/mutant.rb +14 -6
  48. data/lib/henitai/mutant_history_store/sql.rb +90 -0
  49. data/lib/henitai/mutant_history_store/verdict_cache.rb +84 -0
  50. data/lib/henitai/mutant_history_store.rb +67 -81
  51. data/lib/henitai/mutant_identity.rb +33 -2
  52. data/lib/henitai/mutation_skip_directives.rb +227 -0
  53. data/lib/henitai/operator.rb +3 -1
  54. data/lib/henitai/operators/equality_identity_operator.rb +51 -0
  55. data/lib/henitai/operators/equality_operator.rb +8 -3
  56. data/lib/henitai/operators.rb +1 -0
  57. data/lib/henitai/per_test_coverage.rb +66 -0
  58. data/lib/henitai/per_test_coverage_collector.rb +23 -6
  59. data/lib/henitai/per_test_coverage_selector.rb +11 -33
  60. data/lib/henitai/process_worker_runner.rb +48 -334
  61. data/lib/henitai/reporter/dashboard_metadata_provider.rb +113 -0
  62. data/lib/henitai/reporter.rb +258 -125
  63. data/lib/henitai/reports_directory_lock.rb +76 -0
  64. data/lib/henitai/result.rb +88 -23
  65. data/lib/henitai/runner.rb +137 -218
  66. data/lib/henitai/scenario_execution_result.rb +12 -0
  67. data/lib/henitai/slot_scheduler/draining.rb +146 -0
  68. data/lib/henitai/slot_scheduler/process_control.rb +43 -0
  69. data/lib/henitai/slot_scheduler.rb +272 -0
  70. data/lib/henitai/static_filter.rb +16 -6
  71. data/lib/henitai/survivor_rerun_strategy.rb +195 -0
  72. data/lib/henitai/survivor_test_filter.rb +1 -1
  73. data/lib/henitai/test_prioritizer.rb +28 -2
  74. data/lib/henitai/timeout_calibrator.rb +44 -0
  75. data/lib/henitai/unparse_helper.rb +5 -2
  76. data/lib/henitai/verdict_fingerprint.rb +155 -0
  77. data/lib/henitai/version.rb +1 -1
  78. data/lib/henitai.rb +16 -1
  79. data/sig/configuration_validator.rbs +46 -22
  80. data/sig/henitai.rbs +386 -96
  81. metadata +45 -3
  82. data/lib/henitai/parallel_execution_runner.rb +0 -153
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: henitai
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Otten
@@ -103,26 +103,59 @@ files:
103
103
  - lib/henitai.rb
104
104
  - lib/henitai/arid_node_filter.rb
105
105
  - lib/henitai/available_cpu_count.rb
106
+ - lib/henitai/canonical_report_merger.rb
107
+ - lib/henitai/canonical_report_writer.rb
108
+ - lib/henitai/checkpoint_reporter.rb
106
109
  - lib/henitai/cli.rb
110
+ - lib/henitai/cli/clean_command.rb
111
+ - lib/henitai/cli/command_support.rb
112
+ - lib/henitai/cli/init_command.rb
113
+ - lib/henitai/cli/operator_command.rb
114
+ - lib/henitai/cli/options.rb
115
+ - lib/henitai/cli/run_command.rb
116
+ - lib/henitai/cli/run_options.rb
117
+ - lib/henitai/composite_progress_reporter.rb
107
118
  - lib/henitai/configuration.rb
108
119
  - lib/henitai/configuration_validator.rb
120
+ - lib/henitai/configuration_validator/rules.rb
121
+ - lib/henitai/configuration_validator/scalars.rb
109
122
  - lib/henitai/coverage_bootstrapper.rb
110
123
  - lib/henitai/coverage_formatter.rb
111
124
  - lib/henitai/coverage_report_reader.rb
112
125
  - lib/henitai/eager_load.rb
113
126
  - lib/henitai/equivalence_detector.rb
114
127
  - lib/henitai/execution_engine.rb
128
+ - lib/henitai/execution_engine/env_scope.rb
129
+ - lib/henitai/generated_artifacts.rb
115
130
  - lib/henitai/git_diff_analyzer.rb
131
+ - lib/henitai/incremental_filter.rb
116
132
  - lib/henitai/integration.rb
133
+ - lib/henitai/integration/base.rb
134
+ - lib/henitai/integration/child_debug_support.rb
135
+ - lib/henitai/integration/child_runtime_control.rb
136
+ - lib/henitai/integration/coverage_suppression.rb
137
+ - lib/henitai/integration/minitest.rb
138
+ - lib/henitai/integration/minitest_load_path.rb
139
+ - lib/henitai/integration/minitest_suite_command.rb
140
+ - lib/henitai/integration/minitest_test_runner.rb
141
+ - lib/henitai/integration/mutant_run_support.rb
142
+ - lib/henitai/integration/rails_environment_preloader.rb
143
+ - lib/henitai/integration/rspec_child_runner.rb
117
144
  - lib/henitai/integration/rspec_process_runner.rb
145
+ - lib/henitai/integration/rspec_test_selection.rb
146
+ - lib/henitai/integration/scenario_log_support.rb
118
147
  - lib/henitai/minitest_coverage_hook.rb
119
148
  - lib/henitai/minitest_coverage_reporter.rb
120
149
  - lib/henitai/minitest_simplecov.rb
121
150
  - lib/henitai/mutant.rb
122
151
  - lib/henitai/mutant/activator.rb
152
+ - lib/henitai/mutant/parameter_source.rb
123
153
  - lib/henitai/mutant_generator.rb
124
154
  - lib/henitai/mutant_history_store.rb
155
+ - lib/henitai/mutant_history_store/sql.rb
156
+ - lib/henitai/mutant_history_store/verdict_cache.rb
125
157
  - lib/henitai/mutant_identity.rb
158
+ - lib/henitai/mutation_skip_directives.rb
126
159
  - lib/henitai/operator.rb
127
160
  - lib/henitai/operators.rb
128
161
  - lib/henitai/operators/arithmetic_operator.rb
@@ -131,6 +164,7 @@ files:
131
164
  - lib/henitai/operators/block_statement.rb
132
165
  - lib/henitai/operators/boolean_literal.rb
133
166
  - lib/henitai/operators/conditional_expression.rb
167
+ - lib/henitai/operators/equality_identity_operator.rb
134
168
  - lib/henitai/operators/equality_operator.rb
135
169
  - lib/henitai/operators/hash_literal.rb
136
170
  - lib/henitai/operators/logical_operator.rb
@@ -144,18 +178,23 @@ files:
144
178
  - lib/henitai/operators/string_literal.rb
145
179
  - lib/henitai/operators/unary_operator.rb
146
180
  - lib/henitai/operators/update_operator.rb
147
- - lib/henitai/parallel_execution_runner.rb
148
181
  - lib/henitai/parser_current.rb
182
+ - lib/henitai/per_test_coverage.rb
149
183
  - lib/henitai/per_test_coverage_collector.rb
150
184
  - lib/henitai/per_test_coverage_selector.rb
151
185
  - lib/henitai/process_wakeup.rb
152
186
  - lib/henitai/process_worker_runner.rb
153
187
  - lib/henitai/reporter.rb
188
+ - lib/henitai/reporter/dashboard_metadata_provider.rb
189
+ - lib/henitai/reports_directory_lock.rb
154
190
  - lib/henitai/result.rb
155
191
  - lib/henitai/rspec_coverage_formatter.rb
156
192
  - lib/henitai/runner.rb
157
193
  - lib/henitai/sampling_strategy.rb
158
194
  - lib/henitai/scenario_execution_result.rb
195
+ - lib/henitai/slot_scheduler.rb
196
+ - lib/henitai/slot_scheduler/draining.rb
197
+ - lib/henitai/slot_scheduler/process_control.rb
159
198
  - lib/henitai/source_parser.rb
160
199
  - lib/henitai/static_filter.rb
161
200
  - lib/henitai/stillborn_filter.rb
@@ -163,11 +202,14 @@ files:
163
202
  - lib/henitai/subject_resolver.rb
164
203
  - lib/henitai/survivor_activation_cache.rb
165
204
  - lib/henitai/survivor_loader.rb
205
+ - lib/henitai/survivor_rerun_strategy.rb
166
206
  - lib/henitai/survivor_selector.rb
167
207
  - lib/henitai/survivor_test_filter.rb
168
208
  - lib/henitai/syntax_validator.rb
169
209
  - lib/henitai/test_prioritizer.rb
210
+ - lib/henitai/timeout_calibrator.rb
170
211
  - lib/henitai/unparse_helper.rb
212
+ - lib/henitai/verdict_fingerprint.rb
171
213
  - lib/henitai/version.rb
172
214
  - lib/henitai/warning_silencer.rb
173
215
  - sig/configuration_validator.rbs
@@ -181,7 +223,7 @@ metadata:
181
223
  changelog_uri: https://github.com/martinotten/henitai/blob/main/CHANGELOG.md
182
224
  documentation_uri: https://github.com/martinotten/henitai/blob/main/README.md
183
225
  homepage_uri: https://github.com/martinotten/henitai
184
- source_code_uri: https://github.com/martinotten/henitai/tree/v0.1.10
226
+ source_code_uri: https://github.com/martinotten/henitai/tree/v0.3.0
185
227
  rubygems_mfa_required: 'true'
186
228
  rdoc_options: []
187
229
  require_paths:
@@ -1,153 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Henitai
4
- # Runs pending mutants across worker threads with signal and stdin handling.
5
- class ParallelExecutionRunner
6
- ParallelExecutionContext = Struct.new(
7
- :queue, :integration, :config, :progress_reporter,
8
- :mutex, :state, :old_handlers, :stdin_watcher
9
- )
10
-
11
- def initialize(worker_count:)
12
- @worker_count = worker_count
13
- end
14
-
15
- def run(mutants, integration, config, progress_reporter, options = {})
16
- context = build_parallel_context(
17
- mutants,
18
- integration,
19
- config,
20
- progress_reporter
21
- )
22
- execute_parallel_execution(
23
- context,
24
- stdin_pipe: options.fetch(:stdin_pipe, false),
25
- process_mutant: options.fetch(:process_mutant)
26
- )
27
- end
28
-
29
- def execute_parallel_execution(context, stdin_pipe:, process_mutant:)
30
- install_parallel_signal_traps(context)
31
- start_parallel_stdin_watcher(context, stdin_pipe)
32
- parallel_workers(context, process_mutant).each(&:join)
33
- ensure
34
- teardown_parallel_execution(context)
35
- end
36
-
37
- private
38
-
39
- attr_reader :worker_count
40
-
41
- def teardown_parallel_execution(context)
42
- stop_parallel_stdin_watcher(context)
43
- restore_parallel_signal_traps(context)
44
- emit_scheduler_diagnostics if Integration::SchedulerDiagnostics.enabled?
45
- raise context.state[:error] if context&.state&.fetch(:error, nil)
46
- raise Interrupt if context&.state&.fetch(:stopping, false)
47
- end
48
-
49
- def emit_scheduler_diagnostics
50
- summary = Integration::SchedulerDiagnostics.summary
51
- warn "[henitai-scheduler] max_concurrent_children=#{summary[:max_concurrent]}"
52
- warn "[henitai-scheduler] child_intervals=#{summary[:intervals].inspect}"
53
- end
54
-
55
- def build_parallel_queue(mutants)
56
- Queue.new.tap { |queue| mutants.each { |mutant| queue << mutant } }
57
- end
58
-
59
- def build_parallel_context(mutants, integration, config, progress_reporter)
60
- ParallelExecutionContext.new(
61
- build_parallel_queue(mutants),
62
- integration,
63
- config,
64
- progress_reporter,
65
- Mutex.new,
66
- { stopping: false }
67
- )
68
- end
69
-
70
- def install_parallel_signal_traps(context)
71
- context.old_handlers = {
72
- int: trap(:INT) { stop_parallel_execution(context) },
73
- term: trap(:TERM) { stop_parallel_execution(context) },
74
- hup: trap(:HUP) { stop_parallel_execution(context) }
75
- }
76
- end
77
-
78
- def stop_parallel_execution(context)
79
- context.state[:stopping] = true
80
- context.queue.clear
81
- end
82
-
83
- def start_parallel_stdin_watcher(context, stdin_pipe)
84
- return unless stdin_pipe
85
- # CI runners expose stdin as a non-interactive pipe, so EOF there should
86
- # not be treated as a user disconnect.
87
- return if ci_environment?
88
-
89
- context.stdin_watcher = Thread.new do
90
- $stdin.read
91
- stop_parallel_execution(context)
92
- rescue IOError, Errno::EBADF
93
- nil
94
- end
95
- end
96
-
97
- def parallel_workers(context, process_mutant)
98
- Array.new(worker_count) do
99
- Thread.new { process_parallel_worker(context, process_mutant) }
100
- end
101
- end
102
-
103
- def process_parallel_worker(context, process_mutant)
104
- loop do
105
- break if context.state[:stopping]
106
-
107
- run_one_mutant(context, process_mutant)
108
- rescue ThreadError
109
- break
110
- rescue StandardError => e
111
- record_parallel_error(context, e)
112
- break
113
- end
114
- end
115
-
116
- def run_one_mutant(context, process_mutant)
117
- mutant = context.queue.pop(true)
118
- process_mutant.call(
119
- mutant,
120
- context.integration,
121
- context.config,
122
- context.progress_reporter,
123
- context.mutex
124
- )
125
- end
126
-
127
- def stop_parallel_stdin_watcher(context)
128
- context&.stdin_watcher&.kill
129
- end
130
-
131
- def restore_parallel_signal_traps(context)
132
- handlers = context&.old_handlers
133
- return unless handlers
134
-
135
- trap(:INT, handlers[:int] || "DEFAULT")
136
- trap(:TERM, handlers[:term] || "DEFAULT")
137
- trap(:HUP, handlers[:hup] || "DEFAULT")
138
- end
139
-
140
- def record_parallel_error(context, error)
141
- context.mutex.synchronize do
142
- context.state[:error] ||= error
143
- context.state[:stopping] = true
144
- context.queue.clear
145
- end
146
- end
147
-
148
- def ci_environment?
149
- value = ENV.fetch("CI", nil)
150
- value && !%w[0 false].include?(value.downcase)
151
- end
152
- end
153
- end