XML-HTTP test server in Rails

In my current job our main product is an online Bingo service. We have different customers who we run sites for, and to integrate with their user databases, we use some agreed XML-over-HTTP APIs to exchange user details and transactions.

Our service is a J2EE application, and for testing purposes these external user APIs are stubbed out in a simple Java class. This is good for normal testing, but not for testing the API handling code because half of it gets replaced by the stub class.

Since we wanted to make some fixes to our API handling code, it seemed like a good idea to build a standalone server that could emulate the external sites XML handling, and what could be quicker than using Rails?In the external API, the method to invoke is defined by an entry in the XML message itself, so Rails URL based routing wouldn’t work. I put together a generic handling method on the base Controller which all requests would be sent into:

def index
if request.post?
begin
@post_xml = REXML::Document.new(request.raw_post)
if self.respond_to? request_type.underscore
self.send request_type.underscore
else
error_response unknown_request_code, "Unknown request: #{request_type} (#{request_type.underscore})"
end
rescue RequestError => e
error_response e.code, e.message
end
end
end
 
def request_type
@post_xml.root.elements["request/*[2]"].name
end

This uses the REXML library to parse the POST body, then calls our request_type method to pull out the type of the request (in this case, it’s the tag name of part of the XML). It then calls a method with the same name as the request type, or sends an appropriate error message if the method doesn’t exist. (I won’t go into details of the actual XML API).

My next problem was how to test posting XML into the controller. After some digging around I found I could set the test request body in my functional test class like this:

def test_login
@request.env['RAW_POST_DATA'] = <<-END_OF_POST
 
 
<myapi version="0.1">
<request>
<systemauth>
<user>systemuser</user></systemauth></request></myapi>
 
<password>systempass</password>
<accountvalidate>
<username>edward</username></accountvalidate>
<password>password</password>
 
 
END_OF_POST
post :index
assert_response :success
assert_equal "edward", assigns("user").username
assert_not_nil assigns("token")
end

In other words, I make a big string of my sample XML message and stuff it into the right part of the request environment. In some of the more complex test functions, I create objects beforehand and substitute their values into the XML (e.g. the system uses login tokens, so I create a valid token and put the value in the XML, for testing a method where the user is already logged in).

In the next part, I’ll talk about deliberately creating server errors…

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*