diff options
author | Chris Jerdonek <chris.jerdonek@gmail.com> | 2021-02-14 22:10:59 -0800 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2021-04-12 10:23:56 +0200 |
commit | 823a9e6bac38d38f7b0347497b833eec732bd384 (patch) | |
tree | cbc27d15b08c2a457417570a85806bc4c7372259 /tests/servers | |
parent | 71a936f9d84864a1420ce3ecc3de4a4908dff1e8 (diff) | |
download | django-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.py | 69 |
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.') |