ultisuite-backend/internal/integrationtest/containers.go
R3D347HR4Y fa5394e10d feat(tests): add integration testing framework and configuration
- Introduced a new `.env.test.example` file for integration test configuration.
- Added a `Makefile` to streamline test commands for unit and integration tests.
- Implemented an integration testing harness with support for PostgreSQL, MinIO, and Redis using testcontainers.
- Created a suite of integration tests covering health checks and user management functionalities.
- Enhanced CI workflow to include integration tests with necessary environment variables.
2026-06-07 19:44:29 +02:00

119 lines
2.7 KiB
Go

//go:build integration
package integrationtest
import (
"context"
"fmt"
"strings"
"time"
"github.com/alicebob/miniredis/v2"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/minio"
"github.com/testcontainers/testcontainers-go/modules/postgres"
"github.com/testcontainers/testcontainers-go/wait"
)
type infra struct {
pgContainer testcontainers.Container
minioContainer testcontainers.Container
miniredis *miniredis.Miniredis
dbURL string
s3Endpoint string
s3AccessKey string
s3SecretKey string
redisAddr string
}
func sharedInfra(ctx context.Context, env Env) (*infra, error) {
return startInfra(ctx, env)
}
func startInfra(ctx context.Context, env Env) (*infra, error) {
out := &infra{
dbURL: env.DBURL,
s3Endpoint: env.S3Endpoint,
s3AccessKey: env.S3AccessKey,
s3SecretKey: env.S3SecretKey,
redisAddr: env.RedisAddr,
}
if out.dbURL == "" {
pg, err := postgres.Run(ctx,
"postgres:16-alpine",
postgres.WithDatabase("ultidb_test"),
postgres.WithUsername("ulti"),
postgres.WithPassword("test"),
testcontainers.WithWaitStrategy(
wait.ForLog("database system is ready to accept connections").
WithOccurrence(2).
WithStartupTimeout(60*time.Second),
),
)
if err != nil {
return nil, fmt.Errorf("postgres container: %w", err)
}
out.pgContainer = pg
connStr, err := pg.ConnectionString(ctx, "sslmode=disable")
if err != nil {
return nil, fmt.Errorf("postgres connection string: %w", err)
}
out.dbURL = connStr
}
if out.redisAddr == "" {
mr, err := miniredis.Run()
if err != nil {
return nil, fmt.Errorf("miniredis: %w", err)
}
out.miniredis = mr
out.redisAddr = mr.Addr()
}
if out.s3Endpoint == "" {
m, err := minio.Run(ctx,
"minio/minio:latest",
minio.WithUsername(env.S3AccessKey),
minio.WithPassword(env.S3SecretKey),
)
if err != nil {
return nil, fmt.Errorf("minio container: %w", err)
}
out.minioContainer = m
host, err := m.ConnectionString(ctx)
if err != nil {
return nil, fmt.Errorf("minio endpoint: %w", err)
}
out.s3Endpoint = host
}
if out.s3AccessKey == "" {
out.s3AccessKey = "ultiadmin"
}
if out.s3SecretKey == "" {
out.s3SecretKey = "changeme123"
}
return out, nil
}
func (i *infra) Close(ctx context.Context) {
if i == nil {
return
}
if i.miniredis != nil {
i.miniredis.Close()
}
if i.pgContainer != nil {
_ = i.pgContainer.Terminate(ctx)
}
if i.minioContainer != nil {
_ = i.minioContainer.Terminate(ctx)
}
}
func normalizeEndpoint(endpoint string) string {
return strings.TrimPrefix(strings.TrimPrefix(endpoint, "http://"), "https://")
}