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
118 lines
2.4 KiB
Go
118 lines
2.4 KiB
Go
package honeybee
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"git.wisehodl.dev/jay/go-honeybee/honeybeetest"
|
|
"github.com/stretchr/testify/assert"
|
|
"sync/atomic"
|
|
"testing"
|
|
)
|
|
|
|
func TestWorkerSend(t *testing.T) {
|
|
t.Run("data sent to mock socket", func(t *testing.T) {
|
|
conn, _, _, outgoingData := setupTestConnection(t)
|
|
defer conn.Close()
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
heartbeat := make(chan struct{})
|
|
heartbeatCount := atomic.Int32{}
|
|
|
|
w := &DefaultWorker{
|
|
ctx: ctx,
|
|
cancel: cancel,
|
|
id: "wss://test",
|
|
heartbeat: heartbeat,
|
|
outgoingCount: &atomic.Uint64{},
|
|
}
|
|
w.conn.Store(conn)
|
|
defer w.cancel()
|
|
|
|
go func() {
|
|
for range heartbeat {
|
|
heartbeatCount.Add(1)
|
|
}
|
|
}()
|
|
|
|
testData := []byte("hello")
|
|
err := w.Send(testData)
|
|
assert.NoError(t, err)
|
|
|
|
// at least one heartbeat was sent
|
|
honeybeetest.Eventually(t, func() bool {
|
|
return heartbeatCount.Load() >= 1
|
|
}, "expected heartbeats")
|
|
|
|
// message was sent by the socket
|
|
honeybeetest.Eventually(t, func() bool {
|
|
select {
|
|
case msg := <-outgoingData:
|
|
return string(msg.Data) == "hello"
|
|
default:
|
|
return false
|
|
}
|
|
}, "expected message")
|
|
})
|
|
|
|
t.Run("sends one heartbeat per successful send", func(t *testing.T) {
|
|
conn, _, _, _ := setupTestConnection(t)
|
|
defer conn.Close()
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
heartbeat := make(chan struct{})
|
|
heartbeatCount := atomic.Int32{}
|
|
|
|
w := &DefaultWorker{
|
|
ctx: ctx,
|
|
cancel: cancel,
|
|
id: "wss://test",
|
|
heartbeat: heartbeat,
|
|
outgoingCount: &atomic.Uint64{},
|
|
}
|
|
w.conn.Store(conn)
|
|
defer w.cancel()
|
|
|
|
go func() {
|
|
for range heartbeat {
|
|
heartbeatCount.Add(1)
|
|
}
|
|
}()
|
|
|
|
const count = 3
|
|
for i := range count {
|
|
err := w.Send(fmt.Appendf(nil, "msg-%d", i))
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
honeybeetest.Eventually(t, func() bool {
|
|
return heartbeatCount.Load() == count
|
|
}, "expected heartbeats")
|
|
})
|
|
|
|
t.Run("returns error if connection is unavailable", func(t *testing.T) {
|
|
// no connection available to worker
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
heartbeat := make(chan struct{})
|
|
|
|
w := &DefaultWorker{
|
|
ctx: ctx,
|
|
cancel: cancel,
|
|
id: "wss://test",
|
|
heartbeat: heartbeat,
|
|
}
|
|
defer w.cancel()
|
|
|
|
go func() {
|
|
for range heartbeat {
|
|
}
|
|
}()
|
|
|
|
err := w.Send([]byte("hello"))
|
|
assert.ErrorIs(t, err, ErrConnectionUnavailable)
|
|
})
|
|
}
|