DEV Community

Ari Kalfus
Ari Kalfus

Posted on • Originally published at blog.artis3nal.com on

Galaxy Collections Part 3: Integration Tests with Molecule

In part 3 of this series, we will look at how we can test Ansible Collections using the official Ansible test tool, Molecule. In part 1, we created a custom lookup plugin to interact with the GitHub Releases API. In part 2, we refactored this plugin into an Ansible Collection and used GitHub Actions to automatically deploy our collection to Ansible Galaxy.

This article will borrow heavily from Jeff Geerling's article on running Molecule tests on an Ansible Collection. I had to make some small changes to his described project layout in order to get Molecule working on my collection, which I will describe here. Additionally, I've created a GitHub Actions workflow to automate Molecule tests as part of CI.

Directory Structure

If you do not already have a collection you can find one in part 2 of my Galaxy Collections series or create one with ansible-galaxy collection init <namespace>.<name>. This will set up a collection in the format:

ansible-galaxy collection install artis3n.github 
Enter fullscreen mode Exit fullscreen mode
artis3n/
├── github/
│   ├── docs/
│   ├── plugins/
│   ├── roles/
│   └── README.md
│   └── galaxy.yml
Enter fullscreen mode Exit fullscreen mode

You should customize these files as required for your collection (again, you can find a sample setup in my other article).

Ansible-Required Directory Structure

In order for Molecule (well, Ansible) to find your collection and make it available for your tests your collection must exist at a path in the environment variable ANSIBLE_COLLECTIONS_PATHS. We will look at how to easily configure that for Molecule in a moment. However, Ansible has very strict requirements on the directory structure for each path in ANSIBLE_COLLECTIONS_PATHS. Each path must point to a directory with the following structure:

collections/
├── ansible_collections/
│   ├── artis3n/
│   │   ├── github/
│   ├── .../
Enter fullscreen mode Exit fullscreen mode

Ansible will only recognize collections if they exist in collections/ansible_collections/<namespaces>. You can pass specific plugins, roles, and modules to Ansible via environment variables such as ANSIBLE_LOOKUP_PLUGINS, however that would be very tedious for a whole collection, let alone multiple collections. The simplest thing to do is ansible-galaxy collection install collections and let Ansible install them to the default location: ~/.ansible/collections/ansible_collections/. For testing your own collection locally, you must place it underneath <some_path>/collections/ansible_collections and add <some_path> to ANSIBLE_COLLECTIONS_PATHS.

Molecule

We won't discuss every item you can/should configure when setting up Molecule as Jeff Geerling does a great job of this in his article mentioned above. Let's focus on the specific items we need to modify to get your local collection visible to your tests.

Set up Molecule for your collection with:

molecule init scenario
Enter fullscreen mode Exit fullscreen mode

This will create a default scenario under molecule/ in your project root. If you already have a default scenario for some reason you can install another scenario with:

molecule init scenario --scenario-name "<some-name>"
Enter fullscreen mode Exit fullscreen mode

Customize your Molecule configuration and tests as appropriate for your collection. For the following files, we will assume our present working directory is <project root>/molecule/default (or whatever scenario name you have chosen).

playbook.yml

In your playbook.yml file, replace the roles part with collections:


---
- name: Converge
  hosts: all

  collections:
    - artis3n.github
Enter fullscreen mode Exit fullscreen mode

You can then add a tasks section and add whatever Ansible tasks you want to execute to test your collection items. I suggest making use of Ansible's assert module. An example:

- name: latest_release | Get the version
  uri:
    url: https://api.github.com/repos/ansible/ansible/releases/latest
    headers:
      Accept: application/vnd.github.v3+json
    body_format: json
    return_content: yes
  register: ansible_release

- name: latest_release | Test the module
  assert:
    that:
      - lookup('artis3n.github.latest_release', 'ansible/ansible') == ansible_release.json.tag_name
Enter fullscreen mode Exit fullscreen mode

molecule.yml

Assuming you have set your collection underneath a collections/ansible_collections directory, the setup here is simple. Under the provisioners section, add the ANSIBLE_COLLECTIONS_PATHS environment variable. Add both your custom location and Ansible's default location, as our GitHub Actions workflow will use the default location to run in CI. Separate each path with a colon :.

provisioner:
  name: ansible
  lint:
    name: ansible-lint
  env:
    ANSIBLE_COLLECTIONS_PATHS: "~/.ansible/collections:~/Nextcloud/Development/collections"
Enter fullscreen mode Exit fullscreen mode

Running Molecule

Now running molecule test will pick up your collection. You should see the following in the converge section. The specific tests will be different, of course, depending on what you add to your playbook.yml:

--> Scenario: 'default'
--> Action: 'converge'
[WARNING]: running playbook inside collection artis3n.github


    PLAY [Converge] ****************************************************************

    TASK [Gathering Facts] *********************************************************
    ok: [instance]

    TASK [latest_release | Get the version] ****************************************
    ok: [instance]

    TASK [latest_release | Test the module] ****************************************
    ok: [instance] => {
        "changed": false,
        "msg": "All assertions passed"
    }

    PLAY RECAP *********************************************************************
    instance                   : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
Enter fullscreen mode Exit fullscreen mode

Notably, we see [WARNING]: running playbook inside collection artis3n.github means that Molecule has successfully read in our collection.

Running Molecule from GitHub Actions

We can easily have a GitHub Actions workflow run our tests on every pull request, push, or whatever other CI workflow we desire. Here we see a workflow running on every push:

name: Molecule Tests

on: [push]

jobs:
  molecule:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: Set up Python 3
      uses: actions/setup-python@v1
      with:
        python-version: '3.x'
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install ansible docker 'molecule[docker]'

    - name: Move project to Ansible-required location
      run: |
        mkdir -p ~/.ansible/collections/ansible_collections/artis3n/github
        cp -r ./ ~/.ansible/collections/ansible_collections/artis3n/github

    - name: Molecule test
      run: |
        molecule test
Enter fullscreen mode Exit fullscreen mode

The import points are installing our molecule dependencies:

pip install ansible docker 'molecule[docker]'
Enter fullscreen mode Exit fullscreen mode

And moving our custom collection to Ansible's default collection path:

mkdir -p ~/.ansible/collections/ansible_collections/artis3n/github
cp -r ./ ~/.ansible/collections/ansible_collections/artis3n/github
Enter fullscreen mode Exit fullscreen mode

Then we can run our tests with molecule test. We can push a new PR to our GitHub repo and see the action workflow test our code:

Molecule running in GitHub Actions workflow

We can now test our custom collection locally and ensure all changes run through CI.

Top comments (0)