From d7656c8168cc24d407714f6e94e8b94b451706d9 Mon Sep 17 00:00:00 2001
From: Adar Nimrod <nimrod@shore.co.il>
Date: Mon, 10 Jul 2017 13:10:10 +0300
Subject: [PATCH] - Run tests from Tox, use generated environments. - Run tests
 in TravisCI on multiple Ansible, Python versions and OSes. - Create Docker
 container with Ansible. - Split tests to seperate files. - Moved everything
 test related to tests/ . - Update pre-commit hooks. - Merge .flake8 to
 tox.ini. - Added shellcheck hook. - Fixed issues found by shellcheck. -
 Updated README (added usage, testing sections).

---
 .flake8                 |  2 -
 .gitignore              |  1 +
 .pre-commit-config.yaml | 15 ++++---
 .travis.yml             | 44 ++++++++++++++-----
 README.rst              | 12 ++++-
 ansible.cfg             |  3 --
 collectd/collectd_facts |  3 +-
 nginx/nginx_facts       |  3 +-
 playbook.yml            | 97 -----------------------------------------
 ssl/dhparams            |  4 +-
 tests/ansible.cfg       |  5 +++
 tests/collectd.yml      | 23 ++++++++++
 tests/nginx.yml         | 23 ++++++++++
 tests/playbook.yaml     | 54 +++++++++++++++++++++++
 tests/requirements.yaml |  3 ++
 tests/roles/.gitkeep    |  0
 tests/ssl.yml           | 44 +++++++++++++++++++
 tox.ini                 | 40 +++++++++++++++++
 18 files changed, 253 insertions(+), 123 deletions(-)
 delete mode 100644 .flake8
 delete mode 100644 ansible.cfg
 delete mode 100644 playbook.yml
 create mode 100644 tests/ansible.cfg
 create mode 100644 tests/collectd.yml
 create mode 100644 tests/nginx.yml
 create mode 100644 tests/playbook.yaml
 create mode 100644 tests/requirements.yaml
 create mode 100644 tests/roles/.gitkeep
 create mode 100644 tests/ssl.yml
 create mode 100644 tox.ini

diff --git a/.flake8 b/.flake8
deleted file mode 100644
index 1517767..0000000
--- a/.flake8
+++ /dev/null
@@ -1,2 +0,0 @@
-[flake8]
-exclude = ldap/ldap_attr.py
diff --git a/.gitignore b/.gitignore
index fc64061..2a7d2ce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@
 *~
 ~*
 *.pyc
+tests/roles
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 40017a3..8986c29 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,21 +1,24 @@
 -   repo: git://github.com/pre-commit/pre-commit-hooks
-    sha: 97b88d9610bcc03982ddac33caba98bb2b751f5f
+    sha: v0.8.0
     hooks:
     -   id: check-added-large-files
     -   id: check-yaml
     -   id: check-merge-conflict
     -   id: flake8
 -   repo: https://github.com/adarnimrod/shell-pre-commit
-    sha: v0.1.0
+    sha: v0.5.4
     hooks:
     -   id: shell-lint
-        files: collectd/collectd_facts|nginx/nginx_facts|ssl/dhparams
+        files: &shellscripts collectd/collectd_facts|nginx/nginx_facts|ssl/dhparams
+    -   id: shellcheck
+        files: *shellscripts
 -   repo: https://github.com/adarnimrod/ansible-pre-commit.git
-    sha: v0.4.0
+    sha: v0.6.0
     hooks:
     -   id: ansible-syntax-check
+        files: &playbook tests/playbook.yaml
 -   repo: https://github.com/willthames/ansible-lint
-    sha: 959ab0f525e9abb19cf75f34381015cf33695f61
+    sha: v3.4.13
     hooks:
     -   id: ansible-lint
-        files: playbook.yml
+        files: *playbook
diff --git a/.travis.yml b/.travis.yml
index 9287db9..1073338 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,28 +1,50 @@
 ---
 language: python
-python: "2.7"
+python:
+    - "2.7"
 dist: trusty
 sudo: false
-services: [docker]
+services:
+    - docker
+group: beta
 cache:
   - pip
   - directories:
       - $HOME/.pre-commit
 
 env:
-  - DOCKER=ubuntu:trusty
-  - DOCKER=ubuntu:xenial
-  - DOCKER=debian:jessie
+- TOXENV: pre-commit
+- TOXENV: ansible2.3.1.0-image_ubuntu_xenial
+- TOXENV: ansible2.3.1.0-image_ubuntu_trusty
+- TOXENV: ansible2.3.1.0-image_ubuntu_precise
+- TOXENV: ansible2.3.1.0-image_debian_stretch
+- TOXENV: ansible2.3.1.0-image_debian_jessie
+- TOXENV: ansible2.3.1.0-image_debian_wheezy
+- TOXENV: ansible2.2.3.0-image_ubuntu_xenial
+- TOXENV: ansible2.2.3.0-image_ubuntu_trusty
+- TOXENV: ansible2.2.3.0-image_ubuntu_precise
+- TOXENV: ansible2.2.3.0-image_debian_stretch
+- TOXENV: ansible2.2.3.0-image_debian_jessie
+- TOXENV: ansible2.2.3.0-image_debian_wheezy
+- TOXENV: ansible2.1.6.0-image_ubuntu_xenial
+- TOXENV: ansible2.1.6.0-image_ubuntu_trusty
+- TOXENV: ansible2.1.6.0-image_ubuntu_precise
+- TOXENV: ansible2.1.6.0-image_debian_stretch
+- TOXENV: ansible2.1.6.0-image_debian_jessie
+- TOXENV: ansible2.1.6.0-image_debian_wheezy
+- TOXENV: ansible2.0.2.0-image_ubuntu_xenial
+- TOXENV: ansible2.0.2.0-image_ubuntu_trusty
+- TOXENV: ansible2.0.2.0-image_ubuntu_precise
+- TOXENV: ansible2.0.2.0-image_debian_stretch
+- TOXENV: ansible2.0.2.0-image_debian_jessie
+- TOXENV: ansible2.0.2.0-image_debian_wheezy
 
 install:
-  - pip install pre_commit ansible | cat
-
-before_script:
-  - docker run --detach --name $(echo $DOCKER | sed 's/:/_/g') $DOCKER tail -f /.dockerenv
+  - pip install tox-travis | cat
 
 script:
-  - pre-commit run --all-files
-  - ansible-playbook -i $(echo $DOCKER | sed 's/:/_/g'), -c docker -vv playbook.yml
+  - tox
 
 notifications:
   email: false
+  on_failure: never
diff --git a/README.rst b/README.rst
index ae74c91..3c083ea 100644
--- a/README.rst
+++ b/README.rst
@@ -35,6 +35,11 @@ Modules
 - nginx_facts
 - dhparams
 
+Usage
+-----
+
+See example usage in the test playbooks under :code:`tests/`.
+
 License
 -------
 
@@ -44,7 +49,12 @@ This software is licensed under the AGPL v3+ license (see the
 Testing
 -------
 
-Currently the only tests are `pre-commit <http://www.pre-commit.com/>`_ hooks.
+Modules are tested on Ubuntu Precise, Trusty and Xenial and Debian Wheezy,
+Jessie and Stretch with Ansible version 2.0.2.0, 2.1.6.0, 2.2.3.0 and 2.3.1.0
+in `TravisCI <https://travis-ci.org/adarnimrod/ansible-modules>`_. To tests
+require `Tox <https://tox.readthedocs.io/>`_ and `Docker
+<https://docker.com>`_. `Pre-commit <http://pre-commit.com/>`_ is also setup
+for this project.
 
 Author
 ------
diff --git a/ansible.cfg b/ansible.cfg
deleted file mode 100644
index b6d3a7e..0000000
--- a/ansible.cfg
+++ /dev/null
@@ -1,3 +0,0 @@
-[defaults]
-library = ./
-host_key_checking = False
diff --git a/collectd/collectd_facts b/collectd/collectd_facts
index 680a42e..67151eb 100755
--- a/collectd/collectd_facts
+++ b/collectd/collectd_facts
@@ -1,4 +1,5 @@
 #!/bin/sh -e
+# shellcheck disable=SC1090
 . "$1"
 
 fail ()
@@ -7,6 +8,6 @@ fail ()
     exit
 }
 
-which collectd 2>&1 > /dev/null || fail "Can't find collectd executable."
+which collectd > /dev/null 2>&1 || fail "Can't find collectd executable."
 
 collectd -h 2>&1 | sed -n 's/[a-zA-Z ]*\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/{"changed": false, "ansible_facts": {"collectd": {"major":\1, "minor":\2, "patch":\3, "version":"\1.\2.\3"}}}/p'
diff --git a/nginx/nginx_facts b/nginx/nginx_facts
index 1c37c9b..7e1da37 100755
--- a/nginx/nginx_facts
+++ b/nginx/nginx_facts
@@ -1,4 +1,5 @@
 #!/bin/sh -e
+# shellcheck disable=SC1090
 . "$1"
 
 fail ()
@@ -7,6 +8,6 @@ fail ()
     exit
 }
 
-which nginx 2>&1 > /dev/null || fail "Can't find nginx executable."
+which nginx > /dev/null 2>&1 || fail "Can't find nginx executable."
 
 nginx -v 2>&1 | sed -n 's/[a-zA-Z :\/]*\([0-9]*\)\.\([0-9]*\)\.\([0-9]\)*.*$/{"changed": false, "ansible_facts": {"nginx": {"major":\1, "minor":\2, "patch":\3, "version":"\1.\2.\3"}}}/gp'
diff --git a/playbook.yml b/playbook.yml
deleted file mode 100644
index 64b98b3..0000000
--- a/playbook.yml
+++ /dev/null
@@ -1,97 +0,0 @@
----
-- hosts: all
-  gather_facts: False
-  tasks:
-  - name: Update APT sources
-    raw: DEBIAN_FRONTEND=noninteractive apt-get update
-    changed_when: False
-
-  - name: APT install Python
-    raw: DEBIAN_FRONTEND=noninteractive apt-get install -qy python2.7 python
-    register: debian_bootstrap_install_python
-    changed_when: "'Unpacking' in debian_bootstrap_install_python.stdout"
-
-  - name: Gather facts
-    setup:
-
-  - name: APT install
-    apt:
-      name: ['nginx-light', 'collectd-core', 'openssl']
-      state: present
-      install_recommends: no
-
-  - name: Collectd facts
-    collectd_facts:
-    register: collectd_facts
-
-  - name: Debug
-    debug:
-      var: collectd_facts
-      verbosity: 2
-
-  - name: Assertions
-    assert:
-      that:
-      - collectd_facts|changed == False
-      - collectd.major is number
-      - collectd.minor is number
-      - collectd.patch is number
-      - collectd.version is defined
-
-  - name: Nginx facts
-    nginx_facts:
-    register: nginx_facts
-
-  - name: Debug
-    debug:
-      var: nginx_facts
-      verbosity: 2
-
-  - name: Assertions
-    assert:
-      that:
-      - nginx_facts|changed == False
-      - nginx.major is number
-      - nginx.minor is number
-      - nginx.patch is number
-      - nginx.version is defined
-
-  - name: DH params for missing file
-    ignore_errors: True
-    dhparams:
-      path: /etc/ssl/dhparams.pem
-    register: missing_dhparams
-
-  - name: Debug
-    debug:
-      var: missing_dhparams
-      verbosity: 2
-
-  - name: Assertions
-    assert:
-      that:
-      - missing_dhparams.bits == 0
-      - missing_dhparams|failed == True
-      - missing_dhparams|changed == False
-
-  - name: Generate DH params
-    command: openssl dhparam -out /etc/ssl/dhparams.pem 2048
-    changed_when: True
-
-  - name: DH params for existing file
-    dhparams:
-      path: /etc/ssl/dhparams.pem
-    register: existing_dhparams
-
-  - name: Debug
-    debug:
-      var: existing_dhparams
-      verbosity: 2
-
-  - name: Assertions
-    assert:
-      that:
-      - existing_dhparams.bits == 2048
-      - existing_dhparams|failed == False
-      - existing_dhparams|changed == False
-      - existing_dhparams.path == '/etc/ssl/dhparams.pem'
diff --git a/ssl/dhparams b/ssl/dhparams
index 277936c..c50a1b8 100755
--- a/ssl/dhparams
+++ b/ssl/dhparams
@@ -1,4 +1,5 @@
 #!/bin/sh -e
+# shellcheck disable=SC1090
 . "$1"
 
 fail ()
@@ -7,11 +8,12 @@ fail ()
     exit
 }
 
+# shellcheck disable=SC2154
 test -z "$path" && fail "Parameter 'path' is not set."
 test ! -r "$path" && fail "Can't access 'path'."
 test ! -f "$path" && fail "Parameter 'path' doesn't exists or is not a file."
 
-bits="$(openssl dhparam -in $path -text -noout \
+bits="$(openssl dhparam -in "$path" -text -noout \
     | sed -n 's/[a-zA-Z#0-9 \-]*Parameters: (\([0-9]*\) bit)/\1/p')"
 
 echo "{ \"changed\": false, \"path\": \"$path\", \"bits\": $bits }"
diff --git a/tests/ansible.cfg b/tests/ansible.cfg
new file mode 100644
index 0000000..3e039f0
--- /dev/null
+++ b/tests/ansible.cfg
@@ -0,0 +1,5 @@
+[defaults]
+library = ../
+host_key_checking = False
+roles_path = ./roles/
+callback_whitelist = profile_tasks
diff --git a/tests/collectd.yml b/tests/collectd.yml
new file mode 100644
index 0000000..325bdd0
--- /dev/null
+++ b/tests/collectd.yml
@@ -0,0 +1,23 @@
+---
+- name: APT install
+  apt:
+    name: collectd-core
+    state: latest
+    install_recommends: no
+
+- name: Collectd facts
+  collectd_facts:
+  register: collectd_facts
+
+- name: Debug
+  debug:
+    var: collectd_facts
+
+- name: Assertions
+  assert:
+    that:
+    - collectd_facts|changed == False
+    - collectd.major is number
+    - collectd.minor is number
+    - collectd.patch is number
+    - collectd.version is defined
diff --git a/tests/nginx.yml b/tests/nginx.yml
new file mode 100644
index 0000000..946bad7
--- /dev/null
+++ b/tests/nginx.yml
@@ -0,0 +1,23 @@
+---
+- name: APT install
+  apt:
+    name: nginx-light
+    state: latest
+    install_recommends: no
+
+- name: Nginx facts
+  nginx_facts:
+  register: nginx_facts
+
+- name: Debug
+  debug:
+    var: nginx_facts
+
+- name: Assertions
+  assert:
+    that:
+    - nginx_facts|changed == False
+    - nginx.major is number
+    - nginx.minor is number
+    - nginx.patch is number
+    - nginx.version is defined
diff --git a/tests/playbook.yaml b/tests/playbook.yaml
new file mode 100644
index 0000000..f69f178
--- /dev/null
+++ b/tests/playbook.yaml
@@ -0,0 +1,54 @@
+---
+- hosts: localhost
+  connection: local
+  gather_facts: False
+  become: False
+  tasks:
+      - name: Assertion
+        assert:
+            that:
+                - distro is defined
+                - release is defined
+
+      - name: Remove existing Docker container
+        # Use the command module instead of docker/ docker-container for
+        # consistency across different versions of Ansible.
+        command: 'docker rm -f ansible_modules_{{ distro }}_{{ release }}'
+        register: docker_rm
+        failed_when: "docker_rm|failed and 'no such container' not in docker_rm.stderr|lower"
+        changed_when: "'no such container' not in docker_rm.stderr|lower"
+
+      - name: Create Docker container
+        # Use the command module instead of docker/ docker-container for
+        # consistency across different versions of Ansible.
+        command: 'docker run --detach --name ansible_modules_{{ distro }}_{{ release }} {{ distro }}:{{ release }} tail -f /.dockerenv'
+        changed_when: True
+
+      - name: Add Docker container to inventory
+        add_host:
+            name: 'ansible_modules_{{ distro }}_{{ release }}'
+            ansible_connection: docker
+            ansible_user: root
+            groups: containers
+
+- hosts: containers
+  gather_facts: False
+  roles:
+      - name: debian-bootstrap
+  post_tasks:
+  - name: Include test tasks
+    with_fileglob: '{{ playbook_dir }}/*.yml'
+    include: '{{ item }}'
+
+- hosts: localhost
+  connection: local
+  become: False
+  gather_facts: False
+  tasks:
+      - name: Remove existing Docker container
+        # Use the command module instead of docker/ docker-container for
+        # consistency across different versions of Ansible.
+        command: 'docker rm -f ansible_modules_{{ distro }}_{{ release }}'
+        register: docker_rm
+        failed_when: "docker_rm|failed and 'no such container' not in docker_rm.stderr|lower"
+        changed_when: "'no such container' not in docker_rm.stderr|lower"
diff --git a/tests/requirements.yaml b/tests/requirements.yaml
new file mode 100644
index 0000000..e396834
--- /dev/null
+++ b/tests/requirements.yaml
@@ -0,0 +1,3 @@
+---
+- src: adarnimrod.debian-bootstrap
+  name: debian-bootstrap
diff --git a/tests/roles/.gitkeep b/tests/roles/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/tests/ssl.yml b/tests/ssl.yml
new file mode 100644
index 0000000..98beeee
--- /dev/null
+++ b/tests/ssl.yml
@@ -0,0 +1,44 @@
+---
+- name: APT install
+  apt:
+    name: openssl
+    state: latest
+    install_recommends: no
+
+- name: DH params for missing file
+  ignore_errors: True
+  dhparams:
+    path: /etc/ssl/dhparams.pem
+  register: missing_dhparams
+
+- name: Debug
+  debug:
+    var: missing_dhparams
+
+- name: Assertions
+  assert:
+    that:
+    - missing_dhparams.bits == 0
+    - missing_dhparams|failed == True
+    - missing_dhparams|changed == False
+
+- name: Generate DH params
+  command: openssl dhparam -out /etc/ssl/dhparams.pem 2048
+  changed_when: True
+
+- name: DH params for existing file
+  dhparams:
+    path: /etc/ssl/dhparams.pem
+  register: existing_dhparams
+
+- name: Debug
+  debug:
+    var: existing_dhparams
+
+- name: Assertions
+  assert:
+    that:
+    - existing_dhparams.bits == 2048
+    - existing_dhparams|failed == False
+    - existing_dhparams|changed == False
+    - existing_dhparams.path == '/etc/ssl/dhparams.pem'
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..65336ca
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,40 @@
+[tox]
+skip_install = True
+skipsdist = True
+envlist = ansible{2.3.1.0,2.2.3.0,2.1.6.0,2.0.2.0}-image_{ubuntu_xenial,ubuntu_trusty,ubuntu_precise,debian_stretch,debian_jessie,debian_wheezy}, pre-commit
+
+[testenv]
+basepython = python2.7
+deps =
+    ansible2.3.1.0: ansible==2.3.1.0
+    ansible2.2.3.0: ansible==2.2.3.0
+    ansible2.1.6.0: ansible==2.1.6.0
+    ansible2.0.2.0: ansible==2.0.2.0
+    docker-py>=1.7.0
+passenv = TERM HOME VBOX* ANSIBLE_*
+setenv =
+    ANSIBLE_VERBOSITY=2
+changedir = {toxinidir}/tests/
+commands =
+    ansible-galaxy install -r requirements.yaml
+    image_ubuntu_xenial:  ansible-playbook playbook.yaml -e "distro=ubuntu release=xenial"  -i localhost, {posargs}
+    image_ubuntu_trusty:  ansible-playbook playbook.yaml -e "distro=ubuntu release=trusty"  -i localhost, {posargs}
+    image_ubuntu_precise: ansible-playbook playbook.yaml -e "distro=ubuntu release=precise" -i localhost, {posargs}
+    image_debian_stretch: ansible-playbook playbook.yaml -e "distro=debian release=stretch" -i localhost, {posargs}
+    image_debian_jessie:  ansible-playbook playbook.yaml -e "distro=debian release=jessie"  -i localhost, {posargs}
+    image_debian_wheezy:  ansible-playbook playbook.yaml -e "distro=debian release=wheezy"  -i localhost, {posargs}
+
+[testenv:pre-commit]
+deps =
+    pre-commit
+    ansible
+passenv = TERM HOME VBOX* ANSIBLE_*
+setenv =
+    ANSIBLE_ROLES_PATH={toxinidir}/tests/roles
+changedir = {toxinidir}/
+commands =
+    ansible-galaxy install -r tests/requirements.yaml
+    pre-commit run --all-files
+
+[flake8]
+exclude = ldap/ldap_attr.py
-- 
GitLab