77 lines
2.3 KiB
Go
77 lines
2.3 KiB
Go
package aiaudit
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// Call metadata is attached in layers: the job sets company/user/job once, then
|
|
// each product narrows it. A later WithCall must not wipe what an outer scope set.
|
|
func TestWithCall_mergesWithoutClearing(t *testing.T) {
|
|
t.Parallel()
|
|
company, user, job, product := uuid.New(), uuid.New(), uuid.New(), uuid.New()
|
|
|
|
ctx := WithCall(context.Background(), CallContext{
|
|
CompanyID: company, UserID: user, JobID: job, Role: RoleProcessing,
|
|
})
|
|
ctx = WithCall(ctx, CallContext{RawProductID: product})
|
|
|
|
got := FromContext(ctx)
|
|
if got.CompanyID != company || got.UserID != user || got.JobID != job {
|
|
t.Fatalf("outer scope lost: %+v", got)
|
|
}
|
|
if got.RawProductID != product {
|
|
t.Fatalf("product not attached: %+v", got)
|
|
}
|
|
if got.Role != RoleProcessing {
|
|
t.Fatalf("role lost: %q", got.Role)
|
|
}
|
|
|
|
// A narrower scope may override the role (categorize inside a processing job).
|
|
ctx = WithCall(ctx, CallContext{Role: RoleCategorize})
|
|
if got := FromContext(ctx); got.Role != RoleCategorize || got.JobID != job {
|
|
t.Fatalf("role override broke context: %+v", got)
|
|
}
|
|
}
|
|
|
|
func TestFromContext_zeroValueWhenAbsent(t *testing.T) {
|
|
t.Parallel()
|
|
if got := FromContext(context.Background()); got != (CallContext{}) {
|
|
t.Fatalf("expected zero CallContext, got %+v", got)
|
|
}
|
|
//nolint:staticcheck // explicitly asserting the nil-ctx guard
|
|
if got := FromContext(nil); got != (CallContext{}) {
|
|
t.Fatalf("nil ctx must be safe, got %+v", got)
|
|
}
|
|
}
|
|
|
|
// Capture must never be able to take down the call it observes.
|
|
func TestRecorder_nilIsNoOp(t *testing.T) {
|
|
t.Parallel()
|
|
var r *Recorder
|
|
r.Record(context.Background(), Call{System: "x"}) // must not panic
|
|
if got := NewRecorder(nil); got != nil {
|
|
t.Fatal("nil pool must yield a nil (no-op) recorder")
|
|
}
|
|
}
|
|
|
|
// A runaway reply must not write an unbounded row.
|
|
func TestClamp_boundsBody(t *testing.T) {
|
|
t.Parallel()
|
|
short := strings.Repeat("a", 10)
|
|
if clamp(short) != short {
|
|
t.Fatal("short bodies must pass through unchanged")
|
|
}
|
|
long := strings.Repeat("b", maxBodyRunes+500)
|
|
got := clamp(long)
|
|
if len([]rune(got)) <= maxBodyRunes {
|
|
t.Fatalf("clamped body should keep the cap plus a marker, got %d runes", len([]rune(got)))
|
|
}
|
|
if !strings.HasSuffix(got, "[truncated by aiaudit]") {
|
|
t.Fatal("clamped body must say it was truncated")
|
|
}
|
|
}
|