diff --git a/.gitea/workflows/handlers-postgres-integration.yml b/.gitea/workflows/handlers-postgres-integration.yml index 21f6e0a96..a62b822f5 100644 --- a/.gitea/workflows/handlers-postgres-integration.yml +++ b/.gitea/workflows/handlers-postgres-integration.yml @@ -253,6 +253,19 @@ jobs: echo "✓ $tbl table present" done + - if: needs.detect-changes.outputs.handlers == 'true' + name: Preflight — INTEGRATION_DB_URL must be present + run: | + # Belt-and-suspenders: if the postgres-start step failed to + # export INTEGRATION_DB_URL, fail loud BEFORE go test can + # t.Skip its way to a green build. Closes the workflow-level + # fail-open gap identified in PR #2166 blocker #2. + if [ -z "${INTEGRATION_DB_URL:-}" ]; then + echo "::error::INTEGRATION_DB_URL is empty — postgres-start step did not export the connection string" + exit 1 + fi + echo "INTEGRATION_DB_URL is set" + - if: needs.detect-changes.outputs.handlers == 'true' name: Run integration tests run: | diff --git a/workspace-server/internal/handlers/delegation_ledger_integration_test.go b/workspace-server/internal/handlers/delegation_ledger_integration_test.go index 97da5a524..fb0bf85e7 100644 --- a/workspace-server/internal/handlers/delegation_ledger_integration_test.go +++ b/workspace-server/internal/handlers/delegation_ledger_integration_test.go @@ -36,7 +36,6 @@ package handlers import ( "context" "database/sql" - "os" "strings" "testing" "time" @@ -57,10 +56,7 @@ import ( // directly rather than going through the package global. func integrationDB(t *testing.T) *sql.DB { t.Helper() - url := os.Getenv("INTEGRATION_DB_URL") - if url == "" { - t.Skip("INTEGRATION_DB_URL not set; skipping (local devs: see file header)") - } + url := requireIntegrationDBURL(t) conn, err := sql.Open("postgres", url) if err != nil { t.Fatalf("open: %v", err) diff --git a/workspace-server/internal/handlers/integration_helper_test.go b/workspace-server/internal/handlers/integration_helper_test.go new file mode 100644 index 000000000..e3d99b858 --- /dev/null +++ b/workspace-server/internal/handlers/integration_helper_test.go @@ -0,0 +1,40 @@ +//go:build integration +// +build integration + +// integration_helper_test.go — shared preflight for handler Postgres +// integration tests. Extracted so the fail-open/skip logic is in ONE place +// and can be tightened without editing every integration test file. +// +// See delegation_ledger_integration_test.go for the docker-postgres setup +// incantation used by local devs. + +package handlers + +import ( + "os" + "testing" +) + +// requireIntegrationDBURL returns $INTEGRATION_DB_URL. +// +// In CI (CI, GITHUB_ACTIONS, or GITEA_ACTIONS env var is non-empty), an +// empty URL is a fatal error — it means the workflow failed to export the +// variable (postgres container did not start, bridge IP resolution failed, +// or a regression in the workflow YAML). t.Fatalf keeps the test red so the +// failure is visible; t.Skip would silently pass and mask the defect. +// +// Locally (none of the three CI markers set), an empty URL skips the test +// so devs can run `go test ./...` without booting a Postgres container. +func requireIntegrationDBURL(t *testing.T) string { + t.Helper() + url := os.Getenv("INTEGRATION_DB_URL") + if url == "" { + if os.Getenv("CI") != "" || + os.Getenv("GITHUB_ACTIONS") != "" || + os.Getenv("GITEA_ACTIONS") != "" { + t.Fatalf("INTEGRATION_DB_URL required in CI handler integration tests — check workflow env export") + } + t.Skip("INTEGRATION_DB_URL not set; skipping (local devs: see file header)") + } + return url +} diff --git a/workspace-server/internal/handlers/pending_uploads_integration_test.go b/workspace-server/internal/handlers/pending_uploads_integration_test.go index 0e0d74fcd..a16704596 100644 --- a/workspace-server/internal/handlers/pending_uploads_integration_test.go +++ b/workspace-server/internal/handlers/pending_uploads_integration_test.go @@ -43,7 +43,6 @@ package handlers import ( "context" "database/sql" - "os" "strings" "testing" "time" @@ -63,10 +62,7 @@ import ( // but kept separate so each table's wipe step is local to its tests. func integrationDB_PendingUploads(t *testing.T) *sql.DB { t.Helper() - url := os.Getenv("INTEGRATION_DB_URL") - if url == "" { - t.Skip("INTEGRATION_DB_URL not set; skipping (local devs: see file header)") - } + url := requireIntegrationDBURL(t) conn, err := sql.Open("postgres", url) if err != nil { t.Fatalf("open: %v", err) diff --git a/workspace-server/internal/handlers/workspace_create_name_integration_test.go b/workspace-server/internal/handlers/workspace_create_name_integration_test.go index f0cc8b289..77c94e312 100644 --- a/workspace-server/internal/handlers/workspace_create_name_integration_test.go +++ b/workspace-server/internal/handlers/workspace_create_name_integration_test.go @@ -41,7 +41,6 @@ import ( "context" "database/sql" "fmt" - "os" "testing" "github.com/google/uuid" @@ -59,10 +58,7 @@ import ( // only those. func integrationDB_WorkspaceCreateName(t *testing.T) *sql.DB { t.Helper() - url := os.Getenv("INTEGRATION_DB_URL") - if url == "" { - t.Skip("INTEGRATION_DB_URL not set; skipping (see file header)") - } + url := requireIntegrationDBURL(t) conn, err := sql.Open("postgres", url) if err != nil { t.Fatalf("open: %v", err)