aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/test
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/libregrtest/cmdline.py55
-rw-r--r--Lib/test/libregrtest/main.py2
-rw-r--r--Lib/test/libregrtest/results.py4
-rw-r--r--Lib/test/libregrtest/utils.py9
-rw-r--r--Lib/test/test_regrtest.py50
5 files changed, 113 insertions, 7 deletions
diff --git a/Lib/test/libregrtest/cmdline.py b/Lib/test/libregrtest/cmdline.py
index 99f28152f1a..a0a8504fe8f 100644
--- a/Lib/test/libregrtest/cmdline.py
+++ b/Lib/test/libregrtest/cmdline.py
@@ -4,6 +4,8 @@ import shlex
import sys
from test.support import os_helper
+from .utils import MS_WINDOWS
+
USAGE = """\
python -m test [options] [test_name1 [test_name2 ...]]
@@ -145,6 +147,7 @@ RESOURCE_NAMES = ALL_RESOURCES + ('extralargefile', 'tzdata')
class Namespace(argparse.Namespace):
def __init__(self, **kwargs) -> None:
+ self.ci = False
self.testdir = None
self.verbose = 0
self.quiet = False
@@ -209,7 +212,13 @@ def _create_parser():
# We add help explicitly to control what argument group it renders under.
group.add_argument('-h', '--help', action='help',
help='show this help message and exit')
- group.add_argument('--timeout', metavar='TIMEOUT', type=float,
+ group.add_argument('--fast-ci', action='store_true',
+ help='Fast Continuous Integration (CI) mode used by '
+ 'GitHub Actions')
+ group.add_argument('--slow-ci', action='store_true',
+ help='Slow Continuous Integration (CI) mode used by '
+ 'buildbot workers')
+ group.add_argument('--timeout', metavar='TIMEOUT',
help='dump the traceback and exit if a test takes '
'more than TIMEOUT seconds; disabled if TIMEOUT '
'is negative or equals to zero')
@@ -384,7 +393,49 @@ def _parse_args(args, **kwargs):
for arg in ns.args:
if arg.startswith('-'):
parser.error("unrecognized arguments: %s" % arg)
- sys.exit(1)
+
+ if ns.timeout is not None:
+ # Support "--timeout=" (no value) so Makefile.pre.pre TESTTIMEOUT
+ # can be used by "make buildbottest" and "make test".
+ if ns.timeout != "":
+ try:
+ ns.timeout = float(ns.timeout)
+ except ValueError:
+ parser.error(f"invalid timeout value: {ns.timeout!r}")
+ else:
+ ns.timeout = None
+
+ # Continuous Integration (CI): common options for fast/slow CI modes
+ if ns.slow_ci or ns.fast_ci:
+ # Similar to options:
+ #
+ # -j0 --randomize --fail-env-changed --fail-rerun --rerun
+ # --slowest --verbose3 --nowindows
+ if ns.use_mp is None:
+ ns.use_mp = 0
+ ns.randomize = True
+ ns.fail_env_changed = True
+ ns.fail_rerun = True
+ ns.rerun = True
+ ns.print_slow = True
+ ns.verbose3 = True
+ if MS_WINDOWS:
+ ns.nowindows = True # Silence alerts under Windows
+
+ # When both --slow-ci and --fast-ci options are present,
+ # --slow-ci has the priority
+ if ns.slow_ci:
+ # Similar to: -u "all" --timeout=1200
+ if not ns.use:
+ ns.use = [['all']]
+ if ns.timeout is None:
+ ns.timeout = 1200 # 20 minutes
+ elif ns.fast_ci:
+ # Similar to: -u "all,-cpu" --timeout=600
+ if not ns.use:
+ ns.use = [['all', '-cpu']]
+ if ns.timeout is None:
+ ns.timeout = 600 # 10 minutes
if ns.single and ns.fromfile:
parser.error("-s and -f don't go together!")
diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py
index 0ec25a06b6e..2cd79a1eae5 100644
--- a/Lib/test/libregrtest/main.py
+++ b/Lib/test/libregrtest/main.py
@@ -425,7 +425,7 @@ class Regrtest:
if (self.want_header
or not(self.pgo or self.quiet or self.single_test_run
or tests or self.cmdline_args)):
- display_header()
+ display_header(self.use_resources)
if self.randomize:
print("Using random seed", self.random_seed)
diff --git a/Lib/test/libregrtest/results.py b/Lib/test/libregrtest/results.py
index 1a8619fb62b..35df50d581f 100644
--- a/Lib/test/libregrtest/results.py
+++ b/Lib/test/libregrtest/results.py
@@ -8,11 +8,13 @@ from .utils import (
printlist, count, format_duration)
+# Python uses exit code 1 when an exception is not catched
+# argparse.ArgumentParser.error() uses exit code 2
EXITCODE_BAD_TEST = 2
EXITCODE_ENV_CHANGED = 3
EXITCODE_NO_TESTS_RAN = 4
EXITCODE_RERUN_FAIL = 5
-EXITCODE_INTERRUPTED = 130
+EXITCODE_INTERRUPTED = 130 # 128 + signal.SIGINT=2
class TestResults:
diff --git a/Lib/test/libregrtest/utils.py b/Lib/test/libregrtest/utils.py
index 6af949cea9c..f3f0eb53b32 100644
--- a/Lib/test/libregrtest/utils.py
+++ b/Lib/test/libregrtest/utils.py
@@ -547,7 +547,7 @@ def adjust_rlimit_nofile():
f"{new_fd_limit}: {err}.")
-def display_header():
+def display_header(use_resources: tuple[str, ...]):
encoding = sys.stdout.encoding
# Print basic platform information
@@ -569,6 +569,13 @@ def display_header():
print("== encodings: locale=%s, FS=%s"
% (locale.getencoding(), sys.getfilesystemencoding()))
+
+ if use_resources:
+ print(f"== resources ({len(use_resources)}): "
+ f"{', '.join(sorted(use_resources))}")
+ else:
+ print(f"== resources: (all disabled, use -u option)")
+
# This makes it easier to remember what to set in your local
# environment when trying to reproduce a sanitizer failure.
asan = support.check_sanitizer(address=True)
diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py
index 4b819cbbb8d..15aab609ed1 100644
--- a/Lib/test/test_regrtest.py
+++ b/Lib/test/test_regrtest.py
@@ -23,8 +23,9 @@ import unittest
from test import support
from test.support import os_helper, TestStats, without_optimizer
from test.libregrtest import cmdline
-from test.libregrtest import utils
+from test.libregrtest import main
from test.libregrtest import setup
+from test.libregrtest import utils
from test.libregrtest.utils import normalize_test_name
if not support.has_subprocess_support:
@@ -75,8 +76,15 @@ class ParseArgsTestCase(unittest.TestCase):
def test_timeout(self):
ns = self.parse_args(['--timeout', '4.2'])
self.assertEqual(ns.timeout, 4.2)
+
+ # negative, zero and empty string are treated as "no timeout"
+ for value in ('-1', '0', ''):
+ with self.subTest(value=value):
+ ns = self.parse_args([f'--timeout={value}'])
+ self.assertEqual(ns.timeout, None)
+
self.checkError(['--timeout'], 'expected one argument')
- self.checkError(['--timeout', 'foo'], 'invalid float value')
+ self.checkError(['--timeout', 'foo'], 'invalid timeout value:')
def test_wait(self):
ns = self.parse_args(['--wait'])
@@ -366,6 +374,44 @@ class ParseArgsTestCase(unittest.TestCase):
self.checkError(['--unknown-option'],
'unrecognized arguments: --unknown-option')
+ def check_ci_mode(self, args, use_resources):
+ ns = cmdline._parse_args(args)
+ if utils.MS_WINDOWS:
+ self.assertTrue(ns.nowindows)
+
+ # Check Regrtest attributes which are more reliable than Namespace
+ # which has an unclear API
+ regrtest = main.Regrtest(ns)
+ self.assertNotEqual(regrtest.num_workers, 0)
+ self.assertTrue(regrtest.want_rerun)
+ self.assertTrue(regrtest.randomize)
+ self.assertIsNone(regrtest.random_seed)
+ self.assertTrue(regrtest.fail_env_changed)
+ self.assertTrue(regrtest.fail_rerun)
+ self.assertTrue(regrtest.print_slowest)
+ self.assertTrue(regrtest.output_on_failure)
+ self.assertEqual(sorted(regrtest.use_resources), sorted(use_resources))
+ return regrtest
+
+ def test_fast_ci(self):
+ args = ['--fast-ci']
+ use_resources = sorted(cmdline.ALL_RESOURCES)
+ use_resources.remove('cpu')
+ regrtest = self.check_ci_mode(args, use_resources)
+ self.assertEqual(regrtest.timeout, 10 * 60)
+
+ def test_fast_ci_resource(self):
+ # it should be possible to override resources
+ args = ['--fast-ci', '-u', 'network']
+ use_resources = ['network']
+ self.check_ci_mode(args, use_resources)
+
+ def test_slow_ci(self):
+ args = ['--slow-ci']
+ use_resources = sorted(cmdline.ALL_RESOURCES)
+ regrtest = self.check_ci_mode(args, use_resources)
+ self.assertEqual(regrtest.timeout, 20 * 60)
+
@dataclasses.dataclass(slots=True)
class Rerun: