Code

Ticket #8138: django_transaction_tests.diff

File django_transaction_tests.diff, 6.9 KB (added by mremolt, 6 years ago)

Now doesn't touch _doctests.py

Line 
1Index: django/test/testcases.py
2===================================================================
3--- django/test/testcases.py    (Revision 8225)
4+++ django/test/testcases.py    (Arbeitskopie)
5@@ -55,7 +55,7 @@
6         """Tries to do a 'xml-comparision' of want and got.  Plain string
7         comparision doesn't always work because, for example, attribute
8         ordering should not be important.
9-       
10+
11         Based on http://codespeak.net/svn/lxml/trunk/src/lxml/doctestcompare.py
12         """
13         _norm_whitespace_re = re.compile(r'[ \t\n][ \t\n]+')
14@@ -102,7 +102,7 @@
15             wrapper = '<root>%s</root>'
16             want = wrapper % want
17             got = wrapper % got
18-           
19+
20         # Parse the want and got strings, and compare the parsings.
21         try:
22             want_root = parseString(want).firstChild
23@@ -169,12 +169,23 @@
24         # side effects on other tests.
25         transaction.rollback_unless_managed()
26 
27-class TestCase(unittest.TestCase):
28+    def run(self, test, compileflags=None, out=None, clear_globs=True):
29+        """
30+        Wraps the parent run() and encloses it in a transaction.
31+        """
32+        transaction.enter_transaction_management()
33+        transaction.managed(True)
34+        result = doctest.DocTestRunner.run(self, test, compileflags, out, clear_globs)
35+        transaction.rollback()
36+        transaction.leave_transaction_management()
37+        return result
38+
39+class TransactionTestCase(unittest.TestCase):
40     def _pre_setup(self):
41         """Performs any pre-test setup. This includes:
42 
43             * Flushing the database.
44-            * If the Test Case class has a 'fixtures' member, installing the
45+            * If the Test Case class has a 'fixtures' member, installing the
46               named fixtures.
47             * If the Test Case class has a 'urls' member, replace the
48               ROOT_URLCONF with it.
49@@ -206,7 +217,7 @@
50             import sys
51             result.addError(self, sys.exc_info())
52             return
53-        super(TestCase, self).__call__(result)
54+        super(TransactionTestCase, self).__call__(result)
55         try:
56             self._post_teardown()
57         except (KeyboardInterrupt, SystemExit):
58@@ -354,3 +365,32 @@
59         self.failIf(template_name in template_names,
60             (u"Template '%s' was used unexpectedly in rendering the"
61              u" response") % template_name)
62+
63+
64+class TestCase(TransactionTestCase):
65+    """
66+    Does basically the same as TransactionTestCase, but surrounds every test
67+    with a transaction. You have to use TransactionTestCase, if you need
68+    transaction management inside a test.
69+    """
70+    def _pre_setup(self):
71+        transaction.enter_transaction_management()
72+        transaction.managed(True)
73+
74+        if hasattr(self, 'fixtures'):
75+            call_command('loaddata', *self.fixtures, **{
76+                                                        'verbosity': 0,
77+                                                        'no_commit': True
78+                                                        })
79+        if hasattr(self, 'urls'):
80+            self._old_root_urlconf = settings.ROOT_URLCONF
81+            settings.ROOT_URLCONF = self.urls
82+            clear_url_caches()
83+        mail.outbox = []
84+
85+    def _post_teardown(self):
86+        if hasattr(self, '_old_root_urlconf'):
87+            settings.ROOT_URLCONF = self._old_root_urlconf
88+            clear_url_caches()
89+        transaction.rollback()
90+        transaction.leave_transaction_management()
91\ No newline at end of file
92Index: django/core/management/commands/loaddata.py
93===================================================================
94--- django/core/management/commands/loaddata.py (Revision 8225)
95+++ django/core/management/commands/loaddata.py (Arbeitskopie)
96@@ -14,6 +14,8 @@
97         make_option('--verbosity', action='store', dest='verbosity', default='1',
98             type='choice', choices=['0', '1', '2'],
99             help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
100+        make_option('--no-commit', action='store_false', dest='no_commit', default=False,
101+            help='Tells Django to not commit the loaded fixtures to the DB.'),
102     )
103     help = 'Installs the named fixture(s) in the database.'
104     args = "fixture [fixture ...]"
105@@ -28,6 +30,7 @@
106 
107         verbosity = int(options.get('verbosity', 1))
108         show_traceback = options.get('traceback', False)
109+        no_commit = options.get('no_commit', False)
110 
111         # Keep a count of the installed objects and fixtures
112         fixture_count = 0
113@@ -44,9 +47,10 @@
114 
115         # Start transaction management. All fixtures are installed in a
116         # single transaction to ensure that all references are resolved.
117-        transaction.commit_unless_managed()
118-        transaction.enter_transaction_management()
119-        transaction.managed(True)
120+        if not no_commit:
121+            transaction.commit_unless_managed()
122+            transaction.enter_transaction_management()
123+            transaction.managed(True)
124 
125         app_fixtures = [os.path.join(os.path.dirname(app.__file__), 'fixtures') for app in get_apps()]
126         for fixture_label in fixture_labels:
127@@ -133,7 +137,7 @@
128                                 (format, fixture_name, humanize(fixture_dir))
129 
130 
131-        # If any of the fixtures we loaded contain 0 objects, assume that an
132+        # If any of the fixtures we loaded contain 0 objects, assume that an
133         # error was encountered during fixture loading.
134         if 0 in objects_per_fixture:
135             sys.stderr.write(
136@@ -142,8 +146,8 @@
137             transaction.rollback()
138             transaction.leave_transaction_management()
139             return
140-           
141-        # If we found even one object in a fixture, we need to reset the
142+
143+        # If we found even one object in a fixture, we need to reset the
144         # database sequences.
145         if object_count > 0:
146             sequence_sql = connection.ops.sequence_reset_sql(self.style, models)
147@@ -152,19 +156,21 @@
148                     print "Resetting sequences"
149                 for line in sequence_sql:
150                     cursor.execute(line)
151-           
152-        transaction.commit()
153-        transaction.leave_transaction_management()
154 
155+        if not no_commit:
156+            transaction.commit()
157+            transaction.leave_transaction_management()
158+
159         if object_count == 0:
160             if verbosity > 1:
161                 print "No fixtures found."
162         else:
163             if verbosity > 0:
164                 print "Installed %d object(s) from %d fixture(s)" % (object_count, fixture_count)
165-               
166+
167         # Close the DB connection. This is required as a workaround for an
168         # edge case in MySQL: if the same connection is used to
169         # create tables, load data, and query, the query can return
170         # incorrect results. See Django #7572, MySQL #37735.
171-        connection.close()
172+        if not no_commit:
173+            connection.close()