[Zope3-dev] recycling testbrowser tests: a virtual hosting test hack

Gary Poster gary at zope.com
Fri Dec 16 15:59:24 EST 2005


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
     'http://localhost/@@contents.html'

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.

----8<----8<----8<----

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(
     testing.PublisherMechanizeBrowser):
     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
     f.setSiteManager(LocalSiteManager(f))
     transaction.commit()

#### 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
     suite.addTest(s)

     s = functional.FunctionalDocFileSuite(
             'README.txt', globs={'Browser': VirtualHostingBrowser},
             setUp=virtualHostingSetUp,
             checker=virtualHostChecker)
     s.layer = TestLayer
     suite.addTest(s)

     return suite

if __name__ == '__main__':
     unittest.main(defaultTest='test_suite')

----8<----8<----8<----

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. :-)

Gary


More information about the Zope3-dev mailing list