fix flaky test TestHTTPNodeRPC

There is a race condition between subscribing and generating an event in
the test. The TestAPI now exposes the number of active subscriptions so
clients can ensure their subscription is active before calling the api.
This commit is contained in:
Marius Guggenmos 2024-07-30 21:58:52 +02:00
parent 6e33dbf96a
commit 33dbe85355

View file

@ -234,10 +234,11 @@ func (t *testService) Snapshot() ([]byte, error) {
// * get and increment a counter // * get and increment a counter
// * subscribe to counter increment events // * subscribe to counter increment events
type TestAPI struct { type TestAPI struct {
state *atomic.Value state *atomic.Value
peerCount *int64 peerCount *int64
counter int64 counter int64
feed event.Feed feed event.Feed
activeSubscriptions int64
} }
func (t *TestAPI) PeerCount() int64 { func (t *TestAPI) PeerCount() int64 {
@ -273,14 +274,17 @@ func (t *TestAPI) Events(ctx context.Context) (*rpc.Subscription, error) {
events := make(chan int64) events := make(chan int64)
sub := t.feed.Subscribe(events) sub := t.feed.Subscribe(events)
defer sub.Unsubscribe() defer sub.Unsubscribe()
atomic.AddInt64(&t.activeSubscriptions, 1)
for { for {
select { select {
case event := <-events: case event := <-events:
notifier.Notify(rpcSub.ID, event) notifier.Notify(rpcSub.ID, event)
case <-sub.Err(): case <-sub.Err():
atomic.AddInt64(&t.activeSubscriptions, -1)
return return
case <-rpcSub.Err(): case <-rpcSub.Err():
atomic.AddInt64(&t.activeSubscriptions, -1)
return return
} }
} }
@ -289,6 +293,10 @@ func (t *TestAPI) Events(ctx context.Context) (*rpc.Subscription, error) {
return rpcSub, nil return rpcSub, nil
} }
func (t *TestAPI) GetNumActiveSubscriptions() int64 {
return atomic.LoadInt64(&t.activeSubscriptions)
}
var testServices = adapters.LifecycleConstructors{ var testServices = adapters.LifecycleConstructors{
"test": newTestService, "test": newTestService,
} }
@ -557,6 +565,14 @@ func TestHTTPNodeRPC(t *testing.T) {
t.Fatalf("error getting node RPC client: %s", err) t.Fatalf("error getting node RPC client: %s", err)
} }
// get the number of subscriptions before subscribing to know what number to
// expect once it becomes active
var expectedActiveSubscriptions int64
if err := rpcClient1.CallContext(ctx, &expectedActiveSubscriptions, "test_getNumActiveSubscriptions"); err != nil {
t.Fatalf("error calling RPC method: %s", err)
}
expectedActiveSubscriptions += 1
// subscribe to events using client 1 // subscribe to events using client 1
events := make(chan int64, 1) events := make(chan int64, 1)
sub, err := rpcClient1.Subscribe(ctx, "test", events, "events") sub, err := rpcClient1.Subscribe(ctx, "test", events, "events")
@ -565,6 +581,22 @@ func TestHTTPNodeRPC(t *testing.T) {
} }
defer sub.Unsubscribe() defer sub.Unsubscribe()
// make sure the subscription becomes active
var numActiveSubscriptions int64
for i := 0; i < 3; i++ {
err := rpcClient1.CallContext(ctx, &numActiveSubscriptions, "test_getNumActiveSubscriptions")
if err != nil {
t.Fatalf("error calling RPC method: %s", err)
}
if numActiveSubscriptions > 0 {
break
}
time.Sleep(100 * time.Millisecond)
}
if numActiveSubscriptions != expectedActiveSubscriptions {
t.Fatalf("subscription never became active")
}
// call some RPC methods using client 2 // call some RPC methods using client 2
if err := rpcClient2.CallContext(ctx, nil, "test_add", 10); err != nil { if err := rpcClient2.CallContext(ctx, nil, "test_add", 10); err != nil {
t.Fatalf("error calling RPC method: %s", err) t.Fatalf("error calling RPC method: %s", err)