test(backend): gate testcontainers tests behind VEZA_SKIP_INTEGRATION

The Forgejo runner doesn't expose /var/run/docker.sock, so anything
relying on testcontainers-go panicked with "Cannot connect to the
Docker daemon". This caused internal/testutils, tests/transactions
and tests/integration to fail wholesale, plus internal/handlers
to hit the 5min hard timeout while waiting for container startup.

Approach (least invasive):
- testutils.GetTestContainerDB short-circuits when VEZA_SKIP_INTEGRATION=1
  is set, returning a sentinel error immediately instead of attempting
  three retries against a missing Docker socket.
- Add testutils.SkipIfNoIntegration helper for granular per-test skips.
- Add TestMain to internal/testutils, tests/transactions and
  tests/integration packages that os.Exit(0) when the env var is set,
  so the entire integration-only package is silently skipped in CI.
- Wire the helper into the three setupTestDB* functions in
  tests/transactions/ for local runs (where TestMain doesn't fire when
  using -run on individual tests).

Local nightly runs / dev workstations leave VEZA_SKIP_INTEGRATION unset
and exercise the full suite against testcontainers as before.
This commit is contained in:
senke 2026-04-14 11:45:19 +02:00
parent 15b29f6620
commit f84dbf5c66
8 changed files with 98 additions and 1 deletions

View file

@ -0,0 +1,21 @@
package testutils
import (
"fmt"
"os"
"testing"
)
// TestMain skips the entire testutils test suite when integration prerequisites
// (Docker daemon for testcontainers) are unavailable. The testutils package's own
// tests exercise SetupTestDB and CleanupDatabaseWithOptions which require a real
// Postgres container, so there is nothing meaningful to run without it.
//
// CI sets VEZA_SKIP_INTEGRATION=1 on runners without /var/run/docker.sock.
func TestMain(m *testing.M) {
if os.Getenv("VEZA_SKIP_INTEGRATION") == "1" {
fmt.Println("testutils: skipping package (VEZA_SKIP_INTEGRATION=1)")
os.Exit(0)
}
os.Exit(m.Run())
}

View file

@ -26,9 +26,17 @@ var (
// GetTestContainerDB ensures the postgres container is running and returns the DSN.
// It uses a singleton pattern to start the container only once per test run.
// If DATABASE_URL is set (e.g. CI with real PostgreSQL), uses it instead of testcontainer.
//
// Resolution order:
// 1. VEZA_SKIP_INTEGRATION=1 → return an error immediately (CI runners w/o Docker)
// 2. DATABASE_URL set → use it directly (CI with a sidecar Postgres service)
// 3. Otherwise → start a postgres testcontainer (local dev / nightly job)
func GetTestContainerDB(ctx context.Context) (string, error) {
containerOnce.Do(func() {
if os.Getenv("VEZA_SKIP_INTEGRATION") == "1" {
pgErr = fmt.Errorf("integration tests skipped: VEZA_SKIP_INTEGRATION=1")
return
}
if dsn := os.Getenv("DATABASE_URL"); dsn != "" {
pgDSN = dsn
pgErr = nil

View file

@ -0,0 +1,23 @@
package testutils
import (
"os"
"testing"
)
// SkipIfNoIntegration skips the current test when integration prerequisites
// (notably a running Docker daemon for testcontainers-go) are unavailable.
//
// It honors:
// - `go test -short` (testing.Short())
// - VEZA_SKIP_INTEGRATION=1 environment variable (set by CI runners
// without Docker socket access)
//
// Call this at the very top of any test helper that relies on
// GetTestContainerDB or otherwise spins up Postgres via testcontainers.
func SkipIfNoIntegration(t *testing.T) {
t.Helper()
if testing.Short() || os.Getenv("VEZA_SKIP_INTEGRATION") == "1" {
t.Skip("integration test requires Docker; skipped (-short or VEZA_SKIP_INTEGRATION=1)")
}
}

View file

@ -0,0 +1,21 @@
package integration
import (
"fmt"
"os"
"testing"
)
// TestMain skips the entire integration test suite when Docker is unavailable
// (no /var/run/docker.sock). Integration tests rely on testcontainers for
// Postgres, Redis, etc., and have no meaningful behavior without them.
//
// Set by CI: VEZA_SKIP_INTEGRATION=1 on Forgejo runners that don't expose
// the Docker socket. Local dev / nightly jobs leave it unset.
func TestMain(m *testing.M) {
if os.Getenv("VEZA_SKIP_INTEGRATION") == "1" {
fmt.Println("integration: skipping package (VEZA_SKIP_INTEGRATION=1)")
os.Exit(0)
}
os.Exit(m.Run())
}

View file

@ -0,0 +1,21 @@
package transactions
import (
"fmt"
"os"
"testing"
)
// TestMain skips the entire transactions test suite when Docker is unavailable.
// All tests in this package rely on testcontainers-go to spin up a real Postgres
// container so transactional rollback semantics can be validated.
//
// Set by CI: VEZA_SKIP_INTEGRATION=1 on Forgejo runners that don't expose
// the Docker socket. Local dev / nightly jobs leave it unset.
func TestMain(m *testing.M) {
if os.Getenv("VEZA_SKIP_INTEGRATION") == "1" {
fmt.Println("transactions: skipping package (VEZA_SKIP_INTEGRATION=1)")
os.Exit(0)
}
os.Exit(m.Run())
}

View file

@ -19,6 +19,7 @@ import (
// setupTestDB crée une DB de test avec testcontainers
func setupTestDBForPlaylist(t *testing.T) *gorm.DB {
testutils.SkipIfNoIntegration(t)
ctx := context.Background()
dsn, err := testutils.GetTestContainerDB(ctx)
require.NoError(t, err, "Failed to setup test database")

View file

@ -19,6 +19,7 @@ import (
// setupTestDB crée une DB de test avec testcontainers
func setupTestDB(t *testing.T) *gorm.DB {
testutils.SkipIfNoIntegration(t)
ctx := context.Background()
dsn, err := testutils.GetTestContainerDB(ctx)
require.NoError(t, err, "Failed to setup test database")

View file

@ -18,6 +18,7 @@ import (
// setupTestDB crée une DB de test avec testcontainers
func setupTestDBForSocial(t *testing.T) *gorm.DB {
testutils.SkipIfNoIntegration(t)
ctx := context.Background()
dsn, err := testutils.GetTestContainerDB(ctx)
require.NoError(t, err, "Failed to setup test database")