mirror of https://github.com/django/django.git
Fixed #29062 -- Prevented possibility of database lock when using LiveServerTestCase with in-memory SQLite database.
Thanks Chris Jerdonek for the implementation idea.
This commit is contained in:
parent
1297c0d0d7
commit
855f5a36e7
|
@ -111,6 +111,16 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
skips.update(
|
||||||
|
{
|
||||||
|
"Only connections to in-memory SQLite databases are passed to the "
|
||||||
|
"server thread.": {
|
||||||
|
"servers.tests.LiveServerInMemoryDatabaseLockTest."
|
||||||
|
"test_in_memory_database_lock",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
return skips
|
return skips
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
|
|
|
@ -1778,7 +1778,9 @@ class LiveServerThread(threading.Thread):
|
||||||
try:
|
try:
|
||||||
# Create the handler for serving static and media files
|
# Create the handler for serving static and media files
|
||||||
handler = self.static_handler(_MediaFilesHandler(WSGIHandler()))
|
handler = self.static_handler(_MediaFilesHandler(WSGIHandler()))
|
||||||
self.httpd = self._create_server()
|
self.httpd = self._create_server(
|
||||||
|
connections_override=self.connections_override,
|
||||||
|
)
|
||||||
# If binding to port zero, assign the port allocated by the OS.
|
# If binding to port zero, assign the port allocated by the OS.
|
||||||
if self.port == 0:
|
if self.port == 0:
|
||||||
self.port = self.httpd.server_address[1]
|
self.port = self.httpd.server_address[1]
|
||||||
|
|
|
@ -5,6 +5,7 @@ import errno
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
import threading
|
import threading
|
||||||
|
import unittest
|
||||||
from http.client import HTTPConnection
|
from http.client import HTTPConnection
|
||||||
from urllib.error import HTTPError
|
from urllib.error import HTTPError
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
@ -12,7 +13,7 @@ from urllib.request import urlopen
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.servers.basehttp import ThreadedWSGIServer, WSGIServer
|
from django.core.servers.basehttp import ThreadedWSGIServer, WSGIServer
|
||||||
from django.db import DEFAULT_DB_ALIAS, connections
|
from django.db import DEFAULT_DB_ALIAS, connection, connections
|
||||||
from django.test import LiveServerTestCase, override_settings
|
from django.test import LiveServerTestCase, override_settings
|
||||||
from django.test.testcases import LiveServerThread, QuietWSGIRequestHandler
|
from django.test.testcases import LiveServerThread, QuietWSGIRequestHandler
|
||||||
|
|
||||||
|
@ -107,8 +108,33 @@ class LiveServerTestCloseConnectionTest(LiveServerBase):
|
||||||
self.assertIsNone(conn.connection)
|
self.assertIsNone(conn.connection)
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipUnless(connection.vendor == "sqlite", "SQLite specific test.")
|
||||||
|
class LiveServerInMemoryDatabaseLockTest(LiveServerBase):
|
||||||
|
def test_in_memory_database_lock(self):
|
||||||
|
"""
|
||||||
|
With a threaded LiveServer and an in-memory database, an error can
|
||||||
|
occur when 2 requests reach the server and try to lock the database
|
||||||
|
at the same time, if the requests do not share the same database
|
||||||
|
connection.
|
||||||
|
"""
|
||||||
|
conn = self.server_thread.connections_override[DEFAULT_DB_ALIAS]
|
||||||
|
# Open a connection to the database.
|
||||||
|
conn.connect()
|
||||||
|
# Create a transaction to lock the database.
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("BEGIN IMMEDIATE TRANSACTION")
|
||||||
|
try:
|
||||||
|
with self.urlopen("/create_model_instance/") as f:
|
||||||
|
self.assertEqual(f.status, 200)
|
||||||
|
except HTTPError:
|
||||||
|
self.fail("Unexpected error due to a database lock.")
|
||||||
|
finally:
|
||||||
|
# Release the transaction.
|
||||||
|
cursor.execute("ROLLBACK")
|
||||||
|
|
||||||
|
|
||||||
class FailingLiveServerThread(LiveServerThread):
|
class FailingLiveServerThread(LiveServerThread):
|
||||||
def _create_server(self):
|
def _create_server(self, connections_override=None):
|
||||||
raise RuntimeError("Error creating server.")
|
raise RuntimeError("Error creating server.")
|
||||||
|
|
||||||
|
|
||||||
|
@ -150,7 +176,7 @@ class LiveServerAddress(LiveServerBase):
|
||||||
|
|
||||||
|
|
||||||
class LiveServerSingleThread(LiveServerThread):
|
class LiveServerSingleThread(LiveServerThread):
|
||||||
def _create_server(self):
|
def _create_server(self, connections_override=None):
|
||||||
return WSGIServer(
|
return WSGIServer(
|
||||||
(self.host, self.port), QuietWSGIRequestHandler, allow_reuse_address=False
|
(self.host, self.port), QuietWSGIRequestHandler, allow_reuse_address=False
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue