Skip to content

Commit be4c7be

Browse files
committed
gh-109566, regrtest: Add --fast-ci and --slow-ci options
* Add --fast-ci and --slow-ci options to libregrtest: * --fast-ci uses a default timeout of 10 minutes and "-u all,-cpu" (skip slowest tests). * --slow-ci uses a default timeout of 20 minues and "-u all" (run all tests). * regrtest header now lists test resources. * Makefile changes: * "make test", "make hostrunnertest" and "make coverage-report" now use --fast-ci option and TESTTIMEOUT variable. * "make buildbottest" now uses "--slow-ci". Remove options which became redundant with "--slow-ci". * "make testall" and "make testuniversal" now use --slow-ci option and TESTTIMEOUT variable. * "make testall" now uses "find -exec rm ..." instead of "find ... -print|xargs rm ...", same as "make clean". * GitHub Actions workflow: * Ubuntu and Address Sanitizer jobs now use "make test". Remove options which became redundant with "--fast-ci". * Windows jobs now use --fast-ci option. * Use -j0 to detect the number of CPUs. * Set Makefile TESTTIMEOUT default to an empty string, since --slow-ci and --fast-ci use different default timeout. It's now accepted to pass "--timeout=" to regrtest: treated as not timeout. * Tools/scripts/run_tests.py now uses --fast-ci option. * Tools/buildbot/test.bat now uses --slow-ci option. Remove --timeout=1200 option, redundant with --slow-ci.
1 parent 2897142 commit be4c7be

File tree

11 files changed

+155
-51
lines changed

11 files changed

+155
-51
lines changed

.github/workflows/build.yml

+5-5
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ jobs:
182182
- name: Display build info
183183
run: .\python.bat -m test.pythoninfo
184184
- name: Tests
185-
run: .\PCbuild\rt.bat -p Win32 -d -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0
185+
run: .\PCbuild\rt.bat -p Win32 -d -q --fast-ci
186186

187187
build_win_amd64:
188188
name: 'Windows (x64)'
@@ -201,7 +201,7 @@ jobs:
201201
- name: Display build info
202202
run: .\python.bat -m test.pythoninfo
203203
- name: Tests
204-
run: .\PCbuild\rt.bat -p x64 -d -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0
204+
run: .\PCbuild\rt.bat -p x64 -d -q --fast-ci
205205

206206
build_win_arm64:
207207
name: 'Windows (arm64)'
@@ -252,7 +252,7 @@ jobs:
252252
- name: Display build info
253253
run: make pythoninfo
254254
- name: Tests
255-
run: make buildbottest TESTOPTS="-j4 -uall,-cpu"
255+
run: make test
256256

257257
build_ubuntu:
258258
name: 'Ubuntu'
@@ -319,7 +319,7 @@ jobs:
319319
run: sudo mount $CPYTHON_RO_SRCDIR -oremount,rw
320320
- name: Tests
321321
working-directory: ${{ env.CPYTHON_BUILDDIR }}
322-
run: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu"
322+
run: xvfb-run make test
323323

324324
build_ubuntu_ssltests:
325325
name: 'Ubuntu SSL tests with OpenSSL'
@@ -535,7 +535,7 @@ jobs:
535535
- name: Display build info
536536
run: make pythoninfo
537537
- name: Tests
538-
run: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu"
538+
run: xvfb-run make test
539539

540540
all-required-green: # This job does nothing and is only used for the branch protection
541541
name: All required checks pass

Doc/using/configure.rst

+12-3
Original file line numberDiff line numberDiff line change
@@ -964,9 +964,18 @@ Main Makefile targets
964964
You can use the configure :option:`--enable-optimizations` option to make
965965
this the default target of the ``make`` command (``make all`` or just
966966
``make``).
967-
* ``make buildbottest``: Build Python and run the Python test suite, the same
968-
way than buildbots test Python. Set ``TESTTIMEOUT`` variable (in seconds)
969-
to change the test timeout (1200 by default: 20 minutes).
967+
968+
* ``make test``: Build Python and run the Python test suite with ``--slow-ci``
969+
option. Variables:
970+
971+
* ``TESTOPTS``: additional regrtest command line options.
972+
* ``TESTPYTHONOPTS``: additional Python command line options.
973+
* ``TESTTIMEOUT``: timeout in seconds (default: 20 minutes).
974+
975+
* ``make buildbottest``: Similar to ``make test``, but use ``--slow-ci``
976+
option and default timeout of 20 minutes, instead of ``--fast-ci`` option
977+
and a default timeout of 10 minutes.
978+
970979
* ``make install``: Build and install Python.
971980
* ``make regen-all``: Regenerate (almost) all generated files;
972981
``make regen-stdlib-module-names`` and ``autoconf`` must be run separately

Lib/test/libregrtest/cmdline.py

+53-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import sys
55
from test.support import os_helper
66

7+
from .utils import MS_WINDOWS
8+
79

810
USAGE = """\
911
python -m test [options] [test_name1 [test_name2 ...]]
@@ -145,6 +147,7 @@
145147

146148
class Namespace(argparse.Namespace):
147149
def __init__(self, **kwargs) -> None:
150+
self.ci = False
148151
self.testdir = None
149152
self.verbose = 0
150153
self.quiet = False
@@ -209,7 +212,13 @@ def _create_parser():
209212
# We add help explicitly to control what argument group it renders under.
210213
group.add_argument('-h', '--help', action='help',
211214
help='show this help message and exit')
212-
group.add_argument('--timeout', metavar='TIMEOUT', type=float,
215+
group.add_argument('--fast-ci', action='store_true',
216+
help='Fast Continuous Integration (CI) mode used by '
217+
'GitHub Actions')
218+
group.add_argument('--slow-ci', action='store_true',
219+
help='Slow Continuous Integration (CI) mode used by '
220+
'buildbot workers')
221+
group.add_argument('--timeout', metavar='TIMEOUT',
213222
help='dump the traceback and exit if a test takes '
214223
'more than TIMEOUT seconds; disabled if TIMEOUT '
215224
'is negative or equals to zero')
@@ -384,7 +393,49 @@ def _parse_args(args, **kwargs):
384393
for arg in ns.args:
385394
if arg.startswith('-'):
386395
parser.error("unrecognized arguments: %s" % arg)
387-
sys.exit(1)
396+
397+
if ns.timeout is not None:
398+
# Support "--timeout=" (no value) so Makefile.pre.pre TESTTIMEOUT
399+
# can be used by "make buildbottest" and "make test".
400+
if ns.timeout != "":
401+
try:
402+
ns.timeout = float(ns.timeout)
403+
except ValueError:
404+
parser.error(f"invalid timeout value: {ns.timeout!r}")
405+
else:
406+
ns.timeout = None
407+
408+
# Continuous Integration (CI): common options for fast/slow CI modes
409+
if ns.slow_ci or ns.fast_ci:
410+
# Similar to options:
411+
#
412+
# -j0 --randomize --fail-env-changed --fail-rerun --rerun
413+
# --slowest --verbose3 --nowindows
414+
if ns.use_mp is None:
415+
ns.use_mp = 0
416+
ns.randomize = True
417+
ns.fail_env_changed = True
418+
ns.fail_rerun = True
419+
ns.rerun = True
420+
ns.print_slow = True
421+
ns.verbose3 = True
422+
if MS_WINDOWS:
423+
ns.nowindows = True # Silence alerts under Windows
424+
425+
# When both --slow-ci and --fast-ci options are present,
426+
# --slow-ci has the priority
427+
if ns.slow_ci:
428+
# Similar to: -u "all" --timeout=1200
429+
if not ns.use:
430+
ns.use = [['all']]
431+
if ns.timeout is None:
432+
ns.timeout = 1200 # 20 minutes
433+
elif ns.fast_ci:
434+
# Similar to: -u "all,-cpu" --timeout=600
435+
if not ns.use:
436+
ns.use = [['all', '-cpu']]
437+
if ns.timeout is None:
438+
ns.timeout = 600 # 10 minutes
388439

389440
if ns.single and ns.fromfile:
390441
parser.error("-s and -f don't go together!")

Lib/test/libregrtest/main.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ def _run_tests(self, selected: TestTuple, tests: TestList | None) -> int:
425425
if (self.want_header
426426
or not(self.pgo or self.quiet or self.single_test_run
427427
or tests or self.cmdline_args)):
428-
display_header()
428+
display_header(self.use_resources)
429429

430430
if self.randomize:
431431
print("Using random seed", self.random_seed)

Lib/test/libregrtest/results.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88
printlist, count, format_duration)
99

1010

11+
# Python uses exit code 1 when an exception is not catched
12+
# argparse.ArgumentParser.error() uses exit code 2
1113
EXITCODE_BAD_TEST = 2
1214
EXITCODE_ENV_CHANGED = 3
1315
EXITCODE_NO_TESTS_RAN = 4
1416
EXITCODE_RERUN_FAIL = 5
15-
EXITCODE_INTERRUPTED = 130
17+
EXITCODE_INTERRUPTED = 130 # 128 + signal.SIGINT=2
1618

1719

1820
class TestResults:

Lib/test/libregrtest/utils.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ def adjust_rlimit_nofile():
547547
f"{new_fd_limit}: {err}.")
548548

549549

550-
def display_header():
550+
def display_header(use_resources: tuple[str, ...]):
551551
encoding = sys.stdout.encoding
552552

553553
# Print basic platform information
@@ -569,6 +569,13 @@ def display_header():
569569
print("== encodings: locale=%s, FS=%s"
570570
% (locale.getencoding(), sys.getfilesystemencoding()))
571571

572+
573+
if use_resources:
574+
print(f"== resources ({len(use_resources)}): "
575+
f"{', '.join(sorted(use_resources))}")
576+
else:
577+
print(f"== resources: (all disabled, use -u option)")
578+
572579
# This makes it easier to remember what to set in your local
573580
# environment when trying to reproduce a sanitizer failure.
574581
asan = support.check_sanitizer(address=True)

Lib/test/test_regrtest.py

+42-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@
2323
from test import support
2424
from test.support import os_helper, TestStats, without_optimizer
2525
from test.libregrtest import cmdline
26-
from test.libregrtest import utils
26+
from test.libregrtest import main
2727
from test.libregrtest import setup
28+
from test.libregrtest import utils
2829
from test.libregrtest.utils import normalize_test_name
2930

3031
if not support.has_subprocess_support:
@@ -75,8 +76,15 @@ def test_help(self):
7576
def test_timeout(self):
7677
ns = self.parse_args(['--timeout', '4.2'])
7778
self.assertEqual(ns.timeout, 4.2)
79+
80+
# negative, zero and empty string are treated as "no timeout"
81+
for value in ('-1', '0', ''):
82+
with self.subTest(value=value):
83+
ns = self.parse_args([f'--timeout={value}'])
84+
self.assertEqual(ns.timeout, None)
85+
7886
self.checkError(['--timeout'], 'expected one argument')
79-
self.checkError(['--timeout', 'foo'], 'invalid float value')
87+
self.checkError(['--timeout', 'foo'], 'invalid timeout value:')
8088

8189
def test_wait(self):
8290
ns = self.parse_args(['--wait'])
@@ -366,6 +374,38 @@ def test_unknown_option(self):
366374
self.checkError(['--unknown-option'],
367375
'unrecognized arguments: --unknown-option')
368376

377+
def check_ci_mode(self, args, use_resources):
378+
ns = cmdline._parse_args(args)
379+
if utils.MS_WINDOWS:
380+
self.assertTrue(ns.nowindows)
381+
382+
# Check Regrtest attributes which are more reliable than Namespace
383+
# which has an unclear API
384+
regrtest = main.Regrtest(ns)
385+
self.assertNotEqual(regrtest.num_workers, 0)
386+
self.assertTrue(regrtest.want_rerun)
387+
self.assertTrue(regrtest.randomize)
388+
self.assertIsNone(regrtest.random_seed)
389+
self.assertTrue(regrtest.fail_env_changed)
390+
self.assertTrue(regrtest.fail_rerun)
391+
self.assertTrue(regrtest.print_slowest)
392+
self.assertTrue(regrtest.output_on_failure)
393+
self.assertEqual(sorted(regrtest.use_resources), sorted(use_resources))
394+
return regrtest
395+
396+
def test_fast_ci(self):
397+
args = ['--fast-ci']
398+
use_resources = sorted(cmdline.ALL_RESOURCES)
399+
use_resources.remove('cpu')
400+
regrtest = self.check_ci_mode(args, use_resources)
401+
self.assertEqual(regrtest.timeout, 10 * 60)
402+
403+
def test_slow_ci(self):
404+
args = ['--slow-ci']
405+
use_resources = sorted(cmdline.ALL_RESOURCES)
406+
regrtest = self.check_ci_mode(args, use_resources)
407+
self.assertEqual(regrtest.timeout, 20 * 60)
408+
369409

370410
@dataclasses.dataclass(slots=True)
371411
class Rerun:

Makefile.pre.in

+23-22
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,7 @@ coverage-report: regen-token regen-frozen
771771
@ # build with coverage info
772772
$(MAKE) coverage
773773
@ # run tests, ignore failures
774-
$(TESTRUNNER) $(TESTOPTS) || true
774+
$(TESTRUNNER) --fast-ci --timeout=$(TESTTIMEOUT) $(TESTOPTS) || true
775775
@ # build lcov report
776776
$(MAKE) coverage-lcov
777777

@@ -1844,7 +1844,7 @@ $(LIBRARY_OBJS) $(MODOBJS) Programs/python.o: $(PYTHON_HEADERS)
18441844
TESTOPTS= $(EXTRATESTOPTS)
18451845
TESTPYTHON= $(RUNSHARED) $(PYTHON_FOR_BUILD) $(TESTPYTHONOPTS)
18461846
TESTRUNNER= $(TESTPYTHON) $(srcdir)/Tools/scripts/run_tests.py
1847-
TESTTIMEOUT= 1200
1847+
TESTTIMEOUT=
18481848

18491849
# Remove "test_python_*" directories of previous failed test jobs.
18501850
# Pass TESTOPTS options because it can contain --tempdir option.
@@ -1854,9 +1854,10 @@ cleantest: all
18541854

18551855
# Run a basic set of regression tests.
18561856
# This excludes some tests that are particularly resource-intensive.
1857+
# Similar to buildbottest, but use --fast-ci option, instead of --slow-ci.
18571858
.PHONY: test
18581859
test: all
1859-
$(TESTRUNNER) $(TESTOPTS)
1860+
$(TESTRUNNER) --fast-ci --timeout=$(TESTTIMEOUT) $(TESTOPTS)
18601861

18611862
# Run the full test suite twice - once without .pyc files, and once with.
18621863
# In the past, we've had problems where bugs in the marshalling or
@@ -1867,43 +1868,43 @@ test: all
18671868
# sample data.
18681869
.PHONY: testall
18691870
testall: all
1870-
-find $(srcdir)/Lib -name '*.py[co]' -print | xargs rm -f
1871-
$(TESTPYTHON) -E $(srcdir)/Lib/compileall.py
1872-
-find $(srcdir)/Lib -name '*.py[co]' -print | xargs rm -f
1873-
-$(TESTRUNNER) -u all $(TESTOPTS)
1874-
$(TESTRUNNER) -u all $(TESTOPTS)
1871+
-find $(srcdir)/Lib -name '*.py[co]' -exec rm -f {} ';' || true
1872+
$(TESTPYTHON) -E $(srcdir)/Lib/compileall.py
1873+
-find $(srcdir)/Lib -name '*.py[co]' -exec rm -f {} ';' || true
1874+
$(TESTRUNNER) --slow-ci --timeout=$(TESTTIMEOUT) $(TESTOPTS)
1875+
$(TESTRUNNER) --slow-ci --timeout=$(TESTTIMEOUT) $(TESTOPTS)
18751876

18761877
# Run the test suite for both architectures in a Universal build on OSX.
18771878
# Must be run on an Intel box.
18781879
.PHONY: testuniversal
18791880
testuniversal: all
1880-
@if [ `arch` != 'i386' ]; then \
1881-
echo "This can only be used on OSX/i386" ;\
1882-
exit 1 ;\
1883-
fi
1884-
$(TESTRUNNER) -u all $(TESTOPTS)
1885-
$(RUNSHARED) /usr/libexec/oah/translate \
1886-
./$(BUILDPYTHON) -E -m test -j 0 -u all $(TESTOPTS)
1881+
@if [ `arch` != 'i386' ]; then \
1882+
echo "This can only be used on OSX/i386" ;\
1883+
exit 1 ;\
1884+
fi
1885+
$(TESTRUNNER) --slow-ci --timeout=$(TESTTIMEOUT) $(TESTOPTS)
1886+
$(RUNSHARED) /usr/libexec/oah/translate \
1887+
./$(BUILDPYTHON) -E -m test -j 0 -u all $(TESTOPTS)
18871888

18881889
# Like testall, but with only one pass and without multiple processes.
18891890
# Run an optional script to include information about the build environment.
18901891
.PHONY: buildbottest
18911892
buildbottest: all
1892-
-@if which pybuildbot.identify >/dev/null 2>&1; then \
1893-
pybuildbot.identify "CC='$(CC)'" "CXX='$(CXX)'"; \
1894-
fi
1895-
$(TESTRUNNER) -j 1 -u all -W --slowest --fail-env-changed --fail-rerun --timeout=$(TESTTIMEOUT) $(TESTOPTS)
1893+
-@if which pybuildbot.identify >/dev/null 2>&1; then \
1894+
pybuildbot.identify "CC='$(CC)'" "CXX='$(CXX)'"; \
1895+
fi
1896+
$(TESTRUNNER) --slow-ci --timeout=$(TESTTIMEOUT) $(TESTOPTS)
18961897

18971898
# Like testall, but run Python tests with HOSTRUNNER directly.
18981899
.PHONY: hostrunnertest
18991900
hostrunnertest: all
1900-
$(RUNSHARED) $(HOSTRUNNER) ./$(BUILDPYTHON) -m test -u all $(TESTOPTS)
1901+
$(RUNSHARED) $(HOSTRUNNER) ./$(BUILDPYTHON) -m test --slow-ci --timeout=$(TESTTIMEOUT) $(TESTOPTS)
19011902

19021903
.PHONY: pythoninfo
19031904
pythoninfo: all
19041905
$(RUNSHARED) $(HOSTRUNNER) ./$(BUILDPYTHON) -m test.pythoninfo
19051906

1906-
QUICKTESTOPTS= $(TESTOPTS) -x test_subprocess test_io \
1907+
QUICKTESTOPTS= -x test_subprocess test_io \
19071908
test_multibytecodec test_urllib2_localnet test_itertools \
19081909
test_multiprocessing_fork test_multiprocessing_spawn \
19091910
test_multiprocessing_forkserver \
@@ -1912,7 +1913,7 @@ QUICKTESTOPTS= $(TESTOPTS) -x test_subprocess test_io \
19121913

19131914
.PHONY: quicktest
19141915
quicktest: all
1915-
$(TESTRUNNER) $(QUICKTESTOPTS)
1916+
$(TESTRUNNER) --fast-ci --timeout=$(TESTTIMEOUT) $(TESTOPTS) $(QUICKTESTOPTS)
19161917

19171918
# SSL tests
19181919
.PHONY: multisslcompile
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
regrtest: Add ``--fast-ci`` and ``--slow-ci`` options. ``--fast-ci`` uses a
2+
default timeout of 10 minutes and ``-u all,-cpu`` (skip slowest tests).
3+
``--slow-ci`` uses a default timeout of 20 minues and ``-u all`` (run all
4+
tests). Patch by Victor Stinner.

Tools/buildbot/test.bat

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ setlocal
55
set PATH=%PATH%;%SystemRoot%\SysNative\OpenSSH;%SystemRoot%\System32\OpenSSH
66
set here=%~dp0
77
set rt_opts=-q -d
8-
set regrtest_args=-j1
8+
set regrtest_args=
99
set arm32_ssh=
1010

1111
:CheckOpts
@@ -23,7 +23,7 @@ if "%PROCESSOR_ARCHITECTURE%"=="ARM" if "%arm32_ssh%"=="true" goto NativeExecuti
2323
if "%arm32_ssh%"=="true" goto :Arm32Ssh
2424

2525
:NativeExecution
26-
call "%here%..\..\PCbuild\rt.bat" %rt_opts% -uall -rwW --slowest --timeout=1200 %regrtest_args%
26+
call "%here%..\..\PCbuild\rt.bat" %rt_opts% --slow-ci %regrtest_args%
2727
exit /b %ERRORLEVEL%
2828

2929
:Arm32Ssh
@@ -35,7 +35,7 @@ if NOT "%REMOTE_PYTHON_DIR:~-1,1%"=="\" (set REMOTE_PYTHON_DIR=%REMOTE_PYTHON_DI
3535

3636
set TEMP_ARGS=--temp %REMOTE_PYTHON_DIR%temp
3737

38-
set rt_args=%rt_opts% %dashU% -rwW --slowest --timeout=1200 %regrtest_args% %TEMP_ARGS%
38+
set rt_args=%rt_opts% --slow-ci %dashU% %regrtest_args% %TEMP_ARGS%
3939
ssh %SSH_SERVER% "set TEMP=%REMOTE_PYTHON_DIR%temp& cd %REMOTE_PYTHON_DIR% & %REMOTE_PYTHON_DIR%PCbuild\rt.bat" %rt_args%
4040
set ERR=%ERRORLEVEL%
4141
scp %SSH_SERVER%:"%REMOTE_PYTHON_DIR%test-results.xml" "%PYTHON_SOURCE%\test-results.xml"

0 commit comments

Comments
 (0)