//go:build integration package postgresadmin import ( "context" "fmt" "os" "sync" "sync/atomic" "testing" "time" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgxpool" "proxy-pool/internal/domain/adminstate" ) var postgresTestSchemaSequence atomic.Uint64 type postgresTestFixture struct { Store adminstate.Store Pool *pgxpool.Pool Schema string Cleanup func() } func newPostgresTestFixture(t *testing.T) postgresTestFixture { t.Helper() postgresURL := os.Getenv("PROXY_POOL_TEST_POSTGRES_URL") if postgresURL == "" { t.Skip("PROXY_POOL_TEST_POSTGRES_URL is not set") } ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() adminConfig, err := pgxpool.ParseConfig(postgresURL) if err != nil { t.Fatalf("parse PROXY_POOL_TEST_POSTGRES_URL: %v", err) } adminPool, err := pgxpool.NewWithConfig(ctx, adminConfig) if err != nil { t.Fatalf("connect test PostgreSQL: %v", err) } if err := adminPool.Ping(ctx); err != nil { adminPool.Close() t.Fatalf("ping test PostgreSQL: %v", err) } schema := fmt.Sprintf("it_%d_%d_%d", os.Getpid(), time.Now().UnixNano(), postgresTestSchemaSequence.Add(1)) quotedSchema := pgx.Identifier{schema}.Sanitize() if _, err := adminPool.Exec(ctx, "CREATE SCHEMA "+quotedSchema); err != nil { adminPool.Close() t.Fatalf("create isolated PostgreSQL schema: %v", err) } testConfig, err := pgxpool.ParseConfig(postgresURL) if err != nil { adminPool.Close() t.Fatalf("parse isolated PostgreSQL config: %v", err) } testConfig.ConnConfig.RuntimeParams["search_path"] = schema testPool, err := pgxpool.NewWithConfig(ctx, testConfig) if err != nil { _, _ = adminPool.Exec(context.Background(), "DROP SCHEMA "+quotedSchema+" CASCADE") adminPool.Close() t.Fatalf("connect isolated PostgreSQL schema: %v", err) } if err := ApplyMigrations(ctx, testPool); err != nil { testPool.Close() _, _ = adminPool.Exec(context.Background(), "DROP SCHEMA "+quotedSchema+" CASCADE") adminPool.Close() t.Fatalf("apply PostgreSQL migrations: %v", err) } store, err := New(testPool) if err != nil { testPool.Close() _, _ = adminPool.Exec(context.Background(), "DROP SCHEMA "+quotedSchema+" CASCADE") adminPool.Close() t.Fatalf("construct PostgreSQL adapter: %v", err) } var cleanupOnce sync.Once cleanup := func() { cleanupOnce.Do(func() { testPool.Close() cleanupCtx, cleanupCancel := context.WithTimeout(context.Background(), 10*time.Second) defer cleanupCancel() if _, err := adminPool.Exec(cleanupCtx, "DROP SCHEMA "+quotedSchema+" CASCADE"); err != nil { t.Errorf("drop isolated PostgreSQL schema: %v", err) } adminPool.Close() }) } t.Cleanup(cleanup) return postgresTestFixture{Store: store, Pool: testPool, Schema: schema, Cleanup: cleanup} }