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()") } }