test: RequestManager observable assertions and ReqSendFailed subtest
This commit is contained in:
+91
-6
@@ -1,6 +1,7 @@
|
||||
package prism
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.wisehodl.dev/jay/go-roots-ws"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
@@ -78,7 +79,8 @@ func TestRequestManager_Options(t *testing.T) {
|
||||
|
||||
func TestRequestManager_Stream(t *testing.T) {
|
||||
t.Run("sends req when connected", func(t *testing.T) {
|
||||
p, envoy := newMockEnvoy(t)
|
||||
obs := &mockObserver{}
|
||||
p, envoy := newMockEnvoy(t, WithEmbassyObserver(obs))
|
||||
|
||||
p.connect()
|
||||
Eventually(t, envoy.IsConnected, "envoy should be connected")
|
||||
@@ -104,6 +106,12 @@ func TestRequestManager_Stream(t *testing.T) {
|
||||
}, "expected REQ send")
|
||||
|
||||
assert.Equal(t, []byte(envelope.EncloseReq(id, filters)), got)
|
||||
|
||||
Eventually(t, func() bool {
|
||||
return len(EventsOf[ReqDispatched](obs)) == 1
|
||||
}, "expected ReqDispatched observable")
|
||||
dispatched := EventsOf[ReqDispatched](obs)
|
||||
assert.Equal(t, id, dispatched[0].SubID)
|
||||
})
|
||||
|
||||
t.Run("does not send req when disconnected", func(t *testing.T) {
|
||||
@@ -130,7 +138,8 @@ func TestRequestManager_Stream(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("forwards events to caller", func(t *testing.T) {
|
||||
p, envoy := newMockEnvoy(t)
|
||||
obs := &mockObserver{}
|
||||
p, envoy := newMockEnvoy(t, WithEmbassyObserver(obs))
|
||||
p.connect()
|
||||
Eventually(t, envoy.IsConnected, "envoy should be connected")
|
||||
|
||||
@@ -172,10 +181,18 @@ func TestRequestManager_Stream(t *testing.T) {
|
||||
assert.Len(t, got, 2)
|
||||
assert.Equal(t, eventA, got[0].Data)
|
||||
assert.Equal(t, eventB, got[1].Data)
|
||||
|
||||
Eventually(t, func() bool {
|
||||
return len(EventsOf[FirstEventReceived](obs)) == 1
|
||||
}, "expected FirstEventReceived observable")
|
||||
first := EventsOf[FirstEventReceived](obs)
|
||||
assert.Equal(t, id, first[0].SubID)
|
||||
assert.False(t, first[0].ReceivedAt.IsZero())
|
||||
})
|
||||
|
||||
t.Run("ignores eose", func(t *testing.T) {
|
||||
p, envoy := newMockEnvoy(t)
|
||||
obs := &mockObserver{}
|
||||
p, envoy := newMockEnvoy(t, WithEmbassyObserver(obs))
|
||||
p.connect()
|
||||
Eventually(t, envoy.IsConnected, "envoy should be connected")
|
||||
|
||||
@@ -225,10 +242,17 @@ func TestRequestManager_Stream(t *testing.T) {
|
||||
return false
|
||||
}
|
||||
}, "expected event after eose")
|
||||
|
||||
Eventually(t, func() bool {
|
||||
return len(EventsOf[StreamEOSEReceived](obs)) == 1
|
||||
}, "expected StreamEOSEReceived observable")
|
||||
eoseEvents := EventsOf[StreamEOSEReceived](obs)
|
||||
assert.Equal(t, id, eoseEvents[0].SubID)
|
||||
})
|
||||
|
||||
t.Run("closed deregisters and signals caller", func(t *testing.T) {
|
||||
p, envoy := newMockEnvoy(t)
|
||||
obs := &mockObserver{}
|
||||
p, envoy := newMockEnvoy(t, WithEmbassyObserver(obs))
|
||||
p.connect()
|
||||
Eventually(t, envoy.IsConnected, "envoy should be connected")
|
||||
|
||||
@@ -261,6 +285,13 @@ func TestRequestManager_Stream(t *testing.T) {
|
||||
}, "expected closed signal")
|
||||
assert.Equal(t, "error: test", got.Data)
|
||||
|
||||
Eventually(t, func() bool {
|
||||
return len(EventsOf[ClosedReceived](obs)) == 1
|
||||
}, "expected ClosedReceived observable")
|
||||
closedEvents := EventsOf[ClosedReceived](obs)
|
||||
assert.Equal(t, id, closedEvents[0].SubID)
|
||||
assert.Equal(t, "error: test", closedEvents[0].Message)
|
||||
|
||||
Eventually(t, func() bool {
|
||||
select {
|
||||
case _, ok := <-events:
|
||||
@@ -284,6 +315,47 @@ func TestRequestManager_Stream(t *testing.T) {
|
||||
m.mu.RUnlock()
|
||||
assert.False(t, ok, "registration should be removed from reqs")
|
||||
})
|
||||
|
||||
t.Run("send failure recorded", func(t *testing.T) {
|
||||
obs := &mockObserver{}
|
||||
p, envoy := newMockEnvoy(t, WithEmbassyObserver(obs))
|
||||
|
||||
p.connect()
|
||||
Eventually(t, envoy.IsConnected, "envoy should be connected")
|
||||
|
||||
m := NewRequestManager(envoy)
|
||||
t.Cleanup(func() { m.Close() })
|
||||
|
||||
// disconnect, arm send error, reconnect so the send attempt
|
||||
// happens after the error is in place
|
||||
p.disconnect()
|
||||
p.setSendError(errors.New("send failed"))
|
||||
p.connect()
|
||||
Eventually(t, envoy.IsConnected, "envoy should be reconnected")
|
||||
|
||||
// prevent activate() race between Stream and on-connect handler
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
|
||||
filters := [][]byte{[]byte(`{}`)}
|
||||
id, _, _, err := m.Stream(filters)
|
||||
assert.NoError(t, err)
|
||||
|
||||
Eventually(t, func() bool {
|
||||
return len(EventsOf[ReqSendFailed](obs)) == 1
|
||||
}, "expected ReqSendFailed observable")
|
||||
failed := EventsOf[ReqSendFailed](obs)
|
||||
assert.Equal(t, id, failed[0].SubID)
|
||||
assert.NotNil(t, failed[0].Err)
|
||||
|
||||
Never(t, func() bool {
|
||||
select {
|
||||
case <-p.sent:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}, "no REQ envelope should have been sent")
|
||||
})
|
||||
}
|
||||
|
||||
func TestRequestManager_Cancel(t *testing.T) {
|
||||
@@ -377,7 +449,8 @@ func TestRequestManager_Cancel(t *testing.T) {
|
||||
|
||||
func TestRequestManager_Query(t *testing.T) {
|
||||
t.Run("returns events and nil closed on eose", func(t *testing.T) {
|
||||
p, envoy := newMockEnvoy(t)
|
||||
obs := &mockObserver{}
|
||||
p, envoy := newMockEnvoy(t, WithEmbassyObserver(obs))
|
||||
p.connect()
|
||||
Eventually(t, envoy.IsConnected, "envoy should be connected")
|
||||
|
||||
@@ -387,6 +460,7 @@ func TestRequestManager_Query(t *testing.T) {
|
||||
filters := [][]byte{[]byte(`{}`)}
|
||||
eventData := []byte(`{"id":"abc"}`)
|
||||
|
||||
var querySubID string
|
||||
go func() {
|
||||
// wait for the REQ to arrive, extract the sub ID
|
||||
reqBytes := <-p.sent
|
||||
@@ -395,6 +469,7 @@ func TestRequestManager_Query(t *testing.T) {
|
||||
t.Errorf("FindReq: %v", err)
|
||||
return
|
||||
}
|
||||
querySubID = subID
|
||||
// inject three EVENTs then EOSE
|
||||
for range 3 {
|
||||
raw := envelope.EncloseSubscriptionEvent(subID, eventData)
|
||||
@@ -409,6 +484,12 @@ func TestRequestManager_Query(t *testing.T) {
|
||||
assert.Len(t, events, 3)
|
||||
assert.Nil(t, closed)
|
||||
|
||||
Eventually(t, func() bool {
|
||||
return len(EventsOf[QueryEOSEReceived](obs)) == 1
|
||||
}, "expected QueryEOSEReceived observable")
|
||||
qeose := EventsOf[QueryEOSEReceived](obs)
|
||||
assert.Equal(t, querySubID, qeose[0].SubID)
|
||||
|
||||
// CLOSE envelope should have been sent after EOSE
|
||||
var closeEnv []byte
|
||||
select {
|
||||
@@ -451,7 +532,8 @@ func TestRequestManager_Query(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("returns partial events on timeout", func(t *testing.T) {
|
||||
p, envoy := newMockEnvoy(t)
|
||||
obs := &mockObserver{}
|
||||
p, envoy := newMockEnvoy(t, WithEmbassyObserver(obs))
|
||||
p.connect()
|
||||
Eventually(t, envoy.IsConnected, "envoy should be connected")
|
||||
|
||||
@@ -483,6 +565,9 @@ func TestRequestManager_Query(t *testing.T) {
|
||||
assert.GreaterOrEqual(t, elapsed, queryTimeout)
|
||||
assert.Len(t, events, 2)
|
||||
assert.Nil(t, closed)
|
||||
|
||||
missed := EventsOf[MissedEOSE](obs)
|
||||
assert.Len(t, missed, 1)
|
||||
})
|
||||
|
||||
t.Run("connects within timeout and returns events", func(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user