]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.11] gh-110932: Fix regrtest for SOURCE_DATE_EPOCH (GH-111143) (#111153)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Sat, 21 Oct 2023 09:01:10 +0000 (11:01 +0200)
committerGitHub <noreply@github.com>
Sat, 21 Oct 2023 09:01:10 +0000 (09:01 +0000)
gh-110932: Fix regrtest for SOURCE_DATE_EPOCH (GH-111143)

If the SOURCE_DATE_EPOCH environment variable is defined, use its
value as the random seed.
(cherry picked from commit 7237fb578dc9db9dc557759a24d8083425107b91)

Co-authored-by: Victor Stinner <vstinner@python.org>
Lib/test/libregrtest/main.py
Lib/test/libregrtest/runtests.py
Lib/test/test_regrtest.py
Misc/NEWS.d/next/Tests/2023-10-21-00-10-36.gh-issue-110932.jktjJU.rst [new file with mode: 0644]

index fe35df05c80e896567f049f9d2230bd292ed9b9e..e765ed5c613acb2b4dc99f23758d72577505c476 100644 (file)
@@ -129,14 +129,19 @@ class Regrtest:
 
         # Randomize
         self.randomize: bool = ns.randomize
-        self.random_seed: int | None =  (
-            ns.random_seed
-            if ns.random_seed is not None
-            else random.getrandbits(32)
-        )
-        if 'SOURCE_DATE_EPOCH' in os.environ:
+        if ('SOURCE_DATE_EPOCH' in os.environ
+            # don't use the variable if empty
+            and os.environ['SOURCE_DATE_EPOCH']
+        ):
             self.randomize = False
-            self.random_seed = None
+            # SOURCE_DATE_EPOCH should be an integer, but use a string to not
+            # fail if it's not integer. random.seed() accepts a string.
+            # https://reproducible-builds.org/docs/source-date-epoch/
+            self.random_seed: int | str = os.environ['SOURCE_DATE_EPOCH']
+        elif ns.random_seed is None:
+            self.random_seed = random.getrandbits(32)
+        else:
+            self.random_seed = ns.random_seed
 
         # tests
         self.first_runtests: RunTests | None = None
@@ -441,7 +446,7 @@ class Regrtest:
                    or tests or self.cmdline_args)):
             display_header(self.use_resources, self.python_cmd)
 
-        print("Using random seed", self.random_seed)
+        print("Using random seed:", self.random_seed)
 
         runtests = self.create_run_tests(selected)
         self.first_runtests = runtests
index 4da312db4cb02e525e880ec1f172b334bf24360e..893b311c31297cd44636a88fb7ca5a5263bb56d6 100644 (file)
@@ -91,7 +91,7 @@ class RunTests:
     use_resources: tuple[str, ...]
     python_cmd: tuple[str, ...] | None
     randomize: bool
-    random_seed: int | None
+    random_seed: int | str
     json_file: JsonFile | None
 
     def copy(self, **override):
index c8e182397c835e5c6837dc741053a4223d66ca80..91f2fb0286adfebc4350aa9f886f0bd7654446b9 100644 (file)
@@ -143,18 +143,26 @@ class ParseArgsTestCase(unittest.TestCase):
         self.assertTrue(ns.header)
 
     def test_randomize(self):
-        for opt in '-r', '--randomize':
+        for opt in ('-r', '--randomize'):
             with self.subTest(opt=opt):
                 ns = self.parse_args([opt])
                 self.assertTrue(ns.randomize)
 
         with os_helper.EnvironmentVarGuard() as env:
-            env['SOURCE_DATE_EPOCH'] = '1'
-
+            # with SOURCE_DATE_EPOCH
+            env['SOURCE_DATE_EPOCH'] = '1697839080'
             ns = self.parse_args(['--randomize'])
             regrtest = main.Regrtest(ns)
             self.assertFalse(regrtest.randomize)
-            self.assertIsNone(regrtest.random_seed)
+            self.assertIsInstance(regrtest.random_seed, str)
+            self.assertEqual(regrtest.random_seed, '1697839080')
+
+            # without SOURCE_DATE_EPOCH
+            del env['SOURCE_DATE_EPOCH']
+            ns = self.parse_args(['--randomize'])
+            regrtest = main.Regrtest(ns)
+            self.assertTrue(regrtest.randomize)
+            self.assertIsInstance(regrtest.random_seed, int)
 
     def test_randseed(self):
         ns = self.parse_args(['--randseed', '12345'])
@@ -388,7 +396,13 @@ class ParseArgsTestCase(unittest.TestCase):
 
         # Check Regrtest attributes which are more reliable than Namespace
         # which has an unclear API
-        regrtest = main.Regrtest(ns)
+        with os_helper.EnvironmentVarGuard() as env:
+            # Ignore SOURCE_DATE_EPOCH env var if it's set
+            if 'SOURCE_DATE_EPOCH' in env:
+                del env['SOURCE_DATE_EPOCH']
+
+            regrtest = main.Regrtest(ns)
+
         self.assertEqual(regrtest.num_workers, -1)
         self.assertEqual(regrtest.want_rerun, rerun)
         self.assertTrue(regrtest.randomize)
@@ -662,21 +676,26 @@ class BaseTestCase(unittest.TestCase):
             state = f'{state} then {new_state}'
         self.check_line(output, f'Result: {state}', full=True)
 
-    def parse_random_seed(self, output):
-        match = self.regex_search(r'Using random seed ([0-9]+)', output)
-        randseed = int(match.group(1))
-        self.assertTrue(0 <= randseed, randseed)
-        return randseed
+    def parse_random_seed(self, output: str) -> str:
+        match = self.regex_search(r'Using random seed: (.*)', output)
+        return match.group(1)
 
     def run_command(self, args, input=None, exitcode=0, **kw):
         if not input:
             input = ''
         if 'stderr' not in kw:
             kw['stderr'] = subprocess.STDOUT
+
+        env = kw.pop('env', None)
+        if env is None:
+            env = dict(os.environ)
+            env.pop('SOURCE_DATE_EPOCH', None)
+
         proc = subprocess.run(args,
                               text=True,
                               input=input,
                               stdout=subprocess.PIPE,
+                              env=env,
                               **kw)
         if proc.returncode != exitcode:
             msg = ("Command %s failed with exit code %s, but exit code %s expected!\n"
@@ -752,7 +771,9 @@ class ProgramsTestCase(BaseTestCase):
             self.regrtest_args.append('-n')
 
     def check_output(self, output):
-        self.parse_random_seed(output)
+        randseed = self.parse_random_seed(output)
+        self.assertTrue(randseed.isdigit(), randseed)
+
         self.check_executed_tests(output, self.tests,
                                   randomize=True, stats=len(self.tests))
 
@@ -943,7 +964,7 @@ class ArgsTestCase(BaseTestCase):
         test_random = int(match.group(1))
 
         # try to reproduce with the random seed
-        output = self.run_tests('-r', '--randseed=%s' % randseed, test,
+        output = self.run_tests('-r', f'--randseed={randseed}', test,
                                 exitcode=EXITCODE_NO_TESTS_RAN)
         randseed2 = self.parse_random_seed(output)
         self.assertEqual(randseed2, randseed)
@@ -954,7 +975,32 @@ class ArgsTestCase(BaseTestCase):
 
         # check that random.seed is used by default
         output = self.run_tests(test, exitcode=EXITCODE_NO_TESTS_RAN)
-        self.assertIsInstance(self.parse_random_seed(output), int)
+        randseed = self.parse_random_seed(output)
+        self.assertTrue(randseed.isdigit(), randseed)
+
+        # check SOURCE_DATE_EPOCH (integer)
+        timestamp = '1697839080'
+        env = dict(os.environ, SOURCE_DATE_EPOCH=timestamp)
+        output = self.run_tests('-r', test, exitcode=EXITCODE_NO_TESTS_RAN,
+                                env=env)
+        randseed = self.parse_random_seed(output)
+        self.assertEqual(randseed, timestamp)
+        self.check_line(output, 'TESTRANDOM: 520')
+
+        # check SOURCE_DATE_EPOCH (string)
+        env = dict(os.environ, SOURCE_DATE_EPOCH='XYZ')
+        output = self.run_tests('-r', test, exitcode=EXITCODE_NO_TESTS_RAN,
+                                env=env)
+        randseed = self.parse_random_seed(output)
+        self.assertEqual(randseed, 'XYZ')
+        self.check_line(output, 'TESTRANDOM: 22')
+
+        # check SOURCE_DATE_EPOCH (empty string): ignore the env var
+        env = dict(os.environ, SOURCE_DATE_EPOCH='')
+        output = self.run_tests('-r', test, exitcode=EXITCODE_NO_TESTS_RAN,
+                                env=env)
+        randseed = self.parse_random_seed(output)
+        self.assertTrue(randseed.isdigit(), randseed)
 
     def test_fromfile(self):
         # test --fromfile
diff --git a/Misc/NEWS.d/next/Tests/2023-10-21-00-10-36.gh-issue-110932.jktjJU.rst b/Misc/NEWS.d/next/Tests/2023-10-21-00-10-36.gh-issue-110932.jktjJU.rst
new file mode 100644 (file)
index 0000000..45bb077
--- /dev/null
@@ -0,0 +1,2 @@
+Fix regrtest if the ``SOURCE_DATE_EPOCH`` environment variable is defined:
+use the variable value as the random seed. Patch by Victor Stinner.