Files
deklarix/internal/store/bewertung_test.go
noroot e968cf9761 feat: Ergebnisdarstellung mit Herleitung (Schritt 4 der Baureihenfolge)
POST /antraege berechnet und speichert direkt beim Einreichen eine
append-only bewertung (Datenklasse, KI-VO-Einstufung, Anforderungen,
zulässige/ausgeschlossene Werkzeuge), GET /antraege/{id} zeigt sie
inklusive Herleitung und dem Pflicht-Hinweis, dass das System nicht
entscheidet, sondern nur vorbereitet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-29 10:22:24 +02:00

127 lines
4.0 KiB
Go

package store_test
import (
"context"
"errors"
"testing"
"github.com/netcell-it/deklarix/internal/store"
)
func testBewertungInput(antragID string) store.BewertungInput {
return store.BewertungInput{
AntragID: antragID, Datenklasse: "personenbezogen", DatenklasseHerleitung: "ausgelöst durch b1",
Einstufung: "minimal", EinstufungHerleitung: "Auffangregel", Verboten: false,
Anforderungen: []store.BewertungAnforderung{
{ID: "avv_erforderlich", Beschreibung: "AVV nötig", Herleitung: "aus Datenklasse personenbezogen"},
},
ZulaessigeWerkzeuge: []string{"werkzeug-a"},
AusgeschlosseneWerkzeuge: []store.BewertungAusschluss{
{WerkzeugID: "werkzeug-b", NichtErfuellt: []string{"avv_erforderlich"}},
},
RegelwerkVersion: "dk1.ei1.an1", KatalogVersion: "3-1735300000",
}
}
func TestBewertungCreateAndGetLatest(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, "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)
}
if b.Datenklasse != "personenbezogen" || len(b.Anforderungen) != 1 {
t.Fatalf("CreateBewertung = %+v, unerwartete Werte", b)
}
if b.Anforderungen[0].ID != "avv_erforderlich" {
t.Fatalf("Anforderungen[0] = %+v, unerwartet", b.Anforderungen[0])
}
if len(b.AusgeschlosseneWerkzeuge) != 1 || b.AusgeschlosseneWerkzeuge[0].WerkzeugID != "werkzeug-b" {
t.Fatalf("AusgeschlosseneWerkzeuge = %+v, unerwartet", b.AusgeschlosseneWerkzeuge)
}
got, err := s.GetLatestBewertungForAntrag(ctx, antrag.ID)
if err != nil {
t.Fatalf("GetLatestBewertungForAntrag: %v", err)
}
if got.ID != b.ID {
t.Fatalf("GetLatestBewertungForAntrag returned a different row than CreateBewertung")
}
}
func TestGetLatestBewertungForAntragNotFound(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 Bewertung")
if err != nil {
t.Fatalf("CreateAntrag: %v", err)
}
_, err = s.GetLatestBewertungForAntrag(ctx, antrag.ID)
if !errors.Is(err, store.ErrNotFound) {
t.Fatalf("err = %v, want store.ErrNotFound", err)
}
}
func TestBewertungReturnsNewestWhenMultiple(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, "Mehrfach bewertet")
if err != nil {
t.Fatalf("CreateAntrag: %v", err)
}
if _, err := s.CreateBewertung(ctx, testBewertungInput(antrag.ID)); err != nil {
t.Fatalf("CreateBewertung (1): %v", err)
}
second := testBewertungInput(antrag.ID)
second.Datenklasse = "besondere_kategorie"
newest, err := s.CreateBewertung(ctx, second)
if err != nil {
t.Fatalf("CreateBewertung (2): %v", err)
}
got, err := s.GetLatestBewertungForAntrag(ctx, antrag.ID)
if err != nil {
t.Fatalf("GetLatestBewertungForAntrag: %v", err)
}
if got.ID != newest.ID || got.Datenklasse != "besondere_kategorie" {
t.Fatalf("expected the newest bewertung, got %+v", got)
}
}
func TestBewertungIsAppendOnly(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, "Append-only Test")
if err != nil {
t.Fatalf("CreateAntrag: %v", err)
}
b, err := s.CreateBewertung(ctx, testBewertungInput(antrag.ID))
if err != nil {
t.Fatalf("CreateBewertung: %v", err)
}
_, err = s.Pool.Exec(ctx, `UPDATE bewertung SET datenklasse = 'geaendert' WHERE id = $1`, b.ID)
if err == nil {
t.Fatal("expected UPDATE on bewertung to be rejected by the append-only trigger")
}
_, err = s.Pool.Exec(ctx, `DELETE FROM bewertung WHERE id = $1`, b.ID)
if err == nil {
t.Fatal("expected DELETE on bewertung to be rejected by the append-only trigger")
}
}