''' Canonical tagged-address decoding and legacy input compatibility. ''' from pathlib import Path import pytest from tractor.discovery._addr import wrap_address from tractor.ipc._tcp import TCPAddress from tractor.ipc._uds import UDSAddress @pytest.mark.parametrize( 'value', [ ('tcp', '127.0.0.1', 1616), ['tcp', '127.0.0.1', 1616], ], ) def test_decode_tagged_tcp_address(value): ''' Shape-only decoding cannot distinguish future transport address forms. Feed canonical tuple and msgpack-style list values through the compatibility boundary and prove the explicit `tcp` tag selects the TCP backend and emits the canonical tagged form. ''' addr = wrap_address(value) assert type(addr) is TCPAddress assert addr.unwrap() == ('tcp', '127.0.0.1', 1616) @pytest.mark.parametrize( 'tag', ['unix', 'uds'], ) @pytest.mark.parametrize('container', [tuple, list]) def test_decode_tagged_unix_address( tag: str, container: type, ): ''' Multiaddr calls the protocol `unix` while tractor's transport key remains `uds`. Decode both spellings from tuple/list containers, normalize them to one `UDSAddress`, and emit the canonical `unix` spelling. ''' value = container((tag, '/tmp/tractor/registry.sock')) addr = wrap_address(value) assert type(addr) is UDSAddress assert addr.sockpath == Path('/tmp/tractor/registry.sock') assert addr.unwrap() == ( 'unix', '/tmp/tractor/registry.sock', ) @pytest.mark.parametrize( 'value, expected_type', [ (('127.0.0.1', 1616), TCPAddress), (['127.0.0.1', 1616], TCPAddress), (('/tmp/tractor', 'registry.sock'), UDSAddress), (['/tmp/tractor', 'registry.sock'], UDSAddress), ], ) def test_decode_legacy_address_forms( value, expected_type: type, ): ''' Existing callers, config, and older msgpack payloads still provide untagged pairs. Keep tuple/list forms readable while canonical tagged emission is introduced, proving the writer migration does not break shipped input behavior. ''' addr = wrap_address(value) assert type(addr) is expected_type assert addr.unwrap()[0] in {'tcp', 'unix'} def test_tcp_from_native_ipv6_sockname(): ''' `socket.getsockname()` returns a four-item IPv6 sockaddr which is neither a wire form nor a legacy two-item pair. Preserve it as an OS compatibility boundary and intentionally ignore unsupported flow-info/scope-id fields when constructing `TCPAddress`. ''' addr = TCPAddress.from_addr( ('::1', 1616, 0, 0) ) assert addr.unwrap() == ('tcp', '::1', 1616)