package testhelper import ( "context" "fmt" "os" "time" "github.com/flowy-live/llink/internal/utils/flog" "github.com/golang-migrate/migrate/v4" _ "github.com/golang-migrate/migrate/v4/database/postgres" _ "github.com/golang-migrate/migrate/v4/source/file" "github.com/jackc/pgx/v5/pgxpool" "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/modules/postgres" "github.com/testcontainers/testcontainers-go/wait" ) var ( container *postgres.PostgresContainer dbPool *pgxpool.Pool ctx = context.Background() ) // SetupTestDB starts a PostgreSQL container and returns a connection pool func SetupTestDB() *pgxpool.Pool { var err error // Start PostgreSQL container container, err = postgres.Run(ctx, "postgres:16-alpine", postgres.WithDatabase("testdb"), postgres.WithUsername("postgres"), postgres.WithPassword("testpassword"), testcontainers.WithWaitStrategy( wait.ForLog("database system is ready to accept connections"). WithOccurrence(2). WithStartupTimeout(60*time.Second), ), ) if err != nil { flog.Error("failed to start postgres container", "error", err) os.Exit(1) } // Get connection URL host, err := container.Host(ctx) if err != nil { flog.Error("failed to get container host", "error", err) os.Exit(1) } port, err := container.MappedPort(ctx, "5432") if err != nil { flog.Error("failed to get container port", "error", err) os.Exit(1) } connectionURL := fmt.Sprintf("postgres://postgres:testpassword@%s:%s/testdb?sslmode=disable", host, port.Port()) // Run migrations m, err := migrate.New("file://../../migrations", connectionURL) if err != nil { flog.Error("failed to create migrate instance", "error", err) os.Exit(1) } defer m.Close() if err := m.Up(); err != nil && err != migrate.ErrNoChange { flog.Error("failed to run migrations", "error", err) os.Exit(1) } // Create connection pool dbPool, err = pgxpool.New(ctx, connectionURL) if err != nil { flog.Error("failed to create connection pool", "error", err) os.Exit(1) } return dbPool } // TeardownTestDB cleans up the test database func TeardownTestDB() { if dbPool != nil { dbPool.Close() } if container != nil { if err := container.Terminate(ctx); err != nil { flog.Error("failed to terminate container", "error", err) } } }