Skip to content

Commit

Permalink
Fixed #12364: Added graceful exit from a test run when Ctrl-C is pres…
Browse files Browse the repository at this point in the history
…sed. Thanks Randy Barlow.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12034 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
kmtracey committed Dec 31, 2009
1 parent c35868a commit 9a55432
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 15 deletions.
39 changes: 34 additions & 5 deletions django/test/simple.py
Original file line number Original file line Diff line number Diff line change
@@ -1,4 +1,7 @@
import sys
import signal
import unittest import unittest

from django.conf import settings from django.conf import settings
from django.db.models import get_app, get_apps from django.db.models import get_app, get_apps
from django.test import _doctest as doctest from django.test import _doctest as doctest
Expand All @@ -11,22 +14,48 @@
doctestOutputChecker = OutputChecker() doctestOutputChecker = OutputChecker()


class DjangoTestRunner(unittest.TextTestRunner): class DjangoTestRunner(unittest.TextTestRunner):

def __init__(self, verbosity=0, failfast=False, **kwargs): def __init__(self, verbosity=0, failfast=False, **kwargs):
super(DjangoTestRunner, self).__init__(verbosity=verbosity, **kwargs) super(DjangoTestRunner, self).__init__(verbosity=verbosity, **kwargs)
self.failfast = failfast self.failfast = failfast

self._keyboard_interrupt_intercepted = False

def run(self, *args, **kwargs):
"""
Runs the test suite after registering a custom signal handler
that triggers a graceful exit when Ctrl-C is pressed.
"""
self._default_keyboard_interrupt_handler = signal.signal(signal.SIGINT,
self._keyboard_interrupt_handler)
result = super(DjangoTestRunner, self).run(*args, **kwargs)
signal.signal(signal.SIGINT, self._default_keyboard_interrupt_handler)
return result

def _keyboard_interrupt_handler(self, signal_number, stack_frame):
"""
Handles Ctrl-C by setting a flag that will stop the test run when
the currently running test completes.
"""
self._keyboard_interrupt_intercepted = True
sys.stderr.write(" <Test run halted by Ctrl-C> ")
# Set the interrupt handler back to the default handler, so that
# another Ctrl-C press will trigger immediate exit.
signal.signal(signal.SIGINT, self._default_keyboard_interrupt_handler)

def _makeResult(self): def _makeResult(self):
result = super(DjangoTestRunner, self)._makeResult() result = super(DjangoTestRunner, self)._makeResult()
failfast = self.failfast failfast = self.failfast

def stoptest_override(func): def stoptest_override(func):
def stoptest(test): def stoptest(test):
if failfast and not result.wasSuccessful(): # If we were set to failfast and the unit test failed,
# or if the user has typed Ctrl-C, report and quit
if (failfast and not result.wasSuccessful()) or \
self._keyboard_interrupt_intercepted:
result.stop() result.stop()
func(test) func(test)
return stoptest return stoptest

setattr(result, 'stopTest', stoptest_override(result.stopTest)) setattr(result, 'stopTest', stoptest_override(result.stopTest))
return result return result


Expand Down
6 changes: 2 additions & 4 deletions docs/ref/django-admin.txt
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -812,12 +812,10 @@ test <app or test identifier>
Runs tests for all installed models. See :ref:`topics-testing` for more Runs tests for all installed models. See :ref:`topics-testing` for more
information. information.


--failfast
~~~~~~~~~~

.. versionadded:: 1.2 .. versionadded:: 1.2
.. django-admin-option:: --failfast


Use the ``--failfast`` option to stop running tests and report the failure Use the :djadminopt:`--failfast` option to stop running tests and report the failure
immediately after a test fails. immediately after a test fails.


testserver <fixture fixture ...> testserver <fixture fixture ...>
Expand Down
10 changes: 6 additions & 4 deletions docs/releases/1.2.txt
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -471,10 +471,12 @@ Models can now use a 64 bit :class:`~django.db.models.BigIntegerField` type.
Fast Failure for Tests Fast Failure for Tests
---------------------- ----------------------


The ``test`` subcommand of ``django-admin.py``, and the ``runtests.py`` script The :djadmin:`test` subcommand of ``django-admin.py``, and the ``runtests.py``
used to run Django's own test suite, support a new ``--failfast`` option. script used to run Django's own test suite, support a new ``--failfast`` option.
When specified, this option causes the test runner to exit after When specified, this option causes the test runner to exit after encountering
encountering a failure instead of continuing with the test run. a failure instead of continuing with the test run. In addition, the handling
of ``Ctrl-C`` during a test run has been improved to trigger a graceful exit
from the test run that reports details of the tests run before the interruption.


Improved localization Improved localization
--------------------- ---------------------
Expand Down
21 changes: 19 additions & 2 deletions docs/topics/testing.txt
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -242,8 +242,8 @@ in different circumstances.
Running tests Running tests
============= =============


Once you've written tests, run them using your project's ``manage.py`` Once you've written tests, run them using the :djadmin:`test` subcommand of
utility:: your project's ``manage.py`` utility::


$ ./manage.py test $ ./manage.py test


Expand Down Expand Up @@ -274,6 +274,23 @@ a test case, add the name of the test method to the label::


$ ./manage.py test animals.AnimalTestCase.testFluffyAnimals $ ./manage.py test animals.AnimalTestCase.testFluffyAnimals


.. versionadded:: 1.2
You can now trigger a graceful exit from a test run by pressing ``Ctrl-C``.

If you press ``Ctrl-C`` while the tests are running, the test runner will
wait fur the currently running test to complete and then exit gracefully.
During a graceful exit the test runner will output details of any test
failures, report on how many tests were run and how many errors and failures
were encountered, and destroy any test databases as usual. Thus pressing
``Ctrl-C`` can be very useful if you forget to pass the :djadminopt:`--failfast`
option, notice that some tests are unexpectedly failing, and want to get details
on the failures without waiting for the full test run to complete.

If you do not want to wait for the currently running test to finish, you
can press ``Ctrl-C`` a second time and the test run will halt immediately,
but not gracefully. No details of the tests run before the interruption will
be reported, and any test databases created by the run will not be destroyed.

The test database The test database
----------------- -----------------


Expand Down

0 comments on commit 9a55432

Please sign in to comment.