mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-08-04 05:04:22 -07:00
Move modules and module_utils unit tests to correct place (#81)
* Move modules and module_utils unit tests to correct place. * Update ignore.txt * Fix imports. * Fix typos. * Fix more typos.
This commit is contained in:
parent
ab3c2120fb
commit
be191cce6c
1170 changed files with 732 additions and 751 deletions
0
tests/unit/plugins/modules/packaging/__init__.py
Normal file
0
tests/unit/plugins/modules/packaging/__init__.py
Normal file
139
tests/unit/plugins/modules/packaging/language/test_gem.py
Normal file
139
tests/unit/plugins/modules/packaging/language/test_gem.py
Normal file
|
@ -0,0 +1,139 @@
|
|||
# Copyright (c) 2018 Antoine Catton
|
||||
# MIT License (see licenses/MIT-license.txt or https://opensource.org/licenses/MIT)
|
||||
import copy
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.general.plugins.modules.packaging.language import gem
|
||||
from ansible_collections.community.general.tests.unit.plugins.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase, set_module_args
|
||||
|
||||
|
||||
def get_command(run_command):
|
||||
"""Generate the command line string from the patched run_command"""
|
||||
args = run_command.call_args[0]
|
||||
command = args[0]
|
||||
return ' '.join(command)
|
||||
|
||||
|
||||
class TestGem(ModuleTestCase):
|
||||
def setUp(self):
|
||||
super(TestGem, self).setUp()
|
||||
self.rubygems_path = ['/usr/bin/gem']
|
||||
self.mocker.patch(
|
||||
'ansible_collections.community.general.plugins.modules.packaging.language.gem.get_rubygems_path',
|
||||
lambda module: copy.deepcopy(self.rubygems_path),
|
||||
)
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _mocker(self, mocker):
|
||||
self.mocker = mocker
|
||||
|
||||
def patch_installed_versions(self, versions):
|
||||
"""Mocks the versions of the installed package"""
|
||||
|
||||
target = 'ansible_collections.community.general.plugins.modules.packaging.language.gem.get_installed_versions'
|
||||
|
||||
def new(module, remote=False):
|
||||
return versions
|
||||
|
||||
return self.mocker.patch(target, new)
|
||||
|
||||
def patch_rubygems_version(self, version=None):
|
||||
target = 'ansible_collections.community.general.plugins.modules.packaging.language.gem.get_rubygems_version'
|
||||
|
||||
def new(module):
|
||||
return version
|
||||
|
||||
return self.mocker.patch(target, new)
|
||||
|
||||
def patch_run_command(self):
|
||||
target = 'ansible.module_utils.basic.AnsibleModule.run_command'
|
||||
return self.mocker.patch(target)
|
||||
|
||||
def test_fails_when_user_install_and_install_dir_are_combined(self):
|
||||
set_module_args({
|
||||
'name': 'dummy',
|
||||
'user_install': True,
|
||||
'install_dir': '/opt/dummy',
|
||||
})
|
||||
|
||||
with pytest.raises(AnsibleFailJson) as exc:
|
||||
gem.main()
|
||||
|
||||
result = exc.value.args[0]
|
||||
assert result['failed']
|
||||
assert result['msg'] == "install_dir requires user_install=false"
|
||||
|
||||
def test_passes_install_dir_to_gem(self):
|
||||
# XXX: This test is extremely fragile, and makes assuptions about the module code, and how
|
||||
# functions are run.
|
||||
# If you start modifying the code of the module, you might need to modify what this
|
||||
# test mocks. The only thing that matters is the assertion that this 'gem install' is
|
||||
# invoked with '--install-dir'.
|
||||
|
||||
set_module_args({
|
||||
'name': 'dummy',
|
||||
'user_install': False,
|
||||
'install_dir': '/opt/dummy',
|
||||
})
|
||||
|
||||
self.patch_rubygems_version()
|
||||
self.patch_installed_versions([])
|
||||
run_command = self.patch_run_command()
|
||||
|
||||
with pytest.raises(AnsibleExitJson) as exc:
|
||||
gem.main()
|
||||
|
||||
result = exc.value.args[0]
|
||||
assert result['changed']
|
||||
assert run_command.called
|
||||
|
||||
assert '--install-dir /opt/dummy' in get_command(run_command)
|
||||
|
||||
def test_passes_install_dir_and_gem_home_when_uninstall_gem(self):
|
||||
# XXX: This test is also extremely fragile because of mocking.
|
||||
# If this breaks, the only that matters is to check whether '--install-dir' is
|
||||
# in the run command, and that GEM_HOME is passed to the command.
|
||||
set_module_args({
|
||||
'name': 'dummy',
|
||||
'user_install': False,
|
||||
'install_dir': '/opt/dummy',
|
||||
'state': 'absent',
|
||||
})
|
||||
|
||||
self.patch_rubygems_version()
|
||||
self.patch_installed_versions(['1.0.0'])
|
||||
|
||||
run_command = self.patch_run_command()
|
||||
|
||||
with pytest.raises(AnsibleExitJson) as exc:
|
||||
gem.main()
|
||||
|
||||
result = exc.value.args[0]
|
||||
|
||||
assert result['changed']
|
||||
assert run_command.called
|
||||
|
||||
assert '--install-dir /opt/dummy' in get_command(run_command)
|
||||
|
||||
update_environ = run_command.call_args[1].get('environ_update', {})
|
||||
assert update_environ.get('GEM_HOME') == '/opt/dummy'
|
||||
|
||||
def test_passes_add_force_option(self):
|
||||
set_module_args({
|
||||
'name': 'dummy',
|
||||
'force': True,
|
||||
})
|
||||
|
||||
self.patch_rubygems_version()
|
||||
self.patch_installed_versions([])
|
||||
run_command = self.patch_run_command()
|
||||
|
||||
with pytest.raises(AnsibleExitJson) as exc:
|
||||
gem.main()
|
||||
|
||||
result = exc.value.args[0]
|
||||
assert result['changed']
|
||||
assert run_command.called
|
||||
|
||||
assert '--force' in get_command(run_command)
|
|
@ -0,0 +1,70 @@
|
|||
# Copyright (c) 2017 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
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.general.plugins.modules.packaging.language import maven_artifact
|
||||
from ansible.module_utils import basic
|
||||
|
||||
|
||||
pytestmark = pytest.mark.usefixtures('patch_ansible_module')
|
||||
|
||||
maven_metadata_example = b"""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<metadata>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<versioning>
|
||||
<latest>4.13-beta-2</latest>
|
||||
<release>4.13-beta-2</release>
|
||||
<versions>
|
||||
<version>3.7</version>
|
||||
<version>3.8</version>
|
||||
<version>3.8.1</version>
|
||||
<version>3.8.2</version>
|
||||
<version>4.0</version>
|
||||
<version>4.1</version>
|
||||
<version>4.2</version>
|
||||
<version>4.3</version>
|
||||
<version>4.3.1</version>
|
||||
<version>4.4</version>
|
||||
<version>4.5</version>
|
||||
<version>4.6</version>
|
||||
<version>4.7</version>
|
||||
<version>4.8</version>
|
||||
<version>4.8.1</version>
|
||||
<version>4.8.2</version>
|
||||
<version>4.9</version>
|
||||
<version>4.10</version>
|
||||
<version>4.11-beta-1</version>
|
||||
<version>4.11</version>
|
||||
<version>4.12-beta-1</version>
|
||||
<version>4.12-beta-2</version>
|
||||
<version>4.12-beta-3</version>
|
||||
<version>4.12</version>
|
||||
<version>4.13-beta-1</version>
|
||||
<version>4.13-beta-2</version>
|
||||
</versions>
|
||||
<lastUpdated>20190202141051</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
"""
|
||||
|
||||
|
||||
@pytest.mark.parametrize('patch_ansible_module, version_by_spec, version_choosed', [
|
||||
(None, "(,3.9]", "3.8.2"),
|
||||
(None, "3.0", "3.8.2"),
|
||||
(None, "[3.7]", "3.7"),
|
||||
(None, "[4.10, 4.12]", "4.12"),
|
||||
(None, "[4.10, 4.12)", "4.11"),
|
||||
(None, "[2.0,)", "4.13-beta-2"),
|
||||
])
|
||||
def test_find_version_by_spec(mocker, version_by_spec, version_choosed):
|
||||
_getContent = mocker.patch('ansible_collections.community.general.plugins.modules.packaging.language.maven_artifact.MavenDownloader._getContent')
|
||||
_getContent.return_value = maven_metadata_example
|
||||
|
||||
artifact = maven_artifact.Artifact("junit", "junit", None, version_by_spec, "jar")
|
||||
mvn_downloader = maven_artifact.MavenDownloader(basic.AnsibleModule, "https://repo1.maven.org/maven2")
|
||||
|
||||
assert mvn_downloader.find_version_by_spec(artifact) == version_choosed
|
0
tests/unit/plugins/modules/packaging/os/__init__.py
Normal file
0
tests/unit/plugins/modules/packaging/os/__init__.py
Normal file
29
tests/unit/plugins/modules/packaging/os/conftest.py
Normal file
29
tests/unit/plugins/modules/packaging/os/conftest.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
from ansible_collections.community.general.tests.unit.compat.mock import patch
|
||||
from ansible.module_utils.six.moves import xmlrpc_client
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def get_method_name(request_body):
|
||||
return xmlrpc_client.loads(request_body)[1]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_request(request, mocker):
|
||||
responses = request.getfixturevalue('testcase')['calls']
|
||||
module_name = request.module.TESTED_MODULE
|
||||
|
||||
def transport_request(host, handler, request_body, verbose=0):
|
||||
"""Fake request"""
|
||||
method_name = get_method_name(request_body)
|
||||
excepted_name, response = responses.pop(0)
|
||||
if method_name == excepted_name:
|
||||
if isinstance(response, Exception):
|
||||
raise response
|
||||
else:
|
||||
return response
|
||||
else:
|
||||
raise Exception('Expected call: %r, called with: %r' % (excepted_name, method_name))
|
||||
|
||||
target = '{0}.xmlrpc_client.Transport.request'.format(module_name)
|
||||
mocker.patch(target, side_effect=transport_request)
|
31
tests/unit/plugins/modules/packaging/os/test_apk.py
Normal file
31
tests/unit/plugins/modules/packaging/os/test_apk.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
from ansible_collections.community.general.tests.unit.compat import mock
|
||||
from ansible_collections.community.general.tests.unit.compat import unittest
|
||||
|
||||
from ansible_collections.community.general.plugins.modules.packaging.os import apk
|
||||
|
||||
|
||||
class TestApkQueryLatest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.module_names = [
|
||||
'bash',
|
||||
'g++',
|
||||
]
|
||||
|
||||
@mock.patch('ansible_collections.community.general.plugins.modules.packaging.os.apk.AnsibleModule')
|
||||
def test_not_latest(self, mock_module):
|
||||
apk.APK_PATH = ""
|
||||
for module_name in self.module_names:
|
||||
command_output = module_name + '-2.0.0-r1 < 3.0.0-r2 '
|
||||
mock_module.run_command.return_value = (0, command_output, None)
|
||||
command_result = apk.query_latest(mock_module, module_name)
|
||||
self.assertFalse(command_result)
|
||||
|
||||
@mock.patch('ansible_collections.community.general.plugins.modules.packaging.os.apk.AnsibleModule')
|
||||
def test_latest(self, mock_module):
|
||||
apk.APK_PATH = ""
|
||||
for module_name in self.module_names:
|
||||
command_output = module_name + '-2.0.0-r1 = 2.0.0-r1 '
|
||||
mock_module.run_command.return_value = (0, command_output, None)
|
||||
command_result = apk.query_latest(mock_module, module_name)
|
||||
self.assertTrue(command_result)
|
1221
tests/unit/plugins/modules/packaging/os/test_redhat_subscription.py
Normal file
1221
tests/unit/plugins/modules/packaging/os/test_redhat_subscription.py
Normal file
File diff suppressed because it is too large
Load diff
141
tests/unit/plugins/modules/packaging/os/test_rhn_channel.py
Normal file
141
tests/unit/plugins/modules/packaging/os/test_rhn_channel.py
Normal file
|
@ -0,0 +1,141 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017 Pierre-Louis Bonicoli <pierre-louis@libregerbil.fr>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
import json
|
||||
|
||||
from ansible_collections.community.general.plugins.modules.packaging.os import rhn_channel
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
pytestmark = pytest.mark.usefixtures('patch_ansible_module')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('patch_ansible_module', [{}], indirect=['patch_ansible_module'])
|
||||
def test_without_required_parameters(capfd):
|
||||
with pytest.raises(SystemExit):
|
||||
rhn_channel.main()
|
||||
out, err = capfd.readouterr()
|
||||
results = json.loads(out)
|
||||
assert results['failed']
|
||||
assert 'missing required arguments' in results['msg']
|
||||
|
||||
|
||||
TESTED_MODULE = rhn_channel.__name__
|
||||
TEST_CASES = [
|
||||
[
|
||||
# add channel already added, check that result isn't changed
|
||||
{
|
||||
'name': 'rhel-x86_64-server-6',
|
||||
'sysname': 'server01',
|
||||
'url': 'https://rhn.redhat.com/rpc/api',
|
||||
'user': 'user',
|
||||
'password': 'pass',
|
||||
},
|
||||
{
|
||||
'calls': [
|
||||
('auth.login', ['X' * 43]),
|
||||
('system.listUserSystems',
|
||||
[[{'last_checkin': '2017-08-06 19:49:52.0', 'id': '0123456789', 'name': 'server01'}]]),
|
||||
('channel.software.listSystemChannels',
|
||||
[[{'channel_name': 'Red Hat Enterprise Linux Server (v. 6 for 64-bit x86_64)', 'channel_label': 'rhel-x86_64-server-6'}]]),
|
||||
('auth.logout', [1]),
|
||||
],
|
||||
'changed': False,
|
||||
'msg': 'Channel rhel-x86_64-server-6 already exists',
|
||||
}
|
||||
],
|
||||
[
|
||||
# add channel, check that result is changed
|
||||
{
|
||||
'name': 'rhel-x86_64-server-6-debuginfo',
|
||||
'sysname': 'server01',
|
||||
'url': 'https://rhn.redhat.com/rpc/api',
|
||||
'user': 'user',
|
||||
'password': 'pass',
|
||||
},
|
||||
{
|
||||
'calls': [
|
||||
('auth.login', ['X' * 43]),
|
||||
('system.listUserSystems',
|
||||
[[{'last_checkin': '2017-08-06 19:49:52.0', 'id': '0123456789', 'name': 'server01'}]]),
|
||||
('channel.software.listSystemChannels',
|
||||
[[{'channel_name': 'Red Hat Enterprise Linux Server (v. 6 for 64-bit x86_64)', 'channel_label': 'rhel-x86_64-server-6'}]]),
|
||||
('channel.software.listSystemChannels',
|
||||
[[{'channel_name': 'Red Hat Enterprise Linux Server (v. 6 for 64-bit x86_64)', 'channel_label': 'rhel-x86_64-server-6'}]]),
|
||||
('system.setChildChannels', [1]),
|
||||
('auth.logout', [1]),
|
||||
],
|
||||
'changed': True,
|
||||
'msg': 'Channel rhel-x86_64-server-6-debuginfo added',
|
||||
}
|
||||
],
|
||||
[
|
||||
# remove inexistent channel, check that result isn't changed
|
||||
{
|
||||
'name': 'rhel-x86_64-server-6-debuginfo',
|
||||
'state': 'absent',
|
||||
'sysname': 'server01',
|
||||
'url': 'https://rhn.redhat.com/rpc/api',
|
||||
'user': 'user',
|
||||
'password': 'pass',
|
||||
},
|
||||
{
|
||||
'calls': [
|
||||
('auth.login', ['X' * 43]),
|
||||
('system.listUserSystems',
|
||||
[[{'last_checkin': '2017-08-06 19:49:52.0', 'id': '0123456789', 'name': 'server01'}]]),
|
||||
('channel.software.listSystemChannels',
|
||||
[[{'channel_name': 'Red Hat Enterprise Linux Server (v. 6 for 64-bit x86_64)', 'channel_label': 'rhel-x86_64-server-6'}]]),
|
||||
('auth.logout', [1]),
|
||||
],
|
||||
'changed': False,
|
||||
'msg': 'Not subscribed to channel rhel-x86_64-server-6-debuginfo.',
|
||||
}
|
||||
],
|
||||
[
|
||||
# remove channel, check that result is changed
|
||||
{
|
||||
'name': 'rhel-x86_64-server-6-debuginfo',
|
||||
'state': 'absent',
|
||||
'sysname': 'server01',
|
||||
'url': 'https://rhn.redhat.com/rpc/api',
|
||||
'user': 'user',
|
||||
'password': 'pass',
|
||||
},
|
||||
{
|
||||
'calls': [
|
||||
('auth.login', ['X' * 43]),
|
||||
('system.listUserSystems',
|
||||
[[{'last_checkin': '2017-08-06 19:49:52.0', 'id': '0123456789', 'name': 'server01'}]]),
|
||||
('channel.software.listSystemChannels', [[
|
||||
{'channel_name': 'RHEL Server Debuginfo (v.6 for x86_64)', 'channel_label': 'rhel-x86_64-server-6-debuginfo'},
|
||||
{'channel_name': 'Red Hat Enterprise Linux Server (v. 6 for 64-bit x86_64)', 'channel_label': 'rhel-x86_64-server-6'}
|
||||
]]),
|
||||
('channel.software.listSystemChannels', [[
|
||||
{'channel_name': 'RHEL Server Debuginfo (v.6 for x86_64)', 'channel_label': 'rhel-x86_64-server-6-debuginfo'},
|
||||
{'channel_name': 'Red Hat Enterprise Linux Server (v. 6 for 64-bit x86_64)', 'channel_label': 'rhel-x86_64-server-6'}
|
||||
]]),
|
||||
('system.setChildChannels', [1]),
|
||||
('auth.logout', [1]),
|
||||
],
|
||||
'changed': True,
|
||||
'msg': 'Channel rhel-x86_64-server-6-debuginfo removed'
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('patch_ansible_module, testcase', TEST_CASES, indirect=['patch_ansible_module'])
|
||||
def test_rhn_channel(capfd, mocker, testcase, mock_request):
|
||||
"""Check 'msg' and 'changed' results"""
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
rhn_channel.main()
|
||||
|
||||
out, err = capfd.readouterr()
|
||||
results = json.loads(out)
|
||||
assert results['changed'] == testcase['changed']
|
||||
assert results['msg'] == testcase['msg']
|
||||
assert not testcase['calls'] # all calls should have been consumed
|
284
tests/unit/plugins/modules/packaging/os/test_rhn_register.py
Normal file
284
tests/unit/plugins/modules/packaging/os/test_rhn_register.py
Normal file
|
@ -0,0 +1,284 @@
|
|||
import json
|
||||
import os
|
||||
|
||||
from ansible_collections.community.general.tests.unit.compat.mock import mock_open
|
||||
from ansible.module_utils import basic
|
||||
from ansible.module_utils._text import to_native
|
||||
import ansible.module_utils.six
|
||||
from ansible.module_utils.six.moves import xmlrpc_client
|
||||
from ansible_collections.community.general.plugins.modules.packaging.os import rhn_register
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
SYSTEMID = """<?xml version="1.0"?>
|
||||
<params>
|
||||
<param>
|
||||
<value><struct>
|
||||
<member>
|
||||
<name>system_id</name>
|
||||
<value><string>ID-123456789</string></value>
|
||||
</member>
|
||||
</struct></value>
|
||||
</param>
|
||||
</params>
|
||||
"""
|
||||
|
||||
|
||||
def skipWhenAllModulesMissing(modules):
|
||||
"""Skip the decorated test unless one of modules is available."""
|
||||
for module in modules:
|
||||
try:
|
||||
__import__(module)
|
||||
return False
|
||||
except ImportError:
|
||||
continue
|
||||
|
||||
return True
|
||||
|
||||
|
||||
orig_import = __import__
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def import_libxml(mocker):
|
||||
def mock_import(name, *args, **kwargs):
|
||||
if name in ['libxml2', 'libxml']:
|
||||
raise ImportError()
|
||||
else:
|
||||
return orig_import(name, *args, **kwargs)
|
||||
|
||||
if ansible.module_utils.six.PY3:
|
||||
mocker.patch('builtins.__import__', side_effect=mock_import)
|
||||
else:
|
||||
mocker.patch('__builtin__.__import__', side_effect=mock_import)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def patch_rhn(mocker):
|
||||
load_config_return = {
|
||||
'serverURL': 'https://xmlrpc.rhn.redhat.com/XMLRPC',
|
||||
'systemIdPath': '/etc/sysconfig/rhn/systemid'
|
||||
}
|
||||
|
||||
mocker.patch.object(rhn_register.Rhn, 'load_config', return_value=load_config_return)
|
||||
mocker.patch.object(rhn_register, 'HAS_UP2DATE_CLIENT', mocker.PropertyMock(return_value=True))
|
||||
|
||||
|
||||
@pytest.mark.skipif(skipWhenAllModulesMissing(['libxml2', 'libxml']), reason='none are available: libxml2, libxml')
|
||||
def test_systemid_with_requirements(capfd, mocker, patch_rhn):
|
||||
"""Check 'msg' and 'changed' results"""
|
||||
|
||||
mocker.patch.object(rhn_register.Rhn, 'enable')
|
||||
mock_isfile = mocker.patch('os.path.isfile', return_value=True)
|
||||
mocker.patch('ansible_collections.community.general.plugins.modules.packaging.os.rhn_register.open', mock_open(read_data=SYSTEMID), create=True)
|
||||
rhn = rhn_register.Rhn()
|
||||
assert '123456789' == to_native(rhn.systemid)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('patch_ansible_module', [{}], indirect=['patch_ansible_module'])
|
||||
@pytest.mark.usefixtures('patch_ansible_module')
|
||||
def test_systemid_requirements_missing(capfd, mocker, patch_rhn, import_libxml):
|
||||
"""Check that missing dependencies are detected"""
|
||||
|
||||
mocker.patch('os.path.isfile', return_value=True)
|
||||
mocker.patch('ansible_collections.community.general.plugins.modules.packaging.os.rhn_register.open', mock_open(read_data=SYSTEMID), create=True)
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
rhn_register.main()
|
||||
|
||||
out, err = capfd.readouterr()
|
||||
results = json.loads(out)
|
||||
assert results['failed']
|
||||
assert 'Missing arguments' in results['msg']
|
||||
|
||||
|
||||
@pytest.mark.parametrize('patch_ansible_module', [{}], indirect=['patch_ansible_module'])
|
||||
@pytest.mark.usefixtures('patch_ansible_module')
|
||||
def test_without_required_parameters(capfd, patch_rhn):
|
||||
"""Failure must occurs when all parameters are missing"""
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
rhn_register.main()
|
||||
out, err = capfd.readouterr()
|
||||
results = json.loads(out)
|
||||
assert results['failed']
|
||||
assert 'Missing arguments' in results['msg']
|
||||
|
||||
|
||||
TESTED_MODULE = rhn_register.__name__
|
||||
TEST_CASES = [
|
||||
[
|
||||
# Registering an unregistered host with channels
|
||||
{
|
||||
'channels': 'rhel-x86_64-server-6',
|
||||
'username': 'user',
|
||||
'password': 'pass',
|
||||
},
|
||||
{
|
||||
'calls': [
|
||||
('auth.login', ['X' * 43]),
|
||||
('channel.software.listSystemChannels',
|
||||
[[{'channel_name': 'Red Hat Enterprise Linux Server (v. 6 for 64-bit x86_64)', 'channel_label': 'rhel-x86_64-server-6'}]]),
|
||||
('channel.software.setSystemChannels', [1]),
|
||||
('auth.logout', [1]),
|
||||
],
|
||||
'is_registered': False,
|
||||
'is_registered.call_count': 1,
|
||||
'enable.call_count': 1,
|
||||
'systemid.call_count': 2,
|
||||
'changed': True,
|
||||
'msg': "System successfully registered to 'rhn.redhat.com'.",
|
||||
'run_command.call_count': 1,
|
||||
'run_command.call_args': '/usr/sbin/rhnreg_ks',
|
||||
'request_called': True,
|
||||
'unlink.call_count': 0,
|
||||
}
|
||||
],
|
||||
[
|
||||
# Registering an unregistered host without channels
|
||||
{
|
||||
'activationkey': 'key',
|
||||
'username': 'user',
|
||||
'password': 'pass',
|
||||
},
|
||||
{
|
||||
'calls': [
|
||||
],
|
||||
'is_registered': False,
|
||||
'is_registered.call_count': 1,
|
||||
'enable.call_count': 1,
|
||||
'systemid.call_count': 0,
|
||||
'changed': True,
|
||||
'msg': "System successfully registered to 'rhn.redhat.com'.",
|
||||
'run_command.call_count': 1,
|
||||
'run_command.call_args': '/usr/sbin/rhnreg_ks',
|
||||
'request_called': False,
|
||||
'unlink.call_count': 0,
|
||||
}
|
||||
],
|
||||
[
|
||||
# Register an host already registered, check that result is unchanged
|
||||
{
|
||||
'activationkey': 'key',
|
||||
'username': 'user',
|
||||
'password': 'pass',
|
||||
},
|
||||
{
|
||||
'calls': [
|
||||
],
|
||||
'is_registered': True,
|
||||
'is_registered.call_count': 1,
|
||||
'enable.call_count': 0,
|
||||
'systemid.call_count': 0,
|
||||
'changed': False,
|
||||
'msg': 'System already registered.',
|
||||
'run_command.call_count': 0,
|
||||
'request_called': False,
|
||||
'unlink.call_count': 0,
|
||||
},
|
||||
],
|
||||
[
|
||||
# Unregister an host, check that result is changed
|
||||
{
|
||||
'activationkey': 'key',
|
||||
'username': 'user',
|
||||
'password': 'pass',
|
||||
'state': 'absent',
|
||||
},
|
||||
{
|
||||
'calls': [
|
||||
('auth.login', ['X' * 43]),
|
||||
('system.deleteSystems', [1]),
|
||||
('auth.logout', [1]),
|
||||
],
|
||||
'is_registered': True,
|
||||
'is_registered.call_count': 1,
|
||||
'enable.call_count': 0,
|
||||
'systemid.call_count': 1,
|
||||
'changed': True,
|
||||
'msg': 'System successfully unregistered from rhn.redhat.com.',
|
||||
'run_command.call_count': 0,
|
||||
'request_called': True,
|
||||
'unlink.call_count': 1,
|
||||
}
|
||||
],
|
||||
[
|
||||
# Unregister a unregistered host (systemid missing) locally, check that result is unchanged
|
||||
{
|
||||
'activationkey': 'key',
|
||||
'username': 'user',
|
||||
'password': 'pass',
|
||||
'state': 'absent',
|
||||
},
|
||||
{
|
||||
'calls': [],
|
||||
'is_registered': False,
|
||||
'is_registered.call_count': 1,
|
||||
'enable.call_count': 0,
|
||||
'systemid.call_count': 0,
|
||||
'changed': False,
|
||||
'msg': 'System already unregistered.',
|
||||
'run_command.call_count': 0,
|
||||
'request_called': False,
|
||||
'unlink.call_count': 0,
|
||||
}
|
||||
|
||||
],
|
||||
[
|
||||
# Unregister an unknown host (an host with a systemid available locally, check that result contains failed
|
||||
{
|
||||
'activationkey': 'key',
|
||||
'username': 'user',
|
||||
'password': 'pass',
|
||||
'state': 'absent',
|
||||
},
|
||||
{
|
||||
'calls': [
|
||||
('auth.login', ['X' * 43]),
|
||||
('system.deleteSystems', xmlrpc_client.Fault(1003, 'The following systems were NOT deleted: 123456789')),
|
||||
('auth.logout', [1]),
|
||||
],
|
||||
'is_registered': True,
|
||||
'is_registered.call_count': 1,
|
||||
'enable.call_count': 0,
|
||||
'systemid.call_count': 1,
|
||||
'failed': True,
|
||||
'msg': "Failed to unregister: <Fault 1003: 'The following systems were NOT deleted: 123456789'>",
|
||||
'run_command.call_count': 0,
|
||||
'request_called': True,
|
||||
'unlink.call_count': 0,
|
||||
}
|
||||
],
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('patch_ansible_module, testcase', TEST_CASES, indirect=['patch_ansible_module'])
|
||||
@pytest.mark.usefixtures('patch_ansible_module')
|
||||
def test_register_parameters(mocker, capfd, mock_request, patch_rhn, testcase):
|
||||
# successful execution, no output
|
||||
mocker.patch.object(basic.AnsibleModule, 'run_command', return_value=(0, '', ''))
|
||||
mock_is_registered = mocker.patch.object(rhn_register.Rhn, 'is_registered', mocker.PropertyMock(return_value=testcase['is_registered']))
|
||||
mocker.patch.object(rhn_register.Rhn, 'enable')
|
||||
mock_systemid = mocker.patch.object(rhn_register.Rhn, 'systemid', mocker.PropertyMock(return_value=12345))
|
||||
mocker.patch('os.unlink', return_value=True)
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
rhn_register.main()
|
||||
|
||||
assert basic.AnsibleModule.run_command.call_count == testcase['run_command.call_count']
|
||||
if basic.AnsibleModule.run_command.call_count:
|
||||
assert basic.AnsibleModule.run_command.call_args[0][0][0] == testcase['run_command.call_args']
|
||||
|
||||
assert mock_is_registered.call_count == testcase['is_registered.call_count']
|
||||
assert rhn_register.Rhn.enable.call_count == testcase['enable.call_count']
|
||||
assert mock_systemid.call_count == testcase['systemid.call_count']
|
||||
assert xmlrpc_client.Transport.request.called == testcase['request_called']
|
||||
assert os.unlink.call_count == testcase['unlink.call_count']
|
||||
|
||||
out, err = capfd.readouterr()
|
||||
results = json.loads(out)
|
||||
assert results.get('changed') == testcase.get('changed')
|
||||
assert results.get('failed') == testcase.get('failed')
|
||||
assert results['msg'] == testcase['msg']
|
||||
assert not testcase['calls'] # all calls should have been consumed
|
141
tests/unit/plugins/modules/packaging/os/test_rhsm_release.py
Normal file
141
tests/unit/plugins/modules/packaging/os/test_rhsm_release.py
Normal file
|
@ -0,0 +1,141 @@
|
|||
# (c) 2018, Sean Myers <sean.myers@redhat.com>
|
||||
# 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.community.general.tests.unit.compat.mock import call, patch
|
||||
from ansible_collections.community.general.plugins.modules.packaging.os import rhsm_release
|
||||
from ansible_collections.community.general.tests.unit.plugins.modules.utils import (
|
||||
AnsibleExitJson, AnsibleFailJson, ModuleTestCase, set_module_args)
|
||||
|
||||
|
||||
class RhsmRepositoryReleaseModuleTestCase(ModuleTestCase):
|
||||
module = rhsm_release
|
||||
|
||||
def setUp(self):
|
||||
super(RhsmRepositoryReleaseModuleTestCase, self).setUp()
|
||||
|
||||
# Mainly interested that the subscription-manager calls are right
|
||||
# based on the module args, so patch out run_command in the module.
|
||||
# returns (rc, out, err) structure
|
||||
self.mock_run_command = patch('ansible_collections.community.general.plugins.modules.packaging.os.rhsm_release.'
|
||||
'AnsibleModule.run_command')
|
||||
self.module_main_command = self.mock_run_command.start()
|
||||
|
||||
# Module does a get_bin_path check before every run_command call
|
||||
self.mock_get_bin_path = patch('ansible_collections.community.general.plugins.modules.packaging.os.rhsm_release.'
|
||||
'AnsibleModule.get_bin_path')
|
||||
self.get_bin_path = self.mock_get_bin_path.start()
|
||||
self.get_bin_path.return_value = '/testbin/subscription-manager'
|
||||
|
||||
def tearDown(self):
|
||||
self.mock_run_command.stop()
|
||||
self.mock_get_bin_path.stop()
|
||||
super(RhsmRepositoryReleaseModuleTestCase, self).tearDown()
|
||||
|
||||
def module_main(self, exit_exc):
|
||||
with self.assertRaises(exit_exc) as exc:
|
||||
self.module.main()
|
||||
return exc.exception.args[0]
|
||||
|
||||
def test_release_set(self):
|
||||
# test that the module attempts to change the release when the current
|
||||
# release is not the same as the user-specific target release
|
||||
set_module_args({'release': '7.5'})
|
||||
self.module_main_command.side_effect = [
|
||||
# first call, get_release: returns different version so set_release is called
|
||||
(0, '7.4', ''),
|
||||
# second call, set_release: just needs to exit with 0 rc
|
||||
(0, '', ''),
|
||||
]
|
||||
|
||||
result = self.module_main(AnsibleExitJson)
|
||||
|
||||
self.assertTrue(result['changed'])
|
||||
self.assertEqual('7.5', result['current_release'])
|
||||
self.module_main_command.assert_has_calls([
|
||||
call('/testbin/subscription-manager release --show', check_rc=True),
|
||||
call('/testbin/subscription-manager release --set 7.5', check_rc=True),
|
||||
])
|
||||
|
||||
def test_release_set_idempotent(self):
|
||||
# test that the module does not attempt to change the release when
|
||||
# the current release matches the user-specified target release
|
||||
set_module_args({'release': '7.5'})
|
||||
self.module_main_command.side_effect = [
|
||||
# first call, get_release: returns same version, set_release is not called
|
||||
(0, '7.5', ''),
|
||||
]
|
||||
|
||||
result = self.module_main(AnsibleExitJson)
|
||||
|
||||
self.assertFalse(result['changed'])
|
||||
self.assertEqual('7.5', result['current_release'])
|
||||
self.module_main_command.assert_has_calls([
|
||||
call('/testbin/subscription-manager release --show', check_rc=True),
|
||||
])
|
||||
|
||||
def test_release_unset(self):
|
||||
# test that the module attempts to change the release when the current
|
||||
# release is not the same as the user-specific target release
|
||||
set_module_args({'release': None})
|
||||
self.module_main_command.side_effect = [
|
||||
# first call, get_release: returns version so set_release is called
|
||||
(0, '7.5', ''),
|
||||
# second call, set_release: just needs to exit with 0 rc
|
||||
(0, '', ''),
|
||||
]
|
||||
|
||||
result = self.module_main(AnsibleExitJson)
|
||||
|
||||
self.assertTrue(result['changed'])
|
||||
self.assertIsNone(result['current_release'])
|
||||
self.module_main_command.assert_has_calls([
|
||||
call('/testbin/subscription-manager release --show', check_rc=True),
|
||||
call('/testbin/subscription-manager release --unset', check_rc=True),
|
||||
])
|
||||
|
||||
def test_release_unset_idempotent(self):
|
||||
# test that the module attempts to change the release when the current
|
||||
# release is not the same as the user-specific target release
|
||||
set_module_args({'release': None})
|
||||
self.module_main_command.side_effect = [
|
||||
# first call, get_release: returns no version, set_release is not called
|
||||
(0, 'Release not set', ''),
|
||||
]
|
||||
|
||||
result = self.module_main(AnsibleExitJson)
|
||||
|
||||
self.assertFalse(result['changed'])
|
||||
self.assertIsNone(result['current_release'])
|
||||
self.module_main_command.assert_has_calls([
|
||||
call('/testbin/subscription-manager release --show', check_rc=True),
|
||||
])
|
||||
|
||||
def test_release_insane(self):
|
||||
# test that insane values for release trigger fail_json
|
||||
insane_value = 'this is an insane release value'
|
||||
set_module_args({'release': insane_value})
|
||||
|
||||
result = self.module_main(AnsibleFailJson)
|
||||
|
||||
# also ensure that the fail msg includes the insane value
|
||||
self.assertIn(insane_value, result['msg'])
|
||||
|
||||
def test_release_matcher(self):
|
||||
# throw a few values at the release matcher -- only sane_values should match
|
||||
sane_values = ['1Server', '10Server', '1.10', '10.0']
|
||||
insane_values = [
|
||||
'6server', # lowercase 's'
|
||||
'100Server', # excessively long 'x' component
|
||||
'100.0', # excessively long 'x' component
|
||||
'6.100', # excessively long 'y' component
|
||||
'100.100', # excessively long 'x' and 'y' components
|
||||
]
|
||||
|
||||
matches = self.module.release_matcher.findall(' '.join(sane_values + insane_values))
|
||||
|
||||
# matches should be returned in the same order they were parsed,
|
||||
# so sorting shouldn't be necessary here
|
||||
self.assertEqual(matches, sane_values)
|
Loading…
Add table
Add a link
Reference in a new issue