mirror of
https://github.com/varun-r-mallya/py-libp2p.git
synced 2025-12-31 20:36:24 +00:00
Fix typecheck errors and improve WebSocket transport implementation
- Fix INotifee interface compliance in WebSocket demo - Fix handler function signatures to be async (THandler compatibility) - Fix is_closed method usage with proper type checking - Fix pytest.raises multiple exception type issue - Fix line length violations (E501) across multiple files - Add debugging logging to Noise security module for troubleshooting - Update WebSocket transport examples and tests - Improve transport registry error handling
This commit is contained in:
@ -2,20 +2,20 @@
|
||||
Tests for the transport registry functionality.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from multiaddr import Multiaddr
|
||||
|
||||
from libp2p.abc import ITransport
|
||||
from libp2p.abc import IListener, IRawConnection, ITransport
|
||||
from libp2p.custom_types import THandler
|
||||
from libp2p.transport.tcp.tcp import TCP
|
||||
from libp2p.transport.websocket.transport import WebsocketTransport
|
||||
from libp2p.transport.transport_registry import (
|
||||
TransportRegistry,
|
||||
create_transport_for_multiaddr,
|
||||
get_supported_transport_protocols,
|
||||
get_transport_registry,
|
||||
register_transport,
|
||||
get_supported_transport_protocols,
|
||||
)
|
||||
from libp2p.transport.upgrader import TransportUpgrader
|
||||
from libp2p.transport.websocket.transport import WebsocketTransport
|
||||
|
||||
|
||||
class TestTransportRegistry:
|
||||
@ -25,7 +25,7 @@ class TestTransportRegistry:
|
||||
"""Test registry initialization."""
|
||||
registry = TransportRegistry()
|
||||
assert isinstance(registry, TransportRegistry)
|
||||
|
||||
|
||||
# Check that default transports are registered
|
||||
supported = registry.get_supported_protocols()
|
||||
assert "tcp" in supported
|
||||
@ -34,22 +34,28 @@ class TestTransportRegistry:
|
||||
def test_register_transport(self):
|
||||
"""Test transport registration."""
|
||||
registry = TransportRegistry()
|
||||
|
||||
|
||||
# Register a custom transport
|
||||
class CustomTransport:
|
||||
pass
|
||||
|
||||
class CustomTransport(ITransport):
|
||||
async def dial(self, maddr: Multiaddr) -> IRawConnection:
|
||||
raise NotImplementedError("CustomTransport dial not implemented")
|
||||
|
||||
def create_listener(self, handler_function: THandler) -> IListener:
|
||||
raise NotImplementedError(
|
||||
"CustomTransport create_listener not implemented"
|
||||
)
|
||||
|
||||
registry.register_transport("custom", CustomTransport)
|
||||
assert registry.get_transport("custom") == CustomTransport
|
||||
|
||||
def test_get_transport(self):
|
||||
"""Test getting registered transports."""
|
||||
registry = TransportRegistry()
|
||||
|
||||
|
||||
# Test existing transports
|
||||
assert registry.get_transport("tcp") == TCP
|
||||
assert registry.get_transport("ws") == WebsocketTransport
|
||||
|
||||
|
||||
# Test non-existent transport
|
||||
assert registry.get_transport("nonexistent") is None
|
||||
|
||||
@ -57,7 +63,7 @@ class TestTransportRegistry:
|
||||
"""Test getting supported protocols."""
|
||||
registry = TransportRegistry()
|
||||
protocols = registry.get_supported_protocols()
|
||||
|
||||
|
||||
assert isinstance(protocols, list)
|
||||
assert "tcp" in protocols
|
||||
assert "ws" in protocols
|
||||
@ -66,7 +72,7 @@ class TestTransportRegistry:
|
||||
"""Test creating TCP transport."""
|
||||
registry = TransportRegistry()
|
||||
upgrader = TransportUpgrader({}, {})
|
||||
|
||||
|
||||
transport = registry.create_transport("tcp", upgrader)
|
||||
assert isinstance(transport, TCP)
|
||||
|
||||
@ -74,7 +80,7 @@ class TestTransportRegistry:
|
||||
"""Test creating WebSocket transport."""
|
||||
registry = TransportRegistry()
|
||||
upgrader = TransportUpgrader({}, {})
|
||||
|
||||
|
||||
transport = registry.create_transport("ws", upgrader)
|
||||
assert isinstance(transport, WebsocketTransport)
|
||||
|
||||
@ -82,14 +88,14 @@ class TestTransportRegistry:
|
||||
"""Test creating transport with invalid protocol."""
|
||||
registry = TransportRegistry()
|
||||
upgrader = TransportUpgrader({}, {})
|
||||
|
||||
|
||||
transport = registry.create_transport("invalid", upgrader)
|
||||
assert transport is None
|
||||
|
||||
def test_create_transport_websocket_no_upgrader(self):
|
||||
"""Test that WebSocket transport requires upgrader."""
|
||||
registry = TransportRegistry()
|
||||
|
||||
|
||||
# This should fail gracefully and return None
|
||||
transport = registry.create_transport("ws", None)
|
||||
assert transport is None
|
||||
@ -105,12 +111,19 @@ class TestGlobalRegistry:
|
||||
|
||||
def test_register_transport_global(self):
|
||||
"""Test registering transport globally."""
|
||||
class GlobalCustomTransport:
|
||||
pass
|
||||
|
||||
|
||||
class GlobalCustomTransport(ITransport):
|
||||
async def dial(self, maddr: Multiaddr) -> IRawConnection:
|
||||
raise NotImplementedError("GlobalCustomTransport dial not implemented")
|
||||
|
||||
def create_listener(self, handler_function: THandler) -> IListener:
|
||||
raise NotImplementedError(
|
||||
"GlobalCustomTransport create_listener not implemented"
|
||||
)
|
||||
|
||||
# Register globally
|
||||
register_transport("global_custom", GlobalCustomTransport)
|
||||
|
||||
|
||||
# Check that it's available
|
||||
registry = get_transport_registry()
|
||||
assert registry.get_transport("global_custom") == GlobalCustomTransport
|
||||
@ -129,79 +142,80 @@ class TestTransportFactory:
|
||||
def test_create_transport_for_multiaddr_tcp(self):
|
||||
"""Test creating transport for TCP multiaddr."""
|
||||
upgrader = TransportUpgrader({}, {})
|
||||
|
||||
|
||||
# TCP multiaddr
|
||||
maddr = Multiaddr("/ip4/127.0.0.1/tcp/8080")
|
||||
transport = create_transport_for_multiaddr(maddr, upgrader)
|
||||
|
||||
|
||||
assert transport is not None
|
||||
assert isinstance(transport, TCP)
|
||||
|
||||
def test_create_transport_for_multiaddr_websocket(self):
|
||||
"""Test creating transport for WebSocket multiaddr."""
|
||||
upgrader = TransportUpgrader({}, {})
|
||||
|
||||
|
||||
# WebSocket multiaddr
|
||||
maddr = Multiaddr("/ip4/127.0.0.1/tcp/8080/ws")
|
||||
transport = create_transport_for_multiaddr(maddr, upgrader)
|
||||
|
||||
|
||||
assert transport is not None
|
||||
assert isinstance(transport, WebsocketTransport)
|
||||
|
||||
def test_create_transport_for_multiaddr_websocket_secure(self):
|
||||
"""Test creating transport for WebSocket multiaddr."""
|
||||
upgrader = TransportUpgrader({}, {})
|
||||
|
||||
|
||||
# WebSocket multiaddr
|
||||
maddr = Multiaddr("/ip4/127.0.0.1/tcp/8080/ws")
|
||||
transport = create_transport_for_multiaddr(maddr, upgrader)
|
||||
|
||||
|
||||
assert transport is not None
|
||||
assert isinstance(transport, WebsocketTransport)
|
||||
|
||||
def test_create_transport_for_multiaddr_ipv6(self):
|
||||
"""Test creating transport for IPv6 multiaddr."""
|
||||
upgrader = TransportUpgrader({}, {})
|
||||
|
||||
|
||||
# IPv6 WebSocket multiaddr
|
||||
maddr = Multiaddr("/ip6/::1/tcp/8080/ws")
|
||||
transport = create_transport_for_multiaddr(maddr, upgrader)
|
||||
|
||||
|
||||
assert transport is not None
|
||||
assert isinstance(transport, WebsocketTransport)
|
||||
|
||||
def test_create_transport_for_multiaddr_dns(self):
|
||||
"""Test creating transport for DNS multiaddr."""
|
||||
upgrader = TransportUpgrader({}, {})
|
||||
|
||||
|
||||
# DNS WebSocket multiaddr
|
||||
maddr = Multiaddr("/dns4/example.com/tcp/443/ws")
|
||||
transport = create_transport_for_multiaddr(maddr, upgrader)
|
||||
|
||||
|
||||
assert transport is not None
|
||||
assert isinstance(transport, WebsocketTransport)
|
||||
|
||||
def test_create_transport_for_multiaddr_unknown(self):
|
||||
"""Test creating transport for unknown multiaddr."""
|
||||
upgrader = TransportUpgrader({}, {})
|
||||
|
||||
|
||||
# Unknown multiaddr
|
||||
maddr = Multiaddr("/ip4/127.0.0.1/udp/8080")
|
||||
transport = create_transport_for_multiaddr(maddr, upgrader)
|
||||
|
||||
|
||||
assert transport is None
|
||||
|
||||
def test_create_transport_for_multiaddr_no_upgrader(self):
|
||||
"""Test creating transport without upgrader."""
|
||||
# This should work for TCP but not WebSocket
|
||||
def test_create_transport_for_multiaddr_with_upgrader(self):
|
||||
"""Test creating transport with upgrader."""
|
||||
upgrader = TransportUpgrader({}, {})
|
||||
|
||||
# This should work for both TCP and WebSocket with upgrader
|
||||
maddr_tcp = Multiaddr("/ip4/127.0.0.1/tcp/8080")
|
||||
transport_tcp = create_transport_for_multiaddr(maddr_tcp, None)
|
||||
transport_tcp = create_transport_for_multiaddr(maddr_tcp, upgrader)
|
||||
assert transport_tcp is not None
|
||||
|
||||
|
||||
maddr_ws = Multiaddr("/ip4/127.0.0.1/tcp/8080/ws")
|
||||
transport_ws = create_transport_for_multiaddr(maddr_ws, None)
|
||||
# WebSocket transport creation should fail gracefully
|
||||
assert transport_ws is None
|
||||
transport_ws = create_transport_for_multiaddr(maddr_ws, upgrader)
|
||||
assert transport_ws is not None
|
||||
|
||||
|
||||
class TestTransportInterfaceCompliance:
|
||||
@ -211,8 +225,8 @@ class TestTransportInterfaceCompliance:
|
||||
"""Test that TCP transport implements ITransport."""
|
||||
transport = TCP()
|
||||
assert isinstance(transport, ITransport)
|
||||
assert hasattr(transport, 'dial')
|
||||
assert hasattr(transport, 'create_listener')
|
||||
assert hasattr(transport, "dial")
|
||||
assert hasattr(transport, "create_listener")
|
||||
assert callable(transport.dial)
|
||||
assert callable(transport.create_listener)
|
||||
|
||||
@ -221,8 +235,8 @@ class TestTransportInterfaceCompliance:
|
||||
upgrader = TransportUpgrader({}, {})
|
||||
transport = WebsocketTransport(upgrader)
|
||||
assert isinstance(transport, ITransport)
|
||||
assert hasattr(transport, 'dial')
|
||||
assert hasattr(transport, 'create_listener')
|
||||
assert hasattr(transport, "dial")
|
||||
assert hasattr(transport, "create_listener")
|
||||
assert callable(transport.dial)
|
||||
assert callable(transport.create_listener)
|
||||
|
||||
@ -234,14 +248,22 @@ class TestErrorHandling:
|
||||
"""Test handling of transport creation exceptions."""
|
||||
registry = TransportRegistry()
|
||||
upgrader = TransportUpgrader({}, {})
|
||||
|
||||
|
||||
# Register a transport that raises an exception
|
||||
class ExceptionTransport:
|
||||
class ExceptionTransport(ITransport):
|
||||
def __init__(self, *args, **kwargs):
|
||||
raise RuntimeError("Transport creation failed")
|
||||
|
||||
|
||||
async def dial(self, maddr: Multiaddr) -> IRawConnection:
|
||||
raise NotImplementedError("ExceptionTransport dial not implemented")
|
||||
|
||||
def create_listener(self, handler_function: THandler) -> IListener:
|
||||
raise NotImplementedError(
|
||||
"ExceptionTransport create_listener not implemented"
|
||||
)
|
||||
|
||||
registry.register_transport("exception", ExceptionTransport)
|
||||
|
||||
|
||||
# Should handle exception gracefully and return None
|
||||
transport = registry.create_transport("exception", upgrader)
|
||||
assert transport is None
|
||||
@ -249,12 +271,13 @@ class TestErrorHandling:
|
||||
def test_invalid_multiaddr_handling(self):
|
||||
"""Test handling of invalid multiaddrs."""
|
||||
upgrader = TransportUpgrader({}, {})
|
||||
|
||||
|
||||
# Test with a multiaddr that has an unsupported transport protocol
|
||||
# This should be handled gracefully by our transport registry
|
||||
maddr = Multiaddr("/ip4/127.0.0.1/tcp/8080/udp/1234") # udp is not a supported transport
|
||||
# udp is not a supported transport
|
||||
maddr = Multiaddr("/ip4/127.0.0.1/tcp/8080/udp/1234")
|
||||
transport = create_transport_for_multiaddr(maddr, upgrader)
|
||||
|
||||
|
||||
assert transport is None
|
||||
|
||||
|
||||
@ -265,15 +288,15 @@ class TestIntegration:
|
||||
"""Test using multiple transport types in the same registry."""
|
||||
registry = TransportRegistry()
|
||||
upgrader = TransportUpgrader({}, {})
|
||||
|
||||
|
||||
# Create different transport types
|
||||
tcp_transport = registry.create_transport("tcp", upgrader)
|
||||
ws_transport = registry.create_transport("ws", upgrader)
|
||||
|
||||
|
||||
# All should be different types
|
||||
assert isinstance(tcp_transport, TCP)
|
||||
assert isinstance(ws_transport, WebsocketTransport)
|
||||
|
||||
|
||||
# All should be different instances
|
||||
assert tcp_transport is not ws_transport
|
||||
|
||||
@ -281,15 +304,21 @@ class TestIntegration:
|
||||
"""Test that transport registry persists across calls."""
|
||||
registry1 = get_transport_registry()
|
||||
registry2 = get_transport_registry()
|
||||
|
||||
|
||||
# Should be the same instance
|
||||
assert registry1 is registry2
|
||||
|
||||
|
||||
# Register a transport in one
|
||||
class PersistentTransport:
|
||||
pass
|
||||
|
||||
class PersistentTransport(ITransport):
|
||||
async def dial(self, maddr: Multiaddr) -> IRawConnection:
|
||||
raise NotImplementedError("PersistentTransport dial not implemented")
|
||||
|
||||
def create_listener(self, handler_function: THandler) -> IListener:
|
||||
raise NotImplementedError(
|
||||
"PersistentTransport create_listener not implemented"
|
||||
)
|
||||
|
||||
registry1.register_transport("persistent", PersistentTransport)
|
||||
|
||||
|
||||
# Should be available in the other
|
||||
assert registry2.get_transport("persistent") == PersistentTransport
|
||||
|
||||
@ -1,23 +1,23 @@
|
||||
from collections.abc import Sequence
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
import trio
|
||||
from multiaddr import Multiaddr
|
||||
import trio
|
||||
|
||||
from libp2p.crypto.secp256k1 import create_new_key_pair
|
||||
from libp2p.custom_types import TProtocol
|
||||
from libp2p.host.basic_host import BasicHost
|
||||
from libp2p.network.swarm import Swarm
|
||||
from libp2p.peer.id import ID
|
||||
from libp2p.peer.peerinfo import PeerInfo
|
||||
from libp2p.peer.peerstore import PeerStore
|
||||
from libp2p.security.insecure.transport import InsecureTransport
|
||||
from libp2p.stream_muxer.yamux.yamux import Yamux
|
||||
from libp2p.transport.upgrader import TransportUpgrader
|
||||
from libp2p.transport.websocket.transport import WebsocketTransport
|
||||
from libp2p.transport.websocket.listener import WebsocketListener
|
||||
from libp2p.transport.exceptions import OpenConnectionError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
PLAINTEXT_PROTOCOL_ID = "/plaintext/1.0.0"
|
||||
|
||||
@ -64,29 +64,30 @@ def create_upgrader():
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# 2. Listener Basic Functionality Tests
|
||||
@pytest.mark.trio
|
||||
async def test_listener_basic_listen():
|
||||
"""Test basic listen functionality"""
|
||||
upgrader = create_upgrader()
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
|
||||
# Test listening on IPv4
|
||||
ma = Multiaddr("/ip4/127.0.0.1/tcp/0/ws")
|
||||
listener = transport.create_listener(lambda conn: None)
|
||||
|
||||
|
||||
async def dummy_handler(conn):
|
||||
await trio.sleep(0)
|
||||
|
||||
listener = transport.create_listener(dummy_handler)
|
||||
|
||||
# Test that listener can be created and has required methods
|
||||
assert hasattr(listener, 'listen')
|
||||
assert hasattr(listener, 'close')
|
||||
assert hasattr(listener, 'get_addrs')
|
||||
|
||||
assert hasattr(listener, "listen")
|
||||
assert hasattr(listener, "close")
|
||||
assert hasattr(listener, "get_addrs")
|
||||
|
||||
# Test that listener can handle the address
|
||||
assert ma.value_for_protocol("ip4") == "127.0.0.1"
|
||||
assert ma.value_for_protocol("tcp") == "0"
|
||||
|
||||
|
||||
# Test that listener can be closed
|
||||
await listener.close()
|
||||
|
||||
@ -96,14 +97,18 @@ async def test_listener_port_0_handling():
|
||||
"""Test listening on port 0 gets actual port"""
|
||||
upgrader = create_upgrader()
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
|
||||
ma = Multiaddr("/ip4/127.0.0.1/tcp/0/ws")
|
||||
listener = transport.create_listener(lambda conn: None)
|
||||
|
||||
|
||||
async def dummy_handler(conn):
|
||||
await trio.sleep(0)
|
||||
|
||||
listener = transport.create_listener(dummy_handler)
|
||||
|
||||
# Test that the address can be parsed correctly
|
||||
port_str = ma.value_for_protocol("tcp")
|
||||
assert port_str == "0"
|
||||
|
||||
|
||||
# Test that listener can be closed
|
||||
await listener.close()
|
||||
|
||||
@ -113,14 +118,18 @@ async def test_listener_any_interface():
|
||||
"""Test listening on 0.0.0.0"""
|
||||
upgrader = create_upgrader()
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
|
||||
ma = Multiaddr("/ip4/0.0.0.0/tcp/0/ws")
|
||||
listener = transport.create_listener(lambda conn: None)
|
||||
|
||||
|
||||
async def dummy_handler(conn):
|
||||
await trio.sleep(0)
|
||||
|
||||
listener = transport.create_listener(dummy_handler)
|
||||
|
||||
# Test that the address can be parsed correctly
|
||||
host = ma.value_for_protocol("ip4")
|
||||
assert host == "0.0.0.0"
|
||||
|
||||
|
||||
# Test that listener can be closed
|
||||
await listener.close()
|
||||
|
||||
@ -130,16 +139,20 @@ async def test_listener_address_preservation():
|
||||
"""Test that p2p IDs are preserved in addresses"""
|
||||
upgrader = create_upgrader()
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
|
||||
# Create address with p2p ID
|
||||
p2p_id = "12D3KooWL5xtmx8Mgc6tByjVaPPpTKH42QK7PUFQtZLabdSMKHpF"
|
||||
ma = Multiaddr(f"/ip4/127.0.0.1/tcp/0/ws/p2p/{p2p_id}")
|
||||
listener = transport.create_listener(lambda conn: None)
|
||||
|
||||
|
||||
async def dummy_handler(conn):
|
||||
await trio.sleep(0)
|
||||
|
||||
listener = transport.create_listener(dummy_handler)
|
||||
|
||||
# Test that p2p ID is preserved in the address
|
||||
addr_str = str(ma)
|
||||
assert p2p_id in addr_str
|
||||
|
||||
|
||||
# Test that listener can be closed
|
||||
await listener.close()
|
||||
|
||||
@ -150,18 +163,18 @@ async def test_dial_basic():
|
||||
"""Test basic dial functionality"""
|
||||
upgrader = create_upgrader()
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
|
||||
# Test that transport can parse addresses for dialing
|
||||
ma = Multiaddr("/ip4/127.0.0.1/tcp/8080/ws")
|
||||
|
||||
|
||||
# Test that the address can be parsed correctly
|
||||
host = ma.value_for_protocol("ip4")
|
||||
port = ma.value_for_protocol("tcp")
|
||||
assert host == "127.0.0.1"
|
||||
assert port == "8080"
|
||||
|
||||
|
||||
# Test that transport has the required methods
|
||||
assert hasattr(transport, 'dial')
|
||||
assert hasattr(transport, "dial")
|
||||
assert callable(transport.dial)
|
||||
|
||||
|
||||
@ -170,16 +183,16 @@ async def test_dial_with_p2p_id():
|
||||
"""Test dialing with p2p ID suffix"""
|
||||
upgrader = create_upgrader()
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
|
||||
p2p_id = "12D3KooWL5xtmx8Mgc6tByjVaPPpTKH42QK7PUFQtZLabdSMKHpF"
|
||||
ma = Multiaddr(f"/ip4/127.0.0.1/tcp/8080/ws/p2p/{p2p_id}")
|
||||
|
||||
|
||||
# Test that p2p ID is preserved in the address
|
||||
addr_str = str(ma)
|
||||
assert p2p_id in addr_str
|
||||
|
||||
|
||||
# Test that transport can handle addresses with p2p IDs
|
||||
assert hasattr(transport, 'dial')
|
||||
assert hasattr(transport, "dial")
|
||||
assert callable(transport.dial)
|
||||
|
||||
|
||||
@ -188,41 +201,42 @@ async def test_dial_port_0_resolution():
|
||||
"""Test dialing to resolved port 0 addresses"""
|
||||
upgrader = create_upgrader()
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
|
||||
# Test that transport can handle port 0 addresses
|
||||
ma = Multiaddr("/ip4/127.0.0.1/tcp/0/ws")
|
||||
|
||||
|
||||
# Test that the address can be parsed correctly
|
||||
port_str = ma.value_for_protocol("tcp")
|
||||
assert port_str == "0"
|
||||
|
||||
|
||||
# Test that transport has the required methods
|
||||
assert hasattr(transport, 'dial')
|
||||
assert hasattr(transport, "dial")
|
||||
assert callable(transport.dial)
|
||||
|
||||
|
||||
# 4. Address Validation Tests (CRITICAL)
|
||||
def test_address_validation_ipv4():
|
||||
"""Test IPv4 address validation"""
|
||||
upgrader = create_upgrader()
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
# upgrader = create_upgrader() # Not used in this test
|
||||
|
||||
# Valid IPv4 WebSocket addresses
|
||||
valid_addresses = [
|
||||
"/ip4/127.0.0.1/tcp/8080/ws",
|
||||
"/ip4/0.0.0.0/tcp/0/ws",
|
||||
"/ip4/192.168.1.1/tcp/443/ws",
|
||||
]
|
||||
|
||||
|
||||
# Test valid addresses can be parsed
|
||||
for addr_str in valid_addresses:
|
||||
ma = Multiaddr(addr_str)
|
||||
# Should not raise exception when creating transport address
|
||||
transport_addr = str(ma)
|
||||
assert "/ws" in transport_addr
|
||||
|
||||
|
||||
# Test that transport can handle addresses with p2p IDs
|
||||
p2p_addr = Multiaddr("/ip4/127.0.0.1/tcp/8080/ws/p2p/Qmb6owHp6eaWArVbcJJbQSyifyJBttMMjYV76N2hMbf5Vw")
|
||||
p2p_addr = Multiaddr(
|
||||
"/ip4/127.0.0.1/tcp/8080/ws/p2p/Qmb6owHp6eaWArVbcJJbQSyifyJBttMMjYV76N2hMbf5Vw"
|
||||
)
|
||||
# Should not raise exception when creating transport address
|
||||
transport_addr = str(p2p_addr)
|
||||
assert "/ws" in transport_addr
|
||||
@ -230,15 +244,14 @@ def test_address_validation_ipv4():
|
||||
|
||||
def test_address_validation_ipv6():
|
||||
"""Test IPv6 address validation"""
|
||||
upgrader = create_upgrader()
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
# upgrader = create_upgrader() # Not used in this test
|
||||
|
||||
# Valid IPv6 WebSocket addresses
|
||||
valid_addresses = [
|
||||
"/ip6/::1/tcp/8080/ws",
|
||||
"/ip6/2001:db8::1/tcp/443/ws",
|
||||
]
|
||||
|
||||
|
||||
# Test valid addresses can be parsed
|
||||
for addr_str in valid_addresses:
|
||||
ma = Multiaddr(addr_str)
|
||||
@ -248,16 +261,15 @@ def test_address_validation_ipv6():
|
||||
|
||||
def test_address_validation_dns():
|
||||
"""Test DNS address validation"""
|
||||
upgrader = create_upgrader()
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
# upgrader = create_upgrader() # Not used in this test
|
||||
|
||||
# Valid DNS WebSocket addresses
|
||||
valid_addresses = [
|
||||
"/dns4/example.com/tcp/80/ws",
|
||||
"/dns6/example.com/tcp/443/ws",
|
||||
"/dnsaddr/example.com/tcp/8080/ws",
|
||||
]
|
||||
|
||||
|
||||
# Test valid addresses can be parsed
|
||||
for addr_str in valid_addresses:
|
||||
ma = Multiaddr(addr_str)
|
||||
@ -267,21 +279,20 @@ def test_address_validation_dns():
|
||||
|
||||
def test_address_validation_mixed():
|
||||
"""Test mixed address validation"""
|
||||
upgrader = create_upgrader()
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
# upgrader = create_upgrader() # Not used in this test
|
||||
|
||||
# Mixed valid and invalid addresses
|
||||
addresses = [
|
||||
"/ip4/127.0.0.1/tcp/8080/ws", # Valid
|
||||
"/ip4/127.0.0.1/tcp/8080", # Invalid (no /ws)
|
||||
"/ip6/::1/tcp/8080/ws", # Valid
|
||||
"/ip4/127.0.0.1/ws", # Invalid (no tcp)
|
||||
"/ip4/127.0.0.1/tcp/8080", # Invalid (no /ws)
|
||||
"/ip6/::1/tcp/8080/ws", # Valid
|
||||
"/ip4/127.0.0.1/ws", # Invalid (no tcp)
|
||||
"/dns4/example.com/tcp/80/ws", # Valid
|
||||
]
|
||||
|
||||
|
||||
# Convert to Multiaddr objects
|
||||
multiaddrs = [Multiaddr(addr) for addr in addresses]
|
||||
|
||||
|
||||
# Test that valid addresses can be processed
|
||||
valid_count = 0
|
||||
for ma in multiaddrs:
|
||||
@ -292,7 +303,7 @@ def test_address_validation_mixed():
|
||||
valid_count += 1
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
assert valid_count == 3 # Should have 3 valid addresses
|
||||
|
||||
|
||||
@ -302,30 +313,29 @@ async def test_dial_invalid_address():
|
||||
"""Test dialing invalid addresses"""
|
||||
upgrader = create_upgrader()
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
|
||||
# Test dialing non-WebSocket addresses
|
||||
invalid_addresses = [
|
||||
Multiaddr("/ip4/127.0.0.1/tcp/8080"), # No /ws
|
||||
Multiaddr("/ip4/127.0.0.1/ws"), # No tcp
|
||||
]
|
||||
|
||||
|
||||
for ma in invalid_addresses:
|
||||
with pytest.raises((ValueError, OpenConnectionError, Exception)):
|
||||
with pytest.raises(Exception):
|
||||
await transport.dial(ma)
|
||||
|
||||
|
||||
@pytest.mark.trio
|
||||
async def test_listen_invalid_address():
|
||||
"""Test listening on invalid addresses"""
|
||||
upgrader = create_upgrader()
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
# upgrader = create_upgrader() # Not used in this test
|
||||
|
||||
# Test listening on non-WebSocket addresses
|
||||
invalid_addresses = [
|
||||
Multiaddr("/ip4/127.0.0.1/tcp/8080"), # No /ws
|
||||
Multiaddr("/ip4/127.0.0.1/ws"), # No tcp
|
||||
]
|
||||
|
||||
|
||||
# Test that invalid addresses are properly identified
|
||||
for ma in invalid_addresses:
|
||||
# Test that the address parsing works correctly
|
||||
@ -342,17 +352,17 @@ async def test_listen_port_in_use():
|
||||
"""Test listening on port that's in use"""
|
||||
upgrader = create_upgrader()
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
|
||||
# Test that transport can handle port conflicts
|
||||
ma1 = Multiaddr("/ip4/127.0.0.1/tcp/8080/ws")
|
||||
ma2 = Multiaddr("/ip4/127.0.0.1/tcp/8080/ws")
|
||||
|
||||
|
||||
# Test that both addresses can be parsed
|
||||
assert ma1.value_for_protocol("tcp") == "8080"
|
||||
assert ma2.value_for_protocol("tcp") == "8080"
|
||||
|
||||
|
||||
# Test that transport can handle these addresses
|
||||
assert hasattr(transport, 'create_listener')
|
||||
assert hasattr(transport, "create_listener")
|
||||
assert callable(transport.create_listener)
|
||||
|
||||
|
||||
@ -362,16 +372,19 @@ async def test_connection_close():
|
||||
"""Test connection closing"""
|
||||
upgrader = create_upgrader()
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
|
||||
# Test that transport has required methods
|
||||
assert hasattr(transport, 'dial')
|
||||
assert hasattr(transport, "dial")
|
||||
assert callable(transport.dial)
|
||||
|
||||
|
||||
# Test that listener can be created and closed
|
||||
listener = transport.create_listener(lambda conn: None)
|
||||
assert hasattr(listener, 'close')
|
||||
async def dummy_handler(conn):
|
||||
await trio.sleep(0)
|
||||
|
||||
listener = transport.create_listener(dummy_handler)
|
||||
assert hasattr(listener, "close")
|
||||
assert callable(listener.close)
|
||||
|
||||
|
||||
# Test that listener can be closed
|
||||
await listener.close()
|
||||
|
||||
@ -381,32 +394,26 @@ async def test_multiple_connections():
|
||||
"""Test multiple concurrent connections"""
|
||||
upgrader = create_upgrader()
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
|
||||
# Test that transport can handle multiple addresses
|
||||
addresses = [
|
||||
Multiaddr("/ip4/127.0.0.1/tcp/8080/ws"),
|
||||
Multiaddr("/ip4/127.0.0.1/tcp/8081/ws"),
|
||||
Multiaddr("/ip4/127.0.0.1/tcp/8082/ws"),
|
||||
]
|
||||
|
||||
|
||||
# Test that all addresses can be parsed
|
||||
for addr in addresses:
|
||||
host = addr.value_for_protocol("ip4")
|
||||
port = addr.value_for_protocol("tcp")
|
||||
assert host == "127.0.0.1"
|
||||
assert port in ["8080", "8081", "8082"]
|
||||
|
||||
|
||||
# Test that transport has required methods
|
||||
assert hasattr(transport, 'dial')
|
||||
assert hasattr(transport, "dial")
|
||||
assert callable(transport.dial)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Original test (kept for compatibility)
|
||||
@pytest.mark.trio
|
||||
async def test_websocket_dial_and_listen():
|
||||
@ -414,42 +421,40 @@ async def test_websocket_dial_and_listen():
|
||||
# Test that WebSocket transport can handle basic operations
|
||||
upgrader = create_upgrader()
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
|
||||
# Test that transport can create listeners
|
||||
listener = transport.create_listener(lambda conn: None)
|
||||
async def dummy_handler(conn):
|
||||
await trio.sleep(0)
|
||||
|
||||
listener = transport.create_listener(dummy_handler)
|
||||
assert listener is not None
|
||||
assert hasattr(listener, 'listen')
|
||||
assert hasattr(listener, 'close')
|
||||
assert hasattr(listener, 'get_addrs')
|
||||
|
||||
assert hasattr(listener, "listen")
|
||||
assert hasattr(listener, "close")
|
||||
assert hasattr(listener, "get_addrs")
|
||||
|
||||
# Test that transport can handle WebSocket addresses
|
||||
ma = Multiaddr("/ip4/127.0.0.1/tcp/0/ws")
|
||||
assert ma.value_for_protocol("ip4") == "127.0.0.1"
|
||||
assert ma.value_for_protocol("tcp") == "0"
|
||||
assert "ws" in str(ma)
|
||||
|
||||
|
||||
# Test that transport has dial method
|
||||
assert hasattr(transport, 'dial')
|
||||
assert hasattr(transport, "dial")
|
||||
assert callable(transport.dial)
|
||||
|
||||
|
||||
# Test that transport can handle WebSocket multiaddrs
|
||||
ws_addr = Multiaddr("/ip4/127.0.0.1/tcp/8080/ws")
|
||||
assert ws_addr.value_for_protocol("ip4") == "127.0.0.1"
|
||||
assert ws_addr.value_for_protocol("tcp") == "8080"
|
||||
assert "ws" in str(ws_addr)
|
||||
|
||||
|
||||
# Cleanup
|
||||
await listener.close()
|
||||
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@pytest.mark.trio
|
||||
async def test_websocket_transport_basic():
|
||||
"""Test basic WebSocket transport functionality without full libp2p stack"""
|
||||
|
||||
# Create WebSocket transport
|
||||
key_pair = create_new_key_pair()
|
||||
upgrader = TransportUpgrader(
|
||||
@ -459,29 +464,31 @@ async def test_websocket_transport_basic():
|
||||
muxer_transports_by_protocol={TProtocol("/yamux/1.0.0"): Yamux},
|
||||
)
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
|
||||
assert transport is not None
|
||||
assert hasattr(transport, 'dial')
|
||||
assert hasattr(transport, 'create_listener')
|
||||
|
||||
listener = transport.create_listener(lambda conn: None)
|
||||
assert hasattr(transport, "dial")
|
||||
assert hasattr(transport, "create_listener")
|
||||
|
||||
async def dummy_handler(conn):
|
||||
await trio.sleep(0)
|
||||
|
||||
listener = transport.create_listener(dummy_handler)
|
||||
assert listener is not None
|
||||
assert hasattr(listener, 'listen')
|
||||
assert hasattr(listener, 'close')
|
||||
assert hasattr(listener, 'get_addrs')
|
||||
|
||||
assert hasattr(listener, "listen")
|
||||
assert hasattr(listener, "close")
|
||||
assert hasattr(listener, "get_addrs")
|
||||
|
||||
valid_addr = Multiaddr("/ip4/127.0.0.1/tcp/0/ws")
|
||||
assert valid_addr.value_for_protocol("ip4") == "127.0.0.1"
|
||||
assert valid_addr.value_for_protocol("tcp") == "0"
|
||||
assert "ws" in str(valid_addr)
|
||||
|
||||
|
||||
await listener.close()
|
||||
|
||||
|
||||
@pytest.mark.trio
|
||||
async def test_websocket_simple_connection():
|
||||
"""Test WebSocket transport creation and basic functionality without real connections"""
|
||||
|
||||
"""Test WebSocket transport creation and basic functionality without real conn"""
|
||||
# Create WebSocket transport
|
||||
key_pair = create_new_key_pair()
|
||||
upgrader = TransportUpgrader(
|
||||
@ -491,32 +498,31 @@ async def test_websocket_simple_connection():
|
||||
muxer_transports_by_protocol={TProtocol("/yamux/1.0.0"): Yamux},
|
||||
)
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
|
||||
assert transport is not None
|
||||
assert hasattr(transport, 'dial')
|
||||
assert hasattr(transport, 'create_listener')
|
||||
|
||||
assert hasattr(transport, "dial")
|
||||
assert hasattr(transport, "create_listener")
|
||||
|
||||
async def simple_handler(conn):
|
||||
await conn.close()
|
||||
|
||||
|
||||
listener = transport.create_listener(simple_handler)
|
||||
assert listener is not None
|
||||
assert hasattr(listener, 'listen')
|
||||
assert hasattr(listener, 'close')
|
||||
assert hasattr(listener, 'get_addrs')
|
||||
|
||||
assert hasattr(listener, "listen")
|
||||
assert hasattr(listener, "close")
|
||||
assert hasattr(listener, "get_addrs")
|
||||
|
||||
test_addr = Multiaddr("/ip4/127.0.0.1/tcp/0/ws")
|
||||
assert test_addr.value_for_protocol("ip4") == "127.0.0.1"
|
||||
assert test_addr.value_for_protocol("tcp") == "0"
|
||||
assert "ws" in str(test_addr)
|
||||
|
||||
|
||||
await listener.close()
|
||||
|
||||
|
||||
@pytest.mark.trio
|
||||
async def test_websocket_real_connection():
|
||||
"""Test WebSocket transport creation and basic functionality"""
|
||||
|
||||
# Create WebSocket transport
|
||||
key_pair = create_new_key_pair()
|
||||
upgrader = TransportUpgrader(
|
||||
@ -526,59 +532,57 @@ async def test_websocket_real_connection():
|
||||
muxer_transports_by_protocol={TProtocol("/yamux/1.0.0"): Yamux},
|
||||
)
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
|
||||
assert transport is not None
|
||||
assert hasattr(transport, 'dial')
|
||||
assert hasattr(transport, 'create_listener')
|
||||
|
||||
assert hasattr(transport, "dial")
|
||||
assert hasattr(transport, "create_listener")
|
||||
|
||||
async def handler(conn):
|
||||
await conn.close()
|
||||
|
||||
|
||||
listener = transport.create_listener(handler)
|
||||
assert listener is not None
|
||||
assert hasattr(listener, 'listen')
|
||||
assert hasattr(listener, 'close')
|
||||
assert hasattr(listener, 'get_addrs')
|
||||
|
||||
assert hasattr(listener, "listen")
|
||||
assert hasattr(listener, "close")
|
||||
assert hasattr(listener, "get_addrs")
|
||||
|
||||
await listener.close()
|
||||
|
||||
|
||||
@pytest.mark.trio
|
||||
async def test_websocket_with_tcp_fallback():
|
||||
"""Test WebSocket functionality using TCP transport as fallback"""
|
||||
|
||||
from tests.utils.factories import host_pair_factory
|
||||
|
||||
|
||||
async with host_pair_factory() as (host_a, host_b):
|
||||
assert len(host_a.get_network().connections) > 0
|
||||
assert len(host_b.get_network().connections) > 0
|
||||
|
||||
|
||||
test_protocol = TProtocol("/test/protocol/1.0.0")
|
||||
received_data = None
|
||||
|
||||
|
||||
async def test_handler(stream):
|
||||
nonlocal received_data
|
||||
received_data = await stream.read(1024)
|
||||
await stream.write(b"Response from TCP")
|
||||
await stream.close()
|
||||
|
||||
|
||||
host_a.set_stream_handler(test_protocol, test_handler)
|
||||
stream = await host_b.new_stream(host_a.get_id(), [test_protocol])
|
||||
|
||||
|
||||
test_data = b"TCP protocol test"
|
||||
await stream.write(test_data)
|
||||
response = await stream.read(1024)
|
||||
|
||||
|
||||
assert received_data == test_data
|
||||
assert response == b"Response from TCP"
|
||||
|
||||
|
||||
await stream.close()
|
||||
|
||||
|
||||
@pytest.mark.trio
|
||||
async def test_websocket_transport_interface():
|
||||
"""Test WebSocket transport interface compliance"""
|
||||
|
||||
key_pair = create_new_key_pair()
|
||||
upgrader = TransportUpgrader(
|
||||
secure_transports_by_protocol={
|
||||
@ -586,23 +590,26 @@ async def test_websocket_transport_interface():
|
||||
},
|
||||
muxer_transports_by_protocol={TProtocol("/yamux/1.0.0"): Yamux},
|
||||
)
|
||||
|
||||
|
||||
transport = WebsocketTransport(upgrader)
|
||||
|
||||
assert hasattr(transport, 'dial')
|
||||
assert hasattr(transport, 'create_listener')
|
||||
|
||||
assert hasattr(transport, "dial")
|
||||
assert hasattr(transport, "create_listener")
|
||||
assert callable(transport.dial)
|
||||
assert callable(transport.create_listener)
|
||||
|
||||
listener = transport.create_listener(lambda conn: None)
|
||||
assert hasattr(listener, 'listen')
|
||||
assert hasattr(listener, 'close')
|
||||
assert hasattr(listener, 'get_addrs')
|
||||
|
||||
|
||||
async def dummy_handler(conn):
|
||||
await trio.sleep(0)
|
||||
|
||||
listener = transport.create_listener(dummy_handler)
|
||||
assert hasattr(listener, "listen")
|
||||
assert hasattr(listener, "close")
|
||||
assert hasattr(listener, "get_addrs")
|
||||
|
||||
test_addr = Multiaddr("/ip4/127.0.0.1/tcp/8080/ws")
|
||||
host = test_addr.value_for_protocol("ip4")
|
||||
port = test_addr.value_for_protocol("tcp")
|
||||
assert host == "127.0.0.1"
|
||||
assert port == "8080"
|
||||
|
||||
|
||||
await listener.close()
|
||||
|
||||
@ -20,7 +20,7 @@ from libp2p.stream_muxer.yamux.yamux import Yamux
|
||||
from libp2p.transport.upgrader import TransportUpgrader
|
||||
from libp2p.transport.websocket.transport import WebsocketTransport
|
||||
|
||||
PLAINTEXT_PROTOCOL_ID = "/plaintext/1.0.0"
|
||||
PLAINTEXT_PROTOCOL_ID = "/plaintext/2.0.0"
|
||||
|
||||
|
||||
@pytest.mark.trio
|
||||
@ -74,6 +74,11 @@ async def test_ping_with_js_node():
|
||||
peer_id = ID.from_base58(peer_id_line)
|
||||
maddr = Multiaddr(addr_line)
|
||||
|
||||
# Debug: Print what we're trying to connect to
|
||||
print(f"JS Node Peer ID: {peer_id_line}")
|
||||
print(f"JS Node Address: {addr_line}")
|
||||
print(f"All JS Node lines: {lines}")
|
||||
|
||||
# Set up Python host
|
||||
key_pair = create_new_key_pair()
|
||||
py_peer_id = ID.from_pubkey(key_pair.public_key)
|
||||
@ -86,13 +91,15 @@ async def test_ping_with_js_node():
|
||||
},
|
||||
muxer_transports_by_protocol={TProtocol("/yamux/1.0.0"): Yamux},
|
||||
)
|
||||
transport = WebsocketTransport()
|
||||
transport = WebsocketTransport(upgrader)
|
||||
swarm = Swarm(py_peer_id, peer_store, upgrader, transport)
|
||||
host = BasicHost(swarm)
|
||||
|
||||
# Connect to JS node
|
||||
peer_info = PeerInfo(peer_id, [maddr])
|
||||
|
||||
print(f"Python trying to connect to: {peer_info}")
|
||||
|
||||
await trio.sleep(1)
|
||||
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user