package postgresadmin_test import ( "context" "errors" "strings" "sync/atomic" "testing" "time" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgconn" "github.com/jackc/pgx/v5/pgxpool" "proxy-pool/internal/adapters/postgresadmin" "proxy-pool/internal/domain/adminstate" ) func TestNewRejectsNilPool(t *testing.T) { t.Parallel() store, err := postgresadmin.New(nil) if store != nil { t.Fatalf("New(nil) store = %T, want nil", store) } if !errors.Is(err, adminstate.ErrInvalidCommand) { t.Fatalf("New(nil) error = %v, want ErrInvalidCommand", err) } } func TestNewRejectsTypedNilPool(t *testing.T) { t.Parallel() var pool *pgxpool.Pool store, err := postgresadmin.New(pool) if store != nil || !errors.Is(err, adminstate.ErrInvalidCommand) { t.Fatalf("New(typed nil) = %T, %v, want nil, ErrInvalidCommand", store, err) } } func TestOperationsPrioritizeCanceledContext(t *testing.T) { t.Parallel() pool := &countingPool{} store, err := postgresadmin.New(pool) if err != nil { t.Fatalf("New(): %v", err) } ctx, cancel := context.WithCancel(context.Background()) cancel() operations := []struct { name string run func() error }{ {name: "commit config", run: func() error { _, operationErr := store.CommitConfig(ctx, adminstate.CommitConfigCommand{}) return operationErr }}, {name: "set upstream", run: func() error { _, operationErr := store.SetUpstreamEnabled(ctx, adminstate.SetUpstreamCommand{}) return operationErr }}, {name: "switch routing", run: func() error { _, operationErr := store.SwitchRouting(ctx, adminstate.SwitchRoutingCommand{}) return operationErr }}, {name: "disable routing", run: func() error { _, operationErr := store.DisableRouting(ctx, adminstate.DisableRoutingCommand{}) return operationErr }}, {name: "snapshot", run: func() error { _, operationErr := store.Snapshot(ctx) return operationErr }}, {name: "read audit", run: func() error { _, operationErr := store.ReadAudit(ctx, adminstate.AuditQuery{}) return operationErr }}, {name: "claim", run: func() error { _, operationErr := store.Claim(ctx, adminstate.ClaimCommand{}) return operationErr }}, {name: "acknowledge", run: func() error { return store.Acknowledge(ctx, adminstate.AcknowledgeCommand{}) }}, } for _, operation := range operations { operation := operation t.Run(operation.name, func(t *testing.T) { if operationErr := operation.run(); !errors.Is(operationErr, context.Canceled) { t.Fatalf("operation error = %v, want context.Canceled", operationErr) } }) } if begins := pool.begins.Load(); begins != 0 { t.Fatalf("BeginTx calls = %d, want 0", begins) } } func TestInvalidOperationsDoNotBeginTransaction(t *testing.T) { t.Parallel() pool := &countingPool{} store, err := postgresadmin.New(pool) if err != nil { t.Fatalf("New(): %v", err) } operations := []struct { name string run func() error }{ {name: "commit config", run: func() error { _, operationErr := store.CommitConfig(context.Background(), adminstate.CommitConfigCommand{}) return operationErr }}, {name: "set upstream", run: func() error { _, operationErr := store.SetUpstreamEnabled(context.Background(), adminstate.SetUpstreamCommand{}) return operationErr }}, {name: "switch routing", run: func() error { _, operationErr := store.SwitchRouting(context.Background(), adminstate.SwitchRoutingCommand{}) return operationErr }}, {name: "disable routing", run: func() error { _, operationErr := store.DisableRouting(context.Background(), adminstate.DisableRoutingCommand{}) return operationErr }}, {name: "read audit", run: func() error { _, operationErr := store.ReadAudit(context.Background(), adminstate.AuditQuery{}) return operationErr }}, {name: "claim", run: func() error { _, operationErr := store.Claim(context.Background(), adminstate.ClaimCommand{}) return operationErr }}, {name: "acknowledge", run: func() error { return store.Acknowledge(context.Background(), adminstate.AcknowledgeCommand{}) }}, } for _, operation := range operations { operation := operation t.Run(operation.name, func(t *testing.T) { if operationErr := operation.run(); !errors.Is(operationErr, adminstate.ErrInvalidCommand) { t.Fatalf("operation error = %v, want ErrInvalidCommand", operationErr) } }) } if begins := pool.begins.Load(); begins != 0 { t.Fatalf("BeginTx calls = %d, want 0", begins) } } func TestDatabaseErrorsAreMappedAndRedacted(t *testing.T) { t.Parallel() tests := []struct { name string err error want error }{ { name: "connection", err: errors.New("postgres://admin:secret@database/private SQL payload"), want: adminstate.ErrUnavailable, }, { name: "unique constraint", err: &pgconn.PgError{ Code: "23505", Message: "duplicate cfg-sensitive at postgres://admin:secret@database", }, want: adminstate.ErrConflict, }, { name: "foreign key constraint", err: &pgconn.PgError{ Code: "23503", Message: "backend revision reference failed with secret details", }, want: adminstate.ErrUnavailable, }, { name: "check constraint", err: &pgconn.PgError{ Code: "23514", Message: "backend invariant failed with secret details", }, want: adminstate.ErrUnavailable, }, { name: "value too long", err: &pgconn.PgError{ Code: "22001", Message: "backend encoding failed with secret details", }, want: adminstate.ErrUnavailable, }, } for _, test := range tests { test := test t.Run(test.name, func(t *testing.T) { t.Parallel() store, err := postgresadmin.New(&errorPool{err: test.err}) if err != nil { t.Fatalf("New(): %v", err) } _, operationErr := store.CommitConfig(context.Background(), validConfigCommand()) if !errors.Is(operationErr, test.want) { t.Fatalf("CommitConfig() error = %v, want %v", operationErr, test.want) } for _, secret := range []string{"secret", "private SQL", "cfg-sensitive", "postgres://"} { if strings.Contains(operationErr.Error(), secret) { t.Fatalf("CommitConfig() error leaked %q: %v", secret, operationErr) } } }) } } type countingPool struct { begins atomic.Int64 } func (pool *countingPool) BeginTx(context.Context, pgx.TxOptions) (pgx.Tx, error) { pool.begins.Add(1) return nil, errors.New("unexpected transaction") } type errorPool struct { err error } func (pool *errorPool) BeginTx(context.Context, pgx.TxOptions) (pgx.Tx, error) { return nil, pool.err } func validConfigCommand() adminstate.CommitConfigCommand { return adminstate.CommitConfigCommand{ RequestID: "request-a", Actor: adminstate.Actor{ID: "admin-a", SourceIP: "192.0.2.10"}, OccurredAt: time.Date(2026, 7, 30, 10, 0, 0, 0, time.UTC), ConfigVersion: "cfg-sensitive", Checksum: strings.Repeat("a", adminstate.SHA256HexBytes), Source: "configs/proxy-pool.yaml", } }