Refactored package structure.
This commit is contained in:
134
transport/connection_close_test.go
Normal file
134
transport/connection_close_test.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"git.wisehodl.dev/jay/go-honeybee/honeybeetest"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDisconnectedConnectionClose(t *testing.T) {
|
||||
t.Run("close succeeds on disconnected connection", func(t *testing.T) {
|
||||
conn, err := NewConnection("ws://test", nil, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, StateDisconnected, conn.State())
|
||||
|
||||
conn.Close()
|
||||
assert.Equal(t, StateClosed, conn.State())
|
||||
})
|
||||
|
||||
t.Run("close is idempotent", func(t *testing.T) {
|
||||
conn, err := NewConnection("ws://test", nil, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
conn.Close()
|
||||
conn.Close()
|
||||
assert.Equal(t, StateClosed, conn.State())
|
||||
})
|
||||
|
||||
t.Run("close with nil socket", func(t *testing.T) {
|
||||
conn, err := NewConnection("ws://test", nil, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, conn.socket)
|
||||
|
||||
conn.Close()
|
||||
assert.Equal(t, StateClosed, conn.State())
|
||||
})
|
||||
|
||||
t.Run("socket close error does not propagate", func(t *testing.T) {
|
||||
expectedErr := fmt.Errorf("socket close failed")
|
||||
mockSocket := honeybeetest.NewMockSocket()
|
||||
mockSocket.CloseFunc = func() error {
|
||||
return expectedErr
|
||||
}
|
||||
|
||||
conn, err := NewConnection("ws://test", nil, nil)
|
||||
assert.NoError(t, err)
|
||||
conn.socket = mockSocket
|
||||
|
||||
conn.Close()
|
||||
assert.Equal(t, StateClosed, conn.State())
|
||||
})
|
||||
|
||||
t.Run("channels close after close", func(t *testing.T) {
|
||||
conn, err := NewConnection("ws://test", nil, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
conn.Close()
|
||||
|
||||
assert.Eventually(t, func() bool {
|
||||
select {
|
||||
case _, ok := <-conn.Errors():
|
||||
return !ok
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}, honeybeetest.TestTimeout, honeybeetest.TestTick,
|
||||
"errors channel should close")
|
||||
})
|
||||
|
||||
t.Run("send fails after close", func(t *testing.T) {
|
||||
conn, err := NewConnection("ws://test", nil, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
conn.Close()
|
||||
|
||||
err = conn.Send([]byte("test"))
|
||||
assert.Error(t, err)
|
||||
assert.ErrorContains(t, err, "connection closed")
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestConnectedConnectionClose(t *testing.T) {
|
||||
t.Run("blocked on ReadMessage, unblocks on closed", func(t *testing.T) {
|
||||
conn, _, incomingData, _ := setupTestConnection(t, nil)
|
||||
|
||||
// Send a message to ensure reader loop is blocking
|
||||
canary := []byte("canary")
|
||||
incomingData <- honeybeetest.MockIncomingData{
|
||||
MsgType: websocket.TextMessage, Data: canary}
|
||||
|
||||
assert.Eventually(t, func() bool {
|
||||
select {
|
||||
case msg := <-conn.Incoming():
|
||||
return bytes.Equal(msg, canary)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}, honeybeetest.TestTimeout, honeybeetest.TestTick)
|
||||
|
||||
conn.Close()
|
||||
assert.Equal(t, StateClosed, conn.State())
|
||||
})
|
||||
|
||||
t.Run("writer active during close exits cleanly", func(t *testing.T) {
|
||||
conn, _, _, _ := setupTestConnection(t, nil)
|
||||
|
||||
for i := 0; i < 50; i++ {
|
||||
conn.Send([]byte("message"))
|
||||
}
|
||||
|
||||
conn.Close()
|
||||
|
||||
err := conn.Send([]byte("late"))
|
||||
assert.Error(t, err, "Send should fail after close")
|
||||
assert.ErrorContains(t, err, "connection closed")
|
||||
})
|
||||
|
||||
t.Run("both goroutines active during close", func(t *testing.T) {
|
||||
conn, _, incomingData, _ := setupTestConnection(t, nil)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
incomingData <- honeybeetest.MockIncomingData{
|
||||
MsgType: websocket.TextMessage,
|
||||
Data: []byte(fmt.Sprintf("in-%d", i)),
|
||||
}
|
||||
conn.Send([]byte(fmt.Sprintf("out-%d", i)))
|
||||
}
|
||||
|
||||
conn.Close()
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user