henitai 0.2.0 → 0.2.1
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 +26 -1
- data/README.md +15 -3
- data/assets/schema/henitai.schema.json +6 -0
- data/lib/henitai/cli/clean_command.rb +48 -0
- data/lib/henitai/cli/command_support.rb +51 -0
- data/lib/henitai/cli/init_command.rb +64 -0
- data/lib/henitai/cli/operator_command.rb +95 -0
- data/lib/henitai/cli/options.rb +120 -0
- data/lib/henitai/cli/run_command.rb +103 -0
- data/lib/henitai/cli.rb +16 -404
- data/lib/henitai/configuration.rb +2 -1
- data/lib/henitai/configuration_validator/rules.rb +143 -0
- data/lib/henitai/configuration_validator/scalars.rb +123 -0
- data/lib/henitai/configuration_validator.rb +12 -239
- data/lib/henitai/eager_load.rb +36 -5
- data/lib/henitai/execution_engine.rb +4 -3
- data/lib/henitai/integration/base.rb +171 -0
- data/lib/henitai/integration/child_debug_support.rb +115 -0
- data/lib/henitai/integration/child_runtime_control.rb +50 -0
- data/lib/henitai/integration/coverage_suppression.rb +43 -0
- data/lib/henitai/integration/minitest.rb +133 -0
- data/lib/henitai/integration/mutant_run_support.rb +77 -0
- data/lib/henitai/integration/rspec_child_runner.rb +61 -0
- data/lib/henitai/integration/rspec_test_selection.rb +135 -0
- data/lib/henitai/integration/scenario_log_support.rb +116 -0
- data/lib/henitai/integration.rb +22 -846
- data/lib/henitai/mutant/activator.rb +1 -79
- data/lib/henitai/mutant/parameter_source.rb +98 -0
- data/lib/henitai/mutant.rb +1 -0
- data/lib/henitai/mutant_history_store/sql.rb +72 -0
- data/lib/henitai/mutant_history_store.rb +5 -69
- data/lib/henitai/per_test_coverage_collector.rb +3 -1
- data/lib/henitai/process_worker_runner.rb +48 -334
- data/lib/henitai/reporter.rb +20 -8
- data/lib/henitai/result.rb +17 -15
- data/lib/henitai/runner.rb +59 -182
- data/lib/henitai/slot_scheduler/draining.rb +140 -0
- data/lib/henitai/slot_scheduler/process_control.rb +43 -0
- data/lib/henitai/slot_scheduler.rb +214 -0
- data/lib/henitai/survivor_rerun_strategy.rb +195 -0
- data/lib/henitai/unparse_helper.rb +5 -2
- data/lib/henitai/version.rb +1 -1
- data/lib/henitai.rb +2 -0
- data/sig/configuration_validator.rbs +46 -22
- data/sig/henitai.rbs +158 -73
- metadata +25 -2
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
|
|
5
|
+
module Henitai
|
|
6
|
+
module Integration
|
|
7
|
+
# Shared helpers for capturing stdout/stderr from child test processes and
|
|
8
|
+
# for reading and combining the captured log files afterwards.
|
|
9
|
+
class ScenarioLogSupport
|
|
10
|
+
def capture_child_output(log_paths)
|
|
11
|
+
output_files = open_child_output(log_paths)
|
|
12
|
+
yield
|
|
13
|
+
ensure
|
|
14
|
+
close_child_output(output_files)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def with_coverage_dir(mutant_id)
|
|
18
|
+
original_coverage_dir = ENV.fetch("HENITAI_COVERAGE_DIR", nil)
|
|
19
|
+
ENV["HENITAI_COVERAGE_DIR"] = mutation_coverage_dir(mutant_id)
|
|
20
|
+
yield
|
|
21
|
+
ensure
|
|
22
|
+
if original_coverage_dir.nil?
|
|
23
|
+
ENV.delete("HENITAI_COVERAGE_DIR")
|
|
24
|
+
else
|
|
25
|
+
ENV["HENITAI_COVERAGE_DIR"] = original_coverage_dir
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def open_child_output(log_paths)
|
|
30
|
+
FileUtils.mkdir_p(File.dirname(log_paths[:log_path]))
|
|
31
|
+
output_files = build_child_output_files(log_paths)
|
|
32
|
+
sync_child_output_files(output_files)
|
|
33
|
+
redirect_child_output(output_files)
|
|
34
|
+
output_files
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def close_child_output(output_files)
|
|
38
|
+
return unless output_files
|
|
39
|
+
|
|
40
|
+
restore_child_output(output_files)
|
|
41
|
+
close_child_output_files(output_files)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def build_child_output_files(log_paths)
|
|
45
|
+
{
|
|
46
|
+
original_stdout: stdout_stream.dup,
|
|
47
|
+
original_stderr: stderr_stream.dup,
|
|
48
|
+
stdout_file: File.new(log_paths[:stdout_path], "w"),
|
|
49
|
+
stderr_file: File.new(log_paths[:stderr_path], "w")
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def sync_child_output_files(output_files)
|
|
54
|
+
output_files[:stdout_file].sync = true
|
|
55
|
+
output_files[:stderr_file].sync = true
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def redirect_child_output(output_files)
|
|
59
|
+
reopen_child_output_stream(stdout_stream, output_files[:stdout_file])
|
|
60
|
+
reopen_child_output_stream(stderr_stream, output_files[:stderr_file])
|
|
61
|
+
$stdout = stdout_stream
|
|
62
|
+
$stderr = stderr_stream
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def restore_child_output(output_files)
|
|
66
|
+
reopen_child_output_stream(stdout_stream, output_files[:original_stdout])
|
|
67
|
+
reopen_child_output_stream(stderr_stream, output_files[:original_stderr])
|
|
68
|
+
$stdout = stdout_stream
|
|
69
|
+
$stderr = stderr_stream
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def reopen_child_output_stream(stream, original_stream)
|
|
73
|
+
stream.reopen(original_stream) if original_stream
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def close_child_output_files(output_files)
|
|
77
|
+
%i[stdout_file stderr_file original_stdout original_stderr].each do |key|
|
|
78
|
+
output_files[key]&.close
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def read_log_file(path)
|
|
83
|
+
return "" unless File.exist?(path)
|
|
84
|
+
|
|
85
|
+
File.read(path)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def write_combined_log(path, stdout, stderr)
|
|
89
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
90
|
+
File.write(path, combined_log(stdout, stderr))
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def combined_log(stdout, stderr)
|
|
94
|
+
[
|
|
95
|
+
(stdout.empty? ? nil : "stdout:\n#{stdout}"),
|
|
96
|
+
(stderr.empty? ? nil : "stderr:\n#{stderr}")
|
|
97
|
+
].compact.join("\n")
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
private
|
|
101
|
+
|
|
102
|
+
def mutation_coverage_dir(mutant_id)
|
|
103
|
+
reports_dir = ENV.fetch("HENITAI_REPORTS_DIR", "reports")
|
|
104
|
+
File.join(reports_dir, "mutation-coverage", mutant_id.to_s)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def stdout_stream
|
|
108
|
+
@stdout_stream ||= IO.for_fd(1)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def stderr_stream
|
|
112
|
+
@stderr_stream ||= IO.for_fd(2)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|