119 lines
2.5 KiB
Go
119 lines
2.5 KiB
Go
package compatibility
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/eleksir/pekoe/internal/config"
|
|
"github.com/eleksir/pekoe/internal/pubsub"
|
|
"github.com/eleksir/pekoe/internal/server"
|
|
)
|
|
|
|
// testServer manages a test server instance for compatibility tests
|
|
type testServer struct {
|
|
cfg *config.Config
|
|
server *server.Server
|
|
ctx context.Context
|
|
cancel context.CancelFunc
|
|
wg sync.WaitGroup
|
|
addr string
|
|
}
|
|
|
|
// startTestServer starts a pekoe server on a random available port for testing
|
|
func startTestServer(t *testing.T) *testServer {
|
|
t.Helper()
|
|
|
|
// Find an available port
|
|
port := findAvailablePort(t)
|
|
|
|
cfg := &config.Config{
|
|
Bind: "127.0.0.1",
|
|
Port: port,
|
|
MaxClients: 100,
|
|
ReadTimeout: 0,
|
|
WriteTimeout: 0,
|
|
MaxMsgBytes: 10 * 1024 * 1024, // 10MB
|
|
LogLevel: "error", // Suppress logs in tests
|
|
}
|
|
cfg.SetDefaults()
|
|
|
|
hub := pubsub.NewHub()
|
|
srv := server.New(cfg, hub)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
ts := &testServer{
|
|
cfg: cfg,
|
|
server: srv,
|
|
ctx: ctx,
|
|
cancel: cancel,
|
|
addr: cfg.Addr(),
|
|
}
|
|
|
|
// Start server in background
|
|
ts.wg.Add(1)
|
|
go func() {
|
|
defer ts.wg.Done()
|
|
_ = srv.Run()
|
|
}()
|
|
|
|
// Wait for server to be ready
|
|
ts.waitForReady(t)
|
|
|
|
return ts
|
|
}
|
|
|
|
// waitForReady blocks until the server accepts connections
|
|
func (ts *testServer) waitForReady(t *testing.T) {
|
|
t.Helper()
|
|
|
|
deadline := time.Now().Add(5 * time.Second)
|
|
for time.Now().Before(deadline) {
|
|
conn, err := net.DialTimeout("tcp", ts.addr, 100*time.Millisecond)
|
|
if err == nil {
|
|
_ = conn.Close()
|
|
return
|
|
}
|
|
time.Sleep(10 * time.Millisecond)
|
|
}
|
|
t.Fatalf("Server at %s not ready after 5 seconds", ts.addr)
|
|
}
|
|
|
|
// Addr returns the server address for client connections
|
|
func (ts *testServer) Addr() string {
|
|
return ts.addr
|
|
}
|
|
|
|
// Close shuts down the test server
|
|
func (ts *testServer) Close() {
|
|
ts.cancel()
|
|
// Give time for graceful shutdown
|
|
time.Sleep(100 * time.Millisecond)
|
|
}
|
|
|
|
// findAvailablePort finds an available TCP port for testing
|
|
func findAvailablePort(t *testing.T) int {
|
|
t.Helper()
|
|
|
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
t.Fatalf("Failed to find available port: %v", err)
|
|
}
|
|
port := listener.Addr().(*net.TCPAddr).Port
|
|
_ = listener.Close()
|
|
return port
|
|
}
|
|
|
|
// waitForMessage waits for a message on a channel with timeout
|
|
func waitForMessage[T any](ch <-chan T, timeout time.Duration) (T, bool) {
|
|
select {
|
|
case msg := <-ch:
|
|
return msg, true
|
|
case <-time.After(timeout):
|
|
var zero T
|
|
return zero, false
|
|
}
|
|
}
|