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
_______________________________________________
Zope3-dev mailing list
Zope3-dev@zope.org
Unsub: http://mail.zope.org/mailman/options/zope3-dev/archive%40mail-archive.com