6

I'm using Django (1.5.5), selenium (2.41.0), splinter (0.6.0) and phantomjs (1.9.7) for running live tests.

While the tests mostly work, every now and then (very often on CircleCI, less often in a local VM) they hang until either there's a timeout on CircleCI or I kill the runner manually (Ctrl-C ie. KeyboardInterrupt works).

This is how my base test class looks:

class SplinterTestCase(LiveServerTestCase):
    @classmethod
    def setUpClass(cls):
        super(SplinterTestCase, cls).setUpClass()
        # start phantom just once per class, to speed up tests
        cls.phantom = splinter.Browser('phantomjs', load_images=False)

    @classmethod
    def tearDownClass(cls):
        cls.phantom.quit()
        super(SplinterTestCase, cls).tearDownClass()

    def login(self, *args, **kwargs):
        # perform a login using Django builtin "client", steal the session
        # cookie and inject it to phantomjs, avoiding the need to do the
        # login dance for each test
        from django.conf import settings
        cn = settings.SESSION_COOKIE_NAME

        self.django_client.login(*args, **kwargs)
        if cn in self.django_client.cookies:
            self.client.driver.add_cookie({
                'name': cn,
                'value': self.django_client.cookies[cn].value,
                'path': '/',
                'domain': 'localhost'
            })

    def setUp(self):
        # use phantom as the test client instead of Django's
        super(SplinterTestCase, self).setUp()
        self.django_client = self.client
        self.client = self.phantom

    def tearDown(self):
        # this seems to help somewhat (decreases the number of timeouts), but
        # doesn't solve it completely
        self.client.visit('about:config')
        super(SplinterTestCase, self).tearDown()

After Ctrl-C, this is the stacktrace I get:

Traceback (most recent call last):
  File "/usr/lib/python2.7/wsgiref/handlers.py", line 86, in run
    self.finish_response()
  File "/usr/lib/python2.7/wsgiref/handlers.py", line 127, in finish_response
    self.write(data)
  File "/usr/lib/python2.7/wsgiref/handlers.py", line 215, in write
    self._write(data)
  File "/usr/lib/python2.7/socket.py", line 324, in write
    self.flush()
  File "/usr/lib/python2.7/socket.py", line 303, in flush
    self._sock.sendall(view[write_offset:write_offset+buffer_size])
error: [Errno 104] Connection reset by peer
Traceback (most recent call last):
  File "/home/ubuntu/memo-angel/venv/local/lib/python2.7/site-packages/django/test/testcases.py", line 998, in _handle_request_noblock
    self.process_request(request, client_address)
  File "/usr/lib/python2.7/SocketServer.py", line 310, in process_request
    self.finish_request(request, client_address)
  File "/usr/lib/python2.7/SocketServer.py", line 323, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/home/ubuntu/memo-angel/venv/local/lib/python2.7/site-packages/django/core/servers/basehttp.py", line 150, in __init__
    super(WSGIRequestHandler, self).__init__(*args, **kwargs)
  File "/usr/lib/python2.7/SocketServer.py", line 640, in __init__
    self.finish()
  File "/usr/lib/python2.7/SocketServer.py", line 693, in finish
    self.wfile.flush()
  File "/usr/lib/python2.7/socket.py", line 303, in flush
    self._sock.sendall(view[write_offset:write_offset+buffer_size])
error: [Errno 32] Broken pipe

A similar problem might've been discussed in Django with splinter and phantomjs is painfully slow as the original poster also mentioned "it just freezes until I am out of patience to wait for it to finish". The answer there mentioned to try to put phantomjs start/stop in class setup/teardown, which I did here, but it doesn't solve the problem.

Has anyone experienced a similar problem, and if you have, what are your workarounds?

Community
  • 1
  • 1
Senko Rašić
  • 421
  • 3
  • 7
  • I have a similar problem with the latest versions of all those components (as of January 2017). My best workaround is MechanTOurS answer plus my comment on it. – Dave Schweisguth Jan 06 '17 at 00:19

1 Answers1

2

To identify the issue and make your tests fail faster, you may want to configure a socket timeout inside your setUpClass / setUp:

import socket

...
socket.setdefaulttimeout(10)
MechanTOurS
  • 1,485
  • 2
  • 15
  • 18
  • I set the default socket timeout and wrap my hanging button click in `try: ... except socket.timeout: pass` and my tests pass. The click seems to be occurring, and the hang taking place only in non-essential communication of the result back through the stack. – Dave Schweisguth Jan 06 '17 at 00:22