package events
import (
"time"
"testing"
"craftdesign.group/quarry/internal/evt"
)
// A WatchNoun subscriber wakes when a matching event is raised for its
// own repo and noun — the change signal the CI run page waits on
// instead of polling dagnats on a timer.
func TestWatchNounTicksOnMatchingRaise(t *testing.T) {
s := testServer(t)
ticks, cancel := s.WatchNoun("alpha", "ci")
defer cancel()
if err := s.Raise(evt.CIStarted, "alpha", map[string]any{"runId": "r1"}); err != nil {
t.Fatal(err)
}
select {
case <-ticks:
case <-time.After(3 * time.Second):
t.Fatal("no tick for a matching raise")
}
}
// A different noun in the same repo must not wake this watcher — the
// whole point of scoping the subscription is that a chat message does
// not push every open CI run page.
func TestWatchNounIgnoresAnotherNoun(t *testing.T) {
s := testServer(t)
ticks, cancel := s.WatchNoun("alpha", "ci")
defer cancel()
if err := s.Raise(evt.TicketOpened, "alpha", nil); err != nil {
t.Fatal(err)
}
select {
case <-ticks:
t.Fatal("ticked for a different noun")
case <-time.After(300 * time.Millisecond):
}
}
// Nor may a matching noun in another repository wake it — one poller's
// event must reach only the readers watching that repo.
func TestWatchNounIgnoresAnotherRepo(t *testing.T) {
s := testServer(t)
ticks, cancel := s.WatchNoun("alpha", "ci")
defer cancel()
if err := s.Raise(evt.CIStarted, "beta", map[string]any{"runId": "r1"}); err != nil {
t.Fatal(err)
}
select {
case <-ticks:
t.Fatal("ticked for another repo's event")
case <-time.After(300 * time.Millisecond):
}
}
// A subscribe failure — here forced by closing the connection first —
// must not leave the caller blocking on a channel that will never tick;
// the channel is closed instead.
func TestWatchNounClosesChannelOnSubscribeFailure(t *testing.T) {
s := testServer(t)
s.nc.Close() // the connection is gone; Subscribe must fail
ticks, cancel := s.WatchNoun("alpha", "ci")
defer cancel()
select {
case _, ok := <-ticks:
if ok {
t.Fatal("channel delivered a value instead of closing")
}
case <-time.After(2 * time.Second):
t.Fatal("channel neither ticked nor closed")
}
}