Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django's LiveServerTestCase Always Fails Due to Conflicting Address... Despite Address Appearing Free

Tags:

python

django

I'm currently working on cleaning my Django functional tests to use the LiveServerTestCase rather than bouncing selenium based tests off an instance of the development environment running in the background, and I've hit a wall. Every time I try to run a LiveServerTestCase test, I get the following error:

======================================================================
ERROR: setUpClass (fun_tests.tests.backend.TestCmsLogin)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/user/Documents/env/local/lib/python2.7/site-packages/django/test/testcases.py", line 1187, in setUpClass
    raise cls.server_thread.error
error: [Errno 98] Address already in use

Super fun, considering sudo netstat -netp | grep 8081 yields nothing. Some background: I'm using Django 1.6, and I was using nose, django-nose, nose-exclude, but I've effectively chopped them out to help diagnose the issue. The code I'm using is abysmally simple:

from django.test import LiveServerTestCase
class TestCmsLogin(LiveServerTestCase):
    def test_a_test_itself(self):
        self.assertTrue(True)

I can't find any prior art on the subject, and Djangoproject's bug tracker is clean. What am I missing?

Edit: This morning the issue is irreproducible, whatever was flagging port 8081 as open is no longer causing issues.

edit2: Mistyped 8081 as 8082 in my writeup, fixed (and checked to make sure I had it right at the time).

like image 991
TimClifford Avatar asked Dec 16 '13 20:12

TimClifford


5 Answers

You can set (in settings.py) the environment variable DJANGO_LIVE_TEST_SERVER_ADDRESS to include multiple ranges of ports that will be attempted:

os.environ['DJANGO_LIVE_TEST_SERVER_ADDRESS']="localhost:8000-8010,8080,9200-9300"

Had the same issue myself, maybe this helps someone out.

like image 116
radu.ciorba Avatar answered Sep 29 '22 11:09

radu.ciorba


This started happening to me when running subsequent tests after a previous one generated an internal server error. On a mac, use lsof to find the program using the port, and kill it. E.g.:

$ sudo lsof -i :8081
COMMAND    PID    USER   FD   TYPE            DEVICE SIZE/OFF NODE NAME
firefox-b 1097 username    3u  IPv4 0x94495559c6dea35      0t0  TCP localhost:sunproxyadmin (LISTEN)

$ kill -9 1097
like image 34
mynameistechno Avatar answered Sep 29 '22 10:09

mynameistechno


If environment variable DJANGO_LIVE_TEST_SERVER_ADDRESS is not set the default address to start the live test server is localhost:8081. See LiveServerTestCase src code.

  # Launch the live server's thread
    specified_address = os.environ.get(
        'DJANGO_LIVE_TEST_SERVER_ADDRESS', 'localhost:8081')

As the OS seems to be complaining about the port 8081 being in use. One can quickly pick another port (say 9000) by running the tests like below.

/manage.py test functional_tests --liveserver :9000

However, explicitly setting the DJANGO_LIVE_TEST_SERVER_ADDRESS would be ideal.

export DJANGO_LIVE_TEST_SERVER_ADDRESS="localhost:9000"
like image 42
maitreyak Avatar answered Sep 29 '22 12:09

maitreyak


For what it's worth, I had a similar issue and solved it slightly differently. Our LiveServerTestCase was running alongside a few other machines in a virtualized environment, and needed to keep the same port so Nginx (on a different machine) would be able to redirect traffic properly.

The problematic line was https://github.com/django/django/blob/1.11.15/django/test/testcases.py#L1296, specifically allow_reuse_address=False.

allow_reuse_address defaults to True, and is overridden here with the expectation that the server thread will bind to port 0, and will be guaranteed to have a free port. If the port is reused between subsequent runs, though, when the next test starts the OS hasn't timed out the previous test's socket request yet. More details are available here

My solution was just to subclass and override the kwarg:

import django.test.testcases
from django.core.servers.basehttp import WSGIServer


class LiveServerThreadWithReuse(django.test.testcases.LiveServerThread):
    """
    This miniclass overrides _create_server to allow port reuse. This avoids creating
    "address already in use" errors for tests that have been run subsequently.
    """

    def _create_server(self):
        return WSGIServer(
            (self.host, self.port),
            django.test.testcases.QuietWSGIRequestHandler,
            allow_reuse_address=True,
        )


class MyFunctionalTestCase(django.test.testcases.LiveServerTestCase):
    port = 8000
    server_thread_class = LiveServerThreadWithReuse

    def test_something(self):
        # ...

Note that this was for django v1.11. In later versions, the names have slightly changed (I think from WSGIServer to ThreadedWSGIServer).

like image 21
Alec Rosenbaum Avatar answered Sep 29 '22 11:09

Alec Rosenbaum


Change your teardown method if you're going to separate your test cases

Testing in one file is okay to use the .close() method

def tearDown(self):
    self.browser.close()

Testing in multiple files will require starting new threads.

def tearDown(self):
    self.browser.quit()
like image 28
Zanzobar Avatar answered Sep 29 '22 10:09

Zanzobar