8000 gh-110932: Fix regrtest for SOURCE_DATE_EPOCH (#111143) · python/cpython@7237fb5 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7237fb5

Browse files
authored
gh-110932: Fix regrtest for SOURCE_DATE_EPOCH (#111143)
If the SOURCE_DATE_EPOCH environment variable is defined, use its value as the random seed.
1 parent b07f232 commit 7237fb5

File tree

4 files changed

+75
-22
lines changed

4 files changed

+75
-22
lines changed

Lib/test/libregrtest/main.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,19 @@ def __init__(self, ns: Namespace, _add_python_opts: bool = False):
129129

130130
# Randomize
131131
self.randomize: bool = ns.randomize
132-
self.random_seed: int | None = (
133-
ns.random_seed
134-
if ns.random_seed is not None
135-
else random.getrandbits(32)
136-
)
137-
if 'SOURCE_DATE_EPOCH' in os.environ:
132+
if ('SOURCE_DATE_EPOCH' in os.environ
133+
# don't use the variable if empty
134+
and os.environ['SOURCE_DATE_EPOCH']
135+
):
138136
self.randomize = False
139-
self.random_seed = None
137+
# SOURCE_DATE_EPOCH should be an integer, but use a string to not
138+
# fail if it's not integer. random.seed() accepts a string.
139+
# https://reproducible-builds.org/docs/source-date-epoch/
140+
self.random_seed: int | str = os.environ['SOURCE_DATE_EPOCH']
141+
elif ns.random_seed is None:
142+
self.random_seed = random.getrandbits(32)
143+
else:
144+
self.random_seed = ns.random_seed
140145

141146
# tests
142147
self.first_runtests: RunTests | None = None
@@ -441,7 +446,7 @@ def _run_tests(self, selected: TestTuple, tests: TestList | None) -> int:
441446
or tests or self.cmdline_args)):
442447
display_header(self.use_resources, self.python_cmd)
443448

444-
print("Using random seed", self.random_seed)
449+
print("Using random seed:", self.random_seed)
445450

446451
runtests = self.create_run_tests(selected)
447452
self.first_runtests = runtests

Lib/test/libregrtest/runtests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ class RunTests:
9191
use_resources: tuple[str, ...]
9292
python_cmd: tuple[str, ...] | None
9393
randomize: bool
94-
random_seed: int | None
94+
random_seed: int | str
9595
json_file: JsonFile | None
9696

9797
def copy(self, **override):

Lib/test/test_regrtest.py

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -143,18 +143,26 @@ def test_header(self):
143143
self.assertTrue(ns.header)
144144

145145
def test_randomize(self):
146-
for opt in '-r', '--randomize':
146+
for opt in ('-r', '--randomize'):
147147
with self.subTest(opt=opt):
148148
ns = self.parse_args([opt])
149149
self.assertTrue(ns.randomize)
150150

151151
with os_helper.EnvironmentVarGuard() as env:
152-
env['SOURCE_DATE_EPOCH'] = '1'
153-
152+
# with SOURCE_DATE_EPOCH
153+
env['SOURCE_DATE_EPOCH'] = '1697839080'
154154
ns = self.parse_args(['--randomize'])
155155
regrtest = main.Regrtest(ns)
156156
self.assertFalse(regrtest.randomize)
157-
self.assertIsNone(regrtest.random_seed)
157+
self.assertIsInstance(regrtest.random_seed, str)
158+
self.assertEqual(regrtest.random_seed, '1697839080')
159+
160+
# without SOURCE_DATE_EPOCH
161+
del env['SOURCE_DATE_EPOCH']
162+
ns = self.parse_args(['--randomize'])
163+
regrtest = main.Regrtest(ns)
164+
self.assertTrue(regrtest.randomize)
165+
self.assertIsInstance(regrtest.random_seed, int)
158166

159167
def test_randseed(self):
160168
ns = self.parse_args(['--randseed', '12345'])
@@ -388,7 +396,13 @@ def check_ci_mode(self, args, use_resources, rerun=True):
388396

389397
# Check Regrtest attributes which are more reliable than Namespace
390398
# which has an unclear API
391-
regrtest = main.Regrtest(ns)
399+
with os_helper.EnvironmentVarGuard() as env:
400+
# Ignore SOURCE_DATE_EPOCH env var if it's set
401+
if 'SOURCE_DATE_EPOCH' in env:
402+
del env['SOURCE_DATE_EPOCH']
403+
404+
regrtest = main.Regrtest(ns)
405+
392406
self.assertEqual(regrtest.num_workers, -1)
393407
self.assertEqual(regrtest.want_rerun, rerun)
394408
self.assertTrue(regrtest.randomize)
@@ -661,21 +675,26 @@ def list_regex(line_format, tests):
661675
state = f'{state} then {new_state}'
662676
self.check_line(output, f'Result: {state}', full=True)
663677

664-
def parse_random_seed(self, output):
665-
match = self.regex_search(r'Using random seed ([0-9]+)', output)
666-
randseed = int(match.group(1))
667-
self.assertTrue(0 <= randseed, randseed)
668-
return randseed
678+
def parse_random_seed(self, output: str) -> str:
679+
match = self.regex_search(r'Using random seed: (.*)', output)
680+
return match.group(1)
669681

670682
def run_command(self, args, input=None, exitcode=0, **kw):
671683
if not input:
672684
input = ''
673685
if 'stderr' not in kw:
674686
kw['stderr'] = subprocess.STDOUT
687+
688+
env = kw.pop('env', None)
689+
if env is None:
690+
env = dict(os.environ)
691+
env.pop('SOURCE_DATE_EPOCH', None)
692+
675693
proc = subprocess.run(args,
676694
text=True,
677695
input=input,
678696
stdout=subprocess.PIPE,
697+
env=env,
679698
**kw)
680699
if proc.returncode != exitcode:
681700
msg = ("Command %s failed with exit code %s, but exit code %s expected!\n"
@@ -751,7 +770,9 @@ def setUp(self):
751770
self.regrtest_args.append('-n')
752771

753772
def check_output(self, output):
754-
self.parse_random_seed(output)
773+
randseed = self.parse_random_seed(output)
774+
self.assertTrue(randseed.isdigit(), randseed)
775+
755776
self.check_executed_tests(output, self.tests,
756777
randomize=True, stats=len(self.tests))
757778

@@ -942,7 +963,7 @@ def test_random(self):
942963
test_random = int(match.group(1))
943964

944965
# try to reproduce with the random seed
945-
output = self.run_tests('-r', '--randseed=%s' % randseed, test,
966+
output = self.run_tests('-r', f'--randseed={randseed}', test,
946967
exitcode=EXITCODE_NO_TESTS_RAN)
947968
randseed2 = self.parse_random_seed(output)
948969
self.assertEqual(randseed2, randseed)
@@ -953,7 +974,32 @@ def test_random(self):
953974

954975
# check that random.seed is used by default
955976
output = self.run_tests(test, exitcode=EXITCODE_NO_TESTS_RAN)
956-
self.assertIsInstance(self.parse_random_seed(output), int)
977+
randseed = self.parse_random_seed(output)
978+
self.assertTrue(randseed.isdigit(), randseed)
979+
980+
# check SOURCE_DATE_EPOCH (integer)
981+
timestamp = '1697839080'
982+
env = dict(os.environ, SOURCE_DATE_EPOCH=timestamp)
983+
output = self.run_tests('-r', test, exitcode=EXITCODE_NO_TESTS_RAN,
984+
env=env)
985+
randseed = self.parse_random_seed(output)
986+
self.assertEqual(randseed, timestamp)
987+
self.check_line(output, 'TESTRANDOM: 520')
988+
989+
# check SOURCE_DATE_EPOCH (string)
990+
env = dict(os.environ, SOURCE_DATE_EPOCH='XYZ')
991+
output = self.run_tests('-r', test, exitcode=EXITCODE_NO_TESTS_RAN,
992+
env=env)
993+
randseed = self.parse_random_seed(output)
994+
self.assertEqual(randseed, 'XYZ')
995+
self.check_line(output, 'TESTRANDOM: 22')
996+
997+
# check SOURCE_DATE_EPOCH (empty string): ignore the env var
998+
env = dict(os.environ, SOURCE_DATE_EPOCH='')
999+
output = self.run_tests('-r', test, exitcode=EXITCODE_NO_TESTS_RAN,
1000+
env=env)
1001+
randseed = self.parse_random_seed(output)
1002+
self.assertTrue(randseed.isdigit(), randseed)
9571003

9581004
def test_fromfile(self):
9591005
# test --fromfile
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix regrtest if the ``SOURCE_DATE_EPOCH`` environment variable is defined:
2+
use the variable value as the random seed. Patch by Victor Stinner.

0 commit comments

Comments
 (0)
0