Files
RenewCMS/test/activity_validation_test.go

93 lines
3.2 KiB
Go

package test
import (
"RenewCMS/internal/domain/audit"
"errors"
"net/http"
"strings"
"testing"
)
func validActivityEvent() audit.Event {
event := audit.NewEvent("article.publish", audit.CategoryArticles)
event.Source = audit.SourceWeb
event.Actor = audit.Actor{Type: audit.ActorUser, Name: "marta"}
return event
}
func TestActivityEventValidation(t *testing.T) {
long := func(n int) *string { value := strings.Repeat("x", n); return &value }
cases := []struct {
name string
mutate func(*audit.Event)
valid bool
}{
{"complete event", func(e *audit.Event) {}, true},
{"empty action", func(e *audit.Event) { e.Action = "" }, false},
{"action at the limit", func(e *audit.Event) { e.Action = strings.Repeat("a", 64) }, true},
{"action over the limit", func(e *audit.Event) { e.Action = strings.Repeat("a", 65) }, false},
{"unknown category", func(e *audit.Event) { e.Category = "nope" }, false},
{"unknown outcome", func(e *audit.Event) { e.Outcome = "nope" }, false},
{"unknown source", func(e *audit.Event) { e.Source = "nope" }, false},
{"unknown actor type", func(e *audit.Event) { e.Actor.Type = "nope" }, false},
{"failure reason at the limit", func(e *audit.Event) { e.FailureReason = long(255) }, true},
{"failure reason over the limit", func(e *audit.Event) { e.FailureReason = long(256) }, false},
{"unknown change kind", func(e *audit.Event) { e.Changes = []audit.Change{{Field: "a", Kind: "nope"}} }, false},
{"body change", func(e *audit.Event) { e.Changes = []audit.Change{{Field: "a", Kind: audit.ChangeBody}} }, true},
}
for _, c := range cases {
event := validActivityEvent()
c.mutate(&event)
err := event.Validate()
if c.valid && err != nil {
t.Errorf("%s: expected valid, got %v", c.name, err)
}
if !c.valid && !errors.Is(err, audit.ErrInvalidEvent) {
t.Errorf("%s: expected ErrInvalidEvent, got %v", c.name, err)
}
}
t.Run("Names are cut to 255 characters", func(t *testing.T) {
event := validActivityEvent()
event.Actor.Name = strings.Repeat("é", 256)
event.Target.Name = strings.Repeat("é", 255)
cut := event.Truncated()
if len([]rune(cut.Actor.Name)) != 255 || len([]rune(cut.Target.Name)) != 255 {
t.Errorf("unexpected lengths %d and %d", len([]rune(cut.Actor.Name)), len([]rune(cut.Target.Name)))
}
})
t.Run("The discard recorder accepts events silently", func(t *testing.T) {
audit.Discard.Record(testCtx, validActivityEvent())
})
}
func TestActivityHandlerErrorMapping(t *testing.T) {
t.Run("A signed-in user who no longer exists is unauthorised", func(t *testing.T) {
e := newActivityHTTPEnv(t, 1000)
rec := e.get("/v1/activity", asUser(e, 99))
if rec.Code != http.StatusUnauthorized {
t.Errorf("expected 401, got %d", rec.Code)
}
})
t.Run("A storage failure is a plain 500", func(t *testing.T) {
for _, path := range []string{"/v1/activity", "/v1/activity/summary", "/v1/activity/export"} {
e := newActivityHTTPEnv(t, 1000)
e.probe.readErr = errors.New("storage down")
rec := e.get(path, asUser(e, activityOwnerID))
if path != "/v1/activity/export" && rec.Code != http.StatusInternalServerError {
t.Errorf("%s: expected 500, got %d", path, rec.Code)
}
}
})
}