diff --git a/django/core/servers/basehttp.py b/django/core/servers/basehttp.py index 4e2f8dd8637..b9184ca20d4 100644 --- a/django/core/servers/basehttp.py +++ b/django/core/servers/basehttp.py @@ -70,6 +70,7 @@ class WSGIServer(simple_server.WSGIServer, object): def __init__(self, *args, **kwargs): if kwargs.pop('ipv6', False): self.address_family = socket.AF_INET6 + self.allow_reuse_address = kwargs.pop('allow_reuse_address', True) super(WSGIServer, self).__init__(*args, **kwargs) def server_bind(self): diff --git a/django/test/testcases.py b/django/test/testcases.py index 2acacd5a91b..4e4ada9c646 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -1252,7 +1252,7 @@ class LiveServerThread(threading.Thread): self.is_ready.set() def _create_server(self, port): - return WSGIServer((self.host, port), QuietWSGIRequestHandler) + return WSGIServer((self.host, port), QuietWSGIRequestHandler, allow_reuse_address=False) def terminate(self): if hasattr(self, 'httpd'): diff --git a/tests/servers/tests.py b/tests/servers/tests.py index dbb298e0036..18102ff5099 100644 --- a/tests/servers/tests.py +++ b/tests/servers/tests.py @@ -5,6 +5,7 @@ Tests for django.core.servers. from __future__ import unicode_literals import contextlib +import errno import os import socket @@ -174,3 +175,31 @@ class LiveServerDatabase(LiveServerBase): ['jane', 'robert', 'emily'], lambda b: b.name ) + + +class LiveServerPort(LiveServerBase): + + def test_port_bind(self): + """ + Each LiveServerTestCase binds to a unique port or fails to start a + server thread when run concurrently (#26011). + """ + TestCase = type(str("TestCase"), (LiveServerBase,), {}) + try: + TestCase.setUpClass() + except socket.error as e: + if e.ernrno == errno.EADDRINUSE: + # We're out of ports, LiveServerTestCase correctly fails with + # a socket error. + return + # Unexpected error. + raise + try: + # We've acquired a port, ensure our server threads acquired + # different addresses. + self.assertNotEqual( + self.live_server_url, TestCase.live_server_url, + "Acquired duplicate server addresses for server threads: %s" % self.live_server_url + ) + finally: + TestCase.tearDownClass()