Thursday, September 4, 2014

Clean assertion tests in bash

You've likely seen test tools like spec, rspec, and the like, where the tests are written like:

describe package('httpd') do it { should be_installed } end

Recently, I had the need to test guest images using simple assertion tests, like checking for options in sshd_config, or if a package was installed. I initially looked at serverspec which looks like a nice tool, but it seemed to require that my image be a running instance for an ssh session to run the tests.

I figured I could check all these things in a bash chroot environment.

Previously, when running tests, I'd always check for exit status, for example:

grep -q UTC /etc/localtime
if [ $? -ne 0 ]; then
  echo "Failed"
  exit 1
else
  echo "OK"
fi

This seemed like a really tedious thing to keep up as the number of tests increased. Thankfully bash is more and more powerful than most people give it credit for.

Enter traps
I created a generic function for handling errors and successes of tests, and use `trap` to execute those functions based on the signals received. This makes writing tests very easy. More tests means better end products.

function error_exit() {
  echo -e "\E[31mTest $TEST failed\E[0m"
  exit 1
}
function success_exit() {
  echo -e "\E[32m $TEST OK\E[0m"
}

trap "error_exit" ERR
trap "success_exit" SIGCHLD

TEST="Check for UTC timezone"
grep -q UTC /etc/localtime

TEST="Check for cloud-user"
grep -q cloud-user /etc/cloud/cloud.cfg

TEST="Check for no password auth"
grep PasswordAuthentication /etc/ssh/sshd_config | grep -qi no

TEST="Check for puppet client"
which puppet

That's it! Simple. I just set the value of $TEST to a nice descriptive name, and let the traps figure out if the test succeeded or failed. Color output added for a nice extra touch.

No comments:

Post a Comment