#20142: Transaction methods are not re-enabled when fixture loading fails
-----------------------------------+--------------------
     Reporter:  mlarente           |      Owner:  nobody
         Type:  Bug                |     Status:  new
    Component:  Testing framework  |    Version:  1.5
     Severity:  Normal             |   Keywords:
 Triage Stage:  Unreviewed         |  Has patch:  0
Easy pickings:  0                  |      UI/UX:  0
-----------------------------------+--------------------
 When a test case fails to properly load a fixture (integrity error or some
 other reason), the transaction methods (which are disabled before the test
 is run) are not re-enabled before the next test is run. This can cause
 other tests (especially transaction test cases) to fail.

 I've created a simple django application to reproduce this. You just have
 to add the application to a Django project, and then run:
 {{{
 manage.py test myapp.Before myapp.Broken myapp.After
 }}}

 This command is used to enforce the test order that shows the bug. The
 `Before` and `After` tests are actually the same test that checks if
 transaction methods are enabled (as they should be for a transaction test
 case). The first one passes and the other one fails:
 {{{
 import django.db.transaction
 from django.test.testcases import TestCase
 from django.test.testcases import TransactionTestCase

 ORIGINAL = django.db.transaction.enter_transaction_management


 class TransactionCheckMixin(object):
     def test_transaction_method(self):
         self.assertEqual(ORIGINAL,
 django.db.transaction.enter_transaction_management)


 class Before(TransactionCheckMixin, TransactionTestCase):
     pass


 class Broken(TestCase):
     fixtures = ['broken_fixture']

     def test_something(self):
         self.assertTrue(True)  # will not happen


 class After(TransactionCheckMixin, TransactionTestCase):
     pass
 }}}

 The problem lies in the `_fixture_setup` method of the `TestCase` class:
 {{{
 class TestCase(TransactionTestCase):
     """
     Does basically the same as TransactionTestCase, but surrounds every
 test
     with a transaction, monkey-patches the real transaction management
 routines
     to do nothing, and rollsback the test transaction at the end of the
 test.
     You have to use TransactionTestCase, if you need transaction
 management
     inside a test.
     """

     def _fixture_setup(self):
         if not connections_support_transactions():
             return super(TestCase, self)._fixture_setup()

         assert not self.reset_sequences, 'reset_sequences cannot be used
 on TestCase instances'

         for db_name in self._databases_names():
             transaction.enter_transaction_management(using=db_name)
             transaction.managed(True, using=db_name)
         disable_transaction_methods()

         from django.contrib.sites.models import Site
         Site.objects.clear_cache()

         for db in self._databases_names(include_mirrors=False):
             if hasattr(self, 'fixtures'):
                 call_command('loaddata', *self.fixtures,
                              **{
                                 'verbosity': 0,
                                 'commit': False,
                                 'database': db,
                                 'skip_validation': True,
                              })
 }}}
 It should handle errors and call the `_fixture_teardown` method if there's
 an error.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/20142>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to