From 526a423dd2fdb638053a4f305ebc013ebc3682de Mon Sep 17 00:00:00 2001
From: Ian Wienand <iwienand@redhat.com>
Date: Thu, 1 Nov 2018 15:31:44 +1100
Subject: [PATCH] Add unittest for yamlgroup inventory plugin

This mocks out enough of the Ansible inventory framework so we can
test the group matching against a range of corner cases as present in
the results.yaml file.

Change-Id: I05114d9aae6f149122da20f239c8b3546bc140bc
---
 .../test-fixtures/groups.yaml                 |  1 +
 .../test-fixtures/results.yaml                | 62 ++++++++++++
 .../files/inventory_plugins/test_yamlgroup.py | 98 +++++++++++++++++++
 test-requirements.txt                         |  2 +
 tox.ini                                       |  1 +
 5 files changed, 164 insertions(+)
 create mode 120000 playbooks/roles/install-ansible/files/inventory_plugins/test-fixtures/groups.yaml
 create mode 100644 playbooks/roles/install-ansible/files/inventory_plugins/test-fixtures/results.yaml
 create mode 100644 playbooks/roles/install-ansible/files/inventory_plugins/test_yamlgroup.py

diff --git a/playbooks/roles/install-ansible/files/inventory_plugins/test-fixtures/groups.yaml b/playbooks/roles/install-ansible/files/inventory_plugins/test-fixtures/groups.yaml
new file mode 120000
index 0000000000..b5f1b3aa80
--- /dev/null
+++ b/playbooks/roles/install-ansible/files/inventory_plugins/test-fixtures/groups.yaml
@@ -0,0 +1 @@
+../../../../../../inventory/groups.yaml
\ No newline at end of file
diff --git a/playbooks/roles/install-ansible/files/inventory_plugins/test-fixtures/results.yaml b/playbooks/roles/install-ansible/files/inventory_plugins/test-fixtures/results.yaml
new file mode 100644
index 0000000000..cab7f3fb0f
--- /dev/null
+++ b/playbooks/roles/install-ansible/files/inventory_plugins/test-fixtures/results.yaml
@@ -0,0 +1,62 @@
+# This is a dictionary of hosts, with a list of what
+# groups they should be in
+
+results:
+
+  adns1.openstack.org:
+    - adns
+    - puppet
+
+  afs01.dfw.openstack.org:
+    - afs
+    - afs-client
+    - puppet
+
+  firehose01.openstack.org:
+    - firehose
+    - futureparser
+    - puppet
+
+  graphite.openstack.org:
+    - graphite
+    - puppet
+    - webservers
+
+  lists.katacontainers.io:
+    - mailman
+    - puppet
+
+  logstash-worker02.openstack.org:
+    - futureparser
+    - logstash-worker
+    - puppet
+
+  mirror02.dfw.rax.openstack.org:
+    - afs-client
+    - mirror
+    - puppet
+    - webservers
+
+  mirror-update01.openstack.org:
+    - afsadmin
+    - puppet
+
+  review.openstack.org:
+    - disabled
+    - gerrit
+    - puppet
+
+  nb01.openstack.org:
+    - nodepool
+    - nodepool-builder
+    - puppet
+    - webservers
+
+  ze01.openstack.org:
+    - afs-client
+    - puppet
+    - zuul-executor
+
+  zk01.openstack.org:
+    - puppet
+    - zookeeper
\ No newline at end of file
diff --git a/playbooks/roles/install-ansible/files/inventory_plugins/test_yamlgroup.py b/playbooks/roles/install-ansible/files/inventory_plugins/test_yamlgroup.py
new file mode 100644
index 0000000000..7562ddb4fe
--- /dev/null
+++ b/playbooks/roles/install-ansible/files/inventory_plugins/test_yamlgroup.py
@@ -0,0 +1,98 @@
+# Copyright (C) 2018 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+#
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import testtools
+import mock
+import yaml
+
+from ansible.inventory.host import Host
+
+from .yamlgroup import InventoryModule
+
+FIXTURE_DIR = os.path.join(os.path.dirname(__file__),
+                           'test-fixtures')
+
+class TestInventory(testtools.TestCase):
+
+    def test_yaml_groups(self):
+        inventory = mock.MagicMock()
+
+        results_yaml = os.path.join(FIXTURE_DIR, 'results.yaml')
+        with open(results_yaml) as f:
+            results = yaml.load(f)
+            results = results['results']
+
+        # Build the inventory list.  This is a list of Host objects
+        # which are the keys in our results.yaml file, keyed by the
+        # hostname (... I dunno, we're just tricking the inventory and
+        # making something it's happy with)
+        inventory.hosts = {}
+        for host in results.keys():
+            inventory.hosts[host] = Host(name=host)
+
+        # Fake out add_group() and add_child() for the inventory
+        # object to store our groups.
+        inventory.groups = {}
+        def add_group(group):
+            inventory.groups[group] = []
+        inventory.add_group = add_group
+        def add_child(group, host):
+            inventory.groups[group].append(host)
+        inventory.add_child = add_child
+
+        # Not really needed for unit test
+        loader = mock.MagicMock()
+
+        # This is all setup by ansible magic plugin/inventory stuff in
+        # real-life, which gets the groups into the config object
+        path = os.path.join(FIXTURE_DIR, 'groups.yaml')
+        with open(path) as f:
+            config_groups = yaml.load(f)
+            config_groups = config_groups['groups']
+        im = InventoryModule()
+        im._read_config_data = mock.MagicMock()
+        im._load_name = 'yamlgroup'
+        im.get_option = mock.MagicMock(side_effect=lambda x: config_groups)
+
+        im.parse(inventory, loader, path)
+
+        # Now, for every host we have in our results, we should be
+        # able to see it listed as a child of the groups it wants to
+        # be in
+        for host, groups in results.items():
+            for group in groups:
+                message=(
+                    "The inventory does not have a group <%s>;"
+                    "host <%s> should be in this group" % (group, host))
+                self.assertEquals(group in inventory.groups, True, message)
+
+                message=(
+                    "The group <%s> does not contain host <%s>"
+                    % (group, host))
+                self.assertIn(host, inventory.groups[group], message)
+
+            # Additionally, check this host hasn't managed to get into
+            # any groups it is *not* supposed to be in
+            for inventory_group, inventory_hosts in inventory.groups.items():
+                if host in inventory_hosts:
+                    message = ("The host <%s> should not be in group <%s>"
+                               % (host, inventory_group))
+                    self.assertTrue(inventory_group in groups, message)
diff --git a/test-requirements.txt b/test-requirements.txt
index cc0b68cd0d..229881d9bb 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -7,5 +7,7 @@ PyYAML>=3.10.0 # MIT
 ansible-lint
 openstacksdk
 zuul-sphinx>=0.2.3
+testtools
+mock
 # testinfra 1.17.0 has a broken wheel that won't install under python3
 testinfra!=1.17.0
diff --git a/tox.ini b/tox.ini
index 94b014ed8d..0db4ea645b 100644
--- a/tox.ini
+++ b/tox.ini
@@ -17,6 +17,7 @@ commands =
   python3 {toxinidir}/tools/sorted_modules_env.py {toxinidir}/modules.env
   python3 {toxinidir}/tools/irc_checks.py
   python3 {toxinidir}/tools/check_clouds_yaml.py
+  python3 -m unittest playbooks/roles/install-ansible/files/inventory_plugins/test_yamlgroup.py
   # Ansible Lint Check
   bash -c "find roles playbooks -type f -regex '.*.y[a]?ml' -print0 | xargs -t -n1 -0 \
     ansible-lint -x ANSIBLE0004 -x ANSIBLE0006 -x ANSIBLE0007 -x ANSIBLE0011 \