Test: TestVerifyWithContext_RateSpikeTriggersAuditEvent Zeitrennen behoben
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (push) 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 / 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
Supply-Chain-Scan (Go) / govulncheck (push) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Canceled after 0s

Basislinie wird jetzt deterministisch in die DB geseedet statt ueber
reale time.Sleep-Abstaende erzeugt, dadurch entfaellt die 24ms-Schwelle
unter Host-Last als Fehlerquelle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
patrickandClaude Sonnet 5 committed 2026-09-22 20:13:05 +02:00
1 parent 94290aa47b
commit f809b9f8f6
1 file changed
+26 -12
+26 -12
View File
@@ -160,23 +160,37 @@ func TestVerifyWithContext_RateSpikeTriggersAuditEvent(t *testing.T) {
t.Fatalf("issue token: %v", err)
}
// Gewohntes Muster etablieren: mehrere Zugriffe mit spuerbarem Abstand,
// alle aus derselben IP-Range, damit ausschliesslich die Zugriffsrate
// geprueft wird.
for i := 0; i < 4; i++ {
if _, err := store.VerifyWithContext(ctx, plaintext, "", "10.0.0.5"); err != nil {
t.Fatalf("verify (basislinie, durchlauf %d): %v", i, err)
}
if i < 3 {
time.Sleep(120 * time.Millisecond)
}
// Gewohntes Muster etablieren: ein realer Zugriff legt die Zeile an,
// danach wird die Basislinie DIREKT in der DB gesetzt statt ueber
// reale time.Sleep-Abstaende erzeugt zu werden. Grund (2026-09-22,
// Root-Cause-Fix eines unter Host-Last flackernden Tests): bei
// time.Sleep(120ms) lag die Schwelle fuer den anschliessenden
// "Spike"-Zugriff bei baseline/rateSpikeFactor = 24ms — auf einem
// parallel stark ausgelasteten Testhost kann ein einzelner
// VerifyWithContext-Aufruf (Verify + mehrere DB-Round-Trips) diese
// 24ms leicht ueberschreiten, wodurch der Test nicht die
// Testumgebung, sondern eine reale Wettlaufbedingung gegen die
// Host-Last maß. Mit einer Basislinie von 5s (Schwelle 1s) ist der
// Abstand so groß, dass ein einzelner DB-Round-Trip ihn in jeder
// realistischen Lastsituation sicher unterschreitet — deterministisch,
// nicht toleranter gemacht.
if _, err := store.VerifyWithContext(ctx, plaintext, "", "10.0.0.5"); err != nil {
t.Fatalf("verify (basislinie anlegen): %v", err)
}
const seededBaselineSeconds = 5.0
if _, err := pool.Exec(ctx, `
UPDATE api_token_rate_state
SET last_seen_at = now(), baseline_interval_seconds = $2, sample_count = $3
WHERE token_id = $1
`, tokenID, seededBaselineSeconds, minSamplesForRateBaseline); err != nil {
t.Fatalf("basislinie seeden: %v", err)
}
if n := countAuditEvents(t, pool, ActionAnomalyRate, tokenID); n != 0 {
t.Fatalf("gleichmaessige nutzung soll keinen raten-alarm ausloesen, habe %d event(s)", n)
}
// Jetzt ein Buendel von Zugriffen praktisch ohne Abstand — weit unter der
// gewohnten ~120ms-Basislinie (Akzeptanzkriterium 2).
// Jetzt ein Zugriff praktisch ohne Abstand — weit unter der auf 5s
// gesetzten Basislinie, deren Schwelle bei 1s liegt (Akzeptanzkriterium 2).
if _, err := store.VerifyWithContext(ctx, plaintext, "", "10.0.0.5"); err != nil {
t.Fatalf("verify (rate spike): %v", err)
}