Fixed #31509 -- Made DiscoverRunner enable faulthandler by default.

This commit is contained in:
ovkulkarni 2020-05-06 13:52:12 -04:00 committed by Mariusz Felisiak
parent 188f7786bc
commit b7a438c7e2
5 changed files with 61 additions and 3 deletions

View File

@ -1,9 +1,12 @@
import ctypes import ctypes
import faulthandler
import io
import itertools import itertools
import logging import logging
import multiprocessing import multiprocessing
import os import os
import pickle import pickle
import sys
import textwrap import textwrap
import unittest import unittest
from importlib import import_module from importlib import import_module
@ -434,7 +437,7 @@ class DiscoverRunner:
interactive=True, failfast=False, keepdb=False, interactive=True, failfast=False, keepdb=False,
reverse=False, debug_mode=False, debug_sql=False, parallel=0, reverse=False, debug_mode=False, debug_sql=False, parallel=0,
tags=None, exclude_tags=None, test_name_patterns=None, 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.pattern = pattern
self.top_level = top_level self.top_level = top_level
@ -448,6 +451,11 @@ class DiscoverRunner:
self.parallel = parallel self.parallel = parallel
self.tags = set(tags or []) self.tags = set(tags or [])
self.exclude_tags = set(exclude_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 self.pdb = pdb
if self.pdb and self.parallel > 1: if self.pdb and self.parallel > 1:
raise ValueError('You cannot use --pdb with parallel tests; pass --parallel=1 to use it.') 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', '-b', '--buffer', action='store_true',
help='Discard output from passing tests.', 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: if PY37:
parser.add_argument( parser.add_argument(
'-k', action='append', dest='test_name_patterns', '-k', action='append', dest='test_name_patterns',

View File

@ -1515,6 +1515,14 @@ installed, ``ipdb`` is used instead.
Discards output (``stdout`` and ``stderr``) for passing tests, in the same way Discards output (``stdout`` and ``stderr``) for passing tests, in the same way
as :option:`unittest's --buffer option<unittest.-b>`. 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`` ``testserver``
-------------- --------------

View File

@ -266,6 +266,10 @@ Tests
creating deep copies with :py:func:`copy.deepcopy`. Assigning objects which 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. 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 * :class:`~django.test.Client` now preserves the request query string when
following 307 and 308 redirects. following 307 and 308 redirects.

View File

@ -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, selection of other methods that are used to by ``run_tests()`` to set up,
execute and tear down the test suite. 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``. ``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 ``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 Django may, from time to time, extend the capabilities of the test runner
by adding new arguments. The ``**kwargs`` declaration allows for this by adding new arguments. The ``**kwargs`` declaration allows for this
expansion. If you subclass ``DiscoverRunner`` or write your own test 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. The ``buffer`` argument was added.
.. versionadded:: 3.2
The ``enable_faulthandler`` argument was added.
Attributes Attributes
~~~~~~~~~~ ~~~~~~~~~~

View File

@ -1,7 +1,9 @@
import os import os
from argparse import ArgumentParser from argparse import ArgumentParser
from contextlib import contextmanager 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.db import connections
from django.test import SimpleTestCase from django.test import SimpleTestCase
@ -297,6 +299,31 @@ class DiscoverRunnerTests(SimpleTestCase):
self.assertIn('Write to stderr.', stderr.getvalue()) self.assertIn('Write to stderr.', stderr.getvalue())
self.assertIn('Write to stdout.', stdout.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): class DiscoverRunnerGetDatabasesTests(SimpleTestCase):
runner = DiscoverRunner(verbosity=2) runner = DiscoverRunner(verbosity=2)