henitai 0.2.1 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +80 -1
- data/README.md +123 -2
- data/assets/schema/henitai.schema.json +35 -0
- data/lib/henitai/available_cpu_count.rb +16 -23
- data/lib/henitai/canonical_report_merger.rb +107 -0
- data/lib/henitai/canonical_report_writer.rb +22 -0
- data/lib/henitai/checkpoint_reporter.rb +79 -0
- data/lib/henitai/cli/clean_command.rb +14 -8
- data/lib/henitai/cli/command_support.rb +2 -1
- data/lib/henitai/cli/operator_command.rb +2 -1
- data/lib/henitai/cli/options.rb +21 -57
- data/lib/henitai/cli/run_command.rb +36 -3
- data/lib/henitai/cli/run_options.rb +108 -0
- data/lib/henitai/cli.rb +12 -4
- data/lib/henitai/composite_progress_reporter.rb +42 -0
- data/lib/henitai/configuration.rb +41 -9
- data/lib/henitai/configuration_validator/rules.rb +18 -0
- data/lib/henitai/configuration_validator/scalars.rb +46 -0
- data/lib/henitai/configuration_validator.rb +8 -1
- data/lib/henitai/coverage_bootstrapper.rb +54 -5
- data/lib/henitai/coverage_formatter.rb +5 -1
- data/lib/henitai/coverage_report_reader.rb +28 -5
- data/lib/henitai/execution_engine/env_scope.rb +67 -0
- data/lib/henitai/execution_engine.rb +111 -50
- data/lib/henitai/generated_artifacts.rb +58 -0
- data/lib/henitai/incremental_filter.rb +100 -0
- data/lib/henitai/integration/child_debug_support.rb +6 -2
- data/lib/henitai/integration/coverage_suppression.rb +9 -0
- data/lib/henitai/integration/minitest.rb +11 -43
- data/lib/henitai/integration/minitest_load_path.rb +14 -0
- data/lib/henitai/integration/minitest_suite_command.rb +17 -0
- data/lib/henitai/integration/minitest_test_runner.rb +39 -0
- data/lib/henitai/integration/rails_environment_preloader.rb +14 -0
- data/lib/henitai/integration/rspec_child_runner.rb +3 -3
- data/lib/henitai/integration/rspec_test_selection.rb +3 -0
- data/lib/henitai/integration/scenario_log_support.rb +64 -20
- data/lib/henitai/minitest_coverage_reporter.rb +4 -1
- data/lib/henitai/mutant/activator.rb +14 -0
- data/lib/henitai/mutant.rb +13 -6
- data/lib/henitai/mutant_history_store/sql.rb +21 -3
- data/lib/henitai/mutant_history_store/verdict_cache.rb +84 -0
- data/lib/henitai/mutant_history_store.rb +62 -12
- data/lib/henitai/mutant_identity.rb +33 -2
- data/lib/henitai/mutation_skip_directives.rb +227 -0
- data/lib/henitai/operator.rb +3 -1
- data/lib/henitai/operators/equality_identity_operator.rb +51 -0
- data/lib/henitai/operators/equality_operator.rb +8 -3
- data/lib/henitai/operators.rb +1 -0
- data/lib/henitai/per_test_coverage.rb +66 -0
- data/lib/henitai/per_test_coverage_collector.rb +20 -5
- data/lib/henitai/per_test_coverage_selector.rb +11 -33
- data/lib/henitai/reporter/dashboard_metadata_provider.rb +113 -0
- data/lib/henitai/reporter.rb +238 -117
- data/lib/henitai/reports_directory_lock.rb +76 -0
- data/lib/henitai/result.rb +72 -9
- data/lib/henitai/runner.rb +82 -40
- data/lib/henitai/scenario_execution_result.rb +12 -0
- data/lib/henitai/slot_scheduler/draining.rb +21 -15
- data/lib/henitai/slot_scheduler.rb +73 -15
- data/lib/henitai/static_filter.rb +16 -6
- data/lib/henitai/survivor_rerun_strategy.rb +1 -1
- data/lib/henitai/survivor_test_filter.rb +1 -1
- data/lib/henitai/test_prioritizer.rb +28 -2
- data/lib/henitai/timeout_calibrator.rb +44 -0
- data/lib/henitai/verdict_fingerprint.rb +155 -0
- data/lib/henitai/version.rb +1 -1
- data/lib/henitai.rb +14 -1
- data/sig/henitai.rbs +230 -25
- metadata +22 -3
- data/lib/henitai/parallel_execution_runner.rb +0 -153
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "coverage_report_reader"
|
|
4
|
+
require_relative "mutation_skip_directives"
|
|
4
5
|
|
|
5
6
|
module Henitai
|
|
6
7
|
# Applies static, pre-execution filtering to generated mutants.
|
|
@@ -8,8 +9,10 @@ module Henitai
|
|
|
8
9
|
DEFAULT_COVERAGE_REPORT_PATH = CoverageReportReader::DEFAULT_COVERAGE_REPORT_PATH
|
|
9
10
|
DEFAULT_PER_TEST_COVERAGE_REPORT_PATH = CoverageReportReader::DEFAULT_PER_TEST_COVERAGE_REPORT_PATH
|
|
10
11
|
|
|
11
|
-
def initialize(coverage_report_reader: CoverageReportReader.new
|
|
12
|
+
def initialize(coverage_report_reader: CoverageReportReader.new,
|
|
13
|
+
skip_directives: MutationSkipDirectives.new)
|
|
12
14
|
@coverage_report_reader = coverage_report_reader
|
|
15
|
+
@skip_directives = skip_directives
|
|
13
16
|
end
|
|
14
17
|
|
|
15
18
|
# This method is the gate-level filter orchestrator.
|
|
@@ -18,7 +21,7 @@ module Henitai
|
|
|
18
21
|
coverage_report_present = coverage_report_present?(config)
|
|
19
22
|
|
|
20
23
|
Array(mutants).each do |mutant|
|
|
21
|
-
next if ignored_mutant?(mutant, config)
|
|
24
|
+
next if ignored_mutant?(mutant, config) || skip_directive_mutant?(mutant)
|
|
22
25
|
|
|
23
26
|
mark_equivalent_mutant(mutant)
|
|
24
27
|
mark_no_coverage_mutant(
|
|
@@ -61,7 +64,7 @@ module Henitai
|
|
|
61
64
|
|
|
62
65
|
private
|
|
63
66
|
|
|
64
|
-
attr_reader :coverage_report_reader
|
|
67
|
+
attr_reader :coverage_report_reader, :skip_directives
|
|
65
68
|
|
|
66
69
|
def ignored?(mutant, config)
|
|
67
70
|
source = source_for(mutant)
|
|
@@ -79,6 +82,15 @@ module Henitai
|
|
|
79
82
|
true
|
|
80
83
|
end
|
|
81
84
|
|
|
85
|
+
def skip_directive_mutant?(mutant)
|
|
86
|
+
directive = skip_directives.directive_for(mutant)
|
|
87
|
+
return false unless directive
|
|
88
|
+
|
|
89
|
+
mutant.status = :ignored
|
|
90
|
+
mutant.ignore_reason = directive.reason if mutant.respond_to?(:ignore_reason=)
|
|
91
|
+
true
|
|
92
|
+
end
|
|
93
|
+
|
|
82
94
|
def mark_equivalent_mutant(mutant)
|
|
83
95
|
return unless mutant.pending?
|
|
84
96
|
|
|
@@ -96,9 +108,7 @@ module Henitai
|
|
|
96
108
|
def covered?(mutant, coverage_lines)
|
|
97
109
|
file = normalize_path(mutant.location[:file])
|
|
98
110
|
covered = Array(coverage_lines[file])
|
|
99
|
-
(mutant.location[:start_line]..mutant.location[:end_line]).
|
|
100
|
-
covered.include?(line)
|
|
101
|
-
end
|
|
111
|
+
covered.any? { |line| (mutant.location[:start_line]..mutant.location[:end_line]).cover?(line) }
|
|
102
112
|
end
|
|
103
113
|
|
|
104
114
|
def source_for(mutant)
|
|
@@ -137,7 +137,7 @@ module Henitai
|
|
|
137
137
|
split[:stable] + split[:pending]
|
|
138
138
|
end
|
|
139
139
|
|
|
140
|
-
def test_filter(loaded, dirty_source_files:
|
|
140
|
+
def test_filter(loaded, dirty_source_files:)
|
|
141
141
|
SurvivorTestFilter.new(
|
|
142
142
|
coverage_map: loaded.coverage_map,
|
|
143
143
|
git_sha: loaded.git_sha,
|
|
@@ -57,7 +57,7 @@ module Henitai
|
|
|
57
57
|
covering = @coverage_map[mutant.stable_id]
|
|
58
58
|
return false if covering.nil? || covering.empty?
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
!changed.intersect?(covering)
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
# Returns a Set of changed test file paths, or nil on any git error
|
|
@@ -2,15 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|
module Henitai
|
|
4
4
|
# Orders test files so previously effective tests run first.
|
|
5
|
+
#
|
|
6
|
+
# Primary key: kill-history count (a test that killed neighbouring mutants
|
|
7
|
+
# probably kills this one). Tiebreaker: measured per-test-file runtime,
|
|
8
|
+
# ascending, so the first kill costs as little wall-clock as possible.
|
|
9
|
+
# Untimed tests sort after timed ones by original inventory order; with no
|
|
10
|
+
# timing source at all the ordering is exactly the historical behavior.
|
|
5
11
|
class TestPrioritizer
|
|
12
|
+
# @param timing_source [#call, nil] returns a Hash of test file path to
|
|
13
|
+
# wall-clock seconds; resolved lazily on first sort.
|
|
14
|
+
def initialize(timing_source: nil)
|
|
15
|
+
@timing_source = timing_source
|
|
16
|
+
end
|
|
17
|
+
|
|
6
18
|
def sort(tests, _mutant, history)
|
|
7
19
|
Array(tests).each_with_index.sort_by do |test, index|
|
|
8
|
-
[-history_count(history, test), index]
|
|
20
|
+
[-history_count(history, test), runtime(test), index]
|
|
9
21
|
end.map(&:first)
|
|
10
22
|
end
|
|
11
23
|
|
|
12
24
|
private
|
|
13
25
|
|
|
26
|
+
def runtime(test)
|
|
27
|
+
durations = timing_durations
|
|
28
|
+
history_key_candidates(test).each do |key|
|
|
29
|
+
value = durations[key]
|
|
30
|
+
return value.to_f unless value.nil?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Float::INFINITY
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def timing_durations
|
|
37
|
+
@timing_durations ||= @timing_source&.call || {}
|
|
38
|
+
end
|
|
39
|
+
|
|
14
40
|
def history_count(history, test)
|
|
15
41
|
return 0 unless history.respond_to?(:fetch)
|
|
16
42
|
|
|
@@ -45,7 +71,7 @@ module Henitai
|
|
|
45
71
|
|
|
46
72
|
def relative_history_key(path)
|
|
47
73
|
pathname = Pathname.new(path)
|
|
48
|
-
return unless pathname.absolute?
|
|
74
|
+
return path unless pathname.absolute?
|
|
49
75
|
|
|
50
76
|
pathname.relative_path_from(Pathname.pwd).to_s
|
|
51
77
|
rescue StandardError
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Henitai
|
|
4
|
+
# Derives a per-mutant timeout from measured per-test-file durations.
|
|
5
|
+
#
|
|
6
|
+
# The calibrated value is `multiplier × sum(durations of the selected test
|
|
7
|
+
# files)`, clamped to a floor so a near-instant baseline doesn't flag normal
|
|
8
|
+
# jitter as a timeout. Returns nil — caller falls back to the static
|
|
9
|
+
# default — when any selected test lacks timing data, so a partially
|
|
10
|
+
# measured run is treated as uncalibratable rather than under-estimated.
|
|
11
|
+
class TimeoutCalibrator
|
|
12
|
+
FLOOR_SECONDS = 2.0
|
|
13
|
+
|
|
14
|
+
# @param timing_source [#call] returns a Hash of test file path to
|
|
15
|
+
# wall-clock seconds; resolved lazily on first use.
|
|
16
|
+
# @param multiplier [Numeric]
|
|
17
|
+
def initialize(timing_source:, multiplier:)
|
|
18
|
+
@timing_source = timing_source
|
|
19
|
+
@multiplier = multiplier
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @param test_files [Array<String>]
|
|
23
|
+
# @return [Float, nil]
|
|
24
|
+
def timeout_for(test_files)
|
|
25
|
+
files = Array(test_files)
|
|
26
|
+
return nil if files.empty? || durations.empty?
|
|
27
|
+
|
|
28
|
+
baselines = files.map { |file| durations[normalize(file)] }
|
|
29
|
+
return nil if baselines.any?(&:nil?)
|
|
30
|
+
|
|
31
|
+
[@multiplier * baselines.sum, FLOOR_SECONDS].max
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def durations
|
|
37
|
+
@durations ||= (@timing_source.call || {}).transform_keys { |key| normalize(key) }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def normalize(path)
|
|
41
|
+
File.expand_path(path.to_s)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "digest"
|
|
4
|
+
require "find"
|
|
5
|
+
require "json"
|
|
6
|
+
|
|
7
|
+
require_relative "generated_artifacts"
|
|
8
|
+
|
|
9
|
+
module Henitai
|
|
10
|
+
# Content fingerprints that decide whether a stored verdict is still
|
|
11
|
+
# trustworthy: the subject's source (method body) and the covering test
|
|
12
|
+
# files must both be byte-identical to what was recorded. Survived verdicts
|
|
13
|
+
# additionally record the full-map covering-set membership plus a run-level
|
|
14
|
+
# dependency fingerprint (ADR-11). Any read failure yields nil / a mismatch
|
|
15
|
+
# — conservative, never reuse on doubt.
|
|
16
|
+
module VerdictFingerprint
|
|
17
|
+
# Files that influence test behavior but never appear in any covering
|
|
18
|
+
# set: helpers, support code, fixtures/factories, lockfile and tool
|
|
19
|
+
# config. One combined hash over all of them gates survivor reuse.
|
|
20
|
+
DEPENDENCY_GLOBS = %w[
|
|
21
|
+
spec/spec_helper.rb
|
|
22
|
+
spec/rails_helper.rb
|
|
23
|
+
spec/support/**/*
|
|
24
|
+
spec/fixtures/**/*
|
|
25
|
+
spec/factories/**/*
|
|
26
|
+
test/test_helper.rb
|
|
27
|
+
test/support/**/*
|
|
28
|
+
test/fixtures/**/*
|
|
29
|
+
test/factories/**/*
|
|
30
|
+
Gemfile.lock
|
|
31
|
+
.henitai.yml
|
|
32
|
+
.rspec
|
|
33
|
+
].freeze
|
|
34
|
+
|
|
35
|
+
module_function
|
|
36
|
+
|
|
37
|
+
# SHA256 of the subject's source lines. nil when the subject has no
|
|
38
|
+
# source range or the file cannot be read.
|
|
39
|
+
def subject_source_hash(mutant)
|
|
40
|
+
subject = mutant.subject
|
|
41
|
+
return nil unless subject.respond_to?(:source_file) && subject.respond_to?(:source_range)
|
|
42
|
+
|
|
43
|
+
range = subject.source_range
|
|
44
|
+
return nil unless range
|
|
45
|
+
|
|
46
|
+
lines = File.readlines(subject.source_file)
|
|
47
|
+
Digest::SHA256.hexdigest(lines[(range.begin - 1)..(range.end - 1)].to_a.join)
|
|
48
|
+
rescue SystemCallError, IOError
|
|
49
|
+
nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# JSON fingerprint of the covering test files: their sorted paths plus a
|
|
53
|
+
# combined content hash. nil when no tests are known or any is unreadable.
|
|
54
|
+
def tests_fingerprint(test_files)
|
|
55
|
+
paths = Array(test_files).map(&:to_s).sort
|
|
56
|
+
return nil if paths.empty?
|
|
57
|
+
|
|
58
|
+
sha = combined_content_sha(paths)
|
|
59
|
+
return nil unless sha
|
|
60
|
+
|
|
61
|
+
JSON.generate("paths" => paths, "sha" => sha)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# True when every recorded test file still exists with identical content.
|
|
65
|
+
def tests_fingerprint_current?(fingerprint_json)
|
|
66
|
+
return false if fingerprint_json.nil?
|
|
67
|
+
|
|
68
|
+
fingerprint = JSON.parse(fingerprint_json)
|
|
69
|
+
combined_content_sha(fingerprint.fetch("paths")) == fingerprint.fetch("sha")
|
|
70
|
+
rescue StandardError
|
|
71
|
+
false
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Existing dependency files resolved against +root+, sorted. Shared by
|
|
75
|
+
# the fingerprint below and by the coverage freshness watch — a stale
|
|
76
|
+
# per-test map after a dependency edit would let the test selector omit
|
|
77
|
+
# a newly covering test. Uses Find with pruning instead of Dir.glob so
|
|
78
|
+
# generated subtrees (thousands of mutation-log files under fixture
|
|
79
|
+
# projects) are never walked at all.
|
|
80
|
+
def dependency_files(root = Dir.pwd)
|
|
81
|
+
files = DEPENDENCY_GLOBS.flat_map do |pattern|
|
|
82
|
+
base = File.join(root, pattern)
|
|
83
|
+
pattern.include?("*") ? pruned_tree_files(File.dirname(base.sub("/**/*", "/x"))) : [base]
|
|
84
|
+
end
|
|
85
|
+
files.select { |path| File.file?(path) }.uniq.sort
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def pruned_tree_files(dir)
|
|
89
|
+
return [] unless File.directory?(dir)
|
|
90
|
+
|
|
91
|
+
collected = [] # : Array[String]
|
|
92
|
+
Find.find(dir) do |path|
|
|
93
|
+
Find.prune if File.directory?(path) && GeneratedArtifacts.generated_dir?(path)
|
|
94
|
+
collected << path if File.file?(path)
|
|
95
|
+
end
|
|
96
|
+
collected
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Run-level combined SHA over the dependency file set. Missing files are
|
|
100
|
+
# simply excluded (not an error); a read failure yields nil — no reuse.
|
|
101
|
+
def dependency_fingerprint(root = Dir.pwd) = combined_content_sha(dependency_files(root))
|
|
102
|
+
|
|
103
|
+
# Fingerprint recorded for a Survived verdict: the sorted full-map
|
|
104
|
+
# intersection set (paths + combined content sha) plus the run-level
|
|
105
|
+
# dependency sha. nil when any input is unavailable — the verdict is
|
|
106
|
+
# then never reusable.
|
|
107
|
+
def survivor_tests_fingerprint(test_files, dependency_sha:)
|
|
108
|
+
return nil if dependency_sha.nil?
|
|
109
|
+
|
|
110
|
+
paths = Array(test_files).map(&:to_s).sort
|
|
111
|
+
return nil if paths.empty?
|
|
112
|
+
|
|
113
|
+
sha = combined_content_sha(paths)
|
|
114
|
+
return nil unless sha
|
|
115
|
+
|
|
116
|
+
JSON.generate("paths" => paths, "sha" => sha, "dependencies" => dependency_sha)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# True when the recorded covering set still equals the live one in
|
|
120
|
+
# membership AND content, and the dependency fingerprint is unchanged.
|
|
121
|
+
# Any parse/read failure or missing field resolves to stale.
|
|
122
|
+
def survivor_fingerprint_current?(fingerprint_json, live_paths:, dependency_sha:)
|
|
123
|
+
return false if fingerprint_json.nil? || dependency_sha.nil?
|
|
124
|
+
|
|
125
|
+
survivor_fingerprint_matches?(JSON.parse(fingerprint_json), live_paths, dependency_sha)
|
|
126
|
+
rescue StandardError
|
|
127
|
+
false
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def survivor_fingerprint_matches?(fingerprint, live_paths, dependency_sha)
|
|
131
|
+
recorded_paths = fingerprint.fetch("paths")
|
|
132
|
+
return false if recorded_paths.empty?
|
|
133
|
+
|
|
134
|
+
recorded_paths == Array(live_paths).map(&:to_s).sort &&
|
|
135
|
+
fingerprint.fetch("dependencies") == dependency_sha &&
|
|
136
|
+
combined_content_sha(recorded_paths) == fingerprint.fetch("sha")
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def combined_content_sha(paths)
|
|
140
|
+
digest = Digest::SHA256.new
|
|
141
|
+
paths.each do |path|
|
|
142
|
+
content = File.read(path)
|
|
143
|
+
digest.update(path.bytesize.to_s)
|
|
144
|
+
digest.update(":")
|
|
145
|
+
digest.update(path)
|
|
146
|
+
digest.update(content.bytesize.to_s)
|
|
147
|
+
digest.update(":")
|
|
148
|
+
digest.update(content)
|
|
149
|
+
end
|
|
150
|
+
digest.hexdigest
|
|
151
|
+
rescue StandardError
|
|
152
|
+
nil
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
data/lib/henitai/version.rb
CHANGED
data/lib/henitai.rb
CHANGED
|
@@ -20,9 +20,13 @@ module Henitai
|
|
|
20
20
|
# Raised when coverage data cannot be bootstrapped or validated.
|
|
21
21
|
class CoverageError < StandardError; end
|
|
22
22
|
|
|
23
|
+
# Raised when another process is using the configured reports directory.
|
|
24
|
+
class ConcurrentRunError < StandardError; end
|
|
25
|
+
|
|
23
26
|
autoload :Configuration, "henitai/configuration"
|
|
24
27
|
autoload :CoverageBootstrapper, "henitai/coverage_bootstrapper"
|
|
25
28
|
autoload :CoverageReportReader, "henitai/coverage_report_reader"
|
|
29
|
+
autoload :PerTestCoverage, "henitai/per_test_coverage"
|
|
26
30
|
autoload :PerTestCoverageSelector, "henitai/per_test_coverage_selector"
|
|
27
31
|
autoload :Subject, "henitai/subject"
|
|
28
32
|
autoload :Mutant, "henitai/mutant"
|
|
@@ -31,15 +35,24 @@ module Henitai
|
|
|
31
35
|
autoload :Operators, "henitai/operators"
|
|
32
36
|
autoload :SourceParser, "henitai/source_parser"
|
|
33
37
|
autoload :SubjectResolver, "henitai/subject_resolver"
|
|
38
|
+
autoload :GeneratedArtifacts, "henitai/generated_artifacts"
|
|
34
39
|
autoload :GitDiffAnalyzer, "henitai/git_diff_analyzer"
|
|
35
40
|
autoload :GitDiffError, "henitai/git_diff_analyzer"
|
|
36
41
|
autoload :MutantGenerator, "henitai/mutant_generator"
|
|
37
42
|
autoload :MutantHistoryStore, "henitai/mutant_history_store"
|
|
43
|
+
autoload :MutationSkipDirectives, "henitai/mutation_skip_directives"
|
|
38
44
|
autoload :AridNodeFilter, "henitai/arid_node_filter"
|
|
39
45
|
autoload :AvailableCpuCount, "henitai/available_cpu_count"
|
|
40
46
|
autoload :EquivalenceDetector, "henitai/equivalence_detector"
|
|
41
47
|
autoload :StaticFilter, "henitai/static_filter"
|
|
48
|
+
autoload :IncrementalFilter, "henitai/incremental_filter"
|
|
49
|
+
autoload :VerdictFingerprint, "henitai/verdict_fingerprint"
|
|
42
50
|
autoload :StillbornFilter, "henitai/stillborn_filter"
|
|
51
|
+
autoload :CanonicalReportMerger, "henitai/canonical_report_merger"
|
|
52
|
+
autoload :CanonicalReportWriter, "henitai/canonical_report_writer"
|
|
53
|
+
autoload :CheckpointReporter, "henitai/checkpoint_reporter"
|
|
54
|
+
autoload :CompositeProgressReporter, "henitai/composite_progress_reporter"
|
|
55
|
+
autoload :ReportsDirectoryLock, "henitai/reports_directory_lock"
|
|
43
56
|
autoload :SurvivorLoader, "henitai/survivor_loader"
|
|
44
57
|
autoload :SurvivorSelector, "henitai/survivor_selector"
|
|
45
58
|
autoload :SurvivorTestFilter, "henitai/survivor_test_filter"
|
|
@@ -52,8 +65,8 @@ module Henitai
|
|
|
52
65
|
autoload :SyntaxValidator, "henitai/syntax_validator"
|
|
53
66
|
autoload :SamplingStrategy, "henitai/sampling_strategy"
|
|
54
67
|
autoload :TestPrioritizer, "henitai/test_prioritizer"
|
|
68
|
+
autoload :TimeoutCalibrator, "henitai/timeout_calibrator"
|
|
55
69
|
autoload :ExecutionEngine, "henitai/execution_engine"
|
|
56
|
-
autoload :ParallelExecutionRunner, "henitai/parallel_execution_runner"
|
|
57
70
|
autoload :ProcessWorkerRunner, "henitai/process_worker_runner"
|
|
58
71
|
autoload :SlotScheduler, "henitai/slot_scheduler"
|
|
59
72
|
autoload :ProcessWakeup, "henitai/process_wakeup"
|