diff --git a/django/test/testcases.py b/django/test/testcases.py index 8203a3837d..d70f57588f 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -1257,9 +1257,9 @@ 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 @@ -1279,8 +1279,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() @@ -1290,8 +1292,8 @@ class LiveServerThread(threading.Thread): finally: connections.close_all() - def _create_server(self, port): - return WSGIServer((self.host, port), QuietWSGIRequestHandler, allow_reuse_address=False) + def _create_server(self): + return WSGIServer((self.host, self.port), QuietWSGIRequestHandler, allow_reuse_address=False) def terminate(self): if hasattr(self, 'httpd'): @@ -1313,6 +1315,7 @@ class LiveServerTestCase(TransactionTestCase): other thread can see the changes. """ host = 'localhost' + port = 0 server_thread_class = LiveServerThread static_handler = _StaticFilesHandler @@ -1354,6 +1357,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 2cc51435ff..f23091f4fb 100644 --- a/docs/spelling_wordlist +++ b/docs/spelling_wordlist @@ -644,6 +644,7 @@ rc readded reallow reallowed +reallows rebase rebased rebasing diff --git a/tests/servers/tests.py b/tests/servers/tests.py index 03e05d0957..1224dddc22 100644 --- a/tests/servers/tests.py +++ b/tests/servers/tests.py @@ -136,3 +136,21 @@ class LiveServerPort(LiveServerBase): finally: 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()