Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #12364: Added graceful exit from a test run when Ctrl-C is pres…

…sed. Thanks Randy Barlow.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12034 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 9a554322139e5c65b4b40bc538ca263a922c824f 1 parent c35868a
Karen Tracey authored December 31, 2009
39  django/test/simple.py
... ...
@@ -1,4 +1,7 @@
  1
+import sys
  2
+import signal
1 3
 import unittest
  4
+
2 5
 from django.conf import settings
3 6
 from django.db.models import get_app, get_apps
4 7
 from django.test import _doctest as doctest
@@ -11,22 +14,48 @@
11 14
 doctestOutputChecker = OutputChecker()
12 15
 
13 16
 class DjangoTestRunner(unittest.TextTestRunner):
14  
-    
  17
+
15 18
     def __init__(self, verbosity=0, failfast=False, **kwargs):
16 19
         super(DjangoTestRunner, self).__init__(verbosity=verbosity, **kwargs)
17 20
         self.failfast = failfast
18  
-        
  21
+        self._keyboard_interrupt_intercepted = False
  22
+
  23
+    def run(self, *args, **kwargs):
  24
+        """
  25
+        Runs the test suite after registering a custom signal handler
  26
+        that triggers a graceful exit when Ctrl-C is pressed.
  27
+        """
  28
+        self._default_keyboard_interrupt_handler = signal.signal(signal.SIGINT,
  29
+            self._keyboard_interrupt_handler)
  30
+        result = super(DjangoTestRunner, self).run(*args, **kwargs)
  31
+        signal.signal(signal.SIGINT, self._default_keyboard_interrupt_handler)
  32
+        return result
  33
+
  34
+    def _keyboard_interrupt_handler(self, signal_number, stack_frame):
  35
+        """
  36
+        Handles Ctrl-C by setting a flag that will stop the test run when
  37
+        the currently running test completes.
  38
+        """
  39
+        self._keyboard_interrupt_intercepted = True
  40
+        sys.stderr.write(" <Test run halted by Ctrl-C> ")
  41
+        # Set the interrupt handler back to the default handler, so that 
  42
+        # another Ctrl-C press will trigger immediate exit.
  43
+        signal.signal(signal.SIGINT, self._default_keyboard_interrupt_handler)
  44
+
19 45
     def _makeResult(self):
20 46
         result = super(DjangoTestRunner, self)._makeResult()
21 47
         failfast = self.failfast
22  
-        
  48
+
23 49
         def stoptest_override(func):
24 50
             def stoptest(test):
25  
-                if failfast and not result.wasSuccessful():
  51
+                # If we were set to failfast and the unit test failed,
  52
+                # or if the user has typed Ctrl-C, report and quit
  53
+                if (failfast and not result.wasSuccessful()) or \
  54
+                    self._keyboard_interrupt_intercepted:
26 55
                     result.stop()
27 56
                 func(test)
28 57
             return stoptest
29  
-        
  58
+
30 59
         setattr(result, 'stopTest', stoptest_override(result.stopTest))
31 60
         return result
32 61
 
6  docs/ref/django-admin.txt
@@ -812,12 +812,10 @@ test <app or test identifier>
812 812
 Runs tests for all installed models. See :ref:`topics-testing` for more
813 813
 information.
814 814
 
815  
---failfast
816  
-~~~~~~~~~~
817  
-
818 815
 .. versionadded:: 1.2
  816
+.. django-admin-option:: --failfast
819 817
 
820  
-Use the ``--failfast`` option to stop running tests and report the failure
  818
+Use the :djadminopt:`--failfast` option to stop running tests and report the failure
821 819
 immediately after a test fails.
822 820
 
823 821
 testserver <fixture fixture ...>
10  docs/releases/1.2.txt
@@ -471,10 +471,12 @@ Models can now use a 64 bit :class:`~django.db.models.BigIntegerField` type.
471 471
 Fast Failure for Tests
472 472
 ----------------------
473 473
 
474  
-The ``test`` subcommand of ``django-admin.py``, and the ``runtests.py`` script
475  
-used to run Django's own test suite, support a new ``--failfast`` option.
476  
-When specified, this option causes the test runner to exit after
477  
-encountering a failure instead of continuing with the test run.
  474
+The :djadmin:`test` subcommand of ``django-admin.py``, and the ``runtests.py`` 
  475
+script used to run Django's own test suite, support a new ``--failfast`` option.
  476
+When specified, this option causes the test runner to exit after encountering 
  477
+a failure instead of continuing with the test run.  In addition, the handling 
  478
+of ``Ctrl-C`` during a test run has been improved to trigger a graceful exit 
  479
+from the test run that reports details of the tests run before the interruption.        
478 480
 
479 481
 Improved localization
480 482
 ---------------------
21  docs/topics/testing.txt
@@ -242,8 +242,8 @@ in different circumstances.
242 242
 Running tests
243 243
 =============
244 244
 
245  
-Once you've written tests, run them using your project's ``manage.py``
246  
-utility::
  245
+Once you've written tests, run them using the :djadmin:`test` subcommand of
  246
+your project's ``manage.py`` utility::
247 247
 
248 248
     $ ./manage.py test
249 249
 
@@ -274,6 +274,23 @@ a test case, add the name of the test method to the label::
274 274
 
275 275
     $ ./manage.py test animals.AnimalTestCase.testFluffyAnimals
276 276
 
  277
+.. versionadded:: 1.2
  278
+   You can now trigger a graceful exit from a test run by pressing ``Ctrl-C``. 
  279
+
  280
+If you press ``Ctrl-C`` while the tests are running, the test runner will 
  281
+wait fur the currently running test to complete and then exit gracefully.
  282
+During a graceful exit the test runner will output details of any test 
  283
+failures, report on how many tests were run and how many errors and failures
  284
+were encountered, and destroy any test databases as usual. Thus pressing 
  285
+``Ctrl-C`` can be very useful if you forget to pass the :djadminopt:`--failfast`
  286
+option, notice that some tests are unexpectedly failing, and want to get details 
  287
+on the failures without waiting for the full test run to complete.
  288
+
  289
+If you do not want to wait for the currently running test to finish, you
  290
+can press ``Ctrl-C`` a second time and the test run will halt immediately,
  291
+but not gracefully. No details of the tests run before the interruption will
  292
+be reported, and any test databases created by the run will not be destroyed.
  293
+
277 294
 The test database
278 295
 -----------------
279 296
 

0 notes on commit 9a55432

Please sign in to comment.
Something went wrong with that request. Please try again.