IMP-09: import-testsuite
Testsuite für Import-Scheduler, Anhangsverarbeitung und Regelwerk, inklusive Tenant-Scoping und nicht-konformer Server. - tenant_scoping_test.go (imapimport + mailrules): schließt eine echte Lücke — kein bestehender Test bewies bislang explizit, dass zwei Mandanten (identischer Postfachname bzw. fehlende eigene Regel) sich nicht gegenseitig beeinflussen. - importtestgate/gate.go: echtes, ausführbares Gate (spiegelt qagate/ QA-03) — RunTestSuites liefert realen Testabdeckungsbericht (go test -cover) je Importpfad, ScanForExternalMailboxReferences bestätigt automatisiert, dass keine Testdatei einen echten externen IMAP- Anbieter referenziert. - Echten Bug beim eigenen Testlauf gefunden und behoben: die t.Cleanup-Löschfilter in scheduler_test.go/engine_test.go waren ticket- statt paketspezifisch (mandant-imp01-%/mandant-imp03-%) — die neuen IMP-09-Tenant-Testdaten wurden nie aufgeräumt, ein zweiter Testlauf schlug real mit falschen Zählungen fehl. Auf mandant-% verallgemeinert. Prüfungen (alle real durchgeführt, siehe mail/docs/IMP-09-PRUEFPROTOKOLL.md): 1. TestRun_RealGateAgainstImportPackages: realer Abdeckungsbericht imapimport 81.5%, attachments 94.4%, mailrules 71.2%. 2. go test -count=1 zweimal hintereinander real grün (reproduzierbar nach Cleanup-Fix). 3. TestScanForExternalMailboxReferences_RealImportPackagesPass: real keine externe Postfach-Referenz in den Testsuiten. Kein Umbau der geprüften Produktionslogik. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
56d31c9176
commit
dac7854440
@@ -30,7 +30,12 @@ func setupStore(t *testing.T) *Store {
|
||||
t.Fatalf("schema: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_, _ = pool.Exec(context.Background(), `DELETE FROM mail_import_state WHERE tenant_slug LIKE 'mandant-imp01-%'`)
|
||||
// LIKE-Muster bewusst paket-, nicht ticketspezifisch (mandant-%
|
||||
// statt mandant-imp01-%) — mehrere Tickets (u. a. IMP-09) fügen
|
||||
// diesem Paket über die Zeit weitere Tests mit eigenen
|
||||
// Mandanten-Präfixen hinzu; ein zu enges Muster ließ bereits real
|
||||
// Testdaten ungelöscht zurück (siehe IMP-09-Prüfprotokoll).
|
||||
_, _ = pool.Exec(context.Background(), `DELETE FROM mail_import_state WHERE tenant_slug LIKE 'mandant-%'`)
|
||||
})
|
||||
return store
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// IMP-09: Tenant-Scoping-Nachweis für den Postfach-Abruf
|
||||
// (Akzeptanzkriterium 2). Bekannten Fehler vermeiden (known-issues-
|
||||
// archivmail.md #4): Import-nahe Module waren praktisch ungetestet —
|
||||
// dieser Test schließt eine reale Lücke, die vor IMP-09 bestand: kein
|
||||
// bestehender Test bewies bislang, dass zwei Mandanten mit DEMSELBEN
|
||||
// Postfachnamen sich nicht gegenseitig beeinflussen.
|
||||
package imapimport
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestScheduler_TenantScopingIsolatesSyncState(t *testing.T) {
|
||||
store := setupStore(t)
|
||||
scheduler := NewScheduler(store)
|
||||
ctx := context.Background()
|
||||
|
||||
tenantA := "mandant-imp09-tenant-a"
|
||||
tenantB := "mandant-imp09-tenant-b"
|
||||
const mailbox = "INBOX" // BEWUSST derselbe Postfachname bei beiden Mandanten
|
||||
|
||||
clientA := &fakeIMAPClient{uidvalidity: 1, messages: []RemoteMessage{{UID: 1}, {UID: 2}}}
|
||||
clientB := &fakeIMAPClient{uidvalidity: 1, messages: []RemoteMessage{{UID: 1}, {UID: 2}, {UID: 3}}}
|
||||
|
||||
handlerA := &recordingHandler{}
|
||||
resultA, err := scheduler.RunOnce(ctx, tenantA, mailbox, clientA, handlerA)
|
||||
if err != nil {
|
||||
t.Fatalf("mandant a: %v", err)
|
||||
}
|
||||
if resultA.NewMessages != 2 {
|
||||
t.Fatalf("mandant a: erwartete 2 neue nachrichten, habe %d", resultA.NewMessages)
|
||||
}
|
||||
|
||||
handlerB := &recordingHandler{}
|
||||
resultB, err := scheduler.RunOnce(ctx, tenantB, mailbox, clientB, handlerB)
|
||||
if err != nil {
|
||||
t.Fatalf("mandant b: %v", err)
|
||||
}
|
||||
// Entscheidender Nachweis: Mandant B startet trotz identischem
|
||||
// Postfachnamen bei UID 0 — sähe er fälschlich den Zustand von
|
||||
// Mandant A (UID 2 bereits synchronisiert), würden hier nur 1 statt
|
||||
// 3 neue Nachrichten gezählt.
|
||||
if resultB.NewMessages != 3 {
|
||||
t.Fatalf("mandant b: erwartete 3 neue nachrichten (kein zustand von mandant a übernommen), habe %d", resultB.NewMessages)
|
||||
}
|
||||
|
||||
stateA, err := store.Get(ctx, tenantA, mailbox)
|
||||
if err != nil {
|
||||
t.Fatalf("zustand mandant a: %v", err)
|
||||
}
|
||||
stateB, err := store.Get(ctx, tenantB, mailbox)
|
||||
if err != nil {
|
||||
t.Fatalf("zustand mandant b: %v", err)
|
||||
}
|
||||
if stateA.LastSyncedUID != 2 {
|
||||
t.Fatalf("mandant a: erwartete last_synced_uid=2, habe %d", stateA.LastSyncedUID)
|
||||
}
|
||||
if stateB.LastSyncedUID != 3 {
|
||||
t.Fatalf("mandant b: erwartete last_synced_uid=3, habe %d", stateB.LastSyncedUID)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user