generated from ansible-collections/collection_template
-
Notifications
You must be signed in to change notification settings - Fork 140
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add unit test for the Ansible module
- Loading branch information
Showing
2 changed files
with
281 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,40 +1,240 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright: (c) 2020, Ansible Project | ||
# Copyright: (c) 2021, Ansible Project | ||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
|
||
from __future__ import absolute_import, division, print_function | ||
|
||
__metaclass__ = type | ||
|
||
from ansible_collections.kubernetes.core.plugins.modules.helm import ( | ||
run_dep_update | ||
import unittest | ||
|
||
from unittest.mock import MagicMock, patch, call | ||
|
||
from ansible.module_utils import basic | ||
from ansible_collections.kubernetes.core.plugins.modules import helm | ||
from ansible_collections.kubernetes.core.tests.unit.utils.ansible_module_mock import ( | ||
AnsibleFailJson, | ||
AnsibleExitJson, | ||
exit_json, | ||
fail_json, | ||
get_bin_path, | ||
set_module_args | ||
) | ||
|
||
|
||
class MockedModule: | ||
def __init__(self): | ||
self.params = { | ||
"api_key": None, | ||
"ca_cert": None, | ||
"host": None, | ||
"kube_context": None, | ||
"kubeconfig": None, | ||
"release_namespace": None, | ||
"validate_certs": None, | ||
class TestDependencyUpdateWithoutChartRepoUrlOption(unittest.TestCase): | ||
|
||
def setUp(self): | ||
self.mock_module_helper = patch.multiple(basic.AnsibleModule, | ||
exit_json=exit_json, | ||
fail_json=fail_json, | ||
get_bin_path=get_bin_path) | ||
self.mock_module_helper.start() | ||
|
||
# Stop the patch after test execution | ||
# like tearDown but executed also when the setup failed | ||
self.addCleanup(self.mock_module_helper.stop) | ||
|
||
self.chart_info_without_dep = { | ||
'apiVersion': 'v2', | ||
'appVersion': 'default', | ||
'description': 'A chart used in molecule tests', | ||
'name': 'test-chart', | ||
'type': 'application', | ||
'version': '0.1.0' | ||
} | ||
|
||
self.chart_info_with_dep = { | ||
'apiVersion': 'v2', | ||
'appVersion': 'default', | ||
'description': 'A chart used in molecule tests', | ||
'name': 'test-chart', | ||
'type': 'application', | ||
'version': '0.1.0', | ||
'dependencies': [ | ||
{ | ||
'name': 'test', | ||
'version': '0.1.0', | ||
'repository': 'file://../test-chart' | ||
} | ||
] | ||
} | ||
|
||
def test_module_fail_when_required_args_missing(self): | ||
with self.assertRaises(AnsibleFailJson): | ||
set_module_args({}) | ||
helm.main() | ||
|
||
def test_dependency_update_option_not_defined(self): | ||
set_module_args({ | ||
'release_name': 'test', | ||
'release_namespace': 'test', | ||
'chart_ref': '/tmp/path' | ||
}) | ||
helm.get_release_status = MagicMock(return_value=None) | ||
helm.fetch_chart_info = MagicMock(return_value=self.chart_info_without_dep) | ||
helm.run_dep_update = MagicMock() | ||
with patch.object(basic.AnsibleModule, 'run_command') as mock_run_command: | ||
mock_run_command.return_value = 0, 'configuration updated', '' # successful execution | ||
with self.assertRaises(AnsibleExitJson) as result: | ||
helm.main() | ||
helm.run_dep_update.assert_not_called() | ||
mock_run_command.assert_called_once_with('/usr/bin/helm upgrade -i --reset-values test /tmp/path', | ||
environ_update={'HELM_NAMESPACE': 'test'}) | ||
assert result.exception.args[0]['command'] == '/usr/bin/helm upgrade -i --reset-values test /tmp/path' | ||
|
||
def test_dependency_update_option_false(self): | ||
set_module_args({ | ||
'release_name': 'test', | ||
'release_namespace': 'test', | ||
'chart_ref': '/tmp/path', | ||
'dependency_update': False | ||
}) | ||
helm.get_release_status = MagicMock(return_value=None) | ||
helm.fetch_chart_info = MagicMock(return_value=self.chart_info_without_dep) | ||
helm.run_dep_update = MagicMock() | ||
with patch.object(basic.AnsibleModule, 'run_command') as mock_run_command: | ||
mock_run_command.return_value = 0, 'configuration updated', '' # successful execution | ||
with self.assertRaises(AnsibleExitJson) as result: | ||
helm.main() | ||
helm.run_dep_update.assert_not_called() | ||
mock_run_command.assert_called_once_with('/usr/bin/helm upgrade -i --reset-values test /tmp/path', | ||
environ_update={'HELM_NAMESPACE': 'test'}) | ||
assert result.exception.args[0]['command'] == '/usr/bin/helm upgrade -i --reset-values test /tmp/path' | ||
|
||
def test_dependency_update_option_true(self): | ||
set_module_args({ | ||
'release_name': 'test', | ||
'release_namespace': 'test', | ||
'chart_ref': '/tmp/path', | ||
'dependency_update': True | ||
}) | ||
helm.get_release_status = MagicMock(return_value=None) | ||
helm.fetch_chart_info = MagicMock(return_value=self.chart_info_with_dep) | ||
|
||
with patch.object(basic.AnsibleModule, 'run_command') as mock_run_command: | ||
mock_run_command.return_value = 0, 'configuration updated', '' | ||
with patch.object(basic.AnsibleModule, 'warn') as mock_warn: | ||
with self.assertRaises(AnsibleExitJson) as result: | ||
helm.main() | ||
mock_warn.assert_not_called() | ||
mock_run_command.assert_has_calls([ | ||
call('/usr/bin/helm dependency update /tmp/path'), # Run commmand for dependency update | ||
call('/usr/bin/helm upgrade -i --reset-values test /tmp/path', environ_update={'HELM_NAMESPACE': 'test'})]) | ||
assert result.exception.args[0]['command'] == '/usr/bin/helm upgrade -i --reset-values test /tmp/path' | ||
|
||
def test_dependency_update_option_true_without_dependencies_block(self): | ||
set_module_args({ | ||
'release_name': 'test', | ||
'release_namespace': 'test', | ||
'chart_ref': '/tmp/path', | ||
'dependency_update': True | ||
}) | ||
helm.get_release_status = MagicMock(return_value=None) | ||
helm.fetch_chart_info = MagicMock(return_value=self.chart_info_without_dep) | ||
with patch.object(basic.AnsibleModule, 'run_command') as mock_run_command: | ||
mock_run_command.return_value = 0, 'configuration updated', '' # successful execution | ||
with patch.object(basic.AnsibleModule, 'warn') as mock_warn: | ||
with self.assertRaises(AnsibleExitJson) as result: | ||
helm.main() | ||
mock_warn.assert_called_once() | ||
mock_run_command.assert_has_calls([ | ||
call('/usr/bin/helm dependency update /tmp/path'), # Run commmand for dependency update | ||
call('/usr/bin/helm upgrade -i --reset-values test /tmp/path', environ_update={'HELM_NAMESPACE': 'test'})]) | ||
assert result.exception.args[0]['command'] == '/usr/bin/helm upgrade -i --reset-values test /tmp/path' | ||
|
||
|
||
class TestDependencyUpdateWithChartRepoUrlOption(unittest.TestCase): | ||
def setUp(self): | ||
self.mock_module_helper = patch.multiple(basic.AnsibleModule, | ||
exit_json=exit_json, | ||
fail_json=fail_json, | ||
get_bin_path=get_bin_path) | ||
self.mock_module_helper.start() | ||
|
||
# Stop the patch after test execution | ||
# like tearDown but executed also when the setup failed | ||
self.addCleanup(self.mock_module_helper.stop) | ||
|
||
self.chart_info_without_dep = { | ||
'apiVersion': 'v2', | ||
'appVersion': 'default', | ||
'description': 'A chart used in molecule tests', | ||
'name': 'test-chart', | ||
'type': 'application', | ||
'version': '0.1.0' | ||
} | ||
|
||
self.r = {} | ||
def test_dependency_update_option_not_defined(self): | ||
set_module_args({ | ||
'release_name': 'test', | ||
'release_namespace': 'test', | ||
'chart_ref': 'chart1', | ||
'chart_repo_url': 'http://repo.example/charts' | ||
}) | ||
helm.get_release_status = MagicMock(return_value=None) | ||
helm.fetch_chart_info = MagicMock(return_value=self.chart_info_without_dep) | ||
with patch.object(basic.AnsibleModule, 'run_command') as mock_run_command: | ||
mock_run_command.return_value = 0, 'configuration updated', '' # successful execution | ||
with self.assertRaises(AnsibleExitJson) as result: | ||
helm.main() | ||
mock_run_command.assert_called_once_with('/usr/bin/helm --repo=http://repo.example/charts upgrade -i --reset-values test chart1', | ||
environ_update={'HELM_NAMESPACE': 'test'}) | ||
assert result.exception.args[0]['command'] == '/usr/bin/helm --repo=http://repo.example/charts upgrade -i --reset-values test chart1' | ||
|
||
def run_command(self, command, environ_update=None): | ||
self.r = {"command": command, "environ_update": environ_update} | ||
return 0, "", "" | ||
def test_dependency_update_option_False(self): | ||
set_module_args({ | ||
'release_name': 'test', | ||
'release_namespace': 'test', | ||
'chart_ref': 'chart1', | ||
'chart_repo_url': 'http://repo.example/charts', | ||
'dependency_update': False | ||
}) | ||
helm.get_release_status = MagicMock(return_value=None) | ||
helm.fetch_chart_info = MagicMock(return_value=self.chart_info_without_dep) | ||
with patch.object(basic.AnsibleModule, 'run_command') as mock_run_command: | ||
mock_run_command.return_value = 0, 'configuration updated', '' # successful execution | ||
with self.assertRaises(AnsibleExitJson) as result: | ||
helm.main() | ||
mock_run_command.assert_called_once_with('/usr/bin/helm --repo=http://repo.example/charts upgrade -i --reset-values test chart1', | ||
environ_update={'HELM_NAMESPACE': 'test'}) | ||
assert result.exception.args[0]['command'] == '/usr/bin/helm --repo=http://repo.example/charts upgrade -i --reset-values test chart1' | ||
|
||
def test_dependency_update_option_True_and_replace_option_disabled(self): | ||
set_module_args({ | ||
'release_name': 'test', | ||
'release_namespace': 'test', | ||
'chart_ref': 'chart1', | ||
'chart_repo_url': 'http://repo.example/charts', | ||
'dependency_update': True | ||
}) | ||
helm.get_release_status = MagicMock(return_value=None) | ||
helm.fetch_chart_info = MagicMock(return_value=self.chart_info_without_dep) | ||
with patch.object(basic.AnsibleModule, 'run_command') as mock_run_command: | ||
mock_run_command.return_value = 0, 'configuration updated', '' # successful execution | ||
with self.assertRaises(AnsibleFailJson) as result: | ||
helm.main() | ||
# mock_run_command.assert_called_once_with('/usr/bin/helm --repo=http://repo.example/charts upgrade -i --reset-values test chart1', | ||
# environ_update={'HELM_NAMESPACE': 'test'}) | ||
assert result.exception.args[0]['msg'] == ("'--dependency-update' hasn't been supported yet with 'helm upgrade'. " | ||
"Please use 'helm install' instead by adding 'replace' option") | ||
assert result.exception.args[0]['failed'] | ||
|
||
def test_dependency_update_naked(): | ||
module = MockedModule() | ||
module.params = {} | ||
common_cmd = "helm" | ||
chart_ref = "/tmp/path/chart" | ||
run_dep_update(module, common_cmd, chart_ref) | ||
assert module.r["command"] == "helm dependency update /tmp/path/chart" | ||
assert module.r["environ_update"] == {} | ||
def test_dependency_update_option_True_and_replace_option_enabled(self): | ||
set_module_args({ | ||
'release_name': "test", | ||
'release_namespace': 'test', | ||
'chart_ref': "chart1", | ||
'chart_repo_url': 'http://repo.example/charts', | ||
'dependency_update': True, | ||
'replace': True | ||
}) | ||
helm.get_release_status = MagicMock(return_value=None) | ||
helm.fetch_chart_info = MagicMock(return_value=self.chart_info_without_dep) | ||
with patch.object(basic.AnsibleModule, 'run_command') as mock_run_command: | ||
mock_run_command.return_value = 0, 'configuration updated', '' # successful execution | ||
with self.assertRaises(AnsibleExitJson) as result: | ||
helm.main() | ||
mock_run_command.assert_called_once_with('/usr/bin/helm --repo=http://repo.example/charts install --dependency-update --replace test chart1', | ||
environ_update={'HELM_NAMESPACE': 'test'}) | ||
assert result.exception.args[0]['command'] == '/usr/bin/helm --repo=http://repo.example/charts install --dependency-update --replace test chart1' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright: (c) 2021, Ansible Project | ||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
|
||
# This module maock the AnsibleModule class for more information please visite | ||
# https://docs.ansible.com/ansible/latest/dev_guide/testing_units_modules.html#module-argument-processing | ||
|
||
from __future__ import absolute_import, division, print_function | ||
|
||
__metaclass__ = type | ||
|
||
import json | ||
|
||
from ansible.module_utils import basic | ||
from ansible.module_utils.common.text.converters import to_bytes | ||
|
||
|
||
def set_module_args(args): | ||
"""prepare arguments so that they will be picked up during module creation""" | ||
args = json.dumps({'ANSIBLE_MODULE_ARGS': args}) | ||
basic._ANSIBLE_ARGS = to_bytes(args) | ||
|
||
|
||
class AnsibleExitJson(Exception): | ||
"""Exception class to be raised by module.exit_json and caught by the test case""" | ||
pass | ||
|
||
|
||
class AnsibleFailJson(Exception): | ||
"""Exception class to be raised by module.fail_json and caught by the test case""" | ||
pass | ||
|
||
|
||
def exit_json(*args, **kwargs): | ||
"""function to patch over exit_json; package return data into an exception""" | ||
if 'changed' not in kwargs: | ||
kwargs['changed'] = False | ||
raise AnsibleExitJson(kwargs) | ||
|
||
|
||
def fail_json(*args, **kwargs): | ||
"""function to patch over fail_json; package return data into an exception""" | ||
kwargs['failed'] = True | ||
raise AnsibleFailJson(kwargs) | ||
|
||
|
||
def get_bin_path(self, arg, required=False): | ||
"""Mock AnsibleModule.get_bin_path""" | ||
if arg.endswith('helm'): | ||
return '/usr/bin/helm' | ||
else: | ||
if required: | ||
fail_json(msg='%r not found !' % arg) | ||
|
||
# def warn(self,msg): | ||
# return msg |