Django

Code

Ticket #2879: django_live_server_r7936.diff

File django_live_server_r7936.diff, 8.7 kB (added by devin, 2 months ago)

refactor and cleanup

  • django/test/testcases.py

    old new  
    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

    old new  
    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

    old new  
    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

    old new  
    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

    old new  
    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