package broker_test import ( "testing" "time" "github.com/uopi/uopi/internal/broker" ) // BenchmarkFanOut measures the end-to-end latency and throughput of the broker // fan-out with varying numbers of downstream clients. func BenchmarkFanOut1Client(b *testing.B) { benchFanOut(b, 1) } func BenchmarkFanOut10Clients(b *testing.B) { benchFanOut(b, 10) } func BenchmarkFanOut20Clients(b *testing.B) { benchFanOut(b, 20) } func BenchmarkFanOut100Clients(b *testing.B) { benchFanOut(b, 100) } func benchFanOut(b *testing.B, nClients int) { b.Helper() brk, cancel := newBroker(b) defer cancel() ref := broker.SignalRef{DS: "stub", Name: "counter_fast"} // Subscribe N downstream clients. type sub struct { ch chan broker.Update cancel func() } subs := make([]sub, nClients) for i := range subs { ch := make(chan broker.Update, 512) cancelFn, err := brk.Subscribe(ref, ch) if err != nil { b.Skip("signal not available:", err) } subs[i] = sub{ch, cancelFn} } defer func() { for _, s := range subs { s.cancel() } }() // Warm-up: wait for the first update to arrive on every client. timeout := time.After(3 * time.Second) for _, s := range subs { select { case <-s.ch: case <-timeout: b.Skip("timed out waiting for first update — signal may not exist in stub") } } b.ResetTimer() b.ReportAllocs() for range b.N { // Drain one update from every client channel. for _, s := range subs { select { case <-s.ch: case <-time.After(2 * time.Second): b.Fatal("timed out waiting for update") } } } } // newBroker is defined in broker_test.go (same package broker_test) and shared // across test files. It returns a broker pre-populated with the stub DS. // BenchmarkSubscribeUnsubscribe measures the overhead of adding and removing // a subscription (the fast path — signal is already active). func BenchmarkSubscribeUnsubscribe(b *testing.B) { brk, cancel := newBroker(b) defer cancel() ref := broker.SignalRef{DS: "stub", Name: "sine_1hz"} // Prime the signal so the fanOut goroutine exists. ch0 := make(chan broker.Update, 256) unsub0, err := brk.Subscribe(ref, ch0) if err != nil { b.Fatal(err) } defer unsub0() b.ResetTimer() b.ReportAllocs() for range b.N { ch := make(chan broker.Update, 16) unsub, err := brk.Subscribe(ref, ch) if err != nil { b.Fatal(err) } unsub() } }