103 lines
2.7 KiB
Go
103 lines
2.7 KiB
Go
package testenv
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"testing"
|
|
|
|
"github.com/testcontainers/testcontainers-go"
|
|
)
|
|
|
|
// Platform aggregates a fully booted Galaxy stack: shared Docker
|
|
// network, Postgres, Redis, mailpit, backend and gateway. Tests use
|
|
// this struct to access HTTP/gRPC endpoints, mailpit and backend
|
|
// admin without touching testcontainers directly.
|
|
type Platform struct {
|
|
Network string
|
|
Postgres *Postgres
|
|
Redis *Redis
|
|
Mailpit *Mailpit
|
|
Backend *BackendContainer
|
|
Gateway *GatewayContainer
|
|
}
|
|
|
|
// BootstrapOptions tunes platform-level knobs that flow into backend
|
|
// or gateway configuration. The zero value is valid and produces a
|
|
// stack with sensible defaults for happy-path scenarios.
|
|
type BootstrapOptions struct {
|
|
BackendExtra map[string]string
|
|
GatewayExtra map[string]string
|
|
}
|
|
|
|
// Bootstrap builds three Docker images (backend, gateway, optionally
|
|
// the engine in the caller), spins up Postgres, Redis, mailpit, then
|
|
// boots backend and gateway connected to those services. It registers
|
|
// t.Cleanup hooks for every component, so callers do not own
|
|
// teardown.
|
|
//
|
|
// The function calls RequireDocker and skips the test gracefully if
|
|
// the daemon is unreachable, so every scenario can start with a
|
|
// single Bootstrap call.
|
|
func Bootstrap(t *testing.T, opts BootstrapOptions) *Platform {
|
|
t.Helper()
|
|
RequireDocker(t)
|
|
|
|
net := StartNetwork(t)
|
|
pg := StartPostgres(t, net.Name)
|
|
redis := StartRedis(t, net.Name)
|
|
mp := StartMailpit(t, net.Name)
|
|
geoip := SyntheticGeoIPDB(t)
|
|
|
|
backend := StartBackend(t, BackendOptions{
|
|
NetworkAlias: "backend",
|
|
NetworkName: net.Name,
|
|
PostgresDSN: pg.NetworkDSN,
|
|
MailpitHost: "mailpit",
|
|
MailpitPort: 1025,
|
|
GeoIPHostPath: geoip,
|
|
Extra: opts.BackendExtra,
|
|
})
|
|
gateway := StartGateway(t, GatewayOptions{
|
|
NetworkAlias: "gateway",
|
|
NetworkName: net.Name,
|
|
BackendHTTPURL: "http://backend:8080",
|
|
BackendGRPCURL: "backend:8081",
|
|
RedisAddr: "redis:6379",
|
|
Extra: opts.GatewayExtra,
|
|
})
|
|
|
|
plat := &Platform{
|
|
Network: net.Name,
|
|
Postgres: pg,
|
|
Redis: redis,
|
|
Mailpit: mp,
|
|
Backend: backend,
|
|
Gateway: gateway,
|
|
}
|
|
t.Cleanup(func() {
|
|
if !t.Failed() {
|
|
return
|
|
}
|
|
dumpLogs(t, "backend", backend.Container)
|
|
dumpLogs(t, "gateway", gateway.Container)
|
|
})
|
|
return plat
|
|
}
|
|
|
|
// dumpLogs writes the container's stdout/stderr to test output. Used
|
|
// only on failure to surface backend / gateway diagnostics.
|
|
func dumpLogs(t *testing.T, name string, c testcontainers.Container) {
|
|
t.Helper()
|
|
if c == nil {
|
|
return
|
|
}
|
|
rc, err := c.Logs(context.Background())
|
|
if err != nil {
|
|
t.Logf("%s logs unavailable: %v", name, err)
|
|
return
|
|
}
|
|
defer rc.Close()
|
|
body, _ := io.ReadAll(rc)
|
|
t.Logf("--- %s container logs ---\n%s", name, string(body))
|
|
}
|