Skip to content

Commit c5b750d

Browse files
authored
gh-93852: Add test.support.create_unix_domain_name() (#93914)
test_asyncio, test_logging, test_socket and test_socketserver now create AF_UNIX domains in the current directory to no longer fail with OSError("AF_UNIX path too long") if the temporary directory (the TMPDIR environment variable) is too long. Modify the following tests to use create_unix_domain_name(): * test_asyncio * test_logging * test_socket * test_socketserver test_asyncio.utils: remove unused time import.
1 parent ffc228d commit c5b750d

File tree

7 files changed

+82
-86
lines changed

7 files changed

+82
-86
lines changed

Lib/test/support/socket_helper.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import contextlib
22
import errno
3+
import os.path
34
import socket
4-
import unittest
55
import sys
6+
import tempfile
7+
import unittest
68

79
from .. import support
810
from . import warnings_helper
@@ -270,3 +272,14 @@ def filter_error(err):
270272
# __cause__ or __context__?
271273
finally:
272274
socket.setdefaulttimeout(old_timeout)
275+
276+
277+
def create_unix_domain_name():
278+
"""
279+
Create a UNIX domain name: socket.bind() argument of a AF_UNIX socket.
280+
281+
Return a path relative to the current directory to get a short path
282+
(around 27 ASCII characters).
283+
"""
284+
return tempfile.mktemp(prefix="test_python_", suffix='.sock',
285+
dir=os.path.curdir)

Lib/test/test_asyncio/test_unix_events.py

+21-19
Original file line numberDiff line numberDiff line change
@@ -315,11 +315,15 @@ def test_create_unix_connection_pathlib(self):
315315
self.loop.run_until_complete(coro)
316316

317317
def test_create_unix_server_existing_path_nonsock(self):
318-
with tempfile.NamedTemporaryFile() as file:
319-
coro = self.loop.create_unix_server(lambda: None, file.name)
320-
with self.assertRaisesRegex(OSError,
321-
'Address.*is already in use'):
322-
self.loop.run_until_complete(coro)
318+
path = test_utils.gen_unix_socket_path()
319+
self.addCleanup(os_helper.unlink, path)
320+
# create the file
321+
open(path, "wb").close()
322+
323+
coro = self.loop.create_unix_server(lambda: None, path)
324+
with self.assertRaisesRegex(OSError,
325+
'Address.*is already in use'):
326+
self.loop.run_until_complete(coro)
323327

324328
def test_create_unix_server_ssl_bool(self):
325329
coro = self.loop.create_unix_server(lambda: None, path='spam',
@@ -356,20 +360,18 @@ def test_create_unix_server_path_dgram(self):
356360
'no socket.SOCK_NONBLOCK (linux only)')
357361
@socket_helper.skip_unless_bind_unix_socket
358362
def test_create_unix_server_path_stream_bittype(self):
359-
sock = socket.socket(
360-
socket.AF_UNIX, socket.SOCK_STREAM | socket.SOCK_NONBLOCK)
361-
with tempfile.NamedTemporaryFile() as file:
362-
fn = file.name
363-
try:
364-
with sock:
365-
sock.bind(fn)
366-
coro = self.loop.create_unix_server(lambda: None, path=None,
367-
sock=sock)
368-
srv = self.loop.run_until_complete(coro)
369-
srv.close()
370-
self.loop.run_until_complete(srv.wait_closed())
371-
finally:
372-
os.unlink(fn)
363+
fn = test_utils.gen_unix_socket_path()
364+
self.addCleanup(os_helper.unlink, fn)
365+
366+
sock = socket.socket(socket.AF_UNIX,
367+
socket.SOCK_STREAM | socket.SOCK_NONBLOCK)
368+
with sock:
369+
sock.bind(fn)
370+
coro = self.loop.create_unix_server(lambda: None, path=None,
371+
sock=sock)
372+
srv = self.loop.run_until_complete(coro)
373+
srv.close()
374+
self.loop.run_until_complete(srv.wait_closed())
373375

374376
def test_create_unix_server_ssl_timeout_with_plain_sock(self):
375377
coro = self.loop.create_unix_server(lambda: None, path='spam',

Lib/test/test_asyncio/utils.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@
1111
import socket
1212
import socketserver
1313
import sys
14-
import tempfile
1514
import threading
16-
import time
1715
import unittest
1816
import weakref
1917

@@ -34,6 +32,7 @@
3432
from asyncio import tasks
3533
from asyncio.log import logger
3634
from test import support
35+
from test.support import socket_helper
3736
from test.support import threading_helper
3837

3938

@@ -251,8 +250,7 @@ class UnixSSLWSGIServer(SSLWSGIServerMixin, SilentUnixWSGIServer):
251250

252251

253252
def gen_unix_socket_path():
254-
with tempfile.NamedTemporaryFile() as file:
255-
return file.name
253+
return socket_helper.create_unix_domain_name()
256254

257255

258256
@contextlib.contextmanager

Lib/test/test_logging.py

+6-21
Original file line numberDiff line numberDiff line change
@@ -1828,12 +1828,6 @@ def test_noserver(self):
18281828
time.sleep(self.sock_hdlr.retryTime - now + 0.001)
18291829
self.root_logger.error('Nor this')
18301830

1831-
def _get_temp_domain_socket():
1832-
fn = make_temp_file(prefix='test_logging_', suffix='.sock')
1833-
# just need a name - file can't be present, or we'll get an
1834-
# 'address already in use' error.
1835-
os.remove(fn)
1836-
return fn
18371831

18381832
@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
18391833
class UnixSocketHandlerTest(SocketHandlerTest):
@@ -1845,13 +1839,10 @@ class UnixSocketHandlerTest(SocketHandlerTest):
18451839

18461840
def setUp(self):
18471841
# override the definition in the base class
1848-
self.address = _get_temp_domain_socket()
1842+
self.address = socket_helper.create_unix_domain_name()
1843+
self.addCleanup(os_helper.unlink, self.address)
18491844
SocketHandlerTest.setUp(self)
18501845

1851-
def tearDown(self):
1852-
SocketHandlerTest.tearDown(self)
1853-
os_helper.unlink(self.address)
1854-
18551846
@support.requires_working_socket()
18561847
@threading_helper.requires_working_threading()
18571848
class DatagramHandlerTest(BaseTest):
@@ -1928,13 +1919,10 @@ class UnixDatagramHandlerTest(DatagramHandlerTest):
19281919

19291920
def setUp(self):
19301921
# override the definition in the base class
1931-
self.address = _get_temp_domain_socket()
1922+
self.address = socket_helper.create_unix_domain_name()
1923+
self.addCleanup(os_helper.unlink, self.address)
19321924
DatagramHandlerTest.setUp(self)
19331925

1934-
def tearDown(self):
1935-
DatagramHandlerTest.tearDown(self)
1936-
os_helper.unlink(self.address)
1937-
19381926
@support.requires_working_socket()
19391927
@threading_helper.requires_working_threading()
19401928
class SysLogHandlerTest(BaseTest):
@@ -2022,13 +2010,10 @@ class UnixSysLogHandlerTest(SysLogHandlerTest):
20222010

20232011
def setUp(self):
20242012
# override the definition in the base class
2025-
self.address = _get_temp_domain_socket()
2013+
self.address = socket_helper.create_unix_domain_name()
2014+
self.addCleanup(os_helper.unlink, self.address)
20262015
SysLogHandlerTest.setUp(self)
20272016

2028-
def tearDown(self):
2029-
SysLogHandlerTest.tearDown(self)
2030-
os_helper.unlink(self.address)
2031-
20322017
@unittest.skipUnless(socket_helper.IPV6_ENABLED,
20332018
'IPv6 support required for this test.')
20342019
class IPv6SysLogHandlerTest(SysLogHandlerTest):

Lib/test/test_socket.py

+34-38
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,30 @@
44
from test.support import socket_helper
55
from test.support import threading_helper
66

7+
import _thread as thread
8+
import array
9+
import contextlib
710
import errno
811
import io
912
import itertools
10-
import socket
11-
import select
12-
import tempfile
13-
import time
14-
import traceback
15-
import queue
16-
import sys
17-
import os
18-
import platform
19-
import array
20-
import contextlib
21-
from weakref import proxy
22-
import signal
2313
import math
14+
import os
2415
import pickle
25-
import re
26-
import struct
16+
import platform
17+
import queue
2718
import random
28-
import shutil
19+
import re
20+
import select
21+
import signal
22+
import socket
2923
import string
30-
import _thread as thread
24+
import struct
25+
import sys
26+
import tempfile
3127
import threading
28+
import time
29+
import traceback
30+
from weakref import proxy
3231
try:
3332
import multiprocessing
3433
except ImportError:
@@ -605,17 +604,18 @@ class SocketTestBase(unittest.TestCase):
605604

606605
def setUp(self):
607606
self.serv = self.newSocket()
607+
self.addCleanup(self.close_server)
608608
self.bindServer()
609609

610+
def close_server(self):
611+
self.serv.close()
612+
self.serv = None
613+
610614
def bindServer(self):
611615
"""Bind server socket and set self.serv_addr to its address."""
612616
self.bindSock(self.serv)
613617
self.serv_addr = self.serv.getsockname()
614618

615-
def tearDown(self):
616-
self.serv.close()
617-
self.serv = None
618-
619619

620620
class SocketListeningTestMixin(SocketTestBase):
621621
"""Mixin to listen on the server socket."""
@@ -700,15 +700,10 @@ class UnixSocketTestBase(SocketTestBase):
700700
# can't send anything that might be problematic for a privileged
701701
# user running the tests.
702702

703-
def setUp(self):
704-
self.dir_path = tempfile.mkdtemp()
705-
self.addCleanup(os.rmdir, self.dir_path)
706-
super().setUp()
707-
708703
def bindSock(self, sock):
709-
path = tempfile.mktemp(dir=self.dir_path)
710-
socket_helper.bind_unix_socket(sock, path)
704+
path = socket_helper.create_unix_domain_name()
711705
self.addCleanup(os_helper.unlink, path)
706+
socket_helper.bind_unix_socket(sock, path)
712707

713708
class UnixStreamBase(UnixSocketTestBase):
714709
"""Base class for Unix-domain SOCK_STREAM tests."""
@@ -1905,17 +1900,18 @@ def test_socket_fileno(self):
19051900
self._test_socket_fileno(s, socket.AF_INET6, socket.SOCK_STREAM)
19061901

19071902
if hasattr(socket, "AF_UNIX"):
1908-
tmpdir = tempfile.mkdtemp()
1909-
self.addCleanup(shutil.rmtree, tmpdir)
1903+
unix_name = socket_helper.create_unix_domain_name()
1904+
self.addCleanup(os_helper.unlink, unix_name)
1905+
19101906
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
1911-
self.addCleanup(s.close)
1912-
try:
1913-
s.bind(os.path.join(tmpdir, 'socket'))
1914-
except PermissionError:
1915-
pass
1916-
else:
1917-
self._test_socket_fileno(s, socket.AF_UNIX,
1918-
socket.SOCK_STREAM)
1907+
with s:
1908+
try:
1909+
s.bind(unix_name)
1910+
except PermissionError:
1911+
pass
1912+
else:
1913+
self._test_socket_fileno(s, socket.AF_UNIX,
1914+
socket.SOCK_STREAM)
19191915

19201916
def test_socket_fileno_rejects_float(self):
19211917
with self.assertRaises(TypeError):

Lib/test/test_socketserver.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import select
99
import signal
1010
import socket
11-
import tempfile
1211
import threading
1312
import unittest
1413
import socketserver
@@ -98,8 +97,7 @@ def pickaddr(self, proto):
9897
else:
9998
# XXX: We need a way to tell AF_UNIX to pick its own name
10099
# like AF_INET provides port==0.
101-
dir = None
102-
fn = tempfile.mktemp(prefix='unix_socket.', dir=dir)
100+
fn = socket_helper.create_unix_domain_name()
103101
self.test_files.append(fn)
104102
return fn
105103

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
test_asyncio, test_logging, test_socket and test_socketserver now create
2+
AF_UNIX domains in the current directory to no longer fail with
3+
``OSError("AF_UNIX path too long")`` if the temporary directory (the
4+
:envvar:`TMPDIR` environment variable) is too long. Patch by Victor Stinner.

0 commit comments

Comments
 (0)