Ticket #2879: django_live_server_r7936.diff

File django_live_server_r7936.diff, 8.7 KB (added by devin, 16 years ago)

refactor and cleanup

  • django/test/testcases.py

     
    1 import re
    2 import unittest
     1import re, socket, threading, unittest
    32from urlparse import urlsplit, urlunsplit
    43
    54from django.http import QueryDict
    65from django.db import transaction
    76from django.conf import settings
    87from django.core import mail
     8from django.core.handlers.wsgi import WSGIHandler
    99from django.core.management import call_command
     10from django.core.servers import basehttp
    1011from django.test import _doctest as doctest
    1112from django.test.client import Client
     13from django.test.utils import create_test_db
    1214from django.core.urlresolvers import clear_url_caches
    1315
    1416normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s)
     
    4951        # side effects on other tests.
    5052        transaction.rollback_unless_managed()
    5153
     54class TestServerThread(threading.Thread):
     55    """Thread for running a http server while tests are running."""
     56
     57    def __init__(self, address, port):
     58        self.address = address
     59        self.port = port
     60        self._stopevent = threading.Event()
     61        self.started = threading.Event()
     62        self.error = None
     63        super(TestServerThread, self).__init__()
     64
     65    def run(self):
     66        """Sets up test server and database and loops over handling http requests."""
     67        try:
     68            handler = basehttp.AdminMediaHandler(WSGIHandler())
     69            server_address = (self.address, self.port)
     70            httpd = basehttp.StoppableWSGIServer(server_address, basehttp.WSGIRequestHandler)
     71            httpd.set_app(handler)
     72            self.started.set()
     73        except basehttp.WSGIServerException, e:
     74            self.error = e
     75            self.started.set()
     76            return
     77
     78        # Must do database stuff in this new thread if database in memory.
     79        from django.conf import settings
     80        if settings.DATABASE_ENGINE == 'sqlite3' \
     81            and (not settings.TEST_DATABASE_NAME or settings.TEST_DATABASE_NAME == ':memory:'):
     82            db_name = create_test_db(0)
     83            # Import the fixture data into the test database.
     84            if hasattr(self, 'fixtures'):
     85                # We have to use this slightly awkward syntax due to the fact
     86                # that we're using *args and **kwargs together.
     87                call_command('loaddata', *self.fixtures, **{'verbosity': 0})
     88
     89        # Loop until we get a stop event.
     90        while not self._stopevent.isSet():
     91            httpd.handle_request()
     92
     93    def join(self, timeout=None):
     94        """Stop the thread and wait for it to finish."""
     95        self._stopevent.set()
     96        threading.Thread.join(self, timeout)
     97
    5298class TestCase(unittest.TestCase):
    5399    def _pre_setup(self):
    54100        """Performs any pre-test setup. This includes:
     
    105151            settings.ROOT_URLCONF = self._old_root_urlconf
    106152            clear_url_caches()
    107153
     154    def start_test_server(self, address='localhost', port=8000):
     155        """Creates a live test server object (instance of WSGIServer)."""
     156        self.server_thread = TestServerThread(address, port)
     157        self.server_thread.start()
     158        self.server_thread.started.wait()
     159        if self.server_thread.error:
     160            raise self.server_thread.error
     161
     162    def stop_test_server(self):
     163        if self.server_thread:
     164            self.server_thread.join()
     165
    108166    def assertRedirects(self, response, expected_url, status_code=302,
    109167                        target_status_code=200, host=None):
    110168        """Asserts that a response redirected to a specific URL, and that the
  • django/core/servers/basehttp.py

     
    1111import mimetypes
    1212import os
    1313import re
     14import socket
    1415import sys
    1516import urllib
    1617
     
    658659        start_response(status, headers.items())
    659660        return output
    660661
     662class StoppableWSGIServer(WSGIServer):
     663    """WSGIServer with short timeout, so that server thread can stop this server."""
     664
     665    def server_bind(self):
     666        """Sets timeout to 1 second."""
     667        WSGIServer.server_bind(self)
     668        self.socket.settimeout(1)
     669
     670    def get_request(self):
     671        """Checks for timeout when getting request."""
     672        try:
     673            sock, address = self.socket.accept()
     674            sock.settimeout(None)
     675            return (sock, address)
     676        except socket.timeout:
     677            raise
     678
    661679def run(addr, port, wsgi_handler):
    662680    server_address = (addr, port)
    663681    httpd = WSGIServer(server_address, WSGIRequestHandler)
  • tests/regressiontests/test_client_regress/models.py

     
    77from django.core.exceptions import SuspiciousOperation
    88import os
    99import sha
     10import urllib
    1011
    1112class AssertContainsTests(TestCase):
    1213    def test_contains(self):
     
    327328        "URLconf is reverted to original value after modification in a TestCase"
    328329        url = reverse('arg_view', args=['somename'])
    329330        self.assertEquals(url, '/test_client_regress/arg_view/somename/')
     331
     332class TestServerTests(TestCase):
     333
     334    def setUp(self):
     335        self.start_test_server(address='localhost', port=8001)
     336
     337    def tearDown(self):
     338        self.stop_test_server()
     339
     340    def test_server_up(self):
     341        url = urllib.urlopen('http://localhost:8001')
     342        self.assertEqual(url.read(), 'Django Internal Tests: 404 Error')
     343        url.close()
     344
     345    def test_serve_page(self):
     346        url = urllib.urlopen('http://localhost:8001/accounts/login')
     347        # Just make sure this isn't a 404, and we've gotten something.
     348        self.assertNotEqual(url.read(), 'Django Internal Tests: 404 Error')
     349        url.close()
  • AUTHORS

     
    273273    Robert Myers <myer0052@gmail.com>
    274274    Nebojša Dorđević
    275275    Doug Napoleone <doug@dougma.com>
     276    Devin Naquin <dnaquin@gmail.com>
    276277    Gopal Narayanan <gopastro@gmail.com>
    277278    Fraser Nevett <mail@nevett.org>
    278279    Sam Newman <http://www.magpiebrain.com/>
  • docs/testing.txt

     
    830830This test case will use the contents of ``myapp.test_urls`` as the
    831831URLconf for the duration of the test case.
    832832
     833Running tests with a live test server
     834~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     835
     836**New in Django development version**
     837
     838When running tests that use in-browser frameworks such as Twille_ and
     839Selenium_, it's necessary to have a running test server. Django's custom
     840``TestCase`` class supports starting a live server for these purposes.
     841
     842``start_test_server(address='localhost', port=8000)``
     843    Starts a test server at ``address`` on ``port``. This should be done in the
     844    ``setUp()`` method of a subclass of ``TestCase``. The server then can be
     845    accessed at http://address:port.
     846
     847``stop_test_server()``
     848    Stops the test server that was started with ``start_test_server``. This
     849    must be done before ``start_test_server`` can be called again, so this
     850    should be done in the ``tearDown()`` method of a subclass of ``TestCase``.
     851
     852This can be used to start a server that can then be accessed by Twill, Selenium
     853or another in-browser test framework. For example::
     854
     855        from django.test.testcases import TestCase
     856        from selenium import selenium
     857       
     858        class TestLogin(TestCase):
     859            fixtures = ['login_info.xml']
     860
     861            def setUp(self):
     862                # Start a test server and tell selenium where to find it.
     863                self.start_test_server('localhost', 8000)
     864                self.selenium = selenium('localhost', 4444, \
     865                        '*pifirefox', 'http://localhost:8000')
     866
     867            def tearDown(self):
     868                # Stop server and Selenium
     869                self.selenium.stop()
     870                self.stop_test_server()
     871
     872            def testLogin(self):
     873                self.selenium.open('/admin/')
     874                self.selenium.type('username', 'admin')
     875                self.selenium.type('password', 'password')
     876                self.selenium.click("//input[@value='Log in']")
     877
     878.. _Twill: http://twill.idyll.org/
     879.. _Selenium: http://www.openqa.org/selenium/
     880
    833881Emptying the test outbox
    834882~~~~~~~~~~~~~~~~~~~~~~~~
    835883
Back to Top