root: Support PyCharm's test runner (#7074)

* Initial commit.

* Use Django's test runner as basis

* Skip already correctly formatted test labels
This commit is contained in:
Philipp Kolberg 2023-10-05 20:13:38 +02:00 committed by GitHub
parent 36c10c74e4
commit 205d3d10e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1,8 +1,10 @@
"""Integrate ./manage.py test with pytest"""
import os
from argparse import ArgumentParser
from unittest import TestCase
from django.conf import settings
from django.test.runner import DiscoverRunner
from authentik.lib.config import CONFIG
from authentik.lib.sentry import sentry_init
@ -12,13 +14,11 @@ from tests.e2e.utils import get_docker_tag
TestCase.maxDiff = None
class PytestTestRunner: # pragma: no cover
class PytestTestRunner(DiscoverRunner): # pragma: no cover
"""Runs pytest to discover and run tests."""
def __init__(self, verbosity=1, failfast=False, keepdb=False, **kwargs):
self.verbosity = verbosity
self.failfast = failfast
self.keepdb = keepdb
super().__init__(verbosity, failfast, keepdb, **kwargs)
self.args = []
if self.failfast:
@ -47,16 +47,61 @@ class PytestTestRunner: # pragma: no cover
@classmethod
def add_arguments(cls, parser: ArgumentParser):
"""Add more pytest-specific arguments"""
parser.add_argument("--randomly-seed", type=int)
parser.add_argument("--keepdb", action="store_true")
parser.add_argument(
"--randomly-seed",
type=int,
help="Set the seed that pytest-randomly uses (int), or pass the special value 'last'"
"to reuse the seed from the previous run."
"Default behaviour: use random.Random().getrandbits(32), so the seed is"
"different on each run.",
)
parser.add_argument(
"--keepdb", action="store_true", help="Preserves the test DB between runs."
)
def run_tests(self, test_labels):
def run_tests(self, test_labels, extra_tests=None, **kwargs):
"""Run pytest and return the exitcode.
It translates some of Django's test command option to pytest's.
It is supported to only run specific classes and methods using
a dotted module name i.e. foo.bar[.Class[.method]]
The extra_tests argument has been deprecated since Django 5.x
It is kept for compatibility with PyCharm's Django test runner.
"""
for label in test_labels:
valid_label_found = False
label_as_path = os.path.abspath(label)
# File path has been specified
if os.path.exists(label_as_path):
self.args.append(label_as_path)
valid_label_found = True
else:
# Already correctly formatted test found (file_path::class::method)
if "::" in label:
self.args.append(label)
valid_label_found = True
# Convert dotted module path to file_path::class::method
else:
path_pieces = label.split(".")
# Check whether only class or class and method are specified
for i in range(-1, -3, -1):
path = os.path.join(*path_pieces[:i]) + ".py"
label_as_path = os.path.abspath(path)
if os.path.exists(label_as_path):
path_method = label_as_path + "::" + "::".join(path_pieces[i:])
self.args.append(path_method)
valid_label_found = True
break
if not valid_label_found:
raise RuntimeError(
f"One of the test labels: {label!r}, "
f"is not supported. Use a dotted module name or "
f"path instead."
)
import pytest
self.args.extend(test_labels)
return pytest.main(self.args)