From 315f93c09a0a43a0e686713d46bb44c2e0d366ed Mon Sep 17 00:00:00 2001
From: Sergio Oliveira Campos <seocam@redhat.com>
Date: Mon, 18 May 2020 17:43:08 -0300
Subject: [PATCH] Added pytests as test entrypoint

---
 pytest.ini                  |  2 +
 tests/README.md             | 54 +++++++++++++++++++++++
 tests/ansible.cfg           |  5 +++
 tests/test_playbook_runs.py | 87 +++++++++++++++++++++++++++++++++++++
 4 files changed, 148 insertions(+)
 create mode 100644 pytest.ini
 create mode 100644 tests/README.md
 create mode 100644 tests/ansible.cfg
 create mode 100644 tests/test_playbook_runs.py

diff --git a/pytest.ini b/pytest.ini
new file mode 100644
index 00000000..0ee949b8
--- /dev/null
+++ b/pytest.ini
@@ -0,0 +1,2 @@
+[pytest]
+python_files = test_*.py
diff --git a/tests/README.md b/tests/README.md
new file mode 100644
index 00000000..2e12bd4b
--- /dev/null
+++ b/tests/README.md
@@ -0,0 +1,54 @@
+# Running the tests
+
+## Before starting
+
+In order to run ansible-freeipa tests you will need to have `ansible` and `pytest`
+installed on your machine. We'll call this local machine `controller`.
+
+You will also need to have a remote host with freeipa server installed and configured.
+We'll call this remote host `ipaserver`.
+
+Some other requirements:
+
+ * The `controller` must be able to connect to `ipaserver` through ssh using keys.
+ * `ipaserver` must be configured with DNS support. See [ipaserver role](../roles/ipaserver/README.md).
+ * IPA admin password must be `SomeADMINpassword`.
+ * Directory Server admin password must be `SomeDMpassword`.
+
+
+## Running the tests
+
+To run the tests run:
+```
+IPA_SERVER_HOST=<ipaserver_host_or_ip> pytest
+```
+
+If you need to run using a different user you can use `ANSIBLE_REMOTE_USER`
+environment variable. For example:
+```
+ANSIBLE_REMOTE_USER=root IPA_SERVER_HOST=<ipaserver_host_or_ip> pytest
+```
+
+To select which tests to run use the option `-k`. For example:
+```
+IPA_SERVER_HOST=<ipaserver_host_or_ip> pytest -k dnszone
+```
+
+To see the ansible output use the option `--capture=sys`. For example:
+```
+IPA_SERVER_HOST=<ipaserver_host_or_ip> pytest --capture=sys
+```
+
+To see why tests were skipped use `-rs`. For example:
+```
+IPA_SERVER_HOST=<ipaserver_host_or_ip> pytest -rs
+```
+
+For a complete list of options check `pytest --help`.
+
+
+## Upcoming/desired improvements:
+
+* A script to pre-config the complete test environment using virsh.
+* A test matrix to run tests against different distros in parallel (probably using tox).
+* Allow to connect to `ipaserver` using ssh and password.
diff --git a/tests/ansible.cfg b/tests/ansible.cfg
new file mode 100644
index 00000000..e7f44439
--- /dev/null
+++ b/tests/ansible.cfg
@@ -0,0 +1,5 @@
+[defaults]
+roles_path = ../roles:~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
+library = ../plugins/modules:~/.ansible/plugins/modules:/usr/share/ansible/plugins/modules
+module_utils = ../plugins/module_utils:~/.ansible/plugins/module_utils:/usr/share/ansible/plugins/module_utils
+host_key_checking = false
diff --git a/tests/test_playbook_runs.py b/tests/test_playbook_runs.py
new file mode 100644
index 00000000..4c63fe72
--- /dev/null
+++ b/tests/test_playbook_runs.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+
+import os
+import tempfile
+
+from subprocess import Popen
+
+from unittest import TestCase
+
+import pytest
+
+SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
+
+
+def get_inventory_content():
+    ipa_server_host = os.getenv("IPA_SERVER_HOST")
+    return "[ipaserver]\n{}".format(ipa_server_host).encode("utf8")
+
+
+def run_playbook(playbook):
+    with tempfile.NamedTemporaryFile() as inventory_file:
+        inventory_file.write(get_inventory_content())
+        inventory_file.flush()
+        cmd = [
+            "ansible-playbook",
+            "-i",
+            inventory_file.name,
+            playbook,
+        ]
+        process = Popen(cmd, cwd=SCRIPT_DIR)
+        process.wait()
+
+    return process
+
+
+def list_test_yaml(dir_path):
+    yamls = []
+    for yaml_name in os.listdir(dir_path):
+        if yaml_name.startswith("test_") and yaml_name.endswith(".yml"):
+            yamls.append(
+                {
+                    "path": os.path.join(dir_path, yaml_name),
+                    "name": yaml_name.split(".")[0],
+                }
+            )
+    return yamls
+
+
+def get_test_groups():
+    test_dirs = os.listdir(SCRIPT_DIR)
+    groups = {}
+    for test_group_dir in test_dirs:
+        group_dir_path = os.path.join(SCRIPT_DIR, test_group_dir)
+        if not os.path.isdir(group_dir_path):
+            continue
+        yamls = list_test_yaml(group_dir_path)
+        if yamls:
+            groups[test_group_dir] = yamls
+    return groups
+
+
+def rename(newname):
+    def decorator(f):
+        f.__name__ = newname
+        return f
+
+    return decorator
+
+
+# Dynamically create the TestCase classes with respective
+#   test_* methods.
+for group_name, group_tests in get_test_groups().items():
+    _tests = {}
+    for test_config in group_tests:
+        test_name = test_config["name"].replace("-", "_")
+
+        @pytest.mark.skipif(
+            os.getenv("IPA_SERVER_HOST") is None,
+            reason="Environment variable IPA_SERVER_HOST must be set",
+        )
+        @rename(test_name)
+        def method(self):
+            result = run_playbook(test_config["path"])
+            assert result.returncode == 0
+
+        _tests[test_name] = method
+    globals()[group_name] = type(group_name, (TestCase,), _tests)
-- 
GitLab