summaryrefslogtreecommitdiff
path: root/tests/unit
diff options
context:
space:
mode:
authoransible-zuul[bot] <48994755+ansible-zuul[bot]@users.noreply.github.com>2020-01-16 18:56:16 +0000
committerGitHub <noreply@github.com>2020-01-16 18:56:16 +0000
commit03addce56012d4bd360e18612d2eb3af04d8f01a (patch)
tree9cf59872c2ddc7e99595db4f47c72a7ce08b6c10 /tests/unit
parentd31b74ba6c74a6e3cdebd80b9eb5272aeb9b0fb4 (diff)
parent6b6166151faa3d811ae0ec3010a89e518a26287b (diff)
downloadvyos-ansible-collection-03addce56012d4bd360e18612d2eb3af04d8f01a.tar.gz
vyos-ansible-collection-03addce56012d4bd360e18612d2eb3af04d8f01a.zip
Merge pull request #59 from CaptTrews/master
Updated from network content collector Reviewed-by: https://github.com/apps/ansible-zuul
Diffstat (limited to 'tests/unit')
-rw-r--r--tests/unit/__init__.py0
-rw-r--r--tests/unit/compat/__init__.py0
-rw-r--r--tests/unit/compat/builtins.py34
-rw-r--r--tests/unit/compat/mock.py127
-rw-r--r--tests/unit/compat/unittest.py39
-rw-r--r--tests/unit/mock/__init__.py0
-rw-r--r--tests/unit/mock/loader.py116
-rw-r--r--tests/unit/mock/path.py7
-rw-r--r--tests/unit/mock/procenv.py94
-rw-r--r--tests/unit/mock/vault_helper.py42
-rw-r--r--tests/unit/mock/yaml_helper.py164
-rw-r--r--tests/unit/modules/__init__.py0
-rw-r--r--tests/unit/modules/conftest.py37
-rw-r--r--tests/unit/modules/network/__init__.py0
-rw-r--r--tests/unit/modules/network/vyos/__init__.py0
-rw-r--r--tests/unit/modules/network/vyos/fixtures/__init__.py0
-rw-r--r--tests/unit/modules/network/vyos/fixtures/show_host_name1
-rw-r--r--tests/unit/modules/network/vyos/fixtures/show_version14
-rw-r--r--tests/unit/modules/network/vyos/fixtures/vyos_config_config.cfg10
-rw-r--r--tests/unit/modules/network/vyos/fixtures/vyos_config_src.cfg6
-rw-r--r--tests/unit/modules/network/vyos/fixtures/vyos_config_src_brackets.cfg13
-rw-r--r--tests/unit/modules/network/vyos/fixtures/vyos_ping_ping_10.10.10.10_count_27
-rw-r--r--tests/unit/modules/network/vyos/fixtures/vyos_ping_ping_10.10.10.11_count_10_ttl_128_size_51215
-rw-r--r--tests/unit/modules/network/vyos/fixtures/vyos_ping_ping_10.10.10.20_count_49
-rw-r--r--tests/unit/modules/network/vyos/fixtures/vyos_user_config.cfg2
-rw-r--r--tests/unit/modules/network/vyos/test_vyos_banner.py63
-rw-r--r--tests/unit/modules/network/vyos/test_vyos_command.py122
-rw-r--r--tests/unit/modules/network/vyos/test_vyos_config.py159
-rw-r--r--tests/unit/modules/network/vyos/test_vyos_facts.py109
-rw-r--r--tests/unit/modules/network/vyos/test_vyos_ping.py107
-rw-r--r--tests/unit/modules/network/vyos/test_vyos_static_route.py71
-rw-r--r--tests/unit/modules/network/vyos/test_vyos_system.py116
-rw-r--r--tests/unit/modules/network/vyos/test_vyos_user.py139
-rw-r--r--tests/unit/modules/network/vyos/vyos_module.py104
-rw-r--r--tests/unit/modules/utils.py48
-rw-r--r--tests/unit/requirements.txt42
36 files changed, 1817 insertions, 0 deletions
diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/unit/__init__.py
diff --git a/tests/unit/compat/__init__.py b/tests/unit/compat/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/unit/compat/__init__.py
diff --git a/tests/unit/compat/builtins.py b/tests/unit/compat/builtins.py
new file mode 100644
index 0000000..bfc8adf
--- /dev/null
+++ b/tests/unit/compat/builtins.py
@@ -0,0 +1,34 @@
+# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+#
+# Compat for python2.7
+#
+
+# One unittest needs to import builtins via __import__() so we need to have
+# the string that represents it
+try:
+ import __builtin__
+except ImportError:
+ BUILTINS = "builtins"
+else:
+ BUILTINS = "__builtin__"
diff --git a/tests/unit/compat/mock.py b/tests/unit/compat/mock.py
new file mode 100644
index 0000000..b45d6b5
--- /dev/null
+++ b/tests/unit/compat/mock.py
@@ -0,0 +1,127 @@
+# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+"""
+Compat module for Python3.x's unittest.mock module
+"""
+import sys
+
+# Python 2.7
+
+# Note: Could use the pypi mock library on python3.x as well as python2.x. It
+# is the same as the python3 stdlib mock library
+
+try:
+ # Allow wildcard import because we really do want to import all of mock's
+ # symbols into this compat shim
+ # pylint: disable=wildcard-import,unused-wildcard-import
+ from unittest.mock import *
+except ImportError:
+ # Python 2
+ # pylint: disable=wildcard-import,unused-wildcard-import
+ try:
+ from mock import *
+ except ImportError:
+ print("You need the mock library installed on python2.x to run tests")
+
+
+# Prior to 3.4.4, mock_open cannot handle binary read_data
+if sys.version_info >= (3,) and sys.version_info < (3, 4, 4):
+ file_spec = None
+
+ def _iterate_read_data(read_data):
+ # Helper for mock_open:
+ # Retrieve lines from read_data via a generator so that separate calls to
+ # readline, read, and readlines are properly interleaved
+ sep = b"\n" if isinstance(read_data, bytes) else "\n"
+ data_as_list = [l + sep for l in read_data.split(sep)]
+
+ if data_as_list[-1] == sep:
+ # If the last line ended in a newline, the list comprehension will have an
+ # extra entry that's just a newline. Remove this.
+ data_as_list = data_as_list[:-1]
+ else:
+ # If there wasn't an extra newline by itself, then the file being
+ # emulated doesn't have a newline to end the last line remove the
+ # newline that our naive format() added
+ data_as_list[-1] = data_as_list[-1][:-1]
+
+ for line in data_as_list:
+ yield line
+
+ def mock_open(mock=None, read_data=""):
+ """
+ A helper function to create a mock to replace the use of `open`. It works
+ for `open` called directly or used as a context manager.
+
+ The `mock` argument is the mock object to configure. If `None` (the
+ default) then a `MagicMock` will be created for you, with the API limited
+ to methods or attributes available on standard file handles.
+
+ `read_data` is a string for the `read` methoddline`, and `readlines` of the
+ file handle to return. This is an empty string by default.
+ """
+
+ def _readlines_side_effect(*args, **kwargs):
+ if handle.readlines.return_value is not None:
+ return handle.readlines.return_value
+ return list(_data)
+
+ def _read_side_effect(*args, **kwargs):
+ if handle.read.return_value is not None:
+ return handle.read.return_value
+ return type(read_data)().join(_data)
+
+ def _readline_side_effect():
+ if handle.readline.return_value is not None:
+ while True:
+ yield handle.readline.return_value
+ for line in _data:
+ yield line
+
+ global file_spec
+ if file_spec is None:
+ import _io
+
+ file_spec = list(
+ set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO)))
+ )
+
+ if mock is None:
+ mock = MagicMock(name="open", spec=open)
+
+ handle = MagicMock(spec=file_spec)
+ handle.__enter__.return_value = handle
+
+ _data = _iterate_read_data(read_data)
+
+ handle.write.return_value = None
+ handle.read.return_value = None
+ handle.readline.return_value = None
+ handle.readlines.return_value = None
+
+ handle.read.side_effect = _read_side_effect
+ handle.readline.side_effect = _readline_side_effect()
+ handle.readlines.side_effect = _readlines_side_effect
+
+ mock.return_value = handle
+ return mock
diff --git a/tests/unit/compat/unittest.py b/tests/unit/compat/unittest.py
new file mode 100644
index 0000000..df3379b
--- /dev/null
+++ b/tests/unit/compat/unittest.py
@@ -0,0 +1,39 @@
+# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+"""
+Compat module for Python2.7's unittest module
+"""
+
+import sys
+
+# Allow wildcard import because we really do want to import all of
+# unittests's symbols into this compat shim
+# pylint: disable=wildcard-import,unused-wildcard-import
+if sys.version_info < (2, 7):
+ try:
+ # Need unittest2 on python2.6
+ from unittest2 import *
+ except ImportError:
+ print("You need unittest2 installed on python2.6.x to run tests")
+else:
+ from unittest import *
diff --git a/tests/unit/mock/__init__.py b/tests/unit/mock/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/unit/mock/__init__.py
diff --git a/tests/unit/mock/loader.py b/tests/unit/mock/loader.py
new file mode 100644
index 0000000..c21188e
--- /dev/null
+++ b/tests/unit/mock/loader.py
@@ -0,0 +1,116 @@
+# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import os
+
+from ansible.errors import AnsibleParserError
+from ansible.parsing.dataloader import DataLoader
+from ansible.module_utils._text import to_bytes, to_text
+
+
+class DictDataLoader(DataLoader):
+ def __init__(self, file_mapping=None):
+ file_mapping = {} if file_mapping is None else file_mapping
+ assert type(file_mapping) == dict
+
+ super(DictDataLoader, self).__init__()
+
+ self._file_mapping = file_mapping
+ self._build_known_directories()
+ self._vault_secrets = None
+
+ def load_from_file(self, path, cache=True, unsafe=False):
+ path = to_text(path)
+ if path in self._file_mapping:
+ return self.load(self._file_mapping[path], path)
+ return None
+
+ # TODO: the real _get_file_contents returns a bytestring, so we actually convert the
+ # unicode/text it's created with to utf-8
+ def _get_file_contents(self, path):
+ path = to_text(path)
+ if path in self._file_mapping:
+ return (to_bytes(self._file_mapping[path]), False)
+ else:
+ raise AnsibleParserError("file not found: %s" % path)
+
+ def path_exists(self, path):
+ path = to_text(path)
+ return path in self._file_mapping or path in self._known_directories
+
+ def is_file(self, path):
+ path = to_text(path)
+ return path in self._file_mapping
+
+ def is_directory(self, path):
+ path = to_text(path)
+ return path in self._known_directories
+
+ def list_directory(self, path):
+ ret = []
+ path = to_text(path)
+ for x in list(self._file_mapping.keys()) + self._known_directories:
+ if x.startswith(path):
+ if os.path.dirname(x) == path:
+ ret.append(os.path.basename(x))
+ return ret
+
+ def is_executable(self, path):
+ # FIXME: figure out a way to make paths return true for this
+ return False
+
+ def _add_known_directory(self, directory):
+ if directory not in self._known_directories:
+ self._known_directories.append(directory)
+
+ def _build_known_directories(self):
+ self._known_directories = []
+ for path in self._file_mapping:
+ dirname = os.path.dirname(path)
+ while dirname not in ("/", ""):
+ self._add_known_directory(dirname)
+ dirname = os.path.dirname(dirname)
+
+ def push(self, path, content):
+ rebuild_dirs = False
+ if path not in self._file_mapping:
+ rebuild_dirs = True
+
+ self._file_mapping[path] = content
+
+ if rebuild_dirs:
+ self._build_known_directories()
+
+ def pop(self, path):
+ if path in self._file_mapping:
+ del self._file_mapping[path]
+ self._build_known_directories()
+
+ def clear(self):
+ self._file_mapping = dict()
+ self._known_directories = []
+
+ def get_basedir(self):
+ return os.getcwd()
+
+ def set_vault_secrets(self, vault_secrets):
+ self._vault_secrets = vault_secrets
diff --git a/tests/unit/mock/path.py b/tests/unit/mock/path.py
new file mode 100644
index 0000000..aea8ba1
--- /dev/null
+++ b/tests/unit/mock/path.py
@@ -0,0 +1,7 @@
+from ansible_collections.vyos.vyos.tests.unit.compat.mock import MagicMock
+from ansible.utils.path import unfrackpath
+
+
+mock_unfrackpath_noop = MagicMock(
+ spec_set=unfrackpath, side_effect=lambda x, *args, **kwargs: x
+)
diff --git a/tests/unit/mock/procenv.py b/tests/unit/mock/procenv.py
new file mode 100644
index 0000000..1587949
--- /dev/null
+++ b/tests/unit/mock/procenv.py
@@ -0,0 +1,94 @@
+# (c) 2016, Matt Davis <mdavis@ansible.com>
+# (c) 2016, Toshio Kuratomi <tkuratomi@ansible.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import sys
+import json
+
+from contextlib import contextmanager
+from io import BytesIO, StringIO
+from ansible_collections.vyos.vyos.tests.unit.compat import unittest
+from ansible.module_utils.six import PY3
+from ansible.module_utils._text import to_bytes
+
+
+@contextmanager
+def swap_stdin_and_argv(stdin_data="", argv_data=tuple()):
+ """
+ context manager that temporarily masks the test runner's values for stdin and argv
+ """
+ real_stdin = sys.stdin
+ real_argv = sys.argv
+
+ if PY3:
+ fake_stream = StringIO(stdin_data)
+ fake_stream.buffer = BytesIO(to_bytes(stdin_data))
+ else:
+ fake_stream = BytesIO(to_bytes(stdin_data))
+
+ try:
+ sys.stdin = fake_stream
+ sys.argv = argv_data
+
+ yield
+ finally:
+ sys.stdin = real_stdin
+ sys.argv = real_argv
+
+
+@contextmanager
+def swap_stdout():
+ """
+ context manager that temporarily replaces stdout for tests that need to verify output
+ """
+ old_stdout = sys.stdout
+
+ if PY3:
+ fake_stream = StringIO()
+ else:
+ fake_stream = BytesIO()
+
+ try:
+ sys.stdout = fake_stream
+
+ yield fake_stream
+ finally:
+ sys.stdout = old_stdout
+
+
+class ModuleTestCase(unittest.TestCase):
+ def setUp(self, module_args=None):
+ if module_args is None:
+ module_args = {
+ "_ansible_remote_tmp": "/tmp",
+ "_ansible_keep_remote_files": False,
+ }
+
+ args = json.dumps(dict(ANSIBLE_MODULE_ARGS=module_args))
+
+ # unittest doesn't have a clean place to use a context manager, so we have to enter/exit manually
+ self.stdin_swap = swap_stdin_and_argv(stdin_data=args)
+ self.stdin_swap.__enter__()
+
+ def tearDown(self):
+ # unittest doesn't have a clean place to use a context manager, so we have to enter/exit manually
+ self.stdin_swap.__exit__(None, None, None)
diff --git a/tests/unit/mock/vault_helper.py b/tests/unit/mock/vault_helper.py
new file mode 100644
index 0000000..b34ae13
--- /dev/null
+++ b/tests/unit/mock/vault_helper.py
@@ -0,0 +1,42 @@
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+from ansible.module_utils._text import to_bytes
+
+from ansible.parsing.vault import VaultSecret
+
+
+class TextVaultSecret(VaultSecret):
+ """A secret piece of text. ie, a password. Tracks text encoding.
+
+ The text encoding of the text may not be the default text encoding so
+ we keep track of the encoding so we encode it to the same bytes."""
+
+ def __init__(self, text, encoding=None, errors=None, _bytes=None):
+ super(TextVaultSecret, self).__init__()
+ self.text = text
+ self.encoding = encoding or "utf-8"
+ self._bytes = _bytes
+ self.errors = errors or "strict"
+
+ @property
+ def bytes(self):
+ """The text encoded with encoding, unless we specifically set _bytes."""
+ return self._bytes or to_bytes(
+ self.text, encoding=self.encoding, errors=self.errors
+ )
diff --git a/tests/unit/mock/yaml_helper.py b/tests/unit/mock/yaml_helper.py
new file mode 100644
index 0000000..1a945f1
--- /dev/null
+++ b/tests/unit/mock/yaml_helper.py
@@ -0,0 +1,164 @@
+import io
+import yaml
+
+from ansible.module_utils.six import PY3
+from ansible.parsing.yaml.loader import AnsibleLoader
+from ansible.parsing.yaml.dumper import AnsibleDumper
+
+
+class YamlTestUtils(object):
+ """Mixin class to combine with a unittest.TestCase subclass."""
+
+ def _loader(self, stream):
+ """Vault related tests will want to override this.
+
+ Vault cases should setup a AnsibleLoader that has the vault password."""
+ return AnsibleLoader(stream)
+
+ def _dump_stream(self, obj, stream, dumper=None):
+ """Dump to a py2-unicode or py3-string stream."""
+ if PY3:
+ return yaml.dump(obj, stream, Dumper=dumper)
+ else:
+ return yaml.dump(obj, stream, Dumper=dumper, encoding=None)
+
+ def _dump_string(self, obj, dumper=None):
+ """Dump to a py2-unicode or py3-string"""
+ if PY3:
+ return yaml.dump(obj, Dumper=dumper)
+ else:
+ return yaml.dump(obj, Dumper=dumper, encoding=None)
+
+ def _dump_load_cycle(self, obj):
+ # Each pass though a dump or load revs the 'generation'
+ # obj to yaml string
+ string_from_object_dump = self._dump_string(obj, dumper=AnsibleDumper)
+
+ # wrap a stream/file like StringIO around that yaml
+ stream_from_object_dump = io.StringIO(string_from_object_dump)
+ loader = self._loader(stream_from_object_dump)
+ # load the yaml stream to create a new instance of the object (gen 2)
+ obj_2 = loader.get_data()
+
+ # dump the gen 2 objects directory to strings
+ string_from_object_dump_2 = self._dump_string(
+ obj_2, dumper=AnsibleDumper
+ )
+
+ # The gen 1 and gen 2 yaml strings
+ self.assertEqual(string_from_object_dump, string_from_object_dump_2)
+ # the gen 1 (orig) and gen 2 py object
+ self.assertEqual(obj, obj_2)
+
+ # again! gen 3... load strings into py objects
+ stream_3 = io.StringIO(string_from_object_dump_2)
+ loader_3 = self._loader(stream_3)
+ obj_3 = loader_3.get_data()
+
+ string_from_object_dump_3 = self._dump_string(
+ obj_3, dumper=AnsibleDumper
+ )
+
+ self.assertEqual(obj, obj_3)
+ # should be transitive, but...
+ self.assertEqual(obj_2, obj_3)
+ self.assertEqual(string_from_object_dump, string_from_object_dump_3)
+
+ def _old_dump_load_cycle(self, obj):
+ """Dump the passed in object to yaml, load it back up, dump again, compare."""
+ stream = io.StringIO()
+
+ yaml_string = self._dump_string(obj, dumper=AnsibleDumper)
+ self._dump_stream(obj, stream, dumper=AnsibleDumper)
+
+ yaml_string_from_stream = stream.getvalue()
+
+ # reset stream
+ stream.seek(0)
+
+ loader = self._loader(stream)
+ # loader = AnsibleLoader(stream, vault_password=self.vault_password)
+ obj_from_stream = loader.get_data()
+
+ stream_from_string = io.StringIO(yaml_string)
+ loader2 = self._loader(stream_from_string)
+ # loader2 = AnsibleLoader(stream_from_string, vault_password=self.vault_password)
+ obj_from_string = loader2.get_data()
+
+ stream_obj_from_stream = io.StringIO()
+ stream_obj_from_string = io.StringIO()
+
+ if PY3:
+ yaml.dump(
+ obj_from_stream, stream_obj_from_stream, Dumper=AnsibleDumper
+ )
+ yaml.dump(
+ obj_from_stream, stream_obj_from_string, Dumper=AnsibleDumper
+ )
+ else:
+ yaml.dump(
+ obj_from_stream,
+ stream_obj_from_stream,
+ Dumper=AnsibleDumper,
+ encoding=None,
+ )
+ yaml.dump(
+ obj_from_stream,
+ stream_obj_from_string,
+ Dumper=AnsibleDumper,
+ encoding=None,
+ )
+
+ yaml_string_stream_obj_from_stream = stream_obj_from_stream.getvalue()
+ yaml_string_stream_obj_from_string = stream_obj_from_string.getvalue()
+
+ stream_obj_from_stream.seek(0)
+ stream_obj_from_string.seek(0)
+
+ if PY3:
+ yaml_string_obj_from_stream = yaml.dump(
+ obj_from_stream, Dumper=AnsibleDumper
+ )
+ yaml_string_obj_from_string = yaml.dump(
+ obj_from_string, Dumper=AnsibleDumper
+ )
+ else:
+ yaml_string_obj_from_stream = yaml.dump(
+ obj_from_stream, Dumper=AnsibleDumper, encoding=None
+ )
+ yaml_string_obj_from_string = yaml.dump(
+ obj_from_string, Dumper=AnsibleDumper, encoding=None
+ )
+
+ assert yaml_string == yaml_string_obj_from_stream
+ assert (
+ yaml_string
+ == yaml_string_obj_from_stream
+ == yaml_string_obj_from_string
+ )
+ assert (
+ yaml_string
+ == yaml_string_obj_from_stream
+ == yaml_string_obj_from_string
+ == yaml_string_stream_obj_from_stream
+ == yaml_string_stream_obj_from_string
+ )
+ assert obj == obj_from_stream
+ assert obj == obj_from_string
+ assert obj == yaml_string_obj_from_stream
+ assert obj == yaml_string_obj_from_string
+ assert (
+ obj
+ == obj_from_stream
+ == obj_from_string
+ == yaml_string_obj_from_stream
+ == yaml_string_obj_from_string
+ )
+ return {
+ "obj": obj,
+ "yaml_string": yaml_string,
+ "yaml_string_from_stream": yaml_string_from_stream,
+ "obj_from_stream": obj_from_stream,
+ "obj_from_string": obj_from_string,
+ "yaml_string_obj_from_string": yaml_string_obj_from_string,
+ }
diff --git a/tests/unit/modules/__init__.py b/tests/unit/modules/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/unit/modules/__init__.py
diff --git a/tests/unit/modules/conftest.py b/tests/unit/modules/conftest.py
new file mode 100644
index 0000000..ac56c9c
--- /dev/null
+++ b/tests/unit/modules/conftest.py
@@ -0,0 +1,37 @@
+# Copyright (c) 2017 Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+import json
+
+import pytest
+
+from ansible.module_utils.six import string_types
+from ansible.module_utils._text import to_bytes
+from ansible.module_utils.common._collections_compat import MutableMapping
+
+
+@pytest.fixture
+def patch_ansible_module(request, mocker):
+ if isinstance(request.param, string_types):
+ args = request.param
+ elif isinstance(request.param, MutableMapping):
+ if "ANSIBLE_MODULE_ARGS" not in request.param:
+ request.param = {"ANSIBLE_MODULE_ARGS": request.param}
+ if "_ansible_remote_tmp" not in request.param["ANSIBLE_MODULE_ARGS"]:
+ request.param["ANSIBLE_MODULE_ARGS"][
+ "_ansible_remote_tmp"
+ ] = "/tmp"
+ if (
+ "_ansible_keep_remote_files"
+ not in request.param["ANSIBLE_MODULE_ARGS"]
+ ):
+ request.param["ANSIBLE_MODULE_ARGS"][
+ "_ansible_keep_remote_files"
+ ] = False
+ args = json.dumps(request.param)
+ else:
+ raise Exception(
+ "Malformed data to the patch_ansible_module pytest fixture"
+ )
+
+ mocker.patch("ansible.module_utils.basic._ANSIBLE_ARGS", to_bytes(args))
diff --git a/tests/unit/modules/network/__init__.py b/tests/unit/modules/network/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/unit/modules/network/__init__.py
diff --git a/tests/unit/modules/network/vyos/__init__.py b/tests/unit/modules/network/vyos/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/unit/modules/network/vyos/__init__.py
diff --git a/tests/unit/modules/network/vyos/fixtures/__init__.py b/tests/unit/modules/network/vyos/fixtures/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/unit/modules/network/vyos/fixtures/__init__.py
diff --git a/tests/unit/modules/network/vyos/fixtures/show_host_name b/tests/unit/modules/network/vyos/fixtures/show_host_name
new file mode 100644
index 0000000..e89bc06
--- /dev/null
+++ b/tests/unit/modules/network/vyos/fixtures/show_host_name
@@ -0,0 +1 @@
+vyos01
diff --git a/tests/unit/modules/network/vyos/fixtures/show_version b/tests/unit/modules/network/vyos/fixtures/show_version
new file mode 100644
index 0000000..a015d55
--- /dev/null
+++ b/tests/unit/modules/network/vyos/fixtures/show_version
@@ -0,0 +1,14 @@
+Version: VyOS 1.1.7
+Description: VyOS 1.1.7 (helium)
+Copyright: 2016 VyOS maintainers and contributors
+Built by: maintainers@vyos.net
+Built on: Wed Feb 17 09:57:31 UTC 2016
+Build ID: 1602170957-4459750
+System type: x86 64-bit
+Boot via: image
+Hypervisor: VMware
+HW model: VMware Virtual Platform
+HW S/N: VMware-42 3c 26 25 44 c5 0a 91-cf 2c 97 2b fe 9b 25 be
+HW UUID: 423C2625-44C5-0A91-CF2C-972BFE9B25BE
+Uptime: 01:08:20 up 52 days, 2:13, 1 user, load average: 0.00, 0.01, 0.05
+
diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_config_config.cfg b/tests/unit/modules/network/vyos/fixtures/vyos_config_config.cfg
new file mode 100644
index 0000000..fcef8eb
--- /dev/null
+++ b/tests/unit/modules/network/vyos/fixtures/vyos_config_config.cfg
@@ -0,0 +1,10 @@
+set system host-name 'router'
+set system domain-name 'example.com'
+set system domain-search domain 'example.com'
+set system name-server '8.8.8.8'
+set system name-server '8.8.4.4'
+set interfaces ethernet eth0 address '1.2.3.4/24'
+set interfaces ethernet eth0 description 'test string'
+set interfaces ethernet eth1 address '6.7.8.9/24'
+set interfaces ethernet eth1 description 'test string'
+set interfaces ethernet eth1 disable
diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_config_src.cfg b/tests/unit/modules/network/vyos/fixtures/vyos_config_src.cfg
new file mode 100644
index 0000000..410f611
--- /dev/null
+++ b/tests/unit/modules/network/vyos/fixtures/vyos_config_src.cfg
@@ -0,0 +1,6 @@
+set system host-name foo
+
+delete interfaces ethernet eth0 address
+set interfaces ethernet eth1 address '6.7.8.9/24'
+ set interfaces ethernet eth1 description 'test string'
+set interfaces ethernet eth1 disable
diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_config_src_brackets.cfg b/tests/unit/modules/network/vyos/fixtures/vyos_config_src_brackets.cfg
new file mode 100644
index 0000000..468b32c
--- /dev/null
+++ b/tests/unit/modules/network/vyos/fixtures/vyos_config_src_brackets.cfg
@@ -0,0 +1,13 @@
+interfaces {
+ ethernet eth0 {
+ address 10.10.10.10/24
+ }
+ ethernet eth1 {
+ address 6.7.8.9/24
+ description test string
+ disable
+ }
+}
+system {
+ host-name foo
+}
diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_ping_ping_10.10.10.10_count_2 b/tests/unit/modules/network/vyos/fixtures/vyos_ping_ping_10.10.10.10_count_2
new file mode 100644
index 0000000..c28fba1
--- /dev/null
+++ b/tests/unit/modules/network/vyos/fixtures/vyos_ping_ping_10.10.10.10_count_2
@@ -0,0 +1,7 @@
+PING 10.10.10.10 (10.10.10.10) 56(84) bytes of data.
+64 bytes from 10.10.10.10: icmp_req=1 ttl=255 time=1.27 ms
+64 bytes from 10.10.10.10: icmp_req=2 ttl=255 time=2.28 ms
+
+--- 10.8.38.66 ping statistics ---
+2 packets transmitted, 2 received, 0% packet loss, time 1001ms
+rtt min/avg/max/mdev = 12.1222/17.124/22.225/10.143 ms
diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_ping_ping_10.10.10.11_count_10_ttl_128_size_512 b/tests/unit/modules/network/vyos/fixtures/vyos_ping_ping_10.10.10.11_count_10_ttl_128_size_512
new file mode 100644
index 0000000..54e026c
--- /dev/null
+++ b/tests/unit/modules/network/vyos/fixtures/vyos_ping_ping_10.10.10.11_count_10_ttl_128_size_512
@@ -0,0 +1,15 @@
+PING 10.10.10.11 (10.8.38.65) 512(540) bytes of data.
+520 bytes from 10.10.10.11: icmp_req=1 ttl=255 time=1.17 ms
+520 bytes from 10.10.10.11: icmp_req=2 ttl=255 time=1.32 ms
+520 bytes from 10.10.10.11: icmp_req=3 ttl=255 time=1.21 ms
+520 bytes from 10.10.10.11: icmp_req=4 ttl=255 time=1.46 ms
+520 bytes from 10.10.10.11: icmp_req=5 ttl=255 time=1.32 ms
+520 bytes from 10.10.10.11: icmp_req=6 ttl=255 time=1.28 ms
+520 bytes from 10.10.10.11: icmp_req=7 ttl=255 time=1.25 ms
+520 bytes from 10.10.10.11: icmp_req=8 ttl=255 time=1.23 ms
+520 bytes from 10.10.10.11: icmp_req=9 ttl=255 time=1.34 ms
+520 bytes from 10.10.10.11: icmp_req=10 ttl=255 time=21.0 ms
+
+--- 10.10.10.11 ping statistics ---
+10 packets transmitted, 10 received, 0% packet loss, time 9012ms
+rtt min/avg/max/mdev = 1.170/3.262/21.002/5.913 ms
diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_ping_ping_10.10.10.20_count_4 b/tests/unit/modules/network/vyos/fixtures/vyos_ping_ping_10.10.10.20_count_4
new file mode 100644
index 0000000..08e6181
--- /dev/null
+++ b/tests/unit/modules/network/vyos/fixtures/vyos_ping_ping_10.10.10.20_count_4
@@ -0,0 +1,9 @@
+PING 10.10.10.20 (10.10.10.20) 56(84) bytes of data.
+From 10.10.10.20 icmp_seq=1 Destination Host Unreachable
+From 10.10.10.20 icmp_seq=2 Destination Host Unreachable
+From 10.10.10.20 icmp_seq=3 Destination Host Unreachable
+From 10.10.10.20 icmp_seq=4 Destination Host Unreachable
+
+--- 10.10.10.20 ping statistics ---
+4 packets transmitted, 0 received, +4 errors, 100% packet loss, time 3053ms
+pipe 3
diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_user_config.cfg b/tests/unit/modules/network/vyos/fixtures/vyos_user_config.cfg
new file mode 100644
index 0000000..81cd1a4
--- /dev/null
+++ b/tests/unit/modules/network/vyos/fixtures/vyos_user_config.cfg
@@ -0,0 +1,2 @@
+set system login user admin level operator authentication encrypted-password '$6$V5oWW3JM9NFAwOG$P2L4raFvIrZjjs3g0qmH4Ns5ti7flRpSs6aEqy4TrGZYXGeBiYzwi2A6jy'
+set system login user ansible level operator authentication encrypted-password '$6$ZfvSv6A50W6yNPYX$4HP5eg2sywcXYxTqhApQ7zvUvx0HsQHrI9xuJoFLy2gM/'
diff --git a/tests/unit/modules/network/vyos/test_vyos_banner.py b/tests/unit/modules/network/vyos/test_vyos_banner.py
new file mode 100644
index 0000000..c575409
--- /dev/null
+++ b/tests/unit/modules/network/vyos/test_vyos_banner.py
@@ -0,0 +1,63 @@
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+from ansible_collections.vyos.vyos.tests.unit.compat.mock import patch
+from ansible_collections.vyos.vyos.plugins.modules import vyos_banner
+from ansible_collections.vyos.vyos.tests.unit.modules.utils import (
+ set_module_args,
+)
+from .vyos_module import TestVyosModule
+
+
+class TestVyosBannerModule(TestVyosModule):
+
+ module = vyos_banner
+
+ def setUp(self):
+ super(TestVyosBannerModule, self).setUp()
+
+ self.mock_get_config = patch(
+ "ansible_collections.vyos.vyos.plugins.modules.vyos_banner.get_config"
+ )
+ self.get_config = self.mock_get_config.start()
+
+ self.mock_load_config = patch(
+ "ansible_collections.vyos.vyos.plugins.modules.vyos_banner.load_config"
+ )
+ self.load_config = self.mock_load_config.start()
+
+ def tearDown(self):
+ super(TestVyosBannerModule, self).tearDown()
+ self.mock_get_config.stop()
+ self.mock_load_config.stop()
+
+ def load_fixtures(self, commands=None):
+ self.load_config.return_value = dict(diff=None, session="session")
+
+ def test_vyos_banner_create(self):
+ set_module_args(dict(banner="pre-login", text="test\nbanner\nstring"))
+ commands = [
+ "set system login banner pre-login 'test\\nbanner\\nstring'"
+ ]
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vyos_banner_remove(self):
+ set_module_args(dict(banner="pre-login", state="absent"))
+ self.execute_module(changed=False, commands=[])
diff --git a/tests/unit/modules/network/vyos/test_vyos_command.py b/tests/unit/modules/network/vyos/test_vyos_command.py
new file mode 100644
index 0000000..820c6c4
--- /dev/null
+++ b/tests/unit/modules/network/vyos/test_vyos_command.py
@@ -0,0 +1,122 @@
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+from ansible_collections.vyos.vyos.tests.unit.compat.mock import patch
+from ansible_collections.vyos.vyos.plugins.modules import vyos_command
+from ansible_collections.vyos.vyos.tests.unit.modules.utils import (
+ set_module_args,
+)
+from .vyos_module import TestVyosModule, load_fixture
+
+
+class TestVyosCommandModule(TestVyosModule):
+
+ module = vyos_command
+
+ def setUp(self):
+ super(TestVyosCommandModule, self).setUp()
+ self.mock_run_commands = patch(
+ "ansible_collections.vyos.vyos.plugins.modules.vyos_command.run_commands"
+ )
+ self.run_commands = self.mock_run_commands.start()
+
+ def tearDown(self):
+ super(TestVyosCommandModule, self).tearDown()
+ self.mock_run_commands.stop()
+
+ def load_fixtures(self, commands=None):
+ def load_from_file(*args, **kwargs):
+ module, commands = args
+ output = list()
+
+ for item in commands:
+ try:
+ command = item["command"]
+ except ValueError:
+ command = item
+ filename = str(command).replace(" ", "_")
+ output.append(load_fixture(filename))
+ return output
+
+ self.run_commands.side_effect = load_from_file
+
+ def test_vyos_command_simple(self):
+ set_module_args(dict(commands=["show version"]))
+ result = self.execute_module()
+ self.assertEqual(len(result["stdout"]), 1)
+ self.assertTrue(result["stdout"][0].startswith("Version: VyOS"))
+
+ def test_vyos_command_multiple(self):
+ set_module_args(dict(commands=["show version", "show version"]))
+ result = self.execute_module()
+ self.assertEqual(len(result["stdout"]), 2)
+ self.assertTrue(result["stdout"][0].startswith("Version: VyOS"))
+
+ def test_vyos_command_wait_for(self):
+ wait_for = 'result[0] contains "VyOS maintainers"'
+ set_module_args(dict(commands=["show version"], wait_for=wait_for))
+ self.execute_module()
+
+ def test_vyos_command_wait_for_fails(self):
+ wait_for = 'result[0] contains "test string"'
+ set_module_args(dict(commands=["show version"], wait_for=wait_for))
+ self.execute_module(failed=True)
+ self.assertEqual(self.run_commands.call_count, 10)
+
+ def test_vyos_command_retries(self):
+ wait_for = 'result[0] contains "test string"'
+ set_module_args(
+ dict(commands=["show version"], wait_for=wait_for, retries=2)
+ )
+ self.execute_module(failed=True)
+ self.assertEqual(self.run_commands.call_count, 2)
+
+ def test_vyos_command_match_any(self):
+ wait_for = [
+ 'result[0] contains "VyOS maintainers"',
+ 'result[0] contains "test string"',
+ ]
+ set_module_args(
+ dict(commands=["show version"], wait_for=wait_for, match="any")
+ )
+ self.execute_module()
+
+ def test_vyos_command_match_all(self):
+ wait_for = [
+ 'result[0] contains "VyOS maintainers"',
+ 'result[0] contains "maintainers@vyos.net"',
+ ]
+ set_module_args(
+ dict(commands=["show version"], wait_for=wait_for, match="all")
+ )
+ self.execute_module()
+
+ def test_vyos_command_match_all_failure(self):
+ wait_for = [
+ 'result[0] contains "VyOS maintainers"',
+ 'result[0] contains "test string"',
+ ]
+ commands = ["show version", "show version"]
+ set_module_args(
+ dict(commands=commands, wait_for=wait_for, match="all")
+ )
+ self.execute_module(failed=True)
diff --git a/tests/unit/modules/network/vyos/test_vyos_config.py b/tests/unit/modules/network/vyos/test_vyos_config.py
new file mode 100644
index 0000000..a471edd
--- /dev/null
+++ b/tests/unit/modules/network/vyos/test_vyos_config.py
@@ -0,0 +1,159 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+from ansible_collections.vyos.vyos.tests.unit.compat.mock import (
+ patch,
+ MagicMock,
+)
+from ansible_collections.vyos.vyos.plugins.modules import vyos_config
+from ansible_collections.vyos.vyos.plugins.cliconf.vyos import Cliconf
+from ansible_collections.vyos.vyos.tests.unit.modules.utils import (
+ set_module_args,
+)
+from .vyos_module import TestVyosModule, load_fixture
+
+
+class TestVyosConfigModule(TestVyosModule):
+
+ module = vyos_config
+
+ def setUp(self):
+ super(TestVyosConfigModule, self).setUp()
+
+ self.mock_get_config = patch(
+ "ansible_collections.vyos.vyos.plugins.modules.vyos_config.get_config"
+ )
+ self.get_config = self.mock_get_config.start()
+
+ self.mock_load_config = patch(
+ "ansible_collections.vyos.vyos.plugins.modules.vyos_config.load_config"
+ )
+ self.load_config = self.mock_load_config.start()
+
+ self.mock_run_commands = patch(
+ "ansible_collections.vyos.vyos.plugins.modules.vyos_config.run_commands"
+ )
+ self.run_commands = self.mock_run_commands.start()
+
+ self.mock_get_connection = patch(
+ "ansible_collections.vyos.vyos.plugins.modules.vyos_config.get_connection"
+ )
+ self.get_connection = self.mock_get_connection.start()
+
+ self.cliconf_obj = Cliconf(MagicMock())
+ self.running_config = load_fixture("vyos_config_config.cfg")
+
+ self.conn = self.get_connection()
+ self.conn.edit_config = MagicMock()
+ self.running_config = load_fixture("vyos_config_config.cfg")
+
+ def tearDown(self):
+ super(TestVyosConfigModule, self).tearDown()
+
+ self.mock_get_config.stop()
+ self.mock_load_config.stop()
+ self.mock_run_commands.stop()
+ self.mock_get_connection.stop()
+
+ def load_fixtures(self, commands=None):
+ config_file = "vyos_config_config.cfg"
+ self.get_config.return_value = load_fixture(config_file)
+ self.load_config.return_value = None
+
+ def test_vyos_config_unchanged(self):
+ src = load_fixture("vyos_config_config.cfg")
+ self.conn.get_diff = MagicMock(
+ return_value=self.cliconf_obj.get_diff(src, src)
+ )
+ set_module_args(dict(src=src))
+ self.execute_module()
+
+ def test_vyos_config_src(self):
+ src = load_fixture("vyos_config_src.cfg")
+ set_module_args(dict(src=src))
+ candidate = "\n".join(self.module.format_commands(src.splitlines()))
+ commands = [
+ "set system host-name foo",
+ "delete interfaces ethernet eth0 address",
+ ]
+ self.conn.get_diff = MagicMock(
+ return_value=self.cliconf_obj.get_diff(
+ candidate, self.running_config
+ )
+ )
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vyos_config_src_brackets(self):
+ src = load_fixture("vyos_config_src_brackets.cfg")
+ set_module_args(dict(src=src))
+ candidate = "\n".join(self.module.format_commands(src.splitlines()))
+ commands = [
+ "set interfaces ethernet eth0 address 10.10.10.10/24",
+ "set system host-name foo",
+ ]
+ self.conn.get_diff = MagicMock(
+ return_value=self.cliconf_obj.get_diff(
+ candidate, self.running_config
+ )
+ )
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vyos_config_backup(self):
+ set_module_args(dict(backup=True))
+ result = self.execute_module()
+ self.assertIn("__backup__", result)
+
+ def test_vyos_config_lines(self):
+ commands = ["set system host-name foo"]
+ set_module_args(dict(lines=commands))
+ candidate = "\n".join(commands)
+ self.conn.get_diff = MagicMock(
+ return_value=self.cliconf_obj.get_diff(
+ candidate, self.running_config
+ )
+ )
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vyos_config_config(self):
+ config = "set system host-name localhost"
+ new_config = ["set system host-name router"]
+ set_module_args(dict(lines=new_config, config=config))
+ candidate = "\n".join(new_config)
+ self.conn.get_diff = MagicMock(
+ return_value=self.cliconf_obj.get_diff(candidate, config)
+ )
+ self.execute_module(changed=True, commands=new_config)
+
+ def test_vyos_config_match_none(self):
+ lines = [
+ "set system interfaces ethernet eth0 address 1.2.3.4/24",
+ "set system interfaces ethernet eth0 description test string",
+ ]
+ set_module_args(dict(lines=lines, match="none"))
+ candidate = "\n".join(lines)
+ self.conn.get_diff = MagicMock(
+ return_value=self.cliconf_obj.get_diff(
+ candidate, None, diff_match="none"
+ )
+ )
+ self.execute_module(changed=True, commands=lines, sort=False)
diff --git a/tests/unit/modules/network/vyos/test_vyos_facts.py b/tests/unit/modules/network/vyos/test_vyos_facts.py
new file mode 100644
index 0000000..b22a523
--- /dev/null
+++ b/tests/unit/modules/network/vyos/test_vyos_facts.py
@@ -0,0 +1,109 @@
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+import json
+from ansible_collections.vyos.vyos.tests.unit.compat.mock import patch
+from ansible_collections.vyos.vyos.plugins.modules import vyos_facts
+from ansible_collections.vyos.vyos.tests.unit.modules.utils import (
+ set_module_args,
+)
+from .vyos_module import TestVyosModule, load_fixture
+
+
+class TestVyosFactsModule(TestVyosModule):
+ module = vyos_facts
+
+ def setUp(self):
+ super(TestVyosFactsModule, self).setUp()
+ self.mock_run_commands = patch(
+ "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.legacy.base.run_commands"
+ )
+ self.run_commands = self.mock_run_commands.start()
+
+ self.mock_get_resource_connection = patch(
+ "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection"
+ )
+ self.get_resource_connection = (
+ self.mock_get_resource_connection.start()
+ )
+
+ self.mock_get_capabilities = patch(
+ "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.legacy.base.get_capabilities"
+ )
+ self.get_capabilities = self.mock_get_capabilities.start()
+ self.get_capabilities.return_value = {
+ "device_info": {
+ "network_os": "vyos",
+ "network_os_hostname": "vyos01",
+ "network_os_model": "VMware",
+ "network_os_version": "VyOS 1.1.7",
+ },
+ "network_api": "cliconf",
+ }
+
+ def tearDown(self):
+ super(TestVyosFactsModule, self).tearDown()
+ self.mock_run_commands.stop()
+ self.mock_get_capabilities.stop()
+ self.mock_get_resource_connection.stop()
+
+ def load_fixtures(self, commands=None):
+ def load_from_file(*args, **kwargs):
+ module, commands = args
+ output = list()
+ for item in commands:
+ try:
+ obj = json.loads(item)
+ command = obj["command"]
+ except ValueError:
+ command = item
+ filename = str(command).replace(" ", "_")
+ output.append(load_fixture(filename))
+ return output
+
+ self.run_commands.side_effect = load_from_file
+
+ def test_vyos_facts_default(self):
+ set_module_args(dict(gather_subset="default"))
+ result = self.execute_module()
+ facts = result.get("ansible_facts")
+ self.assertEqual(len(facts), 10)
+ self.assertEqual(facts["ansible_net_hostname"].strip(), "vyos01")
+ self.assertEqual(facts["ansible_net_version"], "VyOS 1.1.7")
+
+ def test_vyos_facts_not_all(self):
+ set_module_args(dict(gather_subset="!all"))
+ result = self.execute_module()
+ facts = result.get("ansible_facts")
+ self.assertEqual(len(facts), 10)
+ self.assertEqual(facts["ansible_net_hostname"].strip(), "vyos01")
+ self.assertEqual(facts["ansible_net_version"], "VyOS 1.1.7")
+
+ def test_vyos_facts_exclude_most(self):
+ set_module_args(dict(gather_subset=["!neighbors", "!config"]))
+ result = self.execute_module()
+ facts = result.get("ansible_facts")
+ self.assertEqual(len(facts), 10)
+ self.assertEqual(facts["ansible_net_hostname"].strip(), "vyos01")
+ self.assertEqual(facts["ansible_net_version"], "VyOS 1.1.7")
+
+ def test_vyos_facts_invalid_subset(self):
+ set_module_args(dict(gather_subset="cereal"))
+ self.execute_module(failed=True)
diff --git a/tests/unit/modules/network/vyos/test_vyos_ping.py b/tests/unit/modules/network/vyos/test_vyos_ping.py
new file mode 100644
index 0000000..e307610
--- /dev/null
+++ b/tests/unit/modules/network/vyos/test_vyos_ping.py
@@ -0,0 +1,107 @@
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+from ansible_collections.vyos.vyos.tests.unit.compat.mock import patch
+from ansible_collections.vyos.vyos.plugins.modules import vyos_ping
+from ansible_collections.vyos.vyos.tests.unit.modules.utils import (
+ set_module_args,
+)
+from .vyos_module import TestVyosModule, load_fixture
+
+
+class TestVyosPingModule(TestVyosModule):
+
+ module = vyos_ping
+
+ def setUp(self):
+ super(TestVyosPingModule, self).setUp()
+ self.mock_run_commands = patch(
+ "ansible_collections.vyos.vyos.plugins.modules.vyos_ping.run_commands"
+ )
+ self.run_commands = self.mock_run_commands.start()
+
+ def tearDown(self):
+ super(TestVyosPingModule, self).tearDown()
+ self.mock_run_commands.stop()
+
+ def load_fixtures(self, commands=None):
+ def load_from_file(*args, **kwargs):
+ commands = kwargs["commands"]
+ output = list()
+
+ for command in commands:
+ filename = str(command).split(" | ")[0].replace(" ", "_")
+ output.append(load_fixture("vyos_ping_%s" % filename))
+ return output
+
+ self.run_commands.side_effect = load_from_file
+
+ def test_vyos_ping_expected_success(self):
+ """ Test for successful pings when destination should be reachable """
+ set_module_args(dict(count=2, dest="10.10.10.10"))
+ self.execute_module()
+
+ def test_vyos_ping_expected_failure(self):
+ """ Test for unsuccessful pings when destination should not be reachable """
+ set_module_args(dict(count=4, dest="10.10.10.20", state="absent"))
+ self.execute_module()
+
+ def test_vyos_ping_unexpected_success(self):
+ """ Test for successful pings when destination should not be reachable - FAIL. """
+ set_module_args(dict(count=2, dest="10.10.10.10", state="absent"))
+ self.execute_module(failed=True)
+
+ def test_vyos_ping_unexpected_failure(self):
+ """ Test for unsuccessful pings when destination should be reachable - FAIL. """
+ set_module_args(dict(count=4, dest="10.10.10.20"))
+ self.execute_module(failed=True)
+
+ def test_vyos_ping_failure_stats(self):
+ """Test for asserting stats when ping fails"""
+ set_module_args(dict(count=4, dest="10.10.10.20"))
+ result = self.execute_module(failed=True)
+ self.assertEqual(result["packet_loss"], "100%")
+ self.assertEqual(result["packets_rx"], 0)
+ self.assertEqual(result["packets_tx"], 4)
+
+ def test_vyos_ping_success_stats(self):
+ """Test for asserting stats when ping passes"""
+ set_module_args(dict(count=2, dest="10.10.10.10"))
+ result = self.execute_module()
+ self.assertEqual(result["packet_loss"], "0%")
+ self.assertEqual(result["packets_rx"], 2)
+ self.assertEqual(result["packets_tx"], 2)
+ self.assertEqual(result["rtt"]["min"], 12)
+ self.assertEqual(result["rtt"]["avg"], 17)
+ self.assertEqual(result["rtt"]["max"], 22)
+ self.assertEqual(result["rtt"]["mdev"], 10)
+
+ def test_vyos_ping_success_stats_with_options(self):
+ set_module_args(dict(count=10, ttl=128, size=512, dest="10.10.10.11"))
+ result = self.execute_module()
+ self.assertEqual(result["packet_loss"], "0%")
+ self.assertEqual(result["packets_rx"], 10)
+ self.assertEqual(result["packets_tx"], 10)
+ self.assertEqual(result["rtt"]["min"], 1)
+ self.assertEqual(result["rtt"]["avg"], 3)
+ self.assertEqual(result["rtt"]["max"], 21)
+ self.assertEqual(result["rtt"]["mdev"], 5)
diff --git a/tests/unit/modules/network/vyos/test_vyos_static_route.py b/tests/unit/modules/network/vyos/test_vyos_static_route.py
new file mode 100644
index 0000000..e020ca5
--- /dev/null
+++ b/tests/unit/modules/network/vyos/test_vyos_static_route.py
@@ -0,0 +1,71 @@
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+from ansible_collections.vyos.vyos.tests.unit.compat.mock import patch
+from ansible_collections.vyos.vyos.plugins.modules import vyos_static_route
+from ansible_collections.vyos.vyos.tests.unit.modules.utils import (
+ set_module_args,
+)
+from .vyos_module import TestVyosModule
+
+
+class TestVyosStaticRouteModule(TestVyosModule):
+
+ module = vyos_static_route
+
+ def setUp(self):
+ super(TestVyosStaticRouteModule, self).setUp()
+
+ self.mock_get_config = patch(
+ "ansible_collections.vyos.vyos.plugins.modules.vyos_static_route.get_config"
+ )
+ self.get_config = self.mock_get_config.start()
+
+ self.mock_load_config = patch(
+ "ansible_collections.vyos.vyos.plugins.modules.vyos_static_route.load_config"
+ )
+ self.load_config = self.mock_load_config.start()
+
+ def tearDown(self):
+ super(TestVyosStaticRouteModule, self).tearDown()
+
+ self.mock_get_config.stop()
+ self.mock_load_config.stop()
+
+ def load_fixtures(self, commands=None, transport="cli"):
+ self.load_config.return_value = dict(diff=None, session="session")
+
+ def test_vyos_static_route_present(self):
+ set_module_args(
+ dict(
+ prefix="172.26.0.0/16",
+ next_hop="172.26.4.1",
+ admin_distance="1",
+ )
+ )
+ result = self.execute_module(changed=True)
+ self.assertEqual(
+ result["commands"],
+ [
+ "set protocols static route 172.26.0.0/16 next-hop 172.26.4.1 distance 1"
+ ],
+ )
diff --git a/tests/unit/modules/network/vyos/test_vyos_system.py b/tests/unit/modules/network/vyos/test_vyos_system.py
new file mode 100644
index 0000000..c22f7c1
--- /dev/null
+++ b/tests/unit/modules/network/vyos/test_vyos_system.py
@@ -0,0 +1,116 @@
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+from ansible_collections.vyos.vyos.tests.unit.compat.mock import patch
+from ansible_collections.vyos.vyos.plugins.modules import vyos_system
+from ansible_collections.vyos.vyos.tests.unit.modules.utils import (
+ set_module_args,
+)
+from .vyos_module import TestVyosModule, load_fixture
+
+
+class TestVyosSystemModule(TestVyosModule):
+
+ module = vyos_system
+
+ def setUp(self):
+ super(TestVyosSystemModule, self).setUp()
+
+ self.mock_get_config = patch(
+ "ansible_collections.vyos.vyos.plugins.modules.vyos_system.get_config"
+ )
+ self.get_config = self.mock_get_config.start()
+
+ self.mock_load_config = patch(
+ "ansible_collections.vyos.vyos.plugins.modules.vyos_system.load_config"
+ )
+ self.load_config = self.mock_load_config.start()
+
+ def tearDown(self):
+ super(TestVyosSystemModule, self).tearDown()
+
+ self.mock_get_config.stop()
+ self.mock_load_config.stop()
+
+ def load_fixtures(self, commands=None):
+ self.get_config.return_value = load_fixture("vyos_config_config.cfg")
+
+ def test_vyos_system_hostname(self):
+ set_module_args(dict(host_name="foo"))
+ commands = ["set system host-name 'foo'"]
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vyos_system_clear_hostname(self):
+ set_module_args(dict(host_name="foo", state="absent"))
+ commands = ["delete system host-name"]
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vyos_remove_single_name_server(self):
+ set_module_args(dict(name_server=["8.8.4.4"], state="absent"))
+ commands = ["delete system name-server '8.8.4.4'"]
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vyos_system_domain_name(self):
+ set_module_args(dict(domain_name="example2.com"))
+ commands = ["set system domain-name 'example2.com'"]
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vyos_system_clear_domain_name(self):
+ set_module_args(dict(domain_name="example.com", state="absent"))
+ commands = ["delete system domain-name"]
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vyos_system_domain_search(self):
+ set_module_args(
+ dict(domain_search=["foo.example.com", "bar.example.com"])
+ )
+ commands = [
+ "set system domain-search domain 'foo.example.com'",
+ "set system domain-search domain 'bar.example.com'",
+ ]
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vyos_system_clear_domain_search(self):
+ set_module_args(dict(domain_search=[]))
+ commands = ["delete system domain-search domain"]
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vyos_system_no_change(self):
+ set_module_args(
+ dict(
+ host_name="router",
+ domain_name="example.com",
+ name_server=["8.8.8.8", "8.8.4.4"],
+ )
+ )
+ result = self.execute_module()
+ self.assertEqual([], result["commands"])
+
+ def test_vyos_system_clear_all(self):
+ set_module_args(dict(state="absent"))
+ commands = [
+ "delete system host-name",
+ "delete system domain-search domain",
+ "delete system domain-name",
+ "delete system name-server",
+ ]
+ self.execute_module(changed=True, commands=commands)
diff --git a/tests/unit/modules/network/vyos/test_vyos_user.py b/tests/unit/modules/network/vyos/test_vyos_user.py
new file mode 100644
index 0000000..d4c2dbe
--- /dev/null
+++ b/tests/unit/modules/network/vyos/test_vyos_user.py
@@ -0,0 +1,139 @@
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+from ansible_collections.vyos.vyos.tests.unit.compat.mock import patch
+from ansible_collections.vyos.vyos.plugins.modules import vyos_user
+from ansible_collections.vyos.vyos.tests.unit.modules.utils import (
+ set_module_args,
+)
+from .vyos_module import TestVyosModule, load_fixture
+
+
+class TestVyosUserModule(TestVyosModule):
+
+ module = vyos_user
+
+ def setUp(self):
+ super(TestVyosUserModule, self).setUp()
+
+ self.mock_get_config = patch(
+ "ansible_collections.vyos.vyos.plugins.modules.vyos_user.get_config"
+ )
+ self.get_config = self.mock_get_config.start()
+
+ self.mock_load_config = patch(
+ "ansible_collections.vyos.vyos.plugins.modules.vyos_user.load_config"
+ )
+ self.load_config = self.mock_load_config.start()
+
+ def tearDown(self):
+ super(TestVyosUserModule, self).tearDown()
+ self.mock_get_config.stop()
+ self.mock_load_config.stop()
+
+ def load_fixtures(self, commands=None, transport="cli"):
+ self.get_config.return_value = load_fixture("vyos_user_config.cfg")
+ self.load_config.return_value = dict(diff=None, session="session")
+
+ def test_vyos_user_password(self):
+ set_module_args(dict(name="ansible", configured_password="test"))
+ result = self.execute_module(changed=True)
+ self.assertEqual(
+ result["commands"],
+ [
+ "set system login user ansible authentication plaintext-password test"
+ ],
+ )
+
+ def test_vyos_user_delete(self):
+ set_module_args(dict(name="ansible", state="absent"))
+ result = self.execute_module(changed=True)
+ self.assertEqual(
+ result["commands"], ["delete system login user ansible"]
+ )
+
+ def test_vyos_user_level(self):
+ set_module_args(dict(name="ansible", level="operator"))
+ result = self.execute_module(changed=True)
+ self.assertEqual(
+ result["commands"],
+ ["set system login user ansible level operator"],
+ )
+
+ def test_vyos_user_level_invalid(self):
+ set_module_args(dict(name="ansible", level="sysadmin"))
+ self.execute_module(failed=True)
+
+ def test_vyos_user_purge(self):
+ set_module_args(dict(purge=True))
+ result = self.execute_module(changed=True)
+ self.assertEqual(
+ sorted(result["commands"]),
+ sorted(
+ [
+ "delete system login user ansible",
+ "delete system login user admin",
+ ]
+ ),
+ )
+
+ def test_vyos_user_update_password_changed(self):
+ set_module_args(
+ dict(
+ name="test",
+ configured_password="test",
+ update_password="on_create",
+ )
+ )
+ result = self.execute_module(changed=True)
+ self.assertEqual(
+ result["commands"],
+ [
+ "set system login user test authentication plaintext-password test"
+ ],
+ )
+
+ def test_vyos_user_update_password_on_create_ok(self):
+ set_module_args(
+ dict(
+ name="ansible",
+ configured_password="test",
+ update_password="on_create",
+ )
+ )
+ self.execute_module()
+
+ def test_vyos_user_update_password_always(self):
+ set_module_args(
+ dict(
+ name="ansible",
+ configured_password="test",
+ update_password="always",
+ )
+ )
+ result = self.execute_module(changed=True)
+ self.assertEqual(
+ result["commands"],
+ [
+ "set system login user ansible authentication plaintext-password test"
+ ],
+ )
diff --git a/tests/unit/modules/network/vyos/vyos_module.py b/tests/unit/modules/network/vyos/vyos_module.py
new file mode 100644
index 0000000..fb15c71
--- /dev/null
+++ b/tests/unit/modules/network/vyos/vyos_module.py
@@ -0,0 +1,104 @@
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+import os
+import json
+
+from ansible_collections.vyos.vyos.tests.unit.modules.utils import (
+ AnsibleExitJson,
+ AnsibleFailJson,
+ ModuleTestCase,
+)
+
+
+fixture_path = os.path.join(os.path.dirname(__file__), "fixtures")
+fixture_data = {}
+
+
+def load_fixture(name):
+ path = os.path.join(fixture_path, name)
+
+ if path in fixture_data:
+ return fixture_data[path]
+
+ with open(path) as f:
+ data = f.read()
+
+ try:
+ data = json.loads(data)
+ except Exception:
+ pass
+
+ fixture_data[path] = data
+ return data
+
+
+class TestVyosModule(ModuleTestCase):
+ def execute_module(
+ self,
+ failed=False,
+ changed=False,
+ commands=None,
+ sort=True,
+ defaults=False,
+ ):
+ self.load_fixtures(commands)
+
+ if failed:
+ result = self.failed()
+ self.assertTrue(result["failed"], result)
+ else:
+ result = self.changed(changed)
+ self.assertEqual(result["changed"], changed, result)
+
+ if commands is not None:
+ if sort:
+ self.assertEqual(
+ sorted(commands),
+ sorted(result["commands"]),
+ result["commands"],
+ )
+ else:
+ self.assertEqual(
+ commands, result["commands"], result["commands"]
+ )
+
+ return result
+
+ def failed(self):
+ with self.assertRaises(AnsibleFailJson) as exc:
+ self.module.main()
+
+ result = exc.exception.args[0]
+ self.assertTrue(result["failed"], result)
+ return result
+
+ def changed(self, changed=False):
+ with self.assertRaises(AnsibleExitJson) as exc:
+ self.module.main()
+
+ result = exc.exception.args[0]
+ self.assertEqual(result["changed"], changed, result)
+ return result
+
+ def load_fixtures(self, commands=None):
+ pass
diff --git a/tests/unit/modules/utils.py b/tests/unit/modules/utils.py
new file mode 100644
index 0000000..2c9c602
--- /dev/null
+++ b/tests/unit/modules/utils.py
@@ -0,0 +1,48 @@
+import json
+
+from ansible_collections.vyos.vyos.tests.unit.compat import unittest
+from ansible_collections.vyos.vyos.tests.unit.compat.mock import patch
+from ansible.module_utils import basic
+from ansible.module_utils._text import to_bytes
+
+
+def set_module_args(args):
+ if "_ansible_remote_tmp" not in args:
+ args["_ansible_remote_tmp"] = "/tmp"
+ if "_ansible_keep_remote_files" not in args:
+ args["_ansible_keep_remote_files"] = False
+
+ args = json.dumps({"ANSIBLE_MODULE_ARGS": args})
+ basic._ANSIBLE_ARGS = to_bytes(args)
+
+
+class AnsibleExitJson(Exception):
+ pass
+
+
+class AnsibleFailJson(Exception):
+ pass
+
+
+def exit_json(*args, **kwargs):
+ if "changed" not in kwargs:
+ kwargs["changed"] = False
+ raise AnsibleExitJson(kwargs)
+
+
+def fail_json(*args, **kwargs):
+ kwargs["failed"] = True
+ raise AnsibleFailJson(kwargs)
+
+
+class ModuleTestCase(unittest.TestCase):
+ def setUp(self):
+ self.mock_module = patch.multiple(
+ basic.AnsibleModule, exit_json=exit_json, fail_json=fail_json
+ )
+ self.mock_module.start()
+ self.mock_sleep = patch("time.sleep")
+ self.mock_sleep.start()
+ set_module_args({})
+ self.addCleanup(self.mock_module.stop)
+ self.addCleanup(self.mock_sleep.stop)
diff --git a/tests/unit/requirements.txt b/tests/unit/requirements.txt
new file mode 100644
index 0000000..a9772be
--- /dev/null
+++ b/tests/unit/requirements.txt
@@ -0,0 +1,42 @@
+boto3
+placebo
+pycrypto
+passlib
+pypsrp
+python-memcached
+pytz
+pyvmomi
+redis
+requests
+setuptools > 0.6 # pytest-xdist installed via requirements does not work with very old setuptools (sanity_ok)
+unittest2 ; python_version < '2.7'
+importlib ; python_version < '2.7'
+netaddr
+ipaddress
+netapp-lib
+solidfire-sdk-python
+
+# requirements for F5 specific modules
+f5-sdk ; python_version >= '2.7'
+f5-icontrol-rest ; python_version >= '2.7'
+deepdiff
+
+# requirement for Fortinet specific modules
+pyFMG
+
+# requirement for aci_rest module
+xmljson
+
+# requirement for winrm connection plugin tests
+pexpect
+
+# requirement for the linode module
+linode-python # APIv3
+linode_api4 ; python_version > '2.6' # APIv4
+
+# requirement for the gitlab module
+python-gitlab
+httmock
+
+# requirment for kubevirt modules
+openshift ; python_version >= '2.7'