Files
RenewCMS/test/activity_recorder_test.go

109 lines
3.6 KiB
Go

package test
import (
"RenewCMS/internal/domain/audit"
"strings"
"testing"
"time"
)
func TestActivityRecorder(t *testing.T) {
t.Run("A failing repository does not fail the caller and the failure is logged", func(t *testing.T) {
h := newActivityHarness(t)
h.probe.appendErr = errDiskFull
h.recorder.Record(testCtx, activityValidEvent())
logs := h.logs.String()
if !strings.Contains(logs, "audit.test") || !strings.Contains(logs, "disk full") {
t.Errorf("expected a log line naming the write and the error, got %q", logs)
}
})
t.Run("A panicking repository does not crash the caller", func(t *testing.T) {
h := newActivityHarness(t)
h.probe.appendPanic = true
h.recorder.Record(testCtx, activityValidEvent())
if !strings.Contains(h.logs.String(), "panicked") {
t.Errorf("expected the panic to be logged, got %q", h.logs.String())
}
})
t.Run("The recorder fills the event from the audit context", func(t *testing.T) {
h := newActivityHarness(t)
h.now = time.Date(2026, time.October, 6, 14, 0, 0, 0, time.FixedZone("CEST", 2*3600))
ctx := audit.WithOrigin(testCtx, audit.Origin{
Actor: audit.Actor{Type: audit.ActorUser, ID: activityPtr(uint32(3)), Name: "marta"},
Source: audit.SourceWeb,
IP: "203.0.113.12",
UserAgent: "Mozilla/5.0 test",
})
event := audit.NewEvent("audit.test", audit.CategorySystem)
h.recorder.Record(ctx, event)
stored := h.all(t)
if len(stored) != 1 {
t.Fatalf("expected one event, got %d", len(stored))
}
got := stored[0]
if got.Actor.Type != audit.ActorUser || *got.Actor.ID != 3 || got.Actor.Name != "marta" || got.Source != audit.SourceWeb {
t.Errorf("unexpected actor or source %+v", got)
}
if got.IP == nil || *got.IP != "203.0.113.12" || got.UserAgent == nil || *got.UserAgent != "Mozilla/5.0 test" {
t.Errorf("unexpected ip or user agent %v %v", got.IP, got.UserAgent)
}
if !got.CreatedAt.Equal(h.now) || got.CreatedAt.Location() != time.UTC {
t.Errorf("expected created_at %v in UTC, got %v", h.now.UTC(), got.CreatedAt)
}
})
t.Run("Values already on the event are kept", func(t *testing.T) {
h := newActivityHarness(t)
ctx := audit.WithOrigin(testCtx, audit.Origin{Actor: audit.AnonymousActor("x"), Source: audit.SourceWeb, IP: "203.0.113.12", UserAgent: "ua"})
event := audit.NewEvent(audit.ActionCleanup, audit.CategorySystem)
event.Actor = audit.SystemActor()
event.Source = audit.SourceSystem
h.recorder.Record(ctx, event)
got := h.all(t)[0]
if got.Actor.Type != audit.ActorSystem || got.Source != audit.SourceSystem {
t.Errorf("the explicit actor and source must win, got %+v", got)
}
})
t.Run("An event outside the vocabulary is dropped and logged", func(t *testing.T) {
h := newActivityHarness(t)
event := activityValidEvent()
event.Category = "billing"
h.recorder.Record(testCtx, event)
if len(h.all(t)) != 0 || !strings.Contains(h.logs.String(), "dropped") {
t.Errorf("expected nothing stored and a log line, got %q", h.logs.String())
}
})
t.Run("Long names are bounded", func(t *testing.T) {
h := newActivityHarness(t)
event := activityValidEvent()
event.Target = audit.Target{Type: "article", ID: "1", Name: strings.Repeat("é", 400)}
h.recorder.Record(testCtx, event)
if got := h.all(t); len(got) != 1 || len([]rune(got[0].Target.Name)) != 255 {
t.Errorf("expected one event with a 255 character target name, got %+v", got)
}
})
}
func activityValidEvent() audit.Event {
event := audit.NewEvent("audit.test", audit.CategorySystem)
event.Actor = audit.SystemActor()
event.Source = audit.SourceSystem
return event
}