From 87330e72690309d6277c448387f11b7171f670cb Mon Sep 17 00:00:00 2001 From: Ronald Oussoren <ronaldoussoren@mac.com> Date: Sun, 14 Jan 2024 14:51:34 +0100 Subject: [PATCH 1/3] gh-80931: Skip some socket tests while hunting for refleaks on macOS --- Lib/test/test_socket.py | 76 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 4eb5af99d6674c..9f43a04ee40feb 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -52,6 +52,28 @@ except ImportError: _socket = None +_hunting_for_refleaks = None +def hunting_for_refleaks(): + """ + Return true iff running tests while hunting for refleaks + """ + from test.libregrtest.runtests import RunTests + import gc + + global _hunting_for_refleaks + + if _hunting_for_refleaks is None: + for value in gc.get_objects(): + if isinstance(value, RunTests): + _hunting_for_refleaks = (value.hunt_refleak is not None) + break + else: + _hunting_for_refleaks = False + + return _hunting_for_refleaks + + + def get_cid(): if fcntl is None: return None @@ -3817,6 +3839,9 @@ def checkTruncatedHeader(self, result, ignoreflags=0): def testCmsgTruncNoBufSize(self): # Check that no ancillary data is received when no buffer size # is specified. + if sys.platform == "darwin" and hunting_for_refleaks(): + return + self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG)), # BSD seems to set MSG_CTRUNC only # if an item has been partially @@ -3824,26 +3849,44 @@ def testCmsgTruncNoBufSize(self): ignoreflags=socket.MSG_CTRUNC) def _testCmsgTruncNoBufSize(self): + if sys.platform == "darwin" and hunting_for_refleaks(): + return + self.createAndSendFDs(1) def testCmsgTrunc0(self): + if sys.platform == "darwin" and hunting_for_refleaks(): + return + # Check that no ancillary data is received when buffer size is 0. self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG), 0), ignoreflags=socket.MSG_CTRUNC) def _testCmsgTrunc0(self): + if sys.platform == "darwin" and hunting_for_refleaks(): + return + self.createAndSendFDs(1) # Check that no ancillary data is returned for various non-zero # (but still too small) buffer sizes. def testCmsgTrunc1(self): + if sys.platform == "darwin" and hunting_for_refleaks(): + return + self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG), 1)) def _testCmsgTrunc1(self): + if sys.platform == "darwin" and hunting_for_refleaks(): + return + self.createAndSendFDs(1) def testCmsgTrunc2Int(self): + if sys.platform == "darwin" and hunting_for_refleaks(): + return + # The cmsghdr structure has at least three members, two of # which are ints, so we still shouldn't see any ancillary # data. @@ -3851,13 +3894,22 @@ def testCmsgTrunc2Int(self): SIZEOF_INT * 2)) def _testCmsgTrunc2Int(self): + if sys.platform == "darwin" and hunting_for_refleaks(): + return + self.createAndSendFDs(1) def testCmsgTruncLen0Minus1(self): + if sys.platform == "darwin" and hunting_for_refleaks(): + return + self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG), socket.CMSG_LEN(0) - 1)) def _testCmsgTruncLen0Minus1(self): + if sys.platform == "darwin" and hunting_for_refleaks(): + return + self.createAndSendFDs(1) # The following tests try to truncate the control message in the @@ -3888,29 +3940,53 @@ def checkTruncatedArray(self, ancbuf, maxdata, mindata=0): self.checkFDs(fds) def testCmsgTruncLen0(self): + if sys.platform == "darwin" and hunting_for_refleaks(): + return + self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(0), maxdata=0) def _testCmsgTruncLen0(self): + if sys.platform == "darwin" and hunting_for_refleaks(): + return + self.createAndSendFDs(1) def testCmsgTruncLen0Plus1(self): + if sys.platform == "darwin" and hunting_for_refleaks(): + return + self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(0) + 1, maxdata=1) def _testCmsgTruncLen0Plus1(self): + if sys.platform == "darwin" and hunting_for_refleaks(): + return + self.createAndSendFDs(2) def testCmsgTruncLen1(self): + if sys.platform == "darwin" and hunting_for_refleaks(): + return + self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(SIZEOF_INT), maxdata=SIZEOF_INT) def _testCmsgTruncLen1(self): + if sys.platform == "darwin" and hunting_for_refleaks(): + return + self.createAndSendFDs(2) def testCmsgTruncLen2Minus1(self): + if sys.platform == "darwin" and hunting_for_refleaks(): + return + self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(2 * SIZEOF_INT) - 1, maxdata=(2 * SIZEOF_INT) - 1) def _testCmsgTruncLen2Minus1(self): + if sys.platform == "darwin" and hunting_for_refleaks(): + return + self.createAndSendFDs(2) From 1fc244379dfe5fb518f14246b5a25a0980335758 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren <ronaldoussoren@mac.com> Date: Sun, 14 Jan 2024 15:34:25 +0100 Subject: [PATCH 2/3] Cleaner way of annotating test functions using a decorator --- Lib/test/test_socket.py | 98 ++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 51 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 9f43a04ee40feb..7904f4c701d4c3 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -73,6 +73,34 @@ def hunting_for_refleaks(): return _hunting_for_refleaks +def skipForRefleakHuntinIf(condition, issueref): + if not condition: + def decorator(f): + f.client_skip = lambda f: f + return f + + else: + def decorator(f): + @contextlib.wraps(f) + def wrapper(*args, **kwds): + if hunting_for_refleaks(): + raise unittest.SkipTest(f"ignore while hunting for refleaks, see {issueref}") + + return f(*args, **kwds) + + def client_skip(f): + @contextlib.wraps(f) + def wrapper(*args, **kwds): + if hunting_for_refleaks(): + return + + return f(*args, **kwds) + + return wrapper + wrapper.client_skip = client_skip + return wrapper + + return decorator def get_cid(): if fcntl is None: @@ -3836,32 +3864,27 @@ def checkTruncatedHeader(self, result, ignoreflags=0): self.checkFlags(flags, eor=True, checkset=socket.MSG_CTRUNC, ignore=ignoreflags) + @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") def testCmsgTruncNoBufSize(self): # Check that no ancillary data is received when no buffer size # is specified. - if sys.platform == "darwin" and hunting_for_refleaks(): - return - self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG)), # BSD seems to set MSG_CTRUNC only # if an item has been partially # received. ignoreflags=socket.MSG_CTRUNC) + @testCmsgTruncNoBufSize.client_skip def _testCmsgTruncNoBufSize(self): - if sys.platform == "darwin" and hunting_for_refleaks(): - return - self.createAndSendFDs(1) + @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") def testCmsgTrunc0(self): - if sys.platform == "darwin" and hunting_for_refleaks(): - return - # Check that no ancillary data is received when buffer size is 0. self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG), 0), ignoreflags=socket.MSG_CTRUNC) + @testCmsgTrunc0.client_skip def _testCmsgTrunc0(self): if sys.platform == "darwin" and hunting_for_refleaks(): return @@ -3871,45 +3894,33 @@ def _testCmsgTrunc0(self): # Check that no ancillary data is returned for various non-zero # (but still too small) buffer sizes. + @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") def testCmsgTrunc1(self): - if sys.platform == "darwin" and hunting_for_refleaks(): - return - self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG), 1)) + @testCmsgTrunc1.client_skip def _testCmsgTrunc1(self): - if sys.platform == "darwin" and hunting_for_refleaks(): - return - self.createAndSendFDs(1) + @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") def testCmsgTrunc2Int(self): - if sys.platform == "darwin" and hunting_for_refleaks(): - return - # The cmsghdr structure has at least three members, two of # which are ints, so we still shouldn't see any ancillary # data. self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG), SIZEOF_INT * 2)) + @testCmsgTrunc2Int.client_skip def _testCmsgTrunc2Int(self): - if sys.platform == "darwin" and hunting_for_refleaks(): - return - self.createAndSendFDs(1) + @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") def testCmsgTruncLen0Minus1(self): - if sys.platform == "darwin" and hunting_for_refleaks(): - return - self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG), socket.CMSG_LEN(0) - 1)) + @testCmsgTruncLen0Minus1.client_skip def _testCmsgTruncLen0Minus1(self): - if sys.platform == "darwin" and hunting_for_refleaks(): - return - self.createAndSendFDs(1) # The following tests try to truncate the control message in the @@ -3939,54 +3950,39 @@ def checkTruncatedArray(self, ancbuf, maxdata, mindata=0): len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) self.checkFDs(fds) + @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") def testCmsgTruncLen0(self): - if sys.platform == "darwin" and hunting_for_refleaks(): - return - self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(0), maxdata=0) + @testCmsgTruncLen0.client_skip def _testCmsgTruncLen0(self): - if sys.platform == "darwin" and hunting_for_refleaks(): - return - self.createAndSendFDs(1) + @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") def testCmsgTruncLen0Plus1(self): - if sys.platform == "darwin" and hunting_for_refleaks(): - return - self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(0) + 1, maxdata=1) + @testCmsgTruncLen0Plus1.client_skip def _testCmsgTruncLen0Plus1(self): - if sys.platform == "darwin" and hunting_for_refleaks(): - return - self.createAndSendFDs(2) + @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") def testCmsgTruncLen1(self): - if sys.platform == "darwin" and hunting_for_refleaks(): - return - self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(SIZEOF_INT), maxdata=SIZEOF_INT) + @testCmsgTruncLen1.client_skip def _testCmsgTruncLen1(self): - if sys.platform == "darwin" and hunting_for_refleaks(): - return - self.createAndSendFDs(2) - def testCmsgTruncLen2Minus1(self): - if sys.platform == "darwin" and hunting_for_refleaks(): - return + @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") + def testCmsgTruncLen2Minus1(self): self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(2 * SIZEOF_INT) - 1, maxdata=(2 * SIZEOF_INT) - 1) + @testCmsgTruncLen2Minus1.client_skip def _testCmsgTruncLen2Minus1(self): - if sys.platform == "darwin" and hunting_for_refleaks(): - return - self.createAndSendFDs(2) From 8907efc6b32abc28848ecc93c406777261202d8a Mon Sep 17 00:00:00 2001 From: Ronald Oussoren <ronaldoussoren@mac.com> Date: Sun, 14 Jan 2024 15:51:18 +0100 Subject: [PATCH 3/3] Integrate the refleak run check into regrtest and test.support --- Lib/test/libregrtest/refleak.py | 8 +++++++- Lib/test/support/refleak_helper.py | 8 ++++++++ Lib/test/test_socket.py | 29 +++-------------------------- 3 files changed, 18 insertions(+), 27 deletions(-) create mode 100644 Lib/test/support/refleak_helper.py diff --git a/Lib/test/libregrtest/refleak.py b/Lib/test/libregrtest/refleak.py index 5836a8421cb42d..7da16cf721f097 100644 --- a/Lib/test/libregrtest/refleak.py +++ b/Lib/test/libregrtest/refleak.py @@ -5,6 +5,7 @@ from test import support from test.support import os_helper +from test.support import refleak_helper from .runtests import HuntRefleak from .utils import clear_caches @@ -96,7 +97,12 @@ def get_pooled_int(value): support.gc_collect() for i in rep_range: - results = test_func() + current = refleak_helper._hunting_for_refleaks + refleak_helper._hunting_for_refleaks = True + try: + results = test_func() + finally: + refleak_helper._hunting_for_refleaks = current dash_R_cleanup(fs, ps, pic, zdc, abcs) support.gc_collect() diff --git a/Lib/test/support/refleak_helper.py b/Lib/test/support/refleak_helper.py new file mode 100644 index 00000000000000..2f86c93a1e2e58 --- /dev/null +++ b/Lib/test/support/refleak_helper.py @@ -0,0 +1,8 @@ +""" +Utilities for changing test behaviour while hunting +for refleaks +""" + +_hunting_for_refleaks = False +def hunting_for_refleaks(): + return _hunting_for_refleaks diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 7904f4c701d4c3..231448c75f01db 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -3,6 +3,7 @@ from test.support import os_helper from test.support import socket_helper from test.support import threading_helper +from test.support import refleak_helper import _thread as thread import array @@ -52,27 +53,6 @@ except ImportError: _socket = None -_hunting_for_refleaks = None -def hunting_for_refleaks(): - """ - Return true iff running tests while hunting for refleaks - """ - from test.libregrtest.runtests import RunTests - import gc - - global _hunting_for_refleaks - - if _hunting_for_refleaks is None: - for value in gc.get_objects(): - if isinstance(value, RunTests): - _hunting_for_refleaks = (value.hunt_refleak is not None) - break - else: - _hunting_for_refleaks = False - - return _hunting_for_refleaks - - def skipForRefleakHuntinIf(condition, issueref): if not condition: def decorator(f): @@ -83,7 +63,7 @@ def decorator(f): def decorator(f): @contextlib.wraps(f) def wrapper(*args, **kwds): - if hunting_for_refleaks(): + if refleak_helper.hunting_for_refleaks(): raise unittest.SkipTest(f"ignore while hunting for refleaks, see {issueref}") return f(*args, **kwds) @@ -91,7 +71,7 @@ def wrapper(*args, **kwds): def client_skip(f): @contextlib.wraps(f) def wrapper(*args, **kwds): - if hunting_for_refleaks(): + if refleak_helper.hunting_for_refleaks(): return return f(*args, **kwds) @@ -3886,9 +3866,6 @@ def testCmsgTrunc0(self): @testCmsgTrunc0.client_skip def _testCmsgTrunc0(self): - if sys.platform == "darwin" and hunting_for_refleaks(): - return - self.createAndSendFDs(1) # Check that no ancillary data is returned for various non-zero