package store_test import ( "context" "errors" "testing" "time" "github.com/netcell-it/deklarix/internal/store" ) func testAntragMitBewertung(t *testing.T, s *store.Store, accountID, userID string) (store.Antrag, store.Bewertung) { t.Helper() ctx := context.Background() antrag, err := s.CreateAntrag(ctx, accountID, userID, nil, "Testantrag") if err != nil { t.Fatalf("CreateAntrag: %v", err) } b, err := s.CreateBewertung(ctx, testBewertungInput(antrag.ID)) if err != nil { t.Fatalf("CreateBewertung: %v", err) } return antrag, b } func TestEntscheidungCreateAndGetLatest(t *testing.T) { s := openTestStore(t) ctx := context.Background() accID := testAccountID(t, s) userID := testUserID(t, s, accID) antrag, b := testAntragMitBewertung(t, s, accID, userID) w, err := s.CreateWerkzeug(ctx, testWerkzeugInput(nil, "ChatGPT Enterprise")) if err != nil { t.Fatalf("CreateWerkzeug: %v", err) } gueltigBis := time.Now().Add(365 * 24 * time.Hour).Truncate(time.Millisecond) e, err := s.CreateEntscheidung(ctx, store.EntscheidungInput{ AntragID: antrag.ID, BewertungID: b.ID, EntscheiderUserID: userID, Entscheidung: "genehmigt", WerkzeugID: &w.ID, WerkzeugSnapshot: &w, Begruendung: "", GueltigBis: &gueltigBis, }) if err != nil { t.Fatalf("CreateEntscheidung: %v", err) } if e.Entscheidung != "genehmigt" || e.WerkzeugSnapshot == nil || e.WerkzeugSnapshot.Name != "ChatGPT Enterprise" { t.Fatalf("CreateEntscheidung = %+v, unerwartete Werte", e) } got, err := s.GetLatestEntscheidungForAntrag(ctx, antrag.ID) if err != nil { t.Fatalf("GetLatestEntscheidungForAntrag: %v", err) } if got.ID != e.ID { t.Fatalf("GetLatestEntscheidungForAntrag returned a different row than CreateEntscheidung") } } func TestEntscheidungOhneWerkzeugHatKeinenSnapshot(t *testing.T) { s := openTestStore(t) ctx := context.Background() accID := testAccountID(t, s) userID := testUserID(t, s, accID) antrag, b := testAntragMitBewertung(t, s, accID, userID) e, err := s.CreateEntscheidung(ctx, store.EntscheidungInput{ AntragID: antrag.ID, BewertungID: b.ID, EntscheiderUserID: userID, Entscheidung: "abgelehnt", Begruendung: "Kein geeignetes Werkzeug im Katalog", }) if err != nil { t.Fatalf("CreateEntscheidung: %v", err) } if e.WerkzeugID != nil || e.WerkzeugSnapshot != nil { t.Fatalf("expected no werkzeug/snapshot for an abgelehnt Entscheidung, got %+v", e) } } func TestGetLatestEntscheidungForAntragNotFound(t *testing.T) { s := openTestStore(t) ctx := context.Background() accID := testAccountID(t, s) userID := testUserID(t, s, accID) antrag, err := s.CreateAntrag(ctx, accID, userID, nil, "Ohne Entscheidung") if err != nil { t.Fatalf("CreateAntrag: %v", err) } _, err = s.GetLatestEntscheidungForAntrag(ctx, antrag.ID) if !errors.Is(err, store.ErrNotFound) { t.Fatalf("err = %v, want store.ErrNotFound", err) } } func TestEntscheidungIsAppendOnly(t *testing.T) { s := openTestStore(t) ctx := context.Background() accID := testAccountID(t, s) userID := testUserID(t, s, accID) antrag, b := testAntragMitBewertung(t, s, accID, userID) e, err := s.CreateEntscheidung(ctx, store.EntscheidungInput{ AntragID: antrag.ID, BewertungID: b.ID, EntscheiderUserID: userID, Entscheidung: "rueckfrage", }) if err != nil { t.Fatalf("CreateEntscheidung: %v", err) } _, err = s.Pool.Exec(ctx, `UPDATE entscheidung SET entscheidung = 'genehmigt' WHERE id = $1`, e.ID) if err == nil { t.Fatal("expected UPDATE on entscheidung to be rejected by the append-only trigger") } _, err = s.Pool.Exec(ctx, `DELETE FROM entscheidung WHERE id = $1`, e.ID) if err == nil { t.Fatal("expected DELETE on entscheidung to be rejected by the append-only trigger") } } func TestListAktiveGenehmigungenForAccount(t *testing.T) { s := openTestStore(t) ctx := context.Background() accID := testAccountID(t, s) userID := testUserID(t, s, accID) antragGenehmigt, b1 := testAntragMitBewertung(t, s, accID, userID) if _, err := s.CreateEntscheidung(ctx, store.EntscheidungInput{ AntragID: antragGenehmigt.ID, BewertungID: b1.ID, EntscheiderUserID: userID, Entscheidung: "genehmigt", }); err != nil { t.Fatalf("CreateEntscheidung (genehmigt): %v", err) } antragAbgelehnt, b2 := testAntragMitBewertung(t, s, accID, userID) if _, err := s.CreateEntscheidung(ctx, store.EntscheidungInput{ AntragID: antragAbgelehnt.ID, BewertungID: b2.ID, EntscheiderUserID: userID, Entscheidung: "abgelehnt", }); err != nil { t.Fatalf("CreateEntscheidung (abgelehnt): %v", err) } list, err := s.ListAktiveGenehmigungenForAccount(ctx, accID) if err != nil { t.Fatalf("ListAktiveGenehmigungenForAccount: %v", err) } if len(list) != 1 || list[0].AntragID != antragGenehmigt.ID { t.Fatalf("ListAktiveGenehmigungenForAccount = %+v, want exactly the genehmigt entscheidung", list) } otherAcc := testAccountID(t, s) otherList, err := s.ListAktiveGenehmigungenForAccount(ctx, otherAcc) if err != nil { t.Fatalf("ListAktiveGenehmigungenForAccount (other): %v", err) } if len(otherList) != 0 { t.Fatalf("expected no genehmigungen for a different tenant, got %+v", otherList) } }