Ticket #2879: django_live_server_1.0.2.diff

File django_live_server_1.0.2.diff, 8.9 KB (added by Andrew Badr, 16 years ago)

untested patch for Django 1.0.2

  • django/test/testcases.py

     
    11import re
    22import unittest
     3import socket
     4import threading
    35from urlparse import urlsplit, urlunsplit
    46from xml.dom.minidom import parseString, Node
    57
     
    1214from django.test import _doctest as doctest
    1315from django.test.client import Client
    1416from django.utils import simplejson
     17from django.core.handlers.wsgi import WSGIHandler
     18from django.core.servers import basehttp
    1519
    1620normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s)
    1721
     
    169173        # side effects on other tests.
    170174        transaction.rollback_unless_managed()
    171175
     176class TestServerThread(threading.Thread):
     177    """Thread for running a http server while tests are running."""
     178
     179    def __init__(self, address, port):
     180        self.address = address
     181        self.port = port
     182        self._stopevent = threading.Event()
     183        self.started = threading.Event()
     184        self.error = None
     185        super(TestServerThread, self).__init__()
     186
     187    def run(self):
     188        """Sets up test server and database and loops over handling http requests."""
     189        try:
     190            handler = basehttp.AdminMediaHandler(WSGIHandler())
     191            server_address = (self.address, self.port)
     192            httpd = basehttp.StoppableWSGIServer(server_address, basehttp.WSGIRequestHandler)
     193            httpd.set_app(handler)
     194            self.started.set()
     195        except basehttp.WSGIServerException, e:
     196            self.error = e
     197            self.started.set()
     198            return
     199
     200        # Must do database stuff in this new thread if database in memory.
     201        from django.conf import settings
     202        if settings.DATABASE_ENGINE == 'sqlite3' \
     203            and (not settings.TEST_DATABASE_NAME or settings.TEST_DATABASE_NAME == ':memory:'):
     204            from django.db import connection
     205            db_name = connection.creation.create_test_db(0)
     206            # Import the fixture data into the test database.
     207            if hasattr(self, 'fixtures'):
     208                # We have to use this slightly awkward syntax due to the fact
     209                # that we're using *args and **kwargs together.
     210                call_command('loaddata', *self.fixtures, **{'verbosity': 0})
     211
     212        # Loop until we get a stop event.
     213        while not self._stopevent.isSet():
     214            httpd.handle_request()
     215
     216    def join(self, timeout=None):
     217        """Stop the thread and wait for it to finish."""
     218        self._stopevent.set()
     219        threading.Thread.join(self, timeout)
     220
    172221class TestCase(unittest.TestCase):
    173222    def _pre_setup(self):
    174223        """Performs any pre-test setup. This includes:
     
    225274            settings.ROOT_URLCONF = self._old_root_urlconf
    226275            clear_url_caches()
    227276
     277    def start_test_server(self, address='localhost', port=8000):
     278        """Creates a live test server object (instance of WSGIServer)."""
     279        self.server_thread = TestServerThread(address, port)
     280        self.server_thread.start()
     281        self.server_thread.started.wait()
     282        if self.server_thread.error:
     283            raise self.server_thread.error
     284
     285    def stop_test_server(self):
     286        if self.server_thread:
     287            self.server_thread.join()
     288
    228289    def assertRedirects(self, response, expected_url, status_code=302,
    229290                        target_status_code=200, host=None):
    230291        """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 stat
    1516import sys
    1617import urllib
     
    669670        start_response(status, headers.items())
    670671        return output
    671672
     673class StoppableWSGIServer(WSGIServer):
     674    """WSGIServer with short timeout, so that server thread can stop this server."""
     675
     676    def server_bind(self):
     677        """Sets timeout to 1 second."""
     678        WSGIServer.server_bind(self)
     679        self.socket.settimeout(1)
     680
     681    def get_request(self):
     682        """Checks for timeout when getting request."""
     683        try:
     684            sock, address = self.socket.accept()
     685            sock.settimeout(None)
     686            return (sock, address)
     687        except socket.timeout:
     688            raise
     689
    672690def run(addr, port, wsgi_handler):
    673691    server_address = (addr, port)
    674692    httpd = WSGIServer(server_address, WSGIRequestHandler)
  • tests/regressiontests/test_client_regress/models.py

     
    99from django.core.exceptions import SuspiciousOperation
    1010from django.template import TemplateDoesNotExist, TemplateSyntaxError
    1111
     12import urllib
     13
    1214class AssertContainsTests(TestCase):
    1315    def test_contains(self):
    1416        "Responses can be inspected for content, including counting repeated substrings"
     
    354356        url = reverse('arg_view', args=['somename'])
    355357        self.assertEquals(url, '/test_client_regress/arg_view/somename/')
    356358
     359class TestServerTests(TestCase):
     360     def setUp(self):
     361         self.start_test_server(address='localhost', port=8001)
     362 
     363     def tearDown(self):
     364         self.stop_test_server()
     365 
     366     def test_server_up(self):
     367         url = urllib.urlopen('http://localhost:8001')
     368         self.assertEqual(url.read(), 'Django Internal Tests: 404 Error')
     369         url.close()
     370 
     371     def test_serve_page(self):
     372         url = urllib.urlopen('http://localhost:8001/accounts/login')
     373         # Just make sure this isn't a 404, and we've gotten something.
     374         self.assertNotEqual(url.read(), 'Django Internal Tests: 404 Error')
     375         url.close()
     376
    357377class SessionTests(TestCase):
    358378    fixtures = ['testdata.json']
    359379
     
    382402        response = self.client.get('/test_client_regress/check_session/')
    383403        self.assertEqual(response.status_code, 200)
    384404        self.assertEqual(response.content, 'YES')
    385        
    386  No newline at end of file
     405       
  • AUTHORS

     
    290290    Robert Myers <myer0052@gmail.com>
    291291    Nebojša Dorđević
    292292    Doug Napoleone <doug@dougma.com>
     293    Devin Naquin <dnaquin@gmail.com>
    293294    Gopal Narayanan <gopastro@gmail.com>
    294295    Fraser Nevett <mail@nevett.org>
    295296    Sam Newman <http://www.magpiebrain.com/>
  • docs/topics/testing.txt

     
    867867
    868868.. _emptying-test-outbox:
    869869
     870Running tests with a live test server
     871~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     872
     873**New in Django development version**
     874
     875When running tests that use in-browser frameworks such as Twille_ and
     876Selenium_, it's necessary to have a running test server. Django's custom
     877``TestCase`` class supports starting a live server for these purposes.
     878
     879``start_test_server(address='localhost', port=8000)``
     880    Starts a test server at ``address`` on ``port``. This should be done in the
     881    ``setUp()`` method of a subclass of ``TestCase``. The server then can be
     882    accessed at http://address:port.
     883
     884``stop_test_server()``
     885    Stops the test server that was started with ``start_test_server``. This
     886    must be done before ``start_test_server`` can be called again, so this
     887    should be done in the ``tearDown()`` method of a subclass of ``TestCase``.
     888
     889This can be used to start a server that can then be accessed by Twill, Selenium
     890or another in-browser test framework. For example::
     891
     892        from django.test.testcases import TestCase
     893        from selenium import selenium
     894       
     895        class TestLogin(TestCase):
     896            fixtures = ['login_info.xml']
     897
     898            def setUp(self):
     899                # Start a test server and tell selenium where to find it.
     900                self.start_test_server('localhost', 8000)
     901                self.selenium = selenium('localhost', 4444, \
     902                        '*pifirefox', 'http://localhost:8000')
     903
     904            def tearDown(self):
     905                # Stop server and Selenium
     906                self.selenium.stop()
     907                self.stop_test_server()
     908
     909            def testLogin(self):
     910                self.selenium.open('/admin/')
     911                self.selenium.type('username', 'admin')
     912                self.selenium.type('password', 'password')
     913                self.selenium.click("//input[@value='Log in']")
     914
     915.. _Twill: http://twill.idyll.org/
     916.. _Selenium: http://www.openqa.org/selenium/
     917
    870918Emptying the test outbox
    871919~~~~~~~~~~~~~~~~~~~~~~~~
    872920
Back to Top