alt/services/api/internal/socket/server_test.go
toki 3ee268816b refactor: update API socket handlers and contract parsers
- Add parser map for contract type resolution
- Update socket handlers with new message routing
- Add parser map tests
- Remove outdated code review and plan docs for G07
2026-05-30 19:14:07 +09:00

134 lines
3.7 KiB
Go

package socket
import (
"context"
"net"
"testing"
"time"
altv1 "git.toki-labs.com/toki/alt/packages/contracts/gen/go/alt/v1"
"git.toki-labs.com/toki/alt/services/api/internal/config"
apiContracts "git.toki-labs.com/toki/alt/services/api/internal/contracts"
protoSocket "git.toki-labs.com/toki/proto-socket/go"
)
func TestServerRespondsToHelloRequest(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cfg := config.Config{
Host: "127.0.0.1",
Port: freeTCPPort(t),
SocketPath: "/socket",
HeartbeatIntervalSec: 0,
HeartbeatWaitSec: 0,
}
server := NewServer(cfg)
if err := server.Start(ctx); err != nil {
t.Fatalf("failed to start server: %v", err)
}
defer server.Stop()
client, err := protoSocket.DialWsWithHeartbeat(ctx, cfg.Host, cfg.Port, cfg.SocketPath, 0, 0, apiContracts.ParserMap())
if err != nil {
t.Fatalf("failed to dial server: %v", err)
}
defer client.Close()
res, err := protoSocket.SendRequestTyped[*altv1.HelloRequest, *altv1.HelloResponse](
&client.Communicator,
&altv1.HelloRequest{
ClientName: "alt-test",
ClientVersion: "test",
AltProtocolVersion: "alt.v1",
},
2*time.Second,
)
if err != nil {
t.Fatalf("failed to send hello request: %v", err)
}
if res.GetServerName() != serverName {
t.Errorf("server name mismatch: expected %q, got %q", serverName, res.GetServerName())
}
if res.GetServerVersion() != serverVersion {
t.Errorf("server version mismatch: expected %q, got %q", serverVersion, res.GetServerVersion())
}
if res.GetAltProtocolVersion() != "alt.v1" {
t.Errorf("protocol version mismatch: expected %q, got %q", "alt.v1", res.GetAltProtocolVersion())
}
if len(res.GetCapabilities()) == 0 {
t.Fatal("expected capabilities to be set")
}
}
func TestSessionHandlersHaveUniqueRequestTypes(t *testing.T) {
seen := make(map[string]int)
for _, handler := range sessionHandlers() {
if handler.requestType == "" {
t.Errorf("session handler has empty request type")
continue
}
seen[handler.requestType]++
}
for requestType, count := range seen {
if count > 1 {
t.Errorf("request type %q registered %d times; duplicate handlers would panic the communicator", requestType, count)
}
}
}
func TestSessionHandlersCoverRequiredRequests(t *testing.T) {
registered := make(map[string]bool)
for _, handler := range sessionHandlers() {
registered[handler.requestType] = true
}
required := []string{
protoSocket.TypeNameOf(&altv1.HelloRequest{}),
}
for _, requestType := range required {
if !registered[requestType] {
t.Errorf("required handler for %q is not registered", requestType)
}
}
}
func TestRegisterHandlersSkipsNilRegistrar(t *testing.T) {
// registerHandlers must tolerate a malformed registry entry instead of
// panicking during connection setup. A nil registrar is skipped without
// dereferencing the client.
defer func() {
if r := recover(); r != nil {
t.Fatalf("registerHandlers panicked on nil registrar: %v", r)
}
}()
called := false
handlers := []sessionHandler{
{requestType: "alt.v1.NilRegistrarProbe", register: nil},
{requestType: "alt.v1.LiveRegistrarProbe", register: func(*protoSocket.WsClient) { called = true }},
}
registerHandlers(nil, handlers)
if !called {
t.Fatal("expected non-nil registrar to run after nil registrar was skipped")
}
}
func freeTCPPort(t *testing.T) int {
t.Helper()
listener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("failed to reserve TCP port: %v", err)
}
defer listener.Close()
addr, ok := listener.Addr().(*net.TCPAddr)
if !ok {
t.Fatalf("unexpected listener address type %T", listener.Addr())
}
return addr.Port
}