Author: kkubasik
Date: 2009-07-22 08:12:26 -0500 (Wed, 22 Jul 2009)
New Revision: 11294

Added:
   django/branches/soc2009/test-improvements/django/test/twill_tests.py
Modified:
   django/branches/soc2009/test-improvements/
   django/branches/soc2009/test-improvements/django/test/test_coverage.py
   
django/branches/soc2009/test-improvements/tests/regressiontests/admin_views/windmilltests/primary.py
   django/branches/soc2009/test-improvements/tests/runtests.py
Log:
[gsoc2009-testing] Finally fixed the coverage issue by tracing all imports to a 
file, then loading on test run. Also, this has a copy of the python twill 
runner, still working on the DSL version



Property changes on: django/branches/soc2009/test-improvements
___________________________________________________________________
Name: svk:merge
   - 23ef3597-c209-482b-90c0-ea6045f15f7f:/local/django-gsoc:11116
23ef3597-c209-482b-90c0-ea6045f15f7f:/local/django/trunk:10927
bcc190cf-cafb-0310-a4f2-bffc1f526a37:/django/trunk:11277
   + 23ef3597-c209-482b-90c0-ea6045f15f7f:/local/django-gsoc:11117
23ef3597-c209-482b-90c0-ea6045f15f7f:/local/django/trunk:10927
bcc190cf-cafb-0310-a4f2-bffc1f526a37:/django/trunk:11277

Modified: django/branches/soc2009/test-improvements/django/test/test_coverage.py
===================================================================
--- django/branches/soc2009/test-improvements/django/test/test_coverage.py      
2009-07-22 13:11:55 UTC (rev 11293)
+++ django/branches/soc2009/test-improvements/django/test/test_coverage.py      
2009-07-22 13:12:26 UTC (rev 11294)
@@ -24,8 +24,11 @@
 
     def __init__(self):
         """Placeholder (since it is overrideable)"""
-        self.cov = coverage.coverage(cover_pylib=True)
-        self.cov.erase()
+        self.cov = coverage.coverage(cover_pylib=True, auto_data=True)
+        self.cov.use_cache(True)
+        self.cov.load()
+        #self.cov.combine()
+        
 
 
     def run_tests(self, test_labels, verbosity=1, interactive=True,
@@ -36,7 +39,7 @@
         """
         #self.cov.erase()
         #Allow an on-disk cache of coverage stats.
-        self.cov.use_cache(0)
+        #self.cov.use_cache(0)
         #for e in getattr(settings, 'COVERAGE_CODE_EXCLUDES', []):
         #    self.cov.exclude(e)
 
@@ -45,8 +48,8 @@
         brt = base_run_tests()
         results = brt.run_tests(test_labels, verbosity, interactive, 
extra_tests)
         self.cov.stop()
+        #self.cov.erase()
 
-
         coverage_modules = []
         if test_labels:
             for label in test_labels:

Added: django/branches/soc2009/test-improvements/django/test/twill_tests.py
===================================================================
--- django/branches/soc2009/test-improvements/django/test/twill_tests.py        
                        (rev 0)
+++ django/branches/soc2009/test-improvements/django/test/twill_tests.py        
2009-07-22 13:12:26 UTC (rev 11294)
@@ -0,0 +1,332 @@
+"""
+
+This code is originally by miracle2k:
+http://bitbucket.org/miracle2k/djutils/src/97f92c32c621/djutils/test/twill.py
+
+
+Integrates the twill web browsing scripting language with Django.
+
+Provides too main functions, ``setup()`` and ``teardown``, that hook
+(and unhook) a certain host name to the WSGI interface of your Django
+app, making it possible to test your site using twill without actually
+going through TCP/IP.
+
+It also changes the twill browsing behaviour, so that relative urls
+per default point to the intercept (e.g. your Django app), so long
+as you don't browse away from that host. Further, you are allowed to
+specify the target url as arguments to Django's ``reverse()``.
+
+Usage:
+
+    from test_utils.utils import twill_runner as twill
+    twill.setup()
+    try:
+        twill.go('/')                     # --> Django WSGI
+        twill.code(200)
+
+        twill.go('http://google.com')
+        twill.go('/services')             # --> http://google.com/services
+
+        twill.go('/list', default=True)   # --> back to Django WSGI
+
+        twill.go('proj.app.views.func',
+                 args=[1,2,3])
+    finally:
+        twill.teardown()
+
+For more information about twill, see:
+    http://twill.idyll.org/
+"""
+
+# allows us to import global twill as opposed to this module
+from __future__ import absolute_import
+
+# TODO: import all names with a _-prefix to keep the namespace clean with the 
twill stuff?
+import urlparse
+import cookielib
+
+import twill
+import twill.commands
+import twill.browser
+
+from django.conf import settings
+from django.core.servers.basehttp import AdminMediaHandler
+from django.core.handlers.wsgi import WSGIHandler
+from django.core.urlresolvers import reverse
+from django.http import HttpRequest
+from django.utils.datastructures import SortedDict
+from django.contrib import auth
+
+from django.core.management.commands.test_windmill import ServerContainer, 
attempt_import
+
+# make available through this module
+from twill.commands import *
+
+__all__ = ('INSTALLED', 'setup', 'teardown', 'reverse',) + 
tuple(twill.commands.__all__)
+
+
+DEFAULT_HOST = '127.0.0.1'
+DEFAULT_PORT = 9090
+INSTALLED = SortedDict()   # keep track of the installed hooks
+
+
+def setup(host=None, port=None, allow_xhtml=True, propagate=True):
+    """Install the WSGI hook for ``host`` and ``port``.
+
+    The default values will be used if host or port are not specified.
+
+    ``allow_xhtml`` enables a workaround for the "not viewer HTML"
+    error when browsing sites that are determined to be XHTML, e.g.
+    featuring xhtml-ish mimetypes.
+
+    Unless ``propagate specifies otherwise``, the
+    ``DEBUG_PROPAGATE_EXCEPTIONS`` will be enabled for better debugging:
+    when using twill, we don't really want to see 500 error pages,
+    but rather directly the exceptions that occured on the view side.
+
+    Multiple calls to this function will only result in one handler
+    for each host/port combination being installed.
+    """
+
+    host = host or DEFAULT_HOST
+    port = port or DEFAULT_PORT
+    key = (host, port)
+
+    if not key in INSTALLED:
+        # installer wsgi handler
+        app = AdminMediaHandler(WSGIHandler())
+        twill.add_wsgi_intercept(host, port, lambda: app)
+
+        # start browser fresh
+        browser = get_browser()
+        browser.diverged = False
+
+        # enable xhtml mode if requested
+        _enable_xhtml(browser, allow_xhtml)
+
+        # init debug propagate setting, and remember old value
+        if propagate:
+            old_propgate_setting = settings.DEBUG_PROPAGATE_EXCEPTIONS
+            settings.DEBUG_PROPAGATE_EXCEPTIONS = True
+        else:
+            old_propgate_setting = None
+
+        INSTALLED[key] = (app, old_propgate_setting)
+        return browser
+    return False
+
+
+def teardown(host=None, port=None):
+    """Remove an installed WSGI hook for ``host`` and ```port``.
+
+    If no host or port is passed, the default values will be assumed.
+    If no hook is installed for the defaults, and both the host and
+    port are missing, the last hook installed will be removed.
+
+    Returns True if a hook was removed, otherwise False.
+    """
+
+    both_missing = not host and not port
+    host = host or DEFAULT_HOST
+    port = port or DEFAULT_PORT
+    key = (host, port)
+
+    key_to_delete = None
+    if key in INSTALLED:
+        key_to_delete = key
+    if not key in INSTALLED and both_missing and len(INSTALLED) > 0:
+        host, port = key_to_delete = INSTALLED.keys()[-1]
+
+    if key_to_delete:
+        _, old_propagate = INSTALLED[key_to_delete]
+        del INSTALLED[key_to_delete]
+        result = True
+        if old_propagate is not None:
+            settings.DEBUG_PROPAGATE_EXCEPTIONS = old_propagate
+    else:
+        result = False
+
+    # note that our return value is just a guess according to our
+    # own records, we pass the request on to twill in any case
+    twill.remove_wsgi_intercept(host, port)
+    return result
+
+
+def _enable_xhtml(browser, enable):
+    """Twill (darcs from 19-09-2008) does not work with documents
+    identifying themselves as XHTML.
+
+    This is a workaround.
+    """
+    factory = browser._browser._factory
+    factory.basic_factory._response_type_finder._allow_xhtml = \
+        factory.soup_factory._response_type_finder._allow_xhtml = \
+            enable
+
+
+class _EasyTwillBrowser(twill.browser.TwillBrowser):
+    """Custom version of twill's browser class that defaults relative
+    URLs to the last installed hook, if available.
+
+    It also supports reverse resolving, and some additional commands.
+    """
+
+    def __init__(self, *args, **kwargs):
+        self.diverged = False
+        self._testing_ = False
+        super(_EasyTwillBrowser, self).__init__(*args, **kwargs)
+
+    def go(self, url, args=None, kwargs=None, default=None):
+        assert not ((args or kwargs) and default==False)
+
+        if args or kwargs:
+            url = reverse(url, args=args, kwargs=kwargs)
+            default = True    # default is implied
+
+        if INSTALLED:
+            netloc = '%s:%s' % INSTALLED.keys()[-1]
+            urlbits = urlparse.urlsplit(url)
+            if not urlbits[0]:
+                if default:
+                    # force "undiverge"
+                    self.diverged = False
+                if not self.diverged:
+                    url = urlparse.urlunsplit(('http', netloc)+urlbits[2:])
+            else:
+                self.diverged = True
+
+        if self._testing_:   # hack that makes it simple for us to test this
+            return url
+        return super(_EasyTwillBrowser, self).go(url)
+
+    def login(self, **credentials):
+        """Log the user with the given credentials into your Django
+        site.
+
+        To further simplify things, rather than giving the credentials,
+        you may pass a ``user`` parameter with the ``User`` instance you
+        want to login. Note that in this case the user will not be
+        further validated, i.e. it is possible to login an inactive user
+        this way.
+
+        This works regardless of the url currently browsed, but does
+        require the WSGI intercept to be setup.
+
+        Returns ``True`` if login was possible; ``False`` if the
+        provided credentials are incorrect, or the user is inactive,
+        or if the sessions framework is not available.
+
+        Based on ``django.test.client.Client.logout``.
+
+        Note: A ``twill.reload()`` will not refresh the cookies sent
+        with the request, so your login will not have any effect there.
+        This is different for ``logout``, since it actually invalidates
+        the session server-side, thus making the current key invalid.
+        """
+
+        if not 'django.contrib.sessions' in settings.INSTALLED_APPS:
+            return False
+
+        host, port = INSTALLED.keys()[-1]
+
+        # determine the user we want to login
+        user = credentials.pop('user', None)
+        if user:
+            # Login expects the user object to reference it's backend.
+            # Since we're not going through ``authenticate``, we'll
+            # have to do this ourselves.
+            backend = auth.get_backends()[0]
+            user.backend = user.backend = "%s.%s" % (
+                backend.__module__, backend.__class__.__name__)
+        else:
+            user = auth.authenticate(**credentials)
+            if not user or not user.is_active:
+                return False
+
+        # create a fake request to use with ``auth.login``
+        request = HttpRequest()
+        request.session = __import__(settings.SESSION_ENGINE, {}, {}, 
['']).SessionStore()
+        auth.login(request, user)
+        request.session.save()
+
+        # set the cookie to represent the session
+        self.cj.set_cookie(cookielib.Cookie(
+            version=None,
+            name=settings.SESSION_COOKIE_NAME,
+            value=request.session.session_key,
+            port=str(port),   # must be a string
+            port_specified = False,
+            domain=host, #settings.SESSION_COOKIE_DOMAIN,
+            domain_specified=True,
+            domain_initial_dot=False,
+            path='/',
+            path_specified=True,
+            secure=settings.SESSION_COOKIE_SECURE or None,
+            expires=None,
+            discard=None,
+            comment=None,
+            comment_url=None,
+            rest=None
+        ))
+
+        return True
+
+    def logout(self):
+        """Log the current user out of your Django site.
+
+        This works regardless of the url currently browsed, but does
+        require the WSGI intercept to be setup.
+
+        Based on ``django.test.client.Client.logout``.
+        """
+        host, port = INSTALLED.keys()[-1]
+        for cookie in self.cj:
+            if cookie.name == settings.SESSION_COOKIE_NAME \
+                    and cookie.domain==host \
+                    and (not cookie.port or str(cookie.port)==str(port)):
+                session = __import__(settings.SESSION_ENGINE, {}, {}, 
['']).SessionStore()
+                session.delete(session_key=cookie.value)
+                self.cj.clear(cookie.domain, cookie.path, cookie.name)
+                return True
+        return False
+
+
+def go(*args, **kwargs):
+    # replace the default ``go`` to make the additional
+    # arguments that our custom browser provides available.
+    browser = get_browser()
+    browser.go(*args, **kwargs)
+    return browser.get_url()
+
+def login(*args, **kwargs):
+    return get_browser().login(*args, **kwargs)
+
+def logout(*args, **kwargs):
+    return get_browser().logout(*args, **kwargs)
+
+def reset_browser(*args, **kwargs):
+    # replace the default ``reset_browser`` to ensure
+    # that our custom browser class is used
+    result = twill.commands.reset_browser(*args, **kwargs)
+    twill.commands.browser = _EasyTwillBrowser()
+    return result
+
+# Monkey-patch our custom browser into twill; this will be global, but
+# will only have an actual effect when intercepts are installed through
+# our module (via ``setup``).
+# Unfortunately, twill pretty much forces us to use the same global
+# state it does itself, lest us reimplement everything from
+# ``twill.commands``. It's a bit of a shame, we could provide dedicated
+# browser instances for each call to ``setup()``.
+reset_browser()
+
+
+def url(should_be=None):
+    """Like the default ``url()``, but can be called without arguments,
+    in which case it returns the current url.
+    """
+
+    if should_be is None:
+        return get_browser().get_url()
+    else:
+        return twill.commands.url(should_be)

Modified: 
django/branches/soc2009/test-improvements/tests/regressiontests/admin_views/windmilltests/primary.py
===================================================================
--- 
django/branches/soc2009/test-improvements/tests/regressiontests/admin_views/windmilltests/primary.py
        2009-07-22 13:11:55 UTC (rev 11293)
+++ 
django/branches/soc2009/test-improvements/tests/regressiontests/admin_views/windmilltests/primary.py
        2009-07-22 13:12:26 UTC (rev 11294)
@@ -27,7 +27,7 @@
     client.asserts.assertNode(link=u'Change')
     client.asserts.assertNode(link=u'Admin_Views')
     client.asserts.assertNode(xpath=u"//d...@id='user-tools']/strong")
-    
client.click(xpath=u"//d...@id='content-main']/div/table/tbody/tr[22]/td/a")
+    
client.click(xpath=u"//d...@id='content-main']/div/table/tbody/tr[23]/td/a")
     client.waits.forPageLoad(timeout=u'20000')
     client.type(text=u'Test Section', id=u'id_name')
     client.click(name=u'_save')
@@ -324,15 +324,15 @@
 
     client.open(url=ADMIN_URL)
     client.waits.forPageLoad(timeout=u'20000')
-    
client.waits.forElement(xpath=u"//d...@id='content-main']/div/table/tbody/tr[21]/td/a",
 timeout=u'8000')
-    
client.click(xpath=u"//d...@id='content-main']/div/table/tbody/tr[21]/td/a")
+    
client.waits.forElement(xpath=u"//d...@id='content-main']/div/table/tbody/tr[22]/td/a",
 timeout=u'8000')
+    
client.click(xpath=u"//d...@id='content-main']/div/table/tbody/tr[22]/td/a")
     client.click(name=u'_save')
     client.waits.forPageLoad(timeout=u'20000')
     client.click(link=u'Recommender object')
     client.waits.forPageLoad(timeout=u'20000')
     client.click(link=u'Home')
     client.waits.forPageLoad(timeout=u'20000')
-    
client.click(xpath=u"//d...@id='content-main']/div/table/tbody/tr[20]/td/a")
+    
client.click(xpath=u"//d...@id='content-main']/div/table/tbody/tr[21]/td/a")
     client.click(id=u'id_recommender')
     client.select(option=u'Recommender object', id=u'id_recommender')
     client.click(value=u'1')

Modified: django/branches/soc2009/test-improvements/tests/runtests.py
===================================================================
--- django/branches/soc2009/test-improvements/tests/runtests.py 2009-07-22 
13:11:55 UTC (rev 11293)
+++ django/branches/soc2009/test-improvements/tests/runtests.py 2009-07-22 
13:12:26 UTC (rev 11294)
@@ -1,4 +1,14 @@
 #!/usr/bin/env python
+try:
+    import coverage
+    global _dj_cover
+    _dj_cover = coverage.coverage(cover_pylib=True, auto_data=True)
+    _dj_cover.erase()
+    _dj_cover.use_cache(True)
+    _dj_cover.start()
+except Exception, e:
+    print "coverage.py module not available"
+
 import os, sys, traceback
 import unittest
 import django
@@ -11,11 +21,8 @@
 except NameError:
     from sets import Set as set     # For Python 2.3
 
-try:
-    import coverage
-except Exception, e:
-    print "coverage.py module not available"
 
+
 CONTRIB_DIR_NAME = 'django.contrib'
 MODEL_TESTS_DIR_NAME = 'modeltests'
 REGRESSION_TESTS_DIR_NAME = 'regressiontests'
@@ -202,6 +209,8 @@
     #Run the appropriate test runner based on command line params.
     if do_std:
         if do_coverage:
+            _dj_cover.save()
+            _dj_cover.stop()
             test_runner = get_runner(settings, coverage=True, reports=True)
         else:
             test_runner = get_runner(settings, coverage=False, reports=False)


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-updates@googlegroups.com
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to