Continuous Delivery II: Smoketests in Ruby and Rails
This is part II in a blog mini series on building a build pipeline with Jenkins. The other parts, part I and part III could be worth a read too.
This part is about a implementing built-in smoke tests in a rails application. This Is by no means new, but I added a little something at the end which I thought was quite nifty.
Class definition
I created a small class to hold the actual smoke tests (pardon my ruby, I’m learning):
class Smoketest
attr_accessor :description, :status, :message
def initialize(descr)
self.description = descr
end
def run
yield
end
def self.OK
"OK"
end
def self.FAIL
"FAIL"
end
end
These are called from the SmoketestController. I chose to just put all (well all two) smoke tests in the controller, but they could easily be distributed and put wherever you want. The controller methods looks like this:
require 'smoketest'
class SmoketestController < ApplicationController
def index
@tests = Array.new
mongodb_smoke_test
test_test
respond_to do |format|
format.html
format.xml { render :action => 'index.xml.haml',
:layout => false }
end
end
def test_test
test2 = Smoketest.new("Test")
test2.run {
test2.status = Smoketest.OK
}
@tests << test2
end
def mongodb_smoke_test
test = Smoketest.new("MongoDB test connection")
test.run {
begin
User.first
test.status = Smoketest.OK
rescue Exception => e
test.status = Smoketest.FAIL
test.message = e.message
end
}
@tests << test
end
end
The “test” one is just for making it more than one, and the mongoDB test tries to do a query and gives it and ok status if that works, and a fail with stack trace if somethings amiss. In a bigger application with more external systems, the number of smoke tests would go up. Running this, gives this nice web page for visual inspection:
(The layout is a bit wide since I wrapped in the standard layout for the app.)
The Junit output
I wanted the jenkins build job to track these smoke tests, which are being run as a build step after deployment. The easiest way to do this I figured was to make it spit out Junit XML format and let Jenkins chew on that. So a created an XML template like so:
%testsuite{:name => "smoketests", :failures => @tests.select { |x| x.status == "FAIL" }.count, :tests => @tests.count, :skipped => 0}
- @tests.each do |test|
%testcase{:name => test.description}
- if test.status != "OK"
%failure{:message => test.message}
And when fetching the url http://server/smoketest.xml you get the following output:
<testsuite failures="0" name="smoketests" skipped="0" tests="2">
<testcase name="MongoDB test connection"></testcase>
<testcase name="Test"></testcase>
</testsuite>
(It handles failures too).
The following small shell script is used to check the status:
#!/bin/bash
if [ -z "$1" ]
then
echo "usage: smoketest.sh <URL>"
exit 1
fi
status=`curl --silent --head $1 | head -1 | cut -f 2 -d' '`
if [ $status != "200" ]
then
echo "status was other than 200: was $status"
exit 1
fi
if [ ! -e "reports" ]
then
mkdir "reports"
fi
#put the xml version of the page into a file
curl --silent $1 > reports/smoke.xml
The shell scripts stores the file which is then read by Jenkins. Works like a charm!
Stay tuned for the third article on build pipelines where I explore some future possibilities when using a build pipeline.
blog comments powered by Disqus