b44a46ed2f
Replaces the flat key-value logging scheme with component-based structured logging via go-mana-component. Each layer (pool, worker, connection) builds its own component identity and derives a *slog.Logger from a caller-supplied slog.Handler. - Delete logging/ package (logging.go, logging_test.go) - Strip LoggingEnabled and LogLevel from ConnectionConfig, PoolConfig, WorkerConfig; remove associated option funcs - Change NewConnection and NewConnectionFromSocket to accept ctx and slog.Handler instead of *slog.Logger; constructors build component identity via MustNew/MustExtend internally - Change WorkerFactory, NewWorker, connect, and RunDialer to carry slog.Handler; remove PoolPlugin.Handler - Change NewPool to establish pool component identity via MustNew; remove pool_id field, PoolPlugin.ID, and ErrInvalidPoolID - Fix data race in MockSlogHandler: WithAttrs now shares parent mutex pointer rather than allocating a new one per child - Run go fix
104 lines
2.6 KiB
Go
104 lines
2.6 KiB
Go
package transport
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"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(context.Background(), "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(context.Background(), "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(context.Background(), "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(context.Background(), "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(context.Background(), "ws://test", nil, nil)
|
|
assert.NoError(t, err)
|
|
|
|
conn.Close()
|
|
|
|
assert.True(t, conn.closed)
|
|
_, ok := <-conn.incoming
|
|
assert.False(t, ok)
|
|
_, ok = <-conn.errors
|
|
assert.False(t, ok)
|
|
})
|
|
|
|
t.Run("send fails after close", func(t *testing.T) {
|
|
conn, err := NewConnection(context.Background(), "ws://test", nil, nil)
|
|
assert.NoError(t, err)
|
|
|
|
conn.Close()
|
|
|
|
err = conn.Send([]byte("test"))
|
|
assert.Error(t, err)
|
|
assert.ErrorIs(t, err, ErrConnectionClosed)
|
|
})
|
|
|
|
}
|
|
|
|
func TestConnectedConnectionClose(t *testing.T) {
|
|
t.Run("blocked on ReadMessage, unblocks on closed", func(t *testing.T) {
|
|
conn, _, incomingData, _ := setupTestConnection(t)
|
|
|
|
// Send a message to ensure reader loop is blocking
|
|
canary := []byte("canary")
|
|
incomingData <- honeybeetest.MockIncomingData{
|
|
MsgType: websocket.TextMessage, Data: canary}
|
|
|
|
honeybeetest.Eventually(t, func() bool {
|
|
select {
|
|
case msg := <-conn.Incoming():
|
|
return bytes.Equal(msg, canary)
|
|
default:
|
|
return false
|
|
}
|
|
}, "expected canary message")
|
|
|
|
conn.Close()
|
|
assert.Equal(t, StateClosed, conn.State())
|
|
})
|
|
}
|