diff --git a/archive/docs/TAR-01-PRUEFPROTOKOLL.md b/archive/docs/TAR-01-PRUEFPROTOKOLL.md index 2f164c4c..86a830e8 100644 --- a/archive/docs/TAR-01-PRUEFPROTOKOLL.md +++ b/archive/docs/TAR-01-PRUEFPROTOKOLL.md @@ -15,9 +15,9 @@ Ergebnis: PASS. Alle 50 Fristen nach Migration bitgenau identisch zur Quelle (`t Test: `TestMigrateAll_ResultIndependentOfInjectedNow`. -Zwei vollständig unabhängige Migrationsläufe gegen zwei getrennte Zieldatenbanken, mit demselben Quellobjekt (`retain_until` = 2040-06-15), aber mit injiziertem `now`-Parameter, der künstlich um 73 Jahre auseinanderliegt (2026-10-14 vs. 2099-12-31). `now` fließt im Migrator ausschließlich in `Result.RanAt` (Protokoll-Metadatum) ein, nie in die Frist-Übernahme (`retention.SetRetainUntil` nimmt die Quellfrist unverändert). +Zwei Migrationsläufe gegen dieselbe Zieldatenbank, aber auf zwei voneinander unabhängigen Quellobjekten (`object_reference` `doc-clock-test-a` bzw. `doc-clock-test-b`, dieselbe Quellfrist `retain_until` = 2030-06-15), mit injiziertem `now`-Parameter, der künstlich um 73 Jahre auseinanderliegt (2026-01-01 vs. 2099-01-01). `now` fließt im Migrator ausschließlich in `Result.RanAt` (Protokoll-Metadatum) ein, nie in die Frist-Übernahme (`retention.SetRetainUntil` nimmt die Quellfrist unverändert). -Ergebnis: PASS. Beide Läufe liefern exakt dieselbe `retain_until` in der Zieldatenbank, unabhängig vom injizierten `now`. +Ergebnis: PASS. Beide (unabhängigen) Datensätze erhalten exakt dieselbe `retain_until`, unabhängig vom injizierten `now`. Gegenprobe durchgeführt: wird `now` testweise künstlich in die Fristberechnung eingebaut, schlägt der Test fehl (Vergleich `gotA.Equal(gotB)`), was belegt, dass der Test tatsächlich scharf ist; der Eingriff wurde danach wieder zurückgenommen und nicht committet. ## Prüfung 3 – Objekte ohne Quellfrist bleiben ohne Frist @@ -36,7 +36,7 @@ Migration `archive/migrations/0017_retention_objects_retain_until.{up,down}.sql` | Prüfung | Ergebnis | |---|---| | 1 – 50 Stichproben, Frist exakt identisch | PASS | -| 2 – keine Berechnung aus aktuellem Datum (zwei Läufe, unterschiedliches `now`) | PASS | +| 2 – keine Berechnung aus aktuellem Datum (zwei unabhängige Datensätze, unterschiedliches `now`) | PASS | | 3 – keine Frist ohne Quellfrist | PASS | | Bestehende `archive/internal/retention`-Tests weiterhin grün | PASS (3 PASS, 1 SKIP mangels zweiter Tenant-DSN, unverändert zum Vorzustand) | | `go vet ./...` (archive-Modul) | clean | diff --git a/archive/internal/retentionmigration/retentionmigration_test.go b/archive/internal/retentionmigration/retentionmigration_test.go index a31788e0..63d0d4f6 100644 --- a/archive/internal/retentionmigration/retentionmigration_test.go +++ b/archive/internal/retentionmigration/retentionmigration_test.go @@ -144,36 +144,37 @@ func TestMigrateAll_ObjectsWithoutSourceDeadlineStayWithoutOne(t *testing.T) { // TestMigrateAll_ResultIndependentOfInjectedNow ist Pruefung 2 // (Akzeptanzkriterium 2): zwei Migrationslaeufe mit weit auseinander -// liegenden "jetzt"-Zeitpunkten liefern IDENTISCHE retain_until-Werte - -// echter Nachweis statt Behauptung, dass now() an keiner Stelle in die -// berechnete Frist einfliesst. +// liegenden "jetzt"-Zeitpunkten, auf zwei voneinander unabhaengigen +// Datensaetzen (unterschiedliche ObjectReference, gleiche Quellfrist), +// liefern IDENTISCHE retain_until-Werte - echter Nachweis statt +// Behauptung, dass now() an keiner Stelle in die berechnete Frist +// einfliesst. Wuerde now faelschlich einfliessen, muessten sich die +// beiden Ergebnisse unterscheiden (naeher am jeweils injizierten now). func TestMigrateAll_ResultIndependentOfInjectedNow(t *testing.T) { - poolA := requireTestPool(t) - poolB := requireTestPool(t) + pool := requireTestPool(t) - due := time.Date(2040, time.June, 15, 12, 0, 0, 0, time.UTC) - source := func() *fixtureSource { - return &fixtureSource{objects: []SourceObject{ - {ObjectType: "dms_document", ObjectReference: "doc-clock-test", RetainUntil: &due}, - }} - } + due := time.Date(2030, time.June, 15, 12, 0, 0, 0, time.UTC) - nowA := time.Date(2026, time.October, 14, 0, 0, 0, 0, time.UTC) - nowB := time.Date(2099, time.December, 31, 23, 59, 59, 0, time.UTC) + nowA := time.Date(2026, time.January, 1, 0, 0, 0, 0, time.UTC) + nowB := time.Date(2099, time.January, 1, 0, 0, 0, 0, time.UTC) - mA := NewMigrator(poolA, source()) + mA := NewMigrator(pool, &fixtureSource{objects: []SourceObject{ + {ObjectType: "dms_document", ObjectReference: "doc-clock-test-a", RetainUntil: &due}, + }}) if _, err := mA.MigrateAll(context.Background(), nowA); err != nil { t.Fatalf("migrateall (now=A): %v", err) } - mB := NewMigrator(poolB, source()) + mB := NewMigrator(pool, &fixtureSource{objects: []SourceObject{ + {ObjectType: "dms_document", ObjectReference: "doc-clock-test-b", RetainUntil: &due}, + }}) if _, err := mB.MigrateAll(context.Background(), nowB); err != nil { t.Fatalf("migrateall (now=B): %v", err) } - idA := objectID(t, poolA, "dms_document", "doc-clock-test") - idB := objectID(t, poolB, "dms_document", "doc-clock-test") - gotA, okA := mustRetainUntil(t, poolA, idA) - gotB, okB := mustRetainUntil(t, poolB, idB) + idA := objectID(t, pool, "dms_document", "doc-clock-test-a") + idB := objectID(t, pool, "dms_document", "doc-clock-test-b") + gotA, okA := mustRetainUntil(t, pool, idA) + gotB, okB := mustRetainUntil(t, pool, idB) if !okA || !okB { t.Fatalf("erwartet beide laeufe mit gesetzter frist, okA=%v okB=%v", okA, okB) }