Jede neue Firma (Registrierung + Betreiber-Firmenanlage) bekommt jetzt automatisch vier leere Genehmiger-Rollen mit erklärender Beschreibung (Datenschutzbeauftragter, Geschäftsführer, KI-Manager, CISO) - Admin muss nur noch Personen zuordnen statt bei null anzufangen. Welche Bedingung welche Rolle tatsächlich auslöst, bleibt weiterhin komplett konfigurierbar pro Firma (Migration 0018 fügt genehmiger_rolle.beschreibung als reines Freitext-Orientierungsfeld hinzu, keine feste fachliche Bindung). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
175 lines
6.0 KiB
Go
175 lines
6.0 KiB
Go
package store_test
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/netcell-it/deklarix/internal/store"
|
|
)
|
|
|
|
func TestGenehmigerRolleCRUDAndMitgliedschaft(t *testing.T) {
|
|
s := openTestStore(t)
|
|
ctx := context.Background()
|
|
accID := testAccountID(t, s)
|
|
|
|
g, err := s.CreateGenehmigerRolle(ctx, accID, "Datenschutzbeauftragter", "")
|
|
if err != nil {
|
|
t.Fatalf("CreateGenehmigerRolle: %v", err)
|
|
}
|
|
if g.AccountID != accID || g.Name != "Datenschutzbeauftragter" {
|
|
t.Fatalf("GenehmigerRolle = %+v, unerwartete Werte", g)
|
|
}
|
|
|
|
got, err := s.GetGenehmigerRolle(ctx, g.ID)
|
|
if err != nil || got.Name != "Datenschutzbeauftragter" {
|
|
t.Fatalf("GetGenehmigerRolle = %+v, err=%v", got, err)
|
|
}
|
|
|
|
liste, err := s.ListGenehmigerRollenForAccount(ctx, accID)
|
|
if err != nil || len(liste) != 1 {
|
|
t.Fatalf("ListGenehmigerRollenForAccount = %+v, err=%v", liste, err)
|
|
}
|
|
|
|
user := testUserID(t, s, accID)
|
|
if err := s.AddNutzerGenehmigerRolle(ctx, user, g.ID); err != nil {
|
|
t.Fatalf("AddNutzerGenehmigerRolle: %v", err)
|
|
}
|
|
// Erneutes Hinzufügen derselben Zuordnung ist ein No-op (ON CONFLICT),
|
|
// kein Fehler.
|
|
if err := s.AddNutzerGenehmigerRolle(ctx, user, g.ID); err != nil {
|
|
t.Fatalf("AddNutzerGenehmigerRolle (erneut): %v", err)
|
|
}
|
|
|
|
rollenDesNutzers, err := s.ListGenehmigerRollenForUser(ctx, user)
|
|
if err != nil || len(rollenDesNutzers) != 1 || rollenDesNutzers[0].ID != g.ID {
|
|
t.Fatalf("ListGenehmigerRollenForUser = %+v, err=%v", rollenDesNutzers, err)
|
|
}
|
|
|
|
mitglieder, err := s.ListNutzerForGenehmigerRolle(ctx, g.ID)
|
|
if err != nil || len(mitglieder) != 1 || mitglieder[0].UserID != user {
|
|
t.Fatalf("ListNutzerForGenehmigerRolle = %+v, err=%v", mitglieder, err)
|
|
}
|
|
|
|
if err := s.RemoveNutzerGenehmigerRolle(ctx, user, g.ID); err != nil {
|
|
t.Fatalf("RemoveNutzerGenehmigerRolle: %v", err)
|
|
}
|
|
rollenNachEntfernen, err := s.ListGenehmigerRollenForUser(ctx, user)
|
|
if err != nil || len(rollenNachEntfernen) != 0 {
|
|
t.Fatalf("ListGenehmigerRollenForUser nach Entfernen = %+v, err=%v", rollenNachEntfernen, err)
|
|
}
|
|
|
|
if err := s.DeleteGenehmigerRolle(ctx, g.ID); err != nil {
|
|
t.Fatalf("DeleteGenehmigerRolle: %v", err)
|
|
}
|
|
if _, err := s.GetGenehmigerRolle(ctx, g.ID); !errors.Is(err, store.ErrNotFound) {
|
|
t.Fatalf("err nach Delete = %v, want ErrNotFound", err)
|
|
}
|
|
}
|
|
|
|
func TestFreigabeRegelCRUD(t *testing.T) {
|
|
s := openTestStore(t)
|
|
ctx := context.Background()
|
|
accID := testAccountID(t, s)
|
|
g, err := s.CreateGenehmigerRolle(ctx, accID, "Geschaeftsfuehrung", "")
|
|
if err != nil {
|
|
t.Fatalf("CreateGenehmigerRolle: %v", err)
|
|
}
|
|
|
|
regel, err := s.CreateFreigabeRegel(ctx, accID, "einstufung", "hochrisiko", g.ID)
|
|
if err != nil {
|
|
t.Fatalf("CreateFreigabeRegel: %v", err)
|
|
}
|
|
if regel.BedingungTyp != "einstufung" || regel.BedingungWert != "hochrisiko" {
|
|
t.Fatalf("FreigabeRegel = %+v, unerwartete Werte", regel)
|
|
}
|
|
|
|
liste, err := s.ListFreigabeRegelnForAccount(ctx, accID)
|
|
if err != nil || len(liste) != 1 {
|
|
t.Fatalf("ListFreigabeRegelnForAccount = %+v, err=%v", liste, err)
|
|
}
|
|
|
|
got, err := s.GetFreigabeRegel(ctx, regel.ID)
|
|
if err != nil || got.ID != regel.ID {
|
|
t.Fatalf("GetFreigabeRegel = %+v, err=%v", got, err)
|
|
}
|
|
|
|
if err := s.DeleteFreigabeRegel(ctx, regel.ID); err != nil {
|
|
t.Fatalf("DeleteFreigabeRegel: %v", err)
|
|
}
|
|
if _, err := s.GetFreigabeRegel(ctx, regel.ID); !errors.Is(err, store.ErrNotFound) {
|
|
t.Fatalf("err nach Delete = %v, want ErrNotFound", err)
|
|
}
|
|
}
|
|
|
|
func TestFreigabeschrittLifecycleUndKaskade(t *testing.T) {
|
|
s := openTestStore(t)
|
|
ctx := context.Background()
|
|
accID := testAccountID(t, s)
|
|
user := testUserID(t, s, accID)
|
|
antrag, err := s.CreateAntrag(ctx, accID, user, nil, "Test-Antrag für Freigabeschritte")
|
|
if err != nil {
|
|
t.Fatalf("CreateAntrag: %v", err)
|
|
}
|
|
antragID := antrag.ID
|
|
|
|
dsb, _ := s.CreateGenehmigerRolle(ctx, accID, "Datenschutzbeauftragter", "")
|
|
gf, _ := s.CreateGenehmigerRolle(ctx, accID, "Geschaeftsfuehrung", "")
|
|
|
|
schrittDSB, err := s.CreateFreigabeschritt(ctx, antragID, dsb.ID)
|
|
if err != nil {
|
|
t.Fatalf("CreateFreigabeschritt: %v", err)
|
|
}
|
|
if schrittDSB.Status != "ausstehend" {
|
|
t.Fatalf("Status = %q, want ausstehend", schrittDSB.Status)
|
|
}
|
|
schrittGF, err := s.CreateFreigabeschritt(ctx, antragID, gf.ID)
|
|
if err != nil {
|
|
t.Fatalf("CreateFreigabeschritt: %v", err)
|
|
}
|
|
|
|
alle, err := s.ListFreigabeschritteForAntrag(ctx, antragID)
|
|
if err != nil || len(alle) != 2 {
|
|
t.Fatalf("ListFreigabeschritteForAntrag = %+v, err=%v", alle, err)
|
|
}
|
|
|
|
ausstehend, err := s.ListAusstehendeFreigabeschritteForUser(ctx, user)
|
|
if err != nil {
|
|
t.Fatalf("ListAusstehendeFreigabeschritteForUser: %v", err)
|
|
}
|
|
if len(ausstehend) != 0 {
|
|
t.Fatalf("erwartet 0 ausstehende Freigaben ohne Genehmiger-Rollen-Zuordnung, got %d", len(ausstehend))
|
|
}
|
|
if err := s.AddNutzerGenehmigerRolle(ctx, user, dsb.ID); err != nil {
|
|
t.Fatalf("AddNutzerGenehmigerRolle: %v", err)
|
|
}
|
|
ausstehend, err = s.ListAusstehendeFreigabeschritteForUser(ctx, user)
|
|
if err != nil || len(ausstehend) != 1 || ausstehend[0].ID != schrittDSB.ID {
|
|
t.Fatalf("ListAusstehendeFreigabeschritteForUser = %+v, err=%v", ausstehend, err)
|
|
}
|
|
|
|
entschieden, err := s.EntscheideFreigabeschritt(ctx, schrittDSB.ID, "abgelehnt", user, "nicht ausreichend")
|
|
if err != nil {
|
|
t.Fatalf("EntscheideFreigabeschritt: %v", err)
|
|
}
|
|
if entschieden.Status != "abgelehnt" || entschieden.EntschiedenVon == nil || *entschieden.EntschiedenVon != user {
|
|
t.Fatalf("Freigabeschritt nach Entscheidung = %+v, unerwartete Werte", entschieden)
|
|
}
|
|
|
|
// Ein bereits entschiedener Schritt kann nicht erneut entschieden werden.
|
|
if _, err := s.EntscheideFreigabeschritt(ctx, schrittDSB.ID, "genehmigt", user, ""); !errors.Is(err, store.ErrNotFound) {
|
|
t.Fatalf("erneute Entscheidung err = %v, want ErrNotFound", err)
|
|
}
|
|
|
|
if err := s.KaskadiereAblehnung(ctx, antragID, schrittDSB.ID); err != nil {
|
|
t.Fatalf("KaskadiereAblehnung: %v", err)
|
|
}
|
|
nachKaskade, err := s.GetFreigabeschritt(ctx, schrittGF.ID)
|
|
if err != nil {
|
|
t.Fatalf("GetFreigabeschritt: %v", err)
|
|
}
|
|
if nachKaskade.Status != "abgelehnt" {
|
|
t.Fatalf("Status nach Kaskade = %q, want abgelehnt", nachKaskade.Status)
|
|
}
|
|
}
|