8383 has_ipv6 = True
8484
8585skip_ipv6_mark = pytest .mark .skipif (not has_ipv6 , reason = "IPv6 is not available" )
86+ skip_unix_abstract_mark = pytest .mark .skipif (
87+ not sys .platform .startswith ("linux" ),
88+ reason = "Abstract namespace sockets is a Linux only feature" ,
89+ )
8690
8791
8892@pytest .fixture
@@ -735,12 +739,20 @@ async def test_bind_link_local(self) -> None:
735739 sys .platform == "win32" , reason = "UNIX sockets are not available on Windows"
736740)
737741class TestUNIXStream :
738- @pytest .fixture
739- def socket_path (self ) -> Generator [Path , None , None ]:
742+ @pytest .fixture (
743+ params = [
744+ "path" ,
745+ pytest .param ("abstract" , marks = [skip_unix_abstract_mark ]),
746+ ]
747+ )
748+ def socket_path (self , request : SubRequest ) -> Generator [Path , None , None ]:
740749 # Use stdlib tempdir generation
741750 # Fixes `OSError: AF_UNIX path too long` from pytest generated temp_path
742751 with tempfile .TemporaryDirectory () as path :
743- yield Path (path ) / "socket"
752+ if request .param == "path" :
753+ yield Path (path ) / "socket"
754+ else :
755+ yield Path (f"\0 { path } " ) / "socket"
744756
745757 @pytest .fixture (params = [False , True ], ids = ["str" , "path" ])
746758 def socket_path_or_str (self , request : SubRequest , socket_path : Path ) -> Path | str :
@@ -764,7 +776,15 @@ async def test_extra_attributes(
764776 assert (
765777 stream .extra (SocketAttribute .local_address ) == raw_socket .getsockname ()
766778 )
767- assert stream .extra (SocketAttribute .remote_address ) == str (socket_path )
779+ remote_addr = stream .extra (SocketAttribute .remote_address )
780+ if isinstance (remote_addr , str ):
781+ assert stream .extra (SocketAttribute .remote_address ) == str (socket_path )
782+ else :
783+ assert isinstance (remote_addr , bytes )
784+ assert stream .extra (SocketAttribute .remote_address ) == bytes (
785+ socket_path
786+ )
787+
768788 pytest .raises (
769789 TypedAttributeLookupError , stream .extra , SocketAttribute .local_port
770790 )
@@ -1031,8 +1051,12 @@ async def test_send_after_close(
10311051 await stream .send (b"foo" )
10321052
10331053 async def test_cannot_connect (self , socket_path : Path ) -> None :
1034- with pytest .raises (FileNotFoundError ):
1035- await connect_unix (socket_path )
1054+ if str (socket_path ).startswith ("\0 " ):
1055+ with pytest .raises (ConnectionRefusedError ):
1056+ await connect_unix (socket_path )
1057+ else :
1058+ with pytest .raises (FileNotFoundError ):
1059+ await connect_unix (socket_path )
10361060
10371061 async def test_connecting_using_bytes (
10381062 self , server_sock : socket .socket , socket_path : Path
@@ -1057,12 +1081,20 @@ async def test_connecting_with_non_utf8(self, socket_path: Path) -> None:
10571081 sys .platform == "win32" , reason = "UNIX sockets are not available on Windows"
10581082)
10591083class TestUNIXListener :
1060- @pytest .fixture
1061- def socket_path (self ) -> Generator [Path , None , None ]:
1084+ @pytest .fixture (
1085+ params = [
1086+ "path" ,
1087+ pytest .param ("abstract" , marks = [skip_unix_abstract_mark ]),
1088+ ]
1089+ )
1090+ def socket_path (self , request : SubRequest ) -> Generator [Path , None , None ]:
10621091 # Use stdlib tempdir generation
10631092 # Fixes `OSError: AF_UNIX path too long` from pytest generated temp_path
10641093 with tempfile .TemporaryDirectory () as path :
1065- yield Path (path ) / "socket"
1094+ if request .param == "path" :
1095+ yield Path (path ) / "socket"
1096+ else :
1097+ yield Path (f"\0 { path } " ) / "socket"
10661098
10671099 @pytest .fixture (params = [False , True ], ids = ["str" , "path" ])
10681100 def socket_path_or_str (self , request : SubRequest , socket_path : Path ) -> Path | str :
@@ -1461,12 +1493,20 @@ async def test_send_after_close(self, family: AnyIPAddressFamily) -> None:
14611493 sys .platform == "win32" , reason = "UNIX sockets are not available on Windows"
14621494)
14631495class TestUNIXDatagramSocket :
1464- @pytest .fixture
1465- def socket_path (self ) -> Generator [Path , None , None ]:
1496+ @pytest .fixture (
1497+ params = [
1498+ "path" ,
1499+ pytest .param ("abstract" , marks = [skip_unix_abstract_mark ]),
1500+ ]
1501+ )
1502+ def socket_path (self , request : SubRequest ) -> Generator [Path , None , None ]:
14661503 # Use stdlib tempdir generation
14671504 # Fixes `OSError: AF_UNIX path too long` from pytest generated temp_path
14681505 with tempfile .TemporaryDirectory () as path :
1469- yield Path (path ) / "socket"
1506+ if request .param == "path" :
1507+ yield Path (path ) / "socket"
1508+ else :
1509+ yield Path (f"\0 { path } " ) / "socket"
14701510
14711511 @pytest .fixture (params = [False , True ], ids = ["str" , "path" ])
14721512 def socket_path_or_str (self , request : SubRequest , socket_path : Path ) -> Path | str :
@@ -1506,12 +1546,18 @@ async def test_send_receive(self, socket_path_or_str: Path | str) -> None:
15061546 await sock .sendto (b"blah" , path )
15071547 request , addr = await sock .receive ()
15081548 assert request == b"blah"
1509- assert addr == path
1549+ if isinstance (addr , bytes ):
1550+ assert addr == path .encode ()
1551+ else :
1552+ assert addr == path
15101553
15111554 await sock .sendto (b"halb" , path )
15121555 response , addr = await sock .receive ()
15131556 assert response == b"halb"
1514- assert addr == path
1557+ if isinstance (addr , bytes ):
1558+ assert addr == path .encode ()
1559+ else :
1560+ assert addr == path
15151561
15161562 async def test_iterate (self , peer_socket_path : Path , socket_path : Path ) -> None :
15171563 async def serve () -> None :
@@ -1589,18 +1635,33 @@ async def test_local_path_invalid_ascii(self, socket_path: Path) -> None:
15891635 sys .platform == "win32" , reason = "UNIX sockets are not available on Windows"
15901636)
15911637class TestConnectedUNIXDatagramSocket :
1592- @pytest .fixture
1593- def socket_path (self ) -> Generator [Path , None , None ]:
1638+ @pytest .fixture (
1639+ params = [
1640+ "path" ,
1641+ pytest .param ("abstract" , marks = [skip_unix_abstract_mark ]),
1642+ ]
1643+ )
1644+ def socket_path (self , request : SubRequest ) -> Generator [Path , None , None ]:
15941645 # Use stdlib tempdir generation
15951646 # Fixes `OSError: AF_UNIX path too long` from pytest generated temp_path
15961647 with tempfile .TemporaryDirectory () as path :
1597- yield Path (path ) / "socket"
1648+ if request .param == "path" :
1649+ yield Path (path ) / "socket"
1650+ else :
1651+ yield Path (f"\0 { path } " ) / "socket"
15981652
15991653 @pytest .fixture (params = [False , True ], ids = ["str" , "path" ])
16001654 def socket_path_or_str (self , request : SubRequest , socket_path : Path ) -> Path | str :
16011655 return socket_path if request .param else str (socket_path )
16021656
1603- @pytest .fixture
1657+ @pytest .fixture (
1658+ params = [
1659+ pytest .param ("path" , id = "path-peer" ),
1660+ pytest .param (
1661+ "abstract" , marks = [skip_unix_abstract_mark ], id = "abstract-peer"
1662+ ),
1663+ ]
1664+ )
16041665 def peer_socket_path (self ) -> Generator [Path , None , None ]:
16051666 # Use stdlib tempdir generation
16061667 # Fixes `OSError: AF_UNIX path too long` from pytest generated temp_path
@@ -1634,10 +1695,12 @@ async def test_extra_attributes(
16341695 raw_socket = unix_dg .extra (SocketAttribute .raw_socket )
16351696 assert raw_socket is not None
16361697 assert unix_dg .extra (SocketAttribute .family ) == AddressFamily .AF_UNIX
1637- assert unix_dg .extra (SocketAttribute .local_address ) == str (socket_path )
1638- assert unix_dg .extra (SocketAttribute .remote_address ) == str (
1639- peer_socket_path
1640- )
1698+ assert os .fsencode (
1699+ cast (os .PathLike , unix_dg .extra (SocketAttribute .local_address ))
1700+ ) == os .fsencode (socket_path )
1701+ assert os .fsencode (
1702+ cast (os .PathLike , unix_dg .extra (SocketAttribute .remote_address ))
1703+ ) == os .fsencode (peer_socket_path )
16411704 pytest .raises (
16421705 TypedAttributeLookupError , unix_dg .extra , SocketAttribute .local_port
16431706 )
@@ -1657,11 +1720,11 @@ async def test_send_receive(
16571720 peer_socket_path_or_str ,
16581721 local_path = socket_path_or_str ,
16591722 ) as unix_dg2 :
1660- socket_path = str (socket_path_or_str )
1723+ socket_path = os . fsdecode (socket_path_or_str )
16611724
16621725 await unix_dg2 .send (b"blah" )
1663- request = await unix_dg1 .receive ()
1664- assert request == (b"blah" , socket_path )
1726+ data , remote_addr = await unix_dg1 .receive ()
1727+ assert ( data , os . fsdecode ( remote_addr )) == (b"blah" , socket_path )
16651728
16661729 await unix_dg1 .sendto (b"halb" , socket_path )
16671730 response = await unix_dg2 .receive ()
@@ -1682,13 +1745,15 @@ async def serve() -> None:
16821745 async with await create_connected_unix_datagram_socket (
16831746 peer_socket_path , local_path = socket_path
16841747 ) as unix_dg2 :
1685- path = str (socket_path )
1748+ path = os . fsdecode (socket_path )
16861749 async with create_task_group () as tg :
16871750 tg .start_soon (serve )
16881751 await unix_dg1 .sendto (b"FOOBAR" , path )
1689- assert await unix_dg1 .receive () == (b"RABOOF" , path )
1752+ data , addr = await unix_dg1 .receive ()
1753+ assert (data , os .fsdecode (addr )) == (b"RABOOF" , path )
16901754 await unix_dg1 .sendto (b"123456" , path )
1691- assert await unix_dg1 .receive () == (b"654321" , path )
1755+ data , addr = await unix_dg1 .receive ()
1756+ assert (data , os .fsdecode (addr )) == (b"654321" , path )
16921757 tg .cancel_scope .cancel ()
16931758
16941759 async def test_concurrent_receive (
0 commit comments