Tuesday, September 2, 2008

Test Driven Deployment

Let me start by saying the I think TDD is the best way to develop quality software. It helps you develop a rhythm, keeps you focused, and has the nice side effect of leaving your application surrounded by unit tests. I have always felt uncomfortable doing work in environments where the rhythm of TDD was not possible. Lately, I have been feeling this pain while developing deployment scripts for a rails application.

Utilizing the power of capistrano, Paul and I came up with a rather novel way to test that our deployment scripts were working.

namespace :verify do

task :mongrels, :roles => :app do
(0...mongrel_count).each do |port_offset|
assert_status_code '200', "http://localhost:#{mongrel_port + port_offset}/pulse"
end
end

task :ha_proxy, :roles => :app do
assert_status_code '200', "http://localhost:#{proxy_port}/pulse"
end

task :apache, :roles => :app do
assert_status_code '200', "http://localhost:#{apache_port}/monit/token"
end
end

def assert_status_code expected, url
assert_equal expected, %{curl -s -o /dev/null -w '%{http_code}' #{url} }
end

def assert_equal expected, command
errors = []
run command do |ssh_channel, stream, output|
errors << "Expected: #{expected} but was #{output} on #{ssh_channel.connection.host}" unless output == expected
end
raise "Errors on servers: \n #{errors.join("\n ")}\n\n" unless errors.empty?
end

We then execute these 'verify' tasks after the deploy task has completed.

after :deploy do
verify.mongrels
verify.ha_proxy
verify.apache
end

More on this later!

No comments: