test: add comprehensive WebSocket interface tests for connection, key generation, and message handling
This commit is contained in:
280
pkg/interfaces/websocket_native_test.go
Normal file
280
pkg/interfaces/websocket_native_test.go
Normal file
@@ -0,0 +1,280 @@
|
||||
package interfaces
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.quad4.io/Networks/Reticulum-Go/pkg/common"
|
||||
)
|
||||
|
||||
func TestWebSocketGUID(t *testing.T) {
|
||||
if wsGUID != "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" {
|
||||
t.Errorf("wsGUID mismatch: expected RFC 6455 GUID, got %s", wsGUID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateWebSocketKey(t *testing.T) {
|
||||
key1, err := generateWebSocketKey()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate key: %v", err)
|
||||
}
|
||||
|
||||
key2, err := generateWebSocketKey()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate key: %v", err)
|
||||
}
|
||||
|
||||
if key1 == key2 {
|
||||
t.Error("Generated keys should be unique")
|
||||
}
|
||||
|
||||
if len(key1) != 24 {
|
||||
t.Errorf("Expected base64-encoded key length 24, got %d", len(key1))
|
||||
}
|
||||
}
|
||||
|
||||
func TestComputeAcceptKey(t *testing.T) {
|
||||
testKey := "dGhlIHNhbXBsZSBub25jZQ=="
|
||||
expectedAccept := "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
|
||||
|
||||
accept := computeAcceptKey(testKey)
|
||||
if accept != expectedAccept {
|
||||
t.Errorf("Accept key mismatch: expected %s, got %s", expectedAccept, accept)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewWebSocketInterface(t *testing.T) {
|
||||
ws, err := NewWebSocketInterface("test", "wss://socket.quad4.io/ws", true)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create WebSocket interface: %v", err)
|
||||
}
|
||||
|
||||
if ws.GetName() != "test" {
|
||||
t.Errorf("Expected name 'test', got %s", ws.GetName())
|
||||
}
|
||||
|
||||
if ws.GetType() != common.IF_TYPE_UDP {
|
||||
t.Errorf("Expected type IF_TYPE_UDP, got %v", ws.GetType())
|
||||
}
|
||||
|
||||
if ws.GetMTU() != 1064 {
|
||||
t.Errorf("Expected MTU 1064, got %d", ws.GetMTU())
|
||||
}
|
||||
|
||||
if ws.IsOnline() {
|
||||
t.Error("Interface should not be online before Start()")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWebSocketConnection(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping network test in short mode")
|
||||
}
|
||||
|
||||
ws, err := NewWebSocketInterface("test", "wss://socket.quad4.io/ws", true)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create WebSocket interface: %v", err)
|
||||
}
|
||||
|
||||
ws.SetPacketCallback(func(data []byte, ni common.NetworkInterface) {
|
||||
t.Logf("Received packet: %d bytes", len(data))
|
||||
})
|
||||
|
||||
err = ws.Start()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to start WebSocket: %v", err)
|
||||
}
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
if !ws.IsOnline() {
|
||||
t.Error("WebSocket should be online after Start()")
|
||||
}
|
||||
|
||||
testData := []byte{0x01, 0x02, 0x03, 0x04}
|
||||
err = ws.Send(testData, "")
|
||||
if err != nil {
|
||||
t.Errorf("Failed to send data: %v", err)
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
if err := ws.Stop(); err != nil {
|
||||
t.Errorf("Failed to stop WebSocket: %v", err)
|
||||
}
|
||||
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
|
||||
if ws.IsOnline() {
|
||||
t.Error("WebSocket should be offline after Stop()")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWebSocketReconnection(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping network test in short mode")
|
||||
}
|
||||
|
||||
ws, err := NewWebSocketInterface("test", "wss://socket.quad4.io/ws", true)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create WebSocket interface: %v", err)
|
||||
}
|
||||
|
||||
err = ws.Start()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to start WebSocket: %v", err)
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
if !ws.IsOnline() {
|
||||
t.Error("WebSocket should be online")
|
||||
}
|
||||
|
||||
conn := ws.GetConn()
|
||||
if conn == nil {
|
||||
t.Error("GetConn() should return a connection")
|
||||
}
|
||||
|
||||
conn.Close()
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
if ws.IsOnline() {
|
||||
t.Log("WebSocket reconnected successfully")
|
||||
}
|
||||
|
||||
if err := ws.Stop(); err != nil {
|
||||
t.Errorf("Failed to stop WebSocket: %v", err)
|
||||
}
|
||||
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
|
||||
func TestWebSocketMessageQueue(t *testing.T) {
|
||||
ws, err := NewWebSocketInterface("test", "wss://socket.quad4.io/ws", true)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create WebSocket interface: %v", err)
|
||||
}
|
||||
|
||||
ws.Enable()
|
||||
|
||||
testData := []byte{0x01, 0x02, 0x03}
|
||||
err = ws.Send(testData, "")
|
||||
if err != nil {
|
||||
t.Errorf("Send should queue message when offline, got error: %v", err)
|
||||
}
|
||||
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
err = ws.Start()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to start WebSocket: %v", err)
|
||||
}
|
||||
|
||||
// Wait for interface to be online (up to 10 seconds)
|
||||
for i := 0; i < 100; i++ {
|
||||
if ws.IsOnline() {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
if !ws.IsOnline() {
|
||||
t.Error("WebSocket should be online")
|
||||
}
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
if err := ws.Stop(); err != nil {
|
||||
t.Errorf("Failed to stop WebSocket: %v", err)
|
||||
}
|
||||
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
|
||||
func TestWebSocketFrameEncoding(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping frame encoding test in short mode")
|
||||
}
|
||||
|
||||
ws, err := NewWebSocketInterface("test", "wss://socket.quad4.io/ws", true)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create WebSocket interface: %v", err)
|
||||
}
|
||||
|
||||
err = ws.Start()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to start WebSocket: %v", err)
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
data []byte
|
||||
}{
|
||||
{"small frame", []byte{0x01, 0x02, 0x03}},
|
||||
{"medium frame", make([]byte, 200)},
|
||||
{"large frame", make([]byte, 1000)},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := ws.Send(tc.data, "")
|
||||
if err != nil {
|
||||
t.Errorf("Failed to send %s: %v", tc.name, err)
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
})
|
||||
}
|
||||
|
||||
if err := ws.Stop(); err != nil {
|
||||
t.Errorf("Failed to stop WebSocket: %v", err)
|
||||
}
|
||||
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
|
||||
func TestWebSocketEnableDisable(t *testing.T) {
|
||||
ws, err := NewWebSocketInterface("test", "wss://socket.quad4.io/ws", false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create WebSocket interface: %v", err)
|
||||
}
|
||||
|
||||
if ws.IsEnabled() {
|
||||
t.Error("Interface should not be enabled initially")
|
||||
}
|
||||
|
||||
ws.Enable()
|
||||
if !ws.IsEnabled() {
|
||||
t.Error("Interface should be enabled after Enable()")
|
||||
}
|
||||
|
||||
ws.Disable()
|
||||
if ws.IsEnabled() {
|
||||
t.Error("Interface should not be enabled after Disable()")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWebSocketDetach(t *testing.T) {
|
||||
ws, err := NewWebSocketInterface("test", "wss://socket.quad4.io/ws", true)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create WebSocket interface: %v", err)
|
||||
}
|
||||
|
||||
if ws.IsDetached() {
|
||||
t.Error("Interface should not be detached initially")
|
||||
}
|
||||
|
||||
ws.Detach()
|
||||
if !ws.IsDetached() {
|
||||
t.Error("Interface should be detached after Detach()")
|
||||
}
|
||||
|
||||
if ws.IsOnline() {
|
||||
t.Error("Interface should be offline after Detach()")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user