package audit import ( "context" "fmt" "os" "testing" "time" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgxpool" ) func TestAuditEventFollowsBusinessTransaction(t *testing.T) { databaseURL := os.Getenv("TEST_DATABASE_URL") if databaseURL == "" { t.Skip("TEST_DATABASE_URL is not set") } ctx := context.Background() pool, err := pgxpool.New(ctx, databaseURL) if err != nil { t.Fatal(err) } defer pool.Close() repository := NewRepository() tenantID := "10000000-0000-0000-0000-000000000001" actorID := "10000000-0000-0000-0000-000000000111" resourceID := "10000000-0000-0000-0000-000000000211" requestID := fmt.Sprintf("audit-integration-%d", time.Now().UnixNano()) event := Event{ TenantID: &tenantID, ActorType: "user", ActorPublicID: &actorID, Action: "household.read", ResourceType: "household", ResourceID: &resourceID, RequestID: requestID, Purpose: "integration-test", Result: "success", Detail: map[string]any{"synthetic": true}, } rolledBackTx, err := pool.BeginTx(ctx, pgx.TxOptions{}) if err != nil { t.Fatal(err) } if err := repository.Record(ctx, rolledBackTx, event); err != nil { t.Fatal(err) } if err := rolledBackTx.Rollback(ctx); err != nil { t.Fatal(err) } assertAuditCount(t, pool, requestID, 0) committedTx, err := pool.BeginTx(ctx, pgx.TxOptions{}) if err != nil { t.Fatal(err) } if err := repository.Record(ctx, committedTx, event); err != nil { t.Fatal(err) } if err := committedTx.Commit(ctx); err != nil { t.Fatal(err) } assertAuditCount(t, pool, requestID, 1) if _, err := pool.Exec(ctx, `DELETE FROM audit_event WHERE request_id = $1`, requestID); err != nil { t.Fatal(err) } } func assertAuditCount(t *testing.T, pool *pgxpool.Pool, requestID string, expected int) { t.Helper() var count int if err := pool.QueryRow(context.Background(), `SELECT count(*) FROM audit_event WHERE request_id = $1`, requestID).Scan(&count); err != nil { t.Fatal(err) } if count != expected { t.Fatalf("audit count = %d, want %d", count, expected) } }