1
0
mirror of https://github.com/django/django.git synced 2025-10-24 14:16:09 +00:00

Fixed #19707 -- Reset transaction state after requests

This commit is contained in:
Anssi Kääriäinen
2013-02-05 23:52:29 +02:00
parent 0e18fb04ba
commit a4e97cf315
8 changed files with 127 additions and 6 deletions

View File

@@ -9,9 +9,9 @@ import warnings
from django.conf import settings
from django.core import mail
from django.db import transaction
from django.http import HttpRequest
from django.http import HttpResponse, StreamingHttpResponse
from django.db import (transaction, connections, DEFAULT_DB_ALIAS,
IntegrityError)
from django.http import HttpRequest, HttpResponse, StreamingHttpResponse
from django.middleware.clickjacking import XFrameOptionsMiddleware
from django.middleware.common import CommonMiddleware, BrokenLinkEmailsMiddleware
from django.middleware.http import ConditionalGetMiddleware
@@ -710,3 +710,22 @@ class TransactionMiddlewareTest(TransactionTestCase):
TransactionMiddleware().process_exception(self.request, None)
self.assertEqual(Band.objects.count(), 0)
self.assertFalse(transaction.is_dirty())
def test_failing_commit(self):
# It is possible that connection.commit() fails. Check that
# TransactionMiddleware handles such cases correctly.
try:
def raise_exception():
raise IntegrityError()
connections[DEFAULT_DB_ALIAS].commit = raise_exception
transaction.enter_transaction_management()
transaction.managed(True)
Band.objects.create(name='The Beatles')
self.assertTrue(transaction.is_dirty())
with self.assertRaises(IntegrityError):
TransactionMiddleware().process_response(self.request, None)
self.assertEqual(Band.objects.count(), 0)
self.assertFalse(transaction.is_dirty())
self.assertFalse(transaction.is_managed())
finally:
del connections[DEFAULT_DB_ALIAS].commit

View File

@@ -6,9 +6,12 @@ import warnings
from datetime import datetime, timedelta
from io import BytesIO
from django.db import connection, connections, DEFAULT_DB_ALIAS
from django.core import signals
from django.core.exceptions import SuspiciousOperation
from django.core.handlers.wsgi import WSGIRequest, LimitedStream
from django.http import HttpRequest, HttpResponse, parse_cookie, build_request_repr, UnreadablePostError
from django.test import TransactionTestCase
from django.test.client import FakePayload
from django.test.utils import override_settings, str_prefix
from django.utils import six
@@ -524,3 +527,42 @@ class RequestsTests(unittest.TestCase):
with self.assertRaises(UnreadablePostError):
request.body
class TransactionRequestTests(TransactionTestCase):
def test_request_finished_db_state(self):
# The GET below will not succeed, but it will give a response with
# defined ._handler_class. That is needed for sending the
# request_finished signal.
response = self.client.get('/')
# Make sure there is an open connection
connection.cursor()
connection.enter_transaction_management()
connection.managed(True)
signals.request_finished.send(sender=response._handler_class)
# In-memory sqlite doesn't actually close connections.
if connection.vendor != 'sqlite':
self.assertIs(connection.connection, None)
self.assertEqual(len(connection.transaction_state), 0)
@unittest.skipIf(connection.vendor == 'sqlite',
'This test will close the connection, in-memory '
'sqlite connections must not be closed.')
def test_request_finished_failed_connection(self):
# See comments in test_request_finished_db_state() for the self.client
# usage.
response = self.client.get('/')
conn = connections[DEFAULT_DB_ALIAS]
conn.enter_transaction_management()
conn.managed(True)
conn.set_dirty()
# Test that the rollback doesn't succeed (for example network failure
# could cause this).
def fail_horribly():
raise Exception("Horrible failure!")
conn._rollback = fail_horribly
signals.request_finished.send(sender=response._handler_class)
# As even rollback wasn't possible the connection wrapper itself was
# abandoned. Accessing the connections[alias] will create a new
# connection wrapper, whch must be different than the original one.
self.assertIsNot(conn, connections[DEFAULT_DB_ALIAS])
self.assertEqual(len(connection.transaction_state), 0)