//go:build integration package postgresadmin import ( "context" "errors" "strings" "testing" "time" "proxy-pool/internal/domain/adminstate" ) func TestMutationRollsBackWhenAuditInsertFails(t *testing.T) { fixture := newPostgresTestFixture(t) now := integrationNow() commitIntegrationConfig(t, fixture.Store, now) installRejectInsertTrigger(t, fixture, "admin_audit_log", "reject_admin_audit") _, err := fixture.Store.SetUpstreamEnabled(context.Background(), adminstate.SetUpstreamCommand{ RequestID: "req-audit-failure", Actor: integrationActor(), OccurredAt: now.Add(time.Second), Name: "provider-a", Enabled: false, }) if !errors.Is(err, adminstate.ErrUnavailable) { t.Fatalf("SetUpstreamEnabled(audit failure) error = %v, want ErrUnavailable", err) } assertFailedMutationLeftBaseline(t, fixture) dropRejectInsertTrigger(t, fixture, "admin_audit_log", "reject_admin_audit") result, err := fixture.Store.SetUpstreamEnabled(context.Background(), adminstate.SetUpstreamCommand{ RequestID: "req-after-audit-failure", Actor: integrationActor(), OccurredAt: now.Add(2 * time.Second), Name: "provider-a", Enabled: false, }) if err != nil || !result.Changed || result.Revision != 2 { t.Fatalf("SetUpstreamEnabled(after rollback) = %+v, %v", result, err) } } func TestMutationRollsBackWhenOutboxInsertFails(t *testing.T) { fixture := newPostgresTestFixture(t) now := integrationNow() commitIntegrationConfig(t, fixture.Store, now) installRejectInsertTrigger(t, fixture, "admin_outbox", "reject_admin_outbox") _, err := fixture.Store.SetUpstreamEnabled(context.Background(), adminstate.SetUpstreamCommand{ RequestID: "req-outbox-failure", Actor: integrationActor(), OccurredAt: now.Add(time.Second), Name: "provider-a", Enabled: false, }) if !errors.Is(err, adminstate.ErrUnavailable) { t.Fatalf("SetUpstreamEnabled(outbox failure) error = %v, want ErrUnavailable", err) } assertFailedMutationLeftBaseline(t, fixture) dropRejectInsertTrigger(t, fixture, "admin_outbox", "reject_admin_outbox") result, err := fixture.Store.SetUpstreamEnabled(context.Background(), adminstate.SetUpstreamCommand{ RequestID: "req-after-outbox-failure", Actor: integrationActor(), OccurredAt: now.Add(2 * time.Second), Name: "provider-a", Enabled: false, }) if err != nil || !result.Changed || result.Revision != 2 { t.Fatalf("SetUpstreamEnabled(after rollback) = %+v, %v", result, err) } } func assertFailedMutationLeftBaseline(t *testing.T, fixture postgresTestFixture) { t.Helper() snapshot, err := fixture.Store.Snapshot(context.Background()) if err != nil || snapshot.Revision != 1 || !integrationUpstreamEnabled(snapshot, "provider-a") { t.Fatalf("Snapshot(after failed mutation) = %+v, %v", snapshot, err) } audits, err := fixture.Store.ReadAudit(context.Background(), adminstate.AuditQuery{Limit: 10}) if err != nil || len(audits) != 1 { t.Fatalf("ReadAudit(after failed mutation) = %+v, %v", audits, err) } for table, want := range map[string]int{"control_revisions": 1, "admin_outbox": 1} { var count int if err := fixture.Pool.QueryRow(context.Background(), "SELECT COUNT(*) FROM "+table).Scan(&count); err != nil { t.Fatalf("count %s: %v", table, err) } if count != want { t.Fatalf("%s row count = %d, want %d", table, count, want) } } } func installRejectInsertTrigger(t *testing.T, fixture postgresTestFixture, table, trigger string) { t.Helper() function := trigger + "_fn" statement := "CREATE FUNCTION " + function + `() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN RAISE EXCEPTION 'injected management write failure'; END $$; CREATE TRIGGER ` + trigger + " BEFORE INSERT ON " + table + " FOR EACH ROW EXECUTE FUNCTION " + function + "()" if _, err := fixture.Pool.Exec(context.Background(), statement); err != nil { t.Fatalf("install %s trigger: %v", trigger, err) } } func dropRejectInsertTrigger(t *testing.T, fixture postgresTestFixture, table, trigger string) { t.Helper() statement := "DROP TRIGGER " + trigger + " ON " + table + "; DROP FUNCTION " + trigger + "_fn()" if _, err := fixture.Pool.Exec(context.Background(), statement); err != nil { t.Fatalf("drop %s trigger: %v", trigger, err) } } func commitIntegrationConfig(t *testing.T, store adminstate.Store, now time.Time) { t.Helper() result, err := store.CommitConfig(context.Background(), adminstate.CommitConfigCommand{ RequestID: "req-config", Actor: integrationActor(), OccurredAt: now, ConfigVersion: "cfg-1", Checksum: strings.Repeat("a", adminstate.SHA256HexBytes), Source: "configs/proxy-pool.yaml", Upstreams: []adminstate.UpstreamDefinition{ {Name: "provider-a", Enabled: true}, {Name: "provider-b", Enabled: true}, }, Routings: []adminstate.RoutingDefinition{{ Name: "checkout", Enabled: true, Upstreams: []string{"provider-a", "provider-b"}, CurrentUpstream: "provider-a", }}, }) if err != nil || !result.Changed || result.Revision != 1 { t.Fatalf("CommitConfig() = %+v, %v", result, err) } } func integrationActor() adminstate.Actor { return adminstate.Actor{ID: "admin-a", SourceIP: "192.0.2.10"} } func integrationNow() time.Time { return time.Date(2026, 7, 30, 10, 0, 0, 0, time.UTC) } func integrationUpstreamEnabled(snapshot adminstate.Snapshot, name string) bool { for _, upstream := range snapshot.Upstreams { if upstream.Name == name { return upstream.Enabled } } return false }