Now that we have created our basic role in part 1, we need to set-up a Vagrant machine and some tooling to run our tests.
Creating the Vagrant machine
Vagrantfile
To spin up a Vagrant machine, we need to create a Vagrantfile
. We’ll create it in our role top directory:
Vagrant.configure(2) do |config|
config.vm.box = "ubuntu/trusty64"
config.vm.define "nginx" do |nginx|
end
config.vm.provision "shell",
:path => "vagrant_specs.sh",
:upload_path => "/home/vagrant/specs",
# change role name below
:args => "--install ansible-nginx"
end
You can change config.vm.box
to another Vagrant box that better suits your
needs, but keep in mind RoleSpec is very Debian/Ubuntu inclined. We’ll provision
this machine with a shell script (not with Ansible, so we don’t end up in an
inception style situation).
Provisionning script
The provisionning script, vagrant_specs.sh
serves two purposes:
-
it takes care of installing RoleSpec and setting up the test directory when called with
--install
. This happens only at vagrant provisionning time (e.g.vagrant up
ofvagrant provision
) -
it can be called to run the test suite; to make invocation easier, it will copy itself to
/usr/local/bin/specs
Create the vagrant_specs.sh
with the following content:
#!/bin/bash
#
# Vagrant provisionning script
#
# Usage for provisionning VM & running (in Vagrant file):
#
# script.sh --install <role>
#
# e.g. :
# script.sh --install ansible-nginx
#
# Usage for running only (from host):
#
# vagrant ssh -c specs
#
if [ "x$1" == "x--install" ]; then
mv ~vagrant/specs /usr/local/bin/specs
chmod 755 /usr/local/bin/specs
sudo apt-get install -qqy git
su vagrant -c 'git clone --depth 1 https://github.com/nickjj/rolespec'
cd ~vagrant/rolespec && make install
su vagrant -c 'rolespec -i ~/testdir'
su vagrant -c "ln -s /vagrant/ ~/testdir/roles/$2"
su vagrant -c "ln -s /vagrant/tests/$2/ ~/testdir/tests/"
exit
fi
cd ~vagrant/testdir && rolespec -r $(ls roles) "$*"
and make it executable (chmod +x vagrant_specs.sh
).
Running the Vagrat box
Now, let’s check this ! It might take a while if you don’t already have the vagrant image on your box:
$ vagrant up
Bringing machine 'nginx' up with 'virtualbox' provider...
==> nginx: Importing base box 'ubuntu/trusty64'...
==> nginx: Matching MAC address for NAT networking...
==> nginx: Checking if box 'ubuntu/trusty64' is up to date...
==> nginx: Setting the name of the VM: ansible-nginx_nginx_1426331325901_88232
...
==> nginx: Cloning into 'rolespec'...
==> nginx: Installing RoleSpec scripts in /usr/local/bin ...
==> nginx: Installing RoleSpec libs in /usr/local/lib/rolespec ...
==> nginx: Initialized new RoleSpec directory in /home/vagrant/testdir
$
Creating tests
We’re almost done. Only two files left to create. First, we RoleSpec needs an inventory. Nothing fancy here, we just need to create an inventory file with a single host, placeholder_fqdn
, RoleSpec will take care of the rest:
$ echo "placeholder_fqdn" > tests/ansible-nginx/inventory/hosts
Writing the test file
And finally, we need a test file, where we can check if our playbook works. We can check the syntax, the idempotency, the resulting templates, etc…
This test file is simply a bash script, in which we include some RoleSpec files to get access to its DSL.
Let’s start with a simple one, and create tests/ansible-nginx/test
with the following content:
#!/bin/bash
# -*- bash -*-
# This gives you access to the custom DSL
. "${ROLESPEC_LIB}/main"
# Install a specific version of Ansible
install_ansible "v1.8.3"
# Check syntax first, and then that the playbook runs
assert_playbook_runs
# Check that the playbook is idempotent
assert_playbook_idempotent
Don’t forget to make the test file executable (chmod +x tests/ansible-nginx/test
).
Runing tests
Our simple tests are setup. To run them, we need to execute
/usr/local/bin/specs
in the Vagrant host.
vagrant ssh -c 'specs'
RoleSpecs will then download Ansible (version 1.8.3 since this is what we asked for), install it, and run our test case.
As you can see in the recording, RoleSpec:
- installs Ansible (
ROLESPEC: [Install Ansible - v1.8.3]
) - executes the playbook with
assert_playbook_runs
(TEST: [Run playbook syntax check]
andTEST: [Run playbook]
) - check that the playbook is idempotent with
assert_playbook_idempotent
(TEST: [Re-run playbook]
)
Pretty neat !
Runing tests faster
There is one downside though: it takes almost 3 minutes to run. However, you can
speed up subsequent runs as long as you don’t have to change the Ansible
version: since Ansible is already installed, there is no need to install it
again every time. Using the -p
option will run in playbook mode, which means
it will only run assert_playbook_runs
test.
vagrant ssh -c 'specs'
25 seconds only, we cut the runtime by six, not bad.
Local continuous integration
Now that we have reasonable playbook test run time, we can add local continuous integration to our setup. We will use Guard for this.
Assuming you have a ruby environment setup, just install guard
and guard-shell
gems.
gem install guard guard-shell --no-ri --no-rdoc
Then create a Guardfile
in the roles top directory, with the following content:
# -- -*- mode: ruby; -*-
guard :shell do
watch(%r{^(?!tests).*/.*\.yml$}) do |m|
puts "#{m[0]} changed - running tests"
system('vagrant ssh -c "specs -p"')
end
end
This file will ask guard
to execute vagrant ssh -c "specs -p"
everytime it
detects a change in a file ending with .yml
in the project’s subdirectories.
Note that we excluded the tests
directory since it contains somewhere a
test.yml
playbook file generated by RoleSpec at run time. If we don’t exclude
it from the guard watch, the test will loop forever.
Now run guard
, change a file (.e.g. touch tasks/main.yml
), and see what happens.
In the next part, we will add some more tests, and see what we can do with RoleSpec.
comments powered by Disqus