diff --git a/bumble/transport/__init__.py b/bumble/transport/__init__.py index 0dbfef9..b160be4 100644 --- a/bumble/transport/__init__.py +++ b/bumble/transport/__init__.py @@ -12,13 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import logging -import os - # ----------------------------------------------------------------------------- # Imports # ----------------------------------------------------------------------------- -from contextlib import asynccontextmanager +import logging +import os +import re from typing import Optional from bumble import utils @@ -85,12 +84,14 @@ async def open_transport(name: str) -> Transport: scheme, *tail = name.split(':', 1) spec = tail[0] if tail else None metadata = None - if spec: - # Metadata may precede the spec - if spec.startswith('['): - metadata_str, *tail = spec[1:].split(']') - spec = tail[0] if tail else None - metadata = dict([entry.split('=') for entry in metadata_str.split(',')]) + if spec and (m := re.search(r'\[(\w+=\w+(?:,\w+=\w+)*,?)\]', spec)): + metadata_str = m.group(1) + if m.start() == 0: + # + spec = spec[m.end() :] + else: + spec = spec[: m.start()] + metadata = dict([entry.split('=') for entry in metadata_str.split(',')]) transport = await _open_transport(scheme, spec) if metadata: diff --git a/tests/transport_test.py b/tests/transport_test.py index d8e1087..bf7d8d4 100644 --- a/tests/transport_test.py +++ b/tests/transport_test.py @@ -24,7 +24,7 @@ import sys import pytest from bumble import controller, device, hci, link, transport -from bumble.transport.common import PacketParser +from bumble.transport import common # ----------------------------------------------------------------------------- @@ -61,9 +61,9 @@ class Sink: # ----------------------------------------------------------------------------- def test_parser(): sink1 = Sink() - parser1 = PacketParser(sink1) + parser1 = common.PacketParser(sink1) sink2 = Sink() - parser2 = PacketParser(sink2) + parser2 = common.PacketParser(sink2) for parser in [parser1, parser2]: with open( @@ -82,7 +82,7 @@ def test_parser(): # ----------------------------------------------------------------------------- def test_parser_extensions(): sink = Sink() - parser = PacketParser(sink) + parser = common.PacketParser(sink) # Check that an exception is thrown for an unknown type try: @@ -206,7 +206,7 @@ async def test_unix_connection_abstract(): # ----------------------------------------------------------------------------- @pytest.mark.parametrize( "address,", - ("127.0.0.1",), + ("127.0.0.1", "[::1]"), ) async def test_android_netsim_connection(address): controller_transport = await transport.open_transport( @@ -222,6 +222,33 @@ async def test_android_netsim_connection(address): await client_device.power_on() await client_transport.close() + await controller_transport.source.grpc_server.stop(None) + await controller_transport.close() + + +# ----------------------------------------------------------------------------- +@pytest.mark.parametrize( + "spec,", + ( + "android-netsim:[::1]:{port},mode=host[a=b,c=d]", + "android-netsim:localhost:{port},mode=host[a=b,c=d]", + "android-netsim:[a=b,c=d][::1]:{port},mode=host", + "android-netsim:[a=b,c=d]localhost:{port},mode=host", + ), +) +async def test_open_transport_with_metadata(spec): + controller_transport = await transport.open_transport( + "android-netsim:_:0,mode=controller" + ) + port = controller_transport.source.port + _make_controller_from_transport(controller_transport) + + client_transport = await transport.open_transport(spec.format(port=port)) + assert client_transport.source.metadata['a'] == 'b' + assert client_transport.source.metadata['c'] == 'd' + + await client_transport.close() + await controller_transport.source.grpc_server.stop(None) await controller_transport.close()