93 lines
3.2 KiB
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)
|
|
}
|
|
}
|
|
})
|
|
}
|