Fixed #32609 -- Updated runtests.py to support directory path test labels.

For example, with this change, the following now works from the tests
directory:

    $ ./runtests.py view_tests/tests/
This commit is contained in:
Chris Jerdonek 2021-06-08 01:49:11 -07:00 committed by Mariusz Felisiak
parent fa0433d05f
commit de4f620183
3 changed files with 26 additions and 8 deletions

View File

@ -629,8 +629,8 @@ class DiscoverRunner:
assert tests is None assert tests is None
raise RuntimeError( raise RuntimeError(
f'One of the test labels is a path to a file: {label!r}, ' f'One of the test labels is a path to a file: {label!r}, '
f'which is not supported. Use a dotted module name ' f'which is not supported. Use a dotted module name or '
f'instead.' f'path to a directory instead.'
) )
return tests return tests

View File

@ -10,6 +10,7 @@ import subprocess
import sys import sys
import tempfile import tempfile
import warnings import warnings
from pathlib import Path
try: try:
import django import django
@ -142,18 +143,34 @@ def get_test_modules(gis_enabled):
yield test_module yield test_module
def get_label_module(label):
"""Return the top-level module part for a test label."""
path = Path(label)
if len(path.parts) == 1:
# Interpret the label as a dotted module name.
return label.split('.')[0]
# Otherwise, interpret the label as a path. Check existence first to
# provide a better error message than relative_to() if it doesn't exist.
if not path.exists():
raise RuntimeError(f'Test label path {label} does not exist')
path = path.resolve()
rel_path = path.relative_to(RUNTESTS_DIR)
return rel_path.parts[0]
def get_filtered_test_modules(start_at, start_after, gis_enabled, test_labels=None): def get_filtered_test_modules(start_at, start_after, gis_enabled, test_labels=None):
if test_labels is None: if test_labels is None:
test_labels = [] test_labels = []
# Reduce each test label to just the top-level module part. # Reduce each test label to just the top-level module part.
test_labels_set = set() label_modules = set()
for label in test_labels: for label in test_labels:
test_module = label.split('.')[0] test_module = get_label_module(label)
test_labels_set.add(test_module) label_modules.add(test_module)
# It would be nice to put this validation earlier but it must come after # It would be nice to put this validation earlier but it must come after
# django.setup() so that connection.features.gis_enabled can be accessed. # django.setup() so that connection.features.gis_enabled can be accessed.
if 'gis_tests' in test_labels_set and not gis_enabled: if 'gis_tests' in label_modules and not gis_enabled:
print('Aborting: A GIS database backend is required to run gis_tests.') print('Aborting: A GIS database backend is required to run gis_tests.')
sys.exit(1) sys.exit(1)
@ -174,7 +191,8 @@ def get_filtered_test_modules(start_at, start_after, gis_enabled, test_labels=No
# If the module (or an ancestor) was named on the command line, or # If the module (or an ancestor) was named on the command line, or
# no modules were named (i.e., run all), include the test module. # no modules were named (i.e., run all), include the test module.
if not test_labels or any( if not test_labels or any(
_module_match_label(test_module, label) for label in test_labels_set _module_match_label(test_module, label_module) for
label_module in label_modules
): ):
yield test_module yield test_module

View File

@ -63,7 +63,7 @@ class DiscoverRunnerTests(SimpleTestCase):
msg = ( msg = (
"One of the test labels is a path to a file: " "One of the test labels is a path to a file: "
"'test_discover_runner.py', which is not supported. Use a " "'test_discover_runner.py', which is not supported. Use a "
"dotted module name instead." "dotted module name or path to a directory instead."
) )
with self.assertRaisesMessage(RuntimeError, msg): with self.assertRaisesMessage(RuntimeError, msg):
DiscoverRunner().load_tests_for_label('test_discover_runner.py', {}) DiscoverRunner().load_tests_for_label('test_discover_runner.py', {})