alby-hub/tests/mock_event_consumer.go
Roland 0b0cbbd985
fix: make event assertions in tests wait for async event consumption (#2531)
The mock event consumer waited a fixed 10ms before returning consumed
events, which was not always enough on slow CI runners and caused flaky
failures (e.g. TestMarkSettled_App_BudgetWarning missing its
nwc_budget_warning event). It also appended to the events slice from
concurrent goroutines without synchronization, a data race that could
drop events.

- guard the consumed events slice with a mutex and return copies
- add WaitForConsumedEvents which polls until the expected number of
  events arrived (up to 5s) instead of relying on a fixed sleep
- use it in tests that assert on consumed events; tests asserting that
  no event was published keep the short grace period
- normalize event order in the keysend self-payment test, matching the
  existing approach in the self-payment test, since async publishing
  does not guarantee ordering

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 14:48:41 +07:00

52 lines
1.4 KiB
Go

package tests
import (
"context"
"sync"
"time"
"github.com/getAlby/hub/events"
)
type mockEventConsumer struct {
mtx sync.Mutex
consumedEvents []*events.Event
}
func NewMockEventConsumer() *mockEventConsumer {
return &mockEventConsumer{
consumedEvents: []*events.Event{},
}
}
func (e *mockEventConsumer) ConsumeEvent(ctx context.Context, event *events.Event, globalProperties map[string]interface{}) {
e.mtx.Lock()
defer e.mtx.Unlock()
e.consumedEvents = append(e.consumedEvents, event)
}
func (e *mockEventConsumer) GetConsumedEvents() []*events.Event {
// events are consumed async - give it a bit of time for tests
time.Sleep(10 * time.Millisecond)
return e.snapshotConsumedEvents()
}
// WaitForConsumedEvents waits until at least count events have been consumed
// (events are consumed async) and returns them. On timeout it returns the
// events consumed so far, so the caller's assertions fail with a useful message.
func (e *mockEventConsumer) WaitForConsumedEvents(count int) []*events.Event {
deadline := time.Now().Add(5 * time.Second)
for {
consumedEvents := e.snapshotConsumedEvents()
if len(consumedEvents) >= count || time.Now().After(deadline) {
return consumedEvents
}
time.Sleep(10 * time.Millisecond)
}
}
func (e *mockEventConsumer) snapshotConsumedEvents() []*events.Event {
e.mtx.Lock()
defer e.mtx.Unlock()
return append([]*events.Event{}, e.consumedEvents...)
}