PageRenderTime 40ms CodeModel.GetById 26ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/modeltests/transactions/tests.py

https://code.google.com/p/mango-py/
Python | 185 lines | 153 code | 14 blank | 18 comment | 1 complexity | a5c8edcf9f1373675f6b75184c281079 MD5 | raw file
  1import sys
  2
  3from django.db import connection, transaction, IntegrityError, DEFAULT_DB_ALIAS
  4from django.conf import settings
  5from django.test import TransactionTestCase, skipUnlessDBFeature
  6
  7from models import Reporter
  8
  9
 10if sys.version_info >= (2, 5):
 11    from tests_25 import TransactionContextManagerTests
 12
 13
 14class TransactionTests(TransactionTestCase):
 15    def create_a_reporter_then_fail(self, first, last):
 16        a = Reporter(first_name=first, last_name=last)
 17        a.save()
 18        raise Exception("I meant to do that")
 19
 20    def remove_a_reporter(self, first_name):
 21        r = Reporter.objects.get(first_name="Alice")
 22        r.delete()
 23
 24    def manually_managed(self):
 25        r = Reporter(first_name="Dirk", last_name="Gently")
 26        r.save()
 27        transaction.commit()
 28
 29    def manually_managed_mistake(self):
 30        r = Reporter(first_name="Edward", last_name="Woodward")
 31        r.save()
 32        # Oops, I forgot to commit/rollback!
 33
 34    @skipUnlessDBFeature('supports_transactions')
 35    def test_autocommit(self):
 36        """
 37        The default behavior is to autocommit after each save() action.
 38        """
 39        self.assertRaises(Exception,
 40            self.create_a_reporter_then_fail,
 41            "Alice", "Smith"
 42        )
 43
 44        # The object created before the exception still exists
 45        self.assertEqual(Reporter.objects.count(), 1)
 46
 47    @skipUnlessDBFeature('supports_transactions')
 48    def test_autocommit_decorator(self):
 49        """
 50        The autocommit decorator works exactly the same as the default behavior.
 51        """
 52        autocomitted_create_then_fail = transaction.autocommit(
 53            self.create_a_reporter_then_fail
 54        )
 55        self.assertRaises(Exception,
 56            autocomitted_create_then_fail,
 57            "Alice", "Smith"
 58        )
 59        # Again, the object created before the exception still exists
 60        self.assertEqual(Reporter.objects.count(), 1)
 61
 62    @skipUnlessDBFeature('supports_transactions')
 63    def test_autocommit_decorator_with_using(self):
 64        """
 65        The autocommit decorator also works with a using argument.
 66        """
 67        autocomitted_create_then_fail = transaction.autocommit(using='default')(
 68            self.create_a_reporter_then_fail
 69        )
 70        self.assertRaises(Exception,
 71            autocomitted_create_then_fail,
 72            "Alice", "Smith"
 73        )
 74        # Again, the object created before the exception still exists
 75        self.assertEqual(Reporter.objects.count(), 1)
 76
 77    @skipUnlessDBFeature('supports_transactions')
 78    def test_commit_on_success(self):
 79        """
 80        With the commit_on_success decorator, the transaction is only committed
 81        if the function doesn't throw an exception.
 82        """
 83        committed_on_success = transaction.commit_on_success(
 84            self.create_a_reporter_then_fail)
 85        self.assertRaises(Exception, committed_on_success, "Dirk", "Gently")
 86        # This time the object never got saved
 87        self.assertEqual(Reporter.objects.count(), 0)
 88
 89    @skipUnlessDBFeature('supports_transactions')
 90    def test_commit_on_success_with_using(self):
 91        """
 92        The commit_on_success decorator also works with a using argument.
 93        """
 94        using_committed_on_success = transaction.commit_on_success(using='default')(
 95            self.create_a_reporter_then_fail
 96        )
 97        self.assertRaises(Exception,
 98            using_committed_on_success,
 99            "Dirk", "Gently"
100        )
101        # This time the object never got saved
102        self.assertEqual(Reporter.objects.count(), 0)
103
104    @skipUnlessDBFeature('supports_transactions')
105    def test_commit_on_success_succeed(self):
106        """
107        If there aren't any exceptions, the data will get saved.
108        """
109        Reporter.objects.create(first_name="Alice", last_name="Smith")
110        remove_comitted_on_success = transaction.commit_on_success(
111            self.remove_a_reporter
112        )
113        remove_comitted_on_success("Alice")
114        self.assertEqual(list(Reporter.objects.all()), [])
115
116    @skipUnlessDBFeature('supports_transactions')
117    def test_commit_on_success_exit(self):
118        @transaction.autocommit()
119        def gen_reporter():
120            @transaction.commit_on_success
121            def create_reporter():
122                Reporter.objects.create(first_name="Bobby", last_name="Tables")
123
124            create_reporter()
125            # Much more formal
126            r = Reporter.objects.get()
127            r.first_name = "Robert"
128            r.save()
129
130        gen_reporter()
131        r = Reporter.objects.get()
132        self.assertEqual(r.first_name, "Robert")
133
134
135    @skipUnlessDBFeature('supports_transactions')
136    def test_manually_managed(self):
137        """
138        You can manually manage transactions if you really want to, but you
139        have to remember to commit/rollback.
140        """
141        manually_managed = transaction.commit_manually(self.manually_managed)
142        manually_managed()
143        self.assertEqual(Reporter.objects.count(), 1)
144
145    @skipUnlessDBFeature('supports_transactions')
146    def test_manually_managed_mistake(self):
147        """
148        If you forget, you'll get bad errors.
149        """
150        manually_managed_mistake = transaction.commit_manually(
151            self.manually_managed_mistake
152        )
153        self.assertRaises(transaction.TransactionManagementError,
154            manually_managed_mistake)
155
156    @skipUnlessDBFeature('supports_transactions')
157    def test_manually_managed_with_using(self):
158        """
159        The commit_manually function also works with a using argument.
160        """
161        using_manually_managed_mistake = transaction.commit_manually(using='default')(
162            self.manually_managed_mistake
163        )
164        self.assertRaises(transaction.TransactionManagementError,
165            using_manually_managed_mistake
166        )
167
168
169class TransactionRollbackTests(TransactionTestCase):
170    def execute_bad_sql(self):
171        cursor = connection.cursor()
172        cursor.execute("INSERT INTO transactions_reporter (first_name, last_name) VALUES ('Douglas', 'Adams');")
173        transaction.set_dirty()
174
175    @skipUnlessDBFeature('requires_rollback_on_dirty_transaction')
176    def test_bad_sql(self):
177        """
178        Regression for #11900: If a function wrapped by commit_on_success
179        writes a transaction that can't be committed, that transaction should
180        be rolled back. The bug is only visible using the psycopg2 backend,
181        though the fix is generally a good idea.
182        """
183        execute_bad_sql = transaction.commit_on_success(self.execute_bad_sql)
184        self.assertRaises(IntegrityError, execute_bad_sql)
185        transaction.rollback()