Add minimal process reports

This commit is contained in:
2026-05-10 23:30:46 +00:00
parent 2cf2d390da
commit 08b7531149
3 changed files with 231 additions and 0 deletions

View File

@@ -204,6 +204,143 @@ func TestRunProcessOutputToStdout(t *testing.T) {
assertJSONSemanticallyEqual(t, inputBytes, stdout.Bytes())
}
func TestRunProcessReportJSONSuccess(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
transcriptPath := fixturePath("tiny_transcript.json")
glossaryPath := fixturePath("tiny_glossary.yaml")
outputPath := filepath.Join(t.TempDir(), "corrected.json")
reportPath := filepath.Join(t.TempDir(), "report.json")
exitCode := Run([]string{
"process",
transcriptPath,
"--glossary",
glossaryPath,
"--output",
outputPath,
"--report-json",
reportPath,
}, &stdout, &stderr)
if exitCode != 0 {
t.Fatalf("expected exit code 0, got %d with stderr %q", exitCode, stderr.String())
}
if stdout.Len() != 0 {
t.Fatalf("expected empty stdout when --output is used, got %q", stdout.String())
}
report := readProcessReport(t, reportPath)
if report.Status != "success" {
t.Fatalf("expected success report status, got %q", report.Status)
}
if report.Operation != "process" {
t.Fatalf("expected operation process, got %q", report.Operation)
}
if report.TranscriptPath != transcriptPath {
t.Fatalf("unexpected transcript path in report: %q", report.TranscriptPath)
}
if report.GlossaryPath != glossaryPath {
t.Fatalf("unexpected glossary path in report: %q", report.GlossaryPath)
}
if report.OutputPath != outputPath {
t.Fatalf("unexpected output path in report: %q", report.OutputPath)
}
if len(report.Modules) == 0 {
t.Fatalf("expected configured module sequence in report")
}
if report.StartedAt == "" || report.CompletedAt == "" {
t.Fatalf("expected started_at and completed_at timestamps in report")
}
if report.ErrorMessage != "" {
t.Fatalf("did not expect error message in success report, got %q", report.ErrorMessage)
}
}
func TestRunProcessReportJSONNoStdoutPollution(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
transcriptPath := fixturePath("tiny_transcript.json")
glossaryPath := fixturePath("tiny_glossary.yaml")
reportPath := filepath.Join(t.TempDir(), "report.json")
exitCode := Run([]string{
"process",
transcriptPath,
"--glossary",
glossaryPath,
"--report-json",
reportPath,
}, &stdout, &stderr)
if exitCode != 0 {
t.Fatalf("expected exit code 0, got %d with stderr %q", exitCode, stderr.String())
}
assertJSONSemanticallyEqual(t, readFile(t, transcriptPath), stdout.Bytes())
reportBytes := readFile(t, reportPath)
if bytes.Contains(stdout.Bytes(), reportBytes) {
t.Fatalf("stdout was polluted with report JSON")
}
}
func TestRunProcessReportJSONRedactsSecrets(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
secretPrimary := "top-secret-primary-key"
secretValidation := "top-secret-validation-key"
t.Setenv("AUDITA_LLM_API_KEY", secretPrimary)
t.Setenv("AUDITA_VALIDATION_LLM_API_KEY", secretValidation)
reportPath := filepath.Join(t.TempDir(), "report.json")
exitCode := Run([]string{
"process",
fixturePath("tiny_transcript.json"),
"--glossary",
fixturePath("tiny_glossary.yaml"),
"--report-json",
reportPath,
}, &stdout, &stderr)
if exitCode != 0 {
t.Fatalf("expected exit code 0, got %d with stderr %q", exitCode, stderr.String())
}
reportBytes := readFile(t, reportPath)
if strings.Contains(string(reportBytes), secretPrimary) || strings.Contains(string(reportBytes), secretValidation) {
t.Fatalf("report JSON leaked API key material: %q", string(reportBytes))
}
}
func TestRunProcessReportJSONBestEffortOnFailure(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
reportPath := filepath.Join(t.TempDir(), "report.json")
exitCode := Run([]string{
"process",
fixturePath("malformed_transcript.json"),
"--glossary",
fixturePath("tiny_glossary.yaml"),
"--report-json",
reportPath,
}, &stdout, &stderr)
if exitCode == 0 {
t.Fatalf("expected nonzero exit code for malformed transcript")
}
report := readProcessReport(t, reportPath)
if report.Status != "failed" {
t.Fatalf("expected failed report status, got %q", report.Status)
}
if report.ErrorMessage == "" {
t.Fatalf("expected error message in failed report")
}
if !strings.Contains(report.ErrorMessage, "not valid JSON") {
t.Fatalf("expected malformed JSON failure in report error, got %q", report.ErrorMessage)
}
}
func TestRunProcessCLIOverridesEnvironment(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
@@ -281,3 +418,25 @@ func assertJSONSemanticallyEqual(t *testing.T, expected []byte, actual []byte) {
t.Fatalf("JSON content mismatch: expected %q got %q", string(expected), string(actual))
}
}
type minimalProcessReport struct {
Status string `json:"status"`
Operation string `json:"operation"`
TranscriptPath string `json:"transcript_path"`
GlossaryPath string `json:"glossary_path"`
OutputPath string `json:"output_path"`
Modules []string `json:"modules"`
StartedAt string `json:"started_at"`
CompletedAt string `json:"completed_at"`
ErrorMessage string `json:"error_message"`
}
func readProcessReport(t *testing.T, path string) minimalProcessReport {
t.Helper()
raw := readFile(t, path)
var report minimalProcessReport
if err := json.Unmarshal(raw, &report); err != nil {
t.Fatalf("failed to unmarshal process report JSON: %v (raw: %q)", err, string(raw))
}
return report
}