neillturner/kitchen-ansible — pull request #3 by trinitronx (2014-09-05 14:40:14+00:00)
Title: Add support for testing roles

Hello again @neillturner,

In response to my own issue/feature request in #2, I've managed to develop a working proof of concept for testing roles!

I'm using a common pattern borrowed from Chef cookbook development where a wrapper/test-harness cookbook is created in order to test another cookbook or LWRP. In this pattern, a folder structure is created under `test/integration/` where a `cookbooks` directory is placed containing a wrapper cookbook for use in order to run integration tests for one cookbook with other cookbooks, or to test LWRPs defined within the cookbook. For example, the [lsyncd cookbook][1] has an example of this in [`test/fixtures/cookbooks/lsyncd_test`][2], and uses the [`Berksfile`][3] to download this cookbook to a `cookbooks` directory inside the `sandbox_path` before copying it inside the VM. This may be a useful pattern to follow in the future for installing other Ansible role dependencies (e.g.: with an `Ansiblefile` and `librarian-ansible`, or other Bundler-like tool for installing roles from Ansible Galaxy).

My current implementation for testing a single role simply leverages the `calculate_paths` method to resolve the `roles_path` to the current working directory (e.g.: If I'm working on the `foobar` role, I'll be in a top-level directory called "`foobar`" which needs to be copied into the `sandbox_path` under 'roles', and then into the VM under `/tmp/kitchen/roles/foobar`. It expects a directory structure under `test/integration/default/ansible` to contain a basic wrapper playbook called `site.yml` by default, and optionally `hosts`, `modules`, `host_vars`, and `group_vars` too. These all get copied to the `sandbox_path` first and then end up inside the test-kitchen VM under the `kitchen_root` (`/tmp/kitchen/`). The `ansible.cfg` is generated to point the `roles_path` at `/tmp/kitchen/roles`. Finally, `Kitchen::Provisioner::AnsiblePlaybook#run_command` kicks off `ansible-playbook` and points it at the `site.yml` playbook under `/tmp/kitchen/`.

For example, my role directory structure for a `foobar` role would look like:

~/src/ansible/roles/foobar
├── README.md
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── tasks
│ └── main.yml
├── templates
├── test
│ └── integration
│ └── default
│ ├── ansible
│ │ ├── group_vars
│ │ ├── host_vars
│ │ ├── hosts
│ │ ├── modules
│ │ └── site.yml
│ └── serverspec
│ └── foobar_spec.rb
└── vars
└── main.yml

A basic wrapper `site.yml` file might look like:

---
# This playbook deploys the foobar role for testing

- hosts: test-kitchen
user: root

roles:
- foobar

The directory structure copied into `/tmp/kitchen` looks like:

/tmp/kitchen/
├── ansible.cfg
├── group_vars
├── hosts
├── host_vars
├── modules
├── roles
│ └── foobar
│ ├── defaults
│ │ └── main.yml
│ ├── files
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ │ └── main.yml
│ ├── README.md
│ ├── tasks
│ │ └── main.yml
│ ├── templates
│ ├── test
│ │ └── integration
│ │ └── default
│ │ ├── ansible
│ │ │ ├── group_vars
│ │ │ ├── hosts
│ │ │ ├── host_vars
│ │ │ ├── modules
│ │ │ └── site.yml
│ │ └── serverspec
│ │ └── foobar_spec.rb
│ └── vars
│ └── main.yml
└── site.yml

One thing I wasn't sure about was [this section of Kitchen::Provisioner::AnsiblePlaybook#prepare_command][4]. My initial instinct is to want to clean this up by only copying what's absolutely necessary to `/etc/ansible`, which would probably be just `ansible.cfg`; and therefore simply just add settings to `ansible.cfg` that point to appropriate paths in `/tmp/kitchen` for `group_vars`, and `host_vars`. However, I've left things as they are for now. I have been told that `ansible-playbook` figures out the paths for those by using the same directory that is passed for the inventory host file via `-i`. So having them in two places isn't necessarily bad at the moment, but we may want to clean that up so they only live in `/tmp/kitchen`.

Let me know what you think of this implementation of test-kitchen within roles!

[1]: https://github.com/dgivens/chef-lsyncd
[2]: https://github.com/dgivens/chef-lsyncd/tree/master/test/fixtures/cookbooks/lsyncd_test
[3]: https://github.com/dgivens/chef-lsyncd/blob/master/Berksfile
[4]: https://github.com/neillturner/kitchen-ansible/blob/master/lib/kitchen/provisioner/ansible_playbook.rb#L214-227