From 1005782ee9b17ec0f2a11f7c051ce2dfa49568bd Mon Sep 17 00:00:00 2001 From: Ryan Petrello Date: Mon, 13 Mar 2017 12:57:47 -0400 Subject: [PATCH] add tests for our custom ansible callback plugin --- Makefile | 23 +++++-- awx/lib/tests/__init__.py | 0 awx/lib/tests/pytest.ini | 2 + awx/lib/tests/test_display_callback.py | 87 ++++++++++++++++++++++++++ tox.ini | 8 +++ 5 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 awx/lib/tests/__init__.py create mode 100644 awx/lib/tests/pytest.ini create mode 100644 awx/lib/tests/test_display_callback.py diff --git a/Makefile b/Makefile index 2f12ea110a..9ac824d2e5 100644 --- a/Makefile +++ b/Makefile @@ -176,11 +176,11 @@ UI_RELEASE_FLAG_FILE = awx/ui/.release_built .PHONY: clean clean-tmp clean-venv rebase push requirements requirements_dev \ develop refresh adduser migrate dbchange dbshell runserver celeryd \ - receiver test test_unit test_coverage coverage_html test_jenkins dev_build \ - release_build release_clean sdist rpmtar mock-rpm mock-srpm rpm-sign \ - deb deb-src debian debsign pbuilder reprepro setup_tarball \ - virtualbox-ovf virtualbox-centos-7 virtualbox-centos-6 \ - clean-bundle setup_bundle_tarball \ + receiver test test_unit test_ansible test_coverage coverage_html \ + test_jenkins dev_build release_build release_clean sdist rpmtar mock-rpm \ + mock-srpm rpm-sign deb deb-src debian debsign pbuilder \ + reprepro setup_tarball virtualbox-ovf virtualbox-centos-7 \ + virtualbox-centos-6 clean-bundle setup_bundle_tarball \ ui-docker-machine ui-docker ui-release ui-devel \ ui-test ui-deps ui-test-ci ui-test-saucelabs jlaska @@ -291,6 +291,11 @@ requirements_ansible: virtualenv_ansible pip uninstall --yes -r requirements/requirements_ansible_uninstall.txt; \ fi +requirements_ansible_dev: + if [ "$(VENV_BASE)" ]; then \ + $(VENV_BASE)/ansible/bin/pip install pytest; \ + fi + # Install third-party requirements needed for Tower's environment. requirements_tower: virtualenv_tower if [ "$(VENV_BASE)" ]; then \ @@ -311,7 +316,7 @@ requirements_tower_dev: requirements: requirements_ansible requirements_tower -requirements_dev: requirements requirements_tower_dev +requirements_dev: requirements requirements_tower_dev requirements_ansible_dev requirements_test: requirements @@ -494,6 +499,12 @@ test_unit: fi; \ py.test awx/main/tests/unit awx/conf/tests/unit awx/sso/tests/unit +test_ansible: + @if [ "$(VENV_BASE)" ]; then \ + . $(VENV_BASE)/ansible/bin/activate; \ + fi; \ + py.test awx/lib/tests -c awx/lib/tests/pytest.ini + # Run all API unit tests with coverage enabled. test_coverage: @if [ "$(VENV_BASE)" ]; then \ diff --git a/awx/lib/tests/__init__.py b/awx/lib/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/awx/lib/tests/pytest.ini b/awx/lib/tests/pytest.ini new file mode 100644 index 0000000000..2c2dad06eb --- /dev/null +++ b/awx/lib/tests/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +addopts = -v diff --git a/awx/lib/tests/test_display_callback.py b/awx/lib/tests/test_display_callback.py new file mode 100644 index 0000000000..c9132a05ed --- /dev/null +++ b/awx/lib/tests/test_display_callback.py @@ -0,0 +1,87 @@ +import mock +import os +import sys + +import pytest + +# ansible uses `ANSIBLE_CALLBACK_PLUGINS` and `ANSIBLE_STDOUT_CALLBACK` to +# discover callback plugins; `ANSIBLE_CALLBACK_PLUGINS` is a list of paths to +# search for a plugin implementation (which should be named `CallbackModule`) +# +# this code modifies the Python path to make our +# `awx.lib.tower_display_callback` callback importable (because `awx.lib` +# itself is not a package) +# +# we use the `tower_display_callback` imports below within this file, but +# Ansible also uses them when it discovers this file in +# `ANSIBLE_CALLBACK_PLUGINS` +CALLBACK = os.path.splitext(os.path.basename(__file__))[0] +PLUGINS = os.path.dirname(__file__) +with mock.patch.dict(os.environ, {'ANSIBLE_STDOUT_CALLBACK': CALLBACK, + 'ANSIBLE_CALLBACK_PLUGINS': PLUGINS}): + from ansible.cli.playbook import PlaybookCLI + from ansible.executor.playbook_executor import PlaybookExecutor + from ansible.inventory import Inventory + from ansible.parsing.dataloader import DataLoader + from ansible.vars import VariableManager + + # Add awx/lib to sys.path so we can use the plugin + path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) + if path not in sys.path: + sys.path.insert(0, path) + + from tower_display_callback import TowerDefaultCallbackModule as CallbackModule # noqa + from tower_display_callback.events import event_context # noqa + + +@pytest.fixture() +def local_cache(): + class Cache(dict): + def set(self, key, value): + self[key] = value + return Cache() + + +@pytest.fixture() +def executor(tmpdir_factory, request): + playbooks_marker = request.node.get_marker('playbooks') + playbooks = playbooks_marker.kwargs if playbooks_marker else {} + playbook_files = [] + for name, playbook in playbooks.items(): + filename = str(tmpdir_factory.mktemp('data').join(name)) + with open(filename, 'w') as f: + f.write(playbook) + playbook_files.append(filename) + + cli = PlaybookCLI(['', 'playbook.yml']) + cli.parse() + options = cli.parser.parse_args([])[0] + loader = DataLoader() + variable_manager = VariableManager() + inventory = Inventory(loader=loader, variable_manager=variable_manager, + host_list=['localhost']) + variable_manager.set_inventory(inventory) + + return PlaybookExecutor(playbooks=playbook_files, inventory=inventory, + variable_manager=variable_manager, loader=loader, + options=options, passwords={}) + + +@pytest.mark.parametrize('event', {'playbook_on_start', + 'playbook_on_play_start', + 'playbook_on_task_start', 'runner_on_ok', + 'playbook_on_stats'}) +@pytest.mark.playbooks(**{ + 'helloworld.yml': ''' +- name: Hello World Sample + connection: local + hosts: all + tasks: + - name: Hello Message + debug: + msg: "Hello World!"''' +}) +def test_callback_plugin_receives_events(executor, event, local_cache): + with mock.patch.object(event_context, 'cache', local_cache): + executor.run() + assert event in [task['event'] for task in local_cache.values()] diff --git a/tox.ini b/tox.ini index cc7b0f1012..30cf19266e 100644 --- a/tox.ini +++ b/tox.ini @@ -56,6 +56,14 @@ deps = commands = make UI_TEST_MODE=CI test-ui +[testenv:ansible] +deps = + ansible + pytest + -r{toxinidir}/requirements/requirements_ansible.txt +commands = + {envdir}/bin/py.test awx/lib/tests/ -c awx/lib/tests/pytest.ini {posargs} + [testenv:coveralls] commands= coverage combine