TAR-01: now-unabhaengigkeits-test auf echte getrennte Datensaetze umgestellt
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (push) Canceled after 0s
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (pull_request) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (push) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Canceled after 0s
CI / Connect Security-Test-Gate (QA-01 AC4, Merge-Gate) (push) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Canceled after 0s
CI / Web (dms-browser) (push) Canceled after 0s
CI / Web (pdf-viewer) (push) Canceled after 0s
CI / Web (shl) (push) Canceled after 0s
CI / Web (dms-browser) (pull_request) Canceled after 0s
Archive-Pflichttest-Gate / pflichttest-gate (pull_request) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (pull_request) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (pull_request) Canceled after 0s
CI / Connect Security-Test-Gate (QA-01 AC4, Merge-Gate) (pull_request) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (pull_request) Canceled after 0s
CI / Web (pdf-viewer) (pull_request) Canceled after 0s
CI / Web (shl) (pull_request) Canceled after 0s
Supply-Chain-Scan (Go) / govulncheck (push) Canceled after 0s
Core-Schnittstellen-Vertragstests / contract-tests (pull_request) Canceled after 0s
Supply-Chain-Scan (Go) / govulncheck (pull_request) Canceled after 0s
Supply-Chain-Scan (npm) / npm-audit (pull_request) Canceled after 0s
Core-Pflichttest-Gate / pflichttest-gate (pull_request) Canceled after 0s
RBAC-Rollenhierarchie-Pflichtgate / rbac-policy-invariant (pull_request) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (pull_request) Canceled after 0s

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
patrickandClaude Sonnet 5 committed 2026-10-14 15:23:38 +00:00
1 parent ecea9bcc8c
commit bc60e11b4c
2 files changed
+23 -22

No files matched your search

+3 -3
View File
@@ -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 |
@@ -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)
}