summaryrefslogtreecommitdiff
path: root/tests/servers
diff options
context:
space:
mode:
authorChris Jerdonek <chris.jerdonek@gmail.com>2021-02-14 22:10:59 -0800
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-04-12 10:23:56 +0200
commit823a9e6bac38d38f7b0347497b833eec732bd384 (patch)
treecbc27d15b08c2a457417570a85806bc4c7372259 /tests/servers
parent71a936f9d84864a1420ce3ecc3de4a4908dff1e8 (diff)
downloaddjango-823a9e6bac38d38f7b0347497b833eec732bd384.tar.gz
Fixed #32416 -- Made ThreadedWSGIServer close connections after each thread.
ThreadedWSGIServer is used by LiveServerTestCase.
Diffstat (limited to 'tests/servers')
-rw-r--r--tests/servers/tests.py69
1 files changed, 68 insertions, 1 deletions
diff --git a/tests/servers/tests.py b/tests/servers/tests.py
index 8b6e372419..c4b8298fd8 100644
--- a/tests/servers/tests.py
+++ b/tests/servers/tests.py
@@ -4,13 +4,15 @@ Tests for django.core.servers.
import errno
import os
import socket
+import threading
from http.client import HTTPConnection
from urllib.error import HTTPError
from urllib.parse import urlencode
from urllib.request import urlopen
from django.conf import settings
-from django.core.servers.basehttp import WSGIServer
+from django.core.servers.basehttp import ThreadedWSGIServer, WSGIServer
+from django.db import DEFAULT_DB_ALIAS, connections
from django.test import LiveServerTestCase, override_settings
from django.test.testcases import LiveServerThread, QuietWSGIRequestHandler
@@ -40,6 +42,71 @@ class LiveServerBase(LiveServerTestCase):
return urlopen(self.live_server_url + url)
+class CloseConnectionTestServer(ThreadedWSGIServer):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ # This event is set right after the first time a request closes its
+ # database connections.
+ self._connections_closed = threading.Event()
+
+ def _close_connections(self):
+ super()._close_connections()
+ self._connections_closed.set()
+
+
+class CloseConnectionTestLiveServerThread(LiveServerThread):
+
+ server_class = CloseConnectionTestServer
+
+ def _create_server(self, connections_override=None):
+ return super()._create_server(connections_override=self.connections_override)
+
+
+class LiveServerTestCloseConnectionTest(LiveServerBase):
+
+ server_thread_class = CloseConnectionTestLiveServerThread
+
+ @classmethod
+ def _make_connections_override(cls):
+ conn = connections[DEFAULT_DB_ALIAS]
+ cls.conn = conn
+ cls.old_conn_max_age = conn.settings_dict['CONN_MAX_AGE']
+ # Set the connection's CONN_MAX_AGE to None to simulate the
+ # CONN_MAX_AGE setting being set to None on the server. This prevents
+ # Django from closing the connection and allows testing that
+ # ThreadedWSGIServer closes connections.
+ conn.settings_dict['CONN_MAX_AGE'] = None
+ # Pass a database connection through to the server to check it is being
+ # closed by ThreadedWSGIServer.
+ return {DEFAULT_DB_ALIAS: conn}
+
+ @classmethod
+ def tearDownConnectionTest(cls):
+ cls.conn.settings_dict['CONN_MAX_AGE'] = cls.old_conn_max_age
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.tearDownConnectionTest()
+ super().tearDownClass()
+
+ def test_closes_connections(self):
+ # The server's request thread sets this event after closing
+ # its database connections.
+ closed_event = self.server_thread.httpd._connections_closed
+ conn = self.conn
+ # Open a connection to the database.
+ conn.connect()
+ self.assertIsNotNone(conn.connection)
+ with self.urlopen('/model_view/') as f:
+ # The server can access the database.
+ self.assertEqual(f.read().splitlines(), [b'jane', b'robert'])
+ # Wait for the server's request thread to close the connection.
+ # A timeout of 0.1 seconds should be more than enough. If the wait
+ # times out, the assertion after should fail.
+ closed_event.wait(timeout=0.1)
+ self.assertIsNone(conn.connection)
+
+
class FailingLiveServerThread(LiveServerThread):
def _create_server(self):
raise RuntimeError('Error creating server.')