summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorovkulkarni <2019okulkarn@tjhsst.edu>2020-05-06 13:52:12 -0400
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-07-10 18:55:50 +0200
commitb7a438c7e21cdcb26d47f1c1fc5afdc1b3d1a9ef (patch)
treed3de3d982a9e9fae019e2cfe2e3a72a612860737
parent188f7786bc434a3e5ca7b46d2975a08318fe7452 (diff)
Fixed #31509 -- Made DiscoverRunner enable faulthandler by default.
-rw-r--r--django/test/runner.py14
-rw-r--r--docs/ref/django-admin.txt8
-rw-r--r--docs/releases/3.2.txt4
-rw-r--r--docs/topics/testing/advanced.txt9
-rw-r--r--tests/test_runner/test_discover_runner.py29
5 files changed, 61 insertions, 3 deletions
diff --git a/django/test/runner.py b/django/test/runner.py
index 5b634b2ac9..ddf56b336f 100644
--- a/django/test/runner.py
+++ b/django/test/runner.py
@@ -1,9 +1,12 @@
import ctypes
+import faulthandler
+import io
import itertools
import logging
import multiprocessing
import os
import pickle
+import sys
import textwrap
import unittest
from importlib import import_module
@@ -434,7 +437,7 @@ class DiscoverRunner:
interactive=True, failfast=False, keepdb=False,
reverse=False, debug_mode=False, debug_sql=False, parallel=0,
tags=None, exclude_tags=None, test_name_patterns=None,
- pdb=False, buffer=False, **kwargs):
+ pdb=False, buffer=False, enable_faulthandler=True, **kwargs):
self.pattern = pattern
self.top_level = top_level
@@ -448,6 +451,11 @@ class DiscoverRunner:
self.parallel = parallel
self.tags = set(tags or [])
self.exclude_tags = set(exclude_tags or [])
+ if not faulthandler.is_enabled() and enable_faulthandler:
+ try:
+ faulthandler.enable(file=sys.stderr.fileno())
+ except (AttributeError, io.UnsupportedOperation):
+ faulthandler.enable(file=sys.__stderr__.fileno())
self.pdb = pdb
if self.pdb and self.parallel > 1:
raise ValueError('You cannot use --pdb with parallel tests; pass --parallel=1 to use it.')
@@ -513,6 +521,10 @@ class DiscoverRunner:
'-b', '--buffer', action='store_true',
help='Discard output from passing tests.',
)
+ parser.add_argument(
+ '--no-faulthandler', action='store_false', dest='enable_faulthandler',
+ help='Disables the Python faulthandler module during tests.',
+ )
if PY37:
parser.add_argument(
'-k', action='append', dest='test_name_patterns',
diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt
index b0913becf0..99cdafd2c8 100644
--- a/docs/ref/django-admin.txt
+++ b/docs/ref/django-admin.txt
@@ -1515,6 +1515,14 @@ installed, ``ipdb`` is used instead.
Discards output (``stdout`` and ``stderr``) for passing tests, in the same way
as :option:`unittest's --buffer option<unittest.-b>`.
+.. django-admin-option:: --no-faulthandler
+
+.. versionadded:: 3.2
+
+Django automatically calls :func:`faulthandler.enable()` when starting the
+tests, which allows it to print a traceback if the interpreter crashes. Pass
+``--no-faulthandler`` to disable this behavior.
+
``testserver``
--------------
diff --git a/docs/releases/3.2.txt b/docs/releases/3.2.txt
index 0c877bc1f5..64b3b0257c 100644
--- a/docs/releases/3.2.txt
+++ b/docs/releases/3.2.txt
@@ -266,6 +266,10 @@ Tests
creating deep copies with :py:func:`copy.deepcopy`. Assigning objects which
don't support ``deepcopy()`` is deprecated and will be removed in Django 4.1.
+* :class:`~django.test.runner.DiscoverRunner` now enables
+ :py:mod:`faulthandler` by default. This can be disabled by using the
+ :option:`test --no-faulthandler` option.
+
* :class:`~django.test.Client` now preserves the request query string when
following 307 and 308 redirects.
diff --git a/docs/topics/testing/advanced.txt b/docs/topics/testing/advanced.txt
index c4fbee060a..06bd351ccf 100644
--- a/docs/topics/testing/advanced.txt
+++ b/docs/topics/testing/advanced.txt
@@ -510,7 +510,7 @@ behavior. This class defines the ``run_tests()`` entry point, plus a
selection of other methods that are used to by ``run_tests()`` to set up,
execute and tear down the test suite.
-.. class:: DiscoverRunner(pattern='test*.py', top_level=None, verbosity=1, interactive=True, failfast=False, keepdb=False, reverse=False, debug_mode=False, debug_sql=False, test_name_patterns=None, pdb=False, buffer=False, **kwargs)
+.. class:: DiscoverRunner(pattern='test*.py', top_level=None, verbosity=1, interactive=True, failfast=False, keepdb=False, reverse=False, debug_mode=False, debug_sql=False, test_name_patterns=None, pdb=False, buffer=False, enable_faulthandler=True, **kwargs)
``DiscoverRunner`` will search for tests in any file matching ``pattern``.
@@ -557,6 +557,9 @@ execute and tear down the test suite.
If ``buffer`` is ``True``, outputs from passing tests will be discarded.
+ If ``enable_faulthandler`` is ``True``, :py:mod:`faulthandler` will be
+ enabled.
+
Django may, from time to time, extend the capabilities of the test runner
by adding new arguments. The ``**kwargs`` declaration allows for this
expansion. If you subclass ``DiscoverRunner`` or write your own test
@@ -571,6 +574,10 @@ execute and tear down the test suite.
The ``buffer`` argument was added.
+ .. versionadded:: 3.2
+
+ The ``enable_faulthandler`` argument was added.
+
Attributes
~~~~~~~~~~
diff --git a/tests/test_runner/test_discover_runner.py b/tests/test_runner/test_discover_runner.py
index 61af22d818..8caacd2620 100644
--- a/tests/test_runner/test_discover_runner.py
+++ b/tests/test_runner/test_discover_runner.py
@@ -1,7 +1,9 @@
import os
from argparse import ArgumentParser
from contextlib import contextmanager
-from unittest import TestSuite, TextTestRunner, defaultTestLoader, skipUnless
+from unittest import (
+ TestSuite, TextTestRunner, defaultTestLoader, mock, skipUnless,
+)
from django.db import connections
from django.test import SimpleTestCase
@@ -297,6 +299,31 @@ class DiscoverRunnerTests(SimpleTestCase):
self.assertIn('Write to stderr.', stderr.getvalue())
self.assertIn('Write to stdout.', stdout.getvalue())
+ @mock.patch('faulthandler.enable')
+ def test_faulthandler_enabled(self, mocked_enable):
+ with mock.patch('faulthandler.is_enabled', return_value=False):
+ DiscoverRunner(enable_faulthandler=True)
+ mocked_enable.assert_called()
+
+ @mock.patch('faulthandler.enable')
+ def test_faulthandler_already_enabled(self, mocked_enable):
+ with mock.patch('faulthandler.is_enabled', return_value=True):
+ DiscoverRunner(enable_faulthandler=True)
+ mocked_enable.assert_not_called()
+
+ @mock.patch('faulthandler.enable')
+ def test_faulthandler_enabled_fileno(self, mocked_enable):
+ # sys.stderr that is not an actual file.
+ with mock.patch('faulthandler.is_enabled', return_value=False), captured_stderr():
+ DiscoverRunner(enable_faulthandler=True)
+ mocked_enable.assert_called()
+
+ @mock.patch('faulthandler.enable')
+ def test_faulthandler_disabled(self, mocked_enable):
+ with mock.patch('faulthandler.is_enabled', return_value=False):
+ DiscoverRunner(enable_faulthandler=False)
+ mocked_enable.assert_not_called()
+
class DiscoverRunnerGetDatabasesTests(SimpleTestCase):
runner = DiscoverRunner(verbosity=2)