diff --git a/django/test/testcases.py b/django/test/testcases.py index 2752fc646b..cc1da67fb2 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -1201,9 +1201,9 @@ class _MediaFilesHandler(FSFilesHandler): class LiveServerThread(threading.Thread): """Thread for running a live http server while the tests are running.""" - def __init__(self, host, static_handler, connections_override=None): + def __init__(self, host, static_handler, connections_override=None, port=0): self.host = host - self.port = None + self.port = port self.is_ready = threading.Event() self.error = None self.static_handler = static_handler @@ -1223,8 +1223,10 @@ class LiveServerThread(threading.Thread): try: # Create the handler for serving static and media files handler = self.static_handler(_MediaFilesHandler(WSGIHandler())) - self.httpd = self._create_server(0) - self.port = self.httpd.server_address[1] + self.httpd = self._create_server() + # If binding to port zero, assign the port allocated by the OS. + if self.port == 0: + self.port = self.httpd.server_address[1] self.httpd.set_app(handler) self.is_ready.set() self.httpd.serve_forever() @@ -1234,8 +1236,8 @@ class LiveServerThread(threading.Thread): finally: connections.close_all() - def _create_server(self, port): - return ThreadedWSGIServer((self.host, port), QuietWSGIRequestHandler, allow_reuse_address=False) + def _create_server(self): + return ThreadedWSGIServer((self.host, self.port), QuietWSGIRequestHandler, allow_reuse_address=False) def terminate(self): if hasattr(self, 'httpd'): @@ -1257,6 +1259,7 @@ class LiveServerTestCase(TransactionTestCase): thread can see the changes. """ host = 'localhost' + port = 0 server_thread_class = LiveServerThread static_handler = _StaticFilesHandler @@ -1298,6 +1301,7 @@ class LiveServerTestCase(TransactionTestCase): cls.host, cls.static_handler, connections_override=connections_override, + port=cls.port, ) @classmethod diff --git a/docs/releases/1.11.2.txt b/docs/releases/1.11.2.txt index ab7d04959f..a01ecc3342 100644 --- a/docs/releases/1.11.2.txt +++ b/docs/releases/1.11.2.txt @@ -4,7 +4,14 @@ Django 1.11.2 release notes *Under development* -Django 1.11.2 fixes several bugs in 1.11.1. +Django 1.11.2 adds a minor feature and fixes several bugs in 1.11.1. + +Minor feature +============= + +The new ``LiveServerTestCase.port`` attribute reallows the use case of binding +to a specific port following the :ref:`bind to port zero +` change in Django 1.11. Bugfixes ======== diff --git a/docs/releases/1.11.txt b/docs/releases/1.11.txt index e43d53fdf8..05c925259f 100644 --- a/docs/releases/1.11.txt +++ b/docs/releases/1.11.txt @@ -533,6 +533,8 @@ to support it. Also, the minimum supported version of psycopg2 is increased from 2.4.5 to 2.5.4. +.. _liveservertestcase-port-zero-change: + ``LiveServerTestCase`` binds to port zero ----------------------------------------- @@ -542,6 +544,9 @@ to assign a free port. The ``DJANGO_LIVE_TEST_SERVER_ADDRESS`` environment variable is no longer used, and as it's also no longer used, the ``manage.py test --liveserver`` option is removed. +If you need to bind ``LiveServerTestCase`` to a specific port, use the ``port`` +attribute added in Django 1.11.2. + Protection against insecure redirects in :mod:`django.contrib.auth` and ``i18n`` views -------------------------------------------------------------------------------------- diff --git a/docs/spelling_wordlist b/docs/spelling_wordlist index de01fa314c..f4bd112e46 100644 --- a/docs/spelling_wordlist +++ b/docs/spelling_wordlist @@ -550,6 +550,7 @@ rc readded reallow reallowed +reallows rebase rebased rebasing diff --git a/tests/servers/tests.py b/tests/servers/tests.py index cb91131607..e7b263c088 100644 --- a/tests/servers/tests.py +++ b/tests/servers/tests.py @@ -147,6 +147,24 @@ class LiveServerPort(LiveServerBase): if hasattr(TestCase, 'server_thread'): TestCase.server_thread.terminate() + def test_specified_port_bind(self): + """LiveServerTestCase.port customizes the server's port.""" + TestCase = type(str('TestCase'), (LiveServerBase,), {}) + # Find an open port and tell TestCase to use it. + s = socket.socket() + s.bind(('', 0)) + TestCase.port = s.getsockname()[1] + s.close() + TestCase.setUpClass() + try: + self.assertEqual( + TestCase.port, TestCase.server_thread.port, + 'Did not use specified port for LiveServerTestCase thread: %s' % TestCase.port + ) + finally: + if hasattr(TestCase, 'server_thread'): + TestCase.server_thread.terminate() + class LiverServerThreadedTests(LiveServerBase): """If LiverServerTestCase isn't threaded, these tests will hang."""