package postgres import ( "context" "errors" "strings" "testing" "time" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgconn" "knowledge-governance/internal/governance" ) func TestListReleasePlanBuildsSafeSourceTruthActions(t *testing.T) { rows := &releasePlanRows{items: []releasePlanRow{ {publicationID: "tp-add", title: "B.pdf", targetScope: "external", action: "add", testState: "ready", productionState: "absent", canRelease: true}, {publicationID: "tp-delete", title: "C.pdf", targetScope: "internal", action: "delete", testState: "not_required", productionState: "present", canRelease: true, blocker: ""}, {publicationID: "", title: "D.pdf", targetScope: "internal", action: "blocked", testState: "not_ready", productionState: "absent", canRelease: false, blocker: "test_not_ready"}, {publicationID: "tp-same", title: "E.pdf", targetScope: "internal", action: "unchanged", testState: "ready", productionState: "present", canRelease: false}, }} db := &recordingDB{rows: rows} plan, err := NewStore(db).ListReleasePlan(context.Background()) if err != nil { t.Fatal(err) } if plan.Summary.Add != 1 || plan.Summary.Delete != 1 || plan.Summary.Blocked != 1 || plan.Summary.Unchanged != 1 { t.Fatalf("plan=%#v", plan) } if len(plan.Items) != 3 || !plan.Items[0].CanRelease || !plan.Items[1].CanRelease || plan.Items[1].PublicationID != "tp-delete" { t.Fatalf("items=%#v", plan.Items) } if db.querySQL != listReleasePlanSQL { t.Fatalf("query=%q", db.querySQL) } sql := strings.ToLower(db.querySQL) for _, required := range []string{"coalesce(test.publication_id, production.publication_id, '')", "action in ('add', 'update', 'delete')"} { if !strings.Contains(sql, required) { t.Fatalf("release plan SQL missing %q", required) } } } type releasePlanRow struct { publicationID string title string targetScope string action string testState string productionState string canRelease bool blocker string } func (row releasePlanRow) Scan(dest ...any) error { *(dest[0].(*string)) = row.publicationID *(dest[1].(*string)) = row.title *(dest[2].(*string)) = row.targetScope *(dest[3].(*string)) = row.action *(dest[4].(*string)) = row.testState *(dest[5].(*string)) = row.productionState *(dest[6].(*bool)) = row.canRelease *(dest[7].(*string)) = row.blocker return nil } type releasePlanRows struct { items []releasePlanRow index int } func (rows *releasePlanRows) Close() {} func (rows *releasePlanRows) Err() error { return nil } func (rows *releasePlanRows) CommandTag() pgconn.CommandTag { return pgconn.CommandTag{} } func (rows *releasePlanRows) FieldDescriptions() []pgconn.FieldDescription { return nil } func (rows *releasePlanRows) Next() bool { if rows.index >= len(rows.items) { return false } rows.index++ return true } func (rows *releasePlanRows) Scan(dest ...any) error { return rows.items[rows.index-1].Scan(dest...) } func (rows *releasePlanRows) Values() ([]any, error) { return nil, errors.New("not implemented") } func (rows *releasePlanRows) RawValues() [][]byte { return nil } func (rows *releasePlanRows) Conn() *pgx.Conn { return nil } var _ pgx.Rows = (*releasePlanRows)(nil) var _ = time.Time{} var _ governance.ReleasePlan