mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-03-26 21:33:12 +00:00
Reformat everything.
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
4
tests/unit/plugins/cache/test_memcached.py
vendored
4
tests/unit/plugins/cache/test_memcached.py
vendored
@@ -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)
|
||||
|
||||
10
tests/unit/plugins/cache/test_redis.py
vendored
10
tests/unit/plugins/cache/test_redis.py
vendored
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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"),
|
||||
},
|
||||
]
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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},
|
||||
],
|
||||
)
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
@@ -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}))
|
||||
|
||||
@@ -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
|
||||
),
|
||||
)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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"]])
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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},
|
||||
)
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
}
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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]
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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/"),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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__":
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user