]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.12] gh-119050: Add XML support to libregrtest refleak checker (#119148) (#119272)
authorVictor Stinner <vstinner@python.org>
Mon, 20 May 2024 22:56:34 +0000 (18:56 -0400)
committerGitHub <noreply@github.com>
Mon, 20 May 2024 22:56:34 +0000 (22:56 +0000)
gh-119050: Add XML support to libregrtest refleak checker (#119148)

regrtest test runner: Add XML support to the refleak checker
(-R option).

* run_unittest() now stores XML elements as string, rather than
  objects, in support.junit_xml_list.
* runtest_refleak() now saves/restores XML strings before/after
  checking for reference leaks. Save XML into a temporary file.

(cherry picked from commit 9257731f5d3e9d4f99e314b23a14506563e167d7)

Lib/test/libregrtest/cmdline.py
Lib/test/libregrtest/refleak.py
Lib/test/libregrtest/single.py
Lib/test/test_regrtest.py
Misc/NEWS.d/next/Tests/2024-05-18-10-59-27.gh-issue-119050.g4qiH7.rst [new file with mode: 0644]

index 03c83953ce079e308cef8d1a066890eadefb9fb5..3211d04bee0c349857023dd83a0eabb5e87cb05a 100644 (file)
@@ -513,15 +513,6 @@ def _parse_args(args, **kwargs):
               "--huntrleaks without -jN option",
               file=sys.stderr)
 
-    if ns.huntrleaks and ns.xmlpath:
-        # The XML data is written into a file outside runtest_refleak(), so
-        # it looks like a leak but it's not. Simply disable XML output when
-        # hunting for reference leaks (gh-83434).
-        ns.xmlpath = None
-        print("WARNING: Disable --junit-xml because it's incompatible "
-              "with --huntrleaks",
-              file=sys.stderr)
-
     if ns.forever:
         # --forever implies --failfast
         ns.failfast = True
index 7d1f6081889ca39f6b213cb2ef3eb66f94c21a45..a257d1023537b9868bae60d1ef53dc6767ad9c76 100644 (file)
@@ -1,3 +1,4 @@
+import os
 import sys
 import warnings
 from inspect import isabstract
@@ -22,6 +23,30 @@ except ImportError:
                 cls._abc_negative_cache, cls._abc_negative_cache_version)
 
 
+def save_support_xml(filename):
+    if support.junit_xml_list is None:
+        return
+
+    import pickle
+    with open(filename, 'xb') as fp:
+        pickle.dump(support.junit_xml_list, fp)
+    support.junit_xml_list = None
+
+
+def restore_support_xml(filename):
+    try:
+        fp = open(filename, 'rb')
+    except FileNotFoundError:
+        return
+
+    import pickle
+    with fp:
+        xml_list = pickle.load(fp)
+    os.unlink(filename)
+
+    support.junit_xml_list = xml_list
+
+
 def runtest_refleak(test_name, test_func,
                     hunt_refleak: HuntRefleak,
                     quiet: bool):
@@ -94,13 +119,15 @@ def runtest_refleak(test_name, test_func,
         numbers = numbers[:warmups] + ':' + numbers[warmups:]
         print(numbers, file=sys.stderr, flush=True)
 
-    results = None
+    xml_filename = 'refleak-xml.tmp'
+    result = None
     dash_R_cleanup(fs, ps, pic, zdc, abcs)
     support.gc_collect()
 
     for i in rep_range:
-        results = test_func()
+        result = test_func()
 
+        save_support_xml(xml_filename)
         dash_R_cleanup(fs, ps, pic, zdc, abcs)
         support.gc_collect()
 
@@ -139,6 +166,8 @@ def runtest_refleak(test_name, test_func,
         fd_before = fd_after
         interned_before = interned_after
 
+        restore_support_xml(xml_filename)
+
     if not quiet:
         print(file=sys.stderr)
 
@@ -183,7 +212,7 @@ def runtest_refleak(test_name, test_func,
                 failed = True
             else:
                 print(' (this is fine)', file=sys.stderr, flush=True)
-    return (failed, results)
+    return (failed, result)
 
 
 def dash_R_cleanup(fs, ps, pic, zdc, abcs):
index 235029d8620ff5b57c522a564430156d74b9bff7..17323e7f9cf730db9b851d13fd74e8a7b5d06bb1 100644 (file)
@@ -57,7 +57,10 @@ def _run_suite(suite):
     result = runner.run(suite)
 
     if support.junit_xml_list is not None:
-        support.junit_xml_list.append(result.get_xml_element())
+        import xml.etree.ElementTree as ET
+        xml_elem = result.get_xml_element()
+        xml_str = ET.tostring(xml_elem).decode('ascii')
+        support.junit_xml_list.append(xml_str)
 
     if not result.testsRun and not result.skipped and not result.errors:
         raise support.TestDidNotRun
@@ -280,9 +283,7 @@ def _runtest(result: TestResult, runtests: RunTests) -> None:
 
         xml_list = support.junit_xml_list
         if xml_list:
-            import xml.etree.ElementTree as ET
-            result.xml_data = [ET.tostring(x).decode('us-ascii')
-                               for x in xml_list]
+            result.xml_data = xml_list
     finally:
         if use_timeout:
             faulthandler.cancel_dump_traceback_later()
index 0a0c371836dc7a805fe29c9a46c17f3d69eb9343..8135a3fdad17a6e879efb1ec64362185af45f7d2 100644 (file)
@@ -464,15 +464,6 @@ class ParseArgsTestCase(unittest.TestCase):
         self.assertEqual(regrtest.hunt_refleak.runs, 10)
         self.assertFalse(regrtest.output_on_failure)
 
-    def test_xml_huntrleaks(self):
-        args = ['-R', '3:12', '--junit-xml', 'output.xml']
-        with support.captured_stderr():
-            regrtest = self.create_regrtest(args)
-        self.assertIsNotNone(regrtest.hunt_refleak)
-        self.assertEqual(regrtest.hunt_refleak.warmups, 3)
-        self.assertEqual(regrtest.hunt_refleak.runs, 12)
-        self.assertIsNone(regrtest.junit_filename)
-
 
 @dataclasses.dataclass(slots=True)
 class Rerun:
diff --git a/Misc/NEWS.d/next/Tests/2024-05-18-10-59-27.gh-issue-119050.g4qiH7.rst b/Misc/NEWS.d/next/Tests/2024-05-18-10-59-27.gh-issue-119050.g4qiH7.rst
new file mode 100644 (file)
index 0000000..cfc70c1
--- /dev/null
@@ -0,0 +1,2 @@
+regrtest test runner: Add XML support to the refleak checker (-R option).
+Patch by Victor Stinner.