package events import ( "sync" "sync/atomic" "testing" ) // Every subscriber gets every event, in the order they subscribed. func TestPublish(t *testing.T) { var bus Bus var got []string for _, name := range []string{"first", "second"} { bus.Subscribe(func(e Event) { got = append(got, name+":"+e.Type) }) } bus.Publish(Event{ Type: "a", }) bus.Publish(Event{ Type: "b", }) want := []string{"first:a", "second:a", "first:b", "second:b"} if len(got) != len(want) { t.Fatalf("got %v; want %v", got, want) } for i := range want { if got[i] != want[i] { t.Fatalf("got %v; want %v", got, want) } } } // Publishing with no subscribers does nothing. func TestPublishNoSubscribers(t *testing.T) { var bus Bus bus.Publish(Event{ Type: OpportunitiesUpdated, }) } // A handler may subscribe or publish without deadlocking. func TestHandlerReenters(t *testing.T) { var bus Bus var inner atomic.Int32 bus.Subscribe(func(e Event) { if e.Type == "outer" { bus.Subscribe(func(Event) { inner.Add(1) }) bus.Publish(Event{ Type: "inner", }) } }) bus.Publish(Event{ Type: "outer", }) if inner.Load() != 1 { t.Errorf("inner handler ran %d times; want 1", inner.Load()) } } // Publish and Subscribe are safe from several goroutines at once (run with // -race). func TestConcurrent(t *testing.T) { var bus Bus var count atomic.Int32 var wg sync.WaitGroup for range 10 { wg.Add(2) go func() { defer wg.Done() bus.Subscribe(func(Event) { count.Add(1) }) }() go func() { defer wg.Done() bus.Publish(Event{ Type: "x", }) }() } wg.Wait() }