package store_test import ( "context" "errors" "testing" "github.com/netcell-it/deklarix/internal/store" ) func TestEmailVorlagePlattformStandardExistiertNachMigration(t *testing.T) { s := openTestStore(t) ctx := context.Background() v, err := s.GetEmailVorlage(ctx, nil, "passwort_zuruecksetzen") if err != nil { t.Fatalf("GetEmailVorlage (Plattform): %v", err) } if v.AccountID != nil { t.Fatalf("AccountID = %v, want nil (Plattform-Standard)", v.AccountID) } if v.Betreff == "" || v.Text == "" { t.Fatalf("Plattform-Standard unvollständig: %+v", v) } } func TestResolveEmailVorlageFaelltAufPlattformStandardZurueck(t *testing.T) { s := openTestStore(t) ctx := context.Background() accID := testAccountID(t, s) // Ohne eigene Übersteuerung liefert Resolve den Plattform-Standard. resolved, err := s.ResolveEmailVorlage(ctx, accID, "passwort_zuruecksetzen") if err != nil { t.Fatalf("ResolveEmailVorlage (kein eigener Override): %v", err) } if resolved.AccountID != nil { t.Fatalf("AccountID = %v, want nil (geerbt vom Plattform-Standard)", resolved.AccountID) } // Eigene Übersteuerung anlegen — Resolve muss jetzt die eigene liefern. eigene, err := s.UpsertEmailVorlage(ctx, &accID, "passwort_zuruecksetzen", "Eigener Betreff", "Eigener Text {{link}}") if err != nil { t.Fatalf("UpsertEmailVorlage: %v", err) } resolved, err = s.ResolveEmailVorlage(ctx, accID, "passwort_zuruecksetzen") if err != nil { t.Fatalf("ResolveEmailVorlage (mit Override): %v", err) } if resolved.ID != eigene.ID || resolved.Betreff != "Eigener Betreff" { t.Fatalf("resolved = %+v, want eigene Vorlage", resolved) } // Zurücksetzen entfernt die Übersteuerung, Resolve fällt wieder zurück. if err := s.DeleteEmailVorlage(ctx, &accID, "passwort_zuruecksetzen"); err != nil { t.Fatalf("DeleteEmailVorlage: %v", err) } resolved, err = s.ResolveEmailVorlage(ctx, accID, "passwort_zuruecksetzen") if err != nil { t.Fatalf("ResolveEmailVorlage (nach Reset): %v", err) } if resolved.AccountID != nil { t.Fatalf("AccountID nach Reset = %v, want nil (wieder Plattform-Standard)", resolved.AccountID) } } func TestUpsertPlattformStandardAktualisiertStattZuDuplizieren(t *testing.T) { // Regressionstest: SQL behandelt NULL nie als gleich zu NULL, ein // naiver UNIQUE(account_id, typ)-Constraint hätte beliebig viele // Plattform-Standard-Zeilen je typ zugelassen — jedes erneute // Speichern hätte eine neue Zeile erzeugt statt die bestehende zu // aktualisieren (genau das ist beim Live-Verifizieren passiert). s := openTestStore(t) ctx := context.Background() first, err := s.UpsertEmailVorlage(ctx, nil, "passwort_zuruecksetzen", "Erster Betreff", "Erster Text {{link}}") if err != nil { t.Fatalf("UpsertEmailVorlage (1): %v", err) } second, err := s.UpsertEmailVorlage(ctx, nil, "passwort_zuruecksetzen", "Zweiter Betreff", "Zweiter Text {{link}}") if err != nil { t.Fatalf("UpsertEmailVorlage (2): %v", err) } if first.ID != second.ID { t.Fatalf("zweites Upsert erzeugte eine neue Zeile (ID %s statt %s) statt zu aktualisieren", second.ID, first.ID) } got, err := s.GetEmailVorlage(ctx, nil, "passwort_zuruecksetzen") if err != nil { t.Fatalf("GetEmailVorlage: %v", err) } if got.Betreff != "Zweiter Betreff" { t.Fatalf("Betreff = %q, want %q (aktueller Stand)", got.Betreff, "Zweiter Betreff") } } func TestEmailVorlageZweierMandantenIsoliert(t *testing.T) { s := openTestStore(t) ctx := context.Background() accA := testAccountID(t, s) accB := testAccountID(t, s) if _, err := s.UpsertEmailVorlage(ctx, &accA, "passwort_zuruecksetzen", "Vorlage A", "Text A {{link}}"); err != nil { t.Fatalf("UpsertEmailVorlage A: %v", err) } resolvedB, err := s.ResolveEmailVorlage(ctx, accB, "passwort_zuruecksetzen") if err != nil { t.Fatalf("ResolveEmailVorlage B: %v", err) } if resolvedB.Betreff == "Vorlage A" { t.Fatal("Mandant B sieht die Vorlage von Mandant A — Isolation defekt") } if _, err := s.GetEmailVorlage(ctx, &accB, "passwort_zuruecksetzen"); !errors.Is(err, store.ErrNotFound) { t.Fatalf("GetEmailVorlage B (kein eigener Override) err=%v, want ErrNotFound", err) } }