mirror of
https://github.com/google/bumble.git
synced 2026-06-11 09:12:27 +00:00
Enhance transports
* Support IPv6 schema * Add transport integration tests * Add UNIX socket server
This commit is contained in:
@@ -16,8 +16,7 @@ import asyncio
|
||||
import os
|
||||
import pytest
|
||||
import socket
|
||||
import unittest
|
||||
from unittest.mock import ANY, patch
|
||||
from unittest import mock
|
||||
|
||||
from bumble.transport.tcp_server import (
|
||||
open_tcp_server_transport,
|
||||
@@ -25,28 +24,23 @@ from bumble.transport.tcp_server import (
|
||||
)
|
||||
|
||||
|
||||
class OpenTcpServerTransportTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.patcher = patch('bumble.transport.tcp_server._create_server')
|
||||
self.mock_create_server = self.patcher.start()
|
||||
async def test_open_with_spec():
|
||||
with mock.patch.object(asyncio.get_running_loop(), 'create_server') as m:
|
||||
await open_tcp_server_transport('localhost:32100')
|
||||
m.assert_awaited_once_with(mock.ANY, host='localhost', port=32100)
|
||||
|
||||
def tearDown(self):
|
||||
self.patcher.stop()
|
||||
|
||||
def test_open_with_spec(self):
|
||||
asyncio.run(open_tcp_server_transport('localhost:32100'))
|
||||
self.mock_create_server.assert_awaited_once_with(
|
||||
ANY, host='localhost', port=32100
|
||||
)
|
||||
async def test_open_with_port_only_spec():
|
||||
with mock.patch.object(asyncio.get_running_loop(), 'create_server') as m:
|
||||
await open_tcp_server_transport('_:32100')
|
||||
m.assert_awaited_once_with(mock.ANY, host=None, port=32100)
|
||||
|
||||
def test_open_with_port_only_spec(self):
|
||||
asyncio.run(open_tcp_server_transport('_:32100'))
|
||||
self.mock_create_server.assert_awaited_once_with(ANY, host=None, port=32100)
|
||||
|
||||
def test_open_with_socket(self):
|
||||
async def test_open_with_socket():
|
||||
with mock.patch.object(asyncio.get_running_loop(), 'create_server') as m:
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||
asyncio.run(open_tcp_server_transport_with_socket(sock=sock))
|
||||
self.mock_create_server.assert_awaited_once_with(ANY, sock=sock)
|
||||
await open_tcp_server_transport_with_socket(sock=sock)
|
||||
m.assert_awaited_once_with(mock.ANY, sock=sock)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
|
||||
@@ -17,9 +17,41 @@
|
||||
# -----------------------------------------------------------------------------
|
||||
import random
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
from bumble import controller
|
||||
from bumble import device
|
||||
from bumble import hci
|
||||
from bumble import link
|
||||
from bumble import transport
|
||||
from bumble.transport.common import PacketParser
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def _make_controller_from_transport(transport: transport.Transport):
|
||||
return controller.Controller(
|
||||
name="server",
|
||||
host_sink=transport.sink,
|
||||
host_source=transport.source,
|
||||
link=link.LocalLink(),
|
||||
)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
def _make_device_from_transport(
|
||||
transport: transport.Transport, address: str = "11:22:33:44:55:66"
|
||||
):
|
||||
return device.Device.with_hci(
|
||||
name="client",
|
||||
address=hci.Address(address),
|
||||
hci_sink=transport.sink,
|
||||
hci_source=transport.source,
|
||||
)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
class Sink:
|
||||
def __init__(self):
|
||||
@@ -71,6 +103,109 @@ def test_parser_extensions():
|
||||
assert len(sink.packets) == 1
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@pytest.mark.parametrize(
|
||||
"address,",
|
||||
("127.0.0.1", "::1"),
|
||||
)
|
||||
async def test_tcp_connection(address):
|
||||
server_transport = await transport.open_transport(f"tcp-server:{address}:0")
|
||||
port = server_transport.server.sockets[0].getsockname()[1]
|
||||
_make_controller_from_transport(server_transport)
|
||||
|
||||
client_transport = await transport.open_transport(f"tcp-client:{address}:{port}")
|
||||
client_device = _make_device_from_transport(client_transport)
|
||||
await client_device.power_on()
|
||||
|
||||
await client_transport.close()
|
||||
await server_transport.close()
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@pytest.mark.parametrize(
|
||||
"address, family",
|
||||
(("127.0.0.1", socket.AF_INET), ("::1", socket.AF_INET6)),
|
||||
)
|
||||
async def test_udp_connection(address, family):
|
||||
# Pick empty ports
|
||||
ports = []
|
||||
for _ in range(2):
|
||||
sock = socket.socket(family=family, type=socket.SOCK_DGRAM)
|
||||
sock.bind((address, 0))
|
||||
ports.append(sock.getsockname()[1])
|
||||
sock.close()
|
||||
|
||||
server_transport = await transport.open_transport(
|
||||
f"udp:{address}:{ports[0]},{address}:{ports[1]}"
|
||||
)
|
||||
_make_controller_from_transport(server_transport)
|
||||
|
||||
client_transport = await transport.open_transport(
|
||||
f"udp:{address}:{ports[1]},{address}:{ports[0]}"
|
||||
)
|
||||
client_device = _make_device_from_transport(client_transport)
|
||||
await client_device.power_on()
|
||||
|
||||
await client_transport.close()
|
||||
await server_transport.close()
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@pytest.mark.parametrize(
|
||||
"server_address, client_address",
|
||||
(
|
||||
("127.0.0.1", "ws://127.0.0.1"),
|
||||
("::1", "ws://[::1]"),
|
||||
),
|
||||
)
|
||||
async def test_ws_connection(server_address, client_address):
|
||||
server_transport = await transport.open_transport(f"ws-server:{server_address}:0")
|
||||
port = server_transport.server.sockets[0].getsockname()[1]
|
||||
_make_controller_from_transport(server_transport)
|
||||
|
||||
client_transport = await transport.open_transport(
|
||||
f"ws-client:{client_address}:{port}"
|
||||
)
|
||||
client_device = _make_device_from_transport(client_transport)
|
||||
await client_device.power_on()
|
||||
|
||||
await client_transport.close()
|
||||
await server_transport.close()
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@pytest.mark.skipif(
|
||||
sys.platform != 'linux', reason='Unix socket is only fully supported on Linux'
|
||||
)
|
||||
async def test_unix_connection_file(tmpdir):
|
||||
path = str(tmpdir / 'bumble.sock')
|
||||
server_transport = await transport.open_transport(f"unix-server:{path}")
|
||||
_make_controller_from_transport(server_transport)
|
||||
|
||||
client_transport = await transport.open_transport(f"unix-client:{path}")
|
||||
client_device = _make_device_from_transport(client_transport)
|
||||
await client_device.power_on()
|
||||
|
||||
await client_transport.close()
|
||||
await server_transport.close()
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@pytest.mark.skipif(
|
||||
sys.platform != 'linux', reason='Unix socket is only fully supported on Linux'
|
||||
)
|
||||
async def test_unix_connection_abstract():
|
||||
server_transport = await transport.open_transport("unix-server:@bumble.test.sock")
|
||||
_make_controller_from_transport(server_transport)
|
||||
|
||||
client_transport = await transport.open_transport("unix-client:@bumble.test.sock")
|
||||
client_device = _make_device_from_transport(client_transport)
|
||||
await client_device.power_on()
|
||||
|
||||
await client_transport.close()
|
||||
await server_transport.close()
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
test_parser()
|
||||
|
||||
Reference in New Issue
Block a user