75 lines
2.0 KiB
Go
75 lines
2.0 KiB
Go
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)
|
||
|
|
}
|
||
|
|
}
|