Files
2026-07-13 13:00:08 +08:00

77 lines
1.8 KiB
Go

package serve
import (
"encoding/json"
"strings"
"testing"
"reasonix/internal/event"
"reasonix/internal/eventwire"
)
func TestBroadcasterFanOut(t *testing.T) {
b := NewBroadcaster()
a, ca := b.Subscribe()
d, cd := b.Subscribe()
defer ca()
defer cd()
if got := b.Subscribers(); got != 2 {
t.Fatalf("subscribers = %d, want 2", got)
}
b.Emit(event.Event{Kind: event.Text, Text: "hi"})
for i, ch := range []<-chan []byte{a, d} {
var w eventwire.Event
if err := json.Unmarshal(<-ch, &w); err != nil {
t.Fatalf("subscriber %d: %v", i, err)
}
if w.Kind != "text" || w.Text != "hi" {
t.Errorf("subscriber %d got %+v", i, w)
}
}
}
func TestBroadcasterEmitsRetryingJSON(t *testing.T) {
b := NewBroadcaster()
ch, cancel := b.Subscribe()
defer cancel()
b.Emit(event.Event{Kind: event.Retrying, RetryAttempt: 3, RetryMax: 10})
s := string(<-ch)
for _, want := range []string{`"kind":"retrying"`, `"retryAttempt":3`, `"retryMax":10`} {
if !strings.Contains(s, want) {
t.Fatalf("retrying broadcast JSON = %s, want it to contain %s", s, want)
}
}
}
func TestBroadcasterUnsubscribe(t *testing.T) {
b := NewBroadcaster()
_, cancel := b.Subscribe()
if b.Subscribers() != 1 {
t.Fatalf("want 1 subscriber")
}
cancel()
if b.Subscribers() != 0 {
t.Fatalf("unsubscribe should drop to 0, got %d", b.Subscribers())
}
// Emitting with no subscribers must not panic.
b.Emit(event.Event{Kind: event.TurnDone})
}
func TestBroadcasterDropsSlowSubscriber(t *testing.T) {
b := NewBroadcaster()
ch, cancel := b.Subscribe()
defer cancel()
// Overfill far past the 64-slot buffer without reading; Emit must not block.
for i := 0; i < 1000; i++ {
b.Emit(event.Event{Kind: event.Text, Text: "x"})
}
if len(ch) == 0 {
t.Error("expected some buffered frames")
}
}