Monday, September 8, 2014

Updated bash testing suite

As a followup to last week's testing post I wanted to expand from a test script, to a testing suite.

Anyone familiar with TDD will often see something like a `tests` directory and a simple `run_tests` script. I wanted to do this in bash.

Using the same style trapping as before, with a simple change, we can achieve a nice result.

#!/usr/local/bin/bash
set -o pipefail

# Begin tests

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" RETURN

for i in `ls tests/*`; do
  source $i
done

Any file in the tests directory will be evaluated and the results will be reported through the run_tests script
Here's some sample tests:

ls tests/
01-file.sh 02-cows
looking at tests/01-file.sh
export TEST="File exists"
find . -name file &>/dev/null
looking at tests/02-cows:
export TEST="File has cows"
grep -q cows file

Super simple, no shebang interpreter needed, not even an executable file. All we need is to set the value of $TEST to something meaningful. Here's what the test run looks like:


 $ ./run_tests.sh 
 File exists OK

Test File has cows failed

Lets see what's wrong with this...
cat file 
Cows

Ah... wrong case, lets fix that:
 cat file 
cows
$ ./run_tests.sh 
 File exists OK
 File has cows OK

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.

Thursday, July 3, 2014

Ceph cluster in Vagrant

Working on creating a 3-node ceph cluster in Vagrant...
This allows for a real quick-and-dirty development environment that can be used either 'as-is' PoC, or integrated with devstack.

https://github.com/alop/vagrant-ceph