Skip to content

Commit 8a73cac

Browse files
authored
[3.7] bpo-34279: Synchronize regrtest with master (GH-10800)
* bpo-34605, libregrtest: Rename --slaveargs to --worker-args (GH-9099) Rename also run_tests_slave() to run_tests_worker(). (cherry picked from commit 012f5b9) * bpo-34279, regrtest: Issue a warning if no tests have been executed (GH-10150) (cherry picked from commit 9724348) * test_regrtest: remove unused threading import
1 parent 1659c08 commit 8a73cac

File tree

7 files changed

+122
-23
lines changed

7 files changed

+122
-23
lines changed

Lib/test/libregrtest/cmdline.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ def _create_parser():
170170
group.add_argument('--wait', action='store_true',
171171
help='wait for user input, e.g., allow a debugger '
172172
'to be attached')
173-
group.add_argument('--slaveargs', metavar='ARGS')
173+
group.add_argument('--worker-args', metavar='ARGS')
174174
group.add_argument('-S', '--start', metavar='START',
175175
help='the name of the test at which to start.' +
176176
more_details)

Lib/test/libregrtest/main.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from test.libregrtest.runtest import (
1515
findtests, runtest, get_abs_module,
1616
STDTESTS, NOTTESTS, PASSED, FAILED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED,
17-
INTERRUPTED, CHILD_ERROR,
17+
INTERRUPTED, CHILD_ERROR, TEST_DID_NOT_RUN,
1818
PROGRESS_MIN_TIME, format_test_result)
1919
from test.libregrtest.setup import setup_tests
2020
from test.libregrtest.utils import removepy, count, format_duration, printlist
@@ -79,6 +79,7 @@ def __init__(self):
7979
self.resource_denieds = []
8080
self.environment_changed = []
8181
self.rerun = []
82+
self.run_no_tests = []
8283
self.first_result = None
8384
self.interrupted = False
8485

@@ -118,6 +119,8 @@ def accumulate_result(self, test, result):
118119
elif ok == RESOURCE_DENIED:
119120
self.skipped.append(test)
120121
self.resource_denieds.append(test)
122+
elif ok == TEST_DID_NOT_RUN:
123+
self.run_no_tests.append(test)
121124
elif ok != INTERRUPTED:
122125
raise ValueError("invalid test result: %r" % ok)
123126

@@ -368,6 +371,11 @@ def display_result(self):
368371
print("%s:" % count(len(self.rerun), "re-run test"))
369372
printlist(self.rerun)
370373

374+
if self.run_no_tests:
375+
print()
376+
print(count(len(self.run_no_tests), "test"), "run no tests:")
377+
printlist(self.run_no_tests)
378+
371379
def run_tests_sequential(self):
372380
if self.ns.trace:
373381
import trace
@@ -458,6 +466,9 @@ def get_tests_result(self):
458466
result.append("FAILURE")
459467
elif self.ns.fail_env_changed and self.environment_changed:
460468
result.append("ENV CHANGED")
469+
elif not any((self.good, self.bad, self.skipped, self.interrupted,
470+
self.environment_changed)):
471+
result.append("NO TEST RUN")
461472

462473
if self.interrupted:
463474
result.append("INTERRUPTED")
@@ -580,9 +591,9 @@ def _main(self, tests, kwargs):
580591
print(msg, file=sys.stderr, flush=True)
581592
sys.exit(2)
582593

583-
if self.ns.slaveargs is not None:
584-
from test.libregrtest.runtest_mp import run_tests_slave
585-
run_tests_slave(self.ns.slaveargs)
594+
if self.ns.worker_args is not None:
595+
from test.libregrtest.runtest_mp import run_tests_worker
596+
run_tests_worker(self.ns.worker_args)
586597

587598
if self.ns.wait:
588599
input("Press any key to continue...")

Lib/test/libregrtest/runtest.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
RESOURCE_DENIED = -3
2020
INTERRUPTED = -4
2121
CHILD_ERROR = -5 # error in a child process
22+
TEST_DID_NOT_RUN = -6 # error in a child process
2223

2324
_FORMAT_TEST_RESULT = {
2425
PASSED: '%s passed',
@@ -28,6 +29,7 @@
2829
RESOURCE_DENIED: '%s skipped (resource denied)',
2930
INTERRUPTED: '%s interrupted',
3031
CHILD_ERROR: '%s crashed',
32+
TEST_DID_NOT_RUN: '%s run no tests',
3133
}
3234

3335
# Minimum duration of a test to display its duration or to mention that
@@ -94,6 +96,7 @@ def runtest(ns, test):
9496
ENV_CHANGED test failed because it changed the execution environment
9597
FAILED test failed
9698
PASSED test passed
99+
EMPTY_TEST_SUITE test ran no subtests.
97100
98101
If ns.xmlpath is not None, xml_data is a list containing each
99102
generated testsuite element.
@@ -197,6 +200,8 @@ def test_runner():
197200
else:
198201
print("test", test, "failed", file=sys.stderr, flush=True)
199202
return FAILED, test_time
203+
except support.TestDidNotRun:
204+
return TEST_DID_NOT_RUN, test_time
200205
except:
201206
msg = traceback.format_exc()
202207
if not ns.pgo:

Lib/test/libregrtest/runtest_mp.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,23 @@
2424

2525

2626
def run_test_in_subprocess(testname, ns):
27-
"""Run the given test in a subprocess with --slaveargs.
27+
"""Run the given test in a subprocess with --worker-args.
2828
2929
ns is the option Namespace parsed from command-line arguments. regrtest
30-
is invoked in a subprocess with the --slaveargs argument; when the
30+
is invoked in a subprocess with the --worker-args argument; when the
3131
subprocess exits, its return code, stdout and stderr are returned as a
3232
3-tuple.
3333
"""
3434
from subprocess import Popen, PIPE
3535

3636
ns_dict = vars(ns)
37-
slaveargs = (ns_dict, testname)
38-
slaveargs = json.dumps(slaveargs)
37+
worker_args = (ns_dict, testname)
38+
worker_args = json.dumps(worker_args)
3939

4040
cmd = [sys.executable, *support.args_from_interpreter_flags(),
4141
'-u', # Unbuffered stdout and stderr
4242
'-m', 'test.regrtest',
43-
'--slaveargs', slaveargs]
43+
'--worker-args', worker_args]
4444
if ns.pgo:
4545
cmd += ['--pgo']
4646

@@ -58,8 +58,8 @@ def run_test_in_subprocess(testname, ns):
5858
return retcode, stdout, stderr
5959

6060

61-
def run_tests_slave(slaveargs):
62-
ns_dict, testname = json.loads(slaveargs)
61+
def run_tests_worker(worker_args):
62+
ns_dict, testname = json.loads(worker_args)
6363
ns = types.SimpleNamespace(**ns_dict)
6464

6565
setup_tests(ns)

Lib/test/support/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
# globals
7272
"PIPE_MAX_SIZE", "verbose", "max_memuse", "use_resources", "failfast",
7373
# exceptions
74-
"Error", "TestFailed", "ResourceDenied",
74+
"Error", "TestFailed", "TestDidNotRun", "ResourceDenied",
7575
# imports
7676
"import_module", "import_fresh_module", "CleanImport",
7777
# modules
@@ -117,6 +117,9 @@ class Error(Exception):
117117
class TestFailed(Error):
118118
"""Test failed."""
119119

120+
class TestDidNotRun(Error):
121+
"""Test did not run any subtests."""
122+
120123
class ResourceDenied(unittest.SkipTest):
121124
"""Test skipped because it requested a disallowed resource.
122125
@@ -1890,6 +1893,8 @@ def _run_suite(suite):
18901893
if junit_xml_list is not None:
18911894
junit_xml_list.append(result.get_xml_element())
18921895

1896+
if not result.testsRun:
1897+
raise TestDidNotRun
18931898
if not result.wasSuccessful():
18941899
if len(result.errors) == 1 and not result.failures:
18951900
err = result.errors[0][1]

Lib/test/test_regrtest.py

Lines changed: 85 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import sysconfig
1616
import tempfile
1717
import textwrap
18-
import threading
1918
import unittest
2019
from test import libregrtest
2120
from test import support
@@ -67,10 +66,10 @@ def test_wait(self):
6766
ns = libregrtest._parse_args(['--wait'])
6867
self.assertTrue(ns.wait)
6968

70-
def test_slaveargs(self):
71-
ns = libregrtest._parse_args(['--slaveargs', '[[], {}]'])
72-
self.assertEqual(ns.slaveargs, '[[], {}]')
73-
self.checkError(['--slaveargs'], 'expected one argument')
69+
def test_worker_args(self):
70+
ns = libregrtest._parse_args(['--worker-args', '[[], {}]'])
71+
self.assertEqual(ns.worker_args, '[[], {}]')
72+
self.checkError(['--worker-args'], 'expected one argument')
7473

7574
def test_start(self):
7675
for opt in '-S', '--start':
@@ -352,11 +351,20 @@ def setUp(self):
352351
self.tmptestdir = tempfile.mkdtemp()
353352
self.addCleanup(support.rmtree, self.tmptestdir)
354353

355-
def create_test(self, name=None, code=''):
354+
def create_test(self, name=None, code=None):
356355
if not name:
357356
name = 'noop%s' % BaseTestCase.TEST_UNIQUE_ID
358357
BaseTestCase.TEST_UNIQUE_ID += 1
359358

359+
if code is None:
360+
code = textwrap.dedent("""
361+
import unittest
362+
363+
class Tests(unittest.TestCase):
364+
def test_empty_test(self):
365+
pass
366+
""")
367+
360368
# test_regrtest cannot be run twice in parallel because
361369
# of setUp() and create_test()
362370
name = self.TESTNAME_PREFIX + name
@@ -391,7 +399,7 @@ def parse_executed_tests(self, output):
391399

392400
def check_executed_tests(self, output, tests, skipped=(), failed=(),
393401
env_changed=(), omitted=(),
394-
rerun=(),
402+
rerun=(), no_test_ran=(),
395403
randomize=False, interrupted=False,
396404
fail_env_changed=False):
397405
if isinstance(tests, str):
@@ -406,6 +414,8 @@ def check_executed_tests(self, output, tests, skipped=(), failed=(),
406414
omitted = [omitted]
407415
if isinstance(rerun, str):
408416
rerun = [rerun]
417+
if isinstance(no_test_ran, str):
418+
no_test_ran = [no_test_ran]
409419

410420
executed = self.parse_executed_tests(output)
411421
if randomize:
@@ -448,8 +458,12 @@ def list_regex(line_format, tests):
448458
regex = "Re-running test %r in verbose mode" % name
449459
self.check_line(output, regex)
450460

461+
if no_test_ran:
462+
regex = list_regex('%s test%s run no tests', no_test_ran)
463+
self.check_line(output, regex)
464+
451465
good = (len(tests) - len(skipped) - len(failed)
452-
- len(omitted) - len(env_changed))
466+
- len(omitted) - len(env_changed) - len(no_test_ran))
453467
if good:
454468
regex = r'%s test%s OK\.$' % (good, plural(good))
455469
if not skipped and not failed and good > 1:
@@ -466,12 +480,16 @@ def list_regex(line_format, tests):
466480
result.append('ENV CHANGED')
467481
if interrupted:
468482
result.append('INTERRUPTED')
469-
if not result:
483+
if not any((good, result, failed, interrupted, skipped,
484+
env_changed, fail_env_changed)):
485+
result.append("NO TEST RUN")
486+
elif not result:
470487
result.append('SUCCESS')
471488
result = ', '.join(result)
472489
if rerun:
473490
self.check_line(output, 'Tests result: %s' % result)
474491
result = 'FAILURE then %s' % result
492+
475493
self.check_line(output, 'Tests result: %s' % result)
476494

477495
def parse_random_seed(self, output):
@@ -650,7 +668,14 @@ def test_resources(self):
650668
# test -u command line option
651669
tests = {}
652670
for resource in ('audio', 'network'):
653-
code = 'from test import support\nsupport.requires(%r)' % resource
671+
code = textwrap.dedent("""
672+
from test import support; support.requires(%r)
673+
import unittest
674+
class PassingTest(unittest.TestCase):
675+
def test_pass(self):
676+
pass
677+
""" % resource)
678+
654679
tests[resource] = self.create_test(resource, code)
655680
test_names = sorted(tests.values())
656681

@@ -979,6 +1004,56 @@ def test_bug(self):
9791004
output = self.run_tests("-w", testname, exitcode=2)
9801005
self.check_executed_tests(output, [testname],
9811006
failed=testname, rerun=testname)
1007+
def test_no_tests_ran(self):
1008+
code = textwrap.dedent("""
1009+
import unittest
1010+
1011+
class Tests(unittest.TestCase):
1012+
def test_bug(self):
1013+
pass
1014+
""")
1015+
testname = self.create_test(code=code)
1016+
1017+
output = self.run_tests(testname, "-m", "nosuchtest", exitcode=0)
1018+
self.check_executed_tests(output, [testname], no_test_ran=testname)
1019+
1020+
def test_no_tests_ran_multiple_tests_nonexistent(self):
1021+
code = textwrap.dedent("""
1022+
import unittest
1023+
1024+
class Tests(unittest.TestCase):
1025+
def test_bug(self):
1026+
pass
1027+
""")
1028+
testname = self.create_test(code=code)
1029+
testname2 = self.create_test(code=code)
1030+
1031+
output = self.run_tests(testname, testname2, "-m", "nosuchtest", exitcode=0)
1032+
self.check_executed_tests(output, [testname, testname2],
1033+
no_test_ran=[testname, testname2])
1034+
1035+
def test_no_test_ran_some_test_exist_some_not(self):
1036+
code = textwrap.dedent("""
1037+
import unittest
1038+
1039+
class Tests(unittest.TestCase):
1040+
def test_bug(self):
1041+
pass
1042+
""")
1043+
testname = self.create_test(code=code)
1044+
other_code = textwrap.dedent("""
1045+
import unittest
1046+
1047+
class Tests(unittest.TestCase):
1048+
def test_other_bug(self):
1049+
pass
1050+
""")
1051+
testname2 = self.create_test(code=other_code)
1052+
1053+
output = self.run_tests(testname, testname2, "-m", "nosuchtest",
1054+
"-m", "test_other_bug", exitcode=0)
1055+
self.check_executed_tests(output, [testname, testname2],
1056+
no_test_ran=[testname])
9821057

9831058

9841059
class TestUtils(unittest.TestCase):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
regrtest issue a warning when no tests have been executed in a particular
2+
test file. Also, a new final result state is issued if no test have been
3+
executed across all test files. Patch by Pablo Galindo.

0 commit comments

Comments
 (0)