133 lines
3.2 KiB
Go
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)")
|
|
}
|
|
}
|