Add trim report output
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"gitea.maximumdirect.net/eric/seriatim/internal/config"
|
||||
"gitea.maximumdirect.net/eric/seriatim/internal/report"
|
||||
"gitea.maximumdirect.net/eric/seriatim/schema"
|
||||
)
|
||||
|
||||
@@ -221,6 +222,125 @@ func TestTrimRejectsNonSeriatimInputArtifacts(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrimReportFileContainsAuditFields(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
input := writeTrimFullFixture(t, dir, "input.json")
|
||||
output := filepath.Join(dir, "trimmed.json")
|
||||
reportPath := filepath.Join(dir, "trim-report.json")
|
||||
|
||||
err := executeTrim(
|
||||
"--input-file", input,
|
||||
"--output-file", output,
|
||||
"--report-file", reportPath,
|
||||
"--remove", "4,2",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("trim failed: %v", err)
|
||||
}
|
||||
|
||||
var rpt report.Report
|
||||
readJSON(t, reportPath, &rpt)
|
||||
if len(rpt.Events) == 0 {
|
||||
t.Fatal("expected report events")
|
||||
}
|
||||
if !hasReportEvent(rpt, "trim", "trim", "trimmed 4 input segment(s) into 2 output segment(s) with mode=remove") {
|
||||
t.Fatal("expected trim summary event")
|
||||
}
|
||||
if !hasReportEvent(rpt, "trim", "validate-output", "validated 2 output segment(s)") {
|
||||
t.Fatal("expected validation event")
|
||||
}
|
||||
|
||||
audit := extractTrimAuditEvent(t, rpt)
|
||||
if audit.Operation != "trim" {
|
||||
t.Fatalf("operation = %q, want trim", audit.Operation)
|
||||
}
|
||||
if audit.InputFile != input {
|
||||
t.Fatalf("input_file = %q, want %q", audit.InputFile, input)
|
||||
}
|
||||
if audit.OutputFile != output {
|
||||
t.Fatalf("output_file = %q, want %q", audit.OutputFile, output)
|
||||
}
|
||||
if audit.InputSchema != config.OutputSchemaFull || audit.OutputSchema != config.OutputSchemaFull {
|
||||
t.Fatalf("schemas = %q -> %q, want full -> full", audit.InputSchema, audit.OutputSchema)
|
||||
}
|
||||
if audit.Mode != "remove" {
|
||||
t.Fatalf("mode = %q, want remove", audit.Mode)
|
||||
}
|
||||
if audit.Selector != "4,2" {
|
||||
t.Fatalf("selector = %q, want %q", audit.Selector, "4,2")
|
||||
}
|
||||
assertIntSliceEqual(t, audit.SelectedIDs, []int{2, 4})
|
||||
if audit.AllowEmpty {
|
||||
t.Fatal("allow_empty should be false")
|
||||
}
|
||||
if audit.InputSegmentCount != 4 || audit.RetainedSegmentCount != 2 || audit.RemovedSegmentCount != 2 {
|
||||
t.Fatalf("counts = input:%d retained:%d removed:%d, want 4/2/2", audit.InputSegmentCount, audit.RetainedSegmentCount, audit.RemovedSegmentCount)
|
||||
}
|
||||
assertIntSliceEqual(t, audit.RemovedInputIDs, []int{2, 4})
|
||||
if len(audit.OldToNewIDMapping) != 2 {
|
||||
t.Fatalf("mapping length = %d, want 2", len(audit.OldToNewIDMapping))
|
||||
}
|
||||
if audit.OldToNewIDMapping[0].OldID != 1 || audit.OldToNewIDMapping[0].NewID != 1 {
|
||||
t.Fatalf("mapping[0] = %#v, want old_id=1 new_id=1", audit.OldToNewIDMapping[0])
|
||||
}
|
||||
if audit.OldToNewIDMapping[1].OldID != 3 || audit.OldToNewIDMapping[1].NewID != 2 {
|
||||
t.Fatalf("mapping[1] = %#v, want old_id=3 new_id=2", audit.OldToNewIDMapping[1])
|
||||
}
|
||||
if !audit.OverlapGroupsRecomputed {
|
||||
t.Fatal("expected overlap_groups_recomputed=true for full schema trim")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrimReportOldToNewMappingIsDeterministicSorted(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
input := writeTrimFullFixture(t, dir, "input.json")
|
||||
output := filepath.Join(dir, "trimmed.json")
|
||||
reportPath := filepath.Join(dir, "trim-report.json")
|
||||
|
||||
err := executeTrim(
|
||||
"--input-file", input,
|
||||
"--output-file", output,
|
||||
"--report-file", reportPath,
|
||||
"--keep", "4,1,3",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("trim failed: %v", err)
|
||||
}
|
||||
|
||||
var rpt report.Report
|
||||
readJSON(t, reportPath, &rpt)
|
||||
audit := extractTrimAuditEvent(t, rpt)
|
||||
if len(audit.OldToNewIDMapping) != 3 {
|
||||
t.Fatalf("mapping length = %d, want 3", len(audit.OldToNewIDMapping))
|
||||
}
|
||||
for index, expectedOld := range []int{1, 3, 4} {
|
||||
if audit.OldToNewIDMapping[index].OldID != expectedOld {
|
||||
t.Fatalf("mapping[%d].old_id = %d, want %d", index, audit.OldToNewIDMapping[index].OldID, expectedOld)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrimNoReportFileWhenOmitted(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
input := writeTrimFullFixture(t, dir, "input.json")
|
||||
output := filepath.Join(dir, "trimmed.json")
|
||||
reportPath := filepath.Join(dir, "trim-report.json")
|
||||
|
||||
err := executeTrim(
|
||||
"--input-file", input,
|
||||
"--output-file", output,
|
||||
"--keep", "1",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("trim failed: %v", err)
|
||||
}
|
||||
|
||||
_, statErr := os.Stat(reportPath)
|
||||
if !os.IsNotExist(statErr) {
|
||||
t.Fatalf("expected no report file at %q, got err=%v", reportPath, statErr)
|
||||
}
|
||||
}
|
||||
|
||||
func executeTrim(args ...string) error {
|
||||
cmd := NewRootCommand()
|
||||
cmd.SetArgs(append([]string{"trim"}, args...))
|
||||
@@ -299,3 +419,31 @@ func assertSequentialIDs(t *testing.T, ids []int) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func extractTrimAuditEvent(t *testing.T, rpt report.Report) trimAuditReport {
|
||||
t.Helper()
|
||||
|
||||
for _, event := range rpt.Events {
|
||||
if event.Stage == "trim" && event.Module == "trim-audit" {
|
||||
var audit trimAuditReport
|
||||
if err := json.Unmarshal([]byte(event.Message), &audit); err != nil {
|
||||
t.Fatalf("decode trim audit event: %v", err)
|
||||
}
|
||||
return audit
|
||||
}
|
||||
}
|
||||
t.Fatal("missing trim-audit event")
|
||||
return trimAuditReport{}
|
||||
}
|
||||
|
||||
func assertIntSliceEqual(t *testing.T, got []int, want []int) {
|
||||
t.Helper()
|
||||
if len(got) != len(want) {
|
||||
t.Fatalf("slice length = %d, want %d", len(got), len(want))
|
||||
}
|
||||
for index := range got {
|
||||
if got[index] != want[index] {
|
||||
t.Fatalf("slice[%d] = %d, want %d (full got=%v, want=%v)", index, got[index], want[index], got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user