Reformat everything.

This commit is contained in:
Felix Fontein
2025-11-01 12:08:41 +01:00
parent 3f2213791a
commit 340ff8586d
1008 changed files with 61301 additions and 58309 deletions

View File

@@ -15,7 +15,7 @@ from ansible.utils import context_objects as co
@pytest.fixture
def parser():
parser = opt_help.create_base_parser('testparser')
parser = opt_help.create_base_parser("testparser")
opt_help.add_runas_options(parser)
opt_help.add_meta_options(parser)

View File

@@ -1,4 +1,3 @@
# Copyright (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
#
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
@@ -11,7 +10,7 @@ from ansible.plugins.loader import become_loader, get_shell_plugin
def call_become_plugin(task, var_options, cmd, executable=None):
"""Helper function to call become plugin similarly on how Ansible itself handles this."""
plugin = become_loader.get(task['become_method'])
plugin = become_loader.get(task["become_method"])
plugin.set_options(task_keys=task, var_options=var_options)
shell = get_shell_plugin(executable=executable)
return plugin.build_become_command(cmd, shell)

View File

@@ -20,18 +20,18 @@ def test_doas_basic(mocker, parser, reset_cli_args):
default_cmd = "/bin/foo"
default_exe = "/bin/bash"
doas_exe = 'doas'
doas_flags = '-n'
doas_exe = "doas"
doas_flags = "-n"
success = 'BECOME-SUCCESS-.+?'
success = "BECOME-SUCCESS-.+?"
task = {
'become_method': 'community.general.doas',
"become_method": "community.general.doas",
}
var_options = {}
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
print(cmd)
assert (re.match(f"""{doas_exe} {doas_flags} {default_exe} -c 'echo {success}; {default_cmd}'""", cmd) is not None)
assert re.match(f"""{doas_exe} {doas_flags} {default_exe} -c 'echo {success}; {default_cmd}'""", cmd) is not None
def test_doas(mocker, parser, reset_cli_args):
@@ -40,20 +40,26 @@ def test_doas(mocker, parser, reset_cli_args):
default_cmd = "/bin/foo"
default_exe = "/bin/bash"
doas_exe = 'doas'
doas_flags = '-n'
doas_exe = "doas"
doas_flags = "-n"
success = 'BECOME-SUCCESS-.+?'
success = "BECOME-SUCCESS-.+?"
task = {
'become_user': 'foo',
'become_method': 'community.general.doas',
'become_flags': doas_flags,
"become_user": "foo",
"become_method": "community.general.doas",
"become_flags": doas_flags,
}
var_options = {}
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
print(cmd)
assert (re.match(f"""{doas_exe} {doas_flags} -u {task['become_user']} {default_exe} -c 'echo {success}; {default_cmd}'""", cmd) is not None)
assert (
re.match(
f"""{doas_exe} {doas_flags} -u {task["become_user"]} {default_exe} -c 'echo {success}; {default_cmd}'""",
cmd,
)
is not None
)
def test_doas_varoptions(mocker, parser, reset_cli_args):
@@ -62,20 +68,26 @@ def test_doas_varoptions(mocker, parser, reset_cli_args):
default_cmd = "/bin/foo"
default_exe = "/bin/bash"
doas_exe = 'doas'
doas_flags = '-n'
doas_exe = "doas"
doas_flags = "-n"
success = 'BECOME-SUCCESS-.+?'
success = "BECOME-SUCCESS-.+?"
task = {
'become_user': 'foo',
'become_method': 'community.general.doas',
'become_flags': 'xxx',
"become_user": "foo",
"become_method": "community.general.doas",
"become_flags": "xxx",
}
var_options = {
'ansible_become_user': 'bar',
'ansible_become_flags': doas_flags,
"ansible_become_user": "bar",
"ansible_become_flags": doas_flags,
}
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
print(cmd)
assert (re.match(f"""{doas_exe} {doas_flags} -u {var_options['ansible_become_user']} {default_exe} -c 'echo {success}; {default_cmd}'""", cmd) is not None)
assert (
re.match(
f"""{doas_exe} {doas_flags} -u {var_options["ansible_become_user"]} {default_exe} -c 'echo {success}; {default_cmd}'""",
cmd,
)
is not None
)

View File

@@ -20,13 +20,13 @@ def test_dzdo_basic(mocker, parser, reset_cli_args):
default_cmd = "/bin/foo"
default_exe = "/bin/bash"
dzdo_exe = 'dzdo'
dzdo_flags = '-H -S -n'
dzdo_exe = "dzdo"
dzdo_flags = "-H -S -n"
success = 'BECOME-SUCCESS-.+?'
success = "BECOME-SUCCESS-.+?"
task = {
'become_method': 'community.general.dzdo',
"become_method": "community.general.dzdo",
}
var_options = {}
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
@@ -40,25 +40,45 @@ def test_dzdo(mocker, parser, reset_cli_args):
default_cmd = "/bin/foo"
default_exe = "/bin/bash"
dzdo_exe = 'dzdo'
dzdo_flags = ''
dzdo_exe = "dzdo"
dzdo_flags = ""
success = 'BECOME-SUCCESS-.+?'
success = "BECOME-SUCCESS-.+?"
task = {
'become_user': 'foo',
'become_method': 'community.general.dzdo',
'become_flags': dzdo_flags,
"become_user": "foo",
"become_method": "community.general.dzdo",
"become_flags": dzdo_flags,
}
var_options = {}
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
print(cmd)
assert re.match(f"""{dzdo_exe} {dzdo_flags} -u {task['become_user']} {default_exe} -c 'echo {success}; {default_cmd}'""", cmd) is not None
task['become_pass'] = 'testpass'
assert (
re.match(
f"""{dzdo_exe} {dzdo_flags} -u {task["become_user"]} {default_exe} -c 'echo {success}; {default_cmd}'""",
cmd,
)
is not None
)
task["become_pass"] = "testpass"
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
print(cmd)
assert re.match("""%s %s -p %s -u %s %s -c 'echo %s; %s'""" % (dzdo_exe, dzdo_flags, r'\"\[dzdo via ansible, key=.+?\] password:\"',
task['become_user'], default_exe, success, default_cmd), cmd) is not None
assert (
re.match(
"""%s %s -p %s -u %s %s -c 'echo %s; %s'"""
% (
dzdo_exe,
dzdo_flags,
r"\"\[dzdo via ansible, key=.+?\] password:\"",
task["become_user"],
default_exe,
success,
default_cmd,
),
cmd,
)
is not None
)
def test_dzdo_varoptions(mocker, parser, reset_cli_args):
@@ -67,25 +87,45 @@ def test_dzdo_varoptions(mocker, parser, reset_cli_args):
default_cmd = "/bin/foo"
default_exe = "/bin/bash"
dzdo_exe = 'dzdo'
dzdo_flags = ''
dzdo_exe = "dzdo"
dzdo_flags = ""
success = 'BECOME-SUCCESS-.+?'
success = "BECOME-SUCCESS-.+?"
task = {
'become_user': 'foo',
'become_method': 'community.general.dzdo',
'become_flags': 'xxx',
"become_user": "foo",
"become_method": "community.general.dzdo",
"become_flags": "xxx",
}
var_options = {
'ansible_become_user': 'bar',
'ansible_become_flags': dzdo_flags,
"ansible_become_user": "bar",
"ansible_become_flags": dzdo_flags,
}
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
print(cmd)
assert re.match(f"""{dzdo_exe} {dzdo_flags} -u {var_options['ansible_become_user']} {default_exe} -c 'echo {success}; {default_cmd}'""", cmd) is not None
var_options['ansible_become_pass'] = 'testpass'
assert (
re.match(
f"""{dzdo_exe} {dzdo_flags} -u {var_options["ansible_become_user"]} {default_exe} -c 'echo {success}; {default_cmd}'""",
cmd,
)
is not None
)
var_options["ansible_become_pass"] = "testpass"
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
print(cmd)
assert re.match("""%s %s -p %s -u %s %s -c 'echo %s; %s'""" % (dzdo_exe, dzdo_flags, r'\"\[dzdo via ansible, key=.+?\] password:\"',
var_options['ansible_become_user'], default_exe, success, default_cmd), cmd) is not None
assert (
re.match(
"""%s %s -p %s -u %s %s -c 'echo %s; %s'"""
% (
dzdo_exe,
dzdo_flags,
r"\"\[dzdo via ansible, key=.+?\] password:\"",
var_options["ansible_become_user"],
default_exe,
success,
default_cmd,
),
cmd,
)
is not None
)

View File

@@ -20,19 +20,24 @@ def test_ksu_basic(mocker, parser, reset_cli_args):
default_cmd = "/bin/foo"
default_exe = "/bin/bash"
ksu_exe = 'ksu'
ksu_flags = ''
ksu_exe = "ksu"
ksu_flags = ""
success = 'BECOME-SUCCESS-.+?'
success = "BECOME-SUCCESS-.+?"
task = {
'become_user': 'foo',
'become_method': 'community.general.ksu',
"become_user": "foo",
"become_method": "community.general.ksu",
}
var_options = {}
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
print(cmd)
assert (re.match(f"""{ksu_exe} {task['become_user']} {ksu_flags} -e {default_exe} -c 'echo {success}; {default_cmd}'""", cmd) is not None)
assert (
re.match(
f"""{ksu_exe} {task["become_user"]} {ksu_flags} -e {default_exe} -c 'echo {success}; {default_cmd}'""", cmd
)
is not None
)
def test_ksu(mocker, parser, reset_cli_args):
@@ -41,20 +46,25 @@ def test_ksu(mocker, parser, reset_cli_args):
default_cmd = "/bin/foo"
default_exe = "/bin/bash"
ksu_exe = 'ksu'
ksu_flags = ''
ksu_exe = "ksu"
ksu_flags = ""
success = 'BECOME-SUCCESS-.+?'
success = "BECOME-SUCCESS-.+?"
task = {
'become_user': 'foo',
'become_method': 'community.general.ksu',
'become_flags': ksu_flags,
"become_user": "foo",
"become_method": "community.general.ksu",
"become_flags": ksu_flags,
}
var_options = {}
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
print(cmd)
assert (re.match(f"""{ksu_exe} {task['become_user']} {ksu_flags} -e {default_exe} -c 'echo {success}; {default_cmd}'""", cmd) is not None)
assert (
re.match(
f"""{ksu_exe} {task["become_user"]} {ksu_flags} -e {default_exe} -c 'echo {success}; {default_cmd}'""", cmd
)
is not None
)
def test_ksu_varoptions(mocker, parser, reset_cli_args):
@@ -63,20 +73,26 @@ def test_ksu_varoptions(mocker, parser, reset_cli_args):
default_cmd = "/bin/foo"
default_exe = "/bin/bash"
ksu_exe = 'ksu'
ksu_flags = ''
ksu_exe = "ksu"
ksu_flags = ""
success = 'BECOME-SUCCESS-.+?'
success = "BECOME-SUCCESS-.+?"
task = {
'become_user': 'foo',
'become_method': 'community.general.ksu',
'become_flags': 'xxx',
"become_user": "foo",
"become_method": "community.general.ksu",
"become_flags": "xxx",
}
var_options = {
'ansible_become_user': 'bar',
'ansible_become_flags': ksu_flags,
"ansible_become_user": "bar",
"ansible_become_flags": ksu_flags,
}
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
print(cmd)
assert (re.match(f"""{ksu_exe} {var_options['ansible_become_user']} {ksu_flags} -e {default_exe} -c 'echo {success}; {default_cmd}'""", cmd) is not None)
assert (
re.match(
f"""{ksu_exe} {var_options["ansible_become_user"]} {ksu_flags} -e {default_exe} -c 'echo {success}; {default_cmd}'""",
cmd,
)
is not None
)

View File

@@ -20,13 +20,13 @@ def test_pbrun_basic(mocker, parser, reset_cli_args):
default_cmd = "/bin/foo"
default_exe = "/bin/bash"
pbrun_exe = 'pbrun'
pbrun_flags = ''
pbrun_exe = "pbrun"
pbrun_flags = ""
success = 'BECOME-SUCCESS-.+?'
success = "BECOME-SUCCESS-.+?"
task = {
'become_method': 'community.general.pbrun',
"become_method": "community.general.pbrun",
}
var_options = {}
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
@@ -40,20 +40,23 @@ def test_pbrun(mocker, parser, reset_cli_args):
default_cmd = "/bin/foo"
default_exe = "/bin/bash"
pbrun_exe = 'pbrun'
pbrun_flags = ''
pbrun_exe = "pbrun"
pbrun_flags = ""
success = 'BECOME-SUCCESS-.+?'
success = "BECOME-SUCCESS-.+?"
task = {
'become_user': 'foo',
'become_method': 'community.general.pbrun',
'become_flags': pbrun_flags,
"become_user": "foo",
"become_method": "community.general.pbrun",
"become_flags": pbrun_flags,
}
var_options = {}
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
print(cmd)
assert re.match(f"""{pbrun_exe} {pbrun_flags} -u {task['become_user']} 'echo {success}; {default_cmd}'""", cmd) is not None
assert (
re.match(f"""{pbrun_exe} {pbrun_flags} -u {task["become_user"]} 'echo {success}; {default_cmd}'""", cmd)
is not None
)
def test_pbrun_var_varoptions(mocker, parser, reset_cli_args):
@@ -62,20 +65,26 @@ def test_pbrun_var_varoptions(mocker, parser, reset_cli_args):
default_cmd = "/bin/foo"
default_exe = "/bin/bash"
pbrun_exe = 'pbrun'
pbrun_flags = ''
pbrun_exe = "pbrun"
pbrun_flags = ""
success = 'BECOME-SUCCESS-.+?'
success = "BECOME-SUCCESS-.+?"
task = {
'become_user': 'foo',
'become_method': 'community.general.pbrun',
'become_flags': 'xxx',
"become_user": "foo",
"become_method": "community.general.pbrun",
"become_flags": "xxx",
}
var_options = {
'ansible_become_user': 'bar',
'ansible_become_flags': pbrun_flags,
"ansible_become_user": "bar",
"ansible_become_flags": pbrun_flags,
}
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
print(cmd)
assert re.match(f"""{pbrun_exe} {pbrun_flags} -u {var_options['ansible_become_user']} 'echo {success}; {default_cmd}'""", cmd) is not None
assert (
re.match(
f"""{pbrun_exe} {pbrun_flags} -u {var_options["ansible_become_user"]} 'echo {success}; {default_cmd}'""",
cmd,
)
is not None
)

View File

@@ -20,13 +20,13 @@ def test_pfexec_basic(mocker, parser, reset_cli_args):
default_cmd = "/bin/foo"
default_exe = "/bin/bash"
pfexec_exe = 'pfexec'
pfexec_flags = '-H -S -n'
pfexec_exe = "pfexec"
pfexec_flags = "-H -S -n"
success = 'BECOME-SUCCESS-.+?'
success = "BECOME-SUCCESS-.+?"
task = {
'become_method': 'community.general.pfexec',
"become_method": "community.general.pfexec",
}
var_options = {}
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
@@ -40,15 +40,15 @@ def test_pfexec(mocker, parser, reset_cli_args):
default_cmd = "/bin/foo"
default_exe = "/bin/bash"
pfexec_exe = 'pfexec'
pfexec_flags = ''
pfexec_exe = "pfexec"
pfexec_flags = ""
success = 'BECOME-SUCCESS-.+?'
success = "BECOME-SUCCESS-.+?"
task = {
'become_user': 'foo',
'become_method': 'community.general.pfexec',
'become_flags': pfexec_flags,
"become_user": "foo",
"become_method": "community.general.pfexec",
"become_flags": pfexec_flags,
}
var_options = {}
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
@@ -62,19 +62,19 @@ def test_pfexec_varoptions(mocker, parser, reset_cli_args):
default_cmd = "/bin/foo"
default_exe = "/bin/bash"
pfexec_exe = 'pfexec'
pfexec_flags = ''
pfexec_exe = "pfexec"
pfexec_flags = ""
success = 'BECOME-SUCCESS-.+?'
success = "BECOME-SUCCESS-.+?"
task = {
'become_user': 'foo',
'become_method': 'community.general.pfexec',
'become_flags': 'xxx',
"become_user": "foo",
"become_method": "community.general.pfexec",
"become_flags": "xxx",
}
var_options = {
'ansible_become_user': 'bar',
'ansible_become_flags': pfexec_flags,
"ansible_become_user": "bar",
"ansible_become_flags": pfexec_flags,
}
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
print(cmd)

View File

@@ -20,30 +20,49 @@ def test_sudosu(mocker, parser, reset_cli_args):
default_cmd = "/bin/foo"
default_exe = "/bin/bash"
sudo_exe = 'sudo'
sudo_flags = '-H -s -n'
sudo_exe = "sudo"
sudo_flags = "-H -s -n"
success = 'BECOME-SUCCESS-.+?'
success = "BECOME-SUCCESS-.+?"
task = {
'become_user': 'foo',
'become_method': 'community.general.sudosu',
'become_flags': sudo_flags,
"become_user": "foo",
"become_method": "community.general.sudosu",
"become_flags": sudo_flags,
}
var_options = {}
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
print(cmd)
assert (re.match(f"""{sudo_exe} {sudo_flags} su -l {task['become_user']} {default_exe} -c 'echo {success}; {default_cmd}'""", cmd) is not None)
assert (
re.match(
f"""{sudo_exe} {sudo_flags} su -l {task["become_user"]} {default_exe} -c 'echo {success}; {default_cmd}'""",
cmd,
)
is not None
)
task = {
'become_user': 'foo',
'become_method': 'community.general.sudosu',
'become_flags': sudo_flags,
'become_pass': 'testpass',
"become_user": "foo",
"become_method": "community.general.sudosu",
"become_flags": sudo_flags,
"become_pass": "testpass",
}
var_options = {}
cmd = call_become_plugin(task, var_options, cmd=default_cmd, executable=default_exe)
print(cmd)
assert (re.match("""%s %s -p "%s" su -l %s %s -c 'echo %s; %s'""" % (sudo_exe, sudo_flags.replace('-n', ''),
r"\[sudo via ansible, key=.+?\] password:", task['become_user'],
default_exe, success, default_cmd), cmd) is not None)
assert (
re.match(
"""%s %s -p "%s" su -l %s %s -c 'echo %s; %s'"""
% (
sudo_exe,
sudo_flags.replace("-n", ""),
r"\[sudo via ansible, key=.+?\] password:",
task["become_user"],
default_exe,
success,
default_cmd,
),
cmd,
)
is not None
)

View File

@@ -7,11 +7,11 @@ from __future__ import annotations
import pytest
pytest.importorskip('memcache')
pytest.importorskip("memcache")
from ansible.plugins.loader import cache_loader
from ansible_collections.community.general.plugins.cache.memcached import CacheModule as MemcachedCache
def test_memcached_cachemodule():
assert isinstance(cache_loader.get('community.general.memcached'), MemcachedCache)
assert isinstance(cache_loader.get("community.general.memcached"), MemcachedCache)

View File

@@ -7,7 +7,7 @@ from __future__ import annotations
import pytest
pytest.importorskip('redis')
pytest.importorskip("redis")
from ansible.plugins.loader import cache_loader
from ansible_collections.community.general.plugins.cache.redis import CacheModule as RedisCache
@@ -15,11 +15,11 @@ from ansible_collections.community.general.plugins.cache.redis import CacheModul
def test_redis_cachemodule():
# The _uri option is required for the redis plugin
connection = '127.0.0.1:6379:1'
assert isinstance(cache_loader.get('community.general.redis', **{'_uri': connection}), RedisCache)
connection = "127.0.0.1:6379:1"
assert isinstance(cache_loader.get("community.general.redis", **{"_uri": connection}), RedisCache)
def test_redis_cachemodule_2():
# The _uri option is required for the redis plugin
connection = '[::1]:6379:1'
assert isinstance(cache_loader.get('community.general.redis', **{'_uri': connection}), RedisCache)
connection = "[::1]:6379:1"
assert isinstance(cache_loader.get("community.general.redis", **{"_uri": connection}), RedisCache)

View File

@@ -17,84 +17,73 @@ ELASTIC_MINIMUM_PYTHON_VERSION = (3, 6)
class TestOpentelemetry(unittest.TestCase):
@patch('ansible_collections.community.general.plugins.callback.elastic.socket')
@patch("ansible_collections.community.general.plugins.callback.elastic.socket")
def setUp(self, mock_socket):
if sys.version_info < ELASTIC_MINIMUM_PYTHON_VERSION:
self.skipTest(f"Python {'.'.join(map(str, ELASTIC_MINIMUM_PYTHON_VERSION))}+ is needed for Elastic")
mock_socket.gethostname.return_value = 'my-host'
mock_socket.gethostbyname.return_value = '1.2.3.4'
mock_socket.gethostname.return_value = "my-host"
mock_socket.gethostbyname.return_value = "1.2.3.4"
self.elastic = ElasticSource(display=None)
self.task_fields = {'args': {}}
self.mock_host = Mock('MockHost')
self.mock_host.name = 'myhost'
self.mock_host._uuid = 'myhost_uuid'
self.task_fields = {"args": {}}
self.mock_host = Mock("MockHost")
self.mock_host.name = "myhost"
self.mock_host._uuid = "myhost_uuid"
self.mock_task = Task()
self.mock_task.action = 'myaction'
self.mock_task.action = "myaction"
self.mock_task.no_log = False
self.mock_task._role = 'myrole'
self.mock_task._uuid = 'myuuid'
self.mock_task._role = "myrole"
self.mock_task._uuid = "myuuid"
self.mock_task.args = {}
self.mock_task.get_name = MagicMock(return_value='mytask')
self.mock_task.get_path = MagicMock(return_value='/mypath')
self.my_task = TaskData('myuuid', 'mytask', '/mypath', 'myplay', 'myaction', '')
self.my_task_result = TaskResult(host=self.mock_host, task=self.mock_task, return_data={}, task_fields=self.task_fields)
self.mock_task.get_name = MagicMock(return_value="mytask")
self.mock_task.get_path = MagicMock(return_value="/mypath")
self.my_task = TaskData("myuuid", "mytask", "/mypath", "myplay", "myaction", "")
self.my_task_result = TaskResult(
host=self.mock_host, task=self.mock_task, return_data={}, task_fields=self.task_fields
)
def test_start_task(self):
tasks_data = OrderedDict()
self.elastic.start_task(
tasks_data,
False,
'myplay',
self.mock_task
)
self.elastic.start_task(tasks_data, False, "myplay", self.mock_task)
task_data = tasks_data['myuuid']
self.assertEqual(task_data.uuid, 'myuuid')
self.assertEqual(task_data.name, 'mytask')
self.assertEqual(task_data.path, '/mypath')
self.assertEqual(task_data.play, 'myplay')
self.assertEqual(task_data.action, 'myaction')
self.assertEqual(task_data.args, '')
task_data = tasks_data["myuuid"]
self.assertEqual(task_data.uuid, "myuuid")
self.assertEqual(task_data.name, "mytask")
self.assertEqual(task_data.path, "/mypath")
self.assertEqual(task_data.play, "myplay")
self.assertEqual(task_data.action, "myaction")
self.assertEqual(task_data.args, "")
def test_finish_task_with_a_host_match(self):
tasks_data = OrderedDict()
tasks_data['myuuid'] = self.my_task
tasks_data["myuuid"] = self.my_task
self.elastic.finish_task(
tasks_data,
'ok',
self.my_task_result
)
self.elastic.finish_task(tasks_data, "ok", self.my_task_result)
task_data = tasks_data['myuuid']
host_data = task_data.host_data['myhost_uuid']
self.assertEqual(host_data.uuid, 'myhost_uuid')
self.assertEqual(host_data.name, 'myhost')
self.assertEqual(host_data.status, 'ok')
task_data = tasks_data["myuuid"]
host_data = task_data.host_data["myhost_uuid"]
self.assertEqual(host_data.uuid, "myhost_uuid")
self.assertEqual(host_data.name, "myhost")
self.assertEqual(host_data.status, "ok")
def test_finish_task_without_a_host_match(self):
result = TaskResult(host=None, task=self.mock_task, return_data={}, task_fields=self.task_fields)
tasks_data = OrderedDict()
tasks_data['myuuid'] = self.my_task
tasks_data["myuuid"] = self.my_task
self.elastic.finish_task(
tasks_data,
'ok',
result
)
self.elastic.finish_task(tasks_data, "ok", result)
task_data = tasks_data['myuuid']
host_data = task_data.host_data['include']
self.assertEqual(host_data.uuid, 'include')
self.assertEqual(host_data.name, 'include')
self.assertEqual(host_data.status, 'ok')
task_data = tasks_data["myuuid"]
host_data = task_data.host_data["include"]
self.assertEqual(host_data.uuid, "include")
self.assertEqual(host_data.name, "include")
self.assertEqual(host_data.status, "ok")
def test_get_error_message(self):
test_cases = (
('my-exception', 'my-msg', None, 'my-exception'),
(None, 'my-msg', None, 'my-msg'),
(None, None, None, 'failed'),
("my-exception", "my-msg", None, "my-exception"),
(None, "my-msg", None, "my-msg"),
(None, None, None, "failed"),
)
for tc in test_cases:
@@ -103,11 +92,21 @@ class TestOpentelemetry(unittest.TestCase):
def test_enrich_error_message(self):
test_cases = (
('my-exception', 'my-msg', 'my-stderr', 'message: "my-msg"\nexception: "my-exception"\nstderr: "my-stderr"'),
('my-exception', None, 'my-stderr', 'message: "failed"\nexception: "my-exception"\nstderr: "my-stderr"'),
(None, 'my-msg', 'my-stderr', 'message: "my-msg"\nexception: "None"\nstderr: "my-stderr"'),
('my-exception', 'my-msg', None, 'message: "my-msg"\nexception: "my-exception"\nstderr: "None"'),
('my-exception', 'my-msg', '\nline1\nline2', 'message: "my-msg"\nexception: "my-exception"\nstderr: "\nline1\nline2"')
(
"my-exception",
"my-msg",
"my-stderr",
'message: "my-msg"\nexception: "my-exception"\nstderr: "my-stderr"',
),
("my-exception", None, "my-stderr", 'message: "failed"\nexception: "my-exception"\nstderr: "my-stderr"'),
(None, "my-msg", "my-stderr", 'message: "my-msg"\nexception: "None"\nstderr: "my-stderr"'),
("my-exception", "my-msg", None, 'message: "my-msg"\nexception: "my-exception"\nstderr: "None"'),
(
"my-exception",
"my-msg",
"\nline1\nline2",
'message: "my-msg"\nexception: "my-exception"\nstderr: "\nline1\nline2"',
),
)
for tc in test_cases:
@@ -118,9 +117,9 @@ class TestOpentelemetry(unittest.TestCase):
def generate_test_data(exception=None, msg=None, stderr=None):
res_data = OrderedDict()
if exception:
res_data['exception'] = exception
res_data["exception"] = exception
if msg:
res_data['msg'] = msg
res_data["msg"] = msg
if stderr:
res_data['stderr'] = stderr
res_data["stderr"] = stderr
return res_data

View File

@@ -14,52 +14,59 @@ from ansible_collections.community.general.plugins.callback.loganalytics import
class TestAzureLogAnalytics(unittest.TestCase):
@patch('ansible_collections.community.general.plugins.callback.loganalytics.socket')
@patch("ansible_collections.community.general.plugins.callback.loganalytics.socket")
def setUp(self, mock_socket):
mock_socket.gethostname.return_value = 'my-host'
mock_socket.gethostbyname.return_value = '1.2.3.4'
mock_socket.gethostname.return_value = "my-host"
mock_socket.gethostbyname.return_value = "1.2.3.4"
self.loganalytics = AzureLogAnalyticsSource()
self.mock_task = Mock('MockTask')
self.mock_task._role = 'myrole'
self.mock_task._uuid = 'myuuid'
self.task_fields = {'args': {}}
self.mock_host = Mock('MockHost')
self.mock_host.name = 'myhost'
self.mock_task = Mock("MockTask")
self.mock_task._role = "myrole"
self.mock_task._uuid = "myuuid"
self.task_fields = {"args": {}}
self.mock_host = Mock("MockHost")
self.mock_host.name = "myhost"
@patch('ansible_collections.community.general.plugins.callback.loganalytics.now')
@patch('ansible_collections.community.general.plugins.callback.loganalytics.open_url')
@patch("ansible_collections.community.general.plugins.callback.loganalytics.now")
@patch("ansible_collections.community.general.plugins.callback.loganalytics.open_url")
def test_overall(self, open_url_mock, mock_now):
mock_now.return_value = datetime(2020, 12, 1)
result = TaskResult(host=self.mock_host, task=self.mock_task, return_data={}, task_fields=self.task_fields)
self.loganalytics.send_event(workspace_id='01234567-0123-0123-0123-01234567890a',
shared_key='dZD0kCbKl3ehZG6LHFMuhtE0yHiFCmetzFMc2u+roXIUQuatqU924SsAAAAPemhjbGlAemhjbGktTUJQAQIDBA==',
state='OK',
result=result,
runtime=100)
self.loganalytics.send_event(
workspace_id="01234567-0123-0123-0123-01234567890a",
shared_key="dZD0kCbKl3ehZG6LHFMuhtE0yHiFCmetzFMc2u+roXIUQuatqU924SsAAAAPemhjbGlAemhjbGktTUJQAQIDBA==",
state="OK",
result=result,
runtime=100,
)
args, kwargs = open_url_mock.call_args
sent_data = json.loads(args[1])
self.assertEqual(sent_data['event']['timestamp'], 'Tue, 01 Dec 2020 00:00:00 GMT')
self.assertEqual(sent_data['event']['host'], 'my-host')
self.assertEqual(sent_data['event']['uuid'], 'myuuid')
self.assertEqual(args[0], 'https://01234567-0123-0123-0123-01234567890a.ods.opinsights.azure.com/api/logs?api-version=2016-04-01')
self.assertEqual(sent_data["event"]["timestamp"], "Tue, 01 Dec 2020 00:00:00 GMT")
self.assertEqual(sent_data["event"]["host"], "my-host")
self.assertEqual(sent_data["event"]["uuid"], "myuuid")
self.assertEqual(
args[0],
"https://01234567-0123-0123-0123-01234567890a.ods.opinsights.azure.com/api/logs?api-version=2016-04-01",
)
@patch('ansible_collections.community.general.plugins.callback.loganalytics.now')
@patch('ansible_collections.community.general.plugins.callback.loganalytics.open_url')
@patch("ansible_collections.community.general.plugins.callback.loganalytics.now")
@patch("ansible_collections.community.general.plugins.callback.loganalytics.open_url")
def test_auth_headers(self, open_url_mock, mock_now):
mock_now.return_value = datetime(2020, 12, 1)
result = TaskResult(host=self.mock_host, task=self.mock_task, return_data={}, task_fields=self.task_fields)
self.loganalytics.send_event(workspace_id='01234567-0123-0123-0123-01234567890a',
shared_key='dZD0kCbKl3ehZG6LHFMuhtE0yHiFCmetzFMc2u+roXIUQuatqU924SsAAAAPemhjbGlAemhjbGktTUJQAQIDBA==',
state='OK',
result=result,
runtime=100)
self.loganalytics.send_event(
workspace_id="01234567-0123-0123-0123-01234567890a",
shared_key="dZD0kCbKl3ehZG6LHFMuhtE0yHiFCmetzFMc2u+roXIUQuatqU924SsAAAAPemhjbGlAemhjbGktTUJQAQIDBA==",
state="OK",
result=result,
runtime=100,
)
args, kwargs = open_url_mock.call_args
headers = kwargs['headers']
headers = kwargs["headers"]
self.assertRegex(headers['Authorization'], r'^SharedKey 01234567-0123-0123-0123-01234567890a:.*=$')
self.assertEqual(headers['Log-Type'], 'ansible_playbook')
self.assertRegex(headers["Authorization"], r"^SharedKey 01234567-0123-0123-0123-01234567890a:.*=$")
self.assertEqual(headers["Log-Type"], "ansible_playbook")

View File

@@ -17,88 +17,77 @@ OPENTELEMETRY_MINIMUM_PYTHON_VERSION = (3, 7)
class TestOpentelemetry(unittest.TestCase):
@patch('ansible_collections.community.general.plugins.callback.opentelemetry.socket')
@patch("ansible_collections.community.general.plugins.callback.opentelemetry.socket")
def setUp(self, mock_socket):
# TODO: this python version validation won't be needed as long as the _time_ns call is mocked.
if sys.version_info < OPENTELEMETRY_MINIMUM_PYTHON_VERSION:
self.skipTest(f"Python {'.'.join(map(str, OPENTELEMETRY_MINIMUM_PYTHON_VERSION))}+ is needed for OpenTelemetry")
self.skipTest(
f"Python {'.'.join(map(str, OPENTELEMETRY_MINIMUM_PYTHON_VERSION))}+ is needed for OpenTelemetry"
)
mock_socket.gethostname.return_value = 'my-host'
mock_socket.gethostbyname.return_value = '1.2.3.4'
mock_socket.gethostname.return_value = "my-host"
mock_socket.gethostbyname.return_value = "1.2.3.4"
self.opentelemetry = OpenTelemetrySource(display=None)
self.task_fields = {'args': {}}
self.mock_host = Mock('MockHost')
self.mock_host.name = 'myhost'
self.mock_host._uuid = 'myhost_uuid'
self.task_fields = {"args": {}}
self.mock_host = Mock("MockHost")
self.mock_host.name = "myhost"
self.mock_host._uuid = "myhost_uuid"
self.mock_task = Task()
self.mock_task.action = 'myaction'
self.mock_task.action = "myaction"
self.mock_task.no_log = False
self.mock_task._role = 'myrole'
self.mock_task._uuid = 'myuuid'
self.mock_task._role = "myrole"
self.mock_task._uuid = "myuuid"
self.mock_task.args = {}
self.mock_task.get_name = MagicMock(return_value='mytask')
self.mock_task.get_path = MagicMock(return_value='/mypath')
self.my_task = TaskData('myuuid', 'mytask', '/mypath', 'myplay', 'myaction', '')
self.my_task_result = TaskResult(host=self.mock_host, task=self.mock_task, return_data={}, task_fields=self.task_fields)
self.mock_task.get_name = MagicMock(return_value="mytask")
self.mock_task.get_path = MagicMock(return_value="/mypath")
self.my_task = TaskData("myuuid", "mytask", "/mypath", "myplay", "myaction", "")
self.my_task_result = TaskResult(
host=self.mock_host, task=self.mock_task, return_data={}, task_fields=self.task_fields
)
def test_start_task(self):
tasks_data = OrderedDict()
self.opentelemetry.start_task(
tasks_data,
False,
'myplay',
self.mock_task
)
self.opentelemetry.start_task(tasks_data, False, "myplay", self.mock_task)
task_data = tasks_data['myuuid']
self.assertEqual(task_data.uuid, 'myuuid')
self.assertEqual(task_data.name, 'mytask')
self.assertEqual(task_data.path, '/mypath')
self.assertEqual(task_data.play, 'myplay')
self.assertEqual(task_data.action, 'myaction')
task_data = tasks_data["myuuid"]
self.assertEqual(task_data.uuid, "myuuid")
self.assertEqual(task_data.name, "mytask")
self.assertEqual(task_data.path, "/mypath")
self.assertEqual(task_data.play, "myplay")
self.assertEqual(task_data.action, "myaction")
self.assertEqual(task_data.args, {})
def test_finish_task_with_a_host_match(self):
tasks_data = OrderedDict()
tasks_data['myuuid'] = self.my_task
tasks_data["myuuid"] = self.my_task
self.opentelemetry.finish_task(
tasks_data,
'ok',
self.my_task_result,
""
)
self.opentelemetry.finish_task(tasks_data, "ok", self.my_task_result, "")
task_data = tasks_data['myuuid']
host_data = task_data.host_data['myhost_uuid']
self.assertEqual(host_data.uuid, 'myhost_uuid')
self.assertEqual(host_data.name, 'myhost')
self.assertEqual(host_data.status, 'ok')
task_data = tasks_data["myuuid"]
host_data = task_data.host_data["myhost_uuid"]
self.assertEqual(host_data.uuid, "myhost_uuid")
self.assertEqual(host_data.name, "myhost")
self.assertEqual(host_data.status, "ok")
def test_finish_task_without_a_host_match(self):
result = TaskResult(host=None, task=self.mock_task, return_data={}, task_fields=self.task_fields)
tasks_data = OrderedDict()
tasks_data['myuuid'] = self.my_task
tasks_data["myuuid"] = self.my_task
self.opentelemetry.finish_task(
tasks_data,
'ok',
result,
""
)
self.opentelemetry.finish_task(tasks_data, "ok", result, "")
task_data = tasks_data['myuuid']
host_data = task_data.host_data['include']
self.assertEqual(host_data.uuid, 'include')
self.assertEqual(host_data.name, 'include')
self.assertEqual(host_data.status, 'ok')
task_data = tasks_data["myuuid"]
host_data = task_data.host_data["include"]
self.assertEqual(host_data.uuid, "include")
self.assertEqual(host_data.name, "include")
self.assertEqual(host_data.status, "ok")
def test_get_error_message(self):
test_cases = (
('my-exception', 'my-msg', None, 'my-exception'),
(None, 'my-msg', None, 'my-msg'),
(None, None, None, 'failed'),
("my-exception", "my-msg", None, "my-exception"),
(None, "my-msg", None, "my-msg"),
(None, None, None, "failed"),
)
for tc in test_cases:
@@ -107,25 +96,37 @@ class TestOpentelemetry(unittest.TestCase):
def test_get_error_message_from_results(self):
test_cases = (
('my-exception', 'my-msg', None, False, None),
(None, 'my-msg', None, False, None),
("my-exception", "my-msg", None, False, None),
(None, "my-msg", None, False, None),
(None, None, None, False, None),
('my-exception', 'my-msg', None, True, 'shell(none) - my-exception'),
(None, 'my-msg', None, True, 'shell(none) - my-msg'),
(None, None, None, True, 'shell(none) - failed'),
("my-exception", "my-msg", None, True, "shell(none) - my-exception"),
(None, "my-msg", None, True, "shell(none) - my-msg"),
(None, None, None, True, "shell(none) - failed"),
)
for tc in test_cases:
result = self.opentelemetry.get_error_message_from_results([generate_test_data(tc[0], tc[1], tc[2], tc[3])], 'shell')
result = self.opentelemetry.get_error_message_from_results(
[generate_test_data(tc[0], tc[1], tc[2], tc[3])], "shell"
)
self.assertEqual(result, tc[4])
def test_enrich_error_message(self):
test_cases = (
('my-exception', 'my-msg', 'my-stderr', 'message: "my-msg"\nexception: "my-exception"\nstderr: "my-stderr"'),
('my-exception', None, 'my-stderr', 'message: "failed"\nexception: "my-exception"\nstderr: "my-stderr"'),
(None, 'my-msg', 'my-stderr', 'message: "my-msg"\nexception: "None"\nstderr: "my-stderr"'),
('my-exception', 'my-msg', None, 'message: "my-msg"\nexception: "my-exception"\nstderr: "None"'),
('my-exception', 'my-msg', '\nline1\nline2', 'message: "my-msg"\nexception: "my-exception"\nstderr: "\nline1\nline2"')
(
"my-exception",
"my-msg",
"my-stderr",
'message: "my-msg"\nexception: "my-exception"\nstderr: "my-stderr"',
),
("my-exception", None, "my-stderr", 'message: "failed"\nexception: "my-exception"\nstderr: "my-stderr"'),
(None, "my-msg", "my-stderr", 'message: "my-msg"\nexception: "None"\nstderr: "my-stderr"'),
("my-exception", "my-msg", None, 'message: "my-msg"\nexception: "my-exception"\nstderr: "None"'),
(
"my-exception",
"my-msg",
"\nline1\nline2",
'message: "my-msg"\nexception: "my-exception"\nstderr: "\nline1\nline2"',
),
)
for tc in test_cases:
@@ -134,29 +135,61 @@ class TestOpentelemetry(unittest.TestCase):
def test_enrich_error_message_from_results(self):
test_cases = (
('my-exception', 'my-msg', 'my-stderr', False, ''),
('my-exception', None, 'my-stderr', False, ''),
(None, 'my-msg', 'my-stderr', False, ''),
('my-exception', 'my-msg', None, False, ''),
('my-exception', 'my-msg', '\nline1\nline2', False, ''),
('my-exception', 'my-msg', 'my-stderr', True, 'shell(none) - message: "my-msg"\nexception: "my-exception"\nstderr: "my-stderr"\n'),
('my-exception', None, 'my-stderr', True, 'shell(none) - message: "failed"\nexception: "my-exception"\nstderr: "my-stderr"\n'),
(None, 'my-msg', 'my-stderr', True, 'shell(none) - message: "my-msg"\nexception: "None"\nstderr: "my-stderr"\n'),
('my-exception', 'my-msg', None, True, 'shell(none) - message: "my-msg"\nexception: "my-exception"\nstderr: "None"\n'),
('my-exception', 'my-msg', '\nline1\nline2', True, 'shell(none) - message: "my-msg"\nexception: "my-exception"\nstderr: "\nline1\nline2"\n')
("my-exception", "my-msg", "my-stderr", False, ""),
("my-exception", None, "my-stderr", False, ""),
(None, "my-msg", "my-stderr", False, ""),
("my-exception", "my-msg", None, False, ""),
("my-exception", "my-msg", "\nline1\nline2", False, ""),
(
"my-exception",
"my-msg",
"my-stderr",
True,
'shell(none) - message: "my-msg"\nexception: "my-exception"\nstderr: "my-stderr"\n',
),
(
"my-exception",
None,
"my-stderr",
True,
'shell(none) - message: "failed"\nexception: "my-exception"\nstderr: "my-stderr"\n',
),
(
None,
"my-msg",
"my-stderr",
True,
'shell(none) - message: "my-msg"\nexception: "None"\nstderr: "my-stderr"\n',
),
(
"my-exception",
"my-msg",
None,
True,
'shell(none) - message: "my-msg"\nexception: "my-exception"\nstderr: "None"\n',
),
(
"my-exception",
"my-msg",
"\nline1\nline2",
True,
'shell(none) - message: "my-msg"\nexception: "my-exception"\nstderr: "\nline1\nline2"\n',
),
)
for tc in test_cases:
result = self.opentelemetry.enrich_error_message_from_results([generate_test_data(tc[0], tc[1], tc[2], tc[3])], 'shell')
result = self.opentelemetry.enrich_error_message_from_results(
[generate_test_data(tc[0], tc[1], tc[2], tc[3])], "shell"
)
self.assertEqual(result, tc[4])
def test_url_from_args(self):
test_cases = (
({}, ""),
({'url': 'my-url'}, 'my-url'),
({'url': 'my-url', 'api_url': 'my-api_url'}, 'my-url'),
({'api_url': 'my-api_url'}, 'my-api_url'),
({'api_url': 'my-api_url', 'chart_repo_url': 'my-chart_repo_url'}, 'my-api_url')
({"url": "my-url"}, "my-url"),
({"url": "my-url", "api_url": "my-api_url"}, "my-url"),
({"api_url": "my-api_url"}, "my-api_url"),
({"api_url": "my-api_url", "chart_repo_url": "my-chart_repo_url"}, "my-api_url"),
)
for tc in test_cases:
@@ -166,12 +199,12 @@ class TestOpentelemetry(unittest.TestCase):
def test_parse_and_redact_url_if_possible(self):
test_cases = (
({}, None),
({'url': 'wrong'}, None),
({'url': 'https://my-url'}, 'https://my-url'),
({'url': 'https://user:pass@my-url'}, 'https://my-url'),
({'url': 'https://my-url:{{ my_port }}'}, 'https://my-url:{{ my_port }}'),
({'url': 'https://{{ my_hostname }}:{{ my_port }}'}, None),
({'url': '{{my_schema}}{{ my_hostname }}:{{ my_port }}'}, None)
({"url": "wrong"}, None),
({"url": "https://my-url"}, "https://my-url"),
({"url": "https://user:pass@my-url"}, "https://my-url"),
({"url": "https://my-url:{{ my_port }}"}, "https://my-url:{{ my_port }}"),
({"url": "https://{{ my_hostname }}:{{ my_port }}"}, None),
({"url": "{{my_schema}}{{ my_hostname }}:{{ my_port }}"}, None),
)
for tc in test_cases:
@@ -185,10 +218,10 @@ class TestOpentelemetry(unittest.TestCase):
def generate_test_data(exception=None, msg=None, stderr=None, failed=False):
res_data = OrderedDict()
if exception:
res_data['exception'] = exception
res_data["exception"] = exception
if msg:
res_data['msg'] = msg
res_data["msg"] = msg
if stderr:
res_data['stderr'] = stderr
res_data['failed'] = failed
res_data["stderr"] = stderr
res_data["failed"] = failed
return res_data

View File

@@ -14,50 +14,62 @@ import json
class TestSplunkClient(unittest.TestCase):
@patch('ansible_collections.community.general.plugins.callback.splunk.socket')
@patch("ansible_collections.community.general.plugins.callback.splunk.socket")
def setUp(self, mock_socket):
mock_socket.gethostname.return_value = 'my-host'
mock_socket.gethostbyname.return_value = '1.2.3.4'
mock_socket.gethostname.return_value = "my-host"
mock_socket.gethostbyname.return_value = "1.2.3.4"
self.splunk = SplunkHTTPCollectorSource()
self.mock_task = Mock('MockTask')
self.mock_task._role = 'myrole'
self.mock_task._uuid = 'myuuid'
self.task_fields = {'args': {}}
self.mock_host = Mock('MockHost')
self.mock_host.name = 'myhost'
self.mock_task = Mock("MockTask")
self.mock_task._role = "myrole"
self.mock_task._uuid = "myuuid"
self.task_fields = {"args": {}}
self.mock_host = Mock("MockHost")
self.mock_host.name = "myhost"
@patch('ansible_collections.community.general.plugins.callback.splunk.now')
@patch('ansible_collections.community.general.plugins.callback.splunk.open_url')
@patch("ansible_collections.community.general.plugins.callback.splunk.now")
@patch("ansible_collections.community.general.plugins.callback.splunk.open_url")
def test_timestamp_with_milliseconds(self, open_url_mock, mock_now):
mock_now.return_value = datetime(2020, 12, 1)
result = TaskResult(host=self.mock_host, task=self.mock_task, return_data={}, task_fields=self.task_fields)
self.splunk.send_event(
url='endpoint', authtoken='token', validate_certs=False, include_milliseconds=True,
batch="abcefghi-1234-5678-9012-abcdefghijkl", state='OK', result=result, runtime=100
url="endpoint",
authtoken="token",
validate_certs=False,
include_milliseconds=True,
batch="abcefghi-1234-5678-9012-abcdefghijkl",
state="OK",
result=result,
runtime=100,
)
args, kwargs = open_url_mock.call_args
sent_data = json.loads(args[1])
self.assertEqual(sent_data['event']['timestamp'], '2020-12-01 00:00:00.000000 +0000')
self.assertEqual(sent_data['event']['host'], 'my-host')
self.assertEqual(sent_data['event']['ip_address'], '1.2.3.4')
self.assertEqual(sent_data["event"]["timestamp"], "2020-12-01 00:00:00.000000 +0000")
self.assertEqual(sent_data["event"]["host"], "my-host")
self.assertEqual(sent_data["event"]["ip_address"], "1.2.3.4")
@patch('ansible_collections.community.general.plugins.callback.splunk.now')
@patch('ansible_collections.community.general.plugins.callback.splunk.open_url')
@patch("ansible_collections.community.general.plugins.callback.splunk.now")
@patch("ansible_collections.community.general.plugins.callback.splunk.open_url")
def test_timestamp_without_milliseconds(self, open_url_mock, mock_now):
mock_now.return_value = datetime(2020, 12, 1)
result = TaskResult(host=self.mock_host, task=self.mock_task, return_data={}, task_fields=self.task_fields)
self.splunk.send_event(
url='endpoint', authtoken='token', validate_certs=False, include_milliseconds=False,
batch="abcefghi-1234-5678-9012-abcdefghijkl", state='OK', result=result, runtime=100
url="endpoint",
authtoken="token",
validate_certs=False,
include_milliseconds=False,
batch="abcefghi-1234-5678-9012-abcdefghijkl",
state="OK",
result=result,
runtime=100,
)
args, kwargs = open_url_mock.call_args
sent_data = json.loads(args[1])
self.assertEqual(sent_data['event']['timestamp'], '2020-12-01 00:00:00 +0000')
self.assertEqual(sent_data['event']['host'], 'my-host')
self.assertEqual(sent_data['event']['ip_address'], '1.2.3.4')
self.assertEqual(sent_data["event"]["timestamp"], "2020-12-01 00:00:00 +0000")
self.assertEqual(sent_data["event"]["host"], "my-host")
self.assertEqual(sent_data["event"]["ip_address"], "1.2.3.4")

View File

@@ -24,9 +24,9 @@ def lxc(request):
When true (default), a mocked liblxc module is injected. If False,
no liblxc will be present.
"""
liblxc_present = getattr(request, 'param', True)
liblxc_present = getattr(request, "param", True)
class ContainerMock():
class ContainerMock:
# dict of container name to its state
_container_states = {}
@@ -36,56 +36,55 @@ def lxc(request):
@property
def state(self):
return ContainerMock._container_states.get(self.name, 'STARTED')
return ContainerMock._container_states.get(self.name, "STARTED")
liblxc_module_mock = mock.MagicMock()
liblxc_module_mock.Container = ContainerMock
with mock.patch.dict('sys.modules'):
with mock.patch.dict("sys.modules"):
if liblxc_present:
sys.modules['lxc'] = liblxc_module_mock
elif 'lxc' in sys.modules:
del sys.modules['lxc']
sys.modules["lxc"] = liblxc_module_mock
elif "lxc" in sys.modules:
del sys.modules["lxc"]
from ansible_collections.community.general.plugins.connection import lxc as lxc_plugin_module
assert lxc_plugin_module.HAS_LIBLXC == liblxc_present
assert bool(getattr(lxc_plugin_module, '_lxc', None)) == liblxc_present
assert bool(getattr(lxc_plugin_module, "_lxc", None)) == liblxc_present
yield lxc_plugin_module
class TestLXCConnectionClass():
@pytest.mark.parametrize('lxc', [True, False], indirect=True)
class TestLXCConnectionClass:
@pytest.mark.parametrize("lxc", [True, False], indirect=True)
def test_lxc_connection_module(self, lxc):
"""Test that a connection can be created with the plugin."""
play_context = PlayContext()
in_stream = StringIO()
conn = connection_loader.get('lxc', play_context, in_stream)
conn = connection_loader.get("lxc", play_context, in_stream)
assert conn
assert isinstance(conn, lxc.Connection)
@pytest.mark.parametrize('lxc', [False], indirect=True)
@pytest.mark.parametrize("lxc", [False], indirect=True)
def test_lxc_connection_liblxc_error(self, lxc):
"""Test that on connect an error is thrown if liblxc is not present."""
play_context = PlayContext()
in_stream = StringIO()
conn = connection_loader.get('lxc', play_context, in_stream)
conn = connection_loader.get("lxc", play_context, in_stream)
with pytest.raises(AnsibleError, match='lxc python bindings are not installed'):
with pytest.raises(AnsibleError, match="lxc python bindings are not installed"):
conn._connect()
def test_remote_addr_option(self):
"""Test that the remote_addr option is used"""
play_context = PlayContext()
in_stream = StringIO()
conn = connection_loader.get('lxc', play_context, in_stream)
conn = connection_loader.get("lxc", play_context, in_stream)
container_name = 'my-container'
conn.set_option('remote_addr', container_name)
assert conn.get_option('remote_addr') == container_name
container_name = "my-container"
conn.set_option("remote_addr", container_name)
assert conn.get_option("remote_addr") == container_name
conn._connect()
assert conn.container_name == container_name
@@ -94,23 +93,23 @@ class TestLXCConnectionClass():
"""Test that on connect an error is thrown if the container is stopped."""
play_context = PlayContext()
in_stream = StringIO()
conn = connection_loader.get('lxc', play_context, in_stream)
conn.set_option('remote_addr', 'my-container')
conn = connection_loader.get("lxc", play_context, in_stream)
conn.set_option("remote_addr", "my-container")
lxc._lxc.Container._container_states['my-container'] = 'STOPPED'
lxc._lxc.Container._container_states["my-container"] = "STOPPED"
with pytest.raises(AnsibleError, match='my-container is not running'):
with pytest.raises(AnsibleError, match="my-container is not running"):
conn._connect()
def test_container_name_change(self):
"""Test connect method reconnects when remote_addr changes"""
play_context = PlayContext()
in_stream = StringIO()
conn = connection_loader.get('lxc', play_context, in_stream)
conn = connection_loader.get("lxc", play_context, in_stream)
# setting the option does nothing
container1_name = 'my-container'
conn.set_option('remote_addr', container1_name)
container1_name = "my-container"
conn.set_option("remote_addr", container1_name)
assert conn.container_name is None
assert conn.container is None
@@ -128,8 +127,8 @@ class TestLXCConnectionClass():
assert conn.container.name == container1_name
# setting the option does again nothing
container2_name = 'my-other-container'
conn.set_option('remote_addr', container2_name)
container2_name = "my-other-container"
conn.set_option("remote_addr", container2_name)
assert conn.container_name == container1_name
assert conn.container is container1
assert conn.container.name == container1_name

View File

@@ -18,126 +18,126 @@ from pathlib import Path
from unittest.mock import patch, MagicMock, mock_open
paramiko = pytest.importorskip('paramiko')
paramiko = pytest.importorskip("paramiko")
@pytest.fixture
def connection():
play_context = PlayContext()
in_stream = StringIO()
conn = connection_loader.get('community.general.wsl', play_context, in_stream)
conn.set_option('remote_addr', '192.168.1.100')
conn.set_option('remote_user', 'root')
conn.set_option('password', 'password')
conn.set_option('wsl_distribution', 'test')
conn = connection_loader.get("community.general.wsl", play_context, in_stream)
conn.set_option("remote_addr", "192.168.1.100")
conn.set_option("remote_user", "root")
conn.set_option("password", "password")
conn.set_option("wsl_distribution", "test")
return conn
def test_connection_options(connection):
""" Test that connection options are properly set """
assert connection.get_option('remote_addr') == '192.168.1.100'
assert connection.get_option('remote_user') == 'root'
assert connection.get_option('password') == 'password'
assert connection.get_option('wsl_distribution') == 'test'
"""Test that connection options are properly set"""
assert connection.get_option("remote_addr") == "192.168.1.100"
assert connection.get_option("remote_user") == "root"
assert connection.get_option("password") == "password"
assert connection.get_option("wsl_distribution") == "test"
def test_authenticity_msg():
""" Test authenticity message formatting """
msg = authenticity_msg('test.host', 'ssh-rsa', 'AA:BB:CC:DD')
assert 'test.host' in msg
assert 'ssh-rsa' in msg
assert 'AA:BB:CC:DD' in msg
"""Test authenticity message formatting"""
msg = authenticity_msg("test.host", "ssh-rsa", "AA:BB:CC:DD")
assert "test.host" in msg
assert "ssh-rsa" in msg
assert "AA:BB:CC:DD" in msg
def test_missing_host_key(connection):
""" Test MyAddPolicy missing_host_key method """
"""Test MyAddPolicy missing_host_key method"""
client = MagicMock()
key = MagicMock()
key.get_fingerprint.return_value = b'fingerprint'
key.get_name.return_value = 'ssh-rsa'
key.get_fingerprint.return_value = b"fingerprint"
key.get_name.return_value = "ssh-rsa"
policy = MyAddPolicy(connection)
connection.set_option('host_key_auto_add', True)
policy.missing_host_key(client, 'test.host', key)
assert hasattr(key, '_added_by_ansible_this_time')
connection.set_option("host_key_auto_add", True)
policy.missing_host_key(client, "test.host", key)
assert hasattr(key, "_added_by_ansible_this_time")
connection.set_option('host_key_auto_add', False)
connection.set_option('host_key_checking', False)
policy.missing_host_key(client, 'test.host', key)
connection.set_option("host_key_auto_add", False)
connection.set_option("host_key_checking", False)
policy.missing_host_key(client, "test.host", key)
connection.set_option('host_key_checking', True)
connection.set_option('host_key_auto_add', False)
connection.set_option('use_persistent_connections', False)
connection.set_option("host_key_checking", True)
connection.set_option("host_key_auto_add", False)
connection.set_option("use_persistent_connections", False)
with patch('ansible.utils.display.Display.prompt_until', return_value='yes'):
policy.missing_host_key(client, 'test.host', key)
with patch("ansible.utils.display.Display.prompt_until", return_value="yes"):
policy.missing_host_key(client, "test.host", key)
with patch('ansible.utils.display.Display.prompt_until', return_value='no'):
with pytest.raises(AnsibleError, match='host connection rejected by user'):
policy.missing_host_key(client, 'test.host', key)
with patch("ansible.utils.display.Display.prompt_until", return_value="no"):
with pytest.raises(AnsibleError, match="host connection rejected by user"):
policy.missing_host_key(client, "test.host", key)
def test_set_log_channel(connection):
""" Test setting log channel """
connection._set_log_channel('test_channel')
assert connection._log_channel == 'test_channel'
"""Test setting log channel"""
connection._set_log_channel("test_channel")
assert connection._log_channel == "test_channel"
def test_parse_proxy_command(connection):
""" Test proxy command parsing """
connection.set_option('proxy_command', 'ssh -W %h:%p proxy.example.com')
connection.set_option('remote_addr', 'target.example.com')
connection.set_option('remote_user', 'testuser')
"""Test proxy command parsing"""
connection.set_option("proxy_command", "ssh -W %h:%p proxy.example.com")
connection.set_option("remote_addr", "target.example.com")
connection.set_option("remote_user", "testuser")
result = connection._parse_proxy_command(port=2222)
assert 'sock' in result
assert isinstance(result['sock'], paramiko.ProxyCommand)
assert "sock" in result
assert isinstance(result["sock"], paramiko.ProxyCommand)
@patch('paramiko.SSHClient')
@patch("paramiko.SSHClient")
def test_connect_with_rsa_sha2_disabled(mock_ssh, connection):
""" Test connection with RSA SHA2 algorithms disabled """
connection.set_option('use_rsa_sha2_algorithms', False)
"""Test connection with RSA SHA2 algorithms disabled"""
connection.set_option("use_rsa_sha2_algorithms", False)
mock_client = MagicMock()
mock_ssh.return_value = mock_client
connection._connect()
call_kwargs = mock_client.connect.call_args[1]
assert 'disabled_algorithms' in call_kwargs
assert 'pubkeys' in call_kwargs['disabled_algorithms']
assert "disabled_algorithms" in call_kwargs
assert "pubkeys" in call_kwargs["disabled_algorithms"]
@patch('paramiko.SSHClient')
@patch("paramiko.SSHClient")
def test_connect_with_bad_host_key(mock_ssh, connection):
""" Test connection with bad host key """
"""Test connection with bad host key"""
mock_client = MagicMock()
mock_ssh.return_value = mock_client
mock_client.connect.side_effect = paramiko.ssh_exception.BadHostKeyException(
'hostname', MagicMock(), MagicMock())
mock_client.connect.side_effect = paramiko.ssh_exception.BadHostKeyException("hostname", MagicMock(), MagicMock())
with pytest.raises(AnsibleConnectionFailure, match='host key mismatch'):
with pytest.raises(AnsibleConnectionFailure, match="host key mismatch"):
connection._connect()
@patch('paramiko.SSHClient')
@patch("paramiko.SSHClient")
def test_connect_with_invalid_host_key(mock_ssh, connection):
""" Test connection with bad host key """
connection.set_option('host_key_checking', True)
"""Test connection with bad host key"""
connection.set_option("host_key_checking", True)
mock_client = MagicMock()
mock_ssh.return_value = mock_client
mock_client.load_system_host_keys.side_effect = paramiko.hostkeys.InvalidHostKey(
"Bad Line!", Exception('Something crashed!'))
"Bad Line!", Exception("Something crashed!")
)
with pytest.raises(AnsibleConnectionFailure, match="Invalid host key: Bad Line!"):
connection._connect()
@patch('paramiko.SSHClient')
@patch("paramiko.SSHClient")
def test_connect_success(mock_ssh, connection):
""" Test successful SSH connection establishment """
"""Test successful SSH connection establishment"""
mock_client = MagicMock()
mock_ssh.return_value = mock_client
@@ -147,81 +147,72 @@ def test_connect_success(mock_ssh, connection):
assert connection._connected
@patch('paramiko.SSHClient')
@patch("paramiko.SSHClient")
def test_connect_authentication_failure(mock_ssh, connection):
""" Test SSH connection with authentication failure """
"""Test SSH connection with authentication failure"""
mock_client = MagicMock()
mock_ssh.return_value = mock_client
mock_client.connect.side_effect = paramiko.ssh_exception.AuthenticationException('Auth failed')
mock_client.connect.side_effect = paramiko.ssh_exception.AuthenticationException("Auth failed")
with pytest.raises(AnsibleAuthenticationFailure):
connection._connect()
def test_any_keys_added(connection):
""" Test checking for added host keys """
"""Test checking for added host keys"""
connection.ssh = MagicMock()
connection.ssh._host_keys = {
'host1': {
'ssh-rsa': MagicMock(_added_by_ansible_this_time=True),
'ssh-ed25519': MagicMock(_added_by_ansible_this_time=False)
"host1": {
"ssh-rsa": MagicMock(_added_by_ansible_this_time=True),
"ssh-ed25519": MagicMock(_added_by_ansible_this_time=False),
}
}
assert connection._any_keys_added() is True
connection.ssh._host_keys = {
'host1': {
'ssh-rsa': MagicMock(_added_by_ansible_this_time=False)
}
}
connection.ssh._host_keys = {"host1": {"ssh-rsa": MagicMock(_added_by_ansible_this_time=False)}}
assert connection._any_keys_added() is False
@patch('os.path.exists')
@patch('os.stat')
@patch('tempfile.NamedTemporaryFile')
@patch("os.path.exists")
@patch("os.stat")
@patch("tempfile.NamedTemporaryFile")
def test_save_ssh_host_keys(mock_tempfile, mock_stat, mock_exists, connection):
""" Test saving SSH host keys """
"""Test saving SSH host keys"""
mock_exists.return_value = True
mock_stat.return_value = MagicMock(st_mode=0o644, st_uid=1000, st_gid=1000)
mock_tempfile.return_value.__enter__.return_value.name = '/tmp/test_keys'
mock_tempfile.return_value.__enter__.return_value.name = "/tmp/test_keys"
connection.ssh = MagicMock()
connection.ssh._host_keys = {
'host1': {
'ssh-rsa': MagicMock(
get_base64=lambda: 'KEY1',
_added_by_ansible_this_time=True
)
}
"host1": {"ssh-rsa": MagicMock(get_base64=lambda: "KEY1", _added_by_ansible_this_time=True)}
}
mock_open_obj = mock_open()
with patch('builtins.open', mock_open_obj):
connection._save_ssh_host_keys('/tmp/test_keys')
with patch("builtins.open", mock_open_obj):
connection._save_ssh_host_keys("/tmp/test_keys")
mock_open_obj().write.assert_called_with('host1 ssh-rsa KEY1\n')
mock_open_obj().write.assert_called_with("host1 ssh-rsa KEY1\n")
def test_build_wsl_command(connection):
""" Test wsl command building with different users """
"""Test wsl command building with different users"""
cmd = connection._build_wsl_command('/bin/sh -c "ls -la"')
assert cmd == 'wsl.exe --distribution test -- /bin/sh -c "ls -la"'
connection.set_option('wsl_user', 'test-user')
connection.set_option("wsl_user", "test-user")
cmd = connection._build_wsl_command('/bin/sh -c "ls -la"')
assert cmd == 'wsl.exe --distribution test --user test-user -- /bin/sh -c "ls -la"'
connection.set_option('become', True)
connection.set_option('become_user', 'test-become-user')
connection.set_option("become", True)
connection.set_option("become_user", "test-become-user")
cmd = connection._build_wsl_command('/bin/sh -c "ls -la"')
assert cmd == 'wsl.exe --distribution test --user test-become-user -- /bin/sh -c "ls -la"'
@patch('paramiko.SSHClient')
@patch("paramiko.SSHClient")
def test_exec_command_success(mock_ssh, connection):
""" Test successful command execution """
"""Test successful command execution"""
mock_client = MagicMock()
mock_ssh.return_value = mock_client
mock_channel = MagicMock()
@@ -230,21 +221,21 @@ def test_exec_command_success(mock_ssh, connection):
mock_client.get_transport.return_value = mock_transport
mock_transport.open_session.return_value = mock_channel
mock_channel.recv_exit_status.return_value = 0
mock_channel.makefile.return_value = [to_bytes('stdout')]
mock_channel.makefile.return_value = [to_bytes("stdout")]
mock_channel.makefile_stderr.return_value = [to_bytes("")]
connection._connected = True
connection.ssh = mock_client
returncode, stdout, stderr = connection.exec_command('ls -la')
returncode, stdout, stderr = connection.exec_command("ls -la")
mock_transport.open_session.assert_called_once()
mock_transport.set_keepalive.assert_called_once_with(5)
@patch('paramiko.SSHClient')
@patch("paramiko.SSHClient")
def test_exec_command_wsl_not_found(mock_ssh, connection):
""" Test command execution when wsl.exe is not found """
"""Test command execution when wsl.exe is not found"""
mock_client = MagicMock()
mock_ssh.return_value = mock_client
mock_channel = MagicMock()
@@ -259,28 +250,28 @@ def test_exec_command_wsl_not_found(mock_ssh, connection):
connection._connected = True
connection.ssh = mock_client
with pytest.raises(AnsibleError, match='wsl.exe not found in path of host'):
connection.exec_command('ls -la')
with pytest.raises(AnsibleError, match="wsl.exe not found in path of host"):
connection.exec_command("ls -la")
@patch('paramiko.SSHClient')
@patch("paramiko.SSHClient")
def test_exec_command_session_open_failure(mock_ssh, connection):
""" Test exec_command when session opening fails """
"""Test exec_command when session opening fails"""
mock_client = MagicMock()
mock_transport = MagicMock()
mock_transport.open_session.side_effect = Exception('Failed to open session')
mock_transport.open_session.side_effect = Exception("Failed to open session")
mock_client.get_transport.return_value = mock_transport
connection._connected = True
connection.ssh = mock_client
with pytest.raises(AnsibleConnectionFailure, match='Failed to open session'):
connection.exec_command('test command')
with pytest.raises(AnsibleConnectionFailure, match="Failed to open session"):
connection.exec_command("test command")
@patch('paramiko.SSHClient')
@patch("paramiko.SSHClient")
def test_exec_command_with_privilege_escalation(mock_ssh, connection):
""" Test exec_command with privilege escalation """
"""Test exec_command with privilege escalation"""
mock_client = MagicMock()
mock_channel = MagicMock()
mock_transport = MagicMock()
@@ -294,33 +285,35 @@ def test_exec_command_with_privilege_escalation(mock_ssh, connection):
connection.become.expect_prompt.return_value = True
connection.become.check_success.return_value = False
connection.become.check_password_prompt.return_value = True
connection.become.get_option.return_value = 'sudo_password'
connection.become.get_option.return_value = "sudo_password"
mock_channel.recv.return_value = b'[sudo] password:'
mock_channel.recv.return_value = b"[sudo] password:"
mock_channel.recv_exit_status.return_value = 0
mock_channel.makefile.return_value = [b""]
mock_channel.makefile_stderr.return_value = [b""]
returncode, stdout, stderr = connection.exec_command('sudo test command')
returncode, stdout, stderr = connection.exec_command("sudo test command")
mock_channel.sendall.assert_called_once_with(b'sudo_password\n')
mock_channel.sendall.assert_called_once_with(b"sudo_password\n")
def test_put_file(connection):
""" Test putting a file to the remote system """
"""Test putting a file to the remote system"""
connection.exec_command = MagicMock()
connection.exec_command.return_value = (0, b"", b"")
with patch('builtins.open', create=True) as mock_open:
mock_open.return_value.__enter__.return_value.read.return_value = b'test content'
connection.put_file('/local/path', '/remote/path')
with patch("builtins.open", create=True) as mock_open:
mock_open.return_value.__enter__.return_value.read.return_value = b"test content"
connection.put_file("/local/path", "/remote/path")
connection.exec_command.assert_called_once_with("/bin/sh -c 'cat > /remote/path'", in_data=b'test content', sudoable=False)
connection.exec_command.assert_called_once_with(
"/bin/sh -c 'cat > /remote/path'", in_data=b"test content", sudoable=False
)
@patch('paramiko.SSHClient')
@patch("paramiko.SSHClient")
def test_put_file_general_error(mock_ssh, connection):
""" Test put_file with general error """
"""Test put_file with general error"""
mock_client = MagicMock()
mock_ssh.return_value = mock_client
mock_channel = MagicMock()
@@ -330,18 +323,18 @@ def test_put_file_general_error(mock_ssh, connection):
mock_transport.open_session.return_value = mock_channel
mock_channel.recv_exit_status.return_value = 1
mock_channel.makefile.return_value = [to_bytes("")]
mock_channel.makefile_stderr.return_value = [to_bytes('Some error')]
mock_channel.makefile_stderr.return_value = [to_bytes("Some error")]
connection._connected = True
connection.ssh = mock_client
with pytest.raises(AnsibleError, match='error occurred while putting file from /remote/path to /local/path'):
connection.put_file('/remote/path', '/local/path')
with pytest.raises(AnsibleError, match="error occurred while putting file from /remote/path to /local/path"):
connection.put_file("/remote/path", "/local/path")
@patch('paramiko.SSHClient')
@patch("paramiko.SSHClient")
def test_put_file_cat_not_found(mock_ssh, connection):
""" Test command execution when cat is not found """
"""Test command execution when cat is not found"""
mock_client = MagicMock()
mock_ssh.return_value = mock_client
mock_channel = MagicMock()
@@ -351,30 +344,30 @@ def test_put_file_cat_not_found(mock_ssh, connection):
mock_transport.open_session.return_value = mock_channel
mock_channel.recv_exit_status.return_value = 1
mock_channel.makefile.return_value = [to_bytes("")]
mock_channel.makefile_stderr.return_value = [to_bytes('cat: not found')]
mock_channel.makefile_stderr.return_value = [to_bytes("cat: not found")]
connection._connected = True
connection.ssh = mock_client
with pytest.raises(AnsibleError, match='cat not found in path of WSL distribution'):
connection.fetch_file('/remote/path', '/local/path')
with pytest.raises(AnsibleError, match="cat not found in path of WSL distribution"):
connection.fetch_file("/remote/path", "/local/path")
def test_fetch_file(connection):
""" Test fetching a file from the remote system """
"""Test fetching a file from the remote system"""
connection.exec_command = MagicMock()
connection.exec_command.return_value = (0, b'test content', b"")
connection.exec_command.return_value = (0, b"test content", b"")
with patch('builtins.open', create=True) as mock_open:
connection.fetch_file('/remote/path', '/local/path')
with patch("builtins.open", create=True) as mock_open:
connection.fetch_file("/remote/path", "/local/path")
connection.exec_command.assert_called_once_with("/bin/sh -c 'cat /remote/path'", sudoable=False)
mock_open.assert_called_with('/local/path', 'wb')
mock_open.assert_called_with("/local/path", "wb")
@patch('paramiko.SSHClient')
@patch("paramiko.SSHClient")
def test_fetch_file_general_error(mock_ssh, connection):
""" Test fetch_file with general error """
"""Test fetch_file with general error"""
mock_client = MagicMock()
mock_ssh.return_value = mock_client
mock_channel = MagicMock()
@@ -384,18 +377,18 @@ def test_fetch_file_general_error(mock_ssh, connection):
mock_transport.open_session.return_value = mock_channel
mock_channel.recv_exit_status.return_value = 1
mock_channel.makefile.return_value = [to_bytes("")]
mock_channel.makefile_stderr.return_value = [to_bytes('Some error')]
mock_channel.makefile_stderr.return_value = [to_bytes("Some error")]
connection._connected = True
connection.ssh = mock_client
with pytest.raises(AnsibleError, match='error occurred while fetching file from /remote/path to /local/path'):
connection.fetch_file('/remote/path', '/local/path')
with pytest.raises(AnsibleError, match="error occurred while fetching file from /remote/path to /local/path"):
connection.fetch_file("/remote/path", "/local/path")
@patch('paramiko.SSHClient')
@patch("paramiko.SSHClient")
def test_fetch_file_cat_not_found(mock_ssh, connection):
""" Test command execution when cat is not found """
"""Test command execution when cat is not found"""
mock_client = MagicMock()
mock_ssh.return_value = mock_client
mock_channel = MagicMock()
@@ -405,89 +398,95 @@ def test_fetch_file_cat_not_found(mock_ssh, connection):
mock_transport.open_session.return_value = mock_channel
mock_channel.recv_exit_status.return_value = 1
mock_channel.makefile.return_value = [to_bytes("")]
mock_channel.makefile_stderr.return_value = [to_bytes('cat: not found')]
mock_channel.makefile_stderr.return_value = [to_bytes("cat: not found")]
connection._connected = True
connection.ssh = mock_client
with pytest.raises(AnsibleError, match='cat not found in path of WSL distribution'):
connection.fetch_file('/remote/path', '/local/path')
with pytest.raises(AnsibleError, match="cat not found in path of WSL distribution"):
connection.fetch_file("/remote/path", "/local/path")
def test_close(connection):
""" Test connection close """
"""Test connection close"""
mock_ssh = MagicMock()
connection.ssh = mock_ssh
connection._connected = True
connection.close()
assert mock_ssh.close.called, 'ssh.close was not called'
assert not connection._connected, 'self._connected is still True'
assert mock_ssh.close.called, "ssh.close was not called"
assert not connection._connected, "self._connected is still True"
def test_close_with_lock_file(connection):
""" Test close method with lock file creation """
"""Test close method with lock file creation"""
connection._any_keys_added = MagicMock(return_value=True)
connection._connected = True
connection.keyfile = '/tmp/wsl-known_hosts-test'
connection.set_option('host_key_checking', True)
connection.set_option('lock_file_timeout', 5)
connection.set_option('record_host_keys', True)
connection.keyfile = "/tmp/wsl-known_hosts-test"
connection.set_option("host_key_checking", True)
connection.set_option("lock_file_timeout", 5)
connection.set_option("record_host_keys", True)
connection.ssh = MagicMock()
lock_file_path = os.path.join(os.path.dirname(connection.keyfile),
f'ansible-{os.path.basename(connection.keyfile)}.lock')
lock_file_path = os.path.join(
os.path.dirname(connection.keyfile), f"ansible-{os.path.basename(connection.keyfile)}.lock"
)
try:
connection.close()
assert os.path.exists(lock_file_path), 'Lock file was not created'
assert os.path.exists(lock_file_path), "Lock file was not created"
lock_stat = os.stat(lock_file_path)
assert lock_stat.st_mode & 0o777 == 0o600, 'Incorrect lock file permissions'
assert lock_stat.st_mode & 0o777 == 0o600, "Incorrect lock file permissions"
finally:
Path(lock_file_path).unlink(missing_ok=True)
@patch('pathlib.Path.unlink')
@patch('os.path.exists')
@patch("pathlib.Path.unlink")
@patch("os.path.exists")
def test_close_lock_file_time_out_error_handling(mock_exists, mock_unlink, connection):
""" Test close method with lock file timeout error """
"""Test close method with lock file timeout error"""
connection._any_keys_added = MagicMock(return_value=True)
connection._connected = True
connection._save_ssh_host_keys = MagicMock()
connection.keyfile = '/tmp/wsl-known_hosts-test'
connection.set_option('host_key_checking', True)
connection.set_option('lock_file_timeout', 5)
connection.set_option('record_host_keys', True)
connection.keyfile = "/tmp/wsl-known_hosts-test"
connection.set_option("host_key_checking", True)
connection.set_option("lock_file_timeout", 5)
connection.set_option("record_host_keys", True)
connection.ssh = MagicMock()
mock_exists.return_value = False
matcher = f'writing lock file for {connection.keyfile} ran in to the timeout of {connection.get_option("lock_file_timeout")}s'
matcher = f"writing lock file for {connection.keyfile} ran in to the timeout of {connection.get_option('lock_file_timeout')}s"
with pytest.raises(AnsibleError, match=matcher):
with patch('os.getuid', return_value=1000), \
patch('os.getgid', return_value=1000), \
patch('os.chmod'), patch('os.chown'), \
patch('os.rename'), \
patch.object(FileLock, 'lock_file', side_effect=LockTimeout()):
with (
patch("os.getuid", return_value=1000),
patch("os.getgid", return_value=1000),
patch("os.chmod"),
patch("os.chown"),
patch("os.rename"),
patch.object(FileLock, "lock_file", side_effect=LockTimeout()),
):
connection.close()
@patch('ansible_collections.community.general.plugins.module_utils._filelock.FileLock.lock_file')
@patch('tempfile.NamedTemporaryFile')
@patch('os.chmod')
@patch('os.chown')
@patch('os.rename')
@patch('os.path.exists')
def test_tempfile_creation_and_move(mock_exists, mock_rename, mock_chown, mock_chmod, mock_tempfile, mock_lock_file, connection):
""" Test tempfile creation and move during close """
@patch("ansible_collections.community.general.plugins.module_utils._filelock.FileLock.lock_file")
@patch("tempfile.NamedTemporaryFile")
@patch("os.chmod")
@patch("os.chown")
@patch("os.rename")
@patch("os.path.exists")
def test_tempfile_creation_and_move(
mock_exists, mock_rename, mock_chown, mock_chmod, mock_tempfile, mock_lock_file, connection
):
"""Test tempfile creation and move during close"""
connection._any_keys_added = MagicMock(return_value=True)
connection._connected = True
connection._save_ssh_host_keys = MagicMock()
connection.keyfile = '/tmp/wsl-known_hosts-test'
connection.set_option('host_key_checking', True)
connection.set_option('lock_file_timeout', 5)
connection.set_option('record_host_keys', True)
connection.keyfile = "/tmp/wsl-known_hosts-test"
connection.set_option("host_key_checking", True)
connection.set_option("lock_file_timeout", 5)
connection.set_option("record_host_keys", True)
connection.ssh = MagicMock()
mock_exists.return_value = False
@@ -497,7 +496,7 @@ def test_tempfile_creation_and_move(mock_exists, mock_rename, mock_chown, mock_c
mock_lock_file_instance.__enter__.return_value = None
mock_tempfile_instance = MagicMock()
mock_tempfile_instance.name = '/tmp/mock_tempfile'
mock_tempfile_instance.name = "/tmp/mock_tempfile"
mock_tempfile.return_value.__enter__.return_value = mock_tempfile_instance
mode = 0o644
@@ -505,29 +504,29 @@ def test_tempfile_creation_and_move(mock_exists, mock_rename, mock_chown, mock_c
gid = 1000
key_dir = os.path.dirname(connection.keyfile)
with patch('os.getuid', return_value=uid), patch('os.getgid', return_value=gid):
with patch("os.getuid", return_value=uid), patch("os.getgid", return_value=gid):
connection.close()
connection._save_ssh_host_keys.assert_called_once_with('/tmp/mock_tempfile')
mock_chmod.assert_called_once_with('/tmp/mock_tempfile', mode)
mock_chown.assert_called_once_with('/tmp/mock_tempfile', uid, gid)
mock_rename.assert_called_once_with('/tmp/mock_tempfile', connection.keyfile)
connection._save_ssh_host_keys.assert_called_once_with("/tmp/mock_tempfile")
mock_chmod.assert_called_once_with("/tmp/mock_tempfile", mode)
mock_chown.assert_called_once_with("/tmp/mock_tempfile", uid, gid)
mock_rename.assert_called_once_with("/tmp/mock_tempfile", connection.keyfile)
mock_tempfile.assert_called_once_with(dir=key_dir, delete=False)
@patch('pathlib.Path.unlink')
@patch('tempfile.NamedTemporaryFile')
@patch('ansible_collections.community.general.plugins.module_utils._filelock.FileLock.lock_file')
@patch('os.path.exists')
@patch("pathlib.Path.unlink")
@patch("tempfile.NamedTemporaryFile")
@patch("ansible_collections.community.general.plugins.module_utils._filelock.FileLock.lock_file")
@patch("os.path.exists")
def test_close_tempfile_error_handling(mock_exists, mock_lock_file, mock_tempfile, mock_unlink, connection):
""" Test tempfile creation error """
"""Test tempfile creation error"""
connection._any_keys_added = MagicMock(return_value=True)
connection._connected = True
connection._save_ssh_host_keys = MagicMock()
connection.keyfile = '/tmp/wsl-known_hosts-test'
connection.set_option('host_key_checking', True)
connection.set_option('lock_file_timeout', 5)
connection.set_option('record_host_keys', True)
connection.keyfile = "/tmp/wsl-known_hosts-test"
connection.set_option("host_key_checking", True)
connection.set_option("lock_file_timeout", 5)
connection.set_option("record_host_keys", True)
connection.ssh = MagicMock()
mock_exists.return_value = False
@@ -537,29 +536,30 @@ def test_close_tempfile_error_handling(mock_exists, mock_lock_file, mock_tempfil
mock_lock_file_instance.__enter__.return_value = None
mock_tempfile_instance = MagicMock()
mock_tempfile_instance.name = '/tmp/mock_tempfile'
mock_tempfile_instance.name = "/tmp/mock_tempfile"
mock_tempfile.return_value.__enter__.return_value = mock_tempfile_instance
with pytest.raises(AnsibleError, match='error occurred while writing SSH host keys!'):
with patch.object(os, 'chmod', side_effect=Exception()):
with pytest.raises(AnsibleError, match="error occurred while writing SSH host keys!"):
with patch.object(os, "chmod", side_effect=Exception()):
connection.close()
mock_unlink.assert_called_with(missing_ok=True)
@patch('ansible_collections.community.general.plugins.module_utils._filelock.FileLock.lock_file')
@patch('os.path.exists')
@patch("ansible_collections.community.general.plugins.module_utils._filelock.FileLock.lock_file")
@patch("os.path.exists")
def test_close_with_invalid_host_key(mock_exists, mock_lock_file, connection):
""" Test load_system_host_keys on close with InvalidHostKey error """
"""Test load_system_host_keys on close with InvalidHostKey error"""
connection._any_keys_added = MagicMock(return_value=True)
connection._connected = True
connection._save_ssh_host_keys = MagicMock()
connection.keyfile = '/tmp/wsl-known_hosts-test'
connection.set_option('host_key_checking', True)
connection.set_option('lock_file_timeout', 5)
connection.set_option('record_host_keys', True)
connection.keyfile = "/tmp/wsl-known_hosts-test"
connection.set_option("host_key_checking", True)
connection.set_option("lock_file_timeout", 5)
connection.set_option("record_host_keys", True)
connection.ssh = MagicMock()
connection.ssh.load_system_host_keys.side_effect = paramiko.hostkeys.InvalidHostKey(
"Bad Line!", Exception('Something crashed!'))
"Bad Line!", Exception("Something crashed!")
)
mock_exists.return_value = False
@@ -572,7 +572,7 @@ def test_close_with_invalid_host_key(mock_exists, mock_lock_file, connection):
def test_reset(connection):
""" Test connection reset """
"""Test connection reset"""
connection._connected = True
connection.close = MagicMock()
connection._connect = MagicMock()

View File

@@ -10,6 +10,5 @@ from ansible_collections.community.general.plugins.filter.crc32 import crc32s
class TestFilterCrc32(unittest.TestCase):
def test_checksum(self):
self.assertEqual(crc32s('test'), 'd87f7e0c')
self.assertEqual(crc32s("test"), "d87f7e0c")

View File

@@ -48,21 +48,15 @@ class TestJsonPatch(unittest.TestCase):
self.assertEqual(result, {"a": 1, "d": 3})
def test_patch_replace(self):
result = self.json_patch(
{"a": 1, "b": {"c": 2}, "d": 3}, "replace", "/b", {"x": 99}
)
result = self.json_patch({"a": 1, "b": {"c": 2}, "d": 3}, "replace", "/b", {"x": 99})
self.assertEqual(result, {"a": 1, "b": {"x": 99}, "d": 3})
def test_patch_copy(self):
result = self.json_patch(
{"a": 1, "b": {"c": 2}, "d": 3}, "copy", "/d", **{"from": "/b"}
)
result = self.json_patch({"a": 1, "b": {"c": 2}, "d": 3}, "copy", "/d", **{"from": "/b"})
self.assertEqual(result, {"a": 1, "b": {"c": 2}, "d": {"c": 2}})
def test_patch_move(self):
result = self.json_patch(
{"a": 1, "b": {"c": 2}, "d": 3}, "move", "/d", **{"from": "/b"}
)
result = self.json_patch({"a": 1, "b": {"c": 2}, "d": 3}, "move", "/d", **{"from": "/b"})
self.assertEqual(result, {"a": 1, "d": {"c": 2}})
def test_patch_test_pass(self):
@@ -75,9 +69,7 @@ class TestJsonPatch(unittest.TestCase):
def test_patch_test_fail_fail(self):
with self.assertRaises(AnsibleFilterError) as context:
self.json_patch(
{"a": 1, "b": {"c": 2}, "d": 3}, "test", "/b/c", 99, fail_test=True
)
self.json_patch({"a": 1, "b": {"c": 2}, "d": 3}, "test", "/b/c", 99, fail_test=True)
self.assertTrue("json_patch: test operation failed" in str(context.exception))
def test_patch_remove_nonexisting(self):
@@ -188,9 +180,7 @@ class TestJsonPatch(unittest.TestCase):
{"op": "test", "path": "/baz/1", "value": 20},
],
)
self.assertEqual(
result, {"bar": [2], "bax": 1, "bay": 1, "baz": [10, 20, 30], "foo": 1}
)
self.assertEqual(result, {"bar": [2], "bax": 1, "bay": 1, "baz": [10, 20, 30], "foo": 1})
def test_patch_recipe_test_fail(self):
result = self.json_patch_recipe(
@@ -246,9 +236,7 @@ class TestJsonPatch(unittest.TestCase):
[{"op": "test", "path": "/b/c", "value": 99}],
True,
)
self.assertTrue(
"json_patch_recipe: test operation failed" in str(context.exception)
)
self.assertTrue("json_patch_recipe: test operation failed" in str(context.exception))
def test_patch_recipe_test_fail_fail_kw(self):
with self.assertRaises(AnsibleFilterError) as context:
@@ -257,9 +245,7 @@ class TestJsonPatch(unittest.TestCase):
[{"op": "test", "path": "/b/c", "value": 99}],
fail_test=True,
)
self.assertTrue(
"json_patch_recipe: test operation failed" in str(context.exception)
)
self.assertTrue("json_patch_recipe: test operation failed" in str(context.exception))
# json_diff
@@ -300,9 +286,7 @@ class TestJsonPatch(unittest.TestCase):
def test_diff_arg_checking(self):
with self.assertRaises(AnsibleFilterError) as context:
self.json_diff(1, {})
self.assertEqual(
str(context.exception), "json_diff: input is not dictionary, list or string"
)
self.assertEqual(str(context.exception), "json_diff: input is not dictionary, list or string")
with self.assertRaises(AnsibleFilterError) as context:
self.json_diff({}, 1)
self.assertEqual(

View File

@@ -21,4 +21,4 @@ def test_verify_file(tmp_path, inventory):
def test_verify_file_bad_config(inventory):
assert inventory.verify_file('foobar.cobbler.yml') is False
assert inventory.verify_file("foobar.cobbler.yml") is False

View File

@@ -20,7 +20,7 @@ def inventory():
def test_verify_file_bad_config(inventory):
assert inventory.verify_file('foobar.icinga2.yml') is False
assert inventory.verify_file("foobar.icinga2.yml") is False
def check_api():
@@ -33,58 +33,58 @@ def query_hosts(hosts=None, attrs=None, joins=None, host_filter=None):
# _get_hosts - list of dicts
json_host_data = [
{
'attrs': {
'address': 'test-host1.home.local',
'groups': ['home_servers', 'servers_dell'],
'display_name': 'Test Host 1',
'state': 0.0,
'state_type': 1.0
"attrs": {
"address": "test-host1.home.local",
"groups": ["home_servers", "servers_dell"],
"display_name": "Test Host 1",
"state": 0.0,
"state_type": 1.0,
},
'joins': {},
'meta': {},
'name': 'test-host1',
'type': 'Host'
"joins": {},
"meta": {},
"name": "test-host1",
"type": "Host",
},
{
'attrs': {
'address': 'test-host2.home.local',
'display_name': 'Test Host 2',
'groups': ['home_servers', 'servers_hp'],
'state': 1.0,
'state_type': 1.0
"attrs": {
"address": "test-host2.home.local",
"display_name": "Test Host 2",
"groups": ["home_servers", "servers_hp"],
"state": 1.0,
"state_type": 1.0,
},
'joins': {},
'meta': {},
'name': 'test-host2',
'type': 'Host'
"joins": {},
"meta": {},
"name": "test-host2",
"type": "Host",
},
{
'attrs': {
'address': '',
'display_name': 'Test Host 3',
'groups': ['not_home_servers', 'servers_hp'],
'state': 1.0,
'state_type': 1.0
"attrs": {
"address": "",
"display_name": "Test Host 3",
"groups": ["not_home_servers", "servers_hp"],
"state": 1.0,
"state_type": 1.0,
},
'joins': {},
'meta': {},
'name': 'test-host3.example.com',
'type': 'Host'
}
"joins": {},
"meta": {},
"name": "test-host3.example.com",
"type": "Host",
},
]
return json_host_data
def get_option(option):
if option == 'groups':
if option == "groups":
return {}
elif option == 'keyed_groups':
elif option == "keyed_groups":
return []
elif option == 'compose':
elif option == "compose":
return {}
elif option == 'strict':
elif option == "strict":
return False
elif option == 'group_by_hostgroups':
elif option == "group_by_hostgroups":
return True
else:
return None
@@ -92,8 +92,8 @@ def get_option(option):
def test_populate(inventory, mocker):
# module settings
inventory.icinga2_user = 'ansible'
inventory.icinga2_password = 'password'
inventory.icinga2_user = "ansible"
inventory.icinga2_password = "password"
inventory.icinga2_url = "https://localhost:5665/v1"
inventory.inventory_attr = "address"
inventory.group_by_hostgroups = True
@@ -105,46 +105,46 @@ def test_populate(inventory, mocker):
inventory._populate()
# get different hosts
host1_info = inventory.inventory.get_host('test-host1.home.local')
host1_info = inventory.inventory.get_host("test-host1.home.local")
print(host1_info)
host2_info = inventory.inventory.get_host('test-host2.home.local')
host2_info = inventory.inventory.get_host("test-host2.home.local")
print(host2_info)
host3_info = inventory.inventory.get_host('test-host3.example.com')
assert inventory.inventory.get_host('test-host3.example.com') is not None
host3_info = inventory.inventory.get_host("test-host3.example.com")
assert inventory.inventory.get_host("test-host3.example.com") is not None
print(host3_info)
# check if host in the home_servers group
assert 'home_servers' in inventory.inventory.groups
group1_data = inventory.inventory.groups['home_servers']
assert "home_servers" in inventory.inventory.groups
group1_data = inventory.inventory.groups["home_servers"]
group1_test_data = [host1_info, host2_info]
print(group1_data.hosts)
print(group1_test_data)
assert group1_data.hosts == group1_test_data
# Test servers_hp group
group2_data = inventory.inventory.groups['servers_hp']
group2_data = inventory.inventory.groups["servers_hp"]
group2_test_data = [host2_info, host3_info]
print(group2_data.hosts)
print(group2_test_data)
assert group2_data.hosts == group2_test_data
# check if host state rules apply properly
assert host1_info.get_vars()['state'] == 'on'
assert host1_info.get_vars()['display_name'] == "Test Host 1"
assert host2_info.get_vars()['state'] == 'off'
assert host3_info.get_vars().get('ansible_host') is None
assert host1_info.get_vars()["state"] == "on"
assert host1_info.get_vars()["display_name"] == "Test Host 1"
assert host2_info.get_vars()["state"] == "off"
assert host3_info.get_vars().get("ansible_host") is None
# Confirm attribute options switcher
inventory.inventory_attr = "name"
inventory._populate()
assert inventory.inventory.get_host('test-host3.example.com') is not None
host2_info = inventory.inventory.get_host('test-host2')
assert inventory.inventory.get_host("test-host3.example.com") is not None
host2_info = inventory.inventory.get_host("test-host2")
assert host2_info is not None
assert host2_info.get_vars().get('ansible_host') == 'test-host2.home.local'
assert host2_info.get_vars().get("ansible_host") == "test-host2.home.local"
# Confirm attribute options switcher
inventory.inventory_attr = "display_name"
inventory._populate()
assert inventory.inventory.get_host('Test Host 3') is not None
host2_info = inventory.inventory.get_host('Test Host 2')
assert inventory.inventory.get_host("Test Host 3") is not None
host2_info = inventory.inventory.get_host("Test Host 2")
assert host2_info is not None
assert host2_info.get_vars().get('ansible_host') == 'test-host2.home.local'
assert host2_info.get_vars().get("ansible_host") == "test-host2.home.local"

View File

@@ -1,4 +1,3 @@
# Copyright (c) 2024 Vladimir Botka <vbotka@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
@@ -19,51 +18,51 @@ def inventory():
inv = InventoryModule()
inv.inventory = InventoryData()
inv.templar = Templar(None)
inv.jails = load_txt_data('tests/unit/plugins/inventory/fixtures/iocage/iocage_jails.txt')
inv.js_ok = load_yml_data('tests/unit/plugins/inventory/fixtures/iocage/iocage_jails.yml')
inv.jails_dhcp = load_txt_data('tests/unit/plugins/inventory/fixtures/iocage/iocage_jails_dhcp.txt')
inv.js_dhcp_ok = load_yml_data('tests/unit/plugins/inventory/fixtures/iocage/iocage_jails_dhcp.yml')
inv.jails_dhcp_nr = load_txt_data('tests/unit/plugins/inventory/fixtures/iocage/iocage_jails_dhcp_not_running.txt')
inv.js_dhcp_nr_ok = load_yml_data('tests/unit/plugins/inventory/fixtures/iocage/iocage_jails_dhcp_not_running.yml')
prpts_101 = load_txt_data('tests/unit/plugins/inventory/fixtures/iocage/iocage_properties_test_101.txt')
prpts_102 = load_txt_data('tests/unit/plugins/inventory/fixtures/iocage/iocage_properties_test_102.txt')
prpts_103 = load_txt_data('tests/unit/plugins/inventory/fixtures/iocage/iocage_properties_test_103.txt')
inv.prpts = {'test_101': prpts_101, 'test_102': prpts_102, 'test_103': prpts_103}
inv.ps_ok = load_yml_data('tests/unit/plugins/inventory/fixtures/iocage/iocage_properties.yml')
inv.ok = load_yml_data('tests/unit/plugins/inventory/fixtures/iocage/iocage_inventory.yml')
inv.jails = load_txt_data("tests/unit/plugins/inventory/fixtures/iocage/iocage_jails.txt")
inv.js_ok = load_yml_data("tests/unit/plugins/inventory/fixtures/iocage/iocage_jails.yml")
inv.jails_dhcp = load_txt_data("tests/unit/plugins/inventory/fixtures/iocage/iocage_jails_dhcp.txt")
inv.js_dhcp_ok = load_yml_data("tests/unit/plugins/inventory/fixtures/iocage/iocage_jails_dhcp.yml")
inv.jails_dhcp_nr = load_txt_data("tests/unit/plugins/inventory/fixtures/iocage/iocage_jails_dhcp_not_running.txt")
inv.js_dhcp_nr_ok = load_yml_data("tests/unit/plugins/inventory/fixtures/iocage/iocage_jails_dhcp_not_running.yml")
prpts_101 = load_txt_data("tests/unit/plugins/inventory/fixtures/iocage/iocage_properties_test_101.txt")
prpts_102 = load_txt_data("tests/unit/plugins/inventory/fixtures/iocage/iocage_properties_test_102.txt")
prpts_103 = load_txt_data("tests/unit/plugins/inventory/fixtures/iocage/iocage_properties_test_103.txt")
inv.prpts = {"test_101": prpts_101, "test_102": prpts_102, "test_103": prpts_103}
inv.ps_ok = load_yml_data("tests/unit/plugins/inventory/fixtures/iocage/iocage_properties.yml")
inv.ok = load_yml_data("tests/unit/plugins/inventory/fixtures/iocage/iocage_inventory.yml")
return inv
def load_txt_data(path):
with open(path, 'r') as f:
with open(path, "r") as f:
s = f.read()
return s
def load_yml_data(path):
with open(path, 'r') as f:
with open(path, "r") as f:
d = yaml.safe_load(f)
return d
def get_option(option):
groups = {}
groups['test'] = make_trusted("inventory_hostname.startswith('test')")
groups["test"] = make_trusted("inventory_hostname.startswith('test')")
if option == 'groups':
if option == "groups":
return groups
elif option == 'keyed_groups':
elif option == "keyed_groups":
return []
elif option == 'compose':
elif option == "compose":
return {}
elif option == 'strict':
elif option == "strict":
return False
else:
return None
def test_verify_file_bad_config(inventory):
assert inventory.verify_file('foobar.iocage.yml') is False
assert inventory.verify_file("foobar.iocage.yml") is False
def test_verify_file(tmp_path, inventory):
@@ -73,53 +72,61 @@ def test_verify_file(tmp_path, inventory):
def test_get_jails(inventory):
# jails
results = {'_meta': {'hostvars': {}}}
results = {"_meta": {"hostvars": {}}}
inventory.get_jails(inventory.jails, results)
assert results == inventory.js_ok
# jails_dhcp
results = {'_meta': {'hostvars': {}}}
results = {"_meta": {"hostvars": {}}}
inventory.get_jails(inventory.jails_dhcp, results)
assert results == inventory.js_dhcp_ok
# jails_dhcp_not_running
results = {'_meta': {'hostvars': {}}}
results = {"_meta": {"hostvars": {}}}
inventory.get_jails(inventory.jails_dhcp_nr, results)
assert results == inventory.js_dhcp_nr_ok
def test_get_properties(inventory):
results = {'_meta': {'hostvars': {}}}
results = {"_meta": {"hostvars": {}}}
inventory.get_jails(inventory.jails, results)
for hostname, host_vars in results['_meta']['hostvars'].items():
for hostname, host_vars in results["_meta"]["hostvars"].items():
inventory.get_properties(inventory.prpts[hostname], results, hostname)
assert results == inventory.ps_ok
def test_populate(inventory, mocker):
results = {'_meta': {'hostvars': {}}}
results = {"_meta": {"hostvars": {}}}
inventory.get_jails(inventory.jails, results)
for hostname, host_vars in results['_meta']['hostvars'].items():
for hostname, host_vars in results["_meta"]["hostvars"].items():
inventory.get_properties(inventory.prpts[hostname], results, hostname)
inventory.get_option = mocker.MagicMock(side_effect=get_option)
inventory.populate(results)
# test
hosts = ('test_101', 'test_102', 'test_103')
vars = ('iocage_basejail', 'iocage_boot', 'iocage_ip4', 'iocage_ip6', 'iocage_properties',
'iocage_release', 'iocage_state', 'iocage_template', 'iocage_type')
hosts = ("test_101", "test_102", "test_103")
vars = (
"iocage_basejail",
"iocage_boot",
"iocage_ip4",
"iocage_ip6",
"iocage_properties",
"iocage_release",
"iocage_state",
"iocage_template",
"iocage_type",
)
# test host_vars
for host in hosts:
h = inventory.inventory.get_host(host)
for var in vars:
assert inventory.ok['all']['children']['test']['hosts'][host][var] == h.get_vars()[var]
assert inventory.ok["all"]["children"]["test"]["hosts"][host][var] == h.get_vars()[var]
# test groups
test_101_info = inventory.inventory.get_host('test_101')
test_102_info = inventory.inventory.get_host('test_102')
test_103_info = inventory.inventory.get_host('test_103')
g = inventory.inventory.groups['test']
test_101_info = inventory.inventory.get_host("test_101")
test_102_info = inventory.inventory.get_host("test_102")
test_103_info = inventory.inventory.get_host("test_103")
g = inventory.inventory.groups["test"]
assert g.hosts == [test_101_info, test_102_info, test_103_info]

View File

@@ -6,7 +6,7 @@ from __future__ import annotations
import pytest
linode_apiv4 = pytest.importorskip('linode_api4')
linode_apiv4 = pytest.importorskip("linode_api4")
from ansible.errors import AnsibleError
from ansible.parsing.dataloader import DataLoader
@@ -23,10 +23,10 @@ def inventory():
def test_missing_access_token_lookup(inventory):
loader = DataLoader()
inventory._options = {'access_token': None}
inventory._options = {"access_token": None}
with pytest.raises(AnsibleError) as error_message:
inventory._build_client(loader)
assert 'Could not retrieve Linode access token' in error_message
assert "Could not retrieve Linode access token" in error_message
def test_verify_file_yml(tmp_path, inventory):

View File

@@ -12,24 +12,43 @@ from ansible_collections.community.general.plugins.inventory.lxd import Inventor
HOST_COMPARATIVE_DATA = {
'ansible_connection': 'ssh', 'ansible_host': '10.98.143.199', 'ansible_lxd_os': 'ubuntu', 'ansible_lxd_release': 'focal',
'ansible_lxd_profile': ['default'], 'ansible_lxd_state': 'running', 'ansible_lxd_location': 'Berlin',
'ansible_lxd_vlan_ids': {'my-macvlan': 666}, 'inventory_hostname': 'vlantest', 'inventory_hostname_short': 'vlantest'}
"ansible_connection": "ssh",
"ansible_host": "10.98.143.199",
"ansible_lxd_os": "ubuntu",
"ansible_lxd_release": "focal",
"ansible_lxd_profile": ["default"],
"ansible_lxd_state": "running",
"ansible_lxd_location": "Berlin",
"ansible_lxd_vlan_ids": {"my-macvlan": 666},
"inventory_hostname": "vlantest",
"inventory_hostname_short": "vlantest",
}
GROUP_COMPARATIVE_DATA = {
'all': [], 'ungrouped': [], 'testpattern': ['vlantest'], 'vlan666': ['vlantest'], 'locationBerlin': ['vlantest'],
'osUbuntu': ['vlantest'], 'releaseFocal': ['vlantest'], 'releaseBionic': [], 'profileDefault': ['vlantest'],
'profileX11': [], 'netRangeIPv4': ['vlantest'], 'netRangeIPv6': ['vlantest']}
"all": [],
"ungrouped": [],
"testpattern": ["vlantest"],
"vlan666": ["vlantest"],
"locationBerlin": ["vlantest"],
"osUbuntu": ["vlantest"],
"releaseFocal": ["vlantest"],
"releaseBionic": [],
"profileDefault": ["vlantest"],
"profileX11": [],
"netRangeIPv4": ["vlantest"],
"netRangeIPv6": ["vlantest"],
}
GROUP_Config = {
'testpattern': {'type': 'pattern', 'attribute': 'test'},
'vlan666': {'type': 'vlanid', 'attribute': 666},
'locationBerlin': {'type': 'location', 'attribute': 'Berlin'},
'osUbuntu': {'type': 'os', 'attribute': 'ubuntu'},
'releaseFocal': {'type': 'release', 'attribute': 'focal'},
'releaseBionic': {'type': 'release', 'attribute': 'bionic'},
'profileDefault': {'type': 'profile', 'attribute': 'default'},
'profileX11': {'type': 'profile', 'attribute': 'x11'},
'netRangeIPv4': {'type': 'network_range', 'attribute': '10.98.143.0/24'},
'netRangeIPv6': {'type': 'network_range', 'attribute': 'fd42:bd00:7b11:2167:216:3eff::/96'}}
"testpattern": {"type": "pattern", "attribute": "test"},
"vlan666": {"type": "vlanid", "attribute": 666},
"locationBerlin": {"type": "location", "attribute": "Berlin"},
"osUbuntu": {"type": "os", "attribute": "ubuntu"},
"releaseFocal": {"type": "release", "attribute": "focal"},
"releaseBionic": {"type": "release", "attribute": "bionic"},
"profileDefault": {"type": "profile", "attribute": "default"},
"profileX11": {"type": "profile", "attribute": "x11"},
"netRangeIPv4": {"type": "network_range", "attribute": "10.98.143.0/24"},
"netRangeIPv6": {"type": "network_range", "attribute": "fd42:bd00:7b11:2167:216:3eff::/96"},
}
@pytest.fixture
@@ -38,13 +57,13 @@ def inventory():
inv.inventory = InventoryData()
# Test Values
inv.data = inv.load_json_data('tests/unit/plugins/inventory/fixtures/lxd_inventory.atd') # Load Test Data
inv.data = inv.load_json_data("tests/unit/plugins/inventory/fixtures/lxd_inventory.atd") # Load Test Data
inv.groupby = GROUP_Config
inv.prefered_instance_network_interface = 'eth'
inv.prefered_instance_network_family = 'inet'
inv.filter = 'running'
inv.prefered_instance_network_interface = "eth"
inv.prefered_instance_network_family = "inet"
inv.filter = "running"
inv.dump_data = False
inv.type_filter = 'both'
inv.type_filter = "both"
return inv
@@ -56,7 +75,7 @@ def test_verify_file(tmp_path, inventory):
def test_verify_file_bad_config(inventory):
assert inventory.verify_file('foobar.lxd.yml') is False
assert inventory.verify_file("foobar.lxd.yml") is False
def test_build_inventory_hosts(inventory):
@@ -64,7 +83,7 @@ def test_build_inventory_hosts(inventory):
After the inventory plugin has run with the test data, the result of the host is checked."""
inventory._populate()
generated_data = inventory.inventory.get_host('vlantest').get_vars()
generated_data = inventory.inventory.get_host("vlantest").get_vars()
eq = True
for key, value in HOST_COMPARATIVE_DATA.items():
@@ -94,7 +113,7 @@ def test_build_inventory_groups_with_no_groupselection(inventory):
inventory.groupby = None
inventory._populate()
generated_data = inventory.inventory.get_groups_dict()
group_comparative_data = {'all': [], 'ungrouped': []}
group_comparative_data = {"all": [], "ungrouped": []}
eq = True
print(f"data: {generated_data}")

View File

@@ -47,14 +47,14 @@ def access_mock(path, can_access=True):
class HistoryEntry:
def __init__(self):
self.SEQ = '384'
self.HOSTNAME = 'sam-691-sam'
self.HID = '10'
self.CID = '0'
self.DS_ID = '100'
self.VM_MAD = 'kvm'
self.TM_MAD = '3par'
self.ACTION = '0'
self.SEQ = "384"
self.HOSTNAME = "sam-691-sam"
self.HID = "10"
self.CID = "0"
self.DS_ID = "100"
self.VM_MAD = "kvm"
self.TM_MAD = "3par"
self.ACTION = "0"
class HistoryRecords:
@@ -76,191 +76,223 @@ def test_verify_file(tmp_path, inventory):
def test_verify_file_bad_config(inventory):
assert inventory.verify_file('foobar.opennebula.yml') is False
assert inventory.verify_file("foobar.opennebula.yml") is False
def get_vm_pool_json():
with open('tests/unit/plugins/inventory/fixtures/opennebula_inventory.json', 'r') as json_file:
with open("tests/unit/plugins/inventory/fixtures/opennebula_inventory.json", "r") as json_file:
jsondata = json.load(json_file)
data = type('pyone.bindings.VM_POOLSub', (object,), {'VM': []})()
data = type("pyone.bindings.VM_POOLSub", (object,), {"VM": []})()
for fake_server in jsondata:
data.VM.append(type('pyone.bindings.VMType90Sub', (object,), fake_server)())
data.VM.append(type("pyone.bindings.VMType90Sub", (object,), fake_server)())
return data
def get_vm_pool():
data = type('pyone.bindings.VM_POOLSub', (object,), {'VM': []})()
data = type("pyone.bindings.VM_POOLSub", (object,), {"VM": []})()
vm = type('pyone.bindings.VMType90Sub', (object,), {
'DEPLOY_ID': 'one-7157',
'ETIME': 0,
'GID': 132,
'GNAME': 'CSApparelVDC',
'HISTORY_RECORDS': HistoryRecords(),
'ID': 7157,
'LAST_POLL': 1632762935,
'LCM_STATE': 3,
'MONITORING': {},
'NAME': 'sam-691-sam',
'RESCHED': 0,
'SNAPSHOTS': [],
'STATE': 3,
'STIME': 1632755245,
'TEMPLATE': OrderedDict({
'NIC': OrderedDict({
'AR_ID': '0',
'BRIDGE': 'onebr80',
'BRIDGE_TYPE': 'linux',
'CLUSTER_ID': '0',
'IP': '172.22.4.187',
'MAC': '02:00:ac:16:04:bb',
'MTU': '8192',
'NAME': 'NIC0',
'NETWORK': 'Private Net CSApparel',
'NETWORK_ID': '80',
'NETWORK_UNAME': 'CSApparelVDC-admin',
'NIC_ID': '0',
'PHYDEV': 'team0',
'SECURITY_GROUPS': '0',
'TARGET': 'one-7157-0',
'VLAN_ID': '480',
'VN_MAD': '802.1Q'
})
}),
'USER_TEMPLATE': OrderedDict({
'HYPERVISOR': 'kvm',
'INPUTS_ORDER': '',
'LOGO': 'images/logos/centos.png',
'MEMORY_UNIT_COST': 'MB',
'SCHED_REQUIREMENTS': 'CLUSTER_ID="0"'
})
})()
vm = type(
"pyone.bindings.VMType90Sub",
(object,),
{
"DEPLOY_ID": "one-7157",
"ETIME": 0,
"GID": 132,
"GNAME": "CSApparelVDC",
"HISTORY_RECORDS": HistoryRecords(),
"ID": 7157,
"LAST_POLL": 1632762935,
"LCM_STATE": 3,
"MONITORING": {},
"NAME": "sam-691-sam",
"RESCHED": 0,
"SNAPSHOTS": [],
"STATE": 3,
"STIME": 1632755245,
"TEMPLATE": OrderedDict(
{
"NIC": OrderedDict(
{
"AR_ID": "0",
"BRIDGE": "onebr80",
"BRIDGE_TYPE": "linux",
"CLUSTER_ID": "0",
"IP": "172.22.4.187",
"MAC": "02:00:ac:16:04:bb",
"MTU": "8192",
"NAME": "NIC0",
"NETWORK": "Private Net CSApparel",
"NETWORK_ID": "80",
"NETWORK_UNAME": "CSApparelVDC-admin",
"NIC_ID": "0",
"PHYDEV": "team0",
"SECURITY_GROUPS": "0",
"TARGET": "one-7157-0",
"VLAN_ID": "480",
"VN_MAD": "802.1Q",
}
)
}
),
"USER_TEMPLATE": OrderedDict(
{
"HYPERVISOR": "kvm",
"INPUTS_ORDER": "",
"LOGO": "images/logos/centos.png",
"MEMORY_UNIT_COST": "MB",
"SCHED_REQUIREMENTS": 'CLUSTER_ID="0"',
}
),
},
)()
data.VM.append(vm)
vm = type('pyone.bindings.VMType90Sub', (object,), {
'DEPLOY_ID': 'one-327',
'ETIME': 0,
'GID': 0,
'GNAME': 'oneadmin',
'HISTORY_RECORDS': [],
'ID': 327,
'LAST_POLL': 1632763543,
'LCM_STATE': 3,
'MONITORING': {},
'NAME': 'zabbix-327',
'RESCHED': 0,
'SNAPSHOTS': [],
'STATE': 3,
'STIME': 1575410106,
'TEMPLATE': OrderedDict({
'NIC': [
OrderedDict({
'AR_ID': '0',
'BRIDGE': 'onerb.103',
'BRIDGE_TYPE': 'linux',
'IP': '185.165.1.1',
'IP6_GLOBAL': '2000:a001::b9ff:feae:aa0d',
'IP6_LINK': 'fe80::b9ff:feae:aa0d',
'MAC': '02:00:b9:ae:aa:0d',
'NAME': 'NIC0',
'NETWORK': 'Public',
'NETWORK_ID': '7',
'NIC_ID': '0',
'PHYDEV': 'team0',
'SECURITY_GROUPS': '0',
'TARGET': 'one-327-0',
'VLAN_ID': '100',
'VN_MAD': '802.1Q'
}),
OrderedDict({
'AR_ID': '0',
'BRIDGE': 'br0',
'BRIDGE_TYPE': 'linux',
'CLUSTER_ID': '0',
'IP': '192.168.1.1',
'MAC': '02:00:c0:a8:3b:01',
'NAME': 'NIC1',
'NETWORK': 'Management',
'NETWORK_ID': '11',
'NIC_ID': '1',
'SECURITY_GROUPS': '0',
'TARGET': 'one-327-1',
'VN_MAD': 'bridge'
})
]
}),
'USER_TEMPLATE': OrderedDict({
'HYPERVISOR': 'kvm',
'INPUTS_ORDER': '',
'LABELS': 'Oracle Linux',
'LOGO': 'images/logos/centos.png',
'MEMORY_UNIT_COST': 'MB',
'SAVED_TEMPLATE_ID': '29'
})
})()
vm = type(
"pyone.bindings.VMType90Sub",
(object,),
{
"DEPLOY_ID": "one-327",
"ETIME": 0,
"GID": 0,
"GNAME": "oneadmin",
"HISTORY_RECORDS": [],
"ID": 327,
"LAST_POLL": 1632763543,
"LCM_STATE": 3,
"MONITORING": {},
"NAME": "zabbix-327",
"RESCHED": 0,
"SNAPSHOTS": [],
"STATE": 3,
"STIME": 1575410106,
"TEMPLATE": OrderedDict(
{
"NIC": [
OrderedDict(
{
"AR_ID": "0",
"BRIDGE": "onerb.103",
"BRIDGE_TYPE": "linux",
"IP": "185.165.1.1",
"IP6_GLOBAL": "2000:a001::b9ff:feae:aa0d",
"IP6_LINK": "fe80::b9ff:feae:aa0d",
"MAC": "02:00:b9:ae:aa:0d",
"NAME": "NIC0",
"NETWORK": "Public",
"NETWORK_ID": "7",
"NIC_ID": "0",
"PHYDEV": "team0",
"SECURITY_GROUPS": "0",
"TARGET": "one-327-0",
"VLAN_ID": "100",
"VN_MAD": "802.1Q",
}
),
OrderedDict(
{
"AR_ID": "0",
"BRIDGE": "br0",
"BRIDGE_TYPE": "linux",
"CLUSTER_ID": "0",
"IP": "192.168.1.1",
"MAC": "02:00:c0:a8:3b:01",
"NAME": "NIC1",
"NETWORK": "Management",
"NETWORK_ID": "11",
"NIC_ID": "1",
"SECURITY_GROUPS": "0",
"TARGET": "one-327-1",
"VN_MAD": "bridge",
}
),
]
}
),
"USER_TEMPLATE": OrderedDict(
{
"HYPERVISOR": "kvm",
"INPUTS_ORDER": "",
"LABELS": "Oracle Linux",
"LOGO": "images/logos/centos.png",
"MEMORY_UNIT_COST": "MB",
"SAVED_TEMPLATE_ID": "29",
}
),
},
)()
data.VM.append(vm)
vm = type('pyone.bindings.VMType90Sub', (object,), {
'DEPLOY_ID': 'one-107',
'ETIME': 0,
'GID': 0,
'GNAME': 'oneadmin',
'HISTORY_RECORDS': [],
'ID': 107,
'LAST_POLL': 1632764186,
'LCM_STATE': 3,
'MONITORING': {},
'NAME': 'gitlab-107',
'RESCHED': 0,
'SNAPSHOTS': [],
'STATE': 3,
'STIME': 1572485522,
'TEMPLATE': OrderedDict({
'NIC': OrderedDict({
'AR_ID': '0',
'BRIDGE': 'onerb.103',
'BRIDGE_TYPE': 'linux',
'IP': '185.165.1.3',
'IP6_GLOBAL': '2000:a001::b9ff:feae:aa03',
'IP6_LINK': 'fe80::b9ff:feae:aa03',
'MAC': '02:00:b9:ae:aa:03',
'NAME': 'NIC0',
'NETWORK': 'Public',
'NETWORK_ID': '7',
'NIC_ID': '0',
'PHYDEV': 'team0',
'SECURITY_GROUPS': '0',
'TARGET': 'one-107-0',
'VLAN_ID': '100',
'VN_MAD': '802.1Q'
})
}),
'USER_TEMPLATE': OrderedDict({
'HYPERVISOR': 'kvm',
'INPUTS_ORDER': '',
'LABELS': 'Gitlab,Centos',
'LOGO': 'images/logos/centos.png',
'MEMORY_UNIT_COST': 'MB',
'SCHED_REQUIREMENTS': 'ID="0" | ID="1" | ID="2"',
'SSH_PORT': '8822'
})
})()
vm = type(
"pyone.bindings.VMType90Sub",
(object,),
{
"DEPLOY_ID": "one-107",
"ETIME": 0,
"GID": 0,
"GNAME": "oneadmin",
"HISTORY_RECORDS": [],
"ID": 107,
"LAST_POLL": 1632764186,
"LCM_STATE": 3,
"MONITORING": {},
"NAME": "gitlab-107",
"RESCHED": 0,
"SNAPSHOTS": [],
"STATE": 3,
"STIME": 1572485522,
"TEMPLATE": OrderedDict(
{
"NIC": OrderedDict(
{
"AR_ID": "0",
"BRIDGE": "onerb.103",
"BRIDGE_TYPE": "linux",
"IP": "185.165.1.3",
"IP6_GLOBAL": "2000:a001::b9ff:feae:aa03",
"IP6_LINK": "fe80::b9ff:feae:aa03",
"MAC": "02:00:b9:ae:aa:03",
"NAME": "NIC0",
"NETWORK": "Public",
"NETWORK_ID": "7",
"NIC_ID": "0",
"PHYDEV": "team0",
"SECURITY_GROUPS": "0",
"TARGET": "one-107-0",
"VLAN_ID": "100",
"VN_MAD": "802.1Q",
}
)
}
),
"USER_TEMPLATE": OrderedDict(
{
"HYPERVISOR": "kvm",
"INPUTS_ORDER": "",
"LABELS": "Gitlab,Centos",
"LOGO": "images/logos/centos.png",
"MEMORY_UNIT_COST": "MB",
"SCHED_REQUIREMENTS": 'ID="0" | ID="1" | ID="2"',
"SSH_PORT": "8822",
}
),
},
)()
data.VM.append(vm)
return data
options_base_test = {
'api_url': 'https://opennebula:2633/RPC2',
'api_username': 'username',
'api_password': 'password',
'api_authfile': '~/.one/one_auth',
'hostname': 'v4_first_ip',
'group_by_labels': True,
'filter_by_label': None,
"api_url": "https://opennebula:2633/RPC2",
"api_username": "username",
"api_password": "password",
"api_authfile": "~/.one/one_auth",
"hostname": "v4_first_ip",
"group_by_labels": True,
"filter_by_label": None,
}
@@ -268,6 +300,7 @@ options_base_test = {
def mk_get_options(opts_dict):
def inner(opt):
return opts_dict.get(opt, False)
return inner
@@ -275,22 +308,23 @@ def test_get_connection_info(inventory, mocker):
inventory.get_option = mocker.MagicMock(side_effect=mk_get_options(options_base_test))
auth = inventory._get_connection_info()
assert (auth.username and auth.password)
assert auth.username and auth.password
def test_populate_constructable_templating(mocker):
inventory_filename = '/fake/opennebula.yml'
inventory_filename = "/fake/opennebula.yml"
mocker.patch.object(InventoryModule, '_get_vm_pool', side_effect=get_vm_pool_json)
mocker.patch('ansible_collections.community.general.plugins.inventory.opennebula.HAS_PYONE', True)
mocker.patch('ansible.inventory.manager.unfrackpath', mock_unfrackpath_noop)
mocker.patch('os.path.exists', exists_mock(inventory_filename))
mocker.patch('os.access', access_mock(inventory_filename))
mocker.patch.object(InventoryModule, "_get_vm_pool", side_effect=get_vm_pool_json)
mocker.patch("ansible_collections.community.general.plugins.inventory.opennebula.HAS_PYONE", True)
mocker.patch("ansible.inventory.manager.unfrackpath", mock_unfrackpath_noop)
mocker.patch("os.path.exists", exists_mock(inventory_filename))
mocker.patch("os.access", access_mock(inventory_filename))
# the templating engine is needed for the constructable groups/vars
# so give that some fake data and instantiate it.
C.INVENTORY_ENABLED = ['community.general.opennebula']
inventory_file = {inventory_filename: r'''
C.INVENTORY_ENABLED = ["community.general.opennebula"]
inventory_file = {
inventory_filename: r"""
---
plugin: community.general.opennebula
api_url: https://opennebula:2633/RPC2
@@ -308,43 +342,46 @@ groups:
keyed_groups:
- key: TGROUP
prefix: tgroup
'''}
"""
}
im = InventoryManager(loader=DictDataLoader(inventory_file), sources=inventory_filename)
# note the vm_pool (and json data file) has four hosts,
# but the options above asks ansible to filter one out
assert len(get_vm_pool_json().VM) == 4
assert set(vm.NAME for vm in get_vm_pool_json().VM) == set([
'terraform_demo_00',
'terraform_demo_01',
'terraform_demo_srv_00',
'bs-windows',
])
assert set(im._inventory.hosts) == set(['terraform_demo_00', 'terraform_demo_01', 'terraform_demo_srv_00'])
assert set(vm.NAME for vm in get_vm_pool_json().VM) == set(
[
"terraform_demo_00",
"terraform_demo_01",
"terraform_demo_srv_00",
"bs-windows",
]
)
assert set(im._inventory.hosts) == set(["terraform_demo_00", "terraform_demo_01", "terraform_demo_srv_00"])
host_demo00 = im._inventory.get_host('terraform_demo_00')
host_demo01 = im._inventory.get_host('terraform_demo_01')
host_demosrv = im._inventory.get_host('terraform_demo_srv_00')
host_demo00 = im._inventory.get_host("terraform_demo_00")
host_demo01 = im._inventory.get_host("terraform_demo_01")
host_demosrv = im._inventory.get_host("terraform_demo_srv_00")
assert 'benchmark_clients' in im._inventory.groups
assert 'lin' in im._inventory.groups
assert im._inventory.groups['benchmark_clients'].hosts == [host_demo00, host_demo01]
assert im._inventory.groups['lin'].hosts == [host_demo00, host_demo01, host_demosrv]
assert "benchmark_clients" in im._inventory.groups
assert "lin" in im._inventory.groups
assert im._inventory.groups["benchmark_clients"].hosts == [host_demo00, host_demo01]
assert im._inventory.groups["lin"].hosts == [host_demo00, host_demo01, host_demosrv]
# test group by label:
assert 'bench' in im._inventory.groups
assert 'foo' in im._inventory.groups
assert im._inventory.groups['bench'].hosts == [host_demo00, host_demo01, host_demosrv]
assert im._inventory.groups['serv'].hosts == [host_demosrv]
assert im._inventory.groups['foo'].hosts == [host_demo00, host_demo01]
assert "bench" in im._inventory.groups
assert "foo" in im._inventory.groups
assert im._inventory.groups["bench"].hosts == [host_demo00, host_demo01, host_demosrv]
assert im._inventory.groups["serv"].hosts == [host_demosrv]
assert im._inventory.groups["foo"].hosts == [host_demo00, host_demo01]
# test `compose` transforms GUEST_OS=Linux to is_linux == True
assert host_demo00.get_vars()['GUEST_OS'] == 'linux'
assert host_demo00.get_vars()['is_linux'] is True
assert host_demo00.get_vars()["GUEST_OS"] == "linux"
assert host_demo00.get_vars()["is_linux"] is True
# test `keyed_groups`
assert im._inventory.groups['tgroup_bench_clients'].hosts == [host_demo00, host_demo01]
assert im._inventory.groups['tgroup_bench_server'].hosts == [host_demosrv]
assert im._inventory.groups["tgroup_bench_clients"].hosts == [host_demo00, host_demo01]
assert im._inventory.groups["tgroup_bench_server"].hosts == [host_demosrv]
def test_populate(inventory, mocker):
@@ -354,35 +391,35 @@ def test_populate(inventory, mocker):
inventory._populate()
# get different hosts
host_sam = inventory.inventory.get_host('sam-691-sam')
host_zabbix = inventory.inventory.get_host('zabbix-327')
host_gitlab = inventory.inventory.get_host('gitlab-107')
host_sam = inventory.inventory.get_host("sam-691-sam")
host_zabbix = inventory.inventory.get_host("zabbix-327")
host_gitlab = inventory.inventory.get_host("gitlab-107")
# test if groups exists
assert 'Gitlab' in inventory.inventory.groups
assert 'Centos' in inventory.inventory.groups
assert 'Oracle_Linux' in inventory.inventory.groups
assert "Gitlab" in inventory.inventory.groups
assert "Centos" in inventory.inventory.groups
assert "Oracle_Linux" in inventory.inventory.groups
# check if host_zabbix is in Oracle_Linux group
group_oracle_linux = inventory.inventory.groups['Oracle_Linux']
group_oracle_linux = inventory.inventory.groups["Oracle_Linux"]
assert group_oracle_linux.hosts == [host_zabbix]
# check if host_gitlab is in Gitlab and Centos group
group_gitlab = inventory.inventory.groups['Gitlab']
group_centos = inventory.inventory.groups['Centos']
group_gitlab = inventory.inventory.groups["Gitlab"]
group_centos = inventory.inventory.groups["Centos"]
assert group_gitlab.hosts == [host_gitlab]
assert group_centos.hosts == [host_gitlab]
# check IPv4 address
assert '172.22.4.187' == host_sam.get_vars()['v4_first_ip']
assert "172.22.4.187" == host_sam.get_vars()["v4_first_ip"]
# check IPv6 address
assert '2000:a001::b9ff:feae:aa0d' == host_zabbix.get_vars()['v6_first_ip']
assert "2000:a001::b9ff:feae:aa0d" == host_zabbix.get_vars()["v6_first_ip"]
# check ansible_hosts
assert '172.22.4.187' == host_sam.get_vars()['ansible_host']
assert '185.165.1.1' == host_zabbix.get_vars()['ansible_host']
assert '185.165.1.3' == host_gitlab.get_vars()['ansible_host']
assert "172.22.4.187" == host_sam.get_vars()["ansible_host"]
assert "185.165.1.1" == host_zabbix.get_vars()["ansible_host"]
assert "185.165.1.3" == host_gitlab.get_vars()["ansible_host"]
# check for custom ssh port
assert '8822' == host_gitlab.get_vars()['ansible_port']
assert "8822" == host_gitlab.get_vars()["ansible_port"]

View File

@@ -12,129 +12,127 @@ from ansible.inventory.data import InventoryData
from ansible_collections.community.general.plugins.inventory.xen_orchestra import InventoryModule
objects = {
'vms': {
'0e64588-2bea-2d82-e922-881654b0a48f':
{
'type': 'VM',
'addresses': {},
'CPUs': {'max': 4, 'number': 4},
'memory': {'dynamic': [1073741824, 2147483648], 'static': [536870912, 4294967296], 'size': 2147483648},
'name_description': '',
'name_label': 'XCP-NG lab 2',
'os_version': {},
'parent': 'd3af89b2-d846-0874-6acb-031ccf11c560',
'power_state': 'Running',
'tags': [],
'id': '0e645898-2bea-2d82-e922-881654b0a48f',
'uuid': '0e645898-2bea-2d82-e922-881654b0a48f',
'$pool': '3d315997-73bd-5a74-8ca7-289206cb03ab',
'$poolId': '3d315997-73bd-5a74-8ca7-289206cb03ab',
'$container': '222d8594-9426-468a-ad69-7a6f02330fa3'
},
'b0d25e70-019d-6182-2f7c-b0f5d8ef9331':
{
'type': 'VM',
'addresses': {'0/ipv4/0': '192.168.1.55', '1/ipv4/0': '10.0.90.1'},
'CPUs': {'max': 4, 'number': 4},
'mainIpAddress': '192.168.1.55',
'memory': {'dynamic': [2147483648, 2147483648], 'static': [134217728, 2147483648], 'size': 2147483648},
'name_description': '',
'name_label': 'XCP-NG lab 3',
'os_version': {'name': 'FreeBSD 11.3-STABLE', 'uname': '11.3-STABLE', 'distro': 'FreeBSD'},
'power_state': 'Halted',
'tags': [],
'id': 'b0d25e70-019d-6182-2f7c-b0f5d8ef9331',
'uuid': 'b0d25e70-019d-6182-2f7c-b0f5d8ef9331',
'$pool': '3d315997-73bd-5a74-8ca7-289206cb03ab',
'$poolId': '3d315997-73bd-5a74-8ca7-289206cb03ab',
'$container': 'c96ec4dd-28ac-4df4-b73c-4371bd202728',
}
},
'pools': {
'3d315997-73bd-5a74-8ca7-289206cb03ab': {
'master': '222d8594-9426-468a-ad69-7a6f02330fa3',
'tags': [],
'name_description': '',
'name_label': 'Storage Lab',
'cpus': {'cores': 120, 'sockets': 6},
'id': '3d315997-73bd-5a74-8ca7-289206cb03ab',
'type': 'pool',
'uuid': '3d315997-73bd-5a74-8ca7-289206cb03ab',
'$pool': '3d315997-73bd-5a74-8ca7-289206cb03ab',
'$poolId': '3d315997-73bd-5a74-8ca7-289206cb03ab'
}
},
'hosts': {
'c96ec4dd-28ac-4df4-b73c-4371bd202728': {
'type': 'host',
'uuid': 'c96ec4dd-28ac-4df4-b73c-4371bd202728',
'enabled': True,
'CPUs': {
'cpu_count': '40',
'socket_count': '2',
'vendor': 'GenuineIntel',
'speed': '1699.998',
'modelname': 'Intel(R) Xeon(R) CPU E5-2650L v2 @ 1.70GHz',
'family': '6',
'model': '62',
'stepping': '4'
},
'address': '172.16.210.14',
'build': 'release/stockholm/master/7',
'cpus': {'cores': 40, 'sockets': 2},
'hostname': 'r620-s1',
'name_description': 'Default install',
'name_label': 'R620-S1',
'memory': {'usage': 45283590144, 'size': 137391292416},
'power_state': 'Running',
'tags': [],
'version': '8.2.0',
'productBrand': 'XCP-ng',
'id': 'c96ec4dd-28ac-4df4-b73c-4371bd202728',
'$pool': '3d315997-73bd-5a74-8ca7-289206cb03ab',
'$poolId': '3d315997-73bd-5a74-8ca7-289206cb03ab'
"vms": {
"0e64588-2bea-2d82-e922-881654b0a48f": {
"type": "VM",
"addresses": {},
"CPUs": {"max": 4, "number": 4},
"memory": {"dynamic": [1073741824, 2147483648], "static": [536870912, 4294967296], "size": 2147483648},
"name_description": "",
"name_label": "XCP-NG lab 2",
"os_version": {},
"parent": "d3af89b2-d846-0874-6acb-031ccf11c560",
"power_state": "Running",
"tags": [],
"id": "0e645898-2bea-2d82-e922-881654b0a48f",
"uuid": "0e645898-2bea-2d82-e922-881654b0a48f",
"$pool": "3d315997-73bd-5a74-8ca7-289206cb03ab",
"$poolId": "3d315997-73bd-5a74-8ca7-289206cb03ab",
"$container": "222d8594-9426-468a-ad69-7a6f02330fa3",
},
'222d8594-9426-468a-ad69-7a6f02330fa3': {
'type': 'host',
'uuid': '222d8594-9426-468a-ad69-7a6f02330fa3',
'enabled': True,
'CPUs': {
'cpu_count': '40',
'socket_count': '2',
'vendor': 'GenuineIntel',
'speed': '1700.007',
'modelname': 'Intel(R) Xeon(R) CPU E5-2650L v2 @ 1.70GHz',
'family': '6',
'model': '62',
'stepping': '4'
},
'address': '172.16.210.16',
'build': 'release/stockholm/master/7',
'cpus': {'cores': 40, 'sockets': 2},
'hostname': 'r620-s2',
'name_description': 'Default install',
'name_label': 'R620-S2',
'memory': {'usage': 10636521472, 'size': 137391292416},
'power_state': 'Running',
'tags': ['foo', 'bar', 'baz'],
'version': '8.2.0',
'productBrand': 'XCP-ng',
'id': '222d8594-9426-468a-ad69-7a6f02330fa3',
'$pool': '3d315997-73bd-5a74-8ca7-289206cb03ab',
'$poolId': '3d315997-73bd-5a74-8ca7-289206cb03ab'
"b0d25e70-019d-6182-2f7c-b0f5d8ef9331": {
"type": "VM",
"addresses": {"0/ipv4/0": "192.168.1.55", "1/ipv4/0": "10.0.90.1"},
"CPUs": {"max": 4, "number": 4},
"mainIpAddress": "192.168.1.55",
"memory": {"dynamic": [2147483648, 2147483648], "static": [134217728, 2147483648], "size": 2147483648},
"name_description": "",
"name_label": "XCP-NG lab 3",
"os_version": {"name": "FreeBSD 11.3-STABLE", "uname": "11.3-STABLE", "distro": "FreeBSD"},
"power_state": "Halted",
"tags": [],
"id": "b0d25e70-019d-6182-2f7c-b0f5d8ef9331",
"uuid": "b0d25e70-019d-6182-2f7c-b0f5d8ef9331",
"$pool": "3d315997-73bd-5a74-8ca7-289206cb03ab",
"$poolId": "3d315997-73bd-5a74-8ca7-289206cb03ab",
"$container": "c96ec4dd-28ac-4df4-b73c-4371bd202728",
},
},
"pools": {
"3d315997-73bd-5a74-8ca7-289206cb03ab": {
"master": "222d8594-9426-468a-ad69-7a6f02330fa3",
"tags": [],
"name_description": "",
"name_label": "Storage Lab",
"cpus": {"cores": 120, "sockets": 6},
"id": "3d315997-73bd-5a74-8ca7-289206cb03ab",
"type": "pool",
"uuid": "3d315997-73bd-5a74-8ca7-289206cb03ab",
"$pool": "3d315997-73bd-5a74-8ca7-289206cb03ab",
"$poolId": "3d315997-73bd-5a74-8ca7-289206cb03ab",
}
}
},
"hosts": {
"c96ec4dd-28ac-4df4-b73c-4371bd202728": {
"type": "host",
"uuid": "c96ec4dd-28ac-4df4-b73c-4371bd202728",
"enabled": True,
"CPUs": {
"cpu_count": "40",
"socket_count": "2",
"vendor": "GenuineIntel",
"speed": "1699.998",
"modelname": "Intel(R) Xeon(R) CPU E5-2650L v2 @ 1.70GHz",
"family": "6",
"model": "62",
"stepping": "4",
},
"address": "172.16.210.14",
"build": "release/stockholm/master/7",
"cpus": {"cores": 40, "sockets": 2},
"hostname": "r620-s1",
"name_description": "Default install",
"name_label": "R620-S1",
"memory": {"usage": 45283590144, "size": 137391292416},
"power_state": "Running",
"tags": [],
"version": "8.2.0",
"productBrand": "XCP-ng",
"id": "c96ec4dd-28ac-4df4-b73c-4371bd202728",
"$pool": "3d315997-73bd-5a74-8ca7-289206cb03ab",
"$poolId": "3d315997-73bd-5a74-8ca7-289206cb03ab",
},
"222d8594-9426-468a-ad69-7a6f02330fa3": {
"type": "host",
"uuid": "222d8594-9426-468a-ad69-7a6f02330fa3",
"enabled": True,
"CPUs": {
"cpu_count": "40",
"socket_count": "2",
"vendor": "GenuineIntel",
"speed": "1700.007",
"modelname": "Intel(R) Xeon(R) CPU E5-2650L v2 @ 1.70GHz",
"family": "6",
"model": "62",
"stepping": "4",
},
"address": "172.16.210.16",
"build": "release/stockholm/master/7",
"cpus": {"cores": 40, "sockets": 2},
"hostname": "r620-s2",
"name_description": "Default install",
"name_label": "R620-S2",
"memory": {"usage": 10636521472, "size": 137391292416},
"power_state": "Running",
"tags": ["foo", "bar", "baz"],
"version": "8.2.0",
"productBrand": "XCP-ng",
"id": "222d8594-9426-468a-ad69-7a6f02330fa3",
"$pool": "3d315997-73bd-5a74-8ca7-289206cb03ab",
"$poolId": "3d315997-73bd-5a74-8ca7-289206cb03ab",
},
},
}
def get_option(option):
if option == 'groups':
if option == "groups":
return {}
elif option == 'keyed_groups':
elif option == "keyed_groups":
return []
elif option == 'compose':
elif option == "compose":
return {}
elif option == 'strict':
elif option == "strict":
return False
else:
return None
@@ -152,55 +150,57 @@ def inventory():
def test_verify_file_bad_config(inventory):
assert inventory.verify_file('foobar.xen_orchestra.yml') is False
assert inventory.verify_file("foobar.xen_orchestra.yml") is False
def test_populate(inventory, mocker):
inventory.host_entry_name_type = 'uuid'
inventory.vm_entry_name_type = 'uuid'
inventory.host_entry_name_type = "uuid"
inventory.vm_entry_name_type = "uuid"
inventory.get_option = mocker.MagicMock(side_effect=get_option)
inventory._populate(objects)
actual = sorted(inventory.inventory.hosts.keys())
expected = sorted(['c96ec4dd-28ac-4df4-b73c-4371bd202728', '222d8594-9426-468a-ad69-7a6f02330fa3',
'0e64588-2bea-2d82-e922-881654b0a48f', 'b0d25e70-019d-6182-2f7c-b0f5d8ef9331'])
expected = sorted(
[
"c96ec4dd-28ac-4df4-b73c-4371bd202728",
"222d8594-9426-468a-ad69-7a6f02330fa3",
"0e64588-2bea-2d82-e922-881654b0a48f",
"b0d25e70-019d-6182-2f7c-b0f5d8ef9331",
]
)
assert actual == expected
# Host with ip assertions
host_with_ip = inventory.inventory.get_host(
'b0d25e70-019d-6182-2f7c-b0f5d8ef9331')
host_with_ip = inventory.inventory.get_host("b0d25e70-019d-6182-2f7c-b0f5d8ef9331")
host_with_ip_vars = host_with_ip.vars
assert host_with_ip_vars['ansible_host'] == '192.168.1.55'
assert host_with_ip_vars['power_state'] == 'halted'
assert host_with_ip_vars['type'] == 'VM'
assert host_with_ip_vars["ansible_host"] == "192.168.1.55"
assert host_with_ip_vars["power_state"] == "halted"
assert host_with_ip_vars["type"] == "VM"
assert host_with_ip in inventory.inventory.groups['with_ip'].hosts
assert host_with_ip in inventory.inventory.groups["with_ip"].hosts
# Host without ip
host_without_ip = inventory.inventory.get_host(
'0e64588-2bea-2d82-e922-881654b0a48f')
host_without_ip = inventory.inventory.get_host("0e64588-2bea-2d82-e922-881654b0a48f")
host_without_ip_vars = host_without_ip.vars
assert host_without_ip_vars['ansible_host'] is None
assert host_without_ip_vars['power_state'] == 'running'
assert host_without_ip_vars["ansible_host"] is None
assert host_without_ip_vars["power_state"] == "running"
assert host_without_ip in inventory.inventory.groups['without_ip'].hosts
assert host_without_ip in inventory.inventory.groups["without_ip"].hosts
assert host_with_ip in inventory.inventory.groups['xo_host_r620_s1'].hosts
assert host_without_ip in inventory.inventory.groups['xo_host_r620_s2'].hosts
assert host_with_ip in inventory.inventory.groups["xo_host_r620_s1"].hosts
assert host_without_ip in inventory.inventory.groups["xo_host_r620_s2"].hosts
r620_s1 = inventory.inventory.get_host(
'c96ec4dd-28ac-4df4-b73c-4371bd202728')
r620_s2 = inventory.inventory.get_host(
'222d8594-9426-468a-ad69-7a6f02330fa3')
r620_s1 = inventory.inventory.get_host("c96ec4dd-28ac-4df4-b73c-4371bd202728")
r620_s2 = inventory.inventory.get_host("222d8594-9426-468a-ad69-7a6f02330fa3")
assert r620_s1.vars['address'] == '172.16.210.14'
assert r620_s1.vars['tags'] == []
assert r620_s2.vars['address'] == '172.16.210.16'
assert r620_s2.vars['tags'] == ['foo', 'bar', 'baz']
assert r620_s1.vars["address"] == "172.16.210.14"
assert r620_s1.vars["tags"] == []
assert r620_s2.vars["address"] == "172.16.210.16"
assert r620_s2.vars["tags"] == ["foo", "bar", "baz"]
storage_lab = inventory.inventory.groups['xo_pool_storage_lab']
storage_lab = inventory.inventory.groups["xo_pool_storage_lab"]
# Check that hosts are in their corresponding pool
assert r620_s1 in storage_lab.hosts

View File

@@ -12,7 +12,10 @@ from ansible_collections.community.general.plugins.lookup.onepassword import One
@pytest.fixture
def fake_op(mocker):
def _fake_op(version):
mocker.patch("ansible_collections.community.general.plugins.lookup.onepassword.OnePassCLIBase.get_current_version", return_value=version)
mocker.patch(
"ansible_collections.community.general.plugins.lookup.onepassword.OnePassCLIBase.get_current_version",
return_value=version,
)
op = OnePass()
op._config._config_file_path = "/home/jin/.op/config"
mocker.patch.object(op._cli, "_run")

View File

@@ -22,31 +22,22 @@ def load_file(file):
MOCK_ENTRIES = {
OnePassCLIv1: [
{
'vault_name': 'Acme "Quot\'d" Servers',
'queries': [
'0123456789',
'Mock "Quot\'d" Server'
],
'expected': ['t0pS3cret', 't0pS3cret'],
'output': load_file("v1_out_01.json"),
"vault_name": 'Acme "Quot\'d" Servers',
"queries": ["0123456789", 'Mock "Quot\'d" Server'],
"expected": ["t0pS3cret", "t0pS3cret"],
"output": load_file("v1_out_01.json"),
},
{
'vault_name': 'Acme Logins',
'queries': [
'9876543210',
'Mock Website',
'acme.com'
],
'expected': ['t0pS3cret', 't0pS3cret', 't0pS3cret'],
'output': load_file("v1_out_02.json"),
"vault_name": "Acme Logins",
"queries": ["9876543210", "Mock Website", "acme.com"],
"expected": ["t0pS3cret", "t0pS3cret", "t0pS3cret"],
"output": load_file("v1_out_02.json"),
},
{
'vault_name': 'Acme Logins',
'queries': [
'864201357'
],
'expected': ['vauxhall'],
'output': load_file("v1_out_03.json"),
"vault_name": "Acme Logins",
"queries": ["864201357"],
"expected": ["vauxhall"],
"output": load_file("v1_out_03.json"),
},
],
OnePassCLIv2: [
@@ -67,7 +58,7 @@ MOCK_ENTRIES = {
"field": "password1",
},
"expected": ["data in custom field"],
"output": load_file("v2_out_02.json")
"output": load_file("v2_out_02.json"),
},
{
# Request data from a custom section
@@ -78,7 +69,7 @@ MOCK_ENTRIES = {
"section": "Section 2",
},
"expected": ["first value"],
"output": load_file("v2_out_03.json")
"output": load_file("v2_out_03.json"),
},
{
# Request data from an omitted value (label lookup, no section)
@@ -88,7 +79,7 @@ MOCK_ENTRIES = {
"field": "label-without-value",
},
"expected": [""],
"output": load_file("v2_out_04.json")
"output": load_file("v2_out_04.json"),
},
{
# Request data from an omitted value (id lookup, no section)
@@ -98,18 +89,15 @@ MOCK_ENTRIES = {
"field": "67890q7mspf4x6zrlw3qejn7m",
},
"expected": [""],
"output": load_file("v2_out_04.json")
"output": load_file("v2_out_04.json"),
},
{
# Request data from an omitted value (label lookup, with section)
"vault_name": "Test Vault",
"queries": ["Omitted values"],
"kwargs": {
"field": "section-label-without-value",
"section": "Section-Without-Values"
},
"kwargs": {"field": "section-label-without-value", "section": "Section-Without-Values"},
"expected": [""],
"output": load_file("v2_out_04.json")
"output": load_file("v2_out_04.json"),
},
{
# Request data from an omitted value (id lookup, with section)
@@ -120,7 +108,7 @@ MOCK_ENTRIES = {
"section": "section-without-values",
},
"expected": [""],
"output": load_file("v2_out_04.json")
"output": load_file("v2_out_04.json"),
},
{
# Query item without section by lowercase id (case matching)
@@ -130,7 +118,7 @@ MOCK_ENTRIES = {
"field": "lowercaseid",
},
"expected": ["lowercaseid"],
"output": load_file("v2_out_05.json")
"output": load_file("v2_out_05.json"),
},
{
# Query item without section by lowercase id (case not matching)
@@ -140,7 +128,7 @@ MOCK_ENTRIES = {
"field": "LOWERCASEID",
},
"expected": ["lowercaseid"],
"output": load_file("v2_out_05.json")
"output": load_file("v2_out_05.json"),
},
{
# Query item without section by lowercase label (case matching)
@@ -150,7 +138,7 @@ MOCK_ENTRIES = {
"field": "lowercaselabel",
},
"expected": ["lowercaselabel"],
"output": load_file("v2_out_05.json")
"output": load_file("v2_out_05.json"),
},
{
# Query item without section by lowercase label (case not matching)
@@ -160,7 +148,7 @@ MOCK_ENTRIES = {
"field": "LOWERCASELABEL",
},
"expected": ["lowercaselabel"],
"output": load_file("v2_out_05.json")
"output": load_file("v2_out_05.json"),
},
{
# Query item without section by mixed case id (case matching)
@@ -170,7 +158,7 @@ MOCK_ENTRIES = {
"field": "MiXeDcAsEiD",
},
"expected": ["mixedcaseid"],
"output": load_file("v2_out_05.json")
"output": load_file("v2_out_05.json"),
},
{
# Query item without section by mixed case id (case not matching)
@@ -180,7 +168,7 @@ MOCK_ENTRIES = {
"field": "mixedcaseid",
},
"expected": ["mixedcaseid"],
"output": load_file("v2_out_05.json")
"output": load_file("v2_out_05.json"),
},
{
# Query item without section by mixed case label (case matching)
@@ -190,7 +178,7 @@ MOCK_ENTRIES = {
"field": "MiXeDcAsElAbEl",
},
"expected": ["mixedcaselabel"],
"output": load_file("v2_out_05.json")
"output": load_file("v2_out_05.json"),
},
{
# Query item without section by mixed case label (case not matching)
@@ -200,7 +188,7 @@ MOCK_ENTRIES = {
"field": "mixedcaselabel",
},
"expected": ["mixedcaselabel"],
"output": load_file("v2_out_05.json")
"output": load_file("v2_out_05.json"),
},
{
# Query item with section by lowercase id (case matching)
@@ -211,7 +199,7 @@ MOCK_ENTRIES = {
"section": "section-with-values",
},
"expected": ["sectionlowercaseid"],
"output": load_file("v2_out_05.json")
"output": load_file("v2_out_05.json"),
},
{
# Query item with section by lowercase id (case not matching)
@@ -222,7 +210,7 @@ MOCK_ENTRIES = {
"section": "section-with-values",
},
"expected": ["sectionlowercaseid"],
"output": load_file("v2_out_05.json")
"output": load_file("v2_out_05.json"),
},
{
# Query item with section by lowercase label (case matching)
@@ -233,7 +221,7 @@ MOCK_ENTRIES = {
"section": "section-with-values",
},
"expected": ["sectionlowercaselabel"],
"output": load_file("v2_out_05.json")
"output": load_file("v2_out_05.json"),
},
{
# Query item with section by lowercase label (case not matching)
@@ -244,7 +232,7 @@ MOCK_ENTRIES = {
"section": "section-with-values",
},
"expected": ["sectionlowercaselabel"],
"output": load_file("v2_out_05.json")
"output": load_file("v2_out_05.json"),
},
{
# Query item with section by lowercase id (case matching)
@@ -255,7 +243,7 @@ MOCK_ENTRIES = {
"section": "section-with-values",
},
"expected": ["sectionmixedcaseid"],
"output": load_file("v2_out_05.json")
"output": load_file("v2_out_05.json"),
},
{
# Query item with section by lowercase id (case not matching)
@@ -266,7 +254,7 @@ MOCK_ENTRIES = {
"section": "section-with-values",
},
"expected": ["sectionmixedcaseid"],
"output": load_file("v2_out_05.json")
"output": load_file("v2_out_05.json"),
},
{
# Query item with section by lowercase label (case matching)
@@ -277,7 +265,7 @@ MOCK_ENTRIES = {
"section": "section-with-values",
},
"expected": ["sectionmixedcaselabel"],
"output": load_file("v2_out_05.json")
"output": load_file("v2_out_05.json"),
},
{
# Query item with section by lowercase label (case not matching)
@@ -288,7 +276,7 @@ MOCK_ENTRIES = {
"section": "section-with-values",
},
"expected": ["sectionmixedcaselabel"],
"output": load_file("v2_out_05.json")
"output": load_file("v2_out_05.json"),
},
],
}
@@ -298,9 +286,7 @@ SSH_KEY_MOCK_ENTRIES = [
{
"vault_name": "Personal",
"queries": ["ssh key"],
"expected": [
"-----BEGIN PRIVATE KEY-----\n..........=\n-----END PRIVATE KEY-----\n"
],
"expected": ["-----BEGIN PRIVATE KEY-----\n..........=\n-----END PRIVATE KEY-----\n"],
"output": load_file("ssh_key_output.json"),
},
# loads private key in PKCS#8 format becasue ssh_format=false
@@ -310,9 +296,7 @@ SSH_KEY_MOCK_ENTRIES = [
"kwargs": {
"ssh_format": False,
},
"expected": [
"-----BEGIN PRIVATE KEY-----\n..........=\n-----END PRIVATE KEY-----\n"
],
"expected": ["-----BEGIN PRIVATE KEY-----\n..........=\n-----END PRIVATE KEY-----\n"],
"output": load_file("ssh_key_output.json"),
},
# loads private key in ssh format
@@ -322,9 +306,7 @@ SSH_KEY_MOCK_ENTRIES = [
"kwargs": {
"ssh_format": True,
},
"expected": [
"-----BEGIN OPENSSH PRIVATE KEY-----\r\n.....\r\n-----END OPENSSH PRIVATE KEY-----\r\n"
],
"expected": ["-----BEGIN OPENSSH PRIVATE KEY-----\r\n.....\r\n-----END OPENSSH PRIVATE KEY-----\r\n"],
"output": load_file("ssh_key_output.json"),
},
]

View File

@@ -18,24 +18,12 @@ MOCK_ORGANIZATION_ID = "292ba0c6-f289-11ee-9301-ef7b639ccd2a"
MOCK_RECORDS = [
{
"collectionIds": [
MOCK_COLLECTION_ID
],
"collectionIds": [MOCK_COLLECTION_ID],
"deletedDate": None,
"favorite": False,
"fields": [
{
"linkedId": None,
"name": "a_new_secret",
"type": 1,
"value": "this is a new secret"
},
{
"linkedId": None,
"name": "not so secret",
"type": 0,
"value": "not secret"
}
{"linkedId": None, "name": "a_new_secret", "type": 1, "value": "this is a new secret"},
{"linkedId": None, "name": "not so secret", "type": 0, "value": "not secret"},
],
"folderId": "3b12a9da-7c49-40b8-ad33-aede017a7ead",
"id": "90992f63-ddb6-4e76-8bfc-aede016ca5eb",
@@ -43,29 +31,20 @@ MOCK_RECORDS = [
"password": "passwordA3",
"passwordRevisionDate": "2022-07-26T23:03:23.399Z",
"totp": None,
"username": "userA"
"username": "userA",
},
"name": "a_test",
"notes": None,
"object": "item",
"organizationId": MOCK_ORGANIZATION_ID,
"passwordHistory": [
{
"lastUsedDate": "2022-07-26T23:03:23.405Z",
"password": "a_new_secret: this is secret"
},
{
"lastUsedDate": "2022-07-26T23:03:23.399Z",
"password": "passwordA2"
},
{
"lastUsedDate": "2022-07-26T22:59:52.885Z",
"password": "passwordA"
}
{"lastUsedDate": "2022-07-26T23:03:23.405Z", "password": "a_new_secret: this is secret"},
{"lastUsedDate": "2022-07-26T23:03:23.399Z", "password": "passwordA2"},
{"lastUsedDate": "2022-07-26T22:59:52.885Z", "password": "passwordA"},
],
"reprompt": 0,
"revisionDate": "2022-07-26T23:03:23.743Z",
"type": 1
"type": 1,
},
{
"collectionIds": [],
@@ -73,41 +52,29 @@ MOCK_RECORDS = [
"favorite": False,
"folderId": None,
"id": "5ebd4d31-104c-49fc-a09c-aedf003d28ad",
"login": {
"password": "b",
"passwordRevisionDate": None,
"totp": None,
"username": "a"
},
"login": {"password": "b", "passwordRevisionDate": None, "totp": None, "username": "a"},
"name": "dupe_name",
"notes": None,
"object": "item",
"organizationId": None,
"reprompt": 0,
"revisionDate": "2022-07-27T03:42:40.353Z",
"type": 1
"type": 1,
},
{
"collectionIds": [
MOCK_COLLECTION_ID
],
"collectionIds": [MOCK_COLLECTION_ID],
"deletedDate": None,
"favorite": False,
"folderId": None,
"id": "90657653-6695-496d-9431-aedf003d3015",
"login": {
"password": "d",
"passwordRevisionDate": None,
"totp": None,
"username": "c"
},
"login": {"password": "d", "passwordRevisionDate": None, "totp": None, "username": "c"},
"name": "dupe_name",
"notes": None,
"object": "item",
"organizationId": MOCK_ORGANIZATION_ID,
"reprompt": 0,
"revisionDate": "2022-07-27T03:42:46.673Z",
"type": 1
"type": 1,
},
{
"collectionIds": [],
@@ -115,153 +82,142 @@ MOCK_RECORDS = [
"favorite": False,
"folderId": None,
"id": "2bf517be-fb13-11ee-be89-a345aa369a94",
"login": {
"password": "e",
"passwordRevisionDate": None,
"totp": None,
"username": "f"
},
"login": {"password": "e", "passwordRevisionDate": None, "totp": None, "username": "f"},
"name": "non_collection_org_record",
"notes": None,
"object": "item",
"organizationId": MOCK_ORGANIZATION_ID,
"reprompt": 0,
"revisionDate": "2024-14-15T11:30:00.000Z",
"type": 1
"type": 1,
},
{
"object": "collection",
"id": MOCK_COLLECTION_ID,
"organizationId": MOCK_ORGANIZATION_ID,
"name": "MOCK_COLLECTION",
"externalId": None
"externalId": None,
},
{
"object": "collection",
"id": "3b12a9da-7c49-40b8-ad33-aede017a8ead",
"organizationId": "3b12a9da-7c49-40b8-ad33-aede017a9ead",
"name": "some/other/collection",
"externalId": None
"externalId": None,
},
]
class MockBitwarden(Bitwarden):
unlocked = True
def _run(self, args, stdin=None, expected_rc=0):
if args[0] == 'get':
if args[1] == 'item':
if args[0] == "get":
if args[1] == "item":
for item in MOCK_RECORDS:
if item.get('id') == args[2]:
return AnsibleJSONEncoder().encode(item), ''
if args[0] == 'list':
if args[1] == 'items':
if item.get("id") == args[2]:
return AnsibleJSONEncoder().encode(item), ""
if args[0] == "list":
if args[1] == "items":
try:
search_value = args[args.index('--search') + 1]
search_value = args[args.index("--search") + 1]
except ValueError:
search_value = None
try:
collection_to_filter = args[args.index('--collectionid') + 1]
collection_to_filter = args[args.index("--collectionid") + 1]
except ValueError:
collection_to_filter = None
try:
organization_to_filter = args[args.index('--organizationid') + 1]
organization_to_filter = args[args.index("--organizationid") + 1]
except ValueError:
organization_to_filter = None
items = []
for item in MOCK_RECORDS:
if item.get('object') != 'item':
if item.get("object") != "item":
continue
if search_value and not re.search(search_value, item.get('name')):
if search_value and not re.search(search_value, item.get("name")):
continue
if collection_to_filter and collection_to_filter not in item.get('collectionIds', []):
if collection_to_filter and collection_to_filter not in item.get("collectionIds", []):
continue
if organization_to_filter and item.get('organizationId') != organization_to_filter:
if organization_to_filter and item.get("organizationId") != organization_to_filter:
continue
items.append(item)
return AnsibleJSONEncoder().encode(items), ''
elif args[1] == 'collections':
return AnsibleJSONEncoder().encode(items), ""
elif args[1] == "collections":
try:
search_value = args[args.index('--search') + 1]
search_value = args[args.index("--search") + 1]
except ValueError:
search_value = None
try:
collection_to_filter = args[args.index('--collectionid') + 1]
collection_to_filter = args[args.index("--collectionid") + 1]
except ValueError:
collection_to_filter = None
try:
organization_to_filter = args[args.index('--organizationid') + 1]
organization_to_filter = args[args.index("--organizationid") + 1]
except ValueError:
organization_to_filter = None
collections = []
for item in MOCK_RECORDS:
if item.get('object') != 'collection':
if item.get("object") != "collection":
continue
if search_value and not re.search(search_value, item.get('name')):
if search_value and not re.search(search_value, item.get("name")):
continue
if collection_to_filter and collection_to_filter not in item.get('collectionIds', []):
if collection_to_filter and collection_to_filter not in item.get("collectionIds", []):
continue
if organization_to_filter and item.get('organizationId') != organization_to_filter:
if organization_to_filter and item.get("organizationId") != organization_to_filter:
continue
collections.append(item)
return AnsibleJSONEncoder().encode(collections), ''
return AnsibleJSONEncoder().encode(collections), ""
return '[]', ''
return "[]", ""
class LoggedOutMockBitwarden(MockBitwarden):
unlocked = False
class TestLookupModule(unittest.TestCase):
def setUp(self):
self.lookup = lookup_loader.get('community.general.bitwarden')
self.lookup = lookup_loader.get("community.general.bitwarden")
@patch('ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden', new=MockBitwarden())
@patch("ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden", new=MockBitwarden())
def test_bitwarden_plugin_no_match(self):
# Entry 0, "a_test" of the test input should have no duplicates.
self.assertEqual([], self.lookup.run(['not_here'], field='password')[0])
self.assertEqual([], self.lookup.run(["not_here"], field="password")[0])
@patch('ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden', new=MockBitwarden())
@patch("ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden", new=MockBitwarden())
def test_bitwarden_plugin_fields(self):
# Entry 0, "a_test" of the test input should have no duplicates.
record = MOCK_RECORDS[0]
record_name = record['name']
for k, v in record['login'].items():
self.assertEqual([v],
self.lookup.run([record_name], field=k)[0])
record_name = record["name"]
for k, v in record["login"].items():
self.assertEqual([v], self.lookup.run([record_name], field=k)[0])
@patch('ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden', new=MockBitwarden())
@patch("ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden", new=MockBitwarden())
def test_bitwarden_plugin_duplicates(self):
# There are two records with name dupe_name; we need to be order-insensitive with
# checking what was retrieved.
self.assertEqual(set(['b', 'd']),
set(self.lookup.run(['dupe_name'], field='password')[0]))
self.assertEqual(set(["b", "d"]), set(self.lookup.run(["dupe_name"], field="password")[0]))
@patch('ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden', new=MockBitwarden())
@patch("ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden", new=MockBitwarden())
def test_bitwarden_plugin_full_item(self):
# Try to retrieve the full record of the first entry where the name is "a_name".
self.assertEqual([MOCK_RECORDS[0]],
self.lookup.run(['a_test'])[0])
self.assertEqual([MOCK_RECORDS[0]], self.lookup.run(["a_test"])[0])
@patch('ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden', LoggedOutMockBitwarden())
@patch("ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden", LoggedOutMockBitwarden())
def test_bitwarden_plugin_unlocked(self):
record = MOCK_RECORDS[0]
record_name = record['name']
record_name = record["name"]
with self.assertRaises(AnsibleError) as raised_error:
self.lookup.run([record_name], field='password')
self.lookup.run([record_name], field="password")
self.assertEqual("Bitwarden Vault locked. Run 'bw unlock'.", str(raised_error.exception))
@@ -269,8 +225,8 @@ class TestLookupModule(unittest.TestCase):
mock_bitwarden = MockBitwarden()
with patch("ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden", mock_bitwarden):
record = MOCK_RECORDS[0]
record_name = record['name']
session = 'session'
record_name = record["name"]
session = "session"
self.lookup.run([record_name], field=None)
self.assertIsNone(mock_bitwarden.session)
@@ -279,37 +235,41 @@ class TestLookupModule(unittest.TestCase):
mock_bitwarden = MockBitwarden()
with patch("ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden", mock_bitwarden):
record = MOCK_RECORDS[0]
record_name = record['name']
session = 'session'
record_name = record["name"]
session = "session"
self.lookup.run([record_name], field=None, bw_session=session)
self.assertEqual(mock_bitwarden.session, session)
@patch('ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden', new=MockBitwarden())
@patch("ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden", new=MockBitwarden())
def test_bitwarden_plugin_full_collection(self):
# Try to retrieve the full records of the given collection.
self.assertEqual([MOCK_RECORDS[0], MOCK_RECORDS[2]], self.lookup.run(None, collection_id=MOCK_COLLECTION_ID)[0])
@patch('ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden', new=MockBitwarden())
@patch("ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden", new=MockBitwarden())
def test_bitwarden_plugin_full_organization(self):
self.assertEqual([MOCK_RECORDS[0], MOCK_RECORDS[2], MOCK_RECORDS[3]],
self.lookup.run(None, organization_id=MOCK_ORGANIZATION_ID)[0])
self.assertEqual(
[MOCK_RECORDS[0], MOCK_RECORDS[2], MOCK_RECORDS[3]],
self.lookup.run(None, organization_id=MOCK_ORGANIZATION_ID)[0],
)
@patch('ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden', new=MockBitwarden())
@patch("ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden", new=MockBitwarden())
def test_bitwarden_plugin_filter_organization(self):
self.assertEqual([MOCK_RECORDS[2]],
self.lookup.run(['dupe_name'], organization_id=MOCK_ORGANIZATION_ID)[0])
self.assertEqual([MOCK_RECORDS[2]], self.lookup.run(["dupe_name"], organization_id=MOCK_ORGANIZATION_ID)[0])
@patch('ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden', new=MockBitwarden())
@patch("ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden", new=MockBitwarden())
def test_bitwarden_plugin_full_collection_organization(self):
self.assertEqual([MOCK_RECORDS[0], MOCK_RECORDS[2]], self.lookup.run(None,
collection_id=MOCK_COLLECTION_ID, organization_id=MOCK_ORGANIZATION_ID)[0])
self.assertEqual(
[MOCK_RECORDS[0], MOCK_RECORDS[2]],
self.lookup.run(None, collection_id=MOCK_COLLECTION_ID, organization_id=MOCK_ORGANIZATION_ID)[0],
)
@patch('ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden', new=MockBitwarden())
@patch("ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden", new=MockBitwarden())
def test_bitwarden_plugin_collection_name_filter(self):
# all passwords from MOCK_COLLECTION
self.assertEqual([MOCK_RECORDS[0], MOCK_RECORDS[2]], self.lookup.run(None,
collection_name="MOCK_COLLECTION")[0])
self.assertEqual(
[MOCK_RECORDS[0], MOCK_RECORDS[2]], self.lookup.run(None, collection_name="MOCK_COLLECTION")[0]
)
# Existing collection, no results
self.assertEqual([], self.lookup.run(None, collection_name="some/other/collection")[0])
@@ -317,12 +277,13 @@ class TestLookupModule(unittest.TestCase):
with self.assertRaises(BitwardenException):
self.lookup.run(None, collection_name="nonexistent")
@patch('ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden', new=MockBitwarden())
@patch("ansible_collections.community.general.plugins.lookup.bitwarden._bitwarden", new=MockBitwarden())
def test_bitwarden_plugin_result_count_check(self):
self.lookup.run(None, collection_id=MOCK_COLLECTION_ID, organization_id=MOCK_ORGANIZATION_ID, result_count=2)
with self.assertRaises(BitwardenException):
self.lookup.run(None, collection_id=MOCK_COLLECTION_ID, organization_id=MOCK_ORGANIZATION_ID,
result_count=1)
self.lookup.run(
None, collection_id=MOCK_COLLECTION_ID, organization_id=MOCK_ORGANIZATION_ID, result_count=1
)
self.lookup.run(None, organization_id=MOCK_ORGANIZATION_ID, result_count=3)
with self.assertRaises(BitwardenException):

View File

@@ -23,7 +23,7 @@ MOCK_SECRETS = [
"value": "1234supersecret5678",
"note": "A test secret to use when developing the ansible bitwarden_secrets_manager lookup plugin",
"creationDate": "2023-04-23T13:13:37.7507017Z",
"revisionDate": "2023-04-23T13:13:37.7507017Z"
"revisionDate": "2023-04-23T13:13:37.7507017Z",
},
{
"object": "secret",
@@ -34,13 +34,12 @@ MOCK_SECRETS = [
"value": "abcd_such_secret_very_important_efgh",
"note": "notes go here",
"creationDate": "2023-04-23T13:26:44.0392906Z",
"revisionDate": "2023-04-23T13:26:44.0392906Z"
}
"revisionDate": "2023-04-23T13:26:44.0392906Z",
},
]
class MockBitwardenSecretsManager(BitwardenSecretsManager):
def _run(self, args, stdin=None):
# mock the --version call
if args[0] == "--version":
@@ -68,17 +67,24 @@ class MockBitwardenSecretsManager(BitwardenSecretsManager):
class TestLookupModule(unittest.TestCase):
def setUp(self):
self.lookup = lookup_loader.get('community.general.bitwarden_secrets_manager')
self.lookup = lookup_loader.get("community.general.bitwarden_secrets_manager")
@patch('ansible_collections.community.general.plugins.lookup.bitwarden_secrets_manager._bitwarden_secrets_manager', new=MockBitwardenSecretsManager())
@patch(
"ansible_collections.community.general.plugins.lookup.bitwarden_secrets_manager._bitwarden_secrets_manager",
new=MockBitwardenSecretsManager(),
)
def test_bitwarden_secrets_manager(self):
# Getting a secret by its id should return the full secret info
self.assertEqual([MOCK_SECRETS[0]], self.lookup.run(['ababc4a8-c242-4e54-bceb-77d17cdf2e07'], bws_access_token='123'))
self.assertEqual(
[MOCK_SECRETS[0]], self.lookup.run(["ababc4a8-c242-4e54-bceb-77d17cdf2e07"], bws_access_token="123")
)
@patch('ansible_collections.community.general.plugins.lookup.bitwarden_secrets_manager._bitwarden_secrets_manager', new=MockBitwardenSecretsManager())
@patch(
"ansible_collections.community.general.plugins.lookup.bitwarden_secrets_manager._bitwarden_secrets_manager",
new=MockBitwardenSecretsManager(),
)
def test_bitwarden_secrets_manager_no_match(self):
# Getting a nonexistent secret id throws exception
with self.assertRaises(AnsibleLookupError):
self.lookup.run(['nonexistant_id'], bws_access_token='123')
self.lookup.run(["nonexistant_id"], bws_access_token="123")

View File

@@ -25,16 +25,16 @@ class TestLookupModule(TestCase):
self.assertListEqual(
self.lookup.run(
[
{'a': make_trusted('[1, 2]')},
{'b': make_trusted('[item.a + 3, item.a + 6]')},
{'c': make_trusted('[item.a + item.b * 10]')},
{"a": make_trusted("[1, 2]")},
{"b": make_trusted("[item.a + 3, item.a + 6]")},
{"c": make_trusted("[item.a + item.b * 10]")},
],
{},
),
[
{'a': 1, 'b': 4, 'c': 41},
{'a': 1, 'b': 7, 'c': 71},
{'a': 2, 'b': 5, 'c': 52},
{'a': 2, 'b': 8, 'c': 82},
{"a": 1, "b": 4, "c": 41},
{"a": 1, "b": 7, "c": 71},
{"a": 2, "b": 5, "c": 52},
{"a": 2, "b": 8, "c": 82},
],
)

View File

@@ -37,6 +37,10 @@ class TestLookupModule(TestCase):
self.lookup.run(
["/dummy"],
[],
**{"tenant": "dummy", "client_id": "dummy", "client_secret": "dummy", }
**{
"tenant": "dummy",
"client_id": "dummy",
"client_secret": "dummy",
},
),
)

View File

@@ -13,42 +13,39 @@ from ansible.plugins.loader import lookup_loader
class FakeKVMetadata:
def __init__(self, keyvalue, header):
self.key = keyvalue
self.create_revision = ''
self.mod_revision = ''
self.version = ''
self.lease_id = ''
self.create_revision = ""
self.mod_revision = ""
self.version = ""
self.lease_id = ""
self.response_header = header
class FakeEtcd3Client(MagicMock):
def get_prefix(self, key):
for i in range(1, 4):
yield self.get(f'{key}_{i}')
yield self.get(f"{key}_{i}")
def get(self, key):
return (f"{key} value", FakeKVMetadata(key, None))
class TestLookupModule(unittest.TestCase):
def setUp(self):
etcd3.HAS_ETCD = True
self.lookup = lookup_loader.get('community.general.etcd3')
self.lookup = lookup_loader.get("community.general.etcd3")
@patch('ansible_collections.community.general.plugins.lookup.etcd3.etcd3_client', FakeEtcd3Client())
@patch("ansible_collections.community.general.plugins.lookup.etcd3.etcd3_client", FakeEtcd3Client())
def test_key(self):
expected_result = [{'key': 'a_key', 'value': 'a_key value'}]
self.assertListEqual(expected_result, self.lookup.run(['a_key'], []))
expected_result = [{"key": "a_key", "value": "a_key value"}]
self.assertListEqual(expected_result, self.lookup.run(["a_key"], []))
@patch('ansible_collections.community.general.plugins.lookup.etcd3.etcd3_client', FakeEtcd3Client())
@patch("ansible_collections.community.general.plugins.lookup.etcd3.etcd3_client", FakeEtcd3Client())
def test_key_prefix(self):
expected_result = [
{'key': 'a_key_1', 'value': 'a_key_1 value'},
{'key': 'a_key_2', 'value': 'a_key_2 value'},
{'key': 'a_key_3', 'value': 'a_key_3 value'},
{"key": "a_key_1", "value": "a_key_1 value"},
{"key": "a_key_2", "value": "a_key_2 value"},
{"key": "a_key_3", "value": "a_key_3 value"},
]
self.assertListEqual(expected_result, self.lookup.run(['a_key'], [], **{'prefix': True}))
self.assertListEqual(expected_result, self.lookup.run(["a_key"], [], **{"prefix": True}))

View File

@@ -16,8 +16,8 @@ from unittest.mock import (
from ansible.plugins.loader import lookup_loader
ENCODE_RESULT = 'Foobar'
PRIVATE_KEY = 'private_key'
ENCODE_RESULT = "Foobar"
PRIVATE_KEY = "private_key"
class MockJWT(MagicMock):
@@ -31,101 +31,97 @@ class serialization(MagicMock):
class MockResponse(MagicMock):
response_token = 'Bar'
response_token = "Bar"
def read(self):
return json.dumps({
"token": self.response_token,
}).encode('utf-8')
return json.dumps(
{
"token": self.response_token,
}
).encode("utf-8")
class TestLookupModule(unittest.TestCase):
def test_get_token_with_file_with_pyjwt(self):
pyjwt = types.ModuleType("jwt")
pyjwt.encode = MagicMock(return_value=ENCODE_RESULT)
with patch.dict(sys.modules, {'jwt': pyjwt}), \
patch.multiple("ansible_collections.community.general.plugins.lookup.github_app_access_token",
open=mock_open(read_data="foo_bar"),
open_url=MagicMock(return_value=MockResponse()),
HAS_JWT=True,
HAS_CRYPTOGRAPHY=True,
serialization=serialization()):
lookup = lookup_loader.get('community.general.github_app_access_token')
with (
patch.dict(sys.modules, {"jwt": pyjwt}),
patch.multiple(
"ansible_collections.community.general.plugins.lookup.github_app_access_token",
open=mock_open(read_data="foo_bar"),
open_url=MagicMock(return_value=MockResponse()),
HAS_JWT=True,
HAS_CRYPTOGRAPHY=True,
serialization=serialization(),
),
):
lookup = lookup_loader.get("community.general.github_app_access_token")
self.assertListEqual(
[MockResponse.response_token],
lookup.run(
[],
key_path="key",
app_id="app_id",
installation_id="installation_id",
token_expiry=600
)
lookup.run([], key_path="key", app_id="app_id", installation_id="installation_id", token_expiry=600),
)
def test_get_token_with_fact_with_pyjwt(self):
pyjwt = types.ModuleType("jwt")
pyjwt.encode = MagicMock(return_value=ENCODE_RESULT)
with patch.dict(sys.modules, {'jwt': pyjwt}), \
patch.multiple("ansible_collections.community.general.plugins.lookup.github_app_access_token",
open=mock_open(read_data="foo_bar"),
open_url=MagicMock(return_value=MockResponse()),
HAS_JWT=True,
HAS_CRYPTOGRAPHY=True,
serialization=serialization()):
lookup = lookup_loader.get('community.general.github_app_access_token')
with (
patch.dict(sys.modules, {"jwt": pyjwt}),
patch.multiple(
"ansible_collections.community.general.plugins.lookup.github_app_access_token",
open=mock_open(read_data="foo_bar"),
open_url=MagicMock(return_value=MockResponse()),
HAS_JWT=True,
HAS_CRYPTOGRAPHY=True,
serialization=serialization(),
),
):
lookup = lookup_loader.get("community.general.github_app_access_token")
self.assertListEqual(
[MockResponse.response_token],
lookup.run(
[],
app_id="app_id",
installation_id="installation_id",
private_key="foo_bar",
token_expiry=600
)
[], app_id="app_id", installation_id="installation_id", private_key="foo_bar", token_expiry=600
),
)
def test_get_token_with_python_jwt(self):
python_jwt = types.ModuleType("jwt")
python_jwt.JWT = MagicMock()
python_jwt.jwk_from_pem = MagicMock(return_value='private_key')
python_jwt.jwk_from_pem = MagicMock(return_value="private_key")
python_jwt.jwt_instance = MockJWT()
with patch.dict(sys.modules, {'jwt': python_jwt}), \
patch.multiple("ansible_collections.community.general.plugins.lookup.github_app_access_token",
open=mock_open(read_data="foo_bar"),
open_url=MagicMock(return_value=MockResponse()),
HAS_JWT=True):
lookup = lookup_loader.get('community.general.github_app_access_token')
with (
patch.dict(sys.modules, {"jwt": python_jwt}),
patch.multiple(
"ansible_collections.community.general.plugins.lookup.github_app_access_token",
open=mock_open(read_data="foo_bar"),
open_url=MagicMock(return_value=MockResponse()),
HAS_JWT=True,
),
):
lookup = lookup_loader.get("community.general.github_app_access_token")
self.assertListEqual(
[MockResponse.response_token],
lookup.run(
[],
key_path="key",
app_id="app_id",
installation_id="installation_id",
token_expiry=600
)
lookup.run([], key_path="key", app_id="app_id", installation_id="installation_id", token_expiry=600),
)
def test_get_token_with_fact_with_python_jwt(self):
python_jwt = types.ModuleType("jwt")
python_jwt.JWT = MagicMock()
python_jwt.jwk_from_pem = MagicMock(return_value='private_key')
python_jwt.jwk_from_pem = MagicMock(return_value="private_key")
python_jwt.jwt_instance = MockJWT()
with patch.dict(sys.modules, {'jwt': python_jwt}), \
patch.multiple("ansible_collections.community.general.plugins.lookup.github_app_access_token",
open=mock_open(read_data="foo_bar"),
open_url=MagicMock(return_value=MockResponse()),
HAS_JWT=True):
lookup = lookup_loader.get('community.general.github_app_access_token')
with (
patch.dict(sys.modules, {"jwt": python_jwt}),
patch.multiple(
"ansible_collections.community.general.plugins.lookup.github_app_access_token",
open=mock_open(read_data="foo_bar"),
open_url=MagicMock(return_value=MockResponse()),
HAS_JWT=True,
),
):
lookup = lookup_loader.get("community.general.github_app_access_token")
self.assertListEqual(
[MockResponse.response_token],
lookup.run(
[],
app_id="app_id",
installation_id="installation_id",
private_key="foo_bar",
token_expiry=600
)
[], app_id="app_id", installation_id="installation_id", private_key="foo_bar", token_expiry=600
),
)

View File

@@ -14,112 +14,114 @@ from ansible.plugins.loader import lookup_loader
from ansible_collections.community.general.plugins.lookup.lastpass import LPass, LPassException
MOCK_ENTRIES = [{'username': 'user',
'name': 'Mock Entry',
'password': 't0pS3cret passphrase entry!',
'url': 'https://localhost/login',
'notes': 'Test\nnote with multiple lines.\n',
'id': '0123456789'}]
MOCK_ENTRIES = [
{
"username": "user",
"name": "Mock Entry",
"password": "t0pS3cret passphrase entry!",
"url": "https://localhost/login",
"notes": "Test\nnote with multiple lines.\n",
"id": "0123456789",
}
]
class MockLPass(LPass):
_mock_logged_out = False
_mock_disconnected = False
def _lookup_mock_entry(self, key):
for entry in MOCK_ENTRIES:
if key == entry['id'] or key == entry['name']:
if key == entry["id"] or key == entry["name"]:
return entry
def _run(self, args, stdin=None, expected_rc=0):
# Mock behavior of lpass executable
base_options = ArgumentParser(add_help=False)
base_options.add_argument('--color', default="auto", choices=['auto', 'always', 'never'])
base_options.add_argument("--color", default="auto", choices=["auto", "always", "never"])
p = ArgumentParser()
sp = p.add_subparsers(help='command', dest='subparser_name')
sp = p.add_subparsers(help="command", dest="subparser_name")
logout_p = sp.add_parser('logout', parents=[base_options], help='logout')
show_p = sp.add_parser('show', parents=[base_options], help='show entry details')
logout_p = sp.add_parser("logout", parents=[base_options], help="logout")
show_p = sp.add_parser("show", parents=[base_options], help="show entry details")
field_group = show_p.add_mutually_exclusive_group(required=True)
for field in MOCK_ENTRIES[0].keys():
field_group.add_argument(f"--{field}", default=False, action='store_true')
field_group.add_argument('--field', default=None)
show_p.add_argument('selector', help='Unique Name or ID')
field_group.add_argument(f"--{field}", default=False, action="store_true")
field_group.add_argument("--field", default=None)
show_p.add_argument("selector", help="Unique Name or ID")
args = p.parse_args(args)
def mock_exit(output='', error='', rc=0):
def mock_exit(output="", error="", rc=0):
if rc != expected_rc:
raise LPassException(error)
return output, error
if args.color != 'never':
return mock_exit(error='Error: Mock only supports --color=never', rc=1)
if args.color != "never":
return mock_exit(error="Error: Mock only supports --color=never", rc=1)
if args.subparser_name == 'logout':
if args.subparser_name == "logout":
if self._mock_logged_out:
return mock_exit(error='Error: Not currently logged in', rc=1)
return mock_exit(error="Error: Not currently logged in", rc=1)
logged_in_error = 'Are you sure you would like to log out? [Y/n]'
if stdin and stdin.lower() == 'n\n':
return mock_exit(output='Log out: aborted.', error=logged_in_error, rc=1)
elif stdin and stdin.lower() == 'y\n':
return mock_exit(output='Log out: complete.', error=logged_in_error, rc=0)
logged_in_error = "Are you sure you would like to log out? [Y/n]"
if stdin and stdin.lower() == "n\n":
return mock_exit(output="Log out: aborted.", error=logged_in_error, rc=1)
elif stdin and stdin.lower() == "y\n":
return mock_exit(output="Log out: complete.", error=logged_in_error, rc=0)
else:
return mock_exit(error='Error: aborted response', rc=1)
return mock_exit(error="Error: aborted response", rc=1)
if args.subparser_name == 'show':
if args.subparser_name == "show":
if self._mock_logged_out:
return mock_exit(error="Error: Could not find decryption key. Perhaps you need to login with `lpass login`.", rc=1)
return mock_exit(
error="Error: Could not find decryption key. Perhaps you need to login with `lpass login`.", rc=1
)
if self._mock_disconnected:
return mock_exit(error='Error: Couldn\'t resolve host name.', rc=1)
return mock_exit(error="Error: Couldn't resolve host name.", rc=1)
mock_entry = self._lookup_mock_entry(args.selector)
if args.field:
return mock_exit(output=mock_entry.get(args.field, ''))
return mock_exit(output=mock_entry.get(args.field, ""))
elif args.password:
return mock_exit(output=mock_entry.get('password', ''))
return mock_exit(output=mock_entry.get("password", ""))
elif args.username:
return mock_exit(output=mock_entry.get('username', ''))
return mock_exit(output=mock_entry.get("username", ""))
elif args.url:
return mock_exit(output=mock_entry.get('url', ''))
return mock_exit(output=mock_entry.get("url", ""))
elif args.name:
return mock_exit(output=mock_entry.get('name', ''))
return mock_exit(output=mock_entry.get("name", ""))
elif args.id:
return mock_exit(output=mock_entry.get('id', ''))
return mock_exit(output=mock_entry.get("id", ""))
elif args.notes:
return mock_exit(output=mock_entry.get('notes', ''))
return mock_exit(output=mock_entry.get("notes", ""))
raise LPassException('We should never get here')
raise LPassException("We should never get here")
class DisconnectedMockLPass(MockLPass):
_mock_disconnected = True
class LoggedOutMockLPass(MockLPass):
_mock_logged_out = True
class TestLPass(unittest.TestCase):
def setUp(self):
self.lookup = lookup_loader.get('community.general.lastpass')
self.lookup = lookup_loader.get("community.general.lastpass")
def test_lastpass_cli_path(self):
lp = MockLPass(path='/dev/null')
self.assertEqual('/dev/null', lp.cli_path)
lp = MockLPass(path="/dev/null")
self.assertEqual("/dev/null", lp.cli_path)
def test_lastpass_build_args_logout(self):
lp = MockLPass()
self.assertEqual(['logout', '--color=never'], lp._build_args("logout"))
self.assertEqual(["logout", "--color=never"], lp._build_args("logout"))
def test_lastpass_logged_in_true(self):
lp = MockLPass()
@@ -133,39 +135,37 @@ class TestLPass(unittest.TestCase):
lp = DisconnectedMockLPass()
with self.assertRaises(LPassException):
lp.get_field('0123456789', 'username')
lp.get_field("0123456789", "username")
def test_lastpass_show(self):
lp = MockLPass()
for entry in MOCK_ENTRIES:
entry_id = entry.get('id')
entry_id = entry.get("id")
for k, v in entry.items():
self.assertEqual(v.strip(), lp.get_field(entry_id, k))
class TestLastpassPlugin(unittest.TestCase):
def setUp(self):
self.lookup = lookup_loader.get('community.general.lastpass')
self.lookup = lookup_loader.get("community.general.lastpass")
@patch('ansible_collections.community.general.plugins.lookup.lastpass.LPass', new=MockLPass)
@patch("ansible_collections.community.general.plugins.lookup.lastpass.LPass", new=MockLPass)
def test_lastpass_plugin_normal(self):
for entry in MOCK_ENTRIES:
entry_id = entry.get('id')
entry_id = entry.get("id")
for k, v in entry.items():
self.assertEqual(v.strip(),
self.lookup.run([entry_id], field=k)[0])
self.assertEqual(v.strip(), self.lookup.run([entry_id], field=k)[0])
@patch('ansible_collections.community.general.plugins.lookup.lastpass.LPass', LoggedOutMockLPass)
@patch("ansible_collections.community.general.plugins.lookup.lastpass.LPass", LoggedOutMockLPass)
def test_lastpass_plugin_logged_out(self):
entry = MOCK_ENTRIES[0]
entry_id = entry.get('id')
entry_id = entry.get("id")
with self.assertRaises(AnsibleError):
self.lookup.run([entry_id], field='password')
self.lookup.run([entry_id], field="password")
@patch('ansible_collections.community.general.plugins.lookup.lastpass.LPass', DisconnectedMockLPass)
@patch("ansible_collections.community.general.plugins.lookup.lastpass.LPass", DisconnectedMockLPass)
def test_lastpass_plugin_disconnected(self):
entry = MOCK_ENTRIES[0]
entry_id = entry.get('id')
entry_id = entry.get("id")
with self.assertRaises(AnsibleError):
self.lookup.run([entry_id], field='password')
self.lookup.run([entry_id], field="password")

View File

@@ -18,7 +18,6 @@ from ansible_collections.community.general.plugins.lookup import merge_variables
class TestMergeVariablesLookup(unittest.TestCase):
class HostVarsMock(dict):
def __getattr__(self, item):
return super().__getitem__(item)
@@ -33,269 +32,241 @@ class TestMergeVariablesLookup(unittest.TestCase):
self.templar = Templar(loader=self.loader, variables={})
self.merge_vars_lookup = merge_variables.LookupModule(loader=self.loader, templar=self.templar)
@patch.object(AnsiblePlugin, 'set_options')
@patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'ignore', 'suffix', None])
@patch.object(Templar, 'template', side_effect=[['item1'], ['item3']])
@patch.object(AnsiblePlugin, "set_options")
@patch.object(AnsiblePlugin, "get_option", side_effect=[None, "ignore", "suffix", None])
@patch.object(Templar, "template", side_effect=[["item1"], ["item3"]])
def test_merge_list(self, mock_set_options, mock_get_option, mock_template):
results = self.merge_vars_lookup.run(['__merge_list'], {
'testlist1__merge_list': ['item1'],
'testlist2': ['item2'],
'testlist3__merge_list': ['item3']
})
results = self.merge_vars_lookup.run(
["__merge_list"],
{"testlist1__merge_list": ["item1"], "testlist2": ["item2"], "testlist3__merge_list": ["item3"]},
)
self.assertEqual(results, [['item1', 'item3']])
self.assertEqual(results, [["item1", "item3"]])
@patch.object(AnsiblePlugin, 'set_options')
@patch.object(AnsiblePlugin, 'get_option', side_effect=[['initial_item'], 'ignore', 'suffix', None])
@patch.object(Templar, 'template', side_effect=[['item1'], ['item3']])
@patch.object(AnsiblePlugin, "set_options")
@patch.object(AnsiblePlugin, "get_option", side_effect=[["initial_item"], "ignore", "suffix", None])
@patch.object(Templar, "template", side_effect=[["item1"], ["item3"]])
def test_merge_list_with_initial_value(self, mock_set_options, mock_get_option, mock_template):
results = self.merge_vars_lookup.run(['__merge_list'], {
'testlist1__merge_list': ['item1'],
'testlist2': ['item2'],
'testlist3__merge_list': ['item3']
})
results = self.merge_vars_lookup.run(
["__merge_list"],
{"testlist1__merge_list": ["item1"], "testlist2": ["item2"], "testlist3__merge_list": ["item3"]},
)
self.assertEqual(results, [['initial_item', 'item1', 'item3']])
self.assertEqual(results, [["initial_item", "item1", "item3"]])
@patch.object(AnsiblePlugin, 'set_options')
@patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'ignore', 'suffix', None])
@patch.object(Templar, 'template', side_effect=[{'item1': 'test', 'list_item': ['test1']},
{'item2': 'test', 'list_item': ['test2']}])
@patch.object(AnsiblePlugin, "set_options")
@patch.object(AnsiblePlugin, "get_option", side_effect=[None, "ignore", "suffix", None])
@patch.object(
Templar,
"template",
side_effect=[{"item1": "test", "list_item": ["test1"]}, {"item2": "test", "list_item": ["test2"]}],
)
def test_merge_dict(self, mock_set_options, mock_get_option, mock_template):
results = self.merge_vars_lookup.run(['__merge_dict'], {
'testdict1__merge_dict': {
'item1': 'test',
'list_item': ['test1']
},
'testdict2__merge_dict': {
'item2': 'test',
'list_item': ['test2']
}
})
self.assertEqual(results, [
results = self.merge_vars_lookup.run(
["__merge_dict"],
{
'item1': 'test',
'item2': 'test',
'list_item': ['test1', 'test2']
}
])
"testdict1__merge_dict": {"item1": "test", "list_item": ["test1"]},
"testdict2__merge_dict": {"item2": "test", "list_item": ["test2"]},
},
)
@patch.object(AnsiblePlugin, 'set_options')
@patch.object(AnsiblePlugin, 'get_option', side_effect=[{'initial_item': 'random value', 'list_item': ['test0']},
'ignore', 'suffix', None])
@patch.object(Templar, 'template', side_effect=[{'item1': 'test', 'list_item': ['test1']},
{'item2': 'test', 'list_item': ['test2']}])
self.assertEqual(results, [{"item1": "test", "item2": "test", "list_item": ["test1", "test2"]}])
@patch.object(AnsiblePlugin, "set_options")
@patch.object(
AnsiblePlugin,
"get_option",
side_effect=[{"initial_item": "random value", "list_item": ["test0"]}, "ignore", "suffix", None],
)
@patch.object(
Templar,
"template",
side_effect=[{"item1": "test", "list_item": ["test1"]}, {"item2": "test", "list_item": ["test2"]}],
)
def test_merge_dict_with_initial_value(self, mock_set_options, mock_get_option, mock_template):
results = self.merge_vars_lookup.run(['__merge_dict'], {
'testdict1__merge_dict': {
'item1': 'test',
'list_item': ['test1']
},
'testdict2__merge_dict': {
'item2': 'test',
'list_item': ['test2']
}
})
self.assertEqual(results, [
results = self.merge_vars_lookup.run(
["__merge_dict"],
{
'initial_item': 'random value',
'item1': 'test',
'item2': 'test',
'list_item': ['test0', 'test1', 'test2']
}
])
"testdict1__merge_dict": {"item1": "test", "list_item": ["test1"]},
"testdict2__merge_dict": {"item2": "test", "list_item": ["test2"]},
},
)
@patch.object(AnsiblePlugin, 'set_options')
@patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'warn', 'suffix', None])
@patch.object(Templar, 'template', side_effect=[{'item': 'value1'}, {'item': 'value2'}])
@patch.object(Display, 'warning')
self.assertEqual(
results,
[
{
"initial_item": "random value",
"item1": "test",
"item2": "test",
"list_item": ["test0", "test1", "test2"],
}
],
)
@patch.object(AnsiblePlugin, "set_options")
@patch.object(AnsiblePlugin, "get_option", side_effect=[None, "warn", "suffix", None])
@patch.object(Templar, "template", side_effect=[{"item": "value1"}, {"item": "value2"}])
@patch.object(Display, "warning")
def test_merge_dict_non_unique_warning(self, mock_set_options, mock_get_option, mock_template, mock_display):
results = self.merge_vars_lookup.run(['__merge_non_unique'], {
'testdict1__merge_non_unique': {'item': 'value1'},
'testdict2__merge_non_unique': {'item': 'value2'}
})
results = self.merge_vars_lookup.run(
["__merge_non_unique"],
{"testdict1__merge_non_unique": {"item": "value1"}, "testdict2__merge_non_unique": {"item": "value2"}},
)
self.assertTrue(mock_display.called)
self.assertEqual(results, [{'item': 'value2'}])
self.assertEqual(results, [{"item": "value2"}])
@patch.object(AnsiblePlugin, 'set_options')
@patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'error', 'suffix', None])
@patch.object(Templar, 'template', side_effect=[{'item': 'value1'}, {'item': 'value2'}])
@patch.object(AnsiblePlugin, "set_options")
@patch.object(AnsiblePlugin, "get_option", side_effect=[None, "error", "suffix", None])
@patch.object(Templar, "template", side_effect=[{"item": "value1"}, {"item": "value2"}])
def test_merge_dict_non_unique_error(self, mock_set_options, mock_get_option, mock_template):
with self.assertRaises(AnsibleError):
self.merge_vars_lookup.run(['__merge_non_unique'], {
'testdict1__merge_non_unique': {'item': 'value1'},
'testdict2__merge_non_unique': {'item': 'value2'}
})
self.merge_vars_lookup.run(
["__merge_non_unique"],
{"testdict1__merge_non_unique": {"item": "value1"}, "testdict2__merge_non_unique": {"item": "value2"}},
)
@patch.object(AnsiblePlugin, 'set_options')
@patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'ignore', 'suffix', None])
@patch.object(Templar, 'template', side_effect=[{'item1': 'test', 'list_item': ['test1']},
['item2', 'item3']])
@patch.object(AnsiblePlugin, "set_options")
@patch.object(AnsiblePlugin, "get_option", side_effect=[None, "ignore", "suffix", None])
@patch.object(Templar, "template", side_effect=[{"item1": "test", "list_item": ["test1"]}, ["item2", "item3"]])
def test_merge_list_and_dict(self, mock_set_options, mock_get_option, mock_template):
with self.assertRaises(AnsibleError):
self.merge_vars_lookup.run(['__merge_var'], {
'testlist__merge_var': {
'item1': 'test',
'list_item': ['test1']
self.merge_vars_lookup.run(
["__merge_var"],
{
"testlist__merge_var": {"item1": "test", "list_item": ["test1"]},
"testdict__merge_var": ["item2", "item3"],
},
'testdict__merge_var': ['item2', 'item3']
})
)
@patch.object(AnsiblePlugin, 'set_options')
@patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'ignore', 'suffix', ['all']])
@patch.object(Templar, 'template', side_effect=[
{'var': [{'item1': 'value1', 'item2': 'value2'}]},
{'var': [{'item5': 'value5', 'item6': 'value6'}]},
])
@patch.object(AnsiblePlugin, "set_options")
@patch.object(AnsiblePlugin, "get_option", side_effect=[None, "ignore", "suffix", ["all"]])
@patch.object(
Templar,
"template",
side_effect=[
{"var": [{"item1": "value1", "item2": "value2"}]},
{"var": [{"item5": "value5", "item6": "value6"}]},
],
)
def test_merge_dict_group_all(self, mock_set_options, mock_get_option, mock_template):
hostvars = self.HostVarsMock({
'host1': {
'group_names': ['dummy1'],
'inventory_hostname': 'host1',
'1testlist__merge_var': {
'var': [{'item1': 'value1', 'item2': 'value2'}]
}
},
'host2': {
'group_names': ['dummy1'],
'inventory_hostname': 'host2',
'2otherlist__merge_var': {
'var': [{'item5': 'value5', 'item6': 'value6'}]
}
hostvars = self.HostVarsMock(
{
"host1": {
"group_names": ["dummy1"],
"inventory_hostname": "host1",
"1testlist__merge_var": {"var": [{"item1": "value1", "item2": "value2"}]},
},
"host2": {
"group_names": ["dummy1"],
"inventory_hostname": "host2",
"2otherlist__merge_var": {"var": [{"item5": "value5", "item6": "value6"}]},
},
}
})
variables = {
'inventory_hostname': 'host1',
'hostvars': hostvars
}
)
variables = {"inventory_hostname": "host1", "hostvars": hostvars}
results = self.merge_vars_lookup.run(['__merge_var'], variables)
results = self.merge_vars_lookup.run(["__merge_var"], variables)
self.assertEqual(results, [
{'var': [
{'item1': 'value1', 'item2': 'value2'},
{'item5': 'value5', 'item6': 'value6'}
]}
])
self.assertEqual(
results, [{"var": [{"item1": "value1", "item2": "value2"}, {"item5": "value5", "item6": "value6"}]}]
)
@patch.object(AnsiblePlugin, 'set_options')
@patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'ignore', 'suffix', ['dummy1']])
@patch.object(Templar, 'template', side_effect=[
{'var': [{'item1': 'value1', 'item2': 'value2'}]},
{'var': [{'item5': 'value5', 'item6': 'value6'}]},
])
@patch.object(AnsiblePlugin, "set_options")
@patch.object(AnsiblePlugin, "get_option", side_effect=[None, "ignore", "suffix", ["dummy1"]])
@patch.object(
Templar,
"template",
side_effect=[
{"var": [{"item1": "value1", "item2": "value2"}]},
{"var": [{"item5": "value5", "item6": "value6"}]},
],
)
def test_merge_dict_group_single(self, mock_set_options, mock_get_option, mock_template):
hostvars = self.HostVarsMock({
'host1': {
'group_names': ['dummy1'],
'inventory_hostname': 'host1',
'1testlist__merge_var': {
'var': [{'item1': 'value1', 'item2': 'value2'}]
}
},
'host2': {
'group_names': ['dummy1'],
'inventory_hostname': 'host2',
'2otherlist__merge_var': {
'var': [{'item5': 'value5', 'item6': 'value6'}]
}
},
'host3': {
'group_names': ['dummy2'],
'inventory_hostname': 'host3',
'3otherlist__merge_var': {
'var': [{'item3': 'value3', 'item4': 'value4'}]
}
hostvars = self.HostVarsMock(
{
"host1": {
"group_names": ["dummy1"],
"inventory_hostname": "host1",
"1testlist__merge_var": {"var": [{"item1": "value1", "item2": "value2"}]},
},
"host2": {
"group_names": ["dummy1"],
"inventory_hostname": "host2",
"2otherlist__merge_var": {"var": [{"item5": "value5", "item6": "value6"}]},
},
"host3": {
"group_names": ["dummy2"],
"inventory_hostname": "host3",
"3otherlist__merge_var": {"var": [{"item3": "value3", "item4": "value4"}]},
},
}
})
variables = {
'inventory_hostname': 'host1',
'hostvars': hostvars
}
)
variables = {"inventory_hostname": "host1", "hostvars": hostvars}
results = self.merge_vars_lookup.run(['__merge_var'], variables)
results = self.merge_vars_lookup.run(["__merge_var"], variables)
self.assertEqual(results, [
{'var': [
{'item1': 'value1', 'item2': 'value2'},
{'item5': 'value5', 'item6': 'value6'}
]}
])
self.assertEqual(
results, [{"var": [{"item1": "value1", "item2": "value2"}, {"item5": "value5", "item6": "value6"}]}]
)
@patch.object(AnsiblePlugin, 'set_options')
@patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'ignore', 'suffix', ['dummy1', 'dummy2']])
@patch.object(Templar, 'template', side_effect=[
{'var': [{'item1': 'value1', 'item2': 'value2'}]},
{'var': [{'item5': 'value5', 'item6': 'value6'}]},
])
@patch.object(AnsiblePlugin, "set_options")
@patch.object(AnsiblePlugin, "get_option", side_effect=[None, "ignore", "suffix", ["dummy1", "dummy2"]])
@patch.object(
Templar,
"template",
side_effect=[
{"var": [{"item1": "value1", "item2": "value2"}]},
{"var": [{"item5": "value5", "item6": "value6"}]},
],
)
def test_merge_dict_group_multiple(self, mock_set_options, mock_get_option, mock_template):
hostvars = self.HostVarsMock({
'host1': {
'group_names': ['dummy1'],
'inventory_hostname': 'host1',
'1testlist__merge_var': {
'var': [{'item1': 'value1', 'item2': 'value2'}]
}
},
'host2': {
'group_names': ['dummy2'],
'inventory_hostname': 'host2',
'2otherlist__merge_var': {
'var': [{'item5': 'value5', 'item6': 'value6'}]
}
},
'host3': {
'group_names': ['dummy3'],
'inventory_hostname': 'host3',
'3otherlist__merge_var': {
'var': [{'item3': 'value3', 'item4': 'value4'}]
}
hostvars = self.HostVarsMock(
{
"host1": {
"group_names": ["dummy1"],
"inventory_hostname": "host1",
"1testlist__merge_var": {"var": [{"item1": "value1", "item2": "value2"}]},
},
"host2": {
"group_names": ["dummy2"],
"inventory_hostname": "host2",
"2otherlist__merge_var": {"var": [{"item5": "value5", "item6": "value6"}]},
},
"host3": {
"group_names": ["dummy3"],
"inventory_hostname": "host3",
"3otherlist__merge_var": {"var": [{"item3": "value3", "item4": "value4"}]},
},
}
})
variables = {
'inventory_hostname': 'host1',
'hostvars': hostvars
}
results = self.merge_vars_lookup.run(['__merge_var'], variables)
)
variables = {"inventory_hostname": "host1", "hostvars": hostvars}
results = self.merge_vars_lookup.run(["__merge_var"], variables)
self.assertEqual(results, [
{'var': [
{'item1': 'value1', 'item2': 'value2'},
{'item5': 'value5', 'item6': 'value6'}
]}
])
self.assertEqual(
results, [{"var": [{"item1": "value1", "item2": "value2"}, {"item5": "value5", "item6": "value6"}]}]
)
@patch.object(AnsiblePlugin, 'set_options')
@patch.object(AnsiblePlugin, 'get_option', side_effect=[None, 'ignore', 'suffix', ['dummy1', 'dummy2']])
@patch.object(Templar, 'template', side_effect=[
['item1'],
['item5'],
])
@patch.object(AnsiblePlugin, "set_options")
@patch.object(AnsiblePlugin, "get_option", side_effect=[None, "ignore", "suffix", ["dummy1", "dummy2"]])
@patch.object(
Templar,
"template",
side_effect=[
["item1"],
["item5"],
],
)
def test_merge_list_group_multiple(self, mock_set_options, mock_get_option, mock_template):
hostvars = self.HostVarsMock({
'host1': {
'group_names': ['dummy1'],
'inventory_hostname': 'host1',
'1testlist__merge_var': ['item1']
},
'host2': {
'group_names': ['dummy2'],
'inventory_hostname': 'host2',
'2otherlist__merge_var': ['item5']
},
'host3': {
'group_names': ['dummy3'],
'inventory_hostname': 'host3',
'3otherlist__merge_var': ['item3']
hostvars = self.HostVarsMock(
{
"host1": {"group_names": ["dummy1"], "inventory_hostname": "host1", "1testlist__merge_var": ["item1"]},
"host2": {"group_names": ["dummy2"], "inventory_hostname": "host2", "2otherlist__merge_var": ["item5"]},
"host3": {"group_names": ["dummy3"], "inventory_hostname": "host3", "3otherlist__merge_var": ["item3"]},
}
})
variables = {
'inventory_hostname': 'host1',
'hostvars': hostvars
}
results = self.merge_vars_lookup.run(['__merge_var'], variables)
)
variables = {"inventory_hostname": "host1", "hostvars": hostvars}
results = self.merge_vars_lookup.run(["__merge_var"], variables)
self.assertEqual(results, [['item1', 'item5']])
self.assertEqual(results, [["item1", "item5"]])

View File

@@ -19,19 +19,34 @@ from ansible_collections.community.general.plugins.lookup.onepassword import (
)
OP_VERSION_FIXTURES = [
"opv1",
"opv2"
]
OP_VERSION_FIXTURES = ["opv1", "opv2"]
@pytest.mark.parametrize(
("args", "rc", "expected_call_args", "expected_call_kwargs", "expected"),
(
([], 0, ["get", "account"], {"ignore_errors": True}, True,),
([], 1, ["get", "account"], {"ignore_errors": True}, False,),
(["acme"], 1, ["get", "account", "--account", "acme.1password.com"], {"ignore_errors": True}, False,),
)
(
[],
0,
["get", "account"],
{"ignore_errors": True},
True,
),
(
[],
1,
["get", "account"],
{"ignore_errors": True},
False,
),
(
["acme"],
1,
["get", "account", "--account", "acme.1password.com"],
{"ignore_errors": True},
False,
),
),
)
def test_assert_logged_in_v1(mocker, args, rc, expected_call_args, expected_call_kwargs, expected):
mocker.patch.object(OnePassCLIv1, "_run", return_value=[rc, "", ""])
@@ -54,23 +69,44 @@ def test_full_signin_v1(mocker):
)
result = op_cli.full_signin()
op_cli._run.assert_called_with([
"signin",
"acme.1password.com",
b"bob@acme.com",
b"SECRET",
"--raw",
], command_input=b"ONEKEYTORULETHEMALL")
op_cli._run.assert_called_with(
[
"signin",
"acme.1password.com",
b"bob@acme.com",
b"SECRET",
"--raw",
],
command_input=b"ONEKEYTORULETHEMALL",
)
assert result == [0, "", ""]
@pytest.mark.parametrize(
("args", "out", "expected_call_args", "expected_call_kwargs", "expected"),
(
([], "list of accounts", ["account", "get"], {"ignore_errors": True}, True,),
(["acme"], "list of accounts", ["account", "get", "--account", "acme.1password.com"], {"ignore_errors": True}, True,),
([], "", ["account", "list"], {}, False,),
)
(
[],
"list of accounts",
["account", "get"],
{"ignore_errors": True},
True,
),
(
["acme"],
"list of accounts",
["account", "get", "--account", "acme.1password.com"],
{"ignore_errors": True},
True,
),
(
[],
"",
["account", "list"],
{},
False,
),
),
)
def test_assert_logged_in_v2(mocker, args, out, expected_call_args, expected_call_kwargs, expected):
mocker.patch.object(OnePassCLIv2, "_run", return_value=[0, out, ""])
@@ -100,13 +136,17 @@ def test_full_signin_v2(mocker):
op_cli._run.assert_called_with(
[
"account", "add", "--raw",
"--address", "acme.1password.com",
"--email", b"bob@acme.com",
"account",
"add",
"--raw",
"--address",
"acme.1password.com",
"--email",
b"bob@acme.com",
"--signin",
],
command_input=b"ONEKEYTORULETHEMALL",
environment_update={'OP_SECRET_KEY': 'SECRET'},
environment_update={"OP_SECRET_KEY": "SECRET"},
)
assert result == [0, "", ""]
@@ -116,7 +156,7 @@ def test_full_signin_v2(mocker):
(
("1.17.2", OnePassCLIv1),
("2.27.4", OnePassCLIv2),
)
),
)
def test_op_correct_cli_class(fake_op, version, version_class):
op = fake_op(version)
@@ -146,12 +186,11 @@ def test_op_set_token_with_config(op_fixture, mocker, request):
[
(op, value)
for op in OP_VERSION_FIXTURES
for value in
(
for value in (
"Missing required parameters",
"The operation is unauthorized",
)
]
],
)
def test_op_set_token_with_config_missing_args(op_fixture, message, request, mocker):
op = request.getfixturevalue(op_fixture)
@@ -169,7 +208,9 @@ def test_op_set_token_with_config_missing_args(op_fixture, message, request, moc
def test_op_set_token_with_config_full_signin(op_fixture, request, mocker):
op = request.getfixturevalue(op_fixture)
mocker.patch("os.path.isfile", return_value=True)
mocker.patch.object(op._cli, "signin", return_value=(99, "", ""), side_effect=AnsibleLookupError("Raised intentionally"))
mocker.patch.object(
op._cli, "signin", return_value=(99, "", ""), side_effect=AnsibleLookupError("Raised intentionally")
)
mocker.patch.object(op._cli, "full_signin", return_value=(0, "", ""))
op.set_token()
@@ -192,8 +233,7 @@ def test_op_set_token_without_config(op_fixture, request, mocker):
@pytest.mark.parametrize(
("op_fixture", "login_status"),
[(op, value) for op in OP_VERSION_FIXTURES for value in [False, True]]
("op_fixture", "login_status"), [(op, value) for op in OP_VERSION_FIXTURES for value in [False, True]]
)
def test_op_assert_logged_in(mocker, login_status, op_fixture, request):
op = request.getfixturevalue(op_fixture)
@@ -230,7 +270,7 @@ def test_op_get_raw_v1(mocker, op_fixture, request):
(None, ""),
("", ""),
]
)
),
)
def test_op_get_field(mocker, op_fixture, output, expected, request):
op = request.getfixturevalue(op_fixture)
@@ -251,12 +291,17 @@ def test_op_get_field(mocker, op_fixture, output, expected, request):
(_cli_class, item["vault_name"], item["queries"], item.get("kwargs", {}), item["output"], item["expected"])
for _cli_class in sorted(MOCK_ENTRIES, key=operator.attrgetter("__name__"))
for item in MOCK_ENTRIES[_cli_class]
)
),
)
def test_op_lookup(mocker, cli_class, vault, queries, kwargs, output, expected):
mocker.patch("ansible_collections.community.general.plugins.lookup.onepassword.OnePass._get_cli_class", cli_class)
mocker.patch("ansible_collections.community.general.plugins.lookup.onepassword.OnePass.assert_logged_in", return_value=True)
mocker.patch("ansible_collections.community.general.plugins.lookup.onepassword.OnePassCLIBase._run", return_value=(0, json.dumps(output), ""))
mocker.patch(
"ansible_collections.community.general.plugins.lookup.onepassword.OnePass.assert_logged_in", return_value=True
)
mocker.patch(
"ansible_collections.community.general.plugins.lookup.onepassword.OnePassCLIBase._run",
return_value=(0, json.dumps(output), ""),
)
op_lookup = lookup_loader.get("community.general.onepassword")
result = op_lookup.run(queries, vault=vault, **kwargs)
@@ -269,14 +314,19 @@ def test_signin(op_fixture, request):
op = request.getfixturevalue(op_fixture)
op._cli.master_password = "master_pass"
op._cli.signin()
op._cli._run.assert_called_once_with(['signin', '--raw'], command_input=b"master_pass")
op._cli._run.assert_called_once_with(["signin", "--raw"], command_input=b"master_pass")
def test_op_doc(mocker):
document_contents = "Document Contents\n"
mocker.patch("ansible_collections.community.general.plugins.lookup.onepassword.OnePass.assert_logged_in", return_value=True)
mocker.patch("ansible_collections.community.general.plugins.lookup.onepassword.OnePassCLIBase._run", return_value=(0, document_contents, ""))
mocker.patch(
"ansible_collections.community.general.plugins.lookup.onepassword.OnePass.assert_logged_in", return_value=True
)
mocker.patch(
"ansible_collections.community.general.plugins.lookup.onepassword.OnePassCLIBase._run",
return_value=(0, document_contents, ""),
)
op_lookup = lookup_loader.get("community.general.onepassword_doc")
result = op_lookup.run(["Private key doc"])
@@ -289,17 +339,18 @@ def test_op_doc(mocker):
[
(plugin, connect_host, connect_token)
for plugin in ("community.general.onepassword", "community.general.onepassword_raw")
for (connect_host, connect_token) in
(
for (connect_host, connect_token) in (
("http://localhost", None),
(None, "foobar"),
)
]
],
)
def test_op_connect_partial_args(plugin, connect_host, connect_token, mocker):
op_lookup = lookup_loader.get(plugin)
mocker.patch("ansible_collections.community.general.plugins.lookup.onepassword.OnePass._get_cli_class", OnePassCLIv2)
mocker.patch(
"ansible_collections.community.general.plugins.lookup.onepassword.OnePass._get_cli_class", OnePassCLIv2
)
with pytest.raises(AnsibleOptionsError):
op_lookup.run("login", vault_name="test vault", connect_host=connect_host, connect_token=connect_token)
@@ -310,7 +361,7 @@ def test_op_connect_partial_args(plugin, connect_host, connect_token, mocker):
(
{"connect_host": "http://localhost", "connect_token": "foobar"},
{"service_account_token": "foobar"},
)
),
)
def test_opv1_unsupported_features(kwargs):
op_cli = OnePassCLIv1(**kwargs)

View File

@@ -17,11 +17,16 @@ from ansible.plugins.loader import lookup_loader
(
(item["vault_name"], item["queries"], item.get("kwargs", {}), item["output"], item["expected"])
for item in SSH_KEY_MOCK_ENTRIES
)
),
)
def test_ssh_key(mocker, vault, queries, kwargs, output, expected):
mocker.patch("ansible_collections.community.general.plugins.lookup.onepassword.OnePass.assert_logged_in", return_value=True)
mocker.patch("ansible_collections.community.general.plugins.lookup.onepassword.OnePassCLIBase._run", return_value=(0, json.dumps(output), ""))
mocker.patch(
"ansible_collections.community.general.plugins.lookup.onepassword.OnePass.assert_logged_in", return_value=True
)
mocker.patch(
"ansible_collections.community.general.plugins.lookup.onepassword.OnePassCLIBase._run",
return_value=(0, json.dumps(output), ""),
)
op_lookup = lookup_loader.get("community.general.onepassword_ssh_key")
result = op_lookup.run(queries, vault=vault, **kwargs)

View File

@@ -14,7 +14,7 @@ from ansible.plugins.loader import lookup_loader
class MockPamSecrets(MagicMock):
RESPONSE = 'dummy value'
RESPONSE = "dummy value"
def get_pam_secret(self, path):
return self.RESPONSE
@@ -30,13 +30,7 @@ class TestLookupModule(TestCase):
MockPamSecrets(),
)
def test_get_pam_secret(self):
terms = ['dummy secret']
terms = ["dummy secret"]
variables = []
kwargs = {
"base_url": 'https://dummy.url',
"api_key": 'dummy'
}
self.assertListEqual(
[{'dummy secret': 'dummy value'}],
self.lookup.run(terms, variables, **kwargs)
)
kwargs = {"base_url": "https://dummy.url", "api_key": "dummy"}
self.assertListEqual([{"dummy secret": "dummy value"}], self.lookup.run(terms, variables, **kwargs))

View File

@@ -16,7 +16,7 @@ from ansible_collections.community.general.plugins.lookup import tss
from ansible.plugins.loader import lookup_loader
TSS_IMPORT_PATH = 'ansible_collections.community.general.plugins.lookup.tss'
TSS_IMPORT_PATH = "ansible_collections.community.general.plugins.lookup.tss"
def make_absolute(name):
@@ -25,7 +25,7 @@ def make_absolute(name):
class SecretServerError(Exception):
def __init__(self):
self.message = ''
self.message = ""
class MockSecretServer(MagicMock):
@@ -40,41 +40,39 @@ class MockFaultySecretServer(MagicMock):
raise SecretServerError
@patch(make_absolute('SecretServer'), MockSecretServer())
@patch(make_absolute("SecretServer"), MockSecretServer())
class TestTSSClient(TestCase):
def setUp(self):
self.server_params = {
'base_url': '',
'username': '',
'domain': '',
'password': '',
'api_path_uri': '',
'token_path_uri': '',
"base_url": "",
"username": "",
"domain": "",
"password": "",
"api_path_uri": "",
"token_path_uri": "",
}
def test_from_params(self):
with patch(make_absolute('HAS_TSS_AUTHORIZER'), False):
self.assert_client_version('v0')
with patch(make_absolute("HAS_TSS_AUTHORIZER"), False):
self.assert_client_version("v0")
with patch.dict(self.server_params, {'domain': 'foo'}):
with patch.dict(self.server_params, {"domain": "foo"}):
with self.assertRaises(tss.AnsibleError):
self._get_client()
with patch.multiple(TSS_IMPORT_PATH,
HAS_TSS_AUTHORIZER=True,
PasswordGrantAuthorizer=DEFAULT,
DomainPasswordGrantAuthorizer=DEFAULT):
with patch.multiple(
TSS_IMPORT_PATH,
HAS_TSS_AUTHORIZER=True,
PasswordGrantAuthorizer=DEFAULT,
DomainPasswordGrantAuthorizer=DEFAULT,
):
self.assert_client_version("v1")
self.assert_client_version('v1')
with patch.dict(self.server_params, {'domain': 'foo'}):
self.assert_client_version('v1')
with patch.dict(self.server_params, {"domain": "foo"}):
self.assert_client_version("v1")
def assert_client_version(self, version):
version_to_class = {
'v0': tss.TSSClientV0,
'v1': tss.TSSClientV1
}
version_to_class = {"v0": tss.TSSClientV0, "v1": tss.TSSClientV1}
client = self._get_client()
self.assertIsInstance(client, version_to_class[version])
@@ -85,29 +83,25 @@ class TestTSSClient(TestCase):
class TestLookupModule(TestCase):
VALID_TERMS = [1]
INVALID_TERMS = ['foo']
INVALID_TERMS = ["foo"]
def setUp(self):
self.lookup = lookup_loader.get("community.general.tss")
@patch.multiple(TSS_IMPORT_PATH,
HAS_TSS_SDK=False,
SecretServer=MockSecretServer)
@patch.multiple(TSS_IMPORT_PATH, HAS_TSS_SDK=False, SecretServer=MockSecretServer)
def test_missing_sdk(self):
with self.assertRaises(tss.AnsibleError):
self._run_lookup(self.VALID_TERMS)
@patch.multiple(TSS_IMPORT_PATH,
HAS_TSS_SDK=True,
SecretServerError=SecretServerError)
@patch.multiple(TSS_IMPORT_PATH, HAS_TSS_SDK=True, SecretServerError=SecretServerError)
def test_get_secret_json(self):
with patch(make_absolute('SecretServer'), MockSecretServer):
with patch(make_absolute("SecretServer"), MockSecretServer):
self.assertListEqual([MockSecretServer.RESPONSE], self._run_lookup(self.VALID_TERMS))
with self.assertRaises(tss.AnsibleOptionsError):
self._run_lookup(self.INVALID_TERMS)
with patch(make_absolute('SecretServer'), MockFaultySecretServer):
with patch(make_absolute("SecretServer"), MockFaultySecretServer):
with self.assertRaises(tss.AnsibleError):
self._run_lookup(self.VALID_TERMS)

View File

@@ -7,15 +7,14 @@ from __future__ import annotations
import random
import unittest
from ansible_collections.community.general.plugins.module_utils.cloud import _exponential_backoff, \
_full_jitter_backoff
from ansible_collections.community.general.plugins.module_utils.cloud import _exponential_backoff, _full_jitter_backoff
class ExponentialBackoffStrategyTestCase(unittest.TestCase):
def test_no_retries(self):
strategy = _exponential_backoff(retries=0)
result = list(strategy())
self.assertEqual(result, [], 'list should be empty')
self.assertEqual(result, [], "list should be empty")
def test_exponential_backoff(self):
strategy = _exponential_backoff(retries=5, delay=1, backoff=2)
@@ -37,7 +36,7 @@ class FullJitterBackoffStrategyTestCase(unittest.TestCase):
def test_no_retries(self):
strategy = _full_jitter_backoff(retries=0)
result = list(strategy())
self.assertEqual(result, [], 'list should be empty')
self.assertEqual(result, [], "list should be empty")
def test_full_jitter(self):
retries = 5
@@ -46,8 +45,7 @@ class FullJitterBackoffStrategyTestCase(unittest.TestCase):
r = random.Random(seed)
expected = [r.randint(0, 2**i) for i in range(0, retries)]
strategy = _full_jitter_backoff(
retries=retries, delay=1, _random=random.Random(seed))
strategy = _full_jitter_backoff(retries=retries, delay=1, _random=random.Random(seed))
result = list(strategy())
self.assertEqual(result, expected)

View File

@@ -11,48 +11,48 @@ from ansible_collections.community.general.plugins.module_utils.scaleway import
class SecretVariablesTestCase(unittest.TestCase):
def test_dict_to_list(self):
source = dict(
attribute1="value1",
attribute2="value2"
)
expect = [
dict(key="attribute1", value="value1"),
dict(key="attribute2", value="value2")
]
source = dict(attribute1="value1", attribute2="value2")
expect = [dict(key="attribute1", value="value1"), dict(key="attribute2", value="value2")]
result = SecretVariables.dict_to_list(source)
result = sorted(result, key=lambda el: el['key'])
result = sorted(result, key=lambda el: el["key"])
self.assertEqual(result, expect)
def test_list_to_dict(self):
source = [
dict(key="secret1", hashed_value="$argon2id$v=19$m=65536,t=1,p=2$NuZk+6UATHNFV78nFRXFvA$3kivcXfzNHI1c/4ZBpP8BeBSGhhI82NfOh4Dd48JJgc"),
dict(key="secret2", hashed_value="$argon2id$v=19$m=65536,t=1,p=2$etGO/Z8ImYDeKr6uFsyPAQ$FbL5+hG/duDEpa8UCYqXpEUQ5EacKg6i2iAs+Dq4dAI")
dict(
key="secret1",
hashed_value="$argon2id$v=19$m=65536,t=1,p=2$NuZk+6UATHNFV78nFRXFvA$3kivcXfzNHI1c/4ZBpP8BeBSGhhI82NfOh4Dd48JJgc",
),
dict(
key="secret2",
hashed_value="$argon2id$v=19$m=65536,t=1,p=2$etGO/Z8ImYDeKr6uFsyPAQ$FbL5+hG/duDEpa8UCYqXpEUQ5EacKg6i2iAs+Dq4dAI",
),
]
expect = dict(
secret1="$argon2id$v=19$m=65536,t=1,p=2$NuZk+6UATHNFV78nFRXFvA$3kivcXfzNHI1c/4ZBpP8BeBSGhhI82NfOh4Dd48JJgc",
secret2="$argon2id$v=19$m=65536,t=1,p=2$etGO/Z8ImYDeKr6uFsyPAQ$FbL5+hG/duDEpa8UCYqXpEUQ5EacKg6i2iAs+Dq4dAI"
secret2="$argon2id$v=19$m=65536,t=1,p=2$etGO/Z8ImYDeKr6uFsyPAQ$FbL5+hG/duDEpa8UCYqXpEUQ5EacKg6i2iAs+Dq4dAI",
)
self.assertEqual(SecretVariables.list_to_dict(source, hashed=True), expect)
def test_list_to_dict_2(self):
source = [
dict(key="secret1", value="value1"),
dict(key="secret2", value="value2")
]
expect = dict(
secret1="value1",
secret2="value2"
)
source = [dict(key="secret1", value="value1"), dict(key="secret2", value="value2")]
expect = dict(secret1="value1", secret2="value2")
self.assertEqual(SecretVariables.list_to_dict(source, hashed=False), expect)
@unittest.skipIf(argon2 is None, "Missing required 'argon2' library")
def test_decode_full(self):
source_secret = [
dict(key="secret1", hashed_value="$argon2id$v=19$m=65536,t=1,p=2$NuZk+6UATHNFV78nFRXFvA$3kivcXfzNHI1c/4ZBpP8BeBSGhhI82NfOh4Dd48JJgc"),
dict(key="secret2", hashed_value="$argon2id$v=19$m=65536,t=1,p=2$etGO/Z8ImYDeKr6uFsyPAQ$FbL5+hG/duDEpa8UCYqXpEUQ5EacKg6i2iAs+Dq4dAI"),
dict(
key="secret1",
hashed_value="$argon2id$v=19$m=65536,t=1,p=2$NuZk+6UATHNFV78nFRXFvA$3kivcXfzNHI1c/4ZBpP8BeBSGhhI82NfOh4Dd48JJgc",
),
dict(
key="secret2",
hashed_value="$argon2id$v=19$m=65536,t=1,p=2$etGO/Z8ImYDeKr6uFsyPAQ$FbL5+hG/duDEpa8UCYqXpEUQ5EacKg6i2iAs+Dq4dAI",
),
]
source_value = [
dict(key="secret1", value="value1"),
@@ -65,14 +65,20 @@ class SecretVariablesTestCase(unittest.TestCase):
]
result = SecretVariables.decode(source_secret, source_value)
result = sorted(result, key=lambda el: el['key'])
result = sorted(result, key=lambda el: el["key"])
self.assertEqual(result, expect)
@unittest.skipIf(argon2 is None, "Missing required 'argon2' library")
def test_decode_dict_divergent_values(self):
source_secret = [
dict(key="secret1", hashed_value="$argon2id$v=19$m=65536,t=1,p=2$NuZk+6UATHNFV78nFRXFvA$3kivcXfzNHI1c/4ZBpP8BeBSGhhI82NfOh4Dd48JJgc"),
dict(key="secret2", hashed_value="$argon2id$v=19$m=65536,t=1,p=2$etGO/Z8ImYDeKr6uFsyPAQ$FbL5+hG/duDEpa8UCYqXpEUQ5EacKg6i2iAs+Dq4dAI"),
dict(
key="secret1",
hashed_value="$argon2id$v=19$m=65536,t=1,p=2$NuZk+6UATHNFV78nFRXFvA$3kivcXfzNHI1c/4ZBpP8BeBSGhhI82NfOh4Dd48JJgc",
),
dict(
key="secret2",
hashed_value="$argon2id$v=19$m=65536,t=1,p=2$etGO/Z8ImYDeKr6uFsyPAQ$FbL5+hG/duDEpa8UCYqXpEUQ5EacKg6i2iAs+Dq4dAI",
),
]
source_value = [
dict(key="secret1", value="value1"),
@@ -81,17 +87,23 @@ class SecretVariablesTestCase(unittest.TestCase):
expect = [
dict(key="secret1", value="value1"),
dict(key="secret2", value="$argon2id$v=19$m=65536,t=1,p=2$etGO/Z8ImYDeKr6uFsyPAQ$FbL5+hG/duDEpa8UCYqXpEUQ5EacKg6i2iAs+Dq4dAI"),
dict(
key="secret2",
value="$argon2id$v=19$m=65536,t=1,p=2$etGO/Z8ImYDeKr6uFsyPAQ$FbL5+hG/duDEpa8UCYqXpEUQ5EacKg6i2iAs+Dq4dAI",
),
]
result = SecretVariables.decode(source_secret, source_value)
result = sorted(result, key=lambda el: el['key'])
result = sorted(result, key=lambda el: el["key"])
self.assertEqual(result, expect)
@unittest.skipIf(argon2 is None, "Missing required 'argon2' library")
def test_decode_dict_missing_values_left(self):
source_secret = [
dict(key="secret1", hashed_value="$argon2id$v=19$m=65536,t=1,p=2$NuZk+6UATHNFV78nFRXFvA$3kivcXfzNHI1c/4ZBpP8BeBSGhhI82NfOh4Dd48JJgc"),
dict(
key="secret1",
hashed_value="$argon2id$v=19$m=65536,t=1,p=2$NuZk+6UATHNFV78nFRXFvA$3kivcXfzNHI1c/4ZBpP8BeBSGhhI82NfOh4Dd48JJgc",
),
]
source_value = [
dict(key="secret1", value="value1"),
@@ -103,14 +115,20 @@ class SecretVariablesTestCase(unittest.TestCase):
]
result = SecretVariables.decode(source_secret, source_value)
result = sorted(result, key=lambda el: el['key'])
result = sorted(result, key=lambda el: el["key"])
self.assertEqual(result, expect)
@unittest.skipIf(argon2 is None, "Missing required 'argon2' library")
def test_decode_dict_missing_values_right(self):
source_secret = [
dict(key="secret1", hashed_value="$argon2id$v=19$m=65536,t=1,p=2$NuZk+6UATHNFV78nFRXFvA$3kivcXfzNHI1c/4ZBpP8BeBSGhhI82NfOh4Dd48JJgc"),
dict(key="secret2", hashed_value="$argon2id$v=19$m=65536,t=1,p=2$etGO/Z8ImYDeKr6uFsyPAQ$FbL5+hG/duDEpa8UCYqXpEUQ5EacKg6i2iAs+Dq4dAI"),
dict(
key="secret1",
hashed_value="$argon2id$v=19$m=65536,t=1,p=2$NuZk+6UATHNFV78nFRXFvA$3kivcXfzNHI1c/4ZBpP8BeBSGhhI82NfOh4Dd48JJgc",
),
dict(
key="secret2",
hashed_value="$argon2id$v=19$m=65536,t=1,p=2$etGO/Z8ImYDeKr6uFsyPAQ$FbL5+hG/duDEpa8UCYqXpEUQ5EacKg6i2iAs+Dq4dAI",
),
]
source_value = [
dict(key="secret1", value="value1"),
@@ -118,9 +136,12 @@ class SecretVariablesTestCase(unittest.TestCase):
expect = [
dict(key="secret1", value="value1"),
dict(key="secret2", value="$argon2id$v=19$m=65536,t=1,p=2$etGO/Z8ImYDeKr6uFsyPAQ$FbL5+hG/duDEpa8UCYqXpEUQ5EacKg6i2iAs+Dq4dAI"),
dict(
key="secret2",
value="$argon2id$v=19$m=65536,t=1,p=2$etGO/Z8ImYDeKr6uFsyPAQ$FbL5+hG/duDEpa8UCYqXpEUQ5EacKg6i2iAs+Dq4dAI",
),
]
result = SecretVariables.decode(source_secret, source_value)
result = sorted(result, key=lambda el: el['key'])
result = sorted(result, key=lambda el: el["key"])
self.assertEqual(result, expect)

View File

@@ -14,102 +14,50 @@ from ansible_collections.community.general.plugins.module_utils.hwc_utils import
class HwcDictComparisonTestCase(unittest.TestCase):
def test_simple_no_difference(self):
value1 = {
'foo': 'bar',
'test': 'original'
}
value1 = {"foo": "bar", "test": "original"}
self.assertFalse(are_different_dicts(value1, value1))
def test_simple_different(self):
value1 = {
'foo': 'bar',
'test': 'original'
}
value2 = {
'foo': 'bar',
'test': 'different'
}
value3 = {
'test': 'original'
}
value1 = {"foo": "bar", "test": "original"}
value2 = {"foo": "bar", "test": "different"}
value3 = {"test": "original"}
self.assertTrue(are_different_dicts(value1, value2))
self.assertTrue(are_different_dicts(value1, value3))
self.assertTrue(are_different_dicts(value2, value3))
def test_nested_dictionaries_no_difference(self):
value1 = {
'foo': {
'quiet': {
'tree': 'test'
},
'bar': 'baz'
},
'test': 'original'
}
value1 = {"foo": {"quiet": {"tree": "test"}, "bar": "baz"}, "test": "original"}
self.assertFalse(are_different_dicts(value1, value1))
def test_nested_dictionaries_with_difference(self):
value1 = {
'foo': {
'quiet': {
'tree': 'test'
},
'bar': 'baz'
},
'test': 'original'
}
value2 = {
'foo': {
'quiet': {
'tree': 'baz'
},
'bar': 'hello'
},
'test': 'original'
}
value3 = {
'foo': {
'quiet': {
'tree': 'test'
},
'bar': 'baz'
}
}
value1 = {"foo": {"quiet": {"tree": "test"}, "bar": "baz"}, "test": "original"}
value2 = {"foo": {"quiet": {"tree": "baz"}, "bar": "hello"}, "test": "original"}
value3 = {"foo": {"quiet": {"tree": "test"}, "bar": "baz"}}
self.assertTrue(are_different_dicts(value1, value2))
self.assertTrue(are_different_dicts(value1, value3))
self.assertTrue(are_different_dicts(value2, value3))
def test_arrays_strings_no_difference(self):
value1 = {
'foo': [
'baz',
'bar'
]
}
value1 = {"foo": ["baz", "bar"]}
self.assertFalse(are_different_dicts(value1, value1))
def test_arrays_strings_with_difference(self):
value1 = {
'foo': [
'baz',
'bar',
"foo": [
"baz",
"bar",
]
}
value2 = {
'foo': [
'baz',
'hello'
]
}
value2 = {"foo": ["baz", "hello"]}
value3 = {
'foo': [
'bar',
"foo": [
"bar",
]
}
@@ -118,48 +66,18 @@ class HwcDictComparisonTestCase(unittest.TestCase):
self.assertTrue(are_different_dicts(value2, value3))
def test_arrays_dicts_with_no_difference(self):
value1 = {
'foo': [
{
'test': 'value',
'foo': 'bar'
},
{
'different': 'dict'
}
]
}
value1 = {"foo": [{"test": "value", "foo": "bar"}, {"different": "dict"}]}
self.assertFalse(are_different_dicts(value1, value1))
def test_arrays_dicts_with_difference(self):
value1 = {
'foo': [
{
'test': 'value',
'foo': 'bar'
},
{
'different': 'dict'
}
]
}
value1 = {"foo": [{"test": "value", "foo": "bar"}, {"different": "dict"}]}
value2 = {
'foo': [
{
'test': 'value2',
'foo': 'bar2'
},
]
}
value3 = {
'foo': [
{
'test': 'value',
'foo': 'bar'
}
"foo": [
{"test": "value2", "foo": "bar2"},
]
}
value3 = {"foo": [{"test": "value", "foo": "bar"}]}
self.assertTrue(are_different_dicts(value1, value2))
self.assertTrue(are_different_dicts(value1, value3))

View File

@@ -7,7 +7,7 @@ from __future__ import annotations
import sys
import unittest
from ansible_collections.community.general.plugins.module_utils.hwc_utils import (HwcModuleException, navigate_value)
from ansible_collections.community.general.plugins.module_utils.hwc_utils import HwcModuleException, navigate_value
class HwcUtilsTestCase(unittest.TestCase):
@@ -20,28 +20,24 @@ class HwcUtilsTestCase(unittest.TestCase):
def test_navigate_value(self):
value = {
'foo': {
'quiet': {
'tree': 'test',
"trees": [0, 1]
},
"foo": {
"quiet": {"tree": "test", "trees": [0, 1]},
}
}
self.assertEqual(navigate_value(value, ["foo", "quiet", "tree"]),
"test")
self.assertEqual(navigate_value(value, ["foo", "quiet", "tree"]), "test")
self.assertEqual(
navigate_value(value, ["foo", "quiet", "trees"],
{"foo.quiet.trees": 1}),
1)
self.assertEqual(navigate_value(value, ["foo", "quiet", "trees"], {"foo.quiet.trees": 1}), 1)
self.assertRaisesRegex(HwcModuleException,
r".* key\(q\) is not exist in dict",
navigate_value, value, ["foo", "q", "tree"])
self.assertRaisesRegex(
HwcModuleException, r".* key\(q\) is not exist in dict", navigate_value, value, ["foo", "q", "tree"]
)
self.assertRaisesRegex(HwcModuleException,
r".* the index is out of list",
navigate_value, value,
["foo", "quiet", "trees"],
{"foo.quiet.trees": 2})
self.assertRaisesRegex(
HwcModuleException,
r".* the index is out of list",
navigate_value,
value,
["foo", "quiet", "trees"],
{"foo.quiet.trees": 2},
)

View File

@@ -15,22 +15,23 @@ from ansible_collections.community.general.plugins.module_utils.identity.keycloa
)
module_params_creds = {
'auth_keycloak_url': 'http://keycloak.url/auth',
'validate_certs': True,
'auth_realm': 'master',
'client_id': 'admin-cli',
'auth_username': 'admin',
'auth_password': 'admin',
'client_secret': None,
"auth_keycloak_url": "http://keycloak.url/auth",
"validate_certs": True,
"auth_realm": "master",
"client_id": "admin-cli",
"auth_username": "admin",
"auth_password": "admin",
"client_secret": None,
}
def build_mocked_request(get_id_user_count, response_dict):
def _mocked_requests(*args, **kwargs):
url = args[0]
method = kwargs['method']
method = kwargs["method"]
future_response = response_dict.get(url, None)
return get_response(future_response, method, get_id_user_count)
return _mocked_requests
@@ -38,16 +39,14 @@ def get_response(object_with_future_response, method, get_id_call_count):
if callable(object_with_future_response):
return object_with_future_response()
if isinstance(object_with_future_response, dict):
return get_response(
object_with_future_response[method], method, get_id_call_count)
return get_response(object_with_future_response[method], method, get_id_call_count)
if isinstance(object_with_future_response, list):
try:
call_number = get_id_call_count.__next__()
except AttributeError:
# manage python 2 versions.
call_number = get_id_call_count.next()
return get_response(
object_with_future_response[call_number], method, get_id_call_count)
return get_response(object_with_future_response[call_number], method, get_id_call_count)
return object_with_future_response
@@ -55,52 +54,52 @@ def create_wrapper(text_as_string):
"""Allow to mock many times a call to one address.
Without this function, the StringIO is empty for the second call.
"""
def _create_wrapper():
return StringIO(text_as_string)
return _create_wrapper
@pytest.fixture()
def mock_good_connection(mocker):
token_response = {
'http://keycloak.url/auth/realms/master/protocol/openid-connect/token': create_wrapper('{"access_token": "alongtoken"}'), }
"http://keycloak.url/auth/realms/master/protocol/openid-connect/token": create_wrapper(
'{"access_token": "alongtoken"}'
),
}
return mocker.patch(
'ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak.open_url',
"ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak.open_url",
side_effect=build_mocked_request(count(), token_response),
autospec=True
autospec=True,
)
def test_connect_to_keycloak_with_creds(mock_good_connection):
keycloak_header = get_token(module_params_creds)
assert keycloak_header == {
'Authorization': 'Bearer alongtoken',
'Content-Type': 'application/json'
}
assert keycloak_header == {"Authorization": "Bearer alongtoken", "Content-Type": "application/json"}
def test_connect_to_keycloak_with_token(mock_good_connection):
module_params_token = {
'auth_keycloak_url': 'http://keycloak.url/auth',
'validate_certs': True,
'client_id': 'admin-cli',
'token': "alongtoken"
"auth_keycloak_url": "http://keycloak.url/auth",
"validate_certs": True,
"client_id": "admin-cli",
"token": "alongtoken",
}
keycloak_header = get_token(module_params_token)
assert keycloak_header == {
'Authorization': 'Bearer alongtoken',
'Content-Type': 'application/json'
}
assert keycloak_header == {"Authorization": "Bearer alongtoken", "Content-Type": "application/json"}
@pytest.fixture()
def mock_bad_json_returned(mocker):
token_response = {
'http://keycloak.url/auth/realms/master/protocol/openid-connect/token': create_wrapper('{"access_token":'), }
"http://keycloak.url/auth/realms/master/protocol/openid-connect/token": create_wrapper('{"access_token":'),
}
return mocker.patch(
'ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak.open_url',
"ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak.open_url",
side_effect=build_mocked_request(count(), token_response),
autospec=True
autospec=True,
)
@@ -110,27 +109,29 @@ def test_bad_json_returned(mock_bad_json_returned):
# cannot check all the message, different errors message for the value
# error in python 2.6, 2.7 and 3.*.
assert (
'API returned invalid JSON when trying to obtain access token from '
'http://keycloak.url/auth/realms/master/protocol/openid-connect/token: '
"API returned invalid JSON when trying to obtain access token from "
"http://keycloak.url/auth/realms/master/protocol/openid-connect/token: "
) in str(raised_error.value)
def raise_401(url):
def _raise_401():
raise HTTPError(url=url, code=401, msg='Unauthorized', hdrs='', fp=StringIO(''))
raise HTTPError(url=url, code=401, msg="Unauthorized", hdrs="", fp=StringIO(""))
return _raise_401
@pytest.fixture()
def mock_401_returned(mocker):
token_response = {
'http://keycloak.url/auth/realms/master/protocol/openid-connect/token': raise_401(
'http://keycloak.url/auth/realms/master/protocol/openid-connect/token'),
"http://keycloak.url/auth/realms/master/protocol/openid-connect/token": raise_401(
"http://keycloak.url/auth/realms/master/protocol/openid-connect/token"
),
}
return mocker.patch(
'ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak.open_url',
"ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak.open_url",
side_effect=build_mocked_request(count(), token_response),
autospec=True
autospec=True,
)
@@ -138,20 +139,23 @@ def test_error_returned(mock_401_returned):
with pytest.raises(KeycloakError) as raised_error:
get_token(module_params_creds)
assert str(raised_error.value) == (
'Could not obtain access token from http://keycloak.url'
'/auth/realms/master/protocol/openid-connect/token: '
'HTTP Error 401: Unauthorized'
"Could not obtain access token from http://keycloak.url"
"/auth/realms/master/protocol/openid-connect/token: "
"HTTP Error 401: Unauthorized"
)
@pytest.fixture()
def mock_json_without_token_returned(mocker):
token_response = {
'http://keycloak.url/auth/realms/master/protocol/openid-connect/token': create_wrapper('{"not_token": "It is not a token"}'), }
"http://keycloak.url/auth/realms/master/protocol/openid-connect/token": create_wrapper(
'{"not_token": "It is not a token"}'
),
}
return mocker.patch(
'ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak.open_url',
"ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak.open_url",
side_effect=build_mocked_request(count(), token_response),
autospec=True
autospec=True,
)
@@ -159,6 +163,6 @@ def test_json_without_token_returned(mock_json_without_token_returned):
with pytest.raises(KeycloakError) as raised_error:
get_token(module_params_creds)
assert str(raised_error.value) == (
'API did not include access_token field in response from '
'http://keycloak.url/auth/realms/master/protocol/openid-connect/token'
"API did not include access_token field in response from "
"http://keycloak.url/auth/realms/master/protocol/openid-connect/token"
)

View File

@@ -11,74 +11,44 @@ from ansible_collections.community.general.plugins.module_utils.identity.keycloa
class KeycloakIsStructIncludedTestCase(unittest.TestCase):
dict1 = dict(
test1='test1',
test2=dict(
test1='test1',
test2='test2'
),
test3=['test1', dict(test='test1', test2='test2')]
test1="test1", test2=dict(test1="test1", test2="test2"), test3=["test1", dict(test="test1", test2="test2")]
)
dict2 = dict(
test1='test1',
test2=dict(
test1='test1',
test2='test2',
test3='test3'
),
test3=['test1', dict(test='test1', test2='test2'), 'test3'],
test4='test4'
test1="test1",
test2=dict(test1="test1", test2="test2", test3="test3"),
test3=["test1", dict(test="test1", test2="test2"), "test3"],
test4="test4",
)
dict3 = dict(
test1='test1',
test2=dict(
test1='test1',
test2='test23',
test3='test3'
),
test3=['test1', dict(test='test1', test2='test23'), 'test3'],
test4='test4'
test1="test1",
test2=dict(test1="test1", test2="test23", test3="test3"),
test3=["test1", dict(test="test1", test2="test23"), "test3"],
test4="test4",
)
dict5 = dict(
test1='test1',
test2=dict(
test1=True,
test2='test23',
test3='test3'
),
test3=['test1', dict(test='test1', test2='test23'), 'test3'],
test4='test4'
test1="test1",
test2=dict(test1=True, test2="test23", test3="test3"),
test3=["test1", dict(test="test1", test2="test23"), "test3"],
test4="test4",
)
dict6 = dict(
test1='test1',
test2=dict(
test1='true',
test2='test23',
test3='test3'
),
test3=['test1', dict(test='test1', test2='test23'), 'test3'],
test4='test4'
test1="test1",
test2=dict(test1="true", test2="test23", test3="test3"),
test3=["test1", dict(test="test1", test2="test23"), "test3"],
test4="test4",
)
dict7 = [
{
'roles': ['view-clients', 'view-identity-providers', 'view-users', 'query-realms', 'manage-users'],
'clientid': 'master-realm'
"roles": ["view-clients", "view-identity-providers", "view-users", "query-realms", "manage-users"],
"clientid": "master-realm",
},
{
'roles': ['manage-account', 'view-profile', 'manage-account-links'],
'clientid': 'account'
}
{"roles": ["manage-account", "view-profile", "manage-account-links"], "clientid": "account"},
]
dict8 = [
{
'roles': ['view-clients', 'query-realms', 'view-users'],
'clientid': 'master-realm'
},
{
'roles': ['manage-account-links', 'view-profile', 'manage-account'],
'clientid': 'account'
}
{"roles": ["view-clients", "query-realms", "view-users"], "clientid": "master-realm"},
{"roles": ["manage-account-links", "view-profile", "manage-account"], "clientid": "account"},
]
def test_trivial(self):

View File

@@ -459,9 +459,7 @@ class TestPritunlApi:
):
api._get_pritunl_organizations = get_pritunl_organization_mock()
response = api.list_pritunl_organizations(
**dict_merge(pritunl_settings, {"filters": org_filters})
)
response = api.list_pritunl_organizations(**dict_merge(pritunl_settings, {"filters": org_filters}))
assert len(response) == 1
assert response[0]["name"] == org_expected
@@ -470,14 +468,10 @@ class TestPritunlApi:
"org_id,org_user_count",
[("58070daee63f3b2e6e472c36", 3)],
)
def test_list_all_pritunl_user(
self, pritunl_settings, get_pritunl_user_mock, org_id, org_user_count
):
def test_list_all_pritunl_user(self, pritunl_settings, get_pritunl_user_mock, org_id, org_user_count):
api._get_pritunl_users = get_pritunl_user_mock()
response = api.list_pritunl_users(
**dict_merge(pritunl_settings, {"organization_id": org_id})
)
response = api.list_pritunl_users(**dict_merge(pritunl_settings, {"organization_id": org_id}))
assert len(response) == org_user_count
@@ -499,9 +493,7 @@ class TestPritunlApi:
api._get_pritunl_users = get_pritunl_user_mock()
response = api.list_pritunl_users(
**dict_merge(
pritunl_settings, {"organization_id": org_id, "filters": user_filters}
)
**dict_merge(pritunl_settings, {"organization_id": org_id, "filters": user_filters})
)
assert len(response) > 0
@@ -586,9 +578,7 @@ class TestPritunlApi:
# Test for DELETE operation on Pritunl API
@pytest.mark.parametrize("org_id", [("58070daee63f3b2e6e472c36")])
def test_delete_pritunl_organization(
self, pritunl_settings, org_id, delete_pritunl_organization_mock
):
def test_delete_pritunl_organization(self, pritunl_settings, org_id, delete_pritunl_organization_mock):
api._delete_pritunl_organization = delete_pritunl_organization_mock()
response = api.delete_pritunl_organization(
@@ -602,12 +592,8 @@ class TestPritunlApi:
assert response == {}
@pytest.mark.parametrize(
"org_id,user_id", [("58070daee63f3b2e6e472c36", "590add71e63f3b72d8bb951a")]
)
def test_delete_pritunl_user(
self, pritunl_settings, org_id, user_id, delete_pritunl_user_mock
):
@pytest.mark.parametrize("org_id,user_id", [("58070daee63f3b2e6e472c36", "590add71e63f3b72d8bb951a")])
def test_delete_pritunl_user(self, pritunl_settings, org_id, user_id, delete_pritunl_user_mock):
api._delete_pritunl_user = delete_pritunl_user_mock()
response = api.delete_pritunl_user(

View File

@@ -16,9 +16,24 @@ TC_FORMATS = dict(
simple_boolean__true=(partial(cmd_runner_fmt.as_bool, "--superflag"), True, ["--superflag"], None),
simple_boolean__false=(partial(cmd_runner_fmt.as_bool, "--superflag"), False, [], None),
simple_boolean__none=(partial(cmd_runner_fmt.as_bool, "--superflag"), None, [], None),
simple_boolean_both__true=(partial(cmd_runner_fmt.as_bool, "--superflag", "--falseflag"), True, ["--superflag"], None),
simple_boolean_both__false=(partial(cmd_runner_fmt.as_bool, "--superflag", "--falseflag"), False, ["--falseflag"], None),
simple_boolean_both__none=(partial(cmd_runner_fmt.as_bool, "--superflag", "--falseflag"), None, ["--falseflag"], None),
simple_boolean_both__true=(
partial(cmd_runner_fmt.as_bool, "--superflag", "--falseflag"),
True,
["--superflag"],
None,
),
simple_boolean_both__false=(
partial(cmd_runner_fmt.as_bool, "--superflag", "--falseflag"),
False,
["--falseflag"],
None,
),
simple_boolean_both__none=(
partial(cmd_runner_fmt.as_bool, "--superflag", "--falseflag"),
None,
["--falseflag"],
None,
),
simple_boolean_both__none_ig=(partial(cmd_runner_fmt.as_bool, "--superflag", "--falseflag", True), None, [], None),
simple_boolean_not__true=(partial(cmd_runner_fmt.as_bool_not, "--superflag"), True, [], None),
simple_boolean_not__false=(partial(cmd_runner_fmt.as_bool_not, "--superflag"), False, ["--superflag"], None),
@@ -36,21 +51,56 @@ TC_FORMATS = dict(
simple_list_min_len_fail=(partial(cmd_runner_fmt.as_list, min_len=10), 42, None, ValueError),
simple_list_max_len_ok=(partial(cmd_runner_fmt.as_list, max_len=1), 42, ["42"], None),
simple_list_max_len_fail=(partial(cmd_runner_fmt.as_list, max_len=2), [42, 42, 42], None, ValueError),
simple_map=(partial(cmd_runner_fmt.as_map, {'a': 1, 'b': 2, 'c': 3}), 'b', ["2"], None),
simple_fixed_true=(partial(cmd_runner_fmt.as_fixed, ["--always-here", "--forever"]), True, ["--always-here", "--forever"], None),
simple_fixed_false=(partial(cmd_runner_fmt.as_fixed, ["--always-here", "--forever"]), False, ["--always-here", "--forever"], None),
simple_fixed_none=(partial(cmd_runner_fmt.as_fixed, ["--always-here", "--forever"]), None, ["--always-here", "--forever"], None),
simple_fixed_str=(partial(cmd_runner_fmt.as_fixed, ["--always-here", "--forever"]), "something", ["--always-here", "--forever"], None),
stack_optval__str=(partial(cmd_runner_fmt.stack(cmd_runner_fmt.as_optval), "-t"), ["potatoes", "bananas"], ["-tpotatoes", "-tbananas"], None),
stack_opt_val__str=(partial(cmd_runner_fmt.stack(cmd_runner_fmt.as_opt_val), "-t"), ["potatoes", "bananas"], ["-t", "potatoes", "-t", "bananas"], None),
stack_opt_eq_val__int=(partial(cmd_runner_fmt.stack(cmd_runner_fmt.as_opt_eq_val), "--answer"), [42, 17], ["--answer=42", "--answer=17"], None),
simple_map=(partial(cmd_runner_fmt.as_map, {"a": 1, "b": 2, "c": 3}), "b", ["2"], None),
simple_fixed_true=(
partial(cmd_runner_fmt.as_fixed, ["--always-here", "--forever"]),
True,
["--always-here", "--forever"],
None,
),
simple_fixed_false=(
partial(cmd_runner_fmt.as_fixed, ["--always-here", "--forever"]),
False,
["--always-here", "--forever"],
None,
),
simple_fixed_none=(
partial(cmd_runner_fmt.as_fixed, ["--always-here", "--forever"]),
None,
["--always-here", "--forever"],
None,
),
simple_fixed_str=(
partial(cmd_runner_fmt.as_fixed, ["--always-here", "--forever"]),
"something",
["--always-here", "--forever"],
None,
),
stack_optval__str=(
partial(cmd_runner_fmt.stack(cmd_runner_fmt.as_optval), "-t"),
["potatoes", "bananas"],
["-tpotatoes", "-tbananas"],
None,
),
stack_opt_val__str=(
partial(cmd_runner_fmt.stack(cmd_runner_fmt.as_opt_val), "-t"),
["potatoes", "bananas"],
["-t", "potatoes", "-t", "bananas"],
None,
),
stack_opt_eq_val__int=(
partial(cmd_runner_fmt.stack(cmd_runner_fmt.as_opt_eq_val), "--answer"),
[42, 17],
["--answer=42", "--answer=17"],
None,
),
)
TC_FORMATS_IDS = sorted(TC_FORMATS.keys())
@pytest.mark.parametrize('func, value, expected, exception',
(TC_FORMATS[tc] for tc in TC_FORMATS_IDS),
ids=TC_FORMATS_IDS)
@pytest.mark.parametrize(
"func, value, expected, exception", (TC_FORMATS[tc] for tc in TC_FORMATS_IDS), ids=TC_FORMATS_IDS
)
def test_arg_format(func, value, expected, exception):
fmt_func = func()
try:
@@ -120,14 +170,14 @@ TC_RUNNER = dict(
bb=dict(fmt_func=cmd_runner_fmt.as_bool, fmt_arg="--bb-here"),
),
runner_init_args=dict(),
runner_ctx_args=dict(args_order=['aa', 'bb']),
runner_ctx_args=dict(args_order=["aa", "bb"]),
),
dict(runner_ctx_run_args=dict(bb=True), rc=0, out="", err=""),
dict(
run_info=dict(
cmd=['/mock/bin/testing', '--answer=11', '--bb-here'],
environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'},
args_order=('aa', 'bb'),
cmd=["/mock/bin/testing", "--answer=11", "--bb-here"],
environ_update={"LANGUAGE": "C", "LC_ALL": "C"},
args_order=("aa", "bb"),
),
),
),
@@ -137,15 +187,15 @@ TC_RUNNER = dict(
aa=dict(type="int", value=11, fmt_func=cmd_runner_fmt.as_opt_eq_val, fmt_arg="--answer"),
bb=dict(fmt_func=cmd_runner_fmt.as_bool, fmt_arg="--bb-here"),
),
runner_init_args=dict(default_args_order=['bb', 'aa']),
runner_init_args=dict(default_args_order=["bb", "aa"]),
runner_ctx_args=dict(),
),
dict(runner_ctx_run_args=dict(bb=True), rc=0, out="", err=""),
dict(
run_info=dict(
cmd=['/mock/bin/testing', '--bb-here', '--answer=11'],
environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'},
args_order=('bb', 'aa'),
cmd=["/mock/bin/testing", "--bb-here", "--answer=11"],
environ_update={"LANGUAGE": "C", "LC_ALL": "C"},
args_order=("bb", "aa"),
),
),
),
@@ -155,15 +205,15 @@ TC_RUNNER = dict(
aa=dict(type="int", value=11, fmt_func=cmd_runner_fmt.as_opt_eq_val, fmt_arg="--answer"),
bb=dict(fmt_func=cmd_runner_fmt.as_bool, fmt_arg="--bb-here"),
),
runner_init_args=dict(default_args_order=['bb', 'aa']),
runner_ctx_args=dict(args_order=['aa', 'bb']),
runner_init_args=dict(default_args_order=["bb", "aa"]),
runner_ctx_args=dict(args_order=["aa", "bb"]),
),
dict(runner_ctx_run_args=dict(bb=True), rc=0, out="", err=""),
dict(
run_info=dict(
cmd=['/mock/bin/testing', '--answer=11', '--bb-here'],
environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'},
args_order=('aa', 'bb'),
cmd=["/mock/bin/testing", "--answer=11", "--bb-here"],
environ_update={"LANGUAGE": "C", "LC_ALL": "C"},
args_order=("aa", "bb"),
),
),
),
@@ -174,12 +224,12 @@ TC_RUNNER = dict(
bb=dict(fmt_func=cmd_runner_fmt.as_bool, fmt_arg="--bb-here"),
),
runner_init_args=dict(),
runner_ctx_args=dict(args_order=['aa', 'bb', 'aa']),
runner_ctx_args=dict(args_order=["aa", "bb", "aa"]),
),
dict(runner_ctx_run_args=dict(bb=True), rc=0, out="", err=""),
dict(
run_info=dict(
cmd=['/mock/bin/testing', '--answer=11', '--bb-here', '--answer=11'],
cmd=["/mock/bin/testing", "--answer=11", "--bb-here", "--answer=11"],
),
),
),
@@ -189,18 +239,17 @@ TC_RUNNER = dict(
aa=dict(type="int", value=11, fmt_func=cmd_runner_fmt.as_opt_eq_val, fmt_arg="--answer"),
bb=dict(fmt_func=cmd_runner_fmt.as_bool, fmt_arg="--bb-here"),
),
runner_init_args=dict(default_args_order=['bb', 'aa']),
runner_init_args=dict(default_args_order=["bb", "aa"]),
runner_ctx_args=dict(
args_order=['aa', 'bb'],
output_process=lambda rc, out, err: f"{rc!s}-/-{out}-/-{err}"
args_order=["aa", "bb"], output_process=lambda rc, out, err: f"{rc!s}-/-{out}-/-{err}"
),
),
dict(runner_ctx_run_args=dict(bb=True), rc=0, out="ni", err="nu"),
dict(
run_info=dict(
cmd=['/mock/bin/testing', '--answer=11', '--bb-here'],
cmd=["/mock/bin/testing", "--answer=11", "--bb-here"],
),
results="0-/-ni-/-nu"
results="0-/-ni-/-nu",
),
),
aa_bb_with_none=(
@@ -209,15 +258,15 @@ TC_RUNNER = dict(
aa=dict(type="int", value=49, fmt_func=cmd_runner_fmt.as_opt_eq_val, fmt_arg="--answer"),
bb=dict(fmt_func=cmd_runner_fmt.as_bool, fmt_arg="--bb-here"),
),
runner_init_args=dict(default_args_order=['bb', 'aa']),
runner_init_args=dict(default_args_order=["bb", "aa"]),
runner_ctx_args=dict(
args_order=['aa', 'bb'],
args_order=["aa", "bb"],
),
),
dict(runner_ctx_run_args=dict(bb=None), rc=0, out="ni", err="nu"),
dict(
run_info=dict(
cmd=['/mock/bin/testing', '--answer=49'],
cmd=["/mock/bin/testing", "--answer=49"],
),
),
),
@@ -228,14 +277,14 @@ TC_RUNNER = dict(
bb=dict(fmt_func=cmd_runner_fmt.as_fixed, fmt_arg=["fixed", "args"]),
),
runner_init_args=dict(),
runner_ctx_args=dict(args_order=['aa', 'bb']),
runner_ctx_args=dict(args_order=["aa", "bb"]),
),
dict(runner_ctx_run_args=dict(), rc=0, out="", err=""),
dict(
run_info=dict(
cmd=['/mock/bin/testing', '--answer=11', 'fixed', 'args'],
environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'},
args_order=('aa', 'bb'),
cmd=["/mock/bin/testing", "--answer=11", "fixed", "args"],
environ_update={"LANGUAGE": "C", "LC_ALL": "C"},
args_order=("aa", "bb"),
),
),
),
@@ -246,14 +295,14 @@ TC_RUNNER = dict(
bb=dict(fmt_func=cmd_runner_fmt.as_map, fmt_arg={"v1": 111, "v2": 222}),
),
runner_init_args=dict(),
runner_ctx_args=dict(args_order=['aa', 'bb']),
runner_ctx_args=dict(args_order=["aa", "bb"]),
),
dict(runner_ctx_run_args=dict(bb="v2"), rc=0, out="", err=""),
dict(
run_info=dict(
cmd=['/mock/bin/testing', '--answer=11', '222'],
environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'},
args_order=('aa', 'bb'),
cmd=["/mock/bin/testing", "--answer=11", "222"],
environ_update={"LANGUAGE": "C", "LC_ALL": "C"},
args_order=("aa", "bb"),
),
),
),
@@ -264,14 +313,14 @@ TC_RUNNER = dict(
bb=dict(fmt_func=cmd_runner_fmt.as_map, fmt_arg={"v1": 111, "v2": 222}),
),
runner_init_args=dict(),
runner_ctx_args=dict(args_order=['aa', 'bb']),
runner_ctx_args=dict(args_order=["aa", "bb"]),
),
dict(runner_ctx_run_args=dict(bb="v123456789"), rc=0, out="", err=""),
dict(
run_info=dict(
cmd=['/mock/bin/testing', '--answer=11'],
environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'},
args_order=('aa', 'bb'),
cmd=["/mock/bin/testing", "--answer=11"],
environ_update={"LANGUAGE": "C", "LC_ALL": "C"},
args_order=("aa", "bb"),
),
),
),
@@ -279,69 +328,64 @@ TC_RUNNER = dict(
TC_RUNNER_IDS = sorted(TC_RUNNER.keys())
@pytest.mark.parametrize('runner_input, cmd_execution, expected',
(TC_RUNNER[tc] for tc in TC_RUNNER_IDS),
ids=TC_RUNNER_IDS)
@pytest.mark.parametrize(
"runner_input, cmd_execution, expected", (TC_RUNNER[tc] for tc in TC_RUNNER_IDS), ids=TC_RUNNER_IDS
)
def test_runner_context(runner_input, cmd_execution, expected):
arg_spec = {}
params = {}
arg_formats = {}
for k, v in runner_input['args_bundle'].items():
for k, v in runner_input["args_bundle"].items():
try:
arg_spec[k] = {'type': v['type']}
arg_spec[k] = {"type": v["type"]}
except KeyError:
pass
try:
params[k] = v['value']
params[k] = v["value"]
except KeyError:
pass
try:
arg_formats[k] = v['fmt_func'](v['fmt_arg'])
arg_formats[k] = v["fmt_func"](v["fmt_arg"])
except KeyError:
pass
orig_results = tuple(cmd_execution[x] for x in ('rc', 'out', 'err'))
orig_results = tuple(cmd_execution[x] for x in ("rc", "out", "err"))
print(f"arg_spec={arg_spec}\nparams={params}\narg_formats={arg_formats}\n")
module = MagicMock()
type(module).argument_spec = PropertyMock(return_value=arg_spec)
type(module).params = PropertyMock(return_value=params)
module.get_bin_path.return_value = '/mock/bin/testing'
module.get_bin_path.return_value = "/mock/bin/testing"
module.run_command.return_value = orig_results
runner = CmdRunner(
module=module,
command="testing",
arg_formats=arg_formats,
**runner_input['runner_init_args']
)
runner = CmdRunner(module=module, command="testing", arg_formats=arg_formats, **runner_input["runner_init_args"])
def _assert_run_info(actual, expected):
reduced = {k: actual[k] for k in expected.keys()}
assert reduced == expected, f"{reduced}"
def _assert_run(runner_input, cmd_execution, expected, ctx, results):
_assert_run_info(ctx.run_info, expected['run_info'])
assert results == expected.get('results', orig_results)
_assert_run_info(ctx.run_info, expected["run_info"])
assert results == expected.get("results", orig_results)
exc = expected.get("exc")
if exc:
with pytest.raises(exc):
with runner.context(**runner_input['runner_ctx_args']) as ctx:
results = ctx.run(**cmd_execution['runner_ctx_run_args'])
with runner.context(**runner_input["runner_ctx_args"]) as ctx:
results = ctx.run(**cmd_execution["runner_ctx_run_args"])
_assert_run(runner_input, cmd_execution, expected, ctx, results)
with pytest.raises(exc):
with runner(**runner_input['runner_ctx_args']) as ctx2:
results2 = ctx2.run(**cmd_execution['runner_ctx_run_args'])
with runner(**runner_input["runner_ctx_args"]) as ctx2:
results2 = ctx2.run(**cmd_execution["runner_ctx_run_args"])
_assert_run(runner_input, cmd_execution, expected, ctx2, results2)
else:
with runner.context(**runner_input['runner_ctx_args']) as ctx:
results = ctx.run(**cmd_execution['runner_ctx_run_args'])
with runner.context(**runner_input["runner_ctx_args"]) as ctx:
results = ctx.run(**cmd_execution["runner_ctx_run_args"])
_assert_run(runner_input, cmd_execution, expected, ctx, results)
with runner(**runner_input['runner_ctx_args']) as ctx2:
results2 = ctx2.run(**cmd_execution['runner_ctx_run_args'])
with runner(**runner_input["runner_ctx_args"]) as ctx2:
results2 = ctx2.run(**cmd_execution["runner_ctx_run_args"])
_assert_run(runner_input, cmd_execution, expected, ctx2, results2)

View File

@@ -1,4 +1,3 @@
# Copyright (c) Ansible project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
@@ -14,7 +13,7 @@ from ansible_collections.community.general.plugins.module_utils import csv
VALID_CSV = [
(
'excel',
"excel",
{},
None,
"id,name,role\n1,foo,bar\n2,bar,baz",
@@ -29,10 +28,10 @@ VALID_CSV = [
"name": "bar",
"role": "baz",
},
]
],
),
(
'excel',
"excel",
{"skipinitialspace": True},
None,
"id,name,role\n1, foo, bar\n2, bar, baz",
@@ -47,11 +46,11 @@ VALID_CSV = [
"name": "bar",
"role": "baz",
},
]
],
),
(
'excel',
{"delimiter": '|'},
"excel",
{"delimiter": "|"},
None,
"id|name|role\n1|foo|bar\n2|bar|baz",
[
@@ -65,10 +64,10 @@ VALID_CSV = [
"name": "bar",
"role": "baz",
},
]
],
),
(
'unix',
"unix",
{},
None,
"id,name,role\n1,foo,bar\n2,bar,baz",
@@ -83,12 +82,12 @@ VALID_CSV = [
"name": "bar",
"role": "baz",
},
]
],
),
(
'excel',
"excel",
{},
['id', 'name', 'role'],
["id", "name", "role"],
"1,foo,bar\n2,bar,baz",
[
{
@@ -101,14 +100,14 @@ VALID_CSV = [
"name": "bar",
"role": "baz",
},
]
],
),
]
INVALID_CSV = [
(
'excel',
{'strict': True},
"excel",
{"strict": True},
None,
'id,name,role\n1,"f"oo",bar\n2,bar,baz',
),
@@ -116,7 +115,7 @@ INVALID_CSV = [
INVALID_DIALECT: list[tuple[str, t.Any, t.Any, str]] = [
(
'invalid',
"invalid",
{},
None,
"id,name,role\n1,foo,bar\n2,bar,baz",

View File

@@ -19,15 +19,13 @@ VALID = {
'"public.table"': '"public.table"',
'"public"."table"': '"public"."table"',
'"schema test"."table test"': '"schema test"."table test"',
# We quote part
'public.table': '"public"."table"',
"public.table": '"public"."table"',
'"public".table': '"public"."table"',
'public."table"': '"public"."table"',
'schema test.table test': '"schema test"."table test"',
"schema test.table test": '"schema test"."table test"',
'"schema test".table test': '"schema test"."table test"',
'schema test."table test"': '"schema test"."table test"',
# Embedded double quotes
'table "test"': '"table ""test"""',
'public."table ""test"""': '"public"."table ""test"""',
@@ -40,7 +38,6 @@ VALID = {
'schema."table': '"schema"."""table"',
'"schema.table': '"""schema"."table"',
'schema."table.something': '"schema"."""table"."something"',
# Embedded dots
'"schema.test"."table.test"': '"schema.test"."table.test"',
'"schema.".table': '"schema."."table"',
@@ -50,61 +47,61 @@ VALID = {
'"schema.".".table"': '"schema.".".table"',
# These are valid but maybe not what the user intended
'."table"': '".""table"""',
'table.': '"table."',
"table.": '"table."',
}
INVALID = {
('test.too.many.dots', 'table'): 'PostgreSQL does not support table with more than 3 dots',
('"test.too".many.dots', 'database'): 'PostgreSQL does not support database with more than 1 dots',
('test.too."many.dots"', 'database'): 'PostgreSQL does not support database with more than 1 dots',
('"test"."too"."many"."dots"', 'database'): "PostgreSQL does not support database with more than 1 dots",
('"test"."too"."many"."dots"', 'schema'): "PostgreSQL does not support schema with more than 2 dots",
('"test"."too"."many"."dots"', 'table'): "PostgreSQL does not support table with more than 3 dots",
('"test"."too"."many"."dots"."for"."column"', 'column'): "PostgreSQL does not support column with more than 4 dots",
('"table "invalid" double quote"', 'table'): 'User escaped identifiers must escape extra quotes',
('"schema "invalid"""."table "invalid"', 'table'): 'User escaped identifiers must escape extra quotes',
('"schema."table"', 'table'): 'User escaped identifiers must escape extra quotes',
('"schema".', 'table'): 'Identifier name unspecified or unquoted trailing dot',
("test.too.many.dots", "table"): "PostgreSQL does not support table with more than 3 dots",
('"test.too".many.dots', "database"): "PostgreSQL does not support database with more than 1 dots",
('test.too."many.dots"', "database"): "PostgreSQL does not support database with more than 1 dots",
('"test"."too"."many"."dots"', "database"): "PostgreSQL does not support database with more than 1 dots",
('"test"."too"."many"."dots"', "schema"): "PostgreSQL does not support schema with more than 2 dots",
('"test"."too"."many"."dots"', "table"): "PostgreSQL does not support table with more than 3 dots",
('"test"."too"."many"."dots"."for"."column"', "column"): "PostgreSQL does not support column with more than 4 dots",
('"table "invalid" double quote"', "table"): "User escaped identifiers must escape extra quotes",
('"schema "invalid"""."table "invalid"', "table"): "User escaped identifiers must escape extra quotes",
('"schema."table"', "table"): "User escaped identifiers must escape extra quotes",
('"schema".', "table"): "Identifier name unspecified or unquoted trailing dot",
}
HOW_MANY_DOTS = (
('role', 'role', '"role"',
'PostgreSQL does not support role with more than 1 dots'),
('db', 'database', '"db"',
'PostgreSQL does not support database with more than 1 dots'),
('db.schema', 'schema', '"db"."schema"',
'PostgreSQL does not support schema with more than 2 dots'),
('db.schema.table', 'table', '"db"."schema"."table"',
'PostgreSQL does not support table with more than 3 dots'),
('db.schema.table.column', 'column', '"db"."schema"."table"."column"',
'PostgreSQL does not support column with more than 4 dots'),
("role", "role", '"role"', "PostgreSQL does not support role with more than 1 dots"),
("db", "database", '"db"', "PostgreSQL does not support database with more than 1 dots"),
("db.schema", "schema", '"db"."schema"', "PostgreSQL does not support schema with more than 2 dots"),
("db.schema.table", "table", '"db"."schema"."table"', "PostgreSQL does not support table with more than 3 dots"),
(
"db.schema.table.column",
"column",
'"db"."schema"."table"."column"',
"PostgreSQL does not support column with more than 4 dots",
),
)
VALID_QUOTES = ((test, VALID[test]) for test in sorted(VALID))
INVALID_QUOTES = ((test[0], test[1], INVALID[test]) for test in sorted(INVALID))
IS_STRINGS_DANGEROUS = (
('', False),
(' ', False),
('alternative database', False),
('backup of TRUNCATED table', False),
('bob.dropper', False),
('d\'artagnan', False),
('user_with_select_update_truncate_right', False),
(';DROP DATABASE fluffy_pets_photos', True),
(';drop DATABASE fluffy_pets_photos', True),
('; TRUNCATE TABLE his_valuable_table', True),
('; truncate TABLE his_valuable_table', True),
('\'--', True),
("", False),
(" ", False),
("alternative database", False),
("backup of TRUNCATED table", False),
("bob.dropper", False),
("d'artagnan", False),
("user_with_select_update_truncate_right", False),
(";DROP DATABASE fluffy_pets_photos", True),
(";drop DATABASE fluffy_pets_photos", True),
("; TRUNCATE TABLE his_valuable_table", True),
("; truncate TABLE his_valuable_table", True),
("'--", True),
('"--', True),
('\' union select username, password from admin_credentials', True),
('\' UNION SELECT username, password from admin_credentials', True),
('\' intersect select', True),
('\' INTERSECT select', True),
('\' except select', True),
('\' EXCEPT select', True),
(';ALTER TABLE prices', True),
(';alter table prices', True),
("' union select username, password from admin_credentials", True),
("' UNION SELECT username, password from admin_credentials", True),
("' intersect select", True),
("' INTERSECT select", True),
("' except select", True),
("' EXCEPT select", True),
(";ALTER TABLE prices", True),
(";alter table prices", True),
("; UPDATE products SET price = '0'", True),
(";update products SET price = '0'", True),
("; DELETE FROM products", True),
@@ -116,7 +113,7 @@ IS_STRINGS_DANGEROUS = (
@pytest.mark.parametrize("identifier, quoted_identifier", VALID_QUOTES)
def test_valid_quotes(identifier, quoted_identifier):
assert pg_quote_identifier(identifier, 'table') == quoted_identifier
assert pg_quote_identifier(identifier, "table") == quoted_identifier
@pytest.mark.parametrize("identifier, id_type, msg", INVALID_QUOTES)
@@ -132,7 +129,7 @@ def test_how_many_dots(identifier, id_type, quoted_identifier, msg):
assert pg_quote_identifier(identifier, id_type) == quoted_identifier
with pytest.raises(SQLParseError) as ex:
pg_quote_identifier(f'{identifier}.more', id_type)
pg_quote_identifier(f"{identifier}.more", id_type)
ex.match(msg)

View File

@@ -11,89 +11,94 @@ from ansible_collections.community.general.plugins.module_utils import known_hos
URLS = {
'ssh://one.example.org/example.git': {
'is_ssh_url': True,
'get_fqdn': 'one.example.org',
'add_host_key_cmd': " -t rsa one.example.org",
'port': None,
"ssh://one.example.org/example.git": {
"is_ssh_url": True,
"get_fqdn": "one.example.org",
"add_host_key_cmd": " -t rsa one.example.org",
"port": None,
},
'ssh+git://two.example.org/example.git': {
'is_ssh_url': True,
'get_fqdn': 'two.example.org',
'add_host_key_cmd': " -t rsa two.example.org",
'port': None,
"ssh+git://two.example.org/example.git": {
"is_ssh_url": True,
"get_fqdn": "two.example.org",
"add_host_key_cmd": " -t rsa two.example.org",
"port": None,
},
'rsync://three.example.org/user/example.git': {
'is_ssh_url': False,
'get_fqdn': 'three.example.org',
'add_host_key_cmd': None, # not called for non-ssh urls
'port': None,
"rsync://three.example.org/user/example.git": {
"is_ssh_url": False,
"get_fqdn": "three.example.org",
"add_host_key_cmd": None, # not called for non-ssh urls
"port": None,
},
'git@four.example.org:user/example.git': {
'is_ssh_url': True,
'get_fqdn': 'four.example.org',
'add_host_key_cmd': " -t rsa four.example.org",
'port': None,
"git@four.example.org:user/example.git": {
"is_ssh_url": True,
"get_fqdn": "four.example.org",
"add_host_key_cmd": " -t rsa four.example.org",
"port": None,
},
'git+ssh://five.example.org/example.git': {
'is_ssh_url': True,
'get_fqdn': 'five.example.org',
'add_host_key_cmd': " -t rsa five.example.org",
'port': None,
"git+ssh://five.example.org/example.git": {
"is_ssh_url": True,
"get_fqdn": "five.example.org",
"add_host_key_cmd": " -t rsa five.example.org",
"port": None,
},
'ssh://six.example.org:21/example.org': {
"ssh://six.example.org:21/example.org": {
# ssh on FTP Port?
'is_ssh_url': True,
'get_fqdn': 'six.example.org',
'add_host_key_cmd': " -t rsa -p 21 six.example.org",
'port': '21',
"is_ssh_url": True,
"get_fqdn": "six.example.org",
"add_host_key_cmd": " -t rsa -p 21 six.example.org",
"port": "21",
},
'ssh://[2001:DB8::abcd:abcd]/example.git': {
'is_ssh_url': True,
'get_fqdn': '[2001:DB8::abcd:abcd]',
'add_host_key_cmd': " -t rsa [2001:DB8::abcd:abcd]",
'port': None,
"ssh://[2001:DB8::abcd:abcd]/example.git": {
"is_ssh_url": True,
"get_fqdn": "[2001:DB8::abcd:abcd]",
"add_host_key_cmd": " -t rsa [2001:DB8::abcd:abcd]",
"port": None,
},
'ssh://[2001:DB8::abcd:abcd]:22/example.git': {
'is_ssh_url': True,
'get_fqdn': '[2001:DB8::abcd:abcd]',
'add_host_key_cmd': " -t rsa -p 22 [2001:DB8::abcd:abcd]",
'port': '22',
"ssh://[2001:DB8::abcd:abcd]:22/example.git": {
"is_ssh_url": True,
"get_fqdn": "[2001:DB8::abcd:abcd]",
"add_host_key_cmd": " -t rsa -p 22 [2001:DB8::abcd:abcd]",
"port": "22",
},
'username@[2001:DB8::abcd:abcd]/example.git': {
'is_ssh_url': True,
'get_fqdn': '[2001:DB8::abcd:abcd]',
'add_host_key_cmd': " -t rsa [2001:DB8::abcd:abcd]",
'port': None,
"username@[2001:DB8::abcd:abcd]/example.git": {
"is_ssh_url": True,
"get_fqdn": "[2001:DB8::abcd:abcd]",
"add_host_key_cmd": " -t rsa [2001:DB8::abcd:abcd]",
"port": None,
},
'username@[2001:DB8::abcd:abcd]:path/example.git': {
'is_ssh_url': True,
'get_fqdn': '[2001:DB8::abcd:abcd]',
'add_host_key_cmd': " -t rsa [2001:DB8::abcd:abcd]",
'port': None,
"username@[2001:DB8::abcd:abcd]:path/example.git": {
"is_ssh_url": True,
"get_fqdn": "[2001:DB8::abcd:abcd]",
"add_host_key_cmd": " -t rsa [2001:DB8::abcd:abcd]",
"port": None,
},
'ssh://internal.git.server:7999/repos/repo.git': {
'is_ssh_url': True,
'get_fqdn': 'internal.git.server',
'add_host_key_cmd': " -t rsa -p 7999 internal.git.server",
'port': '7999',
"ssh://internal.git.server:7999/repos/repo.git": {
"is_ssh_url": True,
"get_fqdn": "internal.git.server",
"add_host_key_cmd": " -t rsa -p 7999 internal.git.server",
"port": "7999",
},
}
@pytest.mark.parametrize('url, is_ssh_url', ((k, URLS[k]['is_ssh_url']) for k in sorted(URLS)))
@pytest.mark.parametrize("url, is_ssh_url", ((k, URLS[k]["is_ssh_url"]) for k in sorted(URLS)))
def test_is_ssh_url(url, is_ssh_url):
assert known_hosts.is_ssh_url(url) == is_ssh_url
@pytest.mark.parametrize('url, fqdn, port', ((k, URLS[k]['get_fqdn'], URLS[k]['port']) for k in sorted(URLS)))
@pytest.mark.parametrize("url, fqdn, port", ((k, URLS[k]["get_fqdn"], URLS[k]["port"]) for k in sorted(URLS)))
def test_get_fqdn_and_port(url, fqdn, port):
assert known_hosts.get_fqdn_and_port(url) == (fqdn, port)
@pytest.mark.parametrize('fqdn, port, add_host_key_cmd',
((URLS[k]['get_fqdn'], URLS[k]['port'], URLS[k]['add_host_key_cmd'])
for k in sorted(URLS) if URLS[k]['is_ssh_url']))
@pytest.mark.parametrize(
"fqdn, port, add_host_key_cmd",
(
(URLS[k]["get_fqdn"], URLS[k]["port"], URLS[k]["add_host_key_cmd"])
for k in sorted(URLS)
if URLS[k]["is_ssh_url"]
),
)
def test_add_host_key(mocker, fqdn, port, add_host_key_cmd):
am = mocker.MagicMock()
@@ -109,8 +114,8 @@ def test_add_host_key(mocker, fqdn, port, add_host_key_cmd):
append_to_file.return_value = (None,)
am.append_to_file = append_to_file
mocker.patch('os.path.isdir', return_value=True)
mocker.patch('os.path.exists', return_value=True)
mocker.patch("os.path.isdir", return_value=True)
mocker.patch("os.path.exists", return_value=True)
known_hosts.add_host_key(am, fqdn, port=port)
run_command.assert_called_with(keyscan_cmd + add_host_key_cmd)

View File

@@ -7,9 +7,7 @@ from __future__ import annotations
import pytest
from ansible_collections.community.general.plugins.module_utils.module_helper import (
cause_changes
)
from ansible_collections.community.general.plugins.module_utils.module_helper import cause_changes
#
@@ -17,7 +15,7 @@ from ansible_collections.community.general.plugins.module_utils.module_helper im
# Parameters on_success and on_failure are deprecated and will be removed in community.general 12.0.0
# Remove testcases with those params when releasing 12.0.0
#
CAUSE_CHG_DECO_PARAMS = ['deco_args', 'expect_exception', 'expect_changed']
CAUSE_CHG_DECO_PARAMS = ["deco_args", "expect_exception", "expect_changed"]
CAUSE_CHG_DECO = dict(
none_succ=dict(deco_args={}, expect_exception=False, expect_changed=None),
none_fail=dict(deco_args={}, expect_exception=True, expect_changed=None),
@@ -31,13 +29,12 @@ CAUSE_CHG_DECO = dict(
CAUSE_CHG_DECO_IDS = sorted(CAUSE_CHG_DECO.keys())
@pytest.mark.parametrize(CAUSE_CHG_DECO_PARAMS,
[[CAUSE_CHG_DECO[tc][param]
for param in CAUSE_CHG_DECO_PARAMS]
for tc in CAUSE_CHG_DECO_IDS],
ids=CAUSE_CHG_DECO_IDS)
@pytest.mark.parametrize(
CAUSE_CHG_DECO_PARAMS,
[[CAUSE_CHG_DECO[tc][param] for param in CAUSE_CHG_DECO_PARAMS] for tc in CAUSE_CHG_DECO_IDS],
ids=CAUSE_CHG_DECO_IDS,
)
def test_cause_changes_deco(deco_args, expect_exception, expect_changed):
class MockMH:
changed = None

View File

@@ -16,11 +16,13 @@ from ansible_collections.community.general.plugins.module_utils.ocapi_utils impo
class TestOcapiUtils(unittest.TestCase):
def setUp(self):
self.tempdir = tempfile.mkdtemp()
self.utils = OcapiUtils(creds={"user": "a_user", "pswd": "a_password"},
base_uri="fakeUri",
proxy_slot_number=None,
timeout=30,
module=None)
self.utils = OcapiUtils(
creds={"user": "a_user", "pswd": "a_password"},
base_uri="fakeUri",
proxy_slot_number=None,
timeout=30,
module=None,
)
def tearDown(self):
shutil.rmtree(self.tempdir)
@@ -29,8 +31,8 @@ class TestOcapiUtils(unittest.TestCase):
# Generate a binary file and save it
filename = "fake_firmware.bin"
filepath = os.path.join(self.tempdir, filename)
file_contents = b'\x00\x01\x02\x03\x04'
with open(filepath, 'wb+') as f:
file_contents = b"\x00\x01\x02\x03\x04"
with open(filepath, "wb+") as f:
f.write(file_contents)
# Call prepare_mutipart_firmware_upload
@@ -43,10 +45,10 @@ class TestOcapiUtils(unittest.TestCase):
# Check the returned binary data
boundary = m.group(1)
expected_content_text = f'--{boundary}\r\n'
expected_content_text = f"--{boundary}\r\n"
expected_content_text += f'Content-Disposition: form-data; name="FirmwareFile"; filename="{filename}"\r\n'
expected_content_text += 'Content-Type: application/octet-stream\r\n\r\n'
expected_content_bytes = bytearray(expected_content_text, 'utf-8')
expected_content_text += "Content-Type: application/octet-stream\r\n\r\n"
expected_content_bytes = bytearray(expected_content_text, "utf-8")
expected_content_bytes += file_contents
expected_content_bytes += bytearray(f'\r\n--{boundary}--', 'utf-8')
expected_content_bytes += bytearray(f"\r\n--{boundary}--", "utf-8")
self.assertEqual(expected_content_bytes, b_form_data)

View File

@@ -12,36 +12,12 @@ from ansible_collections.community.general.plugins.module_utils.opennebula impor
FLATTEN_VALID = [
(
[[[1]], [2], 3],
False,
[1, 2, 3]
),
(
[[[1]], [2], 3],
True,
[1, 2, 3]
),
(
[[1]],
False,
[1]
),
(
[[1]],
True,
1
),
(
1,
False,
[1]
),
(
1,
True,
1
),
([[[1]], [2], 3], False, [1, 2, 3]),
([[[1]], [2], 3], True, [1, 2, 3]),
([[1]], False, [1]),
([[1]], True, 1),
(1, False, [1]),
(1, True, 1),
]
RENDER_VALID = [
@@ -51,11 +27,11 @@ RENDER_VALID = [
"CPU": 1,
"MEMORY": 1024,
},
textwrap.dedent('''
textwrap.dedent("""
CPU="1"
MEMORY="1024"
NIC=[NAME="NIC0",NETWORK_ID="0"]
''').strip()
""").strip(),
),
(
{
@@ -66,35 +42,35 @@ RENDER_VALID = [
"CPU": 1,
"MEMORY": 1024,
},
textwrap.dedent('''
textwrap.dedent("""
CPU="1"
MEMORY="1024"
NIC=[NAME="NIC0",NETWORK_ID="0"]
NIC=[NAME="NIC1",NETWORK_ID="1"]
''').strip()
""").strip(),
),
(
{
'EMPTY_VALUE': None,
'SCHED_REQUIREMENTS': 'CLUSTER_ID="100"',
'BACKSLASH_ESCAPED': "this is escaped: \\n; this isn't: \"\nend",
"EMPTY_VALUE": None,
"SCHED_REQUIREMENTS": 'CLUSTER_ID="100"',
"BACKSLASH_ESCAPED": "this is escaped: \\n; this isn't: \"\nend",
},
textwrap.dedent('''
textwrap.dedent("""
BACKSLASH_ESCAPED="this is escaped: \\\\n; this isn't: \\"
end"
SCHED_REQUIREMENTS="CLUSTER_ID=\\"100\\""
''').strip()
""").strip(),
),
]
@pytest.mark.parametrize('to_flatten,extract,expected_result', FLATTEN_VALID)
@pytest.mark.parametrize("to_flatten,extract,expected_result", FLATTEN_VALID)
def test_flatten(to_flatten, extract, expected_result):
result = flatten(to_flatten, extract)
assert result == expected_result, repr(result)
@pytest.mark.parametrize('to_render,expected_result', RENDER_VALID)
@pytest.mark.parametrize("to_render,expected_result", RENDER_VALID)
def test_render(to_render, expected_result):
result = render(to_render)
assert result == expected_result, repr(result)

View File

@@ -70,14 +70,14 @@ TC_RUNNER = dict(
bb=dict(fmt_func=cmd_runner_fmt.as_bool, fmt_arg="--bb-here"),
),
runner_init_args=dict(command="testing"),
runner_ctx_args=dict(args_order=['aa', 'bb']),
runner_ctx_args=dict(args_order=["aa", "bb"]),
),
dict(runner_ctx_run_args=dict(bb=True), rc=0, out="", err=""),
dict(
run_info=dict(
cmd=['/mock/bin/python', 'testing', '--answer=11', '--bb-here'],
environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'},
args_order=('aa', 'bb'),
cmd=["/mock/bin/python", "testing", "--answer=11", "--bb-here"],
environ_update={"LANGUAGE": "C", "LC_ALL": "C"},
args_order=("aa", "bb"),
),
),
),
@@ -88,14 +88,14 @@ TC_RUNNER = dict(
bb=dict(fmt_func=cmd_runner_fmt.as_bool, fmt_arg="--bb-here"),
),
runner_init_args=dict(command="toasting", python="python3"),
runner_ctx_args=dict(args_order=['aa', 'bb']),
runner_ctx_args=dict(args_order=["aa", "bb"]),
),
dict(runner_ctx_run_args=dict(bb=True), rc=0, out="", err=""),
dict(
run_info=dict(
cmd=['/mock/bin/python3', 'toasting', '--answer=11', '--bb-here'],
environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'},
args_order=('aa', 'bb'),
cmd=["/mock/bin/python3", "toasting", "--answer=11", "--bb-here"],
environ_update={"LANGUAGE": "C", "LC_ALL": "C"},
args_order=("aa", "bb"),
),
),
),
@@ -106,14 +106,14 @@ TC_RUNNER = dict(
bb=dict(fmt_func=cmd_runner_fmt.as_bool, fmt_arg="--bb-here"),
),
runner_init_args=dict(command="toasting", python="/crazy/local/bin/python3"),
runner_ctx_args=dict(args_order=['aa', 'bb']),
runner_ctx_args=dict(args_order=["aa", "bb"]),
),
dict(runner_ctx_run_args=dict(bb=True), rc=0, out="", err=""),
dict(
run_info=dict(
cmd=['/crazy/local/bin/python3', 'toasting', '--answer=11', '--bb-here'],
environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C'},
args_order=('aa', 'bb'),
cmd=["/crazy/local/bin/python3", "toasting", "--answer=11", "--bb-here"],
environ_update={"LANGUAGE": "C", "LC_ALL": "C"},
args_order=("aa", "bb"),
),
),
),
@@ -124,14 +124,14 @@ TC_RUNNER = dict(
bb=dict(fmt_func=cmd_runner_fmt.as_bool, fmt_arg="--bb-here"),
),
runner_init_args=dict(command="toasting", venv="/venv"),
runner_ctx_args=dict(args_order=['aa', 'bb']),
runner_ctx_args=dict(args_order=["aa", "bb"]),
),
dict(runner_ctx_run_args=dict(bb=True), rc=0, out="", err=""),
dict(
run_info=dict(
cmd=['/venv/bin/python', 'toasting', '--answer=11', '--bb-here'],
environ_update={'LANGUAGE': 'C', 'LC_ALL': 'C', 'VIRTUAL_ENV': '/venv', 'PATH': '/venv/bin'},
args_order=('aa', 'bb'),
cmd=["/venv/bin/python", "toasting", "--answer=11", "--bb-here"],
environ_update={"LANGUAGE": "C", "LC_ALL": "C", "VIRTUAL_ENV": "/venv", "PATH": "/venv/bin"},
args_order=("aa", "bb"),
),
),
),
@@ -139,28 +139,28 @@ TC_RUNNER = dict(
TC_RUNNER_IDS = sorted(TC_RUNNER.keys())
@pytest.mark.parametrize('runner_input, cmd_execution, expected',
(TC_RUNNER[tc] for tc in TC_RUNNER_IDS),
ids=TC_RUNNER_IDS)
@pytest.mark.parametrize(
"runner_input, cmd_execution, expected", (TC_RUNNER[tc] for tc in TC_RUNNER_IDS), ids=TC_RUNNER_IDS
)
def test_runner_context(runner_input, cmd_execution, expected):
arg_spec = {}
params = {}
arg_formats = {}
for k, v in runner_input['args_bundle'].items():
for k, v in runner_input["args_bundle"].items():
try:
arg_spec[k] = {'type': v['type']}
arg_spec[k] = {"type": v["type"]}
except KeyError:
pass
try:
params[k] = v['value']
params[k] = v["value"]
except KeyError:
pass
try:
arg_formats[k] = v['fmt_func'](v['fmt_arg'])
arg_formats[k] = v["fmt_func"](v["fmt_arg"])
except KeyError:
pass
orig_results = tuple(cmd_execution[x] for x in ('rc', 'out', 'err'))
orig_results = tuple(cmd_execution[x] for x in ("rc", "out", "err"))
print(f"arg_spec={arg_spec}\nparams={params}\narg_formats={arg_formats}\n")
@@ -170,24 +170,16 @@ def test_runner_context(runner_input, cmd_execution, expected):
module.get_bin_path.return_value = os.path.join(
runner_input["runner_init_args"].get("venv", "/mock"),
"bin",
runner_input["runner_init_args"].get("python", "python")
runner_input["runner_init_args"].get("python", "python"),
)
module.run_command.return_value = orig_results
runner = PythonRunner(
module=module,
arg_formats=arg_formats,
**runner_input['runner_init_args']
)
runner = PythonRunner(module=module, arg_formats=arg_formats, **runner_input["runner_init_args"])
def _extract_path(run_info):
path = run_info.get("environ_update", {}).get("PATH")
if path is not None:
run_info["environ_update"] = {
k: v
for k, v in run_info["environ_update"].items()
if k != "PATH"
}
run_info["environ_update"] = {k: v for k, v in run_info["environ_update"].items() if k != "PATH"}
return run_info, path
def _assert_run_info_env_path(actual, expected):
@@ -203,17 +195,17 @@ def test_runner_context(runner_input, cmd_execution, expected):
assert reduced == expected, f"{reduced}"
def _assert_run(expected, ctx, results):
_assert_run_info(ctx.run_info, expected['run_info'])
assert results == expected.get('results', orig_results)
_assert_run_info(ctx.run_info, expected["run_info"])
assert results == expected.get("results", orig_results)
exc = expected.get("exc")
if exc:
with pytest.raises(exc):
with runner.context(**runner_input['runner_ctx_args']) as ctx:
results = ctx.run(**cmd_execution['runner_ctx_run_args'])
with runner.context(**runner_input["runner_ctx_args"]) as ctx:
results = ctx.run(**cmd_execution["runner_ctx_run_args"])
_assert_run(expected, ctx, results)
else:
with runner.context(**runner_input['runner_ctx_args']) as ctx:
results = ctx.run(**cmd_execution['runner_ctx_run_args'])
with runner.context(**runner_input["runner_ctx_args"]) as ctx:
results = ctx.run(**cmd_execution["runner_ctx_run_args"])
_assert_run(expected, ctx, results)

View File

@@ -11,45 +11,45 @@ from ansible_collections.community.general.plugins.module_utils.saslprep import
VALID = [
('', ''),
('\u00A0', ' '),
('a', 'a'),
('й', 'й'),
('\u30DE\u30C8\u30EA\u30C3\u30AF\u30B9', '\u30DE\u30C8\u30EA\u30C3\u30AF\u30B9'),
('The\u00ADM\u00AAtr\u2168', 'TheMatrIX'),
('I\u00ADX', 'IX'),
('user', 'user'),
('USER', 'USER'),
('\u00AA', 'a'),
('\u2168', 'IX'),
('\u05BE\u00A0\u05BE', '\u05BE\u0020\u05BE'),
("", ""),
("\u00a0", " "),
("a", "a"),
("й", "й"),
("\u30de\u30c8\u30ea\u30c3\u30af\u30b9", "\u30de\u30c8\u30ea\u30c3\u30af\u30b9"),
("The\u00adM\u00aatr\u2168", "TheMatrIX"),
("I\u00adX", "IX"),
("user", "user"),
("USER", "USER"),
("\u00aa", "a"),
("\u2168", "IX"),
("\u05be\u00a0\u05be", "\u05be\u0020\u05be"),
]
INVALID = [
(None, TypeError),
(b'', TypeError),
('\u0221', ValueError),
('\u0007', ValueError),
('\u0627\u0031', ValueError),
('\uE0001', ValueError),
('\uE0020', ValueError),
('\uFFF9', ValueError),
('\uFDD0', ValueError),
('\u0000', ValueError),
('\u06DD', ValueError),
('\uFFFFD', ValueError),
('\uD800', ValueError),
('\u200E', ValueError),
('\u05BE\u00AA\u05BE', ValueError),
(b"", TypeError),
("\u0221", ValueError),
("\u0007", ValueError),
("\u0627\u0031", ValueError),
("\ue0001", ValueError),
("\ue0020", ValueError),
("\ufff9", ValueError),
("\ufdd0", ValueError),
("\u0000", ValueError),
("\u06dd", ValueError),
("\uffffD", ValueError),
("\ud800", ValueError),
("\u200e", ValueError),
("\u05be\u00aa\u05be", ValueError),
]
@pytest.mark.parametrize('source,target', VALID)
@pytest.mark.parametrize("source,target", VALID)
def test_saslprep_conversions(source, target):
assert saslprep(source) == target
@pytest.mark.parametrize('source,exception', INVALID)
@pytest.mark.parametrize("source,exception", INVALID)
def test_saslprep_exceptions(source, exception):
with pytest.raises(exception) as ex:
saslprep(source)

View File

@@ -22,8 +22,15 @@ class FakeModule:
def test_combine_headers_returns_only_default():
expected = {"Accept": "application/json", "Content-type": "application/json"}
module = FakeModule(
params={'utm_protocol': 'utm_protocol', 'utm_host': 'utm_host', 'utm_port': 1234, 'utm_token': 'utm_token',
'name': 'FakeName', 'headers': {}})
params={
"utm_protocol": "utm_protocol",
"utm_host": "utm_host",
"utm_port": 1234,
"utm_token": "utm_token",
"name": "FakeName",
"headers": {},
}
)
result = UTM(module, "endpoint", [])._combine_headers()
assert result == expected
@@ -31,17 +38,29 @@ def test_combine_headers_returns_only_default():
def test_combine_headers_returns_only_default2():
expected = {"Accept": "application/json", "Content-type": "application/json"}
module = FakeModule(
params={'utm_protocol': 'utm_protocol', 'utm_host': 'utm_host', 'utm_port': 1234, 'utm_token': 'utm_token',
'name': 'FakeName'})
params={
"utm_protocol": "utm_protocol",
"utm_host": "utm_host",
"utm_port": 1234,
"utm_token": "utm_token",
"name": "FakeName",
}
)
result = UTM(module, "endpoint", [])._combine_headers()
assert result == expected
def test_combine_headers_returns_combined():
expected = {"Accept": "application/json", "Content-type": "application/json",
"extraHeader": "extraHeaderValue"}
module = FakeModule(params={'utm_protocol': 'utm_protocol', 'utm_host': 'utm_host', 'utm_port': 1234,
'utm_token': 'utm_token', 'name': 'FakeName',
"headers": {"extraHeader": "extraHeaderValue"}})
expected = {"Accept": "application/json", "Content-type": "application/json", "extraHeader": "extraHeaderValue"}
module = FakeModule(
params={
"utm_protocol": "utm_protocol",
"utm_host": "utm_host",
"utm_port": 1234,
"utm_token": "utm_token",
"name": "FakeName",
"headers": {"extraHeader": "extraHeaderValue"},
}
)
result = UTM(module, "endpoint", [])._combine_headers()
assert result == expected

View File

@@ -80,7 +80,9 @@ def test_var_diff_dict():
vd.set("aa", 123, diff=True)
vd.aa = 456
assert vd.diff() == {"before": {"aa": 123, "dd": val_before}, "after": {"aa": 456, "dd": val_after}}, f"actual={vd.diff()}"
assert vd.diff() == {"before": {"aa": 123, "dd": val_before}, "after": {"aa": 456, "dd": val_after}}, (
f"actual={vd.diff()}"
)
def test_vardict_set_meta():

View File

@@ -17,9 +17,7 @@ class Failure(Exception):
class Session:
def __init__(self, uri, transport=None, encoding=None, verbose=0,
allow_none=1, ignore_ssl=False):
def __init__(self, uri, transport=None, encoding=None, verbose=0, allow_none=1, ignore_ssl=False):
self.transport = transport
self._session = None
self.last_login_method = None
@@ -42,10 +40,10 @@ class Session:
self.API_version = FAKE_API_VERSION
def xenapi_request(self, methodname, params):
if methodname.startswith('login'):
if methodname.startswith("login"):
self._login(methodname, params)
return None
elif methodname == 'logout' or methodname == 'session.logout':
elif methodname == "logout" or methodname == "session.logout":
self._logout()
return None
else:
@@ -53,14 +51,14 @@ class Session:
return None
def __getattr__(self, name):
if name == 'handle':
if name == "handle":
return self._session
elif name == 'xenapi':
elif name == "xenapi":
# Should be patched with mocker.patch().
return None
elif name.startswith('login') or name.startswith('slave_local'):
elif name.startswith("login") or name.startswith("slave_local"):
return lambda *params: self._login(name, params)
elif name == 'logout':
elif name == "logout":
return self._logout

View File

@@ -13,12 +13,12 @@ def fake_xenapi_ref(xenapi_class):
testcase_bad_xenapi_refs = {
"params": [
None,
'',
'OpaqueRef:NULL',
"",
"OpaqueRef:NULL",
],
"ids": [
'none',
'empty',
'ref-null',
"none",
"empty",
"ref-null",
],
}

View File

@@ -20,7 +20,7 @@ from .FakeAnsibleModule import FakeAnsibleModule
@pytest.fixture
def fake_ansible_module(request):
"""Returns fake AnsibleModule with fake module params."""
if hasattr(request, 'param'):
if hasattr(request, "param"):
return FakeAnsibleModule(request.param)
else:
params = {
@@ -42,12 +42,14 @@ def XenAPI():
# First we use importlib.import_module() to import the module and assign
# it to a local symbol.
fake_xenapi = importlib.import_module('ansible_collections.community.general.tests.unit.plugins.module_utils.xenserver.FakeXenAPI')
fake_xenapi = importlib.import_module(
"ansible_collections.community.general.tests.unit.plugins.module_utils.xenserver.FakeXenAPI"
)
# Now we populate Python module cache with imported fake module using the
# original module name (XenAPI). That way, any 'import XenAPI' statement
# will just load already imported fake module from the cache.
sys.modules['XenAPI'] = fake_xenapi
sys.modules["XenAPI"] = fake_xenapi
return fake_xenapi
@@ -83,7 +85,7 @@ def mock_xenapi_failure(XenAPI, mocker):
child_mock.side_effect = self.side_effect
return child_mock
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', new=MagicMockSideEffect(), create=True)
mocked_xenapi = mocker.patch.object(XenAPI.Session, "xenapi", new=MagicMockSideEffect(), create=True)
mocked_xenapi.side_effect = XenAPI.Failure(fake_error_msg)
return mocked_xenapi, fake_error_msg
@@ -92,10 +94,10 @@ def mock_xenapi_failure(XenAPI, mocker):
@pytest.fixture
def fixture_data_from_file(request):
"""Loads fixture data from files."""
if not hasattr(request, 'param'):
if not hasattr(request, "param"):
return {}
fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
fixture_path = os.path.join(os.path.dirname(__file__), "fixtures")
fixture_data = {}
if isinstance(request.param, str):

View File

@@ -25,7 +25,7 @@ testcase_gather_vm_params_and_facts = {
}
@pytest.mark.parametrize('vm_ref', testcase_bad_xenapi_refs['params'], ids=testcase_bad_xenapi_refs['ids']) # type: ignore
@pytest.mark.parametrize("vm_ref", testcase_bad_xenapi_refs["params"], ids=testcase_bad_xenapi_refs["ids"]) # type: ignore
def test_gather_vm_params_bad_vm_ref(fake_ansible_module, xenserver, vm_ref):
"""Tests return of empty dict on bad vm_ref."""
assert xenserver.gather_vm_params(fake_ansible_module, vm_ref) == {}
@@ -37,13 +37,15 @@ def test_gather_vm_facts_no_vm_params(fake_ansible_module, xenserver):
assert xenserver.gather_vm_facts(fake_ansible_module, {}) == {}
@pytest.mark.parametrize('fixture_data_from_file',
testcase_gather_vm_params_and_facts['params'], # type: ignore
ids=testcase_gather_vm_params_and_facts['ids'], # type: ignore
indirect=True)
@pytest.mark.parametrize(
"fixture_data_from_file",
testcase_gather_vm_params_and_facts["params"], # type: ignore
ids=testcase_gather_vm_params_and_facts["ids"], # type: ignore
indirect=True,
)
def test_gather_vm_params_and_facts(mocker, fake_ansible_module, XenAPI, xenserver, fixture_data_from_file):
"""Tests proper parsing of VM parameters and facts."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_xenapi = mocker.patch.object(XenAPI.Session, "xenapi", create=True)
if "params" in list(fixture_data_from_file.keys())[0]:
params_file = list(fixture_data_from_file.keys())[0]
@@ -53,21 +55,29 @@ def test_gather_vm_params_and_facts(mocker, fake_ansible_module, XenAPI, xenserv
facts_file = list(fixture_data_from_file.keys())[0]
mocked_returns = {
"VM.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]['VM'][obj_ref],
"VM_metrics.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]['VM_metrics'][obj_ref],
"VM_guest_metrics.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]['VM_guest_metrics'][obj_ref],
"VBD.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]['VBD'][obj_ref],
"VDI.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]['VDI'][obj_ref],
"SR.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]['SR'][obj_ref],
"VIF.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]['VIF'][obj_ref],
"network.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]['network'][obj_ref],
"host.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]['host'][obj_ref],
"VM.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]["VM"][obj_ref],
"VM_metrics.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]["VM_metrics"][obj_ref],
"VM_guest_metrics.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file][
"VM_guest_metrics"
][obj_ref],
"VBD.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]["VBD"][obj_ref],
"VDI.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]["VDI"][obj_ref],
"SR.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]["SR"][obj_ref],
"VIF.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]["VIF"][obj_ref],
"network.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]["network"][obj_ref],
"host.get_record.side_effect": lambda obj_ref: fixture_data_from_file[params_file]["host"][obj_ref],
}
mocked_xenapi.configure_mock(**mocked_returns)
mocker.patch('ansible_collections.community.general.plugins.module_utils.xenserver.get_xenserver_version', return_value=[7, 2, 0])
mocker.patch(
"ansible_collections.community.general.plugins.module_utils.xenserver.get_xenserver_version",
return_value=[7, 2, 0],
)
vm_ref = list(fixture_data_from_file[params_file]['VM'].keys())[0]
vm_ref = list(fixture_data_from_file[params_file]["VM"].keys())[0]
assert xenserver.gather_vm_facts(fake_ansible_module, xenserver.gather_vm_params(fake_ansible_module, vm_ref)) == fixture_data_from_file[facts_file]
assert (
xenserver.gather_vm_facts(fake_ansible_module, xenserver.gather_vm_params(fake_ansible_module, vm_ref))
== fixture_data_from_file[facts_file]
)

View File

@@ -14,59 +14,67 @@ from .common import fake_xenapi_ref
def test_get_object_ref_xenapi_failure(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests catching of XenAPI failures."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi_request', side_effect=XenAPI.Failure('Fake XAPI method call error!'))
mocked_xenapi = mocker.patch.object(
XenAPI.Session, "xenapi_request", side_effect=XenAPI.Failure("Fake XAPI method call error!")
)
with pytest.raises(FailJsonException) as exc_info:
xenserver.get_object_ref(fake_ansible_module, "name")
assert exc_info.value.kwargs['msg'] == "XAPI ERROR: Fake XAPI method call error!"
assert exc_info.value.kwargs["msg"] == "XAPI ERROR: Fake XAPI method call error!"
def test_get_object_ref_bad_uuid_and_name(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests failure on bad object uuid and/or name."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi_request')
mocked_xenapi = mocker.patch.object(XenAPI.Session, "xenapi_request")
with pytest.raises(FailJsonException) as exc_info:
xenserver.get_object_ref(fake_ansible_module, None, msg_prefix="Test: ")
mocked_xenapi.xenapi_request.assert_not_called()
assert exc_info.value.kwargs['msg'] == "Test: no valid name or UUID supplied for VM!"
assert exc_info.value.kwargs["msg"] == "Test: no valid name or UUID supplied for VM!"
def test_get_object_ref_uuid_not_found(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests when object is not found by uuid."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi_request', side_effect=XenAPI.Failure('Fake XAPI not found error!'))
mocked_xenapi = mocker.patch.object(
XenAPI.Session, "xenapi_request", side_effect=XenAPI.Failure("Fake XAPI not found error!")
)
with pytest.raises(FailJsonException) as exc_info:
xenserver.get_object_ref(fake_ansible_module, "name", uuid="fake-uuid", msg_prefix="Test: ")
assert exc_info.value.kwargs['msg'] == "Test: VM with UUID 'fake-uuid' not found!"
assert xenserver.get_object_ref(fake_ansible_module, "name", uuid="fake-uuid", fail=False, msg_prefix="Test: ") is None
assert exc_info.value.kwargs["msg"] == "Test: VM with UUID 'fake-uuid' not found!"
assert (
xenserver.get_object_ref(fake_ansible_module, "name", uuid="fake-uuid", fail=False, msg_prefix="Test: ") is None
)
def test_get_object_ref_name_not_found(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests when object is not found by name."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi_request', return_value=[])
mocked_xenapi = mocker.patch.object(XenAPI.Session, "xenapi_request", return_value=[])
with pytest.raises(FailJsonException) as exc_info:
xenserver.get_object_ref(fake_ansible_module, "name", msg_prefix="Test: ")
assert exc_info.value.kwargs['msg'] == "Test: VM with name 'name' not found!"
assert exc_info.value.kwargs["msg"] == "Test: VM with name 'name' not found!"
assert xenserver.get_object_ref(fake_ansible_module, "name", fail=False, msg_prefix="Test: ") is None
def test_get_object_ref_name_multiple_found(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests when multiple objects are found by name."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi_request', return_value=[fake_xenapi_ref('VM'), fake_xenapi_ref('VM')])
mocked_xenapi = mocker.patch.object(
XenAPI.Session, "xenapi_request", return_value=[fake_xenapi_ref("VM"), fake_xenapi_ref("VM")]
)
error_msg = "Test: multiple VMs with name 'name' found! Please use UUID."
with pytest.raises(FailJsonException) as exc_info:
xenserver.get_object_ref(fake_ansible_module, "name", msg_prefix="Test: ")
assert exc_info.value.kwargs['msg'] == error_msg
assert exc_info.value.kwargs["msg"] == error_msg
with pytest.raises(FailJsonException) as exc_info:
xenserver.get_object_ref(fake_ansible_module, "name", fail=False, msg_prefix="Test: ")
assert exc_info.value.kwargs['msg'] == error_msg
assert exc_info.value.kwargs["msg"] == error_msg

View File

@@ -11,171 +11,179 @@ import pytest
from ansible.module_utils.common.network import is_mac
testcase_is_valid_mac_addr = [
('A4-23-8D-F8-C9-E5', True),
('35:71:F4:11:0B:D8', True),
('b3-bd-20-59-0c-cf', True),
('32:61:ca:65:f1:f4', True),
('asdf', False),
('A4-23-8D-G8-C9-E5', False),
('A4-3-8D-F8-C9-E5', False),
('A4-23-88D-F8-C9-E5', False),
('A4-23-8D-F8-C9_E5', False),
('A4-23--8D-F8-C9-E5', False),
("A4-23-8D-F8-C9-E5", True),
("35:71:F4:11:0B:D8", True),
("b3-bd-20-59-0c-cf", True),
("32:61:ca:65:f1:f4", True),
("asdf", False),
("A4-23-8D-G8-C9-E5", False),
("A4-3-8D-F8-C9-E5", False),
("A4-23-88D-F8-C9-E5", False),
("A4-23-8D-F8-C9_E5", False),
("A4-23--8D-F8-C9-E5", False),
]
testcase_is_valid_ip_addr = [
('0.0.0.0', True),
('10.0.0.1', True),
('192.168.0.1', True),
('255.255.255.255', True),
('asdf', False),
('a.b.c.d', False),
('345.345.345.345', False),
('-10.0.0.1', False),
("0.0.0.0", True),
("10.0.0.1", True),
("192.168.0.1", True),
("255.255.255.255", True),
("asdf", False),
("a.b.c.d", False),
("345.345.345.345", False),
("-10.0.0.1", False),
]
testcase_is_valid_ip_netmask = [
('240.0.0.0', True),
('255.224.0.0', True),
('255.255.248.0', True),
('255.255.255.255', True),
('asdf', False),
('a.b.c.d', False),
('192.168.0.1', False),
('255.0.248.0', False),
("240.0.0.0", True),
("255.224.0.0", True),
("255.255.248.0", True),
("255.255.255.255", True),
("asdf", False),
("a.b.c.d", False),
("192.168.0.1", False),
("255.0.248.0", False),
]
testcase_is_valid_ip_prefix = [
('0', True),
('16', True),
('24', True),
('32', True),
('asdf', False),
('-10', False),
('60', False),
('60s', False),
("0", True),
("16", True),
("24", True),
("32", True),
("asdf", False),
("-10", False),
("60", False),
("60s", False),
]
testcase_ip_prefix_to_netmask = {
"params": [
('0', '0.0.0.0'),
('8', '255.0.0.0'),
('11', '255.224.0.0'),
('16', '255.255.0.0'),
('21', '255.255.248.0'),
('24', '255.255.255.0'),
('26', '255.255.255.192'),
('32', '255.255.255.255'),
('a', ''),
('60', ''),
("0", "0.0.0.0"),
("8", "255.0.0.0"),
("11", "255.224.0.0"),
("16", "255.255.0.0"),
("21", "255.255.248.0"),
("24", "255.255.255.0"),
("26", "255.255.255.192"),
("32", "255.255.255.255"),
("a", ""),
("60", ""),
],
"ids": [
'0',
'8',
'11',
'16',
'21',
'24',
'26',
'32',
'a',
'60',
"0",
"8",
"11",
"16",
"21",
"24",
"26",
"32",
"a",
"60",
],
}
testcase_ip_netmask_to_prefix = {
"params": [
('0.0.0.0', '0'),
('255.0.0.0', '8'),
('255.224.0.0', '11'),
('255.255.0.0', '16'),
('255.255.248.0', '21'),
('255.255.255.0', '24'),
('255.255.255.192', '26'),
('255.255.255.255', '32'),
('a', ''),
('60', ''),
("0.0.0.0", "0"),
("255.0.0.0", "8"),
("255.224.0.0", "11"),
("255.255.0.0", "16"),
("255.255.248.0", "21"),
("255.255.255.0", "24"),
("255.255.255.192", "26"),
("255.255.255.255", "32"),
("a", ""),
("60", ""),
],
"ids": [
'0.0.0.0',
'255.0.0.0',
'255.224.0.0',
'255.255.0.0',
'255.255.248.0',
'255.255.255.0',
'255.255.255.192',
'255.255.255.255',
'a',
'60',
"0.0.0.0",
"255.0.0.0",
"255.224.0.0",
"255.255.0.0",
"255.255.248.0",
"255.255.255.0",
"255.255.255.192",
"255.255.255.255",
"a",
"60",
],
}
testcase_is_valid_ip6_addr = [
('::1', True),
('2001:DB8:0:0:8:800:200C:417A', True),
('2001:DB8::8:800:200C:417A', True),
('FF01::101', True),
('asdf', False),
('2001:DB8:0:0:8:800:200C:417A:221', False),
('FF01::101::2', False),
('2001:db8:85a3::8a2e:370k:7334', False),
("::1", True),
("2001:DB8:0:0:8:800:200C:417A", True),
("2001:DB8::8:800:200C:417A", True),
("FF01::101", True),
("asdf", False),
("2001:DB8:0:0:8:800:200C:417A:221", False),
("FF01::101::2", False),
("2001:db8:85a3::8a2e:370k:7334", False),
]
testcase_is_valid_ip6_prefix = [
('0', True),
('56', True),
('78', True),
('128', True),
('asdf', False),
('-10', False),
('345', False),
('60s', False),
("0", True),
("56", True),
("78", True),
("128", True),
("asdf", False),
("-10", False),
("345", False),
("60s", False),
]
@pytest.mark.parametrize('mac_addr, result', testcase_is_valid_mac_addr)
@pytest.mark.parametrize("mac_addr, result", testcase_is_valid_mac_addr)
def test_is_valid_mac_addr(xenserver, mac_addr, result):
"""Tests against examples of valid and invalid mac addresses."""
assert is_mac(mac_addr) is result
@pytest.mark.parametrize('ip_addr, result', testcase_is_valid_ip_addr)
@pytest.mark.parametrize("ip_addr, result", testcase_is_valid_ip_addr)
def test_is_valid_ip_addr(xenserver, ip_addr, result):
"""Tests against examples of valid and invalid ip addresses."""
assert xenserver.is_valid_ip_addr(ip_addr) is result
@pytest.mark.parametrize('ip_netmask, result', testcase_is_valid_ip_netmask)
@pytest.mark.parametrize("ip_netmask, result", testcase_is_valid_ip_netmask)
def test_is_valid_ip_netmask(xenserver, ip_netmask, result):
"""Tests against examples of valid and invalid ip netmasks."""
assert xenserver.is_valid_ip_netmask(ip_netmask) is result
@pytest.mark.parametrize('ip_prefix, result', testcase_is_valid_ip_prefix)
@pytest.mark.parametrize("ip_prefix, result", testcase_is_valid_ip_prefix)
def test_is_valid_ip_prefix(xenserver, ip_prefix, result):
"""Tests against examples of valid and invalid ip prefixes."""
assert xenserver.is_valid_ip_prefix(ip_prefix) is result
@pytest.mark.parametrize('ip_prefix, ip_netmask', testcase_ip_prefix_to_netmask['params'], ids=testcase_ip_prefix_to_netmask['ids']) # type: ignore
@pytest.mark.parametrize(
"ip_prefix, ip_netmask",
testcase_ip_prefix_to_netmask["params"], # type: ignore
ids=testcase_ip_prefix_to_netmask["ids"], # type: ignore
)
def test_ip_prefix_to_netmask(xenserver, ip_prefix, ip_netmask):
"""Tests ip prefix to netmask conversion."""
assert xenserver.ip_prefix_to_netmask(ip_prefix) == ip_netmask
@pytest.mark.parametrize('ip_netmask, ip_prefix', testcase_ip_netmask_to_prefix['params'], ids=testcase_ip_netmask_to_prefix['ids']) # type: ignore
@pytest.mark.parametrize(
"ip_netmask, ip_prefix",
testcase_ip_netmask_to_prefix["params"], # type: ignore
ids=testcase_ip_netmask_to_prefix["ids"], # type: ignore
)
def test_ip_netmask_to_prefix(xenserver, ip_netmask, ip_prefix):
"""Tests ip netmask to prefix conversion."""
assert xenserver.ip_netmask_to_prefix(ip_netmask) == ip_prefix
@pytest.mark.parametrize('ip6_addr, result', testcase_is_valid_ip6_addr)
@pytest.mark.parametrize("ip6_addr, result", testcase_is_valid_ip6_addr)
def test_is_valid_ip6_addr(xenserver, ip6_addr, result):
"""Tests against examples of valid and invalid ip6 addresses."""
assert xenserver.is_valid_ip6_addr(ip6_addr) is result
@pytest.mark.parametrize('ip6_prefix, result', testcase_is_valid_ip6_prefix)
@pytest.mark.parametrize("ip6_prefix, result", testcase_is_valid_ip6_prefix)
def test_is_valid_ip6_prefix(xenserver, ip6_prefix, result):
"""Tests against examples of valid and invalid ip6 prefixes."""
assert xenserver.is_valid_ip6_prefix(ip6_prefix) is result

View File

@@ -14,16 +14,16 @@ from .common import fake_xenapi_ref, testcase_bad_xenapi_refs
testcase_set_vm_power_state_bad_transitions = {
"params": [
('restarted', 'Halted', "Cannot restart VM in state 'poweredoff'!"),
('restarted', 'Suspended', "Cannot restart VM in state 'suspended'!"),
('suspended', 'Halted', "Cannot suspend VM in state 'poweredoff'!"),
('suspended', 'Paused', "Cannot suspend VM in state 'paused'!"),
('shutdownguest', 'Halted', "Cannot shutdown guest when VM is in state 'poweredoff'!"),
('shutdownguest', 'Suspended', "Cannot shutdown guest when VM is in state 'suspended'!"),
('shutdownguest', 'Paused', "Cannot shutdown guest when VM is in state 'paused'!"),
('rebootguest', 'Halted', "Cannot reboot guest when VM is in state 'poweredoff'!"),
('rebootguest', 'Suspended', "Cannot reboot guest when VM is in state 'suspended'!"),
('rebootguest', 'Paused', "Cannot reboot guest when VM is in state 'paused'!"),
("restarted", "Halted", "Cannot restart VM in state 'poweredoff'!"),
("restarted", "Suspended", "Cannot restart VM in state 'suspended'!"),
("suspended", "Halted", "Cannot suspend VM in state 'poweredoff'!"),
("suspended", "Paused", "Cannot suspend VM in state 'paused'!"),
("shutdownguest", "Halted", "Cannot shutdown guest when VM is in state 'poweredoff'!"),
("shutdownguest", "Suspended", "Cannot shutdown guest when VM is in state 'suspended'!"),
("shutdownguest", "Paused", "Cannot shutdown guest when VM is in state 'paused'!"),
("rebootguest", "Halted", "Cannot reboot guest when VM is in state 'poweredoff'!"),
("rebootguest", "Suspended", "Cannot reboot guest when VM is in state 'suspended'!"),
("rebootguest", "Paused", "Cannot reboot guest when VM is in state 'paused'!"),
],
"ids": [
"poweredoff->restarted",
@@ -41,8 +41,8 @@ testcase_set_vm_power_state_bad_transitions = {
testcase_set_vm_power_state_task_timeout = {
"params": [
('shutdownguest', "Guest shutdown task failed: 'timeout'!"),
('rebootguest', "Guest reboot task failed: 'timeout'!"),
("shutdownguest", "Guest shutdown task failed: 'timeout'!"),
("rebootguest", "Guest reboot task failed: 'timeout'!"),
],
"ids": [
"shutdownguest-timeout",
@@ -52,16 +52,16 @@ testcase_set_vm_power_state_task_timeout = {
testcase_set_vm_power_state_no_transitions = {
"params": [
('poweredon', "Running"),
('Poweredon', "Running"),
('powered-on', "Running"),
('Powered_on', "Running"),
('poweredoff', "Halted"),
('Poweredoff', "Halted"),
('powered-off', "Halted"),
('powered_off', "Halted"),
('suspended', "Suspended"),
('Suspended', "Suspended"),
("poweredon", "Running"),
("Poweredon", "Running"),
("powered-on", "Running"),
("Powered_on", "Running"),
("poweredoff", "Halted"),
("Poweredoff", "Halted"),
("powered-off", "Halted"),
("powered_off", "Halted"),
("suspended", "Suspended"),
("Suspended", "Suspended"),
],
"ids": [
"poweredon",
@@ -79,44 +79,44 @@ testcase_set_vm_power_state_no_transitions = {
testcase_set_vm_power_state_transitions = {
"params": [
('poweredon', 'Halted', 'running', 'VM.start'),
('Poweredon', 'Halted', 'running', 'VM.start'),
('powered-on', 'Halted', 'running', 'VM.start'),
('Powered_on', 'Halted', 'running', 'VM.start'),
('poweredon', 'Suspended', 'running', 'VM.resume'),
('Poweredon', 'Suspended', 'running', 'VM.resume'),
('powered-on', 'Suspended', 'running', 'VM.resume'),
('Powered_on', 'Suspended', 'running', 'VM.resume'),
('poweredon', 'Paused', 'running', 'VM.unpause'),
('Poweredon', 'Paused', 'running', 'VM.unpause'),
('powered-on', 'Paused', 'running', 'VM.unpause'),
('Powered_on', 'Paused', 'running', 'VM.unpause'),
('poweredoff', 'Running', 'halted', 'VM.hard_shutdown'),
('Poweredoff', 'Running', 'halted', 'VM.hard_shutdown'),
('powered-off', 'Running', 'halted', 'VM.hard_shutdown'),
('powered_off', 'Running', 'halted', 'VM.hard_shutdown'),
('poweredoff', 'Suspended', 'halted', 'VM.hard_shutdown'),
('Poweredoff', 'Suspended', 'halted', 'VM.hard_shutdown'),
('powered-off', 'Suspended', 'halted', 'VM.hard_shutdown'),
('powered_off', 'Suspended', 'halted', 'VM.hard_shutdown'),
('poweredoff', 'Paused', 'halted', 'VM.hard_shutdown'),
('Poweredoff', 'Paused', 'halted', 'VM.hard_shutdown'),
('powered-off', 'Paused', 'halted', 'VM.hard_shutdown'),
('powered_off', 'Paused', 'halted', 'VM.hard_shutdown'),
('restarted', 'Running', 'running', 'VM.hard_reboot'),
('Restarted', 'Running', 'running', 'VM.hard_reboot'),
('restarted', 'Paused', 'running', 'VM.hard_reboot'),
('Restarted', 'Paused', 'running', 'VM.hard_reboot'),
('suspended', 'Running', 'suspended', 'VM.suspend'),
('Suspended', 'Running', 'suspended', 'VM.suspend'),
('shutdownguest', 'Running', 'halted', 'VM.clean_shutdown'),
('Shutdownguest', 'Running', 'halted', 'VM.clean_shutdown'),
('shutdown-guest', 'Running', 'halted', 'VM.clean_shutdown'),
('shutdown_guest', 'Running', 'halted', 'VM.clean_shutdown'),
('rebootguest', 'Running', 'running', 'VM.clean_reboot'),
('rebootguest', 'Running', 'running', 'VM.clean_reboot'),
('reboot-guest', 'Running', 'running', 'VM.clean_reboot'),
('reboot_guest', 'Running', 'running', 'VM.clean_reboot'),
("poweredon", "Halted", "running", "VM.start"),
("Poweredon", "Halted", "running", "VM.start"),
("powered-on", "Halted", "running", "VM.start"),
("Powered_on", "Halted", "running", "VM.start"),
("poweredon", "Suspended", "running", "VM.resume"),
("Poweredon", "Suspended", "running", "VM.resume"),
("powered-on", "Suspended", "running", "VM.resume"),
("Powered_on", "Suspended", "running", "VM.resume"),
("poweredon", "Paused", "running", "VM.unpause"),
("Poweredon", "Paused", "running", "VM.unpause"),
("powered-on", "Paused", "running", "VM.unpause"),
("Powered_on", "Paused", "running", "VM.unpause"),
("poweredoff", "Running", "halted", "VM.hard_shutdown"),
("Poweredoff", "Running", "halted", "VM.hard_shutdown"),
("powered-off", "Running", "halted", "VM.hard_shutdown"),
("powered_off", "Running", "halted", "VM.hard_shutdown"),
("poweredoff", "Suspended", "halted", "VM.hard_shutdown"),
("Poweredoff", "Suspended", "halted", "VM.hard_shutdown"),
("powered-off", "Suspended", "halted", "VM.hard_shutdown"),
("powered_off", "Suspended", "halted", "VM.hard_shutdown"),
("poweredoff", "Paused", "halted", "VM.hard_shutdown"),
("Poweredoff", "Paused", "halted", "VM.hard_shutdown"),
("powered-off", "Paused", "halted", "VM.hard_shutdown"),
("powered_off", "Paused", "halted", "VM.hard_shutdown"),
("restarted", "Running", "running", "VM.hard_reboot"),
("Restarted", "Running", "running", "VM.hard_reboot"),
("restarted", "Paused", "running", "VM.hard_reboot"),
("Restarted", "Paused", "running", "VM.hard_reboot"),
("suspended", "Running", "suspended", "VM.suspend"),
("Suspended", "Running", "suspended", "VM.suspend"),
("shutdownguest", "Running", "halted", "VM.clean_shutdown"),
("Shutdownguest", "Running", "halted", "VM.clean_shutdown"),
("shutdown-guest", "Running", "halted", "VM.clean_shutdown"),
("shutdown_guest", "Running", "halted", "VM.clean_shutdown"),
("rebootguest", "Running", "running", "VM.clean_reboot"),
("rebootguest", "Running", "running", "VM.clean_reboot"),
("reboot-guest", "Running", "running", "VM.clean_reboot"),
("reboot_guest", "Running", "running", "VM.clean_reboot"),
],
"ids": [
"poweredoff->poweredon",
@@ -162,14 +162,14 @@ testcase_set_vm_power_state_transitions = {
testcase_set_vm_power_state_transitions_async = {
"params": [
('shutdownguest', 'Running', 'halted', 'Async.VM.clean_shutdown'),
('Shutdownguest', 'Running', 'halted', 'Async.VM.clean_shutdown'),
('shutdown-guest', 'Running', 'halted', 'Async.VM.clean_shutdown'),
('shutdown_guest', 'Running', 'halted', 'Async.VM.clean_shutdown'),
('rebootguest', 'Running', 'running', 'Async.VM.clean_reboot'),
('rebootguest', 'Running', 'running', 'Async.VM.clean_reboot'),
('reboot-guest', 'Running', 'running', 'Async.VM.clean_reboot'),
('reboot_guest', 'Running', 'running', 'Async.VM.clean_reboot'),
("shutdownguest", "Running", "halted", "Async.VM.clean_shutdown"),
("Shutdownguest", "Running", "halted", "Async.VM.clean_shutdown"),
("shutdown-guest", "Running", "halted", "Async.VM.clean_shutdown"),
("shutdown_guest", "Running", "halted", "Async.VM.clean_shutdown"),
("rebootguest", "Running", "running", "Async.VM.clean_reboot"),
("rebootguest", "Running", "running", "Async.VM.clean_reboot"),
("reboot-guest", "Running", "running", "Async.VM.clean_reboot"),
("reboot_guest", "Running", "running", "Async.VM.clean_reboot"),
],
"ids": [
"poweredon->shutdownguest",
@@ -184,26 +184,26 @@ testcase_set_vm_power_state_transitions_async = {
}
@pytest.mark.parametrize('vm_ref', testcase_bad_xenapi_refs['params'], ids=testcase_bad_xenapi_refs['ids']) # type: ignore
@pytest.mark.parametrize("vm_ref", testcase_bad_xenapi_refs["params"], ids=testcase_bad_xenapi_refs["ids"]) # type: ignore
def test_set_vm_power_state_bad_vm_ref(fake_ansible_module, xenserver, vm_ref):
"""Tests failure on bad vm_ref."""
with pytest.raises(FailJsonException) as exc_info:
xenserver.set_vm_power_state(fake_ansible_module, vm_ref, None)
assert exc_info.value.kwargs['msg'] == "Cannot set VM power state. Invalid VM reference supplied!"
assert exc_info.value.kwargs["msg"] == "Cannot set VM power state. Invalid VM reference supplied!"
def test_set_vm_power_state_xenapi_failure(mock_xenapi_failure, fake_ansible_module, xenserver):
"""Tests catching of XenAPI failures."""
with pytest.raises(FailJsonException) as exc_info:
xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref('VM'), "poweredon")
xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref("VM"), "poweredon")
assert exc_info.value.kwargs['msg'] == f"XAPI ERROR: {mock_xenapi_failure[1]}"
assert exc_info.value.kwargs["msg"] == f"XAPI ERROR: {mock_xenapi_failure[1]}"
def test_set_vm_power_state_bad_power_state(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests failure on unsupported power state."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_xenapi = mocker.patch.object(XenAPI.Session, "xenapi", create=True)
mocked_returns = {
"VM.get_power_state.return_value": "Running",
@@ -212,21 +212,25 @@ def test_set_vm_power_state_bad_power_state(mocker, fake_ansible_module, XenAPI,
mocked_xenapi.configure_mock(**mocked_returns)
with pytest.raises(FailJsonException) as exc_info:
xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref('VM'), "bad")
xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref("VM"), "bad")
# Beside VM.get_power_state() no other method should have been
# called additionally.
assert len(mocked_xenapi.method_calls) == 1
assert exc_info.value.kwargs['msg'] == "Requested VM power state 'bad' is unsupported!"
assert exc_info.value.kwargs["msg"] == "Requested VM power state 'bad' is unsupported!"
@pytest.mark.parametrize('power_state_desired, power_state_current, error_msg',
testcase_set_vm_power_state_bad_transitions['params'], # type: ignore
ids=testcase_set_vm_power_state_bad_transitions['ids']) # type: ignore
def test_set_vm_power_state_bad_transition(mocker, fake_ansible_module, XenAPI, xenserver, power_state_desired, power_state_current, error_msg):
@pytest.mark.parametrize(
"power_state_desired, power_state_current, error_msg",
testcase_set_vm_power_state_bad_transitions["params"], # type: ignore
ids=testcase_set_vm_power_state_bad_transitions["ids"], # type: ignore
)
def test_set_vm_power_state_bad_transition(
mocker, fake_ansible_module, XenAPI, xenserver, power_state_desired, power_state_current, error_msg
):
"""Tests failure on bad power state transition."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_xenapi = mocker.patch.object(XenAPI.Session, "xenapi", create=True)
mocked_returns = {
"VM.get_power_state.return_value": power_state_current,
@@ -235,48 +239,56 @@ def test_set_vm_power_state_bad_transition(mocker, fake_ansible_module, XenAPI,
mocked_xenapi.configure_mock(**mocked_returns)
with pytest.raises(FailJsonException) as exc_info:
xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref('VM'), power_state_desired)
xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref("VM"), power_state_desired)
# Beside VM.get_power_state() no other method should have been
# called additionally.
assert len(mocked_xenapi.method_calls) == 1
assert exc_info.value.kwargs['msg'] == error_msg
assert exc_info.value.kwargs["msg"] == error_msg
@pytest.mark.parametrize('power_state, error_msg',
testcase_set_vm_power_state_task_timeout['params'], # type: ignore
ids=testcase_set_vm_power_state_task_timeout['ids']) # type: ignore
@pytest.mark.parametrize(
"power_state, error_msg",
testcase_set_vm_power_state_task_timeout["params"], # type: ignore
ids=testcase_set_vm_power_state_task_timeout["ids"], # type: ignore
)
def test_set_vm_power_state_task_timeout(mocker, fake_ansible_module, XenAPI, xenserver, power_state, error_msg):
"""Tests failure on async task timeout."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_xenapi = mocker.patch.object(XenAPI.Session, "xenapi", create=True)
mocked_returns = {
"VM.get_power_state.return_value": "Running",
"Async.VM.clean_shutdown.return_value": fake_xenapi_ref('task'),
"Async.VM.clean_reboot.return_value": fake_xenapi_ref('task'),
"Async.VM.clean_shutdown.return_value": fake_xenapi_ref("task"),
"Async.VM.clean_reboot.return_value": fake_xenapi_ref("task"),
}
mocked_xenapi.configure_mock(**mocked_returns)
mocker.patch('ansible_collections.community.general.plugins.module_utils.xenserver.wait_for_task', return_value="timeout")
mocker.patch(
"ansible_collections.community.general.plugins.module_utils.xenserver.wait_for_task", return_value="timeout"
)
with pytest.raises(FailJsonException) as exc_info:
xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref('VM'), power_state, timeout=1)
xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref("VM"), power_state, timeout=1)
# Beside VM.get_power_state() only one of Async.VM.clean_shutdown or
# Async.VM.clean_reboot should have been called additionally.
assert len(mocked_xenapi.method_calls) == 2
assert exc_info.value.kwargs['msg'] == error_msg
assert exc_info.value.kwargs["msg"] == error_msg
@pytest.mark.parametrize('power_state_desired, power_state_current',
testcase_set_vm_power_state_no_transitions['params'], # type: ignore
ids=testcase_set_vm_power_state_no_transitions['ids']) # type: ignore
def test_set_vm_power_state_no_transition(mocker, fake_ansible_module, XenAPI, xenserver, power_state_desired, power_state_current):
@pytest.mark.parametrize(
"power_state_desired, power_state_current",
testcase_set_vm_power_state_no_transitions["params"], # type: ignore
ids=testcase_set_vm_power_state_no_transitions["ids"], # type: ignore
)
def test_set_vm_power_state_no_transition(
mocker, fake_ansible_module, XenAPI, xenserver, power_state_desired, power_state_current
):
"""Tests regular invocation without power state transition."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_xenapi = mocker.patch.object(XenAPI.Session, "xenapi", create=True)
mocked_returns = {
"VM.get_power_state.return_value": power_state_current,
@@ -284,7 +296,7 @@ def test_set_vm_power_state_no_transition(mocker, fake_ansible_module, XenAPI, x
mocked_xenapi.configure_mock(**mocked_returns)
result = xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref('VM'), power_state_desired)
result = xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref("VM"), power_state_desired)
# Beside VM.get_power_state() no other method should have been
# called additionally.
@@ -294,19 +306,23 @@ def test_set_vm_power_state_no_transition(mocker, fake_ansible_module, XenAPI, x
assert result[1] == power_state_current.lower()
@pytest.mark.parametrize('power_state_desired, power_state_current, power_state_resulting, activated_xenapi_method',
testcase_set_vm_power_state_transitions['params'], # type: ignore
ids=testcase_set_vm_power_state_transitions['ids']) # type: ignore
def test_set_vm_power_state_transition(mocker,
fake_ansible_module,
XenAPI,
xenserver,
power_state_desired,
power_state_current,
power_state_resulting,
activated_xenapi_method):
@pytest.mark.parametrize(
"power_state_desired, power_state_current, power_state_resulting, activated_xenapi_method",
testcase_set_vm_power_state_transitions["params"], # type: ignore
ids=testcase_set_vm_power_state_transitions["ids"], # type: ignore
)
def test_set_vm_power_state_transition(
mocker,
fake_ansible_module,
XenAPI,
xenserver,
power_state_desired,
power_state_current,
power_state_resulting,
activated_xenapi_method,
):
"""Tests regular invocation with power state transition."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_xenapi = mocker.patch.object(XenAPI.Session, "xenapi", create=True)
mocked_returns = {
"VM.get_power_state.return_value": power_state_current,
@@ -314,11 +330,11 @@ def test_set_vm_power_state_transition(mocker,
mocked_xenapi.configure_mock(**mocked_returns)
result = xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref('VM'), power_state_desired, timeout=0)
result = xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref("VM"), power_state_desired, timeout=0)
mocked_xenapi_method = mocked_xenapi
for activated_xenapi_class in activated_xenapi_method.split('.'):
for activated_xenapi_class in activated_xenapi_method.split("."):
mocked_xenapi_method = getattr(mocked_xenapi_method, activated_xenapi_class)
mocked_xenapi_method.assert_called_once()
@@ -331,37 +347,41 @@ def test_set_vm_power_state_transition(mocker,
assert result[1] == power_state_resulting
@pytest.mark.parametrize('power_state_desired, power_state_current, power_state_resulting, activated_xenapi_method',
testcase_set_vm_power_state_transitions_async['params'], # type: ignore
ids=testcase_set_vm_power_state_transitions_async['ids']) # type: ignore
def test_set_vm_power_state_transition_async(mocker,
fake_ansible_module,
XenAPI,
xenserver,
power_state_desired,
power_state_current,
power_state_resulting,
activated_xenapi_method):
@pytest.mark.parametrize(
"power_state_desired, power_state_current, power_state_resulting, activated_xenapi_method",
testcase_set_vm_power_state_transitions_async["params"], # type: ignore
ids=testcase_set_vm_power_state_transitions_async["ids"], # type: ignore
)
def test_set_vm_power_state_transition_async(
mocker,
fake_ansible_module,
XenAPI,
xenserver,
power_state_desired,
power_state_current,
power_state_resulting,
activated_xenapi_method,
):
"""
Tests regular invocation with async power state transition
(shutdownguest and rebootguest only).
"""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_xenapi = mocker.patch.object(XenAPI.Session, "xenapi", create=True)
mocked_returns = {
"VM.get_power_state.return_value": power_state_current,
f"{activated_xenapi_method}.return_value": fake_xenapi_ref('task'),
f"{activated_xenapi_method}.return_value": fake_xenapi_ref("task"),
}
mocked_xenapi.configure_mock(**mocked_returns)
mocker.patch('ansible_collections.community.general.plugins.module_utils.xenserver.wait_for_task', return_value="")
mocker.patch("ansible_collections.community.general.plugins.module_utils.xenserver.wait_for_task", return_value="")
result = xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref('VM'), power_state_desired, timeout=1)
result = xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref("VM"), power_state_desired, timeout=1)
mocked_xenapi_method = mocked_xenapi
for activated_xenapi_class in activated_xenapi_method.split('.'):
for activated_xenapi_class in activated_xenapi_method.split("."):
mocked_xenapi_method = getattr(mocked_xenapi_method, activated_xenapi_class)
mocked_xenapi_method.assert_called_once()
@@ -374,19 +394,23 @@ def test_set_vm_power_state_transition_async(mocker,
assert result[1] == power_state_resulting
@pytest.mark.parametrize('power_state_desired, power_state_current, power_state_resulting, activated_xenapi_method',
testcase_set_vm_power_state_transitions['params'], # type: ignore
ids=testcase_set_vm_power_state_transitions['ids']) # type: ignore
def test_set_vm_power_state_transition_check_mode(mocker,
fake_ansible_module,
XenAPI,
xenserver,
power_state_desired,
power_state_current,
power_state_resulting,
activated_xenapi_method):
@pytest.mark.parametrize(
"power_state_desired, power_state_current, power_state_resulting, activated_xenapi_method",
testcase_set_vm_power_state_transitions["params"], # type: ignore
ids=testcase_set_vm_power_state_transitions["ids"], # type: ignore
)
def test_set_vm_power_state_transition_check_mode(
mocker,
fake_ansible_module,
XenAPI,
xenserver,
power_state_desired,
power_state_current,
power_state_resulting,
activated_xenapi_method,
):
"""Tests regular invocation with power state transition in check mode."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_xenapi = mocker.patch.object(XenAPI.Session, "xenapi", create=True)
mocked_returns = {
"VM.get_power_state.return_value": power_state_current,
@@ -395,11 +419,11 @@ def test_set_vm_power_state_transition_check_mode(mocker,
mocked_xenapi.configure_mock(**mocked_returns)
fake_ansible_module.check_mode = True
result = xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref('VM'), power_state_desired, timeout=0)
result = xenserver.set_vm_power_state(fake_ansible_module, fake_xenapi_ref("VM"), power_state_desired, timeout=0)
mocked_xenapi_method = mocked_xenapi
for activated_xenapi_class in activated_xenapi_method.split('.'):
for activated_xenapi_class in activated_xenapi_method.split("."):
mocked_xenapi_method = getattr(mocked_xenapi_method, activated_xenapi_class)
mocked_xenapi_method.assert_not_called()

View File

@@ -14,71 +14,73 @@ from .common import fake_xenapi_ref, testcase_bad_xenapi_refs
testcase_wait_for_vm_ip_address_bad_power_states = {
"params": [
'Halted',
'Paused',
'Suspended',
'Other',
"Halted",
"Paused",
"Suspended",
"Other",
],
"ids": [
'state-halted',
'state-paused',
'state-suspended',
'state-other',
]
"state-halted",
"state-paused",
"state-suspended",
"state-other",
],
}
testcase_wait_for_vm_ip_address_bad_guest_metrics = {
"params": [
('OpaqueRef:NULL', {"networks": {}}),
(fake_xenapi_ref('VM_guest_metrics'), {"networks": {}}),
("OpaqueRef:NULL", {"networks": {}}),
(fake_xenapi_ref("VM_guest_metrics"), {"networks": {}}),
],
"ids": [
'vm_guest_metrics_ref-null, no-ip',
'vm_guest_metrics_ref-ok, no-ip',
"vm_guest_metrics_ref-null, no-ip",
"vm_guest_metrics_ref-ok, no-ip",
],
}
testcase_wait_for_task_all_statuses = {
"params": [
('Success', ''),
('Failure', 'failure'),
('Cancelling', 'cancelling'),
('Cancelled', 'cancelled'),
('Other', 'other'),
("Success", ""),
("Failure", "failure"),
("Cancelling", "cancelling"),
("Cancelled", "cancelled"),
("Other", "other"),
],
"ids": [
'task-success',
'task-failure',
'task-cancelling',
'task-cancelled',
'task-other',
]
"task-success",
"task-failure",
"task-cancelling",
"task-cancelled",
"task-other",
],
}
@pytest.mark.parametrize('vm_ref', testcase_bad_xenapi_refs['params'], ids=testcase_bad_xenapi_refs['ids']) # type: ignore
@pytest.mark.parametrize("vm_ref", testcase_bad_xenapi_refs["params"], ids=testcase_bad_xenapi_refs["ids"]) # type: ignore
def test_wait_for_vm_ip_address_bad_vm_ref(fake_ansible_module, xenserver, vm_ref):
"""Tests failure on bad vm_ref."""
with pytest.raises(FailJsonException) as exc_info:
xenserver.wait_for_vm_ip_address(fake_ansible_module, vm_ref)
assert exc_info.value.kwargs['msg'] == "Cannot wait for VM IP address. Invalid VM reference supplied!"
assert exc_info.value.kwargs["msg"] == "Cannot wait for VM IP address. Invalid VM reference supplied!"
def test_wait_for_vm_ip_address_xenapi_failure(mock_xenapi_failure, xenserver, fake_ansible_module):
"""Tests catching of XenAPI failures."""
with pytest.raises(FailJsonException) as exc_info:
xenserver.wait_for_vm_ip_address(fake_ansible_module, fake_xenapi_ref('VM'))
xenserver.wait_for_vm_ip_address(fake_ansible_module, fake_xenapi_ref("VM"))
assert exc_info.value.kwargs['msg'] == f"XAPI ERROR: {mock_xenapi_failure[1]}"
assert exc_info.value.kwargs["msg"] == f"XAPI ERROR: {mock_xenapi_failure[1]}"
@pytest.mark.parametrize('bad_power_state',
testcase_wait_for_vm_ip_address_bad_power_states['params'],
ids=testcase_wait_for_vm_ip_address_bad_power_states['ids'])
@pytest.mark.parametrize(
"bad_power_state",
testcase_wait_for_vm_ip_address_bad_power_states["params"],
ids=testcase_wait_for_vm_ip_address_bad_power_states["ids"],
)
def test_wait_for_vm_ip_address_bad_power_state(mocker, fake_ansible_module, XenAPI, xenserver, bad_power_state):
"""Tests failure on bad power state."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_xenapi = mocker.patch.object(XenAPI.Session, "xenapi", create=True)
mocked_returns = {
"VM.get_power_state.return_value": bad_power_state,
@@ -87,18 +89,23 @@ def test_wait_for_vm_ip_address_bad_power_state(mocker, fake_ansible_module, Xen
mocked_xenapi.configure_mock(**mocked_returns)
with pytest.raises(FailJsonException) as exc_info:
xenserver.wait_for_vm_ip_address(fake_ansible_module, fake_xenapi_ref('VM'))
xenserver.wait_for_vm_ip_address(fake_ansible_module, fake_xenapi_ref("VM"))
assert exc_info.value.kwargs['msg'] == (
f"Cannot wait for VM IP address when VM is in state '{xenserver.xapi_to_module_vm_power_state(bad_power_state.lower())}'!")
assert exc_info.value.kwargs["msg"] == (
f"Cannot wait for VM IP address when VM is in state '{xenserver.xapi_to_module_vm_power_state(bad_power_state.lower())}'!"
)
@pytest.mark.parametrize('bad_guest_metrics_ref, bad_guest_metrics',
testcase_wait_for_vm_ip_address_bad_guest_metrics['params'], # type: ignore
ids=testcase_wait_for_vm_ip_address_bad_guest_metrics['ids']) # type: ignore
def test_wait_for_vm_ip_address_timeout(mocker, fake_ansible_module, XenAPI, xenserver, bad_guest_metrics_ref, bad_guest_metrics):
@pytest.mark.parametrize(
"bad_guest_metrics_ref, bad_guest_metrics",
testcase_wait_for_vm_ip_address_bad_guest_metrics["params"], # type: ignore
ids=testcase_wait_for_vm_ip_address_bad_guest_metrics["ids"], # type: ignore
)
def test_wait_for_vm_ip_address_timeout(
mocker, fake_ansible_module, XenAPI, xenserver, bad_guest_metrics_ref, bad_guest_metrics
):
"""Tests timeout."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_xenapi = mocker.patch.object(XenAPI.Session, "xenapi", create=True)
mocked_returns = {
"VM.get_power_state.return_value": "Running",
@@ -108,17 +115,17 @@ def test_wait_for_vm_ip_address_timeout(mocker, fake_ansible_module, XenAPI, xen
mocked_xenapi.configure_mock(**mocked_returns)
mocker.patch('time.sleep')
mocker.patch("time.sleep")
with pytest.raises(FailJsonException) as exc_info:
xenserver.wait_for_vm_ip_address(fake_ansible_module, fake_xenapi_ref('VM'), timeout=1)
xenserver.wait_for_vm_ip_address(fake_ansible_module, fake_xenapi_ref("VM"), timeout=1)
assert exc_info.value.kwargs['msg'] == "Timed out waiting for VM IP address!"
assert exc_info.value.kwargs["msg"] == "Timed out waiting for VM IP address!"
def test_wait_for_vm_ip_address(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests regular invocation."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_xenapi = mocker.patch.object(XenAPI.Session, "xenapi", create=True)
# This mock simulates regular VM IP acquirement lifecycle:
#
@@ -130,9 +137,9 @@ def test_wait_for_vm_ip_address(mocker, fake_ansible_module, XenAPI, xenserver):
mocked_returns = {
"VM.get_power_state.return_value": "Running",
"VM.get_guest_metrics.side_effect": [
'OpaqueRef:NULL',
fake_xenapi_ref('VM_guest_metrics'),
fake_xenapi_ref('VM_guest_metrics'),
"OpaqueRef:NULL",
fake_xenapi_ref("VM_guest_metrics"),
fake_xenapi_ref("VM_guest_metrics"),
],
"VM_guest_metrics.get_record.side_effect": [
{
@@ -149,33 +156,33 @@ def test_wait_for_vm_ip_address(mocker, fake_ansible_module, XenAPI, xenserver):
mocked_xenapi.configure_mock(**mocked_returns)
mocker.patch('time.sleep')
mocker.patch("time.sleep")
fake_guest_metrics = xenserver.wait_for_vm_ip_address(fake_ansible_module, fake_xenapi_ref('VM'))
fake_guest_metrics = xenserver.wait_for_vm_ip_address(fake_ansible_module, fake_xenapi_ref("VM"))
assert fake_guest_metrics == mocked_returns['VM_guest_metrics.get_record.side_effect'][1]
assert fake_guest_metrics == mocked_returns["VM_guest_metrics.get_record.side_effect"][1]
@pytest.mark.parametrize('task_ref', testcase_bad_xenapi_refs['params'], ids=testcase_bad_xenapi_refs['ids']) # type: ignore
@pytest.mark.parametrize("task_ref", testcase_bad_xenapi_refs["params"], ids=testcase_bad_xenapi_refs["ids"]) # type: ignore
def test_wait_for_task_bad_task_ref(fake_ansible_module, xenserver, task_ref):
"""Tests failure on bad task_ref."""
with pytest.raises(FailJsonException) as exc_info:
xenserver.wait_for_task(fake_ansible_module, task_ref)
assert exc_info.value.kwargs['msg'] == "Cannot wait for task. Invalid task reference supplied!"
assert exc_info.value.kwargs["msg"] == "Cannot wait for task. Invalid task reference supplied!"
def test_wait_for_task_xenapi_failure(mock_xenapi_failure, fake_ansible_module, xenserver):
"""Tests catching of XenAPI failures."""
with pytest.raises(FailJsonException) as exc_info:
xenserver.wait_for_task(fake_ansible_module, fake_xenapi_ref('task'))
xenserver.wait_for_task(fake_ansible_module, fake_xenapi_ref("task"))
assert exc_info.value.kwargs['msg'] == f"XAPI ERROR: {mock_xenapi_failure[1]}"
assert exc_info.value.kwargs["msg"] == f"XAPI ERROR: {mock_xenapi_failure[1]}"
def test_wait_for_task_timeout(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests timeout."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_xenapi = mocker.patch.object(XenAPI.Session, "xenapi", create=True)
mocked_returns = {
"task.get_status.return_value": "Pending",
@@ -184,26 +191,28 @@ def test_wait_for_task_timeout(mocker, fake_ansible_module, XenAPI, xenserver):
mocked_xenapi.configure_mock(**mocked_returns)
mocker.patch('time.sleep')
mocker.patch("time.sleep")
fake_result = xenserver.wait_for_task(fake_ansible_module, fake_xenapi_ref('task'), timeout=1)
fake_result = xenserver.wait_for_task(fake_ansible_module, fake_xenapi_ref("task"), timeout=1)
mocked_xenapi.task.destroy.assert_called_once()
assert fake_result == "timeout"
@pytest.mark.parametrize('task_status, result',
testcase_wait_for_task_all_statuses['params'], # type: ignore
ids=testcase_wait_for_task_all_statuses['ids']) # type: ignore
@pytest.mark.parametrize(
"task_status, result",
testcase_wait_for_task_all_statuses["params"], # type: ignore
ids=testcase_wait_for_task_all_statuses["ids"], # type: ignore
)
def test_wait_for_task(mocker, fake_ansible_module, XenAPI, xenserver, task_status, result):
"""Tests regular invocation."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_xenapi = mocker.patch.object(XenAPI.Session, "xenapi", create=True)
# Mock will first return Pending status and on second invocation it will
# return one of possible final statuses.
mocked_returns = {
"task.get_status.side_effect": [
'Pending',
"Pending",
task_status,
],
"task.destroy.return_value": None,
@@ -211,9 +220,9 @@ def test_wait_for_task(mocker, fake_ansible_module, XenAPI, xenserver, task_stat
mocked_xenapi.configure_mock(**mocked_returns)
mocker.patch('time.sleep')
mocker.patch("time.sleep")
fake_result = xenserver.wait_for_task(fake_ansible_module, fake_xenapi_ref('task'))
fake_result = xenserver.wait_for_task(fake_ansible_module, fake_xenapi_ref("task"))
mocked_xenapi.task.destroy.assert_called_once()
assert fake_result == result

View File

@@ -63,24 +63,34 @@ testcase_module_remote_conn_scheme = {
}
@pytest.mark.parametrize('fake_ansible_module', testcase_module_local_conn['params'], ids=testcase_module_local_conn['ids'], indirect=True) # type: ignore
@pytest.mark.parametrize(
"fake_ansible_module",
testcase_module_local_conn["params"], # type: ignore
ids=testcase_module_local_conn["ids"], # type: ignore
indirect=True,
)
def test_xapi_connect_local_session(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests that connection to localhost uses XenAPI.xapi_local() function."""
mocker.patch('XenAPI.xapi_local')
mocker.patch("XenAPI.xapi_local")
xapi_session = xenserver.XAPI.connect(fake_ansible_module)
XenAPI.xapi_local.assert_called_once()
@pytest.mark.parametrize('fake_ansible_module', testcase_module_local_conn['params'], ids=testcase_module_local_conn['ids'], indirect=True) # type: ignore
@pytest.mark.parametrize(
"fake_ansible_module",
testcase_module_local_conn["params"], # type: ignore
ids=testcase_module_local_conn["ids"], # type: ignore
indirect=True,
)
def test_xapi_connect_local_login(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests that connection to localhost uses empty username and password."""
mocker.patch.object(XenAPI.Session, 'login_with_password', create=True)
mocker.patch.object(XenAPI.Session, "login_with_password", create=True)
xapi_session = xenserver.XAPI.connect(fake_ansible_module)
XenAPI.Session.login_with_password.assert_called_once_with('', '', ANSIBLE_VERSION, 'Ansible')
XenAPI.Session.login_with_password.assert_called_once_with("", "", ANSIBLE_VERSION, "Ansible")
def test_xapi_connect_login(mocker, fake_ansible_module, XenAPI, xenserver):
@@ -88,80 +98,88 @@ def test_xapi_connect_login(mocker, fake_ansible_module, XenAPI, xenserver):
Tests that username and password are properly propagated to
XenAPI.Session.login_with_password() function.
"""
mocker.patch.object(XenAPI.Session, 'login_with_password', create=True)
mocker.patch.object(XenAPI.Session, "login_with_password", create=True)
xapi_session = xenserver.XAPI.connect(fake_ansible_module)
username = fake_ansible_module.params['username']
password = fake_ansible_module.params['password']
username = fake_ansible_module.params["username"]
password = fake_ansible_module.params["password"]
XenAPI.Session.login_with_password.assert_called_once_with(username, password, ANSIBLE_VERSION, 'Ansible')
XenAPI.Session.login_with_password.assert_called_once_with(username, password, ANSIBLE_VERSION, "Ansible")
def test_xapi_connect_login_failure(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests that login failure is properly handled."""
fake_error_msg = "Fake XAPI login error!"
mocked_login = mocker.patch.object(XenAPI.Session, 'login_with_password', create=True)
mocked_login = mocker.patch.object(XenAPI.Session, "login_with_password", create=True)
mocked_login.side_effect = XenAPI.Failure(fake_error_msg)
hostname = fake_ansible_module.params['hostname']
username = fake_ansible_module.params['username']
hostname = fake_ansible_module.params["hostname"]
username = fake_ansible_module.params["username"]
with pytest.raises(FailJsonException) as exc_info:
xapi_session = xenserver.XAPI.connect(fake_ansible_module)
assert exc_info.value.kwargs['msg'] == f"Unable to log on to XenServer at http://{hostname} as {username}: {fake_error_msg}"
assert (
exc_info.value.kwargs["msg"]
== f"Unable to log on to XenServer at http://{hostname} as {username}: {fake_error_msg}"
)
@pytest.mark.parametrize(
'fake_ansible_module',
testcase_module_remote_conn_scheme['params'], # type: ignore
ids=testcase_module_remote_conn_scheme['ids'], # type: ignore
"fake_ansible_module",
testcase_module_remote_conn_scheme["params"], # type: ignore
ids=testcase_module_remote_conn_scheme["ids"], # type: ignore
indirect=True,
)
def test_xapi_connect_remote_scheme(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests that explicit scheme in hostname param is preserved."""
mocker.patch('XenAPI.Session')
mocker.patch("XenAPI.Session")
xapi_session = xenserver.XAPI.connect(fake_ansible_module)
hostname = fake_ansible_module.params['hostname']
ignore_ssl = not fake_ansible_module.params['validate_certs']
hostname = fake_ansible_module.params["hostname"]
ignore_ssl = not fake_ansible_module.params["validate_certs"]
XenAPI.Session.assert_called_once_with(hostname, ignore_ssl=ignore_ssl)
@pytest.mark.parametrize('fake_ansible_module', testcase_module_remote_conn['params'], ids=testcase_module_remote_conn['ids'], indirect=True) # type: ignore
@pytest.mark.parametrize(
"fake_ansible_module",
testcase_module_remote_conn["params"], # type: ignore
ids=testcase_module_remote_conn["ids"], # type: ignore
indirect=True,
)
def test_xapi_connect_remote_no_scheme(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests that proper scheme is prepended to hostname without scheme."""
mocker.patch('XenAPI.Session')
mocker.patch("XenAPI.Session")
xapi_session = xenserver.XAPI.connect(fake_ansible_module)
hostname = fake_ansible_module.params['hostname']
ignore_ssl = not fake_ansible_module.params['validate_certs']
hostname = fake_ansible_module.params["hostname"]
ignore_ssl = not fake_ansible_module.params["validate_certs"]
XenAPI.Session.assert_called_once_with(f"http://{hostname}", ignore_ssl=ignore_ssl)
def test_xapi_connect_support_ignore_ssl(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests proper handling of ignore_ssl support."""
mocked_session = mocker.patch('XenAPI.Session')
mocked_session = mocker.patch("XenAPI.Session")
mocked_session.side_effect = TypeError()
with pytest.raises(TypeError) as exc_info:
xapi_session = xenserver.XAPI.connect(fake_ansible_module)
hostname = fake_ansible_module.params['hostname']
ignore_ssl = not fake_ansible_module.params['validate_certs']
hostname = fake_ansible_module.params["hostname"]
ignore_ssl = not fake_ansible_module.params["validate_certs"]
XenAPI.Session.assert_called_with(f"http://{hostname}")
def test_xapi_connect_no_disconnect_atexit(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests skipping registration of atexit disconnect handler."""
mocker.patch('atexit.register')
mocker.patch("atexit.register")
xapi_session = xenserver.XAPI.connect(fake_ansible_module, disconnect_atexit=False)
@@ -170,7 +188,7 @@ def test_xapi_connect_no_disconnect_atexit(mocker, fake_ansible_module, XenAPI,
def test_xapi_connect_singleton(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests if XAPI.connect() returns singleton."""
mocker.patch('XenAPI.Session')
mocker.patch("XenAPI.Session")
xapi_session1 = xenserver.XAPI.connect(fake_ansible_module)
xapi_session2 = xenserver.XAPI.connect(fake_ansible_module)

View File

@@ -14,12 +14,12 @@ from .common import fake_xenapi_ref
def test_xenserverobject_xenapi_lib_detection(mocker, fake_ansible_module, xenserver):
"""Tests XenAPI lib detection code."""
mocker.patch('ansible_collections.community.general.plugins.module_utils.xenserver.HAS_XENAPI', new=False)
mocker.patch("ansible_collections.community.general.plugins.module_utils.xenserver.HAS_XENAPI", new=False)
with pytest.raises(FailJsonException) as exc_info:
xenserver.XenServerObject(fake_ansible_module)
assert 'Failed to import the required Python library (XenAPI) on' in exc_info.value.kwargs['msg']
assert "Failed to import the required Python library (XenAPI) on" in exc_info.value.kwargs["msg"]
def test_xenserverobject_xenapi_failure(mock_xenapi_failure, fake_ansible_module, xenserver):
@@ -27,17 +27,17 @@ def test_xenserverobject_xenapi_failure(mock_xenapi_failure, fake_ansible_module
with pytest.raises(FailJsonException) as exc_info:
xenserver.XenServerObject(fake_ansible_module)
assert exc_info.value.kwargs['msg'] == f"XAPI ERROR: {mock_xenapi_failure[1]}"
assert exc_info.value.kwargs["msg"] == f"XAPI ERROR: {mock_xenapi_failure[1]}"
def test_xenserverobject(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests successful creation of XenServerObject."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
mocked_xenapi = mocker.patch.object(XenAPI.Session, "xenapi", create=True)
mocked_returns = {
"pool.get_all.return_value": [fake_xenapi_ref('pool')],
"pool.get_default_SR.return_value": fake_xenapi_ref('SR'),
"session.get_this_host.return_value": fake_xenapi_ref('host'),
"pool.get_all.return_value": [fake_xenapi_ref("pool")],
"pool.get_default_SR.return_value": fake_xenapi_ref("SR"),
"session.get_this_host.return_value": fake_xenapi_ref("host"),
"host.get_software_version.return_value": {"product_version": "7.2.0"},
}
@@ -45,5 +45,5 @@ def test_xenserverobject(mocker, fake_ansible_module, XenAPI, xenserver):
xso = xenserver.XenServerObject(fake_ansible_module)
assert xso.pool_ref == fake_xenapi_ref('pool')
assert xso.pool_ref == fake_xenapi_ref("pool")
assert xso.xenserver_version == [7, 2, 0]

View File

@@ -17,9 +17,7 @@ class Failure(Exception):
class Session:
def __init__(self, uri, transport=None, encoding=None, verbose=0,
allow_none=1, ignore_ssl=False):
def __init__(self, uri, transport=None, encoding=None, verbose=0, allow_none=1, ignore_ssl=False):
self.transport = transport
self._session = None
self.last_login_method = None
@@ -42,10 +40,10 @@ class Session:
self.API_version = FAKE_API_VERSION
def xenapi_request(self, methodname, params):
if methodname.startswith('login'):
if methodname.startswith("login"):
self._login(methodname, params)
return None
elif methodname == 'logout' or methodname == 'session.logout':
elif methodname == "logout" or methodname == "session.logout":
self._logout()
return None
else:
@@ -53,14 +51,14 @@ class Session:
return None
def __getattr__(self, name):
if name == 'handle':
if name == "handle":
return self._session
elif name == 'xenapi':
elif name == "xenapi":
# Should be patched with mocker.patch().
return None
elif name.startswith('login') or name.startswith('slave_local'):
elif name.startswith("login") or name.startswith("slave_local"):
return lambda *params: self._login(name, params)
elif name == 'logout':
elif name == "logout":
return self._logout

View File

@@ -11,7 +11,9 @@ from collections.abc import MutableMapping
import pytest
from ansible_collections.community.general.plugins.module_utils import deps
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import set_module_args as _set_module_args
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
set_module_args as _set_module_args,
)
def _fix_ansible_args(args):
@@ -22,7 +24,7 @@ def _fix_ansible_args(args):
if isinstance(args, MutableMapping):
return args
raise Exception('Malformed data to the patch_ansible_module pytest fixture')
raise Exception("Malformed data to the patch_ansible_module pytest fixture")
@pytest.fixture
@@ -39,6 +41,7 @@ def patch_ansible_module_uthelper(request):
args = _fix_ansible_args(args)
with _set_module_args(args):
yield
return _patch

File diff suppressed because it is too large Load Diff

View File

@@ -17,23 +17,23 @@ from hpOneView.oneview_client import OneViewClient
class OneViewBaseTest:
@pytest.fixture(autouse=True)
def setUp(self, mock_ansible_module, mock_ov_client, request):
marker = request.node.get_marker('resource')
marker = request.node.get_marker("resource")
self.resource = getattr(mock_ov_client, f"{marker.args}")
self.mock_ov_client = mock_ov_client
self.mock_ansible_module = mock_ansible_module
@pytest.fixture
def testing_module(self):
resource_name = type(self).__name__.replace('Test', '')
resource_module_path_name = resource_name.replace('Module', '')
resource_module_path_name = re.findall('[A-Z][^A-Z]*', resource_module_path_name)
resource_name = type(self).__name__.replace("Test", "")
resource_module_path_name = resource_name.replace("Module", "")
resource_module_path_name = re.findall("[A-Z][^A-Z]*", resource_module_path_name)
resource_module_path_name = f"oneview_{str.join('_', resource_module_path_name).lower()}"
ansible_collections = __import__('ansible_collections')
ansible_collections = __import__("ansible_collections")
oneview_module = ansible_collections.community.general.plugins.modules
resource_module = getattr(oneview_module, resource_module_path_name)
self.testing_class = getattr(resource_module, resource_name)
testing_module = self.testing_class.__module__.split('.')[-1]
testing_module = self.testing_class.__module__.split(".")[-1]
testing_module = getattr(oneview_module, testing_module)
try:
# Load scenarios from module examples (Also checks if it is a valid yaml)
@@ -45,9 +45,9 @@ class OneViewBaseTest:
return testing_module
def test_main_function_should_call_run_method(self, testing_module, mock_ansible_module):
mock_ansible_module.params = {'config': 'config.json'}
mock_ansible_module.params = {"config": "config.json"}
main_func = getattr(testing_module, 'main')
main_func = getattr(testing_module, "main")
with patch.object(self.testing_class, "run") as mock_run:
main_func()
@@ -59,28 +59,28 @@ class FactsParamsTest(OneViewBaseTest):
self.resource.get_all.return_value = []
params_get_all_with_filters = dict(
config='config.json',
config="config.json",
name=None,
params={
'start': 1,
'count': 3,
'sort': 'name:descending',
'filter': 'purpose=General',
'query': 'imported eq true'
})
"start": 1,
"count": 3,
"sort": "name:descending",
"filter": "purpose=General",
"query": "imported eq true",
},
)
self.mock_ansible_module.params = params_get_all_with_filters
self.testing_class().run()
self.resource.get_all.assert_called_once_with(start=1, count=3, sort='name:descending', filter='purpose=General', query='imported eq true')
self.resource.get_all.assert_called_once_with(
start=1, count=3, sort="name:descending", filter="purpose=General", query="imported eq true"
)
def test_should_get_all_without_params(self, testing_module):
self.resource.get_all.return_value = []
params_get_all_with_filters = dict(
config='config.json',
name=None
)
params_get_all_with_filters = dict(config="config.json", name=None)
self.mock_ansible_module.params = params_get_all_with_filters
self.testing_class().run()
@@ -106,7 +106,7 @@ class OneViewBaseTestCase:
self.testing_class = testing_class
# Define OneView Client Mock (FILE)
patcher_json_file = patch.object(OneViewClient, 'from_json_file')
patcher_json_file = patch.object(OneViewClient, "from_json_file")
test_case.addCleanup(patcher_json_file.stop)
self.mock_ov_client_from_json_file = patcher_json_file.start()
@@ -123,9 +123,9 @@ class OneViewBaseTestCase:
self.__set_module_examples()
def test_main_function_should_call_run_method(self):
self.mock_ansible_module.params = {'config': 'config.json'}
self.mock_ansible_module.params = {"config": "config.json"}
main_func = getattr(self.testing_module, 'main')
main_func = getattr(self.testing_module, "main")
with patch.object(self.testing_class, "run") as mock_run:
main_func()
@@ -133,8 +133,8 @@ class OneViewBaseTestCase:
def __set_module_examples(self):
# Load scenarios from module examples (Also checks if it is a valid yaml)
ansible_collections = __import__('ansible_collections')
testing_module = self.testing_class.__module__.split('.')[-1]
ansible_collections = __import__("ansible_collections")
testing_module = self.testing_class.__module__.split(".")[-1]
self.testing_module = getattr(ansible_collections.community.general.plugins.modules, testing_module)
try:
@@ -165,40 +165,39 @@ class FactsParamsTestCase(OneViewBaseTestCase):
if not self.resource_client:
raise Exception(
"Mock for the client not configured, you must call 'configure_client_mock' before running this test.")
"Mock for the client not configured, you must call 'configure_client_mock' before running this test."
)
def test_should_get_all_using_filters(self):
self.__validations()
self.resource_client.get_all.return_value = []
params_get_all_with_filters = dict(
config='config.json',
config="config.json",
name=None,
params={
'start': 1,
'count': 3,
'sort': 'name:descending',
'filter': 'purpose=General',
'query': 'imported eq true'
})
self.mock_ansible_module.params = params_get_all_with_filters
self.testing_class().run()
self.resource_client.get_all.assert_called_once_with(start=1, count=3, sort='name:descending',
filter='purpose=General',
query='imported eq true')
def test_should_get_all_without_params(self):
self.__validations()
self.resource_client.get_all.return_value = []
params_get_all_with_filters = dict(
config='config.json',
name=None
"start": 1,
"count": 3,
"sort": "name:descending",
"filter": "purpose=General",
"query": "imported eq true",
},
)
self.mock_ansible_module.params = params_get_all_with_filters
self.testing_class().run()
self.resource_client.get_all.assert_called_once_with(
start=1, count=3, sort="name:descending", filter="purpose=General", query="imported eq true"
)
def test_should_get_all_without_params(self):
self.__validations()
self.resource_client.get_all.return_value = []
params_get_all_with_filters = dict(config="config.json", name=None)
self.mock_ansible_module.params = params_get_all_with_filters
self.testing_class().run()
self.resource_client.get_all.assert_called_once_with()

View File

@@ -38,8 +38,8 @@ class ModuleMocked:
module = ModuleMocked()
fixture_path = os.path.join(os.path.dirname(__file__), 'interfaces_file_fixtures', 'input')
golden_output_path = os.path.join(os.path.dirname(__file__), 'interfaces_file_fixtures', 'golden_output')
fixture_path = os.path.join(os.path.dirname(__file__), "interfaces_file_fixtures", "input")
golden_output_path = os.path.join(os.path.dirname(__file__), "interfaces_file_fixtures", "golden_output")
class TestInterfacesFileModule(unittest.TestCase):
@@ -47,7 +47,7 @@ class TestInterfacesFileModule(unittest.TestCase):
def getTestFiles(self, include_filter=None, exclude_filter=None):
flist = next(os.walk(fixture_path))[2]
flist = [file for file in flist if not file.endswith('.license')]
flist = [file for file in flist if not file.endswith(".license")]
if include_filter:
flist = filter(lambda x: re.match(include_filter, x), flist)
if exclude_filter:
@@ -57,10 +57,9 @@ class TestInterfacesFileModule(unittest.TestCase):
def compareFileToBackup(self, path, backup):
with open(path) as f1:
with open(backup) as f2:
diffs = difflib.context_diff(f1.readlines(),
f2.readlines(),
fromfile=os.path.basename(path),
tofile=os.path.basename(backup))
diffs = difflib.context_diff(
f1.readlines(), f2.readlines(), fromfile=os.path.basename(path), tofile=os.path.basename(backup)
)
# Restore backup
move(backup, path)
deltas = list(diffs)
@@ -69,37 +68,37 @@ class TestInterfacesFileModule(unittest.TestCase):
def compareInterfacesLinesToFile(self, interfaces_lines, path, testname=None):
if not testname:
testname = f"{path}.{inspect.stack()[1][3]}"
self.compareStringWithFile("".join([d['line'] for d in interfaces_lines if 'line' in d]), testname)
self.compareStringWithFile("".join([d["line"] for d in interfaces_lines if "line" in d]), testname)
def compareInterfacesToFile(self, ifaces, path, testname=None):
if not testname:
testname = f"{path}.{inspect.stack()[1][3]}.json"
testfilepath = os.path.join(golden_output_path, testname)
string = json.dumps(ifaces, sort_keys=True, indent=4, separators=(',', ': '))
if string and not string.endswith('\n'):
string += '\n'
string = json.dumps(ifaces, sort_keys=True, indent=4, separators=(",", ": "))
if string and not string.endswith("\n"):
string += "\n"
goldenstring = string
goldenData = ifaces
if not os.path.isfile(testfilepath):
with io.open(testfilepath, 'wb') as f:
with io.open(testfilepath, "wb") as f:
f.write(string.encode())
else:
with open(testfilepath, 'r') as goldenfile:
with open(testfilepath, "r") as goldenfile:
goldenData = json.load(goldenfile)
self.assertEqual(goldenData, ifaces)
def compareStringWithFile(self, string, path):
testfilepath = os.path.join(golden_output_path, path)
if string and not string.endswith('\n'):
string += '\n'
if string and not string.endswith("\n"):
string += "\n"
goldenstring = string
if not os.path.isfile(testfilepath):
f = io.open(testfilepath, 'wb')
f = io.open(testfilepath, "wb")
f.write(string.encode())
f.close()
else:
with open(testfilepath, 'r') as goldenfile:
with open(testfilepath, "r") as goldenfile:
goldenstring = goldenfile.read()
goldenfile.close()
self.assertEqual(goldenstring, string)
@@ -115,74 +114,74 @@ class TestInterfacesFileModule(unittest.TestCase):
testcases = {
"add_aggi_up": [
{
'iface': 'aggi',
'option': 'up',
'value': 'route add -net 224.0.0.0 netmask 240.0.0.0 dev aggi',
'state': 'present',
"iface": "aggi",
"option": "up",
"value": "route add -net 224.0.0.0 netmask 240.0.0.0 dev aggi",
"state": "present",
}
],
"add_and_delete_aggi_up": [
{
'iface': 'aggi',
'option': 'up',
'value': 'route add -net 224.0.0.0 netmask 240.0.0.0 dev aggi',
'state': 'present',
"iface": "aggi",
"option": "up",
"value": "route add -net 224.0.0.0 netmask 240.0.0.0 dev aggi",
"state": "present",
},
{
'iface': 'aggi',
'option': 'up',
'value': None,
'state': 'absent',
"iface": "aggi",
"option": "up",
"value": None,
"state": "absent",
},
],
"add_aggi_up_twice": [
{
'iface': 'aggi',
'option': 'up',
'value': 'route add -net 224.0.0.0 netmask 240.0.0.0 dev aggi',
'state': 'present',
"iface": "aggi",
"option": "up",
"value": "route add -net 224.0.0.0 netmask 240.0.0.0 dev aggi",
"state": "present",
},
{
'iface': 'aggi',
'option': 'up',
'value': 'route add -net 224.0.0.0 netmask 240.0.0.0 dev aggi',
'state': 'present',
"iface": "aggi",
"option": "up",
"value": "route add -net 224.0.0.0 netmask 240.0.0.0 dev aggi",
"state": "present",
},
],
"aggi_remove_dup": [
{
'iface': 'aggi',
'option': 'up',
'value': None,
'state': 'absent',
"iface": "aggi",
"option": "up",
"value": None,
"state": "absent",
},
{
'iface': 'aggi',
'option': 'up',
'value': 'route add -net 224.0.0.0 netmask 240.0.0.0 dev aggi',
'state': 'present',
"iface": "aggi",
"option": "up",
"value": "route add -net 224.0.0.0 netmask 240.0.0.0 dev aggi",
"state": "present",
},
],
"set_aggi_slaves": [
{
'iface': 'aggi',
'option': 'slaves',
'value': 'int1 int3',
'state': 'present',
"iface": "aggi",
"option": "slaves",
"value": "int1 int3",
"state": "present",
},
],
"set_aggi_and_eth0_mtu": [
{
'iface': 'aggi',
'option': 'mtu',
'value': '1350',
'state': 'present',
"iface": "aggi",
"option": "mtu",
"value": "1350",
"state": "present",
},
{
'iface': 'eth0',
'option': 'mtu',
'value': '1350',
'state': 'present',
"iface": "eth0",
"option": "mtu",
"value": "1350",
"state": "present",
},
],
}
@@ -193,12 +192,16 @@ class TestInterfacesFileModule(unittest.TestCase):
fail_json_iterations = []
for i, options in enumerate(options_list):
try:
dummy, lines = interfaces_file.set_interface_option(module, lines, options['iface'], options['option'],
options['value'], options['state'])
dummy, lines = interfaces_file.set_interface_option(
module, lines, options["iface"], options["option"], options["value"], options["state"]
)
except AnsibleFailJson as e:
fail_json_iterations.append(
f"[{i}] fail_json message: {e!s}\noptions:\n{json.dumps(options, sort_keys=True, indent=4, separators=(',', ': '))}")
self.compareStringWithFile("\n=====\n".join(fail_json_iterations), f"{testfile}_{testname}.exceptions.txt")
f"[{i}] fail_json message: {e!s}\noptions:\n{json.dumps(options, sort_keys=True, indent=4, separators=(',', ': '))}"
)
self.compareStringWithFile(
"\n=====\n".join(fail_json_iterations), f"{testfile}_{testname}.exceptions.txt"
)
self.compareInterfacesLinesToFile(lines, testfile, f"{testfile}_{testname}")
self.compareInterfacesToFile(ifaces, testfile, f"{testfile}_{testname}.json")
@@ -207,9 +210,9 @@ class TestInterfacesFileModule(unittest.TestCase):
testcases = {
"revert": [
{
'iface': 'eth0',
'option': 'mtu',
'value': '1350',
"iface": "eth0",
"option": "mtu",
"value": "1350",
}
],
}
@@ -222,18 +225,22 @@ class TestInterfacesFileModule(unittest.TestCase):
lines, ifaces = interfaces_file.read_interfaces_file(module, path)
backupp = module.backup_local(path)
options = options_list[0]
for state in ['present', 'absent']:
for state in ["present", "absent"]:
fail_json_iterations = []
options['state'] = state
options["state"] = state
try:
dummy, lines = interfaces_file.set_interface_option(module, lines,
options['iface'], options['option'], options['value'], options['state'])
dummy, lines = interfaces_file.set_interface_option(
module, lines, options["iface"], options["option"], options["value"], options["state"]
)
except AnsibleFailJson as e:
fail_json_iterations.append(
f"fail_json message: {e!s}\noptions:\n{json.dumps(options, sort_keys=True, indent=4, separators=(',', ': '))}")
interfaces_file.write_changes(module, [d['line'] for d in lines if 'line' in d], path)
f"fail_json message: {e!s}\noptions:\n{json.dumps(options, sort_keys=True, indent=4, separators=(',', ': '))}"
)
interfaces_file.write_changes(module, [d["line"] for d in lines if "line" in d], path)
self.compareStringWithFile("\n=====\n".join(fail_json_iterations), f"{testfile}_{testname}.exceptions.txt")
self.compareStringWithFile(
"\n=====\n".join(fail_json_iterations), f"{testfile}_{testname}.exceptions.txt"
)
self.compareInterfacesLinesToFile(lines, testfile, f"{testfile}_{testname}")
self.compareInterfacesToFile(ifaces, testfile, f"{testfile}_{testname}.json")
@@ -245,10 +252,10 @@ class TestInterfacesFileModule(unittest.TestCase):
testcases = {
"change_method": [
{
'iface': 'eth1',
'option': 'method',
'value': 'dhcp',
'state': 'present',
"iface": "eth1",
"option": "method",
"value": "dhcp",
"state": "present",
}
],
}
@@ -263,20 +270,27 @@ class TestInterfacesFileModule(unittest.TestCase):
options = options_list[0]
fail_json_iterations = []
try:
changed, lines = interfaces_file.set_interface_option(module, lines, options['iface'], options['option'],
options['value'], options['state'])
changed, lines = interfaces_file.set_interface_option(
module, lines, options["iface"], options["option"], options["value"], options["state"]
)
# When a changed is made try running it again for proper idempotency
if changed:
changed_again, lines = interfaces_file.set_interface_option(module, lines, options['iface'],
options['option'], options['value'], options['state'])
self.assertFalse(changed_again,
msg=f'Second request for change should return false for {testname} running on {testfile}')
changed_again, lines = interfaces_file.set_interface_option(
module, lines, options["iface"], options["option"], options["value"], options["state"]
)
self.assertFalse(
changed_again,
msg=f"Second request for change should return false for {testname} running on {testfile}",
)
except AnsibleFailJson as e:
fail_json_iterations.append(
f"fail_json message: {e!s}\noptions:\n{json.dumps(options, sort_keys=True, indent=4, separators=(',', ': '))}")
interfaces_file.write_changes(module, [d['line'] for d in lines if 'line' in d], path)
f"fail_json message: {e!s}\noptions:\n{json.dumps(options, sort_keys=True, indent=4, separators=(',', ': '))}"
)
interfaces_file.write_changes(module, [d["line"] for d in lines if "line" in d], path)
self.compareStringWithFile("\n=====\n".join(fail_json_iterations), f"{testfile}_{testname}.exceptions.txt")
self.compareStringWithFile(
"\n=====\n".join(fail_json_iterations), f"{testfile}_{testname}.exceptions.txt"
)
self.compareInterfacesLinesToFile(lines, testfile, f"{testfile}_{testname}")
self.compareInterfacesToFile(ifaces, testfile, f"{testfile}_{testname}.json")
@@ -312,8 +326,8 @@ class TestInterfacesFileModule(unittest.TestCase):
"netmask": "",
"post-up": [],
"pre-up": [],
"up": []
}
"up": [],
},
},
{
"address_family": "inet",
@@ -321,7 +335,7 @@ class TestInterfacesFileModule(unittest.TestCase):
"line": " address 1.2.3.5",
"line_type": "option",
"option": "address",
"value": "1.2.3.5"
"value": "1.2.3.5",
},
{
"address_family": "inet",
@@ -329,7 +343,7 @@ class TestInterfacesFileModule(unittest.TestCase):
"line": " netmask 255.255.255.0",
"line_type": "option",
"option": "netmask",
"value": "255.255.255.0"
"value": "255.255.255.0",
},
{
"address_family": "inet",
@@ -337,8 +351,8 @@ class TestInterfacesFileModule(unittest.TestCase):
"line": " gateway 1.2.3.1",
"line_type": "option",
"option": "gateway",
"value": "1.2.3.1"
}
"value": "1.2.3.1",
},
],
"iface_options": [
{
@@ -347,7 +361,7 @@ class TestInterfacesFileModule(unittest.TestCase):
"line": " address 1.2.3.5",
"line_type": "option",
"option": "address",
"value": "1.2.3.5"
"value": "1.2.3.5",
},
{
"address_family": "inet",
@@ -355,7 +369,7 @@ class TestInterfacesFileModule(unittest.TestCase):
"line": " netmask 255.255.255.0",
"line_type": "option",
"option": "netmask",
"value": "255.255.255.0"
"value": "255.255.255.0",
},
{
"address_family": "inet",
@@ -363,9 +377,9 @@ class TestInterfacesFileModule(unittest.TestCase):
"line": " gateway 1.2.3.1",
"line_type": "option",
"option": "gateway",
"value": "1.2.3.1"
}
]
"value": "1.2.3.1",
},
],
},
}
@@ -383,7 +397,7 @@ class TestInterfacesFileModule(unittest.TestCase):
"line": " address 1.2.3.5",
"line_type": "option",
"option": "address",
"value": "1.2.3.5"
"value": "1.2.3.5",
},
{
"address_family": "inet",
@@ -391,7 +405,7 @@ class TestInterfacesFileModule(unittest.TestCase):
"line": " netmask 255.255.255.0",
"line_type": "option",
"option": "netmask",
"value": "255.255.255.0"
"value": "255.255.255.0",
},
{
"address_family": "inet",
@@ -399,8 +413,8 @@ class TestInterfacesFileModule(unittest.TestCase):
"line": " gateway 1.2.3.1",
"line_type": "option",
"option": "gateway",
"value": "1.2.3.1"
}
"value": "1.2.3.1",
},
],
"target_options": [
{
@@ -409,15 +423,17 @@ class TestInterfacesFileModule(unittest.TestCase):
"line": " address 1.2.3.5",
"line_type": "option",
"option": "address",
"value": "1.2.3.5"
"value": "1.2.3.5",
}
],
"option": "address"
"option": "address",
},
}
for testname in testcases.keys():
target_options = interfaces_file.get_target_options(testcases[testname]["iface_options"], testcases[testname]["option"])
target_options = interfaces_file.get_target_options(
testcases[testname]["iface_options"], testcases[testname]["option"]
)
self.assertEqual(testcases[testname]["target_options"], target_options)
def test_update_existing_option_line(self):
@@ -429,7 +445,7 @@ class TestInterfacesFileModule(unittest.TestCase):
"line": " address 1.2.3.5",
"line_type": "option",
"option": "address",
"value": "1.2.3.5"
"value": "1.2.3.5",
},
"value": "1.2.3.4",
"result": " address 1.2.3.4",
@@ -437,7 +453,9 @@ class TestInterfacesFileModule(unittest.TestCase):
}
for testname in testcases.keys():
updated = interfaces_file.update_existing_option_line(testcases[testname]["target_option"], testcases[testname]["value"])
updated = interfaces_file.update_existing_option_line(
testcases[testname]["target_option"], testcases[testname]["value"]
)
self.assertEqual(testcases[testname]["result"], updated)
def test_predefined(self):
@@ -453,7 +471,7 @@ class TestInterfacesFileModule(unittest.TestCase):
"iface": "eno1",
"option": "address",
"value": "1.2.3.5",
'state': 'present',
"state": "present",
},
"result_lines": [
"iface eno1 inet static",
@@ -467,65 +485,71 @@ class TestInterfacesFileModule(unittest.TestCase):
for testname in testcases.keys():
lines, ifaces = interfaces_file.read_interfaces_lines(module, testcases[testname]["source_lines"])
changed, lines = interfaces_file.set_interface_option(module, lines, testcases[testname]["input"]['iface'], testcases[testname]["input"]['option'],
testcases[testname]["input"]['value'], testcases[testname]["input"]['state'])
self.assertEqual(testcases[testname]["result_lines"], [d['line'] for d in lines if 'line' in d])
assert testcases[testname]['changed'] == changed
changed, lines = interfaces_file.set_interface_option(
module,
lines,
testcases[testname]["input"]["iface"],
testcases[testname]["input"]["option"],
testcases[testname]["input"]["value"],
testcases[testname]["input"]["state"],
)
self.assertEqual(testcases[testname]["result_lines"], [d["line"] for d in lines if "line" in d])
assert testcases[testname]["changed"] == changed
def test_inet_inet6(self):
testcases = {
"change_ipv4": [
{
'iface': 'eth0',
'address_family': 'inet',
'option': 'address',
'value': '192.168.0.42',
'state': 'present',
"iface": "eth0",
"address_family": "inet",
"option": "address",
"value": "192.168.0.42",
"state": "present",
}
],
"change_ipv6": [
{
'iface': 'eth0',
'address_family': 'inet6',
'option': 'address',
'value': 'fc00::42',
'state': 'present',
"iface": "eth0",
"address_family": "inet6",
"option": "address",
"value": "fc00::42",
"state": "present",
}
],
"change_ipv4_pre_up": [
{
'iface': 'eth0',
'address_family': 'inet',
'option': 'pre-up',
'value': 'XXXX_ipv4',
'state': 'present',
"iface": "eth0",
"address_family": "inet",
"option": "pre-up",
"value": "XXXX_ipv4",
"state": "present",
}
],
"change_ipv6_pre_up": [
{
'iface': 'eth0',
'address_family': 'inet6',
'option': 'pre-up',
'value': 'XXXX_ipv6',
'state': 'present',
"iface": "eth0",
"address_family": "inet6",
"option": "pre-up",
"value": "XXXX_ipv6",
"state": "present",
}
],
"change_ipv4_post_up": [
{
'iface': 'eth0',
'address_family': 'inet',
'option': 'post-up',
'value': 'XXXX_ipv4',
'state': 'present',
"iface": "eth0",
"address_family": "inet",
"option": "post-up",
"value": "XXXX_ipv4",
"state": "present",
}
],
"change_ipv6_post_up": [
{
'iface': 'eth0',
'address_family': 'inet6',
'option': 'post-up',
'value': 'XXXX_ipv6',
'state': 'present',
"iface": "eth0",
"address_family": "inet6",
"option": "post-up",
"value": "XXXX_ipv6",
"state": "present",
}
],
}
@@ -540,14 +564,24 @@ class TestInterfacesFileModule(unittest.TestCase):
options = options_list[0]
fail_json_iterations = []
try:
dummy, lines = interfaces_file.set_interface_option(module, lines, options['iface'], options['option'],
options['value'], options['state'], options['address_family'])
dummy, lines = interfaces_file.set_interface_option(
module,
lines,
options["iface"],
options["option"],
options["value"],
options["state"],
options["address_family"],
)
except AnsibleFailJson as e:
fail_json_iterations.append(
f"fail_json message: {e!s}\noptions:\n{json.dumps(options, sort_keys=True, indent=4, separators=(',', ': '))}")
interfaces_file.write_changes(module, [d['line'] for d in lines if 'line' in d], path)
f"fail_json message: {e!s}\noptions:\n{json.dumps(options, sort_keys=True, indent=4, separators=(',', ': '))}"
)
interfaces_file.write_changes(module, [d["line"] for d in lines if "line" in d], path)
self.compareStringWithFile("\n=====\n".join(fail_json_iterations), f"{testfile}_{testname}.exceptions.txt")
self.compareStringWithFile(
"\n=====\n".join(fail_json_iterations), f"{testfile}_{testname}.exceptions.txt"
)
self.compareInterfacesLinesToFile(lines, testfile, f"{testfile}_{testname}")
self.compareInterfacesToFile(ifaces, testfile, f"{testfile}_{testname}.json")

View File

@@ -9,78 +9,67 @@ import pytest
@pytest.fixture
def api_key(monkeypatch):
monkeypatch.setenv('LINODE_API_KEY', 'foobar')
monkeypatch.setenv("LINODE_API_KEY", "foobar")
@pytest.fixture
def auth(monkeypatch):
def patched_test_echo(dummy):
return []
monkeypatch.setattr('linode.api.Api.test_echo', patched_test_echo)
monkeypatch.setattr("linode.api.Api.test_echo", patched_test_echo)
@pytest.fixture
def access_token(monkeypatch):
monkeypatch.setenv('LINODE_ACCESS_TOKEN', 'barfoo')
monkeypatch.setenv("LINODE_ACCESS_TOKEN", "barfoo")
@pytest.fixture
def no_access_token_in_env(monkeypatch):
try:
monkeypatch.delenv('LINODE_ACCESS_TOKEN')
monkeypatch.delenv("LINODE_ACCESS_TOKEN")
except KeyError:
pass
@pytest.fixture
def default_args():
return {'state': 'present', 'label': 'foo'}
return {"state": "present", "label": "foo"}
@pytest.fixture
def mock_linode():
class Linode():
class Linode:
def delete(self, *args, **kwargs):
pass
@property
def _raw_json(self):
return {
"alerts": {
"cpu": 90,
"io": 10000,
"network_in": 10,
"network_out": 10,
"transfer_quota": 80
},
"alerts": {"cpu": 90, "io": 10000, "network_in": 10, "network_out": 10, "transfer_quota": 80},
"backups": {
"enabled": False,
"schedule": {
"day": None,
"window": None,
}
},
},
"created": "2018-09-26T08:12:33",
"group": "Foobar Group",
"hypervisor": "kvm",
"id": 10480444,
"image": "linode/centos7",
"ipv4": [
"130.132.285.233"
],
"ipv4": ["130.132.285.233"],
"ipv6": "2a82:7e00::h03c:46ff:fe04:5cd2/64",
"label": "lin-foo",
"region": "eu-west",
"specs": {
"disk": 25600,
"memory": 1024,
"transfer": 1000,
"vcpus": 1
},
"specs": {"disk": 25600, "memory": 1024, "transfer": 1000, "vcpus": 1},
"status": "running",
"tags": [],
"type": "g6-nanode-1",
"updated": "2018-09-26T10:10:14",
"watchdog_enabled": True
"watchdog_enabled": True,
}
return Linode()

View File

@@ -13,7 +13,7 @@ from hpOneView.oneview_client import OneViewClient
@pytest.fixture
def mock_ov_client():
patcher_json_file = patch.object(OneViewClient, 'from_json_file')
patcher_json_file = patch.object(OneViewClient, "from_json_file")
client = patcher_json_file.start()
return client.return_value

View File

@@ -9,11 +9,11 @@ from unittest.mock import Mock
# FIXME: These should be done inside of a fixture so that they're only mocked during
# these unittests
if 'hpOneView' not in sys.modules:
sys.modules['hpOneView'] = Mock()
sys.modules['hpOneView.oneview_client'] = Mock()
if "hpOneView" not in sys.modules:
sys.modules["hpOneView"] = Mock()
sys.modules["hpOneView.oneview_client"] = Mock()
ONEVIEW_MODULE_UTILS_PATH = 'ansible_collections.community.general.plugins.module_utils.oneview'
ONEVIEW_MODULE_UTILS_PATH = "ansible_collections.community.general.plugins.module_utils.oneview"
from ansible_collections.community.general.plugins.module_utils.oneview import ( # noqa: F401, pylint: disable=unused-import
OneViewModuleException,
OneViewModuleTaskError,

View File

@@ -9,7 +9,12 @@ from unittest.mock import patch
import pytest
from ansible_collections.community.general.plugins.modules import alerta_customer
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase, set_module_args
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
AnsibleExitJson,
AnsibleFailJson,
ModuleTestCase,
set_module_args,
)
class MockedReponse:
@@ -21,53 +26,62 @@ class MockedReponse:
def customer_response_page1():
server_response = json.dumps({"customers": [
server_response = json.dumps(
{
"customer": "admin",
"href": "http://localhost:8080/api/customer/d89664a7-9c87-4ab9-8be8-830e7e5f0616",
"id": "d89664a7-9c87-4ab9-8be8-830e7e5f0616",
"match": "admin@example.com"
},
{
"customer": "Developer",
"href": "http://localhost:8080/api/customer/188ed093-84cc-4f46-bf80-4c9127180d9c",
"id": "188ed093-84cc-4f46-bf80-4c9127180d9c",
"match": "dev@example.com"
}],
"more": True,
"page": 1,
"pageSize": 50,
"pages": 1,
"status": "ok",
"total": 2})
"customers": [
{
"customer": "admin",
"href": "http://localhost:8080/api/customer/d89664a7-9c87-4ab9-8be8-830e7e5f0616",
"id": "d89664a7-9c87-4ab9-8be8-830e7e5f0616",
"match": "admin@example.com",
},
{
"customer": "Developer",
"href": "http://localhost:8080/api/customer/188ed093-84cc-4f46-bf80-4c9127180d9c",
"id": "188ed093-84cc-4f46-bf80-4c9127180d9c",
"match": "dev@example.com",
},
],
"more": True,
"page": 1,
"pageSize": 50,
"pages": 1,
"status": "ok",
"total": 2,
}
)
return (MockedReponse(server_response), {"status": 200})
def customer_response_page2():
server_response = json.dumps({"customers": [
server_response = json.dumps(
{
"customer": "admin",
"href": "http://localhost:8080/api/customer/d89664a7-9c87-4ab9-8be8-830e7e5f0616",
"id": "d89664a7-9c87-4ab9-8be8-830e7e5f0616",
"match": "admin@example.com"
},
{
"customer": "Developer",
"href": "http://localhost:8080/api/customer/188ed093-84cc-4f46-bf80-4c9127180d9c",
"id": "188ed093-84cc-4f46-bf80-4c9127180d9c",
"match": "dev@example.com"
}],
"more": True,
"page": 2,
"pageSize": 50,
"pages": 2,
"status": "ok",
"total": 52})
"customers": [
{
"customer": "admin",
"href": "http://localhost:8080/api/customer/d89664a7-9c87-4ab9-8be8-830e7e5f0616",
"id": "d89664a7-9c87-4ab9-8be8-830e7e5f0616",
"match": "admin@example.com",
},
{
"customer": "Developer",
"href": "http://localhost:8080/api/customer/188ed093-84cc-4f46-bf80-4c9127180d9c",
"id": "188ed093-84cc-4f46-bf80-4c9127180d9c",
"match": "dev@example.com",
},
],
"more": True,
"page": 2,
"pageSize": 50,
"pages": 2,
"status": "ok",
"total": 52,
}
)
return (MockedReponse(server_response), {"status": 200})
class TestAlertaCustomerModule(ModuleTestCase):
def setUp(self):
super().setUp()
self.module = alerta_customer
@@ -87,23 +101,23 @@ class TestAlertaCustomerModule(ModuleTestCase):
def test_without_content(self):
"""Failure if customer and match are missing"""
with set_module_args({
'alerta_url': "http://localhost:8080",
'api_username': "admin@example.com",
'api_password': "password"
}):
with set_module_args(
{"alerta_url": "http://localhost:8080", "api_username": "admin@example.com", "api_password": "password"}
):
with self.assertRaises(AnsibleFailJson):
self.module.main()
def test_successful_existing_customer_creation(self):
"""Test the customer creation (already exists)."""
with set_module_args({
'alerta_url': "http://localhost:8080",
'api_username': "admin@example.com",
'api_password': "password",
'customer': 'Developer',
'match': 'dev@example.com'
}):
with set_module_args(
{
"alerta_url": "http://localhost:8080",
"api_username": "admin@example.com",
"api_password": "password",
"customer": "Developer",
"match": "dev@example.com",
}
):
with patch.object(alerta_customer, "fetch_url") as fetch_url_mock:
fetch_url_mock.return_value = customer_response_page1()
with self.assertRaises(AnsibleExitJson):
@@ -112,97 +126,118 @@ class TestAlertaCustomerModule(ModuleTestCase):
def test_successful_customer_creation(self):
"""Test the customer creation."""
with set_module_args({
'alerta_url': "http://localhost:8080",
'api_username': "admin@example.com",
'api_password': "password",
'customer': 'Developer',
'match': 'dev2@example.com'
}):
with set_module_args(
{
"alerta_url": "http://localhost:8080",
"api_username": "admin@example.com",
"api_password": "password",
"customer": "Developer",
"match": "dev2@example.com",
}
):
with patch.object(alerta_customer, "fetch_url") as fetch_url_mock:
fetch_url_mock.return_value = customer_response_page1()
with self.assertRaises(AnsibleExitJson):
self.module.main()
self.assertTrue(fetch_url_mock.call_count, 1)
call_data = json.loads(fetch_url_mock.call_args[1]['data'])
assert call_data['match'] == "dev2@example.com"
assert call_data['customer'] == "Developer"
call_data = json.loads(fetch_url_mock.call_args[1]["data"])
assert call_data["match"] == "dev2@example.com"
assert call_data["customer"] == "Developer"
def test_successful_customer_creation_key(self):
"""Test the customer creation using api_key."""
with set_module_args({
'alerta_url': "http://localhost:8080",
'api_key': "demo-key",
'customer': 'Developer',
'match': 'dev2@example.com'
}):
with set_module_args(
{
"alerta_url": "http://localhost:8080",
"api_key": "demo-key",
"customer": "Developer",
"match": "dev2@example.com",
}
):
with patch.object(alerta_customer, "fetch_url") as fetch_url_mock:
fetch_url_mock.return_value = customer_response_page1()
with self.assertRaises(AnsibleExitJson):
self.module.main()
self.assertTrue(fetch_url_mock.call_count, 1)
call_data = json.loads(fetch_url_mock.call_args[1]['data'])
assert call_data['match'] == "dev2@example.com"
assert call_data['customer'] == "Developer"
call_data = json.loads(fetch_url_mock.call_args[1]["data"])
assert call_data["match"] == "dev2@example.com"
assert call_data["customer"] == "Developer"
def test_failed_not_found(self):
"""Test failure with wrong URL."""
with set_module_args({
'alerta_url': "http://localhost:8080/s",
'api_username': "admin@example.com",
'api_password': "password",
'customer': 'Developer',
'match': 'dev@example.com'
}):
with set_module_args(
{
"alerta_url": "http://localhost:8080/s",
"api_username": "admin@example.com",
"api_password": "password",
"customer": "Developer",
"match": "dev@example.com",
}
):
with patch.object(alerta_customer, "fetch_url") as fetch_url_mock:
fetch_url_mock.return_value = (None, {"status": 404, 'msg': 'Not found for request GET on http://localhost:8080/a/api/customers'})
fetch_url_mock.return_value = (
None,
{"status": 404, "msg": "Not found for request GET on http://localhost:8080/a/api/customers"},
)
with self.assertRaises(AnsibleFailJson):
self.module.main()
def test_failed_forbidden(self):
"""Test failure with wrong user."""
with set_module_args({
'alerta_url': "http://localhost:8080",
'api_username': "dev@example.com",
'api_password': "password",
'customer': 'Developer',
'match': 'dev@example.com'
}):
with set_module_args(
{
"alerta_url": "http://localhost:8080",
"api_username": "dev@example.com",
"api_password": "password",
"customer": "Developer",
"match": "dev@example.com",
}
):
with patch.object(alerta_customer, "fetch_url") as fetch_url_mock:
fetch_url_mock.return_value = (None, {"status": 403, 'msg': 'Permission Denied for GET on http://localhost:8080/api/customers'})
fetch_url_mock.return_value = (
None,
{"status": 403, "msg": "Permission Denied for GET on http://localhost:8080/api/customers"},
)
with self.assertRaises(AnsibleFailJson):
self.module.main()
def test_failed_unauthorized(self):
"""Test failure with wrong username or password."""
with set_module_args({
'alerta_url': "http://localhost:8080",
'api_username': "admin@example.com",
'api_password': "password_wrong",
'customer': 'Developer',
'match': 'dev@example.com'
}):
with set_module_args(
{
"alerta_url": "http://localhost:8080",
"api_username": "admin@example.com",
"api_password": "password_wrong",
"customer": "Developer",
"match": "dev@example.com",
}
):
with patch.object(alerta_customer, "fetch_url") as fetch_url_mock:
fetch_url_mock.return_value = (None, {"status": 401, 'msg': 'Unauthorized to request GET on http://localhost:8080/api/customers'})
fetch_url_mock.return_value = (
None,
{"status": 401, "msg": "Unauthorized to request GET on http://localhost:8080/api/customers"},
)
with self.assertRaises(AnsibleFailJson):
self.module.main()
def test_successful_customer_deletion(self):
"""Test the customer deletion."""
with set_module_args({
'alerta_url': "http://localhost:8080",
'api_username': "admin@example.com",
'api_password': "password",
'customer': 'Developer',
'match': 'dev@example.com',
'state': 'absent'
}):
with set_module_args(
{
"alerta_url": "http://localhost:8080",
"api_username": "admin@example.com",
"api_password": "password",
"customer": "Developer",
"match": "dev@example.com",
"state": "absent",
}
):
with patch.object(alerta_customer, "fetch_url") as fetch_url_mock:
fetch_url_mock.return_value = customer_response_page1()
with self.assertRaises(AnsibleExitJson):
@@ -211,14 +246,16 @@ class TestAlertaCustomerModule(ModuleTestCase):
def test_successful_customer_deletion_page2(self):
"""Test the customer deletion on the second page."""
with set_module_args({
'alerta_url': "http://localhost:8080",
'api_username': "admin@example.com",
'api_password': "password",
'customer': 'Developer',
'match': 'dev@example.com',
'state': 'absent'
}):
with set_module_args(
{
"alerta_url": "http://localhost:8080",
"api_username": "admin@example.com",
"api_password": "password",
"customer": "Developer",
"match": "dev@example.com",
"state": "absent",
}
):
with patch.object(alerta_customer, "fetch_url") as fetch_url_mock:
fetch_url_mock.return_value = customer_response_page2()
with self.assertRaises(AnsibleExitJson):
@@ -227,14 +264,16 @@ class TestAlertaCustomerModule(ModuleTestCase):
def test_successful_nonexisting_customer_deletion(self):
"""Test the customer deletion (non existing)."""
with set_module_args({
'alerta_url': "http://localhost:8080",
'api_username': "admin@example.com",
'api_password': "password",
'customer': 'Billing',
'match': 'dev@example.com',
'state': 'absent'
}):
with set_module_args(
{
"alerta_url": "http://localhost:8080",
"api_username": "admin@example.com",
"api_password": "password",
"customer": "Billing",
"match": "dev@example.com",
"state": "absent",
}
):
with patch.object(alerta_customer, "fetch_url") as fetch_url_mock:
fetch_url_mock.return_value = customer_response_page1()
with self.assertRaises(AnsibleExitJson):

View File

@@ -9,11 +9,11 @@ import pytest
from ansible_collections.community.general.plugins.modules.apache2_module import create_apache_identifier
REPLACEMENTS = [
('php7.1', 'php7_module'),
('php5.6', 'php5_module'),
('shib2', 'mod_shib'),
('evasive', 'evasive20_module'),
('thismoduledoesnotexist', 'thismoduledoesnotexist_module'), # the default
("php7.1", "php7_module"),
("php5.6", "php5_module"),
("shib2", "mod_shib"),
("evasive", "evasive20_module"),
("thismoduledoesnotexist", "thismoduledoesnotexist_module"), # the default
]

View File

@@ -11,14 +11,13 @@ from ansible_collections.community.general.plugins.modules import apk
class TestApkQueryLatest(unittest.TestCase):
def setUp(self):
self.module_names = [
'bash',
'g++',
"bash",
"g++",
]
@mock.patch('ansible_collections.community.general.plugins.modules.apk.AnsibleModule')
@mock.patch("ansible_collections.community.general.plugins.modules.apk.AnsibleModule")
def test_not_latest(self, mock_module):
apk.APK_PATH = [""]
for module_name in self.module_names:
@@ -27,7 +26,7 @@ class TestApkQueryLatest(unittest.TestCase):
command_result = apk.query_latest(mock_module, module_name)
self.assertFalse(command_result)
@mock.patch('ansible_collections.community.general.plugins.modules.apk.AnsibleModule')
@mock.patch("ansible_collections.community.general.plugins.modules.apk.AnsibleModule")
def test_latest(self, mock_module):
apk.APK_PATH = [""]
for module_name in self.module_names:

View File

@@ -8,7 +8,10 @@ import pytest
from unittest.mock import Mock, patch
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import ModuleTestCase, set_module_args
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
ModuleTestCase,
set_module_args,
)
from ansible_collections.community.general.plugins.modules.archive import get_archive, common_path
@@ -16,29 +19,23 @@ class TestArchive(ModuleTestCase):
def setUp(self):
super().setUp()
self.mock_os_path_isdir = patch('os.path.isdir')
self.mock_os_path_isdir = patch("os.path.isdir")
self.os_path_isdir = self.mock_os_path_isdir.start()
def tearDown(self):
self.os_path_isdir = self.mock_os_path_isdir.stop()
def test_archive_removal_safety(self):
with set_module_args(
dict(
path=['/foo', '/bar', '/baz'],
dest='/foo/destination.tgz',
remove=True
)
):
with set_module_args(dict(path=["/foo", "/bar", "/baz"], dest="/foo/destination.tgz", remove=True)):
module = AnsibleModule(
argument_spec=dict(
path=dict(type='list', elements='path', required=True),
format=dict(type='str', default='gz', choices=['bz2', 'gz', 'tar', 'xz', 'zip']),
dest=dict(type='path'),
exclude_path=dict(type='list', elements='path', default=[]),
exclusion_patterns=dict(type='list', elements='path'),
force_archive=dict(type='bool', default=False),
remove=dict(type='bool', default=False),
path=dict(type="list", elements="path", required=True),
format=dict(type="str", default="gz", choices=["bz2", "gz", "tar", "xz", "zip"]),
dest=dict(type="path"),
exclude_path=dict(type="list", elements="path", default=[]),
exclusion_patterns=dict(type="list", elements="path"),
force_archive=dict(type="bool", default=False),
remove=dict(type="bool", default=False),
),
add_file_common_args=True,
supports_check_mode=True,
@@ -51,19 +48,19 @@ class TestArchive(ModuleTestCase):
archive = get_archive(module)
module.fail_json.assert_called_once_with(
path=b', '.join(archive.paths),
msg='Error, created archive can not be contained in source paths when remove=true'
path=b", ".join(archive.paths),
msg="Error, created archive can not be contained in source paths when remove=true",
)
PATHS: tuple[tuple[list[str | bytes], str | bytes], ...] = (
([], ''),
(['/'], '/'),
([b'/'], b'/'),
(['/foo', '/bar', '/baz', '/foobar', '/barbaz', '/foo/bar'], '/'),
([b'/foo', b'/bar', b'/baz', b'/foobar', b'/barbaz', b'/foo/bar'], b'/'),
(['/foo/bar/baz', '/foo/bar'], '/foo/'),
(['/foo/bar/baz', '/foo/bar/'], '/foo/bar/'),
([], ""),
(["/"], "/"),
([b"/"], b"/"),
(["/foo", "/bar", "/baz", "/foobar", "/barbaz", "/foo/bar"], "/"),
([b"/foo", b"/bar", b"/baz", b"/foobar", b"/barbaz", b"/foo/bar"], b"/"),
(["/foo/bar/baz", "/foo/bar"], "/foo/"),
(["/foo/bar/baz", "/foo/bar/"], "/foo/bar/"),
)

View File

@@ -9,7 +9,12 @@ from unittest.mock import patch
from ansible_collections.community.general.plugins.module_utils.source_control.bitbucket import BitbucketHelper
from ansible_collections.community.general.plugins.modules import bitbucket_access_key
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import AnsibleFailJson, AnsibleExitJson, ModuleTestCase, set_module_args
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
AnsibleFailJson,
AnsibleExitJson,
ModuleTestCase,
set_module_args,
)
class TestBucketAccessKeyModule(ModuleTestCase):
@@ -19,325 +24,313 @@ class TestBucketAccessKeyModule(ModuleTestCase):
def test_missing_key_with_present_state(self):
with self.assertRaises(AnsibleFailJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'label': 'key name',
'state': 'present',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"label": "key name",
"state": "present",
}
):
self.module.main()
self.assertEqual(exec_info.exception.args[0]['msg'], self.module.error_messages['required_key'])
self.assertEqual(exec_info.exception.args[0]["msg"], self.module.error_messages["required_key"])
@patch.object(bitbucket_access_key, 'get_existing_deploy_key', return_value=None)
@patch.object(bitbucket_access_key, "get_existing_deploy_key", return_value=None)
def test_create_deploy_key(self, *args):
with patch.object(self.module, 'create_deploy_key') as create_deploy_key_mock:
with patch.object(self.module, "create_deploy_key") as create_deploy_key_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'user': 'ABC',
'password': 'XXX',
'workspace': 'name',
'repository': 'repo',
'key': 'public_key',
'label': 'key name',
'state': 'present',
}):
with set_module_args(
{
"user": "ABC",
"password": "XXX",
"workspace": "name",
"repository": "repo",
"key": "public_key",
"label": "key name",
"state": "present",
}
):
self.module.main()
self.assertEqual(create_deploy_key_mock.call_count, 1)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_access_key, 'get_existing_deploy_key', return_value=None)
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(bitbucket_access_key, "get_existing_deploy_key", return_value=None)
def test_create_deploy_key_check_mode(self, *args):
with patch.object(self.module, 'create_deploy_key') as create_deploy_key_mock:
with patch.object(self.module, "create_deploy_key") as create_deploy_key_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'key': 'public_key',
'label': 'key name',
'state': 'present',
'_ansible_check_mode': True,
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"key": "public_key",
"label": "key name",
"state": "present",
"_ansible_check_mode": True,
}
):
self.module.main()
self.assertEqual(create_deploy_key_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_access_key, 'get_existing_deploy_key', return_value={
"id": 123,
"label": "mykey",
"created_on": "2019-03-23T10:15:21.517377+00:00",
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADA...AdkTg7HGqL3rlaDrEcWfL7Lu6TnhBdq5",
"type": "deploy_key",
"comment": "",
"last_used": None,
"repository": {
"links": {
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/mleu/test"
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_access_key,
"get_existing_deploy_key",
return_value={
"id": 123,
"label": "mykey",
"created_on": "2019-03-23T10:15:21.517377+00:00",
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADA...AdkTg7HGqL3rlaDrEcWfL7Lu6TnhBdq5",
"type": "deploy_key",
"comment": "",
"last_used": None,
"repository": {
"links": {
"self": {"href": "https://api.bitbucket.org/2.0/repositories/mleu/test"},
"html": {"href": "https://bitbucket.org/mleu/test"},
"avatar": {"href": "..."},
},
"html": {
"href": "https://bitbucket.org/mleu/test"
},
"avatar": {
"href": "..."
}
"type": "repository",
"name": "test",
"full_name": "mleu/test",
"uuid": "{85d08b4e-571d-44e9-a507-fa476535aa98}",
},
"type": "repository",
"name": "test",
"full_name": "mleu/test",
"uuid": "{85d08b4e-571d-44e9-a507-fa476535aa98}"
"links": {"self": {"href": "https://api.bitbucket.org/2.0/repositories/mleu/test/deploy-keys/123"}},
},
"links": {
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/mleu/test/deploy-keys/123"
}
},
})
)
def test_update_deploy_key(self, *args):
with patch.object(self.module, 'delete_deploy_key') as delete_deploy_key_mock:
with patch.object(self.module, 'create_deploy_key') as create_deploy_key_mock:
with patch.object(self.module, "delete_deploy_key") as delete_deploy_key_mock:
with patch.object(self.module, "create_deploy_key") as create_deploy_key_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'key': 'new public key',
'label': 'mykey',
'state': 'present',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"key": "new public key",
"label": "mykey",
"state": "present",
}
):
self.module.main()
self.assertEqual(delete_deploy_key_mock.call_count, 1)
self.assertEqual(create_deploy_key_mock.call_count, 1)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_access_key, 'get_existing_deploy_key', return_value={
"id": 123,
"label": "mykey",
"created_on": "2019-03-23T10:15:21.517377+00:00",
"key": "new public key",
"type": "deploy_key",
"comment": "",
"last_used": None,
"repository": {
"links": {
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/mleu/test"
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_access_key,
"get_existing_deploy_key",
return_value={
"id": 123,
"label": "mykey",
"created_on": "2019-03-23T10:15:21.517377+00:00",
"key": "new public key",
"type": "deploy_key",
"comment": "",
"last_used": None,
"repository": {
"links": {
"self": {"href": "https://api.bitbucket.org/2.0/repositories/mleu/test"},
"html": {"href": "https://bitbucket.org/mleu/test"},
"avatar": {"href": "..."},
},
"html": {
"href": "https://bitbucket.org/mleu/test"
},
"avatar": {
"href": "..."
}
"type": "repository",
"name": "test",
"full_name": "mleu/test",
"uuid": "{85d08b4e-571d-44e9-a507-fa476535aa98}",
},
"type": "repository",
"name": "test",
"full_name": "mleu/test",
"uuid": "{85d08b4e-571d-44e9-a507-fa476535aa98}"
"links": {"self": {"href": "https://api.bitbucket.org/2.0/repositories/mleu/test/deploy-keys/123"}},
},
"links": {
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/mleu/test/deploy-keys/123"
}
},
})
)
def test_dont_update_same_value(self, *args):
with patch.object(self.module, 'delete_deploy_key') as delete_deploy_key_mock:
with patch.object(self.module, 'create_deploy_key') as create_deploy_key_mock:
with patch.object(self.module, "delete_deploy_key") as delete_deploy_key_mock:
with patch.object(self.module, "create_deploy_key") as create_deploy_key_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'key': 'new public key',
'label': 'mykey',
'state': 'present',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"key": "new public key",
"label": "mykey",
"state": "present",
}
):
self.module.main()
self.assertEqual(delete_deploy_key_mock.call_count, 0)
self.assertEqual(create_deploy_key_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], False)
self.assertEqual(exec_info.exception.args[0]["changed"], False)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_access_key, 'get_existing_deploy_key', return_value={
"id": 123,
"label": "mykey",
"created_on": "2019-03-23T10:15:21.517377+00:00",
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADA...AdkTg7HGqL3rlaDrEcWfL7Lu6TnhBdq5",
"type": "deploy_key",
"comment": "",
"last_used": None,
"repository": {
"links": {
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/mleu/test"
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_access_key,
"get_existing_deploy_key",
return_value={
"id": 123,
"label": "mykey",
"created_on": "2019-03-23T10:15:21.517377+00:00",
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADA...AdkTg7HGqL3rlaDrEcWfL7Lu6TnhBdq5",
"type": "deploy_key",
"comment": "",
"last_used": None,
"repository": {
"links": {
"self": {"href": "https://api.bitbucket.org/2.0/repositories/mleu/test"},
"html": {"href": "https://bitbucket.org/mleu/test"},
"avatar": {"href": "..."},
},
"html": {
"href": "https://bitbucket.org/mleu/test"
},
"avatar": {
"href": "..."
}
"type": "repository",
"name": "test",
"full_name": "mleu/test",
"uuid": "{85d08b4e-571d-44e9-a507-fa476535aa98}",
},
"type": "repository",
"name": "test",
"full_name": "mleu/test",
"uuid": "{85d08b4e-571d-44e9-a507-fa476535aa98}"
"links": {"self": {"href": "https://api.bitbucket.org/2.0/repositories/mleu/test/deploy-keys/123"}},
},
"links": {
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/mleu/test/deploy-keys/123"
}
},
})
)
def test_update_deploy_key_check_mode(self, *args):
with patch.object(self.module, 'delete_deploy_key') as delete_deploy_key_mock:
with patch.object(self.module, 'create_deploy_key') as create_deploy_key_mock:
with patch.object(self.module, "delete_deploy_key") as delete_deploy_key_mock:
with patch.object(self.module, "create_deploy_key") as create_deploy_key_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'key': 'new public key',
'label': 'mykey',
'state': 'present',
'_ansible_check_mode': True,
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"key": "new public key",
"label": "mykey",
"state": "present",
"_ansible_check_mode": True,
}
):
self.module.main()
self.assertEqual(delete_deploy_key_mock.call_count, 0)
self.assertEqual(create_deploy_key_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_access_key, 'get_existing_deploy_key', return_value={
"id": 123,
"label": "mykey",
"created_on": "2019-03-23T10:15:21.517377+00:00",
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADA...AdkTg7HGqL3rlaDrEcWfL7Lu6TnhBdq5",
"type": "deploy_key",
"comment": "",
"last_used": None,
"repository": {
"links": {
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/mleu/test"
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_access_key,
"get_existing_deploy_key",
return_value={
"id": 123,
"label": "mykey",
"created_on": "2019-03-23T10:15:21.517377+00:00",
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADA...AdkTg7HGqL3rlaDrEcWfL7Lu6TnhBdq5",
"type": "deploy_key",
"comment": "",
"last_used": None,
"repository": {
"links": {
"self": {"href": "https://api.bitbucket.org/2.0/repositories/mleu/test"},
"html": {"href": "https://bitbucket.org/mleu/test"},
"avatar": {"href": "..."},
},
"html": {
"href": "https://bitbucket.org/mleu/test"
},
"avatar": {
"href": "..."
}
"type": "repository",
"name": "test",
"full_name": "mleu/test",
"uuid": "{85d08b4e-571d-44e9-a507-fa476535aa98}",
},
"type": "repository",
"name": "test",
"full_name": "mleu/test",
"uuid": "{85d08b4e-571d-44e9-a507-fa476535aa98}"
"links": {"self": {"href": "https://api.bitbucket.org/2.0/repositories/mleu/test/deploy-keys/123"}},
},
"links": {
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/mleu/test/deploy-keys/123"
}
},
})
)
def test_delete_deploy_key(self, *args):
with patch.object(self.module, 'delete_deploy_key') as delete_deploy_key_mock:
with patch.object(self.module, "delete_deploy_key") as delete_deploy_key_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'label': 'mykey',
'state': 'absent',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"label": "mykey",
"state": "absent",
}
):
self.module.main()
self.assertEqual(delete_deploy_key_mock.call_count, 1)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_access_key, 'get_existing_deploy_key', return_value=None)
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(bitbucket_access_key, "get_existing_deploy_key", return_value=None)
def test_delete_absent_deploy_key(self, *args):
with patch.object(self.module, 'delete_deploy_key') as delete_deploy_key_mock:
with patch.object(self.module, "delete_deploy_key") as delete_deploy_key_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'label': 'mykey',
'state': 'absent',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"label": "mykey",
"state": "absent",
}
):
self.module.main()
self.assertEqual(delete_deploy_key_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], False)
self.assertEqual(exec_info.exception.args[0]["changed"], False)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_access_key, 'get_existing_deploy_key', return_value={
"id": 123,
"label": "mykey",
"created_on": "2019-03-23T10:15:21.517377+00:00",
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADA...AdkTg7HGqL3rlaDrEcWfL7Lu6TnhBdq5",
"type": "deploy_key",
"comment": "",
"last_used": None,
"repository": {
"links": {
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/mleu/test"
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_access_key,
"get_existing_deploy_key",
return_value={
"id": 123,
"label": "mykey",
"created_on": "2019-03-23T10:15:21.517377+00:00",
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADA...AdkTg7HGqL3rlaDrEcWfL7Lu6TnhBdq5",
"type": "deploy_key",
"comment": "",
"last_used": None,
"repository": {
"links": {
"self": {"href": "https://api.bitbucket.org/2.0/repositories/mleu/test"},
"html": {"href": "https://bitbucket.org/mleu/test"},
"avatar": {"href": "..."},
},
"html": {
"href": "https://bitbucket.org/mleu/test"
},
"avatar": {
"href": "..."
}
"type": "repository",
"name": "test",
"full_name": "mleu/test",
"uuid": "{85d08b4e-571d-44e9-a507-fa476535aa98}",
},
"type": "repository",
"name": "test",
"full_name": "mleu/test",
"uuid": "{85d08b4e-571d-44e9-a507-fa476535aa98}"
"links": {"self": {"href": "https://api.bitbucket.org/2.0/repositories/mleu/test/deploy-keys/123"}},
},
"links": {
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/mleu/test/deploy-keys/123"
}
},
})
)
def test_delete_deploy_key_check_mode(self, *args):
with patch.object(self.module, 'delete_deploy_key') as delete_deploy_key_mock:
with patch.object(self.module, "delete_deploy_key") as delete_deploy_key_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'label': 'mykey',
'state': 'absent',
'_ansible_check_mode': True,
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"label": "mykey",
"state": "absent",
"_ansible_check_mode": True,
}
):
self.module.main()
self.assertEqual(delete_deploy_key_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()

View File

@@ -9,7 +9,12 @@ from unittest.mock import patch
from ansible_collections.community.general.plugins.module_utils.source_control.bitbucket import BitbucketHelper
from ansible_collections.community.general.plugins.modules import bitbucket_pipeline_key_pair
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import AnsibleFailJson, AnsibleExitJson, ModuleTestCase, set_module_args
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
AnsibleFailJson,
AnsibleExitJson,
ModuleTestCase,
set_module_args,
)
class TestBucketPipelineKeyPairModule(ModuleTestCase):
@@ -19,180 +24,218 @@ class TestBucketPipelineKeyPairModule(ModuleTestCase):
def test_missing_keys_with_present_state(self):
with self.assertRaises(AnsibleFailJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'state': 'present',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"state": "present",
}
):
self.module.main()
self.assertEqual(exec_info.exception.args[0]['msg'], self.module.error_messages['required_keys'])
self.assertEqual(exec_info.exception.args[0]["msg"], self.module.error_messages["required_keys"])
@patch.object(bitbucket_pipeline_key_pair, 'get_existing_ssh_key_pair', return_value=None)
@patch.object(bitbucket_pipeline_key_pair, "get_existing_ssh_key_pair", return_value=None)
def test_create_keys(self, *args):
with patch.object(self.module, 'update_ssh_key_pair') as update_ssh_key_pair_mock:
with patch.object(self.module, "update_ssh_key_pair") as update_ssh_key_pair_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'user': 'ABC',
'password': 'XXX',
'workspace': 'name',
'repository': 'repo',
'public_key': 'public',
'private_key': 'PRIVATE',
'state': 'present',
}):
with set_module_args(
{
"user": "ABC",
"password": "XXX",
"workspace": "name",
"repository": "repo",
"public_key": "public",
"private_key": "PRIVATE",
"state": "present",
}
):
self.module.main()
self.assertEqual(update_ssh_key_pair_mock.call_count, 1)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_key_pair, 'get_existing_ssh_key_pair', return_value=None)
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(bitbucket_pipeline_key_pair, "get_existing_ssh_key_pair", return_value=None)
def test_create_keys_check_mode(self, *args):
with patch.object(self.module, 'update_ssh_key_pair') as update_ssh_key_pair_mock:
with patch.object(self.module, "update_ssh_key_pair") as update_ssh_key_pair_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'public_key': 'public',
'private_key': 'PRIVATE',
'state': 'present',
'_ansible_check_mode': True,
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"public_key": "public",
"private_key": "PRIVATE",
"state": "present",
"_ansible_check_mode": True,
}
):
self.module.main()
self.assertEqual(update_ssh_key_pair_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_key_pair, 'get_existing_ssh_key_pair', return_value={
'public_key': 'unknown',
'type': 'pipeline_ssh_key_pair',
})
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_pipeline_key_pair,
"get_existing_ssh_key_pair",
return_value={
"public_key": "unknown",
"type": "pipeline_ssh_key_pair",
},
)
def test_update_keys(self, *args):
with patch.object(self.module, 'update_ssh_key_pair') as update_ssh_key_pair_mock:
with patch.object(self.module, "update_ssh_key_pair") as update_ssh_key_pair_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'public_key': 'public',
'private_key': 'PRIVATE',
'state': 'present',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"public_key": "public",
"private_key": "PRIVATE",
"state": "present",
}
):
self.module.main()
self.assertEqual(update_ssh_key_pair_mock.call_count, 1)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_key_pair, 'get_existing_ssh_key_pair', return_value={
'public_key': 'public',
'type': 'pipeline_ssh_key_pair',
})
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_pipeline_key_pair,
"get_existing_ssh_key_pair",
return_value={
"public_key": "public",
"type": "pipeline_ssh_key_pair",
},
)
def test_dont_update_same_key(self, *args):
with patch.object(self.module, 'update_ssh_key_pair') as update_ssh_key_pair_mock:
with patch.object(self.module, "update_ssh_key_pair") as update_ssh_key_pair_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'public_key': 'public',
'private_key': 'PRIVATE',
'state': 'present',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"public_key": "public",
"private_key": "PRIVATE",
"state": "present",
}
):
self.module.main()
self.assertEqual(update_ssh_key_pair_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], False)
self.assertEqual(exec_info.exception.args[0]["changed"], False)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_key_pair, 'get_existing_ssh_key_pair', return_value={
'public_key': 'unknown',
'type': 'pipeline_ssh_key_pair',
})
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_pipeline_key_pair,
"get_existing_ssh_key_pair",
return_value={
"public_key": "unknown",
"type": "pipeline_ssh_key_pair",
},
)
def test_update_keys_check_mode(self, *args):
with patch.object(self.module, 'update_ssh_key_pair') as update_ssh_key_pair_mock:
with patch.object(self.module, "update_ssh_key_pair") as update_ssh_key_pair_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'public_key': 'public',
'private_key': 'PRIVATE',
'state': 'present',
'_ansible_check_mode': True,
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"public_key": "public",
"private_key": "PRIVATE",
"state": "present",
"_ansible_check_mode": True,
}
):
self.module.main()
self.assertEqual(update_ssh_key_pair_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_key_pair, 'get_existing_ssh_key_pair', return_value={
'public_key': 'public',
'type': 'pipeline_ssh_key_pair',
})
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_pipeline_key_pair,
"get_existing_ssh_key_pair",
return_value={
"public_key": "public",
"type": "pipeline_ssh_key_pair",
},
)
def test_delete_keys(self, *args):
with patch.object(self.module, 'delete_ssh_key_pair') as delete_ssh_key_pair_mock:
with patch.object(self.module, "delete_ssh_key_pair") as delete_ssh_key_pair_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'state': 'absent',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"state": "absent",
}
):
self.module.main()
self.assertEqual(delete_ssh_key_pair_mock.call_count, 1)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_key_pair, 'get_existing_ssh_key_pair', return_value=None)
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(bitbucket_pipeline_key_pair, "get_existing_ssh_key_pair", return_value=None)
def test_delete_absent_keys(self, *args):
with patch.object(self.module, 'delete_ssh_key_pair') as delete_ssh_key_pair_mock:
with patch.object(self.module, "delete_ssh_key_pair") as delete_ssh_key_pair_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'state': 'absent',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"state": "absent",
}
):
self.module.main()
self.assertEqual(delete_ssh_key_pair_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], False)
self.assertEqual(exec_info.exception.args[0]["changed"], False)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_key_pair, 'get_existing_ssh_key_pair', return_value={
'public_key': 'public',
'type': 'pipeline_ssh_key_pair',
})
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_pipeline_key_pair,
"get_existing_ssh_key_pair",
return_value={
"public_key": "public",
"type": "pipeline_ssh_key_pair",
},
)
def test_delete_keys_check_mode(self, *args):
with patch.object(self.module, 'delete_ssh_key_pair') as delete_ssh_key_pair_mock:
with patch.object(self.module, "delete_ssh_key_pair") as delete_ssh_key_pair_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'state': 'absent',
'_ansible_check_mode': True,
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"state": "absent",
"_ansible_check_mode": True,
}
):
self.module.main()
self.assertEqual(delete_ssh_key_pair_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()

View File

@@ -12,7 +12,11 @@ import pytest
from ansible_collections.community.general.plugins.module_utils.source_control.bitbucket import BitbucketHelper
from ansible_collections.community.general.plugins.modules import bitbucket_pipeline_known_host
from ansible_collections.community.general.plugins.modules.bitbucket_pipeline_known_host import HAS_PARAMIKO
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import AnsibleExitJson, ModuleTestCase, set_module_args
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
AnsibleExitJson,
ModuleTestCase,
set_module_args,
)
class TestBucketPipelineKnownHostModule(ModuleTestCase):
@@ -20,174 +24,200 @@ class TestBucketPipelineKnownHostModule(ModuleTestCase):
super().setUp()
self.module = bitbucket_pipeline_known_host
@pytest.mark.skipif(not HAS_PARAMIKO, reason='paramiko must be installed to test key creation')
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_known_host, 'get_existing_known_host', return_value=None)
@pytest.mark.skipif(not HAS_PARAMIKO, reason="paramiko must be installed to test key creation")
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(bitbucket_pipeline_known_host, "get_existing_known_host", return_value=None)
def test_create_known_host(self, *args):
with patch.object(self.module, 'create_known_host') as create_known_host_mock:
with patch.object(self.module, "create_known_host") as create_known_host_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'name': 'bitbucket.org',
'state': 'present',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"name": "bitbucket.org",
"state": "present",
}
):
self.module.main()
self.assertEqual(create_known_host_mock.call_count, 1)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@patch.object(BitbucketHelper, 'request', return_value=(dict(status=201), dict()))
@patch.object(bitbucket_pipeline_known_host, 'get_existing_known_host', return_value=None)
@patch.object(BitbucketHelper, "request", return_value=(dict(status=201), dict()))
@patch.object(bitbucket_pipeline_known_host, "get_existing_known_host", return_value=None)
def test_create_known_host_with_key(self, *args):
with patch.object(self.module, 'get_host_key') as get_host_key_mock:
with patch.object(self.module, "get_host_key") as get_host_key_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'user': 'ABC',
'password': 'XXX',
'workspace': 'name',
'repository': 'repo',
'name': 'bitbucket.org',
'key': 'ssh-rsa public',
'state': 'present',
}):
with set_module_args(
{
"user": "ABC",
"password": "XXX",
"workspace": "name",
"repository": "repo",
"name": "bitbucket.org",
"key": "ssh-rsa public",
"state": "present",
}
):
self.module.main()
self.assertEqual(get_host_key_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@pytest.mark.skipif(not HAS_PARAMIKO, reason='paramiko must be installed to test key creation')
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_known_host, 'get_existing_known_host', return_value={
'type': 'pipeline_known_host',
'uuid': '{21cc0590-bebe-4fae-8baf-03722704119a7}',
'hostname': 'bitbucket.org',
'public_key': {
'type': 'pipeline_ssh_public_key',
'md5_fingerprint': 'md5:97:8c:1b:f2:6f:14:6b:4b:3b:ec:aa:46:46:74:7c:40',
'sha256_fingerprint': 'SHA256:zzXQOXSFBEiUtuE8AikoYKwbHaxvSc0ojez9YXaGp1A',
'key_type': 'ssh-rsa',
'key': 'AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kN...seeFVBoGqzHM9yXw=='
}
})
@pytest.mark.skipif(not HAS_PARAMIKO, reason="paramiko must be installed to test key creation")
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_pipeline_known_host,
"get_existing_known_host",
return_value={
"type": "pipeline_known_host",
"uuid": "{21cc0590-bebe-4fae-8baf-03722704119a7}",
"hostname": "bitbucket.org",
"public_key": {
"type": "pipeline_ssh_public_key",
"md5_fingerprint": "md5:97:8c:1b:f2:6f:14:6b:4b:3b:ec:aa:46:46:74:7c:40",
"sha256_fingerprint": "SHA256:zzXQOXSFBEiUtuE8AikoYKwbHaxvSc0ojez9YXaGp1A",
"key_type": "ssh-rsa",
"key": "AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kN...seeFVBoGqzHM9yXw==",
},
},
)
def test_dont_create_same_value(self, *args):
with patch.object(self.module, 'create_known_host') as create_known_host_mock:
with patch.object(self.module, "create_known_host") as create_known_host_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'name': 'bitbucket.org',
'state': 'present',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"name": "bitbucket.org",
"state": "present",
}
):
self.module.main()
self.assertEqual(create_known_host_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], False)
self.assertEqual(exec_info.exception.args[0]["changed"], False)
@pytest.mark.skipif(not HAS_PARAMIKO, reason='paramiko must be installed to test key creation')
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_known_host, 'get_existing_known_host', return_value=None)
@pytest.mark.skipif(not HAS_PARAMIKO, reason="paramiko must be installed to test key creation")
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(bitbucket_pipeline_known_host, "get_existing_known_host", return_value=None)
def test_create_known_host_check_mode(self, *args):
with patch.object(self.module, 'create_known_host') as create_known_host_mock:
with patch.object(self.module, "create_known_host") as create_known_host_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'name': 'bitbucket.org',
'state': 'present',
'_ansible_check_mode': True,
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"name": "bitbucket.org",
"state": "present",
"_ansible_check_mode": True,
}
):
self.module.main()
self.assertEqual(create_known_host_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@pytest.mark.skipif(not HAS_PARAMIKO, reason='paramiko must be installed to test key creation')
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_known_host, 'get_existing_known_host', return_value={
'type': 'pipeline_known_host',
'uuid': '{21cc0590-bebe-4fae-8baf-03722704119a7}',
'hostname': 'bitbucket.org',
'public_key': {
'type': 'pipeline_ssh_public_key',
'md5_fingerprint': 'md5:97:8c:1b:f2:6f:14:6b:4b:3b:ec:aa:46:46:74:7c:40',
'sha256_fingerprint': 'SHA256:zzXQOXSFBEiUtuE8AikoYKwbHaxvSc0ojez9YXaGp1A',
'key_type': 'ssh-rsa',
'key': 'AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kN...seeFVBoGqzHM9yXw=='
}
})
@pytest.mark.skipif(not HAS_PARAMIKO, reason="paramiko must be installed to test key creation")
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_pipeline_known_host,
"get_existing_known_host",
return_value={
"type": "pipeline_known_host",
"uuid": "{21cc0590-bebe-4fae-8baf-03722704119a7}",
"hostname": "bitbucket.org",
"public_key": {
"type": "pipeline_ssh_public_key",
"md5_fingerprint": "md5:97:8c:1b:f2:6f:14:6b:4b:3b:ec:aa:46:46:74:7c:40",
"sha256_fingerprint": "SHA256:zzXQOXSFBEiUtuE8AikoYKwbHaxvSc0ojez9YXaGp1A",
"key_type": "ssh-rsa",
"key": "AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kN...seeFVBoGqzHM9yXw==",
},
},
)
def test_delete_known_host(self, *args):
with patch.object(self.module, 'delete_known_host') as delete_known_host_mock:
with patch.object(self.module, "delete_known_host") as delete_known_host_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'name': 'bitbucket.org',
'state': 'absent',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"name": "bitbucket.org",
"state": "absent",
}
):
self.module.main()
self.assertEqual(delete_known_host_mock.call_count, 1)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@pytest.mark.skipif(not HAS_PARAMIKO, reason='paramiko must be installed to test key creation')
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_known_host, 'get_existing_known_host', return_value=None)
@pytest.mark.skipif(not HAS_PARAMIKO, reason="paramiko must be installed to test key creation")
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(bitbucket_pipeline_known_host, "get_existing_known_host", return_value=None)
def test_delete_absent_known_host(self, *args):
with patch.object(self.module, 'delete_known_host') as delete_known_host_mock:
with patch.object(self.module, "delete_known_host") as delete_known_host_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'name': 'bitbucket.org',
'state': 'absent',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"name": "bitbucket.org",
"state": "absent",
}
):
self.module.main()
self.assertEqual(delete_known_host_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], False)
self.assertEqual(exec_info.exception.args[0]["changed"], False)
@pytest.mark.skipif(not HAS_PARAMIKO, reason='paramiko must be installed to test key creation')
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_known_host, 'get_existing_known_host', return_value={
'type': 'pipeline_known_host',
'uuid': '{21cc0590-bebe-4fae-8baf-03722704119a7}',
'hostname': 'bitbucket.org',
'public_key': {
'type': 'pipeline_ssh_public_key',
'md5_fingerprint': 'md5:97:8c:1b:f2:6f:14:6b:4b:3b:ec:aa:46:46:74:7c:40',
'sha256_fingerprint': 'SHA256:zzXQOXSFBEiUtuE8AikoYKwbHaxvSc0ojez9YXaGp1A',
'key_type': 'ssh-rsa',
'key': 'AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kN...seeFVBoGqzHM9yXw=='
}
})
@pytest.mark.skipif(not HAS_PARAMIKO, reason="paramiko must be installed to test key creation")
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_pipeline_known_host,
"get_existing_known_host",
return_value={
"type": "pipeline_known_host",
"uuid": "{21cc0590-bebe-4fae-8baf-03722704119a7}",
"hostname": "bitbucket.org",
"public_key": {
"type": "pipeline_ssh_public_key",
"md5_fingerprint": "md5:97:8c:1b:f2:6f:14:6b:4b:3b:ec:aa:46:46:74:7c:40",
"sha256_fingerprint": "SHA256:zzXQOXSFBEiUtuE8AikoYKwbHaxvSc0ojez9YXaGp1A",
"key_type": "ssh-rsa",
"key": "AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kN...seeFVBoGqzHM9yXw==",
},
},
)
def test_delete_known_host_check_mode(self, *args):
with patch.object(self.module, 'delete_known_host') as delete_known_host_mock:
with patch.object(self.module, "delete_known_host") as delete_known_host_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'name': 'bitbucket.org',
'state': 'absent',
'_ansible_check_mode': True,
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"name": "bitbucket.org",
"state": "absent",
"_ansible_check_mode": True,
}
):
self.module.main()
self.assertEqual(delete_known_host_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()

View File

@@ -9,7 +9,12 @@ from unittest.mock import patch
from ansible_collections.community.general.plugins.module_utils.source_control.bitbucket import BitbucketHelper
from ansible_collections.community.general.plugins.modules import bitbucket_pipeline_variable
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import AnsibleFailJson, AnsibleExitJson, ModuleTestCase, set_module_args
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
AnsibleFailJson,
AnsibleExitJson,
ModuleTestCase,
set_module_args,
)
class TestBucketPipelineVariableModule(ModuleTestCase):
@@ -19,293 +24,355 @@ class TestBucketPipelineVariableModule(ModuleTestCase):
def test_without_required_parameters(self):
with self.assertRaises(AnsibleFailJson) as exec_info:
with set_module_args({
'workspace': 'name',
'repository': 'repo',
'name': 'PIPELINE_VAR_NAME',
'state': 'absent',
}):
with set_module_args(
{
"workspace": "name",
"repository": "repo",
"name": "PIPELINE_VAR_NAME",
"state": "absent",
}
):
self.module.main()
self.assertEqual(exec_info.exception.args[0]['failed'], True)
self.assertEqual(exec_info.exception.args[0]["failed"], True)
def test_missing_value_with_present_state(self):
with self.assertRaises(AnsibleFailJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'name': 'PIPELINE_VAR_NAME',
'state': 'present',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"name": "PIPELINE_VAR_NAME",
"state": "present",
}
):
self.module.main()
self.assertEqual(exec_info.exception.args[0]['msg'], self.module.error_messages['required_value'])
self.assertEqual(exec_info.exception.args[0]["msg"], self.module.error_messages["required_value"])
@patch.dict('os.environ', {
'BITBUCKET_CLIENT_ID': 'ABC',
'BITBUCKET_CLIENT_SECRET': 'XXX',
})
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_variable, 'get_existing_pipeline_variable', return_value=None)
@patch.dict(
"os.environ",
{
"BITBUCKET_CLIENT_ID": "ABC",
"BITBUCKET_CLIENT_SECRET": "XXX",
},
)
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(bitbucket_pipeline_variable, "get_existing_pipeline_variable", return_value=None)
def test_oauth_env_vars_params(self, *args):
with self.assertRaises(AnsibleExitJson):
with set_module_args({
'workspace': 'name',
'repository': 'repo',
'name': 'PIPELINE_VAR_NAME',
'state': 'absent',
}):
with set_module_args(
{
"workspace": "name",
"repository": "repo",
"name": "PIPELINE_VAR_NAME",
"state": "absent",
}
):
self.module.main()
@patch.dict('os.environ', {
'BITBUCKET_USERNAME': 'ABC',
'BITBUCKET_PASSWORD': 'XXX',
})
@patch.object(bitbucket_pipeline_variable, 'get_existing_pipeline_variable', return_value=None)
@patch.dict(
"os.environ",
{
"BITBUCKET_USERNAME": "ABC",
"BITBUCKET_PASSWORD": "XXX",
},
)
@patch.object(bitbucket_pipeline_variable, "get_existing_pipeline_variable", return_value=None)
def test_basic_auth_env_vars_params(self, *args):
with self.assertRaises(AnsibleExitJson):
with set_module_args({
'workspace': 'name',
'repository': 'repo',
'name': 'PIPELINE_VAR_NAME',
'state': 'absent',
}):
with set_module_args(
{
"workspace": "name",
"repository": "repo",
"name": "PIPELINE_VAR_NAME",
"state": "absent",
}
):
self.module.main()
@patch.object(bitbucket_pipeline_variable, 'get_existing_pipeline_variable', return_value=None)
@patch.object(bitbucket_pipeline_variable, "get_existing_pipeline_variable", return_value=None)
def test_create_variable(self, *args):
with patch.object(self.module, 'create_pipeline_variable') as create_pipeline_variable_mock:
with patch.object(self.module, "create_pipeline_variable") as create_pipeline_variable_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'user': 'ABC',
'password': 'XXX',
'workspace': 'name',
'repository': 'repo',
'name': 'PIPELINE_VAR_NAME',
'value': '42',
'state': 'present',
}):
with set_module_args(
{
"user": "ABC",
"password": "XXX",
"workspace": "name",
"repository": "repo",
"name": "PIPELINE_VAR_NAME",
"value": "42",
"state": "present",
}
):
self.module.main()
self.assertEqual(create_pipeline_variable_mock.call_count, 1)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_variable, 'get_existing_pipeline_variable', return_value=None)
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(bitbucket_pipeline_variable, "get_existing_pipeline_variable", return_value=None)
def test_create_variable_check_mode(self, *args):
with patch.object(self.module, 'create_pipeline_variable') as create_pipeline_variable_mock:
with patch.object(self.module, "create_pipeline_variable") as create_pipeline_variable_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'name': 'PIPELINE_VAR_NAME',
'value': '42',
'state': 'present',
'_ansible_check_mode': True,
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"name": "PIPELINE_VAR_NAME",
"value": "42",
"state": "present",
"_ansible_check_mode": True,
}
):
self.module.main()
self.assertEqual(create_pipeline_variable_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_variable, 'get_existing_pipeline_variable', return_value={
'name': 'PIPELINE_VAR_NAME',
'value': 'Im alive',
'type': 'pipeline_variable',
'secured': False,
'uuid': '{9ddb0507-439a-495a- 99f3 - 564f15138127}'
})
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_pipeline_variable,
"get_existing_pipeline_variable",
return_value={
"name": "PIPELINE_VAR_NAME",
"value": "Im alive",
"type": "pipeline_variable",
"secured": False,
"uuid": "{9ddb0507-439a-495a- 99f3 - 564f15138127}",
},
)
def test_update_variable(self, *args):
with patch.object(self.module, 'update_pipeline_variable') as update_pipeline_variable_mock:
with patch.object(self.module, "update_pipeline_variable") as update_pipeline_variable_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'name': 'PIPELINE_VAR_NAME',
'value': '42',
'state': 'present',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"name": "PIPELINE_VAR_NAME",
"value": "42",
"state": "present",
}
):
self.module.main()
self.assertEqual(update_pipeline_variable_mock.call_count, 1)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_variable, 'get_existing_pipeline_variable', return_value={
'name': 'PIPELINE_VAR_NAME',
'type': 'pipeline_variable',
'secured': True,
'uuid': '{9ddb0507-439a-495a- 99f3 - 564f15138127}'
})
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_pipeline_variable,
"get_existing_pipeline_variable",
return_value={
"name": "PIPELINE_VAR_NAME",
"type": "pipeline_variable",
"secured": True,
"uuid": "{9ddb0507-439a-495a- 99f3 - 564f15138127}",
},
)
def test_update_secured_variable(self, *args):
with patch.object(self.module, 'update_pipeline_variable') as update_pipeline_variable_mock:
with patch.object(self.module, "update_pipeline_variable") as update_pipeline_variable_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'name': 'PIPELINE_VAR_NAME',
'value': '42',
'secured': True,
'state': 'present',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"name": "PIPELINE_VAR_NAME",
"value": "42",
"secured": True,
"state": "present",
}
):
self.module.main()
self.assertEqual(update_pipeline_variable_mock.call_count, 1)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_variable, 'get_existing_pipeline_variable', return_value={
'name': 'PIPELINE_VAR_NAME',
'value': '42',
'type': 'pipeline_variable',
'secured': False,
'uuid': '{9ddb0507-439a-495a- 99f3 - 564f15138127}'
})
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_pipeline_variable,
"get_existing_pipeline_variable",
return_value={
"name": "PIPELINE_VAR_NAME",
"value": "42",
"type": "pipeline_variable",
"secured": False,
"uuid": "{9ddb0507-439a-495a- 99f3 - 564f15138127}",
},
)
def test_update_secured_state(self, *args):
with patch.object(self.module, 'update_pipeline_variable') as update_pipeline_variable_mock:
with patch.object(self.module, "update_pipeline_variable") as update_pipeline_variable_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'name': 'PIPELINE_VAR_NAME',
'value': '42',
'secured': True,
'state': 'present',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"name": "PIPELINE_VAR_NAME",
"value": "42",
"secured": True,
"state": "present",
}
):
self.module.main()
self.assertEqual(update_pipeline_variable_mock.call_count, 1)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_variable, 'get_existing_pipeline_variable', return_value={
'name': 'PIPELINE_VAR_NAME',
'value': '42',
'type': 'pipeline_variable',
'secured': False,
'uuid': '{9ddb0507-439a-495a- 99f3 - 564f15138127}'
})
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_pipeline_variable,
"get_existing_pipeline_variable",
return_value={
"name": "PIPELINE_VAR_NAME",
"value": "42",
"type": "pipeline_variable",
"secured": False,
"uuid": "{9ddb0507-439a-495a- 99f3 - 564f15138127}",
},
)
def test_dont_update_same_value(self, *args):
with patch.object(self.module, 'update_pipeline_variable') as update_pipeline_variable_mock:
with patch.object(self.module, "update_pipeline_variable") as update_pipeline_variable_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'name': 'PIPELINE_VAR_NAME',
'value': '42',
'state': 'present',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"name": "PIPELINE_VAR_NAME",
"value": "42",
"state": "present",
}
):
self.module.main()
self.assertEqual(update_pipeline_variable_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], False)
self.assertEqual(exec_info.exception.args[0]["changed"], False)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_variable, 'get_existing_pipeline_variable', return_value={
'name': 'PIPELINE_VAR_NAME',
'value': 'Im alive',
'type': 'pipeline_variable',
'secured': False,
'uuid': '{9ddb0507-439a-495a- 99f3 - 564f15138127}'
})
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_pipeline_variable,
"get_existing_pipeline_variable",
return_value={
"name": "PIPELINE_VAR_NAME",
"value": "Im alive",
"type": "pipeline_variable",
"secured": False,
"uuid": "{9ddb0507-439a-495a- 99f3 - 564f15138127}",
},
)
def test_update_variable_check_mode(self, *args):
with patch.object(self.module, 'update_pipeline_variable') as update_pipeline_variable_mock:
with patch.object(self.module, "update_pipeline_variable") as update_pipeline_variable_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'name': 'PIPELINE_VAR_NAME',
'value': '42',
'state': 'present',
'_ansible_check_mode': True,
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"name": "PIPELINE_VAR_NAME",
"value": "42",
"state": "present",
"_ansible_check_mode": True,
}
):
self.module.main()
self.assertEqual(update_pipeline_variable_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_variable, 'get_existing_pipeline_variable', return_value={
'name': 'PIPELINE_VAR_NAME',
'value': 'Im alive',
'type': 'pipeline_variable',
'secured': False,
'uuid': '{9ddb0507-439a-495a- 99f3 - 564f15138127}'
})
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_pipeline_variable,
"get_existing_pipeline_variable",
return_value={
"name": "PIPELINE_VAR_NAME",
"value": "Im alive",
"type": "pipeline_variable",
"secured": False,
"uuid": "{9ddb0507-439a-495a- 99f3 - 564f15138127}",
},
)
def test_delete_variable(self, *args):
with patch.object(self.module, 'delete_pipeline_variable') as delete_pipeline_variable_mock:
with patch.object(self.module, "delete_pipeline_variable") as delete_pipeline_variable_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'name': 'PIPELINE_VAR_NAME',
'state': 'absent',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"name": "PIPELINE_VAR_NAME",
"state": "absent",
}
):
self.module.main()
self.assertEqual(delete_pipeline_variable_mock.call_count, 1)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_variable, 'get_existing_pipeline_variable', return_value=None)
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(bitbucket_pipeline_variable, "get_existing_pipeline_variable", return_value=None)
def test_delete_absent_variable(self, *args):
with patch.object(self.module, 'delete_pipeline_variable') as delete_pipeline_variable_mock:
with patch.object(self.module, "delete_pipeline_variable") as delete_pipeline_variable_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'name': 'PIPELINE_VAR_NAME',
'state': 'absent',
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"name": "PIPELINE_VAR_NAME",
"state": "absent",
}
):
self.module.main()
self.assertEqual(delete_pipeline_variable_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], False)
self.assertEqual(exec_info.exception.args[0]["changed"], False)
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
@patch.object(bitbucket_pipeline_variable, 'get_existing_pipeline_variable', return_value={
'name': 'PIPELINE_VAR_NAME',
'value': 'Im alive',
'type': 'pipeline_variable',
'secured': False,
'uuid': '{9ddb0507-439a-495a- 99f3 - 564f15138127}'
})
@patch.object(BitbucketHelper, "fetch_access_token", return_value="token")
@patch.object(
bitbucket_pipeline_variable,
"get_existing_pipeline_variable",
return_value={
"name": "PIPELINE_VAR_NAME",
"value": "Im alive",
"type": "pipeline_variable",
"secured": False,
"uuid": "{9ddb0507-439a-495a- 99f3 - 564f15138127}",
},
)
def test_delete_variable_check_mode(self, *args):
with patch.object(self.module, 'delete_pipeline_variable') as delete_pipeline_variable_mock:
with patch.object(self.module, "delete_pipeline_variable") as delete_pipeline_variable_mock:
with self.assertRaises(AnsibleExitJson) as exec_info:
with set_module_args({
'client_id': 'ABC',
'client_secret': 'XXX',
'workspace': 'name',
'repository': 'repo',
'name': 'PIPELINE_VAR_NAME',
'state': 'absent',
'_ansible_check_mode': True,
}):
with set_module_args(
{
"client_id": "ABC",
"client_secret": "XXX",
"workspace": "name",
"repository": "repo",
"name": "PIPELINE_VAR_NAME",
"state": "absent",
"_ansible_check_mode": True,
}
):
self.module.main()
self.assertEqual(delete_pipeline_variable_mock.call_count, 0)
self.assertEqual(exec_info.exception.args[0]['changed'], True)
self.assertEqual(exec_info.exception.args[0]["changed"], True)
if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()

View File

@@ -6,11 +6,15 @@ from __future__ import annotations
from unittest.mock import patch
from ansible_collections.community.general.plugins.modules import bootc_manage
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase, set_module_args
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
AnsibleExitJson,
AnsibleFailJson,
ModuleTestCase,
set_module_args,
)
class TestBootcManageModule(ModuleTestCase):
def setUp(self):
super().setUp()
self.module = bootc_manage
@@ -20,52 +24,52 @@ class TestBootcManageModule(ModuleTestCase):
def test_switch_without_image(self):
"""Failure if state is 'switch' but no image provided"""
with set_module_args({'state': 'switch'}):
with set_module_args({"state": "switch"}):
with self.assertRaises(AnsibleFailJson) as result:
self.module.main()
self.assertEqual(result.exception.args[0]['msg'], "state is switch but all of the following are missing: image")
self.assertEqual(result.exception.args[0]["msg"], "state is switch but all of the following are missing: image")
def test_switch_with_image(self):
"""Test successful switch with image provided"""
with set_module_args({'state': 'switch', 'image': 'example.com/image:latest'}):
with patch('ansible.module_utils.basic.AnsibleModule.run_command') as run_command_mock:
run_command_mock.return_value = (0, 'Queued for next boot: ', '')
with set_module_args({"state": "switch", "image": "example.com/image:latest"}):
with patch("ansible.module_utils.basic.AnsibleModule.run_command") as run_command_mock:
run_command_mock.return_value = (0, "Queued for next boot: ", "")
with self.assertRaises(AnsibleExitJson) as result:
self.module.main()
self.assertTrue(result.exception.args[0]['changed'])
self.assertTrue(result.exception.args[0]["changed"])
def test_latest_state(self):
"""Test successful upgrade to the latest state"""
with set_module_args({'state': 'latest'}):
with patch('ansible.module_utils.basic.AnsibleModule.run_command') as run_command_mock:
run_command_mock.return_value = (0, 'Queued for next boot: ', '')
with set_module_args({"state": "latest"}):
with patch("ansible.module_utils.basic.AnsibleModule.run_command") as run_command_mock:
run_command_mock.return_value = (0, "Queued for next boot: ", "")
with self.assertRaises(AnsibleExitJson) as result:
self.module.main()
self.assertTrue(result.exception.args[0]['changed'])
self.assertTrue(result.exception.args[0]["changed"])
def test_latest_state_no_change(self):
"""Test no change for latest state"""
with set_module_args({'state': 'latest'}):
with patch('ansible.module_utils.basic.AnsibleModule.run_command') as run_command_mock:
run_command_mock.return_value = (0, 'No changes in ', '')
with set_module_args({"state": "latest"}):
with patch("ansible.module_utils.basic.AnsibleModule.run_command") as run_command_mock:
run_command_mock.return_value = (0, "No changes in ", "")
with self.assertRaises(AnsibleExitJson) as result:
self.module.main()
self.assertFalse(result.exception.args[0]['changed'])
self.assertFalse(result.exception.args[0]["changed"])
def test_switch_image_failure(self):
"""Test failure during image switch"""
with set_module_args({'state': 'switch', 'image': 'example.com/image:latest'}):
with patch('ansible.module_utils.basic.AnsibleModule.run_command') as run_command_mock:
run_command_mock.return_value = (1, '', 'ERROR')
with set_module_args({"state": "switch", "image": "example.com/image:latest"}):
with patch("ansible.module_utils.basic.AnsibleModule.run_command") as run_command_mock:
run_command_mock.return_value = (1, "", "ERROR")
with self.assertRaises(AnsibleFailJson) as result:
self.module.main()
self.assertEqual(result.exception.args[0]['msg'], 'ERROR: Command execution failed.')
self.assertEqual(result.exception.args[0]["msg"], "ERROR: Command execution failed.")
def test_latest_state_failure(self):
"""Test failure during upgrade"""
with set_module_args({'state': 'latest'}):
with patch('ansible.module_utils.basic.AnsibleModule.run_command') as run_command_mock:
run_command_mock.return_value = (1, '', 'ERROR')
with set_module_args({"state": "latest"}):
with patch("ansible.module_utils.basic.AnsibleModule.run_command") as run_command_mock:
run_command_mock.return_value = (1, "", "ERROR")
with self.assertRaises(AnsibleFailJson) as result:
self.module.main()
self.assertEqual(result.exception.args[0]['msg'], 'ERROR: Command execution failed.')
self.assertEqual(result.exception.args[0]["msg"], "ERROR: Command execution failed.")

View File

@@ -7,11 +7,15 @@ from __future__ import annotations
import pytest
from unittest.mock import patch
from ansible_collections.community.general.plugins.modules import campfire
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase, set_module_args
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
AnsibleExitJson,
AnsibleFailJson,
ModuleTestCase,
set_module_args,
)
class TestCampfireModule(ModuleTestCase):
def setUp(self):
super().setUp()
self.module = campfire
@@ -21,7 +25,7 @@ class TestCampfireModule(ModuleTestCase):
@pytest.fixture
def fetch_url_mock(self, mocker):
return mocker.patch('ansible.module_utils.notification.campfire.fetch_url')
return mocker.patch("ansible.module_utils.notification.campfire.fetch_url")
def test_without_required_parameters(self):
"""Failure must occurs when all parameters are missing"""
@@ -31,12 +35,7 @@ class TestCampfireModule(ModuleTestCase):
def test_successful_message(self):
"""Test failure message"""
with set_module_args({
'subscription': 'test',
'token': 'abc',
'room': 'test',
'msg': 'test'
}):
with set_module_args({"subscription": "test", "token": "abc", "room": "test", "msg": "test"}):
with patch.object(campfire, "fetch_url") as fetch_url_mock:
fetch_url_mock.return_value = (None, {"status": 200})
with self.assertRaises(AnsibleExitJson):
@@ -44,20 +43,14 @@ class TestCampfireModule(ModuleTestCase):
assert fetch_url_mock.call_count == 1
url = fetch_url_mock.call_args[0][1]
data = fetch_url_mock.call_args[1]['data']
data = fetch_url_mock.call_args[1]["data"]
assert url == 'https://test.campfirenow.com/room/test/speak.xml'
assert data == '<message><body>test</body></message>'
assert url == "https://test.campfirenow.com/room/test/speak.xml"
assert data == "<message><body>test</body></message>"
def test_successful_message_with_notify(self):
"""Test failure message"""
with set_module_args({
'subscription': 'test',
'token': 'abc',
'room': 'test',
'msg': 'test',
'notify': 'bell'
}):
with set_module_args({"subscription": "test", "token": "abc", "room": "test", "msg": "test", "notify": "bell"}):
with patch.object(campfire, "fetch_url") as fetch_url_mock:
fetch_url_mock.return_value = (None, {"status": 200})
with self.assertRaises(AnsibleExitJson):
@@ -66,26 +59,21 @@ class TestCampfireModule(ModuleTestCase):
assert fetch_url_mock.call_count == 2
notify_call = fetch_url_mock.mock_calls[0]
url = notify_call[1][1]
data = notify_call[2]['data']
data = notify_call[2]["data"]
assert url == 'https://test.campfirenow.com/room/test/speak.xml'
assert data == '<message><type>SoundMessage</type><body>bell</body></message>'
assert url == "https://test.campfirenow.com/room/test/speak.xml"
assert data == "<message><type>SoundMessage</type><body>bell</body></message>"
message_call = fetch_url_mock.mock_calls[1]
url = message_call[1][1]
data = message_call[2]['data']
data = message_call[2]["data"]
assert url == 'https://test.campfirenow.com/room/test/speak.xml'
assert data == '<message><body>test</body></message>'
assert url == "https://test.campfirenow.com/room/test/speak.xml"
assert data == "<message><body>test</body></message>"
def test_failure_message(self):
"""Test failure message"""
with set_module_args({
'subscription': 'test',
'token': 'abc',
'room': 'test',
'msg': 'test'
}):
with set_module_args({"subscription": "test", "token": "abc", "room": "test", "msg": "test"}):
with patch.object(campfire, "fetch_url") as fetch_url_mock:
fetch_url_mock.return_value = (None, {"status": 403})
with self.assertRaises(AnsibleFailJson):

View File

@@ -13,11 +13,15 @@ from urllib3.response import HTTPResponse
from ansible.module_utils.common.text.converters import to_bytes
from ansible_collections.community.general.plugins.modules import circonus_annotation
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase, set_module_args
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
AnsibleExitJson,
AnsibleFailJson,
ModuleTestCase,
set_module_args,
)
class TestCirconusAnnotation(ModuleTestCase):
def setUp(self):
super().setUp()
self.module = circonus_annotation
@@ -33,122 +37,125 @@ class TestCirconusAnnotation(ModuleTestCase):
def test_add_annotation(self):
"""Check that result is changed"""
with set_module_args({
'category': 'test category',
'description': 'test description',
'title': 'test title',
'api_key': str(uuid.uuid4()),
}):
cid = '/annotation/100000'
with set_module_args(
{
"category": "test category",
"description": "test description",
"title": "test title",
"api_key": str(uuid.uuid4()),
}
):
cid = "/annotation/100000"
def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None):
data = {
'_cid': cid,
'_created': 1502146995,
'_last_modified': 1502146995,
'_last_modified_by': '/user/1000',
'category': 'test category',
'description': 'test description',
'rel_metrics': [],
'start': 1502145480,
'stop': None,
'title': 'test title',
"_cid": cid,
"_created": 1502146995,
"_last_modified": 1502146995,
"_last_modified_by": "/user/1000",
"category": "test category",
"description": "test description",
"rel_metrics": [],
"start": 1502145480,
"stop": None,
"title": "test title",
}
raw = to_bytes(json.dumps(data))
resp = HTTPResponse(body=io.BytesIO(raw), preload_content=False)
resp.status = 200
resp.reason = 'OK'
resp.headers = {'X-Circonus-API-Version': '2.00'}
resp.reason = "OK"
resp.headers = {"X-Circonus-API-Version": "2.00"}
return self.build_response(request, resp)
with patch('requests.adapters.HTTPAdapter.send', autospec=True, side_effect=send) as send:
with patch("requests.adapters.HTTPAdapter.send", autospec=True, side_effect=send) as send:
with self.assertRaises(AnsibleExitJson) as result:
self.module.main()
self.assertTrue(result.exception.args[0]['changed'])
self.assertEqual(result.exception.args[0]['annotation']['_cid'], cid)
self.assertTrue(result.exception.args[0]["changed"])
self.assertEqual(result.exception.args[0]["annotation"]["_cid"], cid)
self.assertEqual(send.call_count, 1)
def test_add_annotation_unicode(self):
"""Check that result is changed.
Note: it seems there is a bug which prevent to create an annotation
with a non-ASCII category if this category already exists, in such
case an Internal Server Error (500) occurs."""
with set_module_args({
'category': 'new catégorÿ',
'description': 'test description',
'title': 'test title',
'api_key': str(uuid.uuid4()),
}):
cid = '/annotation/100000'
Note: it seems there is a bug which prevent to create an annotation
with a non-ASCII category if this category already exists, in such
case an Internal Server Error (500) occurs."""
with set_module_args(
{
"category": "new catégorÿ",
"description": "test description",
"title": "test title",
"api_key": str(uuid.uuid4()),
}
):
cid = "/annotation/100000"
def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None):
data = {
'_cid': '/annotation/100000',
'_created': 1502236928,
'_last_modified': 1502236928,
'_last_modified_by': '/user/1000',
"_cid": "/annotation/100000",
"_created": 1502236928,
"_last_modified": 1502236928,
"_last_modified_by": "/user/1000",
# use res['annotation']['category'].encode('latin1').decode('utf8')
'category': 'new cat\xc3\xa9gor\xc3\xbf',
'description': 'test description',
'rel_metrics': [],
'start': 1502236927,
'stop': 1502236927,
'title': 'test title',
"category": "new cat\xc3\xa9gor\xc3\xbf",
"description": "test description",
"rel_metrics": [],
"start": 1502236927,
"stop": 1502236927,
"title": "test title",
}
raw = to_bytes(json.dumps(data), encoding='latin1')
raw = to_bytes(json.dumps(data), encoding="latin1")
resp = HTTPResponse(body=io.BytesIO(raw), preload_content=False)
resp.status = 200
resp.reason = 'OK'
resp.headers = {'X-Circonus-API-Version': '2.00'}
resp.reason = "OK"
resp.headers = {"X-Circonus-API-Version": "2.00"}
return self.build_response(request, resp)
with patch('requests.adapters.HTTPAdapter.send', autospec=True, side_effect=send) as send:
with patch("requests.adapters.HTTPAdapter.send", autospec=True, side_effect=send) as send:
with self.assertRaises(AnsibleExitJson) as result:
self.module.main()
self.assertTrue(result.exception.args[0]['changed'])
self.assertEqual(result.exception.args[0]['annotation']['_cid'], cid)
self.assertTrue(result.exception.args[0]["changed"])
self.assertEqual(result.exception.args[0]["annotation"]["_cid"], cid)
self.assertEqual(send.call_count, 1)
def test_auth_failure(self):
"""Check that an error is raised when authentication failed"""
with set_module_args({
'category': 'test category',
'description': 'test description',
'title': 'test title',
'api_key': str(uuid.uuid4()),
}):
cid = '/annotation/100000'
with set_module_args(
{
"category": "test category",
"description": "test description",
"title": "test title",
"api_key": str(uuid.uuid4()),
}
):
cid = "/annotation/100000"
def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None):
data = {
'_cid': cid,
'_created': 1502146995,
'_last_modified': 1502146995,
'_last_modified_by': '/user/1000',
'category': 'test category',
'description': 'test description',
'rel_metrics': [],
'start': 1502145480,
'stop': None,
'title': 'test title',
"_cid": cid,
"_created": 1502146995,
"_last_modified": 1502146995,
"_last_modified_by": "/user/1000",
"category": "test category",
"description": "test description",
"rel_metrics": [],
"start": 1502145480,
"stop": None,
"title": "test title",
}
raw = to_bytes(json.dumps(data))
resp = HTTPResponse(body=io.BytesIO(raw), preload_content=False)
resp.status = 403
resp.reason = 'Forbidden'
resp.headers = {'X-Circonus-API-Version': '2.00'}
resp.reason = "Forbidden"
resp.headers = {"X-Circonus-API-Version": "2.00"}
return self.build_response(request, resp)
with patch('requests.adapters.HTTPAdapter.send', autospec=True, side_effect=send) as send:
with patch("requests.adapters.HTTPAdapter.send", autospec=True, side_effect=send) as send:
with self.assertRaises(AnsibleFailJson) as result:
self.module.main()
self.assertTrue(result.exception.args[0]['failed'])
self.assertTrue(re.match(r'\b403\b', result.exception.args[0]['reason']))
self.assertTrue(result.exception.args[0]["failed"])
self.assertTrue(re.match(r"\b403\b", result.exception.args[0]["reason"]))
self.assertEqual(send.call_count, 1)

View File

@@ -8,7 +8,10 @@ from __future__ import annotations
from ansible_collections.community.general.plugins.modules import datadog_downtime
from unittest.mock import MagicMock, patch
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
AnsibleExitJson, AnsibleFailJson, ModuleTestCase, set_module_args
AnsibleExitJson,
AnsibleFailJson,
ModuleTestCase,
set_module_args,
)
from pytest import importorskip
@@ -20,7 +23,6 @@ DowntimeRecurrence = datadog_api_client.v1.model.downtime_recurrence.DowntimeRec
class TestDatadogDowntime(ModuleTestCase):
def setUp(self):
super().setUp()
self.module = datadog_downtime
@@ -36,18 +38,20 @@ class TestDatadogDowntime(ModuleTestCase):
@patch("ansible_collections.community.general.plugins.modules.datadog_downtime.DowntimesApi")
def test_create_downtime_when_no_id(self, downtimes_api_mock):
with set_module_args({
"monitor_tags": ["foo:bar"],
"scope": ["*"],
"monitor_id": 12345,
"downtime_message": "Message",
"start": 1111,
"end": 2222,
"timezone": "UTC",
"rrule": "rrule",
"api_key": "an_api_key",
"app_key": "an_app_key",
}):
with set_module_args(
{
"monitor_tags": ["foo:bar"],
"scope": ["*"],
"monitor_id": 12345,
"downtime_message": "Message",
"start": 1111,
"end": 2222,
"timezone": "UTC",
"rrule": "rrule",
"api_key": "an_api_key",
"app_key": "an_app_key",
}
):
downtime = Downtime()
downtime.monitor_tags = ["foo:bar"]
downtime.scope = ["*"]
@@ -56,35 +60,34 @@ class TestDatadogDowntime(ModuleTestCase):
downtime.start = 1111
downtime.end = 2222
downtime.timezone = "UTC"
downtime.recurrence = DowntimeRecurrence(
rrule="rrule",
type="rrule"
)
downtime.recurrence = DowntimeRecurrence(rrule="rrule", type="rrule")
create_downtime_mock = MagicMock(return_value=self.__downtime_with_id(12345))
downtimes_api_mock.return_value = MagicMock(create_downtime=create_downtime_mock)
with self.assertRaises(AnsibleExitJson) as result:
self.module.main()
self.assertTrue(result.exception.args[0]['changed'])
self.assertEqual(result.exception.args[0]['downtime']['id'], 12345)
self.assertTrue(result.exception.args[0]["changed"])
self.assertEqual(result.exception.args[0]["downtime"]["id"], 12345)
create_downtime_mock.assert_called_once_with(downtime)
@patch("ansible_collections.community.general.plugins.modules.datadog_downtime.DowntimesApi")
def test_create_downtime_when_id_and_disabled(self, downtimes_api_mock):
with set_module_args({
"id": 1212,
"monitor_tags": ["foo:bar"],
"scope": ["*"],
"monitor_id": 12345,
"downtime_message": "Message",
"start": 1111,
"end": 2222,
"timezone": "UTC",
"rrule": "rrule",
"api_key": "an_api_key",
"app_key": "an_app_key",
}):
with set_module_args(
{
"id": 1212,
"monitor_tags": ["foo:bar"],
"scope": ["*"],
"monitor_id": 12345,
"downtime_message": "Message",
"start": 1111,
"end": 2222,
"timezone": "UTC",
"rrule": "rrule",
"api_key": "an_api_key",
"app_key": "an_app_key",
}
):
downtime = Downtime()
downtime.monitor_tags = ["foo:bar"]
downtime.scope = ["*"]
@@ -93,10 +96,7 @@ class TestDatadogDowntime(ModuleTestCase):
downtime.start = 1111
downtime.end = 2222
downtime.timezone = "UTC"
downtime.recurrence = DowntimeRecurrence(
rrule="rrule",
type="rrule"
)
downtime.recurrence = DowntimeRecurrence(rrule="rrule", type="rrule")
disabled_downtime = Downtime()
disabled_downtime.disabled = True
@@ -110,26 +110,28 @@ class TestDatadogDowntime(ModuleTestCase):
with self.assertRaises(AnsibleExitJson) as result:
self.module.main()
self.assertTrue(result.exception.args[0]['changed'])
self.assertEqual(result.exception.args[0]['downtime']['id'], 12345)
self.assertTrue(result.exception.args[0]["changed"])
self.assertEqual(result.exception.args[0]["downtime"]["id"], 12345)
create_downtime_mock.assert_called_once_with(downtime)
get_downtime_mock.assert_called_once_with(1212)
@patch("ansible_collections.community.general.plugins.modules.datadog_downtime.DowntimesApi")
def test_update_downtime_when_not_disabled(self, downtimes_api_mock):
with set_module_args({
"id": 1212,
"monitor_tags": ["foo:bar"],
"scope": ["*"],
"monitor_id": 12345,
"downtime_message": "Message",
"start": 1111,
"end": 2222,
"timezone": "UTC",
"rrule": "rrule",
"api_key": "an_api_key",
"app_key": "an_app_key",
}):
with set_module_args(
{
"id": 1212,
"monitor_tags": ["foo:bar"],
"scope": ["*"],
"monitor_id": 12345,
"downtime_message": "Message",
"start": 1111,
"end": 2222,
"timezone": "UTC",
"rrule": "rrule",
"api_key": "an_api_key",
"app_key": "an_app_key",
}
):
downtime = Downtime()
downtime.monitor_tags = ["foo:bar"]
downtime.scope = ["*"]
@@ -138,10 +140,7 @@ class TestDatadogDowntime(ModuleTestCase):
downtime.start = 1111
downtime.end = 2222
downtime.timezone = "UTC"
downtime.recurrence = DowntimeRecurrence(
rrule="rrule",
type="rrule"
)
downtime.recurrence = DowntimeRecurrence(rrule="rrule", type="rrule")
enabled_downtime = Downtime()
enabled_downtime.disabled = False
@@ -155,26 +154,28 @@ class TestDatadogDowntime(ModuleTestCase):
with self.assertRaises(AnsibleExitJson) as result:
self.module.main()
self.assertTrue(result.exception.args[0]['changed'])
self.assertEqual(result.exception.args[0]['downtime']['id'], 1212)
self.assertTrue(result.exception.args[0]["changed"])
self.assertEqual(result.exception.args[0]["downtime"]["id"], 1212)
update_downtime_mock.assert_called_once_with(1212, downtime)
get_downtime_mock.assert_called_once_with(1212)
@patch("ansible_collections.community.general.plugins.modules.datadog_downtime.DowntimesApi")
def test_update_downtime_no_change(self, downtimes_api_mock):
with set_module_args({
"id": 1212,
"monitor_tags": ["foo:bar"],
"scope": ["*"],
"monitor_id": 12345,
"downtime_message": "Message",
"start": 1111,
"end": 2222,
"timezone": "UTC",
"rrule": "rrule",
"api_key": "an_api_key",
"app_key": "an_app_key",
}):
with set_module_args(
{
"id": 1212,
"monitor_tags": ["foo:bar"],
"scope": ["*"],
"monitor_id": 12345,
"downtime_message": "Message",
"start": 1111,
"end": 2222,
"timezone": "UTC",
"rrule": "rrule",
"api_key": "an_api_key",
"app_key": "an_app_key",
}
):
downtime = Downtime()
downtime.monitor_tags = ["foo:bar"]
downtime.scope = ["*"]
@@ -183,10 +184,7 @@ class TestDatadogDowntime(ModuleTestCase):
downtime.start = 1111
downtime.end = 2222
downtime.timezone = "UTC"
downtime.recurrence = DowntimeRecurrence(
rrule="rrule",
type="rrule"
)
downtime.recurrence = DowntimeRecurrence(rrule="rrule", type="rrule")
downtime_get = Downtime()
downtime_get.id = 1212
@@ -198,9 +196,7 @@ class TestDatadogDowntime(ModuleTestCase):
downtime_get.start = 1111
downtime_get.end = 2222
downtime_get.timezone = "UTC"
downtime_get.recurrence = DowntimeRecurrence(
rrule="rrule"
)
downtime_get.recurrence = DowntimeRecurrence(rrule="rrule")
update_downtime_mock = MagicMock(return_value=downtime_get)
get_downtime_mock = MagicMock(return_value=downtime_get)
@@ -210,28 +206,29 @@ class TestDatadogDowntime(ModuleTestCase):
with self.assertRaises(AnsibleExitJson) as result:
self.module.main()
self.assertFalse(result.exception.args[0]['changed'])
self.assertEqual(result.exception.args[0]['downtime']['id'], 1212)
self.assertFalse(result.exception.args[0]["changed"])
self.assertEqual(result.exception.args[0]["downtime"]["id"], 1212)
update_downtime_mock.assert_called_once_with(1212, downtime)
get_downtime_mock.assert_called_once_with(1212)
@patch("ansible_collections.community.general.plugins.modules.datadog_downtime.DowntimesApi")
def test_delete_downtime(self, downtimes_api_mock):
with set_module_args({
"id": 1212,
"state": "absent",
"api_key": "an_api_key",
"app_key": "an_app_key",
}):
with set_module_args(
{
"id": 1212,
"state": "absent",
"api_key": "an_api_key",
"app_key": "an_app_key",
}
):
cancel_downtime_mock = MagicMock()
downtimes_api_mock.return_value = MagicMock(
get_downtime=self.__downtime_with_id,
cancel_downtime=cancel_downtime_mock
get_downtime=self.__downtime_with_id, cancel_downtime=cancel_downtime_mock
)
with self.assertRaises(AnsibleExitJson) as result:
self.module.main()
self.assertTrue(result.exception.args[0]['changed'])
self.assertTrue(result.exception.args[0]["changed"])
cancel_downtime_mock.assert_called_once_with(1212)
def __downtime_with_id(self, id):

View File

@@ -19,25 +19,26 @@ DconfPreference = dconf.DconfPreference
@pytest.mark.parametrize(
"v1,v2,expected,fallback_expected",
(("'foo'", "'foo'", True, True),
('"foo"', "'foo'", True, False),
("'foo'", '"foo"', True, False),
("'foo'", '"bar"', False, False),
("[1, 2, 3]", "[1, 2, 3]", True, True),
("[1, 2, 3]", "[3, 2, 1]", False, False),
('1234', '1234', True, True),
('1234', '1235', False, False),
('1.0', '1.0', True, True),
('1.000', '1.0', True, False),
('2.0', '4.0', False, False),
# GVariants with different types aren't equal!
('1', '1.0', False, False),
# Explicit types
('@as []', '[]', True, False),
))
(
("'foo'", "'foo'", True, True),
('"foo"', "'foo'", True, False),
("'foo'", '"foo"', True, False),
("'foo'", '"bar"', False, False),
("[1, 2, 3]", "[1, 2, 3]", True, True),
("[1, 2, 3]", "[3, 2, 1]", False, False),
("1234", "1234", True, True),
("1234", "1235", False, False),
("1.0", "1.0", True, True),
("1.000", "1.0", True, False),
("2.0", "4.0", False, False),
# GVariants with different types aren't equal!
("1", "1.0", False, False),
# Explicit types
("@as []", "[]", True, False),
),
)
def test_gvariant_equality(mocker, v1, v2, expected, fallback_expected):
assert DconfPreference.variants_are_equal(v1, v2) is \
(expected if Variant else fallback_expected)
mocker.patch.object(dconf, 'Variant', None)
assert DconfPreference.variants_are_equal(v1, v2) is (expected if Variant else fallback_expected)
mocker.patch.object(dconf, "Variant", None)
mocker.patch.object(dconf, "GError", AttributeError)
assert DconfPreference.variants_are_equal(v1, v2) is fallback_expected

View File

@@ -10,11 +10,15 @@ from unittest.mock import patch
import pytest
from ansible_collections.community.general.plugins.modules import discord
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase, set_module_args
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
AnsibleExitJson,
AnsibleFailJson,
ModuleTestCase,
set_module_args,
)
class TestDiscordModule(ModuleTestCase):
def setUp(self):
super().setUp()
self.module = discord
@@ -24,7 +28,7 @@ class TestDiscordModule(ModuleTestCase):
@pytest.fixture
def fetch_url_mock(self, mocker):
return mocker.patch('ansible.module_utils.notification.discord.fetch_url')
return mocker.patch("ansible.module_utils.notification.discord.fetch_url")
def test_without_parameters(self):
"""Failure if no parameters set"""
@@ -34,62 +38,49 @@ class TestDiscordModule(ModuleTestCase):
def test_without_content(self):
"""Failure if content and embeds both are missing"""
with set_module_args({
'webhook_id': 'xxx',
'webhook_token': 'xxx'
}):
with set_module_args({"webhook_id": "xxx", "webhook_token": "xxx"}):
with self.assertRaises(AnsibleFailJson):
self.module.main()
def test_successful_message(self):
"""Test a basic message successfully."""
with set_module_args({
'webhook_id': 'xxx',
'webhook_token': 'xxx',
'content': 'test'
}):
with set_module_args({"webhook_id": "xxx", "webhook_token": "xxx", "content": "test"}):
with patch.object(discord, "fetch_url") as fetch_url_mock:
fetch_url_mock.return_value = (None, {"status": 204, 'msg': 'OK (0 bytes)'})
fetch_url_mock.return_value = (None, {"status": 204, "msg": "OK (0 bytes)"})
with self.assertRaises(AnsibleExitJson):
self.module.main()
self.assertTrue(fetch_url_mock.call_count, 1)
call_data = json.loads(fetch_url_mock.call_args[1]['data'])
assert call_data['content'] == "test"
call_data = json.loads(fetch_url_mock.call_args[1]["data"])
assert call_data["content"] == "test"
def test_message_with_username(self):
"""Test a message with username set successfully."""
with set_module_args({
'webhook_id': 'xxx',
'webhook_token': 'xxx',
'content': 'test',
'username': 'Ansible Bot'
}):
with set_module_args(
{"webhook_id": "xxx", "webhook_token": "xxx", "content": "test", "username": "Ansible Bot"}
):
with patch.object(discord, "fetch_url") as fetch_url_mock:
fetch_url_mock.return_value = (None, {"status": 204, 'msg': 'OK (0 bytes)'})
fetch_url_mock.return_value = (None, {"status": 204, "msg": "OK (0 bytes)"})
with self.assertRaises(AnsibleExitJson):
self.module.main()
self.assertTrue(fetch_url_mock.call_count, 1)
call_data = json.loads(fetch_url_mock.call_args[1]['data'])
assert call_data['username'] == "Ansible Bot"
assert call_data['content'] == "test"
call_data = json.loads(fetch_url_mock.call_args[1]["data"])
assert call_data["username"] == "Ansible Bot"
assert call_data["content"] == "test"
def test_failed_message(self):
"""Test failure because webhook id is wrong."""
with set_module_args({
'webhook_id': 'wrong',
'webhook_token': 'xxx',
'content': 'test'
}):
with set_module_args({"webhook_id": "wrong", "webhook_token": "xxx", "content": "test"}):
with patch.object(discord, "fetch_url") as fetch_url_mock:
fetch_url_mock.return_value = (
None,
{"status": 404, 'msg': 'HTTP Error 404: Not Found', 'body': '{"message": "Unknown Webhook", "code": 10015}'},
{
"status": 404,
"msg": "HTTP Error 404: Not Found",
"body": '{"message": "Unknown Webhook", "code": 10015}',
},
)
with self.assertRaises(AnsibleFailJson):
self.module.main()
@@ -97,13 +88,8 @@ class TestDiscordModule(ModuleTestCase):
def test_failed_message_without_body(self):
"""Test failure with empty response body."""
with set_module_args({
'webhook_id': 'wrong',
'webhook_token': 'xxx',
'content': 'test'
}):
with set_module_args({"webhook_id": "wrong", "webhook_token": "xxx", "content": "test"}):
with patch.object(discord, "fetch_url") as fetch_url_mock:
fetch_url_mock.return_value = (None, {"status": 404, 'msg': 'HTTP Error 404: Not Found'})
fetch_url_mock.return_value = (None, {"status": 404, "msg": "HTTP Error 404: Not Found"})
with self.assertRaises(AnsibleFailJson):
self.module.main()

View File

@@ -1,4 +1,3 @@
# Copyright (c) 2023, Andrew Hyatt <andy@hyatt.xyz>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
@@ -6,8 +5,12 @@ from __future__ import annotations
from unittest.mock import patch, call
from ansible_collections.community.general.plugins.modules import dnf_config_manager as dnf_config_manager_module
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import AnsibleExitJson, AnsibleFailJson, \
ModuleTestCase, set_module_args
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
AnsibleExitJson,
AnsibleFailJson,
ModuleTestCase,
set_module_args,
)
# Return value on all-default arguments
mock_repolist_crb_enabled = """Loaded plugins: builddep, changelog, config-manager, copr, debug, debuginfo-install
@@ -230,37 +233,38 @@ Repo-status : disabled
Repo-status : disabled
"""
expected_repo_states_crb_enabled = {'disabled': ['appstream-debuginfo',
'appstream-source',
'baseos-debuginfo',
'baseos-source'],
'enabled': ['appstream',
'baseos',
'copr:copr.fedorainfracloud.org:uriesk:dracut-crypt-ssh',
'crb',
'rpmfusion-nonfree-updates']}
expected_repo_states_crb_enabled = {
"disabled": ["appstream-debuginfo", "appstream-source", "baseos-debuginfo", "baseos-source"],
"enabled": [
"appstream",
"baseos",
"copr:copr.fedorainfracloud.org:uriesk:dracut-crypt-ssh",
"crb",
"rpmfusion-nonfree-updates",
],
}
expected_repo_states_crb_disabled = {'disabled': ['appstream-debuginfo',
'appstream-source',
'baseos-debuginfo',
'baseos-source',
'crb'],
'enabled': ['appstream',
'baseos',
'copr:copr.fedorainfracloud.org:uriesk:dracut-crypt-ssh',
'rpmfusion-nonfree-updates']}
expected_repo_states_crb_disabled = {
"disabled": ["appstream-debuginfo", "appstream-source", "baseos-debuginfo", "baseos-source", "crb"],
"enabled": [
"appstream",
"baseos",
"copr:copr.fedorainfracloud.org:uriesk:dracut-crypt-ssh",
"rpmfusion-nonfree-updates",
],
}
call_get_repo_states = call(['/usr/bin/dnf', 'repolist', '--all', '--verbose'], check_rc=True)
call_disable_crb = call(['/usr/bin/dnf', 'config-manager', '--assumeyes', '--set-disabled', 'crb'], check_rc=True)
call_enable_crb = call(['/usr/bin/dnf', 'config-manager', '--assumeyes', '--set-enabled', 'crb'], check_rc=True)
call_get_repo_states = call(["/usr/bin/dnf", "repolist", "--all", "--verbose"], check_rc=True)
call_disable_crb = call(["/usr/bin/dnf", "config-manager", "--assumeyes", "--set-disabled", "crb"], check_rc=True)
call_enable_crb = call(["/usr/bin/dnf", "config-manager", "--assumeyes", "--set-enabled", "crb"], check_rc=True)
class TestDNFConfigManager(ModuleTestCase):
def setUp(self):
super().setUp()
self.mock_run_command = (patch('ansible.module_utils.basic.AnsibleModule.run_command'))
self.mock_run_command = patch("ansible.module_utils.basic.AnsibleModule.run_command")
self.run_command = self.mock_run_command.start()
self.mock_path_exists = (patch('os.path.exists'))
self.mock_path_exists = patch("os.path.exists")
self.path_exists = self.mock_path_exists.start()
self.path_exists.return_value = True
self.module = dnf_config_manager_module
@@ -270,7 +274,7 @@ class TestDNFConfigManager(ModuleTestCase):
self.mock_run_command.stop()
self.mock_path_exists.stop()
def set_command_mock(self, execute_return=(0, '', ''), execute_side_effect=None):
def set_command_mock(self, execute_return=(0, "", ""), execute_side_effect=None):
self.run_command.reset_mock()
self.run_command.return_value = execute_return
self.run_command.side_effect = execute_side_effect
@@ -278,10 +282,10 @@ class TestDNFConfigManager(ModuleTestCase):
def execute_module(self, failed=False, changed=False):
if failed:
result = self.failed()
self.assertTrue(result['failed'])
self.assertTrue(result["failed"])
else:
result = self.changed(changed)
self.assertEqual(result['changed'], changed)
self.assertEqual(result["changed"], changed)
return result
@@ -290,7 +294,7 @@ class TestDNFConfigManager(ModuleTestCase):
self.module.main()
result = exc.exception.args[0]
self.assertTrue(result['failed'])
self.assertTrue(result["failed"])
return result
def changed(self, changed=False):
@@ -298,102 +302,84 @@ class TestDNFConfigManager(ModuleTestCase):
self.module.main()
result = exc.exception.args[0]
self.assertEqual(result['changed'], changed)
self.assertEqual(result["changed"], changed)
return result
def test_get_repo_states(self):
with set_module_args({}):
self.set_command_mock(execute_return=(0, mock_repolist_crb_enabled, ''))
self.set_command_mock(execute_return=(0, mock_repolist_crb_enabled, ""))
result = self.execute_module(changed=False)
self.assertEqual(result['repo_states_pre'], expected_repo_states_crb_enabled)
self.assertEqual(result['repo_states_post'], expected_repo_states_crb_enabled)
self.assertEqual(result['changed_repos'], [])
self.assertEqual(result["repo_states_pre"], expected_repo_states_crb_enabled)
self.assertEqual(result["repo_states_post"], expected_repo_states_crb_enabled)
self.assertEqual(result["changed_repos"], [])
self.run_command.assert_has_calls(calls=[call_get_repo_states, call_get_repo_states], any_order=False)
def test_enable_disabled_repo(self):
with set_module_args({
'name': ['crb'],
'state': 'enabled'
}):
side_effects = [(0, mock_repolist_crb_disabled, ''), (0, '', ''), (0, mock_repolist_crb_enabled, '')]
with set_module_args({"name": ["crb"], "state": "enabled"}):
side_effects = [(0, mock_repolist_crb_disabled, ""), (0, "", ""), (0, mock_repolist_crb_enabled, "")]
self.set_command_mock(execute_side_effect=side_effects)
result = self.execute_module(changed=True)
self.assertEqual(result['repo_states_pre'], expected_repo_states_crb_disabled)
self.assertEqual(result['repo_states_post'], expected_repo_states_crb_enabled)
self.assertEqual(result['changed_repos'], ['crb'])
self.assertEqual(result["repo_states_pre"], expected_repo_states_crb_disabled)
self.assertEqual(result["repo_states_post"], expected_repo_states_crb_enabled)
self.assertEqual(result["changed_repos"], ["crb"])
expected_calls = [call_get_repo_states, call_enable_crb, call_get_repo_states]
self.run_command.assert_has_calls(calls=expected_calls, any_order=False)
def test_enable_disabled_repo_check_mode(self):
with set_module_args({
'name': ['crb'],
'state': 'enabled',
'_ansible_check_mode': True
}):
side_effects = [(0, mock_repolist_crb_disabled, ''), (0, mock_repolist_crb_disabled, '')]
with set_module_args({"name": ["crb"], "state": "enabled", "_ansible_check_mode": True}):
side_effects = [(0, mock_repolist_crb_disabled, ""), (0, mock_repolist_crb_disabled, "")]
self.set_command_mock(execute_side_effect=side_effects)
result = self.execute_module(changed=True)
self.assertEqual(result['changed_repos'], ['crb'])
self.assertEqual(result["changed_repos"], ["crb"])
self.run_command.assert_has_calls(calls=[call_get_repo_states], any_order=False)
def test_disable_enabled_repo(self):
with set_module_args({
'name': ['crb'],
'state': 'disabled'
}):
side_effects = [(0, mock_repolist_crb_enabled, ''), (0, '', ''), (0, mock_repolist_crb_disabled, '')]
with set_module_args({"name": ["crb"], "state": "disabled"}):
side_effects = [(0, mock_repolist_crb_enabled, ""), (0, "", ""), (0, mock_repolist_crb_disabled, "")]
self.set_command_mock(execute_side_effect=side_effects)
result = self.execute_module(changed=True)
self.assertEqual(result['repo_states_pre'], expected_repo_states_crb_enabled)
self.assertEqual(result['repo_states_post'], expected_repo_states_crb_disabled)
self.assertEqual(result['changed_repos'], ['crb'])
self.assertEqual(result["repo_states_pre"], expected_repo_states_crb_enabled)
self.assertEqual(result["repo_states_post"], expected_repo_states_crb_disabled)
self.assertEqual(result["changed_repos"], ["crb"])
expected_calls = [call_get_repo_states, call_disable_crb, call_get_repo_states]
self.run_command.assert_has_calls(calls=expected_calls, any_order=False)
def test_crb_already_enabled(self):
with set_module_args({
'name': ['crb'],
'state': 'enabled'
}):
side_effects = [(0, mock_repolist_crb_enabled, ''), (0, mock_repolist_crb_enabled, '')]
with set_module_args({"name": ["crb"], "state": "enabled"}):
side_effects = [(0, mock_repolist_crb_enabled, ""), (0, mock_repolist_crb_enabled, "")]
self.set_command_mock(execute_side_effect=side_effects)
result = self.execute_module(changed=False)
self.assertEqual(result['repo_states_pre'], expected_repo_states_crb_enabled)
self.assertEqual(result['repo_states_post'], expected_repo_states_crb_enabled)
self.assertEqual(result['changed_repos'], [])
self.assertEqual(result["repo_states_pre"], expected_repo_states_crb_enabled)
self.assertEqual(result["repo_states_post"], expected_repo_states_crb_enabled)
self.assertEqual(result["changed_repos"], [])
self.run_command.assert_has_calls(calls=[call_get_repo_states, call_get_repo_states], any_order=False)
def test_get_repo_states_fail_no_status(self):
with set_module_args({}):
self.set_command_mock(execute_return=(0, mock_repolist_no_status, ''))
self.set_command_mock(execute_return=(0, mock_repolist_no_status, ""))
result = self.execute_module(failed=True)
self.assertEqual(result['msg'], 'dnf repolist parse failure: parsed another repo id before next status')
self.assertEqual(result["msg"], "dnf repolist parse failure: parsed another repo id before next status")
self.run_command.assert_has_calls(calls=[call_get_repo_states], any_order=False)
def test_get_repo_states_fail_status_before_id(self):
with set_module_args({}):
self.set_command_mock(execute_return=(0, mock_repolist_status_before_id, ''))
self.set_command_mock(execute_return=(0, mock_repolist_status_before_id, ""))
result = self.execute_module(failed=True)
self.assertEqual(result['msg'], 'dnf repolist parse failure: parsed status before repo id')
self.assertEqual(result["msg"], "dnf repolist parse failure: parsed status before repo id")
self.run_command.assert_has_calls(calls=[call_get_repo_states], any_order=False)
def test_failed__unknown_repo_id(self):
with set_module_args({
'name': ['fake']
}):
self.set_command_mock(execute_return=(0, mock_repolist_crb_disabled, ''))
with set_module_args({"name": ["fake"]}):
self.set_command_mock(execute_return=(0, mock_repolist_crb_disabled, ""))
result = self.execute_module(failed=True)
self.assertEqual(result['msg'], "did not find repo with ID 'fake' in dnf repolist --all --verbose")
self.assertEqual(result["msg"], "did not find repo with ID 'fake' in dnf repolist --all --verbose")
self.run_command.assert_has_calls(calls=[call_get_repo_states], any_order=False)
def test_failed_state_change_ineffective(self):
with set_module_args({
'name': ['crb'],
'state': 'enabled'
}):
side_effects = [(0, mock_repolist_crb_disabled, ''), (0, '', ''), (0, mock_repolist_crb_disabled, '')]
with set_module_args({"name": ["crb"], "state": "enabled"}):
side_effects = [(0, mock_repolist_crb_disabled, ""), (0, "", ""), (0, mock_repolist_crb_disabled, "")]
self.set_command_mock(execute_side_effect=side_effects)
result = self.execute_module(failed=True)
self.assertEqual(result['msg'], "dnf config-manager failed to make 'crb' enabled")
self.assertEqual(result["msg"], "dnf config-manager failed to make 'crb' enabled")
expected_calls = [call_get_repo_states, call_enable_crb, call_get_repo_states]
self.run_command.assert_has_calls(calls=expected_calls, any_order=False)

View File

@@ -1,4 +1,3 @@
# Copyright (c) Ansible project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
@@ -6,15 +5,18 @@
from __future__ import annotations
from ansible_collections.community.general.plugins.modules import dnsimple as dnsimple_module
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import AnsibleFailJson, ModuleTestCase, set_module_args
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
AnsibleFailJson,
ModuleTestCase,
set_module_args,
)
from unittest.mock import patch
import pytest
import sys
dnsimple = pytest.importorskip('dnsimple')
dnsimple = pytest.importorskip("dnsimple")
mandatory_py_version = pytest.mark.skipif(
sys.version_info < (3, 6),
reason='The dnsimple dependency requires python3.6 or higher'
sys.version_info < (3, 6), reason="The dnsimple dependency requires python3.6 or higher"
)
from dnsimple import DNSimpleException
@@ -38,24 +40,24 @@ class TestDNSimple(ModuleTestCase):
with set_module_args({}):
self.module.main()
@patch('dnsimple.service.Identity.whoami')
@patch("dnsimple.service.Identity.whoami")
def test_account_token(self, mock_whoami):
mock_whoami.return_value.data.account = 42
ds = self.module.DNSimpleV2('fake', 'fake', True, self.module)
ds = self.module.DNSimpleV2("fake", "fake", True, self.module)
self.assertEqual(ds.account, 42)
@patch('dnsimple.service.Accounts.list_accounts')
@patch('dnsimple.service.Identity.whoami')
@patch("dnsimple.service.Accounts.list_accounts")
@patch("dnsimple.service.Identity.whoami")
def test_user_token_multiple_accounts(self, mock_whoami, mock_accounts):
mock_accounts.return_value.data = [1, 2, 3]
mock_whoami.return_value.data.account = None
with self.assertRaises(DNSimpleException):
self.module.DNSimpleV2('fake', 'fake', True, self.module)
self.module.DNSimpleV2("fake", "fake", True, self.module)
@patch('dnsimple.service.Accounts.list_accounts')
@patch('dnsimple.service.Identity.whoami')
@patch("dnsimple.service.Accounts.list_accounts")
@patch("dnsimple.service.Identity.whoami")
def test_user_token_single_account(self, mock_whoami, mock_accounts):
mock_accounts.return_value.data = [42]
mock_whoami.return_value.data.account = None
ds = self.module.DNSimpleV2('fake', 'fake', True, self.module)
ds = self.module.DNSimpleV2("fake", "fake", True, self.module)
self.assertEqual(ds.account, 42)

View File

@@ -1,4 +1,3 @@
# Copyright (c) Ansible project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
@@ -7,33 +6,38 @@ from __future__ import annotations
from ansible_collections.community.general.plugins.modules import dnsimple_info
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import AnsibleFailJson, ModuleTestCase, set_module_args, AnsibleExitJson
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
AnsibleFailJson,
ModuleTestCase,
set_module_args,
AnsibleExitJson,
)
from httmock import response
from httmock import with_httmock
from httmock import urlmatch
@urlmatch(netloc='(.)*dnsimple.com(.)*',
path='/v2/[0-9]*/zones/')
@urlmatch(netloc="(.)*dnsimple.com(.)*", path="/v2/[0-9]*/zones/")
def zones_resp(url, request):
"""return domains"""
headers = {'content-type': 'application/json'}
data_content = {"data":
[{"account_id": "1234", }, ],
"pagination": {"total_pages": 1}}
headers = {"content-type": "application/json"}
data_content = {
"data": [
{
"account_id": "1234",
},
],
"pagination": {"total_pages": 1},
}
content = data_content
return response(200, content, headers, None, 5, request)
@urlmatch(netloc='(.)*dnsimple.com(.)*',
path='/v2/[0-9]*/zones/(.)*/records(.*)')
@urlmatch(netloc="(.)*dnsimple.com(.)*", path="/v2/[0-9]*/zones/(.)*/records(.*)")
def records_resp(url, request):
"""return record(s)"""
headers = {'content-type': 'application/json'}
data_content = {"data":
[{"content": "example",
"name": "example.com"}],
"pagination": {"total_pages": 1}}
headers = {"content-type": "application/json"}
data_content = {"data": [{"content": "example", "name": "example.com"}], "pagination": {"total_pages": 1}}
content = data_content
return response(200, content, headers, None, 5, request)
@@ -42,7 +46,6 @@ class TestDNSimple_Info(ModuleTestCase):
"""Main class for testing dnsimple module."""
def setUp(self):
"""Setup."""
super().setUp()
self.module = dnsimple_info
@@ -62,48 +65,38 @@ class TestDNSimple_Info(ModuleTestCase):
"""key and account will pass, returns domains"""
account_id = "1234"
with self.assertRaises(AnsibleExitJson) as exc_info:
with set_module_args({
"api_key": "abcd1324",
"account_id": account_id
}):
with set_module_args({"api_key": "abcd1324", "account_id": account_id}):
self.module.main()
result = exc_info.exception.args[0]
# nothing should change
self.assertFalse(result['changed'])
self.assertFalse(result["changed"])
# we should return at least one item with the matching account ID
assert result['dnsimple_domain_info'][0]["account_id"] == account_id
assert result["dnsimple_domain_info"][0]["account_id"] == account_id
@with_httmock(records_resp)
def test_only_name_without_record(self):
"""name and no record should not fail, returns the record"""
name = "example.com"
with self.assertRaises(AnsibleExitJson) as exc_info:
with set_module_args({
"api_key": "abcd1324",
"name": "example.com",
"account_id": "1234"
}):
with set_module_args({"api_key": "abcd1324", "name": "example.com", "account_id": "1234"}):
self.module.main()
result = exc_info.exception.args[0]
# nothing should change
self.assertFalse(result['changed'])
self.assertFalse(result["changed"])
# we should return at least one item with matching domain
assert result['dnsimple_records_info'][0]['name'] == name
assert result["dnsimple_records_info"][0]["name"] == name
@with_httmock(records_resp)
def test_name_and_record(self):
"""name and record should not fail, returns the record"""
record = "example"
with self.assertRaises(AnsibleExitJson) as exc_info:
with set_module_args({
"api_key": "abcd1324",
"account_id": "1234",
"name": "example.com",
"record": "example"
}):
with set_module_args(
{"api_key": "abcd1324", "account_id": "1234", "name": "example.com", "record": "example"}
):
self.module.main()
result = exc_info.exception.args[0]
# nothing should change
self.assertFalse(result['changed'])
self.assertFalse(result["changed"])
# we should return at least one item and content should match
assert result['dnsimple_record_info'][0]['content'] == record
assert result["dnsimple_record_info"][0]["content"] == record

View File

@@ -8,22 +8,27 @@ import copy
import pytest
from ansible_collections.community.general.plugins.modules import gem
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase, set_module_args
from ansible_collections.community.internal_test_tools.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)
return " ".join(command)
class TestGem(ModuleTestCase):
def setUp(self):
super().setUp()
self.rubygems_path = ['/usr/bin/gem']
self.rubygems_path = ["/usr/bin/gem"]
self.mocker.patch(
'ansible_collections.community.general.plugins.modules.gem.get_rubygems_path',
"ansible_collections.community.general.plugins.modules.gem.get_rubygems_path",
lambda module: copy.deepcopy(self.rubygems_path),
)
@@ -34,7 +39,7 @@ class TestGem(ModuleTestCase):
def patch_installed_versions(self, versions):
"""Mocks the versions of the installed package"""
target = 'ansible_collections.community.general.plugins.modules.gem.get_installed_versions'
target = "ansible_collections.community.general.plugins.modules.gem.get_installed_versions"
def new(module, remote=False):
return versions
@@ -42,7 +47,7 @@ class TestGem(ModuleTestCase):
return self.mocker.patch(target, new)
def patch_rubygems_version(self, version=None):
target = 'ansible_collections.community.general.plugins.modules.gem.get_rubygems_version'
target = "ansible_collections.community.general.plugins.modules.gem.get_rubygems_version"
def new(module):
return version
@@ -50,23 +55,25 @@ class TestGem(ModuleTestCase):
return self.mocker.patch(target, new)
def patch_run_command(self):
target = 'ansible.module_utils.basic.AnsibleModule.run_command'
target = "ansible.module_utils.basic.AnsibleModule.run_command"
mock = self.mocker.patch(target)
mock.return_value = (0, '', '')
mock.return_value = (0, "", "")
return mock
def test_fails_when_user_install_and_install_dir_are_combined(self):
with set_module_args({
'name': 'dummy',
'user_install': True,
'install_dir': '/opt/dummy',
}):
with 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"
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 assumptions about the module code, and how
@@ -75,11 +82,13 @@ class TestGem(ModuleTestCase):
# test mocks. The only thing that matters is the assertion that this 'gem install' is
# invoked with '--install-dir'.
with set_module_args({
'name': 'dummy',
'user_install': False,
'install_dir': '/opt/dummy',
}):
with 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()
@@ -88,23 +97,25 @@ class TestGem(ModuleTestCase):
gem.main()
result = exc.value.args[0]
assert result['changed']
assert result["changed"]
assert run_command.called
assert '--install-dir /opt/dummy' in get_command(run_command)
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.
with set_module_args({
'name': 'dummy',
'user_install': False,
'install_dir': '/opt/dummy',
'state': 'absent',
}):
with 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'])
self.patch_installed_versions(["1.0.0"])
run_command = self.patch_run_command()
@@ -112,19 +123,21 @@ class TestGem(ModuleTestCase):
gem.main()
result = exc.value.args[0]
assert result['failed']
assert result["failed"]
assert run_command.called
assert '--install-dir /opt/dummy' in get_command(run_command)
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'
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):
with set_module_args({
'name': 'dummy',
'force': True,
}):
with set_module_args(
{
"name": "dummy",
"force": True,
}
):
self.patch_rubygems_version()
self.patch_installed_versions([])
run_command = self.patch_run_command()
@@ -133,7 +146,7 @@ class TestGem(ModuleTestCase):
gem.main()
result = exc.value.args[0]
assert result['changed']
assert result["changed"]
assert run_command.called
assert '--force' in get_command(run_command)
assert "--force" in get_command(run_command)

View File

@@ -12,55 +12,48 @@ from httmock import with_httmock, urlmatch, response
from ansible_collections.community.general.plugins.modules import github_repo
pytest.importorskip('github')
pytest.importorskip("github")
@urlmatch(netloc=r'.*')
@urlmatch(netloc=r".*")
def debug_mock(url, request):
print(request.original.__dict__)
@urlmatch(netloc=r'api\.github\.com(:[0-9]+)?$', path=r'/orgs/.*', method="get")
@urlmatch(netloc=r"api\.github\.com(:[0-9]+)?$", path=r"/orgs/.*", method="get")
def get_orgs_mock(url, request):
match = re.search(r"api\.github\.com(:[0-9]+)?/orgs/(?P<org>[^/]+)", request.url)
org = match.group("org")
# https://docs.github.com/en/rest/reference/orgs#get-an-organization
headers = {'content-type': 'application/json'}
content = {
"login": org,
"url": f"https://api.github.com/orgs/{org}"
}
headers = {"content-type": "application/json"}
content = {"login": org, "url": f"https://api.github.com/orgs/{org}"}
content = json.dumps(content).encode("utf-8")
return response(200, content, headers, None, 5, request)
@urlmatch(netloc=r'api\.github\.com(:[0-9]+)?$', path=r'/user', method="get")
@urlmatch(netloc=r"api\.github\.com(:[0-9]+)?$", path=r"/user", method="get")
def get_user_mock(url, request):
# https://docs.github.com/en/rest/reference/users#get-the-authenticated-user
headers = {'content-type': 'application/json'}
content = {
"login": "octocat",
"url": "https://api.github.com/users/octocat"
}
headers = {"content-type": "application/json"}
content = {"login": "octocat", "url": "https://api.github.com/users/octocat"}
content = json.dumps(content).encode("utf-8")
return response(200, content, headers, None, 5, request)
@urlmatch(netloc=r'api\.github\.com(:[0-9]+)?$', path=r'/repos/.*/.*', method="get")
@urlmatch(netloc=r"api\.github\.com(:[0-9]+)?$", path=r"/repos/.*/.*", method="get")
def get_repo_notfound_mock(url, request):
return response(404, "{\"message\": \"Not Found\"}", "", "Not Found", 5, request)
return response(404, '{"message": "Not Found"}', "", "Not Found", 5, request)
@urlmatch(netloc=r'api\.github\.com(:[0-9]+)?$', path=r'/repos/.*/.*', method="get")
@urlmatch(netloc=r"api\.github\.com(:[0-9]+)?$", path=r"/repos/.*/.*", method="get")
def get_repo_mock(url, request):
match = re.search(
r"api\.github\.com(:[0-9]+)?/repos/(?P<org>[^/]+)/(?P<repo>[^/]+)", request.url)
match = re.search(r"api\.github\.com(:[0-9]+)?/repos/(?P<org>[^/]+)/(?P<repo>[^/]+)", request.url)
org = match.group("org")
repo = match.group("repo")
# https://docs.github.com/en/rest/reference/repos#get-a-repository
headers = {'content-type': 'application/json'}
headers = {"content-type": "application/json"}
content = {
"name": repo,
"full_name": f"{org}/{repo}",
@@ -68,21 +61,20 @@ def get_repo_mock(url, request):
"private": False,
"description": "This your first repo!",
"default_branch": "master",
"allow_rebase_merge": True
"allow_rebase_merge": True,
}
content = json.dumps(content).encode("utf-8")
return response(200, content, headers, None, 5, request)
@urlmatch(netloc=r'api\.github\.com(:[0-9]+)?$', path=r'/repos/.*/.*', method="get")
@urlmatch(netloc=r"api\.github\.com(:[0-9]+)?$", path=r"/repos/.*/.*", method="get")
def get_private_repo_mock(url, request):
match = re.search(
r"api\.github\.com(:[0-9]+)?/repos/(?P<org>[^/]+)/(?P<repo>[^/]+)", request.url)
match = re.search(r"api\.github\.com(:[0-9]+)?/repos/(?P<org>[^/]+)/(?P<repo>[^/]+)", request.url)
org = match.group("org")
repo = match.group("repo")
# https://docs.github.com/en/rest/reference/repos#get-a-repository
headers = {'content-type': 'application/json'}
headers = {"content-type": "application/json"}
content = {
"name": repo,
"full_name": f"{org}/{repo}",
@@ -90,80 +82,78 @@ def get_private_repo_mock(url, request):
"private": True,
"description": "This your first repo!",
"default_branch": "master",
"allow_rebase_merge": True
"allow_rebase_merge": True,
}
content = json.dumps(content).encode("utf-8")
return response(200, content, headers, None, 5, request)
@urlmatch(netloc=r'api\.github\.com(:[0-9]+)?$', path=r'/orgs/.*/repos', method="post")
@urlmatch(netloc=r"api\.github\.com(:[0-9]+)?$", path=r"/orgs/.*/repos", method="post")
def create_new_org_repo_mock(url, request):
match = re.search(
r"api\.github\.com(:[0-9]+)?/orgs/(?P<org>[^/]+)/repos", request.url)
match = re.search(r"api\.github\.com(:[0-9]+)?/orgs/(?P<org>[^/]+)/repos", request.url)
org = match.group("org")
repo = json.loads(request.body)
headers = {'content-type': 'application/json'}
headers = {"content-type": "application/json"}
# https://docs.github.com/en/rest/reference/repos#create-an-organization-repository
content = {
"name": repo['name'],
"name": repo["name"],
"full_name": f"{org}/{repo['name']}",
"private": repo.get('private', False),
"description": repo.get('description')
"private": repo.get("private", False),
"description": repo.get("description"),
}
content = json.dumps(content).encode("utf-8")
return response(201, content, headers, None, 5, request)
@urlmatch(netloc=r'api\.github\.com(:[0-9]+)?$', path=r'/user/repos', method="post")
@urlmatch(netloc=r"api\.github\.com(:[0-9]+)?$", path=r"/user/repos", method="post")
def create_new_user_repo_mock(url, request):
repo = json.loads(request.body)
headers = {'content-type': 'application/json'}
headers = {"content-type": "application/json"}
# https://docs.github.com/en/rest/reference/repos#create-a-repository-for-the-authenticated-user
content = {
"name": repo['name'],
"name": repo["name"],
"full_name": f"octocat/{repo['name']}",
"private": repo.get('private', False),
"description": repo.get('description')
"private": repo.get("private", False),
"description": repo.get("description"),
}
content = json.dumps(content).encode("utf-8")
return response(201, content, headers, None, 5, request)
@urlmatch(netloc=r'api\.github\.com(:[0-9]+)?$', path=r'/repos/.*/.*', method="patch")
@urlmatch(netloc=r"api\.github\.com(:[0-9]+)?$", path=r"/repos/.*/.*", method="patch")
def patch_repo_mock(url, request):
match = re.search(
r"api\.github\.com(:[0-9]+)?/repos/(?P<org>[^/]+)/(?P<repo>[^/]+)", request.url)
match = re.search(r"api\.github\.com(:[0-9]+)?/repos/(?P<org>[^/]+)/(?P<repo>[^/]+)", request.url)
org = match.group("org")
repo = match.group("repo")
body = json.loads(request.body)
headers = {'content-type': 'application/json'}
headers = {"content-type": "application/json"}
# https://docs.github.com/en/rest/reference/repos#update-a-repository
content = {
"name": repo,
"full_name": f"{org}/{repo}",
"url": f"https://api.github.com/repos/{org}/{repo}",
"private": body.get('private', False),
"description": body.get('description'),
"private": body.get("private", False),
"description": body.get("description"),
"default_branch": "master",
"allow_rebase_merge": True
"allow_rebase_merge": True,
}
content = json.dumps(content).encode("utf-8")
return response(200, content, headers, None, 5, request)
@urlmatch(netloc=r'api\.github\.com(:[0-9]+)?$', path=r'/repos/.*/.*', method="delete")
@urlmatch(netloc=r"api\.github\.com(:[0-9]+)?$", path=r"/repos/.*/.*", method="delete")
def delete_repo_mock(url, request):
# https://docs.github.com/en/rest/reference/repos#delete-a-repository
return response(204, None, None, None, 5, request)
@urlmatch(netloc=r'api\.github\.com(:[0-9]+)?$', path=r'/repos/.*/.*', method="delete")
@urlmatch(netloc=r"api\.github\.com(:[0-9]+)?$", path=r"/repos/.*/.*", method="delete")
def delete_repo_notfound_mock(url, request):
# https://docs.github.com/en/rest/reference/repos#delete-a-repository
return response(404, "{\"message\": \"Not Found\"}", "", "Not Found", 5, request)
return response(404, '{"message": "Not Found"}', "", "Not Found", 5, request)
class TestGithubRepo(unittest.TestCase):
@@ -171,154 +161,170 @@ class TestGithubRepo(unittest.TestCase):
@with_httmock(get_repo_notfound_mock)
@with_httmock(create_new_org_repo_mock)
def test_create_new_org_repo(self):
result = github_repo.run_module({
'username': None,
'password': None,
"access_token": "mytoken",
"organization": "MyOrganization",
"name": "myrepo",
"description": "Just for fun",
"private": False,
"state": "present",
"api_url": "https://api.github.com",
"force_defaults": False,
})
result = github_repo.run_module(
{
"username": None,
"password": None,
"access_token": "mytoken",
"organization": "MyOrganization",
"name": "myrepo",
"description": "Just for fun",
"private": False,
"state": "present",
"api_url": "https://api.github.com",
"force_defaults": False,
}
)
self.assertEqual(result['changed'], True)
self.assertEqual(result['repo']['private'], False)
self.assertEqual(result['repo']['description'], 'Just for fun')
self.assertEqual(result["changed"], True)
self.assertEqual(result["repo"]["private"], False)
self.assertEqual(result["repo"]["description"], "Just for fun")
@with_httmock(get_orgs_mock)
@with_httmock(get_repo_notfound_mock)
@with_httmock(create_new_org_repo_mock)
def test_create_new_org_repo_incomplete(self):
result = github_repo.run_module({
'username': None,
'password': None,
"access_token": "mytoken",
"organization": "MyOrganization",
"name": "myrepo",
"description": None,
"private": None,
"state": "present",
"api_url": "https://api.github.com",
"force_defaults": False,
})
result = github_repo.run_module(
{
"username": None,
"password": None,
"access_token": "mytoken",
"organization": "MyOrganization",
"name": "myrepo",
"description": None,
"private": None,
"state": "present",
"api_url": "https://api.github.com",
"force_defaults": False,
}
)
self.assertEqual(result['changed'], True)
self.assertEqual(result['repo']['private'], False)
self.assertEqual(result['repo']['description'], None)
self.assertEqual(result["changed"], True)
self.assertEqual(result["repo"]["private"], False)
self.assertEqual(result["repo"]["description"], None)
@with_httmock(get_user_mock)
@with_httmock(get_repo_notfound_mock)
@with_httmock(create_new_user_repo_mock)
def test_create_new_user_repo(self):
result = github_repo.run_module({
'username': None,
'password': None,
"access_token": "mytoken",
"organization": None,
"name": "myrepo",
"description": "Just for fun",
"private": True,
"state": "present",
"api_url": "https://api.github.com",
"force_defaults": False,
})
self.assertEqual(result['changed'], True)
self.assertEqual(result['repo']['private'], True)
result = github_repo.run_module(
{
"username": None,
"password": None,
"access_token": "mytoken",
"organization": None,
"name": "myrepo",
"description": "Just for fun",
"private": True,
"state": "present",
"api_url": "https://api.github.com",
"force_defaults": False,
}
)
self.assertEqual(result["changed"], True)
self.assertEqual(result["repo"]["private"], True)
@with_httmock(get_orgs_mock)
@with_httmock(get_repo_mock)
@with_httmock(patch_repo_mock)
def test_patch_existing_org_repo(self):
result = github_repo.run_module({
'username': None,
'password': None,
"access_token": "mytoken",
"organization": "MyOrganization",
"name": "myrepo",
"description": "Just for fun",
"private": True,
"state": "present",
"api_url": "https://api.github.com",
"force_defaults": False,
})
self.assertEqual(result['changed'], True)
self.assertEqual(result['repo']['private'], True)
result = github_repo.run_module(
{
"username": None,
"password": None,
"access_token": "mytoken",
"organization": "MyOrganization",
"name": "myrepo",
"description": "Just for fun",
"private": True,
"state": "present",
"api_url": "https://api.github.com",
"force_defaults": False,
}
)
self.assertEqual(result["changed"], True)
self.assertEqual(result["repo"]["private"], True)
@with_httmock(get_orgs_mock)
@with_httmock(get_private_repo_mock)
def test_idempotency_existing_org_private_repo(self):
result = github_repo.run_module({
'username': None,
'password': None,
"access_token": "mytoken",
"organization": "MyOrganization",
"name": "myrepo",
"description": None,
"private": None,
"state": "present",
"api_url": "https://api.github.com",
"force_defaults": False,
})
self.assertEqual(result['changed'], False)
self.assertEqual(result['repo']['private'], True)
self.assertEqual(result['repo']['description'], 'This your first repo!')
result = github_repo.run_module(
{
"username": None,
"password": None,
"access_token": "mytoken",
"organization": "MyOrganization",
"name": "myrepo",
"description": None,
"private": None,
"state": "present",
"api_url": "https://api.github.com",
"force_defaults": False,
}
)
self.assertEqual(result["changed"], False)
self.assertEqual(result["repo"]["private"], True)
self.assertEqual(result["repo"]["description"], "This your first repo!")
@with_httmock(get_orgs_mock)
@with_httmock(get_repo_mock)
@with_httmock(delete_repo_mock)
def test_delete_org_repo(self):
result = github_repo.run_module({
'username': None,
'password': None,
"access_token": "mytoken",
"organization": "MyOrganization",
"name": "myrepo",
"description": "Just for fun",
"private": False,
"state": "absent",
"api_url": "https://api.github.com",
"force_defaults": False,
})
self.assertEqual(result['changed'], True)
result = github_repo.run_module(
{
"username": None,
"password": None,
"access_token": "mytoken",
"organization": "MyOrganization",
"name": "myrepo",
"description": "Just for fun",
"private": False,
"state": "absent",
"api_url": "https://api.github.com",
"force_defaults": False,
}
)
self.assertEqual(result["changed"], True)
@with_httmock(get_user_mock)
@with_httmock(get_repo_mock)
@with_httmock(delete_repo_mock)
def test_delete_user_repo(self):
result = github_repo.run_module({
'username': None,
'password': None,
"access_token": "mytoken",
"organization": None,
"name": "myrepo",
"description": "Just for fun",
"private": False,
"state": "absent",
"api_url": "https://api.github.com",
"force_defaults": False,
})
self.assertEqual(result['changed'], True)
result = github_repo.run_module(
{
"username": None,
"password": None,
"access_token": "mytoken",
"organization": None,
"name": "myrepo",
"description": "Just for fun",
"private": False,
"state": "absent",
"api_url": "https://api.github.com",
"force_defaults": False,
}
)
self.assertEqual(result["changed"], True)
@with_httmock(get_orgs_mock)
@with_httmock(get_repo_notfound_mock)
@with_httmock(delete_repo_notfound_mock)
def test_delete_org_repo_notfound(self):
result = github_repo.run_module({
'username': None,
'password': None,
"access_token": "mytoken",
"organization": "MyOrganization",
"name": "myrepo",
"description": "Just for fun",
"private": True,
"state": "absent",
"api_url": "https://api.github.com",
"force_defaults": False,
})
self.assertEqual(result['changed'], False)
result = github_repo.run_module(
{
"username": None,
"password": None,
"access_token": "mytoken",
"organization": "MyOrganization",
"name": "myrepo",
"description": "Just for fun",
"private": True,
"state": "absent",
"api_url": "https://api.github.com",
"force_defaults": False,
}
)
self.assertEqual(result["changed"], False)
if __name__ == "__main__":

View File

@@ -1,4 +1,3 @@
# Copyright (c) 2019, Guillaume Martinez (lunik@tiwabbit.fr)
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
@@ -18,10 +17,14 @@ def _dummy(x):
pytestmark = []
try:
from .gitlab import (GitlabModuleTestCase,
python_version_match_requirement,
resp_get_project, resp_find_project_deploy_key,
resp_create_project_deploy_key, resp_delete_project_deploy_key)
from .gitlab import (
GitlabModuleTestCase,
python_version_match_requirement,
resp_get_project,
resp_find_project_deploy_key,
resp_create_project_deploy_key,
resp_delete_project_deploy_key,
)
# GitLab module requirements
if python_version_match_requirement():
@@ -67,11 +70,16 @@ class TestGitlabDeployKey(GitlabModuleTestCase):
def test_create_deploy_key(self):
project = self.gitlab_instance.projects.get(1)
deploy_key = self.moduleUtil.create_deploy_key(project, {"title": "Public key",
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM"
"4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxc"
"KDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfD"
"zpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0="})
deploy_key = self.moduleUtil.create_deploy_key(
project,
{
"title": "Public key",
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM"
"4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxc"
"KDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfD"
"zpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
},
)
self.assertEqual(type(deploy_key), ProjectKey)
self.assertEqual(deploy_key.title, "Public key")

View File

@@ -1,4 +1,3 @@
# Copyright (c) 2019, Guillaume Martinez (lunik@tiwabbit.fr)
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
@@ -18,10 +17,16 @@ def _dummy(x):
pytestmark = []
try:
from .gitlab import (GitlabModuleTestCase,
python_version_match_requirement,
resp_get_group, resp_get_missing_group, resp_create_group,
resp_create_subgroup, resp_delete_group, resp_find_group_project)
from .gitlab import (
GitlabModuleTestCase,
python_version_match_requirement,
resp_get_group,
resp_get_missing_group,
resp_create_group,
resp_create_subgroup,
resp_delete_group,
resp_find_group_project,
)
# GitLab module requirements
if python_version_match_requirement():
@@ -65,13 +70,16 @@ class TestGitlabGroup(GitlabModuleTestCase):
@with_httmock(resp_create_group)
def test_create_group(self):
group = self.moduleUtil.create_group({'name': "Foobar Group",
'path': "foo-bar",
'description': "An interesting group",
'project_creation_level': "developer",
'subgroup_creation_level': "maintainer",
'require_two_factor_authentication': True,
})
group = self.moduleUtil.create_group(
{
"name": "Foobar Group",
"path": "foo-bar",
"description": "An interesting group",
"project_creation_level": "developer",
"subgroup_creation_level": "maintainer",
"require_two_factor_authentication": True,
}
)
self.assertEqual(type(group), Group)
self.assertEqual(group.name, "Foobar Group")
@@ -84,12 +92,15 @@ class TestGitlabGroup(GitlabModuleTestCase):
@with_httmock(resp_create_subgroup)
def test_create_subgroup(self):
group = self.moduleUtil.create_group({'name': "BarFoo Group",
'path': "bar-foo",
'parent_id': 1,
'project_creation_level': "noone",
'require_two_factor_authentication': True,
})
group = self.moduleUtil.create_group(
{
"name": "BarFoo Group",
"path": "bar-foo",
"parent_id": 1,
"project_creation_level": "noone",
"require_two_factor_authentication": True,
}
)
self.assertEqual(type(group), Group)
self.assertEqual(group.name, "BarFoo Group")
@@ -102,11 +113,15 @@ class TestGitlabGroup(GitlabModuleTestCase):
@with_httmock(resp_get_group)
def test_update_group(self):
group = self.gitlab_instance.groups.get(1)
changed, newGroup = self.moduleUtil.update_group(group, {'name': "BarFoo Group",
'visibility': "private",
'project_creation_level': "maintainer",
'require_two_factor_authentication': True,
})
changed, newGroup = self.moduleUtil.update_group(
group,
{
"name": "BarFoo Group",
"visibility": "private",
"project_creation_level": "maintainer",
"require_two_factor_authentication": True,
},
)
self.assertEqual(changed, True)
self.assertEqual(newGroup.name, "BarFoo Group")
@@ -114,7 +129,7 @@ class TestGitlabGroup(GitlabModuleTestCase):
self.assertEqual(newGroup.project_creation_level, "maintainer")
self.assertEqual(newGroup.require_two_factor_authentication, True)
changed, newGroup = self.moduleUtil.update_group(group, {'name': "BarFoo Group"})
changed, newGroup = self.moduleUtil.update_group(group, {"name": "BarFoo Group"})
self.assertEqual(changed, False)

View File

@@ -1,4 +1,3 @@
# Copyright (c) 2023, Zoran Krleza (zoran.krleza@true-north.hr)
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
@@ -15,7 +14,7 @@ PYTHON_GITLAB_MINIMAL_VERSION = (3, 1)
def python_gitlab_version_match_requirement():
return tuple(map(int, gitlab.__version__.split('.'))) >= PYTHON_GITLAB_MINIMAL_VERSION
return tuple(map(int, gitlab.__version__.split("."))) >= PYTHON_GITLAB_MINIMAL_VERSION
def _dummy(x):
@@ -26,12 +25,14 @@ def _dummy(x):
pytestmark = []
try:
from .gitlab import (GitlabModuleTestCase,
resp_get_user,
resp_get_group,
resp_list_group_access_tokens,
resp_create_group_access_tokens,
resp_revoke_group_access_tokens)
from .gitlab import (
GitlabModuleTestCase,
resp_get_user,
resp_get_group,
resp_list_group_access_tokens,
resp_create_group_access_tokens,
resp_revoke_group_access_tokens,
)
except ImportError:
pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing"))
@@ -56,7 +57,9 @@ class TestGitlabGroupAccessToken(GitlabModuleTestCase):
def setUp(self):
super().setUp()
if not python_gitlab_version_match_requirement():
self.skipTest(f"python-gitlab {'.'.join(map(str, PYTHON_GITLAB_MINIMAL_VERSION))}+ is needed for gitlab_group_access_token")
self.skipTest(
f"python-gitlab {'.'.join(map(str, PYTHON_GITLAB_MINIMAL_VERSION))}+ is needed for gitlab_group_access_token"
)
self.moduleUtil = GitLabGroupAccessToken(module=self.mock_module, gitlab_instance=self.gitlab_instance)
@@ -110,7 +113,9 @@ class TestGitlabGroupAccessToken(GitlabModuleTestCase):
groups = self.gitlab_instance.groups.get(1)
self.assertIsNotNone(groups)
rvalue = self.moduleUtil.create_access_token(groups, {'name': "tokenXYZ", 'scopes': ["api"], 'access_level': 20, 'expires_at': "2024-12-31"})
rvalue = self.moduleUtil.create_access_token(
groups, {"name": "tokenXYZ", "scopes": ["api"], "access_level": 20, "expires_at": "2024-12-31"}
)
self.assertEqual(rvalue, True)
self.assertIsNotNone(self.moduleUtil.access_token_object)

View File

@@ -1,4 +1,3 @@
# Copyright (c) 2019, Guillaume Martinez (lunik@tiwabbit.fr)
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
@@ -18,10 +17,14 @@ def _dummy(x):
pytestmark = []
try:
from .gitlab import (GitlabModuleTestCase,
python_version_match_requirement,
resp_get_project, resp_find_project_hook,
resp_create_project_hook, resp_delete_project_hook)
from .gitlab import (
GitlabModuleTestCase,
python_version_match_requirement,
resp_get_project,
resp_find_project_hook,
resp_create_project_hook,
resp_delete_project_hook,
)
# GitLab module requirements
if python_version_match_requirement():

View File

@@ -1,4 +1,3 @@
# Copyright (c) 2019, Guillaume Martinez (lunik@tiwabbit.fr)
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
@@ -18,10 +17,16 @@ def _dummy(x):
pytestmark = []
try:
from .gitlab import (GitlabModuleTestCase,
python_version_match_requirement,
resp_get_group, resp_get_project_by_name, resp_create_project,
resp_get_project, resp_delete_project, resp_get_user)
from .gitlab import (
GitlabModuleTestCase,
python_version_match_requirement,
resp_get_group,
resp_get_project_by_name,
resp_create_project,
resp_get_project,
resp_delete_project,
resp_get_user,
)
# GitLab module requirements
if python_version_match_requirement():
@@ -70,7 +75,9 @@ class TestGitlabProject(GitlabModuleTestCase):
@with_httmock(resp_create_project)
def test_create_project(self):
group = self.gitlab_instance.groups.get(1)
project = self.moduleUtil.create_project(group, {"name": "Diaspora Client", "path": "diaspora-client", "namespace_id": group.id})
project = self.moduleUtil.create_project(
group, {"name": "Diaspora Client", "path": "diaspora-client", "namespace_id": group.id}
)
self.assertEqual(type(project), Project)
self.assertEqual(project.name, "Diaspora Client")
@@ -97,14 +104,18 @@ class TestGitlabProject(GitlabModuleTestCase):
# merge_method should be 'merge' by default
self.assertEqual(project.merge_method, "merge")
changed, newProject = self.moduleUtil.update_project(project, {"name": "New Name", "merge_method": "rebase_merge"})
changed, newProject = self.moduleUtil.update_project(
project, {"name": "New Name", "merge_method": "rebase_merge"}
)
self.assertEqual(changed, True)
self.assertEqual(type(newProject), Project)
self.assertEqual(newProject.name, "New Name")
self.assertEqual(newProject.merge_method, "rebase_merge")
changed, newProject = self.moduleUtil.update_project(project, {"name": "New Name", "merge_method": "rebase_merge"})
changed, newProject = self.moduleUtil.update_project(
project, {"name": "New Name", "merge_method": "rebase_merge"}
)
self.assertEqual(changed, False)
self.assertEqual(newProject.name, "New Name")

View File

@@ -1,4 +1,3 @@
# Copyright (c) 2023, Zoran Krleza (zoran.krleza@true-north.hr)
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
@@ -15,7 +14,7 @@ PYTHON_GITLAB_MINIMAL_VERSION = (3, 1)
def python_gitlab_version_match_requirement():
return tuple(map(int, gitlab.__version__.split('.'))) >= PYTHON_GITLAB_MINIMAL_VERSION
return tuple(map(int, gitlab.__version__.split("."))) >= PYTHON_GITLAB_MINIMAL_VERSION
def _dummy(x):
@@ -26,12 +25,14 @@ def _dummy(x):
pytestmark = []
try:
from .gitlab import (GitlabModuleTestCase,
resp_get_user,
resp_get_project,
resp_list_project_access_tokens,
resp_create_project_access_tokens,
resp_revoke_project_access_tokens)
from .gitlab import (
GitlabModuleTestCase,
resp_get_user,
resp_get_project,
resp_list_project_access_tokens,
resp_create_project_access_tokens,
resp_revoke_project_access_tokens,
)
except ImportError:
pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing"))
@@ -56,7 +57,9 @@ class TestGitlabProjectAccessToken(GitlabModuleTestCase):
def setUp(self):
super().setUp()
if not python_gitlab_version_match_requirement():
self.skipTest(f"python-gitlab {'.'.join(map(str, PYTHON_GITLAB_MINIMAL_VERSION))}+ is needed for gitlab_project_access_token")
self.skipTest(
f"python-gitlab {'.'.join(map(str, PYTHON_GITLAB_MINIMAL_VERSION))}+ is needed for gitlab_project_access_token"
)
self.moduleUtil = GitLabProjectAccessToken(module=self.mock_module, gitlab_instance=self.gitlab_instance)
@@ -110,7 +113,9 @@ class TestGitlabProjectAccessToken(GitlabModuleTestCase):
project = self.gitlab_instance.projects.get(1)
self.assertIsNotNone(project)
rvalue = self.moduleUtil.create_access_token(project, {'name': "tokenXYZ", 'scopes': ["api"], 'access_level': 20, 'expires_at': "2024-12-31"})
rvalue = self.moduleUtil.create_access_token(
project, {"name": "tokenXYZ", "scopes": ["api"], "access_level": 20, "expires_at": "2024-12-31"}
)
self.assertEqual(rvalue, True)
self.assertIsNotNone(self.moduleUtil.access_token_object)

Some files were not shown because too many files have changed in this diff Show More