116 lines
3.0 KiB
Go
116 lines
3.0 KiB
Go
package postgres_test
|
|
|
|
import (
|
|
"context"
|
|
"embed"
|
|
"io/fs"
|
|
"testing"
|
|
"time"
|
|
|
|
"galaxy/postgres"
|
|
|
|
testcontainers "github.com/testcontainers/testcontainers-go"
|
|
tcpostgres "github.com/testcontainers/testcontainers-go/modules/postgres"
|
|
"github.com/testcontainers/testcontainers-go/wait"
|
|
)
|
|
|
|
const smokeImage = "postgres:16-alpine"
|
|
|
|
//go:embed testdata/migrations/*.sql
|
|
var smokeMigrationsFS embed.FS
|
|
|
|
func TestPostgresPackageRoundTrip(t *testing.T) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
|
t.Cleanup(cancel)
|
|
|
|
pgContainer, err := tcpostgres.Run(ctx,
|
|
smokeImage,
|
|
tcpostgres.WithDatabase("galaxy_smoke"),
|
|
tcpostgres.WithUsername("galaxy_smoke"),
|
|
tcpostgres.WithPassword("galaxy_smoke"),
|
|
// The Postgres image emits "ready to accept connections" twice during
|
|
// startup: once for the temporary bootstrap instance, once for the real
|
|
// listener on the mapped port. Waiting for the second occurrence
|
|
// prevents racing the bootstrap.
|
|
testcontainers.WithWaitStrategy(
|
|
wait.ForLog("database system is ready to accept connections").
|
|
WithOccurrence(2).
|
|
WithStartupTimeout(60*time.Second),
|
|
),
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("start postgres container: %v", err)
|
|
}
|
|
t.Cleanup(func() {
|
|
if err := testcontainers.TerminateContainer(pgContainer); err != nil {
|
|
t.Errorf("terminate postgres container: %v", err)
|
|
}
|
|
})
|
|
|
|
dsn, err := pgContainer.ConnectionString(ctx, "sslmode=disable")
|
|
if err != nil {
|
|
t.Fatalf("postgres connection string: %v", err)
|
|
}
|
|
|
|
cfg := postgres.DefaultConfig()
|
|
cfg.PrimaryDSN = dsn
|
|
cfg.OperationTimeout = 5 * time.Second
|
|
|
|
db, err := postgres.OpenPrimary(ctx, cfg)
|
|
if err != nil {
|
|
t.Fatalf("open primary: %v", err)
|
|
}
|
|
t.Cleanup(func() {
|
|
if err := db.Close(); err != nil {
|
|
t.Errorf("close db: %v", err)
|
|
}
|
|
})
|
|
|
|
if err := postgres.Ping(ctx, db, cfg.OperationTimeout); err != nil {
|
|
t.Fatalf("ping: %v", err)
|
|
}
|
|
|
|
migrationsDir, err := fs.Sub(smokeMigrationsFS, "testdata/migrations")
|
|
if err != nil {
|
|
t.Fatalf("sub migrations FS: %v", err)
|
|
}
|
|
if err := postgres.RunMigrations(ctx, db, migrationsDir, "."); err != nil {
|
|
t.Fatalf("run migrations: %v", err)
|
|
}
|
|
|
|
var insertedID int64
|
|
if err := db.QueryRowContext(ctx,
|
|
"INSERT INTO smoke (note) VALUES ($1) RETURNING id", "hello",
|
|
).Scan(&insertedID); err != nil {
|
|
t.Fatalf("insert returning id: %v", err)
|
|
}
|
|
if insertedID <= 0 {
|
|
t.Fatalf("inserted id = %d, want > 0", insertedID)
|
|
}
|
|
|
|
var note string
|
|
if err := db.QueryRowContext(ctx,
|
|
"SELECT note FROM smoke WHERE id = $1", insertedID,
|
|
).Scan(¬e); err != nil {
|
|
t.Fatalf("select note: %v", err)
|
|
}
|
|
if note != "hello" {
|
|
t.Fatalf("note = %q, want %q", note, "hello")
|
|
}
|
|
}
|
|
|
|
func TestOpenReplicasReturnsNilWhenUnconfigured(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
cfg := postgres.DefaultConfig()
|
|
cfg.PrimaryDSN = "postgres://localhost:5432/galaxy?sslmode=disable"
|
|
|
|
dbs, err := postgres.OpenReplicas(context.Background(), cfg)
|
|
if err != nil {
|
|
t.Fatalf("open replicas: %v", err)
|
|
}
|
|
if dbs != nil {
|
|
t.Fatalf("replicas = %v, want nil", dbs)
|
|
}
|
|
}
|