I've been working on understanding how to do testing of TG apps.
The TG book mentions mechanize. I didn't like how it talks to the
TG server through the web interface. My other unittests use the
testutil module to issue requests directly though createRequest,
and I liked that, instead of starting the server. For example, I
get to recreate my test data set every time.
I wrote an adapter to replace Mechanize's HTTPHandler. If
the URL request is made to a given host/port it is intercepted
by the adapter, converted into a TG request, processed by
the web app, and the TG response converted into the form
that Mechanize expects.
Here it is
import httplib
import mechanize
from mechanize import _http, _response
from turbogears import testutil
import cherrypy
import rfc822
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
class TGHTTPHandler(_http.HTTPHandler):
"""intercept requests to the given http host:port and call
TurboGears directly"""
def __init__(self,
intercept_host = "localhost",
intercept_port = "8080",
intercept_address = "127.0.0.1",
debuglevel=0):
_http.HTTPHandler.__init__(self, debuglevel)
self.intercept_host = intercept_host
self.intercept_port = intercept_port
self.intercept_address = intercept_address
def http_open(self, req):
# The request is either the hostname or the hostname:port
combination
# Normalize to make it easier to compare.
host = req.get_host()
if ":" in host:
host, port = host.split(":", 1)
else:
port = "80"
# if self.intercept_port is None then should I intercept all
ports
# to the intercept machine?
if (host != self.intercept_host or port !=
self.intercept_port):
# Let other requests go through. Useful when testing that
the
# TG app correctly links to external URLs
return _http.HTTPHandler.http_open(self, req)
# Pretty much copied this from what mechanize does to make the
request
headers = dict(req.headers)
headers.update(req.unredirected_hdrs)
headers["Connection"] = "close" # do not support HTTP 1.1
pipelining
# normalize request header keys
headers = dict( [(k.title(), v) for (k,v) in
headers.items()] )
# convert a POST document into a file-like object
rfile = None
if req.data:
rfile = StringIO(req.data)
# Call the local TG server. Here is the createRequest
signature
# create_request(request, method='GET', protocol='HTTP/1.1',
headers={}, rfile=None,
# clientAddress='127.0.0.1', remoteHost='localhost',
scheme='http')
# XXX TG has no way to override the port?
testutil.createRequest(request = req.get_selector(),
method = req.get_method(),
headers = headers,
rfile = rfile,
clientAddress = self.intercept_address,
remoteHost = host)
# Convert the TG response to the expected form for Mechanize
response = cherrypy.response
fp = StringIO(response.body[0])
code, msg = response.status.split(None, 1)
code = int(code)
# Mechanize uses an rfc822.Message and not a dictionary of
items
headers = rfc822.Message(StringIO(""))
for (k,v) in response.headers.sorted_list():
headers[k] = v
# This is a bit of a waste because downstream processors end
# up making this seekable, even though it already is seekable
return _response.closeable_response(
fp, headers, req.get_full_url(), code, msg)
def Browser(*args, **kwargs):
b = mechanize.Browser(*args, **kwargs)
# remove the old HTTPHandler -- this is a hack and I don't know
the
# right way to remove an old handler.
b.handlers = [h for h in b.handlers if not isinstance(h,
_http.HTTPHandler)]
# add the intercepting handler
b.add_handler(TGHTTPHandler())
return b
###### Example use -- I have a project called "pachy3"
from pachy3.controllers import Root
from turbogears import startup
def go():
cherrypy.root = Root()
startup.startTurboGears()
b = Browser()
b.set_handle_robots(False)
b.open("http://localhost:8080/")
print b.title()
startup.stopTurboGears()
go()
Andrew Dalke
[EMAIL PROTECTED]
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"TurboGears" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/turbogears?hl=en
-~----------~----~----~----~------~----~------~--~---