We had some bugs in our code if it ran with virtual hosting, so Benji and I talked about a fun, quick, somewhat hacky way to get virtual hosting functional tests "for free": get your standard, already- existing testbrowser-based functional tests to run with the virtual hosting going on behind the scenes. I prototyped this today, and wanted to share the hack love.

So, imagine that you have a Zope testbrowser test that begins its examples with this:

    >>> from zope.testbrowser import Browser
    >>> browser = Browser()
    >>> browser.addHeader('Authorization', 'Basic gary:123')
    >>> browser.addHeader('Accept-Language', 'test')
    >>> browser.open('http://localhost/@@contents.html')
    >>> browser.url

We'll go ahead and do this up right, so if you haven't seen some of the functional test tricks lately, we'll include most of the new ones.

Further imagine that you have an ftesting.zcml file that is effectively your test's site.zcml. That means you'll be using a layer (shown near the bottom of the code).

In the ftesting.zcml, you have set up the 'test' language, with """<include package="zope.app.i18n.tests" />""", and then our browser will use it thanks to the addHeader call above. Read all about it in zope.app.i18n.tests if you haven't yet. If you need to write internationalized code and test its coverage then it's convenient.

Now, the test has been written without virtual hosting in mind: it just uses localhost, the way that the testbrowser README does. The goal is to use this same doc test to test virtual hosting.

To do so, my hack makes you do two things: remove the first line of the doc test (where you import the Browser), and change your ftests.py to run the same doc test twice, once with virtual hosting, and once without.

Here's the code, with example usage at the bottom. We have imports, then the sorta-but-not-reliably-general virtual hosting tricks that could in theory be stored somewhere and imported, and then the actual test set up.


import re
import unittest
import urllib2

import transaction
from zope.testing import renormalizing
from zope.testbrowser import testing, browser

from zope.app.testing import functional
from zope.app.folder.folder import Folder
from zope.app.component.site import LocalSiteManager

#### virtual host setup ####
# this is the part that is kinda sorta general

virtualHostChecker = renormalizing.RENormalizing([
(re.compile('http://example.com/virtual_path/'), 'http:// localhost/')])

class VirtualHostingPublisherConnection(testing.PublisherConnection):
    def request(self, method, url, body=None, headers=None):
        if self.host == 'example.com':
            assert url.startswith('/virtual_path')
            url = url[13:]
        if not url:
            url = '/'
url = '/vh_test_folder/++vh++http:example.com:80/ virtual_path/++' + url
        super(VirtualHostingPublisherConnection, self).request(
            method, url, body, headers)

class VirtualHostingPublisherHTTPHandler(urllib2.HTTPHandler):
    """Special HTTP handler to use the Zope Publisher."""

    http_request = urllib2.AbstractHTTPHandler.do_request_

    def http_open(self, req):
        """Open an HTTP connection having a ``urllib2`` request."""
        # Here we connect to the publisher.
        return self.do_open(VirtualHostingPublisherConnection, req)

class VirtualHostingPublisherMechanizeBrowser(
handler_classes = testing.PublisherMechanizeBrowser.handler_classes.copy()
    handler_classes['http'] = VirtualHostingPublisherHTTPHandler

class VirtualHostingBrowser(browser.Browser):
"""Zope ``testbrowser` that inserts virtual hosting behind the scenes."""

    def __init__(self, url=None):
        mech_browser = VirtualHostingPublisherMechanizeBrowser()
        super(VirtualHostingBrowser, self).__init__(
            url=url, mech_browser=mech_browser)

def virtualHostingSetUp(test):
    # create a site named vh_test_folder in root
    root = test.globs['getRootFolder']()
    f = Folder()
    root['vh_test_folder'] = f

#### test setup ####
# this is the part that would be specific to your use.

# here's the layer (notice we use it twice in the suite)
functional.defineLayer('TestLayer', 'ftesting.zcml')

def test_suite():
    suite = unittest.TestSuite()

    s = functional.FunctionalDocFileSuite(
            'README.txt', globs={'Browser': testing.Browser})
    s.layer = TestLayer

    s = functional.FunctionalDocFileSuite(
            'README.txt', globs={'Browser': VirtualHostingBrowser},
    s.layer = TestLayer

    return suite

if __name__ == '__main__':


Voila! one unsuspecting testbrowser test, suddenly thrust into a virtual hosting world.

Well, maybe a couple of other people in the world thought that was cool. :-)

Zope3-dev mailing list
Unsub: http://mail.zope.org/mailman/options/zope3-dev/archive%40mail-archive.com

Reply via email to