ZDDC/zddc/internal/handler/logring_test.go
2026-06-11 13:32:31 -05:00

133 lines
3.2 KiB
Go

package handler
import (
"context"
"log/slog"
"strings"
"testing"
"time"
)
func TestLogRingChronological(t *testing.T) {
r := NewLogRing(3)
// Push 5 entries; the oldest 2 should be evicted.
for i := 0; i < 5; i++ {
r.push(LogEntry{
Time: time.Unix(int64(i), 0).UTC(),
Level: "INFO",
Message: "msg",
Attrs: map[string]any{"i": i},
})
}
snap := r.Snapshot()
if len(snap) != 3 {
t.Fatalf("len(snap) = %d, want 3", len(snap))
}
for i, e := range snap {
wantI := i + 2 // 2,3,4
if got := e.Attrs["i"]; got != wantI {
t.Errorf("snap[%d].Attrs.i = %v, want %d", i, got, wantI)
}
}
}
func TestLogRingEmpty(t *testing.T) {
r := NewLogRing(5)
if got := r.Snapshot(); len(got) != 0 {
t.Errorf("empty ring snapshot len = %d, want 0", len(got))
}
}
func TestLogRingPartialFill(t *testing.T) {
r := NewLogRing(10)
for i := 0; i < 3; i++ {
r.push(LogEntry{Message: "x", Attrs: map[string]any{"i": i}})
}
if got := r.Snapshot(); len(got) != 3 {
t.Errorf("partial-fill snapshot len = %d, want 3", len(got))
}
}
func TestRingHandlerCapturesRecord(t *testing.T) {
ring := NewLogRing(10)
h := NewRingHandler(ring, slog.LevelInfo)
logger := slog.New(h)
logger.Info("hello", "user", "alice", "n", 7)
snap := ring.Snapshot()
if len(snap) != 1 {
t.Fatalf("len(snap) = %d, want 1", len(snap))
}
e := snap[0]
if e.Message != "hello" {
t.Errorf("message = %q, want %q", e.Message, "hello")
}
if e.Level != slog.LevelInfo.String() {
t.Errorf("level = %q, want %q", e.Level, slog.LevelInfo.String())
}
if e.Attrs["user"] != "alice" {
t.Errorf("attrs.user = %v, want alice", e.Attrs["user"])
}
if e.Attrs["n"] != int64(7) {
t.Errorf("attrs.n = %v (%T), want int64(7)", e.Attrs["n"], e.Attrs["n"])
}
}
func TestRingHandlerLevelFilter(t *testing.T) {
ring := NewLogRing(10)
h := NewRingHandler(ring, slog.LevelWarn)
logger := slog.New(h)
logger.Debug("d")
logger.Info("i")
logger.Warn("w")
logger.Error("e")
snap := ring.Snapshot()
if len(snap) != 2 {
t.Fatalf("len(snap) = %d, want 2 (warn+error)", len(snap))
}
if snap[0].Message != "w" || snap[1].Message != "e" {
t.Errorf("messages = [%q %q], want [w e]", snap[0].Message, snap[1].Message)
}
}
func TestMultiHandlerFansOut(t *testing.T) {
ring := NewLogRing(10)
rh := NewRingHandler(ring, slog.LevelDebug)
var buf strings.Builder
th := slog.NewTextHandler(&buf, &slog.HandlerOptions{Level: slog.LevelDebug})
multi := NewMultiHandler(th, rh)
logger := slog.New(multi)
logger.Info("teed", "a", 1)
if !strings.Contains(buf.String(), "teed") {
t.Errorf("text handler did not receive: %q", buf.String())
}
snap := ring.Snapshot()
if len(snap) != 1 || snap[0].Message != "teed" {
t.Errorf("ring did not receive: %+v", snap)
}
}
func TestMultiHandlerEnabled(t *testing.T) {
ring := NewLogRing(10)
rhInfo := NewRingHandler(ring, slog.LevelInfo)
rhError := NewRingHandler(ring, slog.LevelError)
multi := NewMultiHandler(rhInfo, rhError)
// Multi.Enabled should be true if ANY child is enabled.
if !multi.Enabled(context.Background(), slog.LevelInfo) {
t.Error("Enabled(Info) = false; expected true (rhInfo accepts it)")
}
if multi.Enabled(context.Background(), slog.LevelDebug) {
t.Error("Enabled(Debug) = true; expected false (no child accepts it)")
}
}