// websocket_test.go -- WebSocket 传输层的单元测试. // // 覆盖场景: // - computeAcceptKey 握手密钥计算 // - headerContains 请求头检查 // - NewWebSocket 默认配置 // - WebSocketTransport Close 关闭 // - Send 未连接时报错 package websocket import ( "net/http" "testing" ) // TestComputeAcceptKey 测试 WebSocket 握手密钥计算 func TestComputeAcceptKey(t *testing.T) { // 验证相同输入产生相同输出(确定性) key := "dGhlIHNhbXBsZSBub25jZQ==" got1 := computeAcceptKey(key) got2 := computeAcceptKey(key) if got1 != got2 { t.Errorf("相同输入应产生相同输出: %q vs %q", got1, got2) } // 不同输入应产生不同输出 got3 := computeAcceptKey("different_key") if got1 == got3 { t.Error("不同输入不应产生相同输出") } // 结果应为 base64 编码(非空) if len(got1) == 0 { t.Error("结果不应为空") } } // TestHeaderContains 测试请求头包含检查 func TestHeaderContains(t *testing.T) { h := http.Header{} h.Set("Connection", "Upgrade") h.Set("Upgrade", "websocket") if !headerContains(h, "Connection", "upgrade") { t.Error("应匹配 'upgrade'(不区分大小写)") } if !headerContains(h, "Upgrade", "websocket") { t.Error("应匹配 'websocket'") } if headerContains(h, "Connection", "keep-alive") { t.Error("不应匹配 'keep-alive'") } // 多值请求头 h2 := http.Header{} h2.Add("Connection", "keep-alive, Upgrade") if !headerContains(h2, "Connection", "upgrade") { t.Error("逗号分隔的多值应匹配") } } // TestNewWebSocket_DefaultConfig 测试默认配置 func TestNewWebSocket_DefaultConfig(t *testing.T) { ws := NewWebSocket(WebSocketConfig{URL: "ws://localhost:8080"}) if ws.cfg.MaxMessageSize != wsMaxMessageSize { t.Errorf("默认 MaxMessageSize: %d, 期望 %d", ws.cfg.MaxMessageSize, wsMaxMessageSize) } if ws.cfg.PingInterval != wsPingInterval { t.Errorf("默认 PingInterval: %v, 期望 %v", ws.cfg.PingInterval, wsPingInterval) } if ws.cfg.MaxReconnectAttempts != wsMaxReconnectAttempts { t.Errorf("默认 MaxReconnectAttempts: %d, 期望 %d", ws.cfg.MaxReconnectAttempts, wsMaxReconnectAttempts) } if ws.cfg.BufferSize != wsBufferSize { t.Errorf("默认 BufferSize: %d, 期望 %d", ws.cfg.BufferSize, wsBufferSize) } } // TestWebSocket_SendNotConnected 测试未连接时发送 func TestWebSocket_SendNotConnected(t *testing.T) { ws := NewWebSocket(WebSocketConfig{URL: "ws://localhost:8080"}) err := ws.Send([]byte("hello")) if err == nil { t.Error("未连接时发送应报错") } } // TestWebSocket_SendBinaryNotConnected 测试未连接时发送二进制 func TestWebSocket_SendBinaryNotConnected(t *testing.T) { ws := NewWebSocket(WebSocketConfig{URL: "ws://localhost:8080"}) err := ws.SendBinary([]byte{0x01, 0x02}) if err == nil { t.Error("未连接时发送二进制应报错") } } // TestWebSocket_Close 测试关闭 func TestWebSocket_Close(t *testing.T) { ws := NewWebSocket(WebSocketConfig{URL: "ws://localhost:8080"}) // 未连接时关闭不应 panic err := ws.Close() if err != nil { t.Errorf("关闭不应报错: %v", err) } // 关闭后发送应报错 err = ws.Send([]byte("hello")) if err == nil { t.Error("关闭后发送应报错") } } // TestWebSocket_IsClosed 测试关闭状态检查 func TestWebSocket_IsClosed(t *testing.T) { ws := NewWebSocket(WebSocketConfig{URL: "ws://localhost:8080"}) if ws.isClosed() { t.Error("新建时不应为已关闭") } ws.Close() if !ws.isClosed() { t.Error("关闭后应为已关闭") } } // TestWebSocket_BufferOnDisconnect 测试断线缓存 func TestWebSocket_BufferOnDisconnect(t *testing.T) { ws := NewWebSocket(WebSocketConfig{ URL: "ws://localhost:8080", AutoReconnect: true, BufferSize: 10, }) // 模拟未连接但启用了自动重连 err := ws.Send([]byte("buffered message")) if err != nil { t.Errorf("启用自动重连时,未连接应缓存消息: %v", err) } ws.mu.Lock() bufLen := len(ws.sendBuffer) ws.mu.Unlock() if bufLen != 1 { t.Errorf("缓冲区应有 1 条消息, 实际: %d", bufLen) } } // TestWebSocket_Receive 测试接收通道 func TestWebSocket_Receive(t *testing.T) { ws := NewWebSocket(WebSocketConfig{URL: "ws://localhost:8080"}) ch := ws.Receive() if ch == nil { t.Error("Receive 通道不应为 nil") } }