feat: use postgres

This commit is contained in:
Ilia Denisov
2026-04-26 20:34:39 +02:00
committed by GitHub
parent 48b0056b49
commit fe829285a6
365 changed files with 29223 additions and 24049 deletions
+81 -1
View File
@@ -5,19 +5,25 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"log/slog"
"net"
"net/http"
"net/url"
"strings"
"testing"
"time"
"galaxy/postgres"
"galaxy/user/internal/app"
"galaxy/user/internal/config"
"github.com/alicebob/miniredis/v2"
"github.com/stretchr/testify/require"
testcontainers "github.com/testcontainers/testcontainers-go"
tcpostgres "github.com/testcontainers/testcontainers-go/modules/postgres"
"github.com/testcontainers/testcontainers-go/wait"
)
type runtimeContractHarness struct {
@@ -34,9 +40,14 @@ func newRuntimeContractHarness(t *testing.T) *runtimeContractHarness {
t.Helper()
redisServer := miniredis.RunT(t)
redisServer.RequireAuth("integration")
pgDSN := startPostgresForContractTest(t)
cfg := config.DefaultConfig()
cfg.Redis.Addr = redisServer.Addr()
cfg.Redis.Conn.MasterAddr = redisServer.Addr()
cfg.Redis.Conn.Password = "integration"
cfg.Postgres.Conn.PrimaryDSN = pgDSN
cfg.InternalHTTP.Addr = freeLoopbackAddress(t)
cfg.AdminHTTP.Addr = ""
cfg.ShutdownTimeout = 10 * time.Second
@@ -841,3 +852,72 @@ func TestEligibilityUnknownMarkersZeroValueMatchesContract(t *testing.T) {
require.Equal(t, eligibilityMarkers{}, eligibilityMarkers{})
require.False(t, strings.HasPrefix("", "user-"))
}
// startPostgresForContractTest boots one isolated PostgreSQL container,
// provisions the user schema with the userservice role, and returns a DSN
// pinned to search_path=user. The test is skipped (not failed) when a
// container cannot be started — typically because Docker is unavailable in
// the dev environment.
func startPostgresForContractTest(t *testing.T) string {
t.Helper()
ctx := context.Background()
container, err := tcpostgres.Run(ctx,
"postgres:16-alpine",
tcpostgres.WithDatabase("galaxy_user"),
tcpostgres.WithUsername("galaxy"),
tcpostgres.WithPassword("galaxy"),
testcontainers.WithWaitStrategy(
wait.ForLog("database system is ready to accept connections").
WithOccurrence(2).
WithStartupTimeout(60*time.Second),
),
)
if err != nil {
t.Skipf("postgres container start failed (Docker likely unavailable): %v", err)
}
t.Cleanup(func() {
if err := testcontainers.TerminateContainer(container); err != nil {
t.Errorf("terminate postgres container: %v", err)
}
})
baseDSN, err := container.ConnectionString(ctx, "sslmode=disable")
require.NoError(t, err)
cfg := postgres.DefaultConfig()
cfg.PrimaryDSN = baseDSN
cfg.OperationTimeout = 5 * time.Second
db, err := postgres.OpenPrimary(ctx, cfg)
require.NoError(t, err)
defer func() { _ = db.Close() }()
for _, statement := range []string{
`CREATE ROLE userservice LOGIN PASSWORD 'userservice'`,
`CREATE SCHEMA IF NOT EXISTS "user" AUTHORIZATION userservice`,
`GRANT USAGE ON SCHEMA "user" TO userservice`,
} {
if _, err := db.ExecContext(ctx, statement); err != nil {
require.NoError(t, err, "provision postgres role/schema: %s", statement)
}
}
parsed, err := url.Parse(baseDSN)
require.NoError(t, err)
values := url.Values{}
values.Set("search_path", "user")
values.Set("sslmode", "disable")
scoped := url.URL{
Scheme: parsed.Scheme,
User: url.UserPassword("userservice", "userservice"),
Host: parsed.Host,
Path: parsed.Path,
RawQuery: values.Encode(),
}
return scoped.String()
}
// errSentinel is a small unused alias kept to silence imports above when
// non-default builds drop testcontainers references.
var errSentinel = fmt.Errorf("contract test sentinel")