Testing XMLRPC Controllers in Pylons

Testing is one of the essential tasks in modern software development, so
it is only natural to want to test an application as thoroughly as

I’m currently working on an application that offers a service via
xmlrpc. For a client side implementaion I use python’s xmlrpclib and
that is working well. Then again, I obviously want to test the xmlrpc
functionality also during regular unit and functional tests and not only
using the client. What’s more, having to instantiate a server to be able
to run tests is cumbersome at best.

Unfortunatly, Pylons does not offer a method to test xmlrpc controllers
out of the box. The solution I found is not quite as complicated as I
had feared at first. Read more after the break.

For the above mentiond reasons, here is my solution for testing a
XMLRPCController in Pylons using a mock transport for xmlrpclib.

This solution is largely based on the excellent post by Jean Schruger
on his Blog

from myapp.tests import *

import sys
from StringIO import StringIO
import xmlrpclib
from xmlrpclib import ServerProxy

class WSGILikeHTTP(object):
  def __init__(self, host, app):
    self.app = app
    self.headers = {}
    self.content = StringIO()

  def putrequest(self, method, handler):
    self.method = method
    self.handler = handler

  def putheader(self, key, value):
    self.headers[key] = value

  def endheaders(self):

  def send(self, body):
    self.body = body

  def getfile(self):
    return self.content

  def getreply(self):
    if self.method == "POST":
      r = self.app.post(self.handler,
                        headers = self.headers,
                        params = self.body )
      self.content = StringIO(r.response.unicode_body)
    return (200, None, None)

class WSGIAppTransport(xmlrpclib.Transport):
  # Only here to pass the 'app'
  def __init__(self, app):
    self.app = app

  # return the fake httplib.HTTP(host)
  def make_connection(self, host):
    host, extra_headers, x509 = self.get_host_info(host)
    return WSGILikeHTTP(host, self.app)

class TestXmlrpcController(TestController):

    def test_index(self):
      server = ServerProxy('http://admin:admin@dummy/xmlrpc',
      print >> sys.stderr, server.system.listMethods()

Pylons and Apache with repoze.who BasicAuth

To be able to use Basic Authentification in repoze.who running in a wsgi
app in your Apache installation, you need to tell Apache to
WSGIPassAuthorization. An Apache configuration like this will do:

# Setup mod_wsgi
WSGIPythonHome /var/www/pylons/runtime
WSGIScriptAlias /myApp /var/www/pylons/myApp/mod_wsgi/dispatch.wsgi
WSGIPassAuthorization On

<directory /var/www/pylons/myApp/mod_wsgi>
Order deny,allow
Allow from all

The importanat part here is

WSGIPassAuthorization On

This will pass HTTP authorisation headers through to the WSGI

Sources: Repoze-dev Mailing List, modwsgi Wiki

Generating Faults in Pylons XMLRPCController

This might seem easy enough, but it took me a while to get it right
since the Pylons documentation is a bit misleading here, really. It says
you should use xmlrpc_fault from pylons.controllers.xmlrpc but
that’s actually not working if you’re doing something like:

from pylons.controllers.xmlrpc import xmlrpc_fault
return xmlrpc_fault( 101, "My Error" )

This will wrap an xmlrpclib.Fault into a
pylons.controllers.util.Reponse object which will fail to marshal
with something like:

TypeError: cannot marshal  objects

The correct way to do it is:

import xmlrpclib...return xmlrpclib.Fault( 101, "My Error" )