summaryrefslogtreecommitdiffstats
path: root/ansible_collections/community/vmware/tests/unit
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 16:03:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 16:03:42 +0000
commit66cec45960ce1d9c794e9399de15c138acb18aed (patch)
tree59cd19d69e9d56b7989b080da7c20ef1a3fe2a5a /ansible_collections/community/vmware/tests/unit
parentInitial commit. (diff)
downloadansible-upstream.tar.xz
ansible-upstream.zip
Adding upstream version 7.3.0+dfsg.upstream/7.3.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/community/vmware/tests/unit')
-rw-r--r--ansible_collections/community/vmware/tests/unit/__init__.py0
-rw-r--r--ansible_collections/community/vmware/tests/unit/compat/__init__.py0
-rw-r--r--ansible_collections/community/vmware/tests/unit/compat/mock.py122
-rw-r--r--ansible_collections/community/vmware/tests/unit/compat/unittest.py38
-rw-r--r--ansible_collections/community/vmware/tests/unit/mock/__init__.py0
-rw-r--r--ansible_collections/community/vmware/tests/unit/mock/loader.py116
-rw-r--r--ansible_collections/community/vmware/tests/unit/mock/path.py11
-rw-r--r--ansible_collections/community/vmware/tests/unit/mock/procenv.py90
-rw-r--r--ansible_collections/community/vmware/tests/unit/mock/vault_helper.py28
-rw-r--r--ansible_collections/community/vmware/tests/unit/mock/yaml_helper.py127
-rw-r--r--ansible_collections/community/vmware/tests/unit/module_utils/__init__.py0
-rw-r--r--ansible_collections/community/vmware/tests/unit/module_utils/conftest.py72
-rw-r--r--ansible_collections/community/vmware/tests/unit/module_utils/test_vmware.py244
-rw-r--r--ansible_collections/community/vmware/tests/unit/modules/__init__.py0
-rw-r--r--ansible_collections/community/vmware/tests/unit/modules/cloud/__init__.py0
-rw-r--r--ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/__init__.py0
-rw-r--r--ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/test_data/test_vmware_guest_with_parameters.json106
-rw-r--r--ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/test_vmware_guest.py52
-rw-r--r--ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/test_vmware_host_sriov.py469
-rw-r--r--ansible_collections/community/vmware/tests/unit/modules/conftest.py31
-rw-r--r--ansible_collections/community/vmware/tests/unit/modules/utils.py53
-rw-r--r--ansible_collections/community/vmware/tests/unit/requirements.txt1
22 files changed, 1560 insertions, 0 deletions
diff --git a/ansible_collections/community/vmware/tests/unit/__init__.py b/ansible_collections/community/vmware/tests/unit/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/__init__.py
diff --git a/ansible_collections/community/vmware/tests/unit/compat/__init__.py b/ansible_collections/community/vmware/tests/unit/compat/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/compat/__init__.py
diff --git a/ansible_collections/community/vmware/tests/unit/compat/mock.py b/ansible_collections/community/vmware/tests/unit/compat/mock.py
new file mode 100644
index 00000000..53b6048d
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/compat/mock.py
@@ -0,0 +1,122 @@
+# (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
+import _io
+
+# 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:
+ 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/ansible_collections/community/vmware/tests/unit/compat/unittest.py b/ansible_collections/community/vmware/tests/unit/compat/unittest.py
new file mode 100644
index 00000000..98f08ad6
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/compat/unittest.py
@@ -0,0 +1,38 @@
+# (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/ansible_collections/community/vmware/tests/unit/mock/__init__.py b/ansible_collections/community/vmware/tests/unit/mock/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/mock/__init__.py
diff --git a/ansible_collections/community/vmware/tests/unit/mock/loader.py b/ansible_collections/community/vmware/tests/unit/mock/loader.py
new file mode 100644
index 00000000..e5dff78c
--- /dev/null
+++ b/ansible_collections/community/vmware/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, file_name):
+ path = to_text(file_name)
+ 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/ansible_collections/community/vmware/tests/unit/mock/path.py b/ansible_collections/community/vmware/tests/unit/mock/path.py
new file mode 100644
index 00000000..37959e5c
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/mock/path.py
@@ -0,0 +1,11 @@
+# Copyright: (c) 2017 Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+from ansible_collections.community.vmware.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/ansible_collections/community/vmware/tests/unit/mock/procenv.py b/ansible_collections/community/vmware/tests/unit/mock/procenv.py
new file mode 100644
index 00000000..30f3b2bf
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/mock/procenv.py
@@ -0,0 +1,90 @@
+# (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.community.vmware.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/ansible_collections/community/vmware/tests/unit/mock/vault_helper.py b/ansible_collections/community/vmware/tests/unit/mock/vault_helper.py
new file mode 100644
index 00000000..10afb639
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/mock/vault_helper.py
@@ -0,0 +1,28 @@
+# Copyright: (c) 2017 Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+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/ansible_collections/community/vmware/tests/unit/mock/yaml_helper.py b/ansible_collections/community/vmware/tests/unit/mock/yaml_helper.py
new file mode 100644
index 00000000..7250393b
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/mock/yaml_helper.py
@@ -0,0 +1,127 @@
+# Copyright: (c) 2017 Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import 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/ansible_collections/community/vmware/tests/unit/module_utils/__init__.py b/ansible_collections/community/vmware/tests/unit/module_utils/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/module_utils/__init__.py
diff --git a/ansible_collections/community/vmware/tests/unit/module_utils/conftest.py b/ansible_collections/community/vmware/tests/unit/module_utils/conftest.py
new file mode 100644
index 00000000..89aecf85
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/module_utils/conftest.py
@@ -0,0 +1,72 @@
+# Copyright (c) 2017 Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import json
+import sys
+from io import BytesIO
+
+import pytest
+
+import ansible.module_utils.basic
+from ansible.module_utils.six import PY3, string_types
+from ansible.module_utils._text import to_bytes
+from ansible.module_utils.common._collections_compat import MutableMapping
+
+
+@pytest.fixture
+def stdin(mocker, request):
+ old_args = ansible.module_utils.basic._ANSIBLE_ARGS
+ ansible.module_utils.basic._ANSIBLE_ARGS = None
+ old_argv = sys.argv
+ sys.argv = ['ansible_unittest']
+
+ 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 stdin pytest fixture')
+
+ fake_stdin = BytesIO(to_bytes(args, errors='surrogate_or_strict'))
+ if PY3:
+ mocker.patch('ansible.module_utils.basic.sys.stdin', mocker.MagicMock())
+ mocker.patch('ansible.module_utils.basic.sys.stdin.buffer', fake_stdin)
+ else:
+ mocker.patch('ansible.module_utils.basic.sys.stdin', fake_stdin)
+
+ yield fake_stdin
+
+ ansible.module_utils.basic._ANSIBLE_ARGS = old_args
+ sys.argv = old_argv
+
+
+@pytest.fixture
+def am(stdin, request):
+ old_args = ansible.module_utils.basic._ANSIBLE_ARGS
+ ansible.module_utils.basic._ANSIBLE_ARGS = None
+ old_argv = sys.argv
+ sys.argv = ['ansible_unittest']
+
+ argspec = {}
+ if hasattr(request, 'param'):
+ if isinstance(request.param, dict):
+ argspec = request.param
+
+ am = ansible.module_utils.basic.AnsibleModule(
+ argument_spec=argspec,
+ )
+ am._name = 'ansible_unittest'
+
+ yield am
+
+ ansible.module_utils.basic._ANSIBLE_ARGS = old_args
+ sys.argv = old_argv
diff --git a/ansible_collections/community/vmware/tests/unit/module_utils/test_vmware.py b/ansible_collections/community/vmware/tests/unit/module_utils/test_vmware.py
new file mode 100644
index 00000000..11483d34
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/module_utils/test_vmware.py
@@ -0,0 +1,244 @@
+# -*- coding: utf-8 -*-
+# Copyright: (c) 2018, Ansible Project
+# Copyright: (c) 2018, Abhijeet Kasurde <akasurde@redhat.com>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import ssl
+import sys
+import pytest
+
+pyvmomi = pytest.importorskip('pyVmomi')
+
+from ansible_collections.community.vmware.tests.unit.compat import mock
+from ansible_collections.community.vmware.plugins.module_utils.vmware import option_diff
+
+import ansible_collections.community.vmware.plugins.module_utils.vmware as vmware_module_utils
+
+
+test_data = [
+ (
+ dict(
+ username='Administrator@vsphere.local',
+ password='Esxi@123$%',
+ hostname=False,
+ validate_certs=False,
+ ),
+ "Hostname parameter is missing. Please specify this parameter in task or"
+ " export environment variable like 'export VMWARE_HOST=ESXI_HOSTNAME'"
+ ),
+ (
+ dict(
+ username=False,
+ password='Esxi@123$%',
+ hostname='esxi1',
+ validate_certs=False,
+ ),
+ "Username parameter is missing. Please specify this parameter in task or"
+ " export environment variable like 'export VMWARE_USER=ESXI_USERNAME'"
+ ),
+ (
+ dict(
+ username='Administrator@vsphere.local',
+ password=False,
+ hostname='esxi1',
+ validate_certs=False,
+ ),
+ "Password parameter is missing. Please specify this parameter in task or"
+ " export environment variable like 'export VMWARE_PASSWORD=ESXI_PASSWORD'"
+ ),
+ (
+ dict(
+ username='Administrator@vsphere.local',
+ password='Esxi@123$%',
+ hostname='esxi1',
+ validate_certs=True,
+ ),
+ "certificate verify failed"
+ ),
+ (
+ dict(
+ username='Administrator@vsphere.local',
+ password='Esxi@123$%',
+ hostname='esxi1',
+ proxy_host='myproxyserver.com',
+ proxy_port=80,
+ validate_certs=False,
+ ),
+ " [proxy: myproxyserver.com:80]"
+ ),
+]
+
+test_ids = [
+ 'hostname',
+ 'username',
+ 'password',
+ 'validate_certs',
+ 'valid_http_proxy',
+]
+
+
+class FailJsonException(BaseException):
+ pass
+
+
+@pytest.fixture
+def fake_ansible_module():
+ ret = mock.Mock()
+ ret.params = test_data[3][0]
+ ret.tmpdir = None
+ ret.fail_json.side_effect = FailJsonException()
+ return ret
+
+
+def fake_connect_to_api(module, return_si=None):
+ return None, mock.Mock()
+
+
+testdata = [
+ ('HAS_PYVMOMI', 'PyVmomi'),
+ ('HAS_REQUESTS', 'requests'),
+]
+
+
+@pytest.mark.parametrize("key,libname", testdata)
+def test_lib_loading_failure(monkeypatch, fake_ansible_module, key, libname):
+ """ Test if Pyvmomi is present or not"""
+ monkeypatch.setattr(vmware_module_utils, key, False)
+ with pytest.raises(FailJsonException):
+ vmware_module_utils.PyVmomi(fake_ansible_module)
+ error_str = 'Failed to import the required Python library (%s)' % libname
+ assert fake_ansible_module.fail_json.called_once()
+ assert error_str in fake_ansible_module.fail_json.call_args[1]['msg']
+
+
+@pytest.mark.skipif(sys.version_info < (2, 7), reason="requires python2.7 and greater")
+@pytest.mark.parametrize("params, msg", test_data, ids=test_ids)
+def test_required_params(request, params, msg, fake_ansible_module):
+ """ Test if required params are correct or not"""
+ fake_ansible_module.params = params
+ with pytest.raises(FailJsonException):
+ vmware_module_utils.connect_to_api(fake_ansible_module)
+ assert fake_ansible_module.fail_json.called_once()
+ # TODO: assert msg in fake_ansible_module.fail_json.call_args[1]['msg']
+
+
+def test_validate_certs(monkeypatch, fake_ansible_module):
+ """ Test if SSL is required or not"""
+ fake_ansible_module.params = test_data[3][0]
+
+ monkeypatch.setattr(vmware_module_utils, 'ssl', mock.Mock())
+ del vmware_module_utils.ssl.SSLContext
+ with pytest.raises(FailJsonException):
+ vmware_module_utils.PyVmomi(fake_ansible_module)
+ msg = 'pyVim does not support changing verification mode with python < 2.7.9.' \
+ ' Either update python or use validate_certs=false.'
+ assert fake_ansible_module.fail_json.called_once()
+ assert msg == fake_ansible_module.fail_json.call_args[1]['msg']
+
+
+def test_vmdk_disk_path_split(monkeypatch, fake_ansible_module):
+ """ Test vmdk_disk_path_split function"""
+ fake_ansible_module.params = test_data[0][0]
+
+ monkeypatch.setattr(vmware_module_utils, 'connect_to_api', fake_connect_to_api)
+ pyv = vmware_module_utils.PyVmomi(fake_ansible_module)
+ v = pyv.vmdk_disk_path_split('[ds1] VM_0001/VM0001_0.vmdk')
+ assert v == ('ds1', 'VM_0001/VM0001_0.vmdk', 'VM0001_0.vmdk', 'VM_0001')
+
+
+def test_vmdk_disk_path_split_negative(monkeypatch, fake_ansible_module):
+ """ Test vmdk_disk_path_split function"""
+ fake_ansible_module.params = test_data[0][0]
+
+ monkeypatch.setattr(vmware_module_utils, 'connect_to_api', fake_connect_to_api)
+ with pytest.raises(FailJsonException):
+ pyv = vmware_module_utils.PyVmomi(fake_ansible_module)
+ pyv.vmdk_disk_path_split('[ds1]')
+ assert fake_ansible_module.fail_json.called_once()
+ assert 'Bad path' in fake_ansible_module.fail_json.call_args[1]['msg']
+
+
+@pytest.mark.skipif(sys.version_info < (2, 7), reason="requires python2.7 and greater")
+def test_connect_to_api_validate_certs(monkeypatch, fake_ansible_module):
+ monkeypatch.setattr(vmware_module_utils, 'connect', mock.Mock())
+
+ def MockSSLContext(proto):
+ ssl_context.proto = proto
+ return ssl_context
+
+ # New Python with SSLContext + validate_certs=True
+ vmware_module_utils.connect.reset_mock()
+ ssl_context = mock.Mock()
+ monkeypatch.setattr(vmware_module_utils.ssl, 'SSLContext', MockSSLContext)
+ fake_ansible_module.params['validate_certs'] = True
+ vmware_module_utils.connect_to_api(fake_ansible_module)
+ assert ssl_context.proto == ssl.PROTOCOL_SSLv23
+ assert ssl_context.verify_mode == ssl.CERT_REQUIRED
+ assert ssl_context.check_hostname is True
+ vmware_module_utils.connect.SmartConnect.assert_called_once_with(
+ host='esxi1',
+ port=443,
+ pwd='Esxi@123$%',
+ user='Administrator@vsphere.local',
+ sslContext=ssl_context)
+
+ # New Python with SSLContext + validate_certs=False
+ vmware_module_utils.connect.reset_mock()
+ ssl_context = mock.Mock()
+ monkeypatch.setattr(vmware_module_utils.ssl, 'SSLContext', MockSSLContext)
+ fake_ansible_module.params['validate_certs'] = False
+ vmware_module_utils.connect_to_api(fake_ansible_module)
+ assert ssl_context.proto == ssl.PROTOCOL_SSLv23
+ assert ssl_context.verify_mode == ssl.CERT_NONE
+ assert ssl_context.check_hostname is False
+ vmware_module_utils.connect.SmartConnect.assert_called_once_with(
+ host='esxi1',
+ port=443,
+ pwd='Esxi@123$%',
+ user='Administrator@vsphere.local',
+ sslContext=ssl_context)
+
+ # Old Python with no SSLContext + validate_certs=True
+ vmware_module_utils.connect.reset_mock()
+ ssl_context = mock.Mock()
+ ssl_context.proto = None
+ monkeypatch.delattr(vmware_module_utils.ssl, 'SSLContext')
+ fake_ansible_module.params['validate_certs'] = True
+ with pytest.raises(FailJsonException):
+ vmware_module_utils.connect_to_api(fake_ansible_module)
+ assert ssl_context.proto is None
+ fake_ansible_module.fail_json.assert_called_once_with(msg=(
+ 'pyVim does not support changing verification mode with python '
+ '< 2.7.9. Either update python or use validate_certs=false.'))
+ assert not vmware_module_utils.connect.SmartConnect.called
+
+ # Old Python with no SSLContext + validate_certs=False
+ vmware_module_utils.connect.reset_mock()
+ ssl_context = mock.Mock()
+ ssl_context.proto = None
+ monkeypatch.delattr(vmware_module_utils.ssl, 'SSLContext', raising=False)
+ fake_ansible_module.params['validate_certs'] = False
+ vmware_module_utils.connect_to_api(fake_ansible_module)
+ assert ssl_context.proto is None
+ vmware_module_utils.connect.SmartConnect.assert_called_once_with(
+ host='esxi1',
+ port=443,
+ pwd='Esxi@123$%',
+ user='Administrator@vsphere.local')
+
+
+@pytest.mark.parametrize("test_options, test_current_options, test_truthy_strings_as_bool", [
+ ({"data": True}, [], True),
+ ({"data": 1}, [], True),
+ ({"data": 1.2}, [], True),
+ ({"data": 'string'}, [], True),
+ ({"data": True}, [], False),
+ ({"data": 1}, [], False),
+ ({"data": 1.2}, [], False),
+ ({"data": 'string'}, [], False),
+])
+def test_option_diff(test_options, test_current_options, test_truthy_strings_as_bool):
+ assert option_diff(test_options, test_current_options, test_truthy_strings_as_bool)[0].value == test_options["data"]
diff --git a/ansible_collections/community/vmware/tests/unit/modules/__init__.py b/ansible_collections/community/vmware/tests/unit/modules/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/modules/__init__.py
diff --git a/ansible_collections/community/vmware/tests/unit/modules/cloud/__init__.py b/ansible_collections/community/vmware/tests/unit/modules/cloud/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/modules/cloud/__init__.py
diff --git a/ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/__init__.py b/ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/__init__.py
diff --git a/ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/test_data/test_vmware_guest_with_parameters.json b/ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/test_data/test_vmware_guest_with_parameters.json
new file mode 100644
index 00000000..ce5e27c7
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/test_data/test_vmware_guest_with_parameters.json
@@ -0,0 +1,106 @@
+[
+ [
+ {
+ "name": "sample_vm_001",
+ "hostname": "esxi01.example.com",
+ "username": "administrator@vsphere.local",
+ "password": "Secret@123$%",
+ "validate_certs": "True"
+ },
+ {
+ "failed": "True",
+ "msg": "Unknown error while connecting to vCenter or ESXi API"
+ }
+ ],
+ [
+ {
+ "name": "sample_vm_001"
+ },
+ {
+ "failed": "True",
+ "msg": "Hostname parameter is missing."
+ }
+ ],
+ [
+ {
+ "uuid": "52f7b088-357e-bb81-59ec-9d9389c7d89e"
+ },
+ {
+ "failed": "True",
+ "msg": "Hostname parameter is missing."
+ }
+ ],
+ [
+ {
+ "name": "sample_vm_001",
+ "hostname": "esxi01.example.com"
+ },
+ {
+ "failed": "True",
+ "msg": "Username parameter is missing."
+ }
+ ],
+ [
+ {
+ "name": "sample_vm_001",
+ "hostname": "esxi01.example.com",
+ "username": "administrator@vsphere.local"
+ },
+ {
+ "failed": "True",
+ "msg": "Password parameter is missing."
+ }
+ ],
+ [
+ {
+ "name": "sample_vm_001",
+ "hostname": "esxi01.example.com",
+ "username": "administrator@vsphere.local",
+ "password": "Secret@123$%"
+ },
+ {
+ "failed": "True",
+ "msg": "Unknown error while connecting to vCenter or ESXi API"
+ }
+ ],
+ [
+ {
+ "name": "sample_vm_001",
+ "hostname": "esxi01.example.com",
+ "username": "administrator@vsphere.local",
+ "password": "Secret@123$%",
+ "validate_certs": "False"
+ },
+ {
+ "failed": "True",
+ "msg": "Unknown error while connecting to vCenter or ESXi API"
+ }
+ ],
+ [
+ {
+ "name": "sample_vm_001",
+ "hostname": "esxi01.example.com",
+ "username": "administrator@vsphere.local",
+ "password": "Secret@123$%",
+ "port": "8443"
+ },
+ {
+ "failed": "True",
+ "msg": "8443"
+ }
+ ],
+ [
+ {
+ "name": "sample_vm_001",
+ "hostname": "esxi01.example.com",
+ "username": "administrator@vsphere.local",
+ "password": "Secret@123$%",
+ "validate_certs": "True"
+ },
+ {
+ "test_ssl_context": "True",
+ "failed": "True",
+ "msg": "pyVim does not support changing verification mode with python < 2.7.9. Either update python or use validate_certs=false."
+ }
+ ]
+]
diff --git a/ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/test_vmware_guest.py b/ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/test_vmware_guest.py
new file mode 100644
index 00000000..29f31b68
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/test_vmware_guest.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright: (c) 2018, Ansible Project
+# Copyright: (c) 2018, Abhijeet Kasurde <akasurde@redhat.com>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import os
+import sys
+import pytest
+import json
+
+pyvmomi = pytest.importorskip('pyVmomi')
+
+if sys.version_info < (2, 7):
+ pytestmark = pytest.mark.skip("vmware_guest Ansible modules require Python >= 2.7")
+
+
+from ansible_collections.community.vmware.plugins.modules import vmware_guest
+
+curr_dir = os.path.dirname(__file__)
+test_data_file = open(os.path.join(curr_dir, 'test_data', 'test_vmware_guest_with_parameters.json'), 'r')
+TEST_CASES = json.loads(test_data_file.read())
+test_data_file.close()
+
+
+@pytest.mark.parametrize('patch_ansible_module', [{}], indirect=['patch_ansible_module'])
+@pytest.mark.usefixtures('patch_ansible_module')
+def test_vmware_guest_wo_parameters(capfd):
+ with pytest.raises(SystemExit):
+ vmware_guest.main()
+ out, err = capfd.readouterr()
+ results = json.loads(out)
+ assert results['failed']
+ assert "one of the following is required: name, uuid" in results['msg']
+
+
+@pytest.mark.parametrize('patch_ansible_module, testcase', TEST_CASES, indirect=['patch_ansible_module'])
+@pytest.mark.usefixtures('patch_ansible_module')
+def test_vmware_guest_with_parameters(mocker, capfd, testcase):
+ if testcase.get('test_ssl_context', None):
+ class mocked_ssl:
+ pass
+ mocker.patch('ansible_collections.community.vmware.plugins.module_utils.vmware.ssl', new=mocked_ssl)
+
+ with pytest.raises(SystemExit):
+ vmware_guest.main()
+ out, err = capfd.readouterr()
+ results = json.loads(out)
+ assert str(results['failed']) == testcase['failed']
+ assert testcase['msg'] in results['msg']
diff --git a/ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/test_vmware_host_sriov.py b/ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/test_vmware_host_sriov.py
new file mode 100644
index 00000000..1d2190db
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/modules/cloud/vmware/test_vmware_host_sriov.py
@@ -0,0 +1,469 @@
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import json
+
+
+try:
+ from unittest import mock
+except ImportError:
+ import mock
+import unittest
+
+from ansible.module_utils import basic
+from ansible.module_utils._text import to_bytes
+
+from ansible_collections.community.vmware.plugins.modules import vmware_host_sriov
+
+
+def gen_mock_attrs(user_input):
+ mock_attrs = dict(user_input)
+ mock_attrs["results"] = {"before": {}, "after": {}, "changes": {}}
+ mock_host = mock.Mock()
+ mock_attrs["hosts"] = [mock_host]
+ return mock_attrs
+
+
+class AnsibleFailJson(Exception):
+ """Exception class to be raised by module.fail_json and caught by the test case"""
+ pass
+
+
+def set_module_args(args):
+ """prepare arguments so that they will be picked up during module creation"""
+ args = json.dumps({"ANSIBLE_MODULE_ARGS": args})
+ basic._ANSIBLE_ARGS = to_bytes(args)
+
+
+class AnsibleExitJson(Exception):
+ """Exception class to be raised by module.exit_json and caught by the test case"""
+ pass
+
+
+def exit_json(*args, **kwargs):
+ """function to patch over exit_json; package return data into an exception"""
+ if "changed" not in kwargs:
+ kwargs["changed"] = False
+ raise AnsibleExitJson(kwargs)
+
+
+def fail_json(*args, **kwargs):
+ """function to patch over fail_json; package return data into an exception"""
+ kwargs["failed"] = True
+ raise AnsibleFailJson(kwargs)
+
+
+def get_bin_path(self, arg, required=False):
+ """Mock AnsibleModule.get_bin_path"""
+ if arg.endswith("my_command"):
+ return "/usr/bin/my_command"
+ else:
+ if required:
+ fail_json(msg="%r not found !" % arg)
+
+
+data_sanitize_params = [
+ # 0. num_virt_func < 0
+ {
+ "user_input": {
+ "hostname": "test_vCenter",
+ "esxi_host_name": "test_host",
+ "sriov_on": True,
+ "num_virt_func": -4,
+ "vmnic": "vmnic0",
+ },
+ "before": {
+ "sriovActive": False,
+ "sriovEnabled": False,
+ "maxVirtualFunctionSupported": 63,
+ "numVirtualFunction": 0,
+ "numVirtualFunctionRequested": 0,
+ "rebootRequired": False,
+ "sriovCapable": True,
+ },
+ "expected": AnsibleFailJson(
+ {"msg": "allowed value for num_virt_func >= 0", "failed": True}
+ ),
+ },
+ # 1. num_virt_func == 0, sriov_on == True
+ {
+ "user_input": {
+ "hostname": "test_vCenter",
+ "esxi_host_name": "test_host",
+ "sriov_on": True,
+ "num_virt_func": 0,
+ "vmnic": "vmnic0",
+ },
+ "before": {
+ "sriovActive": False,
+ "sriovEnabled": False,
+ "maxVirtualFunctionSupported": 63,
+ "numVirtualFunction": 0,
+ "numVirtualFunctionRequested": 0,
+ "rebootRequired": False,
+ "sriovCapable": True,
+ },
+ "expected": AnsibleFailJson(
+ {
+ "msg": "with sriov_on == true, allowed value for num_virt_func > 0",
+ "failed": True,
+ }
+ ),
+ },
+ # 2. num_virt_func > 0, sriov_on == False
+ {
+ "user_input": {
+ "hostname": "test_vCenter",
+ "esxi_host_name": "test_host",
+ "sriov_on": False,
+ "num_virt_func": 5,
+ "vmnic": "vmnic0",
+ },
+ "before": {
+ "sriovActive": False,
+ "sriovEnabled": False,
+ "maxVirtualFunctionSupported": 63,
+ "numVirtualFunction": 0,
+ "numVirtualFunctionRequested": 0,
+ "rebootRequired": False,
+ "sriovCapable": True,
+ },
+ "expected": AnsibleFailJson(
+ {
+ "msg": "with sriov_on == false, allowed value for num_virt_func is 0",
+ "failed": True,
+ }
+ ),
+ },
+ # 3. input OK
+ {
+ "user_input": {
+ "hostname": "test_vCenter",
+ "esxi_host_name": "test_host",
+ "sriov_on": True,
+ "num_virt_func": 8,
+ "vmnic": "vmnic0",
+ },
+ "before": {
+ "sriovActive": False,
+ "sriovEnabled": False,
+ "maxVirtualFunctionSupported": 63,
+ "numVirtualFunction": 0,
+ "numVirtualFunctionRequested": 0,
+ "rebootRequired": False,
+ "sriovCapable": True,
+ },
+ "expected": None,
+ },
+]
+
+data_check_compatibility = [
+ # 0. not supported sriov
+ {
+ "user_input": {
+ "hostname": "test_vCenter",
+ "esxi_host_name": "test_host",
+ "sriov_on": True,
+ "num_virt_func": 8,
+ "vmnic": "vmnic0",
+ },
+ "before": {
+ "sriovActive": False,
+ "sriovEnabled": False,
+ "maxVirtualFunctionSupported": 0,
+ "numVirtualFunction": 0,
+ "numVirtualFunctionRequested": 0,
+ "rebootRequired": False,
+ "sriovCapable": False,
+ },
+ "expected": AnsibleFailJson(
+ {
+ "msg": "sriov not supported on host= test_host, nic= vmnic0",
+ "failed": True,
+ }
+ ),
+ },
+ # 1. not supported num_virt_func
+ {
+ "user_input": {
+ "hostname": "test_vCenter",
+ "esxi_host_name": "test_host",
+ "sriov_on": True,
+ "num_virt_func": 8,
+ "vmnic": "vmnic0",
+ },
+ "before": {
+ "sriovActive": False,
+ "sriovEnabled": False,
+ "maxVirtualFunctionSupported": 4,
+ "numVirtualFunction": 0,
+ "numVirtualFunctionRequested": 0,
+ "rebootRequired": False,
+ "sriovCapable": True,
+ },
+ "expected": AnsibleFailJson(
+ {"msg": "maxVirtualFunctionSupported= 4 on vmnic0", "failed": True}
+ ),
+ },
+ # 2. normal enabling
+ {
+ "user_input": {
+ "hostname": "test_vCenter",
+ "esxi_host_name": "test_host",
+ "sriov_on": True,
+ "num_virt_func": 8,
+ "vmnic": "vmnic0",
+ },
+ "before": {
+ "sriovActive": False,
+ "sriovEnabled": False,
+ "maxVirtualFunctionSupported": 63,
+ "numVirtualFunction": 0,
+ "numVirtualFunctionRequested": 0,
+ "rebootRequired": False,
+ "sriovCapable": True,
+ },
+ "expected": None,
+ },
+ # 3. disable sriov
+ {
+ "user_input": {
+ "hostname": "test_vCenter",
+ "esxi_host_name": "test_host",
+ "sriov_on": False,
+ "num_virt_func": 0,
+ "vmnic": "vmnic0",
+ },
+ "before": {
+ "sriovActive": True,
+ "sriovEnabled": True,
+ "maxVirtualFunctionSupported": 63,
+ "numVirtualFunction": 8,
+ "numVirtualFunctionRequested": 8,
+ "rebootRequired": False,
+ "sriovCapable": True,
+ },
+ "expected": None,
+ },
+]
+
+data_make_diff = [
+ # 0. normal enabling
+ {
+ "user_input": {
+ "hostname": "test_vCenter",
+ "esxi_host_name": "test_host",
+ "sriov_on": True,
+ "num_virt_func": 8,
+ "vmnic": "vmnic0",
+ },
+ "before": {
+ "sriovActive": False,
+ "sriovEnabled": False,
+ "maxVirtualFunctionSupported": 63,
+ "numVirtualFunction": 0,
+ "numVirtualFunctionRequested": 0,
+ "rebootRequired": False,
+ "sriovCapable": True,
+ },
+ "expected": {
+ "sriovEnabled": True,
+ "numVirtualFunction": 8,
+ "msg": "",
+ "change": True,
+ },
+ },
+ # 1. already enabled, not active
+ {
+ "user_input": {
+ "hostname": "test_vCenter",
+ "esxi_host_name": "test_host",
+ "sriov_on": True,
+ "num_virt_func": 8,
+ "vmnic": "vmnic0",
+ },
+ "before": {
+ "sriovActive": False,
+ "sriovEnabled": True,
+ "maxVirtualFunctionSupported": 63,
+ "numVirtualFunction": 0,
+ "numVirtualFunctionRequested": 8,
+ "rebootRequired": True,
+ "sriovCapable": True,
+ },
+ "expected": {
+ "msg": "Not active (looks like not rebooted) No any changes, already configured ",
+ "change": False,
+ },
+ },
+ # 2. already enabled and active
+ {
+ "user_input": {
+ "hostname": "test_vCenter",
+ "esxi_host_name": "test_host",
+ "sriov_on": True,
+ "num_virt_func": 8,
+ "vmnic": "vmnic0",
+ },
+ "before": {
+ "sriovActive": True,
+ "sriovEnabled": True,
+ "maxVirtualFunctionSupported": 63,
+ "numVirtualFunction": 8,
+ "numVirtualFunctionRequested": 8,
+ "rebootRequired": False,
+ "sriovCapable": True,
+ },
+ "expected": {"msg": "No any changes, already configured ", "change": False},
+ },
+ # 3. already enabled diff in numVirtualFunction
+ {
+ "user_input": {
+ "hostname": "test_vCenter",
+ "esxi_host_name": "test_host",
+ "sriov_on": True,
+ "num_virt_func": 8,
+ "vmnic": "vmnic0",
+ },
+ "before": {
+ "sriovActive": True,
+ "sriovEnabled": True,
+ "maxVirtualFunctionSupported": 63,
+ "numVirtualFunction": 4,
+ "numVirtualFunctionRequested": 4,
+ "rebootRequired": False,
+ "sriovCapable": True,
+ },
+ "expected": {"numVirtualFunction": 8, "msg": "", "change": True},
+ },
+ # 4. disable sriov
+ {
+ "user_input": {
+ "hostname": "test_vCenter",
+ "esxi_host_name": "test_host",
+ "sriov_on": False,
+ "num_virt_func": 0,
+ "vmnic": "vmnic0",
+ },
+ "before": {
+ "sriovActive": True,
+ "sriovEnabled": True,
+ "maxVirtualFunctionSupported": 63,
+ "numVirtualFunction": 8,
+ "numVirtualFunctionRequested": 8,
+ "rebootRequired": False,
+ "sriovCapable": True,
+ },
+ "expected": {
+ "sriovEnabled": False,
+ "numVirtualFunction": 0,
+ "msg": "",
+ "change": True,
+ },
+ },
+]
+
+
+class TestAdapterMethods(unittest.TestCase):
+ def setUp(self):
+ pass
+
+ def tearDown(self):
+ pass
+
+ @mock.patch.object(
+ vmware_host_sriov.VmwareAdapterConfigManager, "__init__", return_value=None
+ )
+ def test_sanitize_params(self, mock__init__):
+ for num, case in enumerate(data_sanitize_params):
+ config = vmware_host_sriov.VmwareAdapterConfigManager()
+ config.module = mock.Mock()
+ config.module.check_mode = False
+ config.module.fail_json.side_effect = fail_json
+
+ config.__dict__.update(gen_mock_attrs(case["user_input"]))
+
+ try:
+ result = config.sanitize_params()
+ self.assertIsInstance(
+ result, type(case["expected"]), "test=" + str(num)
+ )
+ self.assertEqual(result, case["expected"], "test=" + str(num))
+
+ except Exception as e:
+ self.assertIsInstance(e, type(case["expected"]), "test=" + str(num))
+ self.assertEqual(
+ e.args[0], case["expected"].args[0], "test=" + str(num)
+ )
+
+ @mock.patch.object(
+ vmware_host_sriov.VmwareAdapterConfigManager, "__init__", return_value=None
+ )
+ def test_check_compatibility(self, mock__init__):
+ for num, case in enumerate(data_check_compatibility):
+ config = vmware_host_sriov.VmwareAdapterConfigManager()
+ config.module = mock.Mock()
+ config.module.check_mode = False
+ config.module.fail_json.side_effect = fail_json
+
+ config.__dict__.update(gen_mock_attrs(case["user_input"]))
+
+ try:
+ result = config.check_compatibility(
+ case["before"], case["user_input"]["esxi_host_name"]
+ )
+ self.assertIsInstance(
+ result, type(case["expected"]), "test=" + str(num)
+ )
+ self.assertEqual(result, case["expected"], "test=" + str(num))
+
+ except Exception as e:
+ self.assertIsInstance(e, type(case["expected"]), "test=" + str(num))
+ self.assertEqual(
+ e.args[0], case["expected"].args[0], "test=" + str(num)
+ )
+
+ for num, case in enumerate(data_check_compatibility):
+ config = vmware_host_sriov.VmwareAdapterConfigManager()
+ config.module = mock.Mock()
+ config.module.check_mode = False
+ config.module.fail_json.side_effect = fail_json
+
+ config.__dict__.update(gen_mock_attrs(case["user_input"]))
+
+ try:
+ result = config.check_compatibility(
+ case["before"], case["user_input"]["esxi_host_name"]
+ )
+ self.assertIsInstance(
+ result, type(case["expected"]), "test=" + str(num)
+ )
+ self.assertEqual(result, case["expected"], "test=" + str(num))
+
+ except Exception as e:
+ self.assertIsInstance(e, type(case["expected"]), "test=" + str(num))
+ self.assertEqual(
+ e.args[0], case["expected"].args[0], "test=" + str(num)
+ )
+
+ @mock.patch.object(
+ vmware_host_sriov.VmwareAdapterConfigManager, "__init__", return_value=None
+ )
+ def test_make_diff(self, mock__init__):
+ for num, case in enumerate(data_make_diff):
+ config = vmware_host_sriov.VmwareAdapterConfigManager()
+ config.module = mock.Mock()
+ config.module.check_mode = False
+ config.module.fail_json.side_effect = fail_json
+
+ config.__dict__.update(gen_mock_attrs(case["user_input"]))
+
+ result = config.make_diff(
+ case["before"], case["user_input"]["esxi_host_name"]
+ )
+ self.assertIsInstance(result, type(case["expected"]), "test=" + str(num))
+ self.assertEqual(result, case["expected"], "test=" + str(num))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/ansible_collections/community/vmware/tests/unit/modules/conftest.py b/ansible_collections/community/vmware/tests/unit/modules/conftest.py
new file mode 100644
index 00000000..d2f7f4b5
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/modules/conftest.py
@@ -0,0 +1,31 @@
+# Copyright (c) 2017 Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import 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/ansible_collections/community/vmware/tests/unit/modules/utils.py b/ansible_collections/community/vmware/tests/unit/modules/utils.py
new file mode 100644
index 00000000..001d6c16
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/modules/utils.py
@@ -0,0 +1,53 @@
+# Copyright: (c) 2020 Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import json
+
+from ansible_collections.community.vmware.tests.unit.compat import unittest
+from ansible_collections.community.vmware.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/ansible_collections/community/vmware/tests/unit/requirements.txt b/ansible_collections/community/vmware/tests/unit/requirements.txt
new file mode 100644
index 00000000..6f750903
--- /dev/null
+++ b/ansible_collections/community/vmware/tests/unit/requirements.txt
@@ -0,0 +1 @@
+pyvmomi