diff options
author | Lee Garrett <lgarrett@rocketjump.eu> | 2022-06-13 23:13:57 +0200 |
---|---|---|
committer | Lee Garrett <lgarrett@rocketjump.eu> | 2022-06-13 23:13:57 +0200 |
commit | df2a2cd18c338647061f3448248f8b97b6971f49 (patch) | |
tree | f223b6b9084be551de18fdb4fe0d596c68a9cebc /test/units | |
parent | 71ed02a1e802462d5d9b5f7e0fad42307a175278 (diff) | |
download | debian-ansible-core-df2a2cd18c338647061f3448248f8b97b6971f49.zip |
New upstream version 2.13.0
Diffstat (limited to 'test/units')
107 files changed, 1331 insertions, 716 deletions
diff --git a/test/units/_vendor/test_vendor.py b/test/units/_vendor/test_vendor.py index fa9fdb25..cda0279d 100644 --- a/test/units/_vendor/test_vendor.py +++ b/test/units/_vendor/test_vendor.py @@ -9,7 +9,7 @@ import pkgutil import pytest import sys -from units.compat.mock import MagicMock, NonCallableMagicMock, patch +from mock import MagicMock, NonCallableMagicMock, patch def reset_internal_vendor_package(): diff --git a/test/units/cli/galaxy/test_display_collection.py b/test/units/cli/galaxy/test_display_collection.py index b1266124..c86227b0 100644 --- a/test/units/cli/galaxy/test_display_collection.py +++ b/test/units/cli/galaxy/test_display_collection.py @@ -14,7 +14,7 @@ from ansible.galaxy.dependency_resolution.dataclasses import Requirement @pytest.fixture def collection_object(): def _cobj(fqcn='sandwiches.ham'): - return Requirement(fqcn, '1.5.0', None, 'galaxy') + return Requirement(fqcn, '1.5.0', None, 'galaxy', None) return _cobj diff --git a/test/units/cli/galaxy/test_execute_list_collection.py b/test/units/cli/galaxy/test_execute_list_collection.py index acd865b5..e8a834d9 100644 --- a/test/units/cli/galaxy/test_execute_list_collection.py +++ b/test/units/cli/galaxy/test_execute_list_collection.py @@ -57,12 +57,14 @@ def mock_collection_objects(mocker): '1.5.0', None, 'dir', + None, ), ( 'sandwiches.reuben', '2.5.0', None, 'dir', + None, ), ) @@ -72,12 +74,14 @@ def mock_collection_objects(mocker): '1.0.0', None, 'dir', + None, ), ( 'sandwiches.ham', '1.0.0', None, 'dir', + None, ), ) @@ -97,12 +101,14 @@ def mock_from_path(mocker): '1.5.0', None, 'dir', + None, ), ( 'sandwiches.pbj', '1.0.0', None, 'dir', + None, ), ), 'sandwiches.ham': ( @@ -111,6 +117,7 @@ def mock_from_path(mocker): '1.0.0', None, 'dir', + None, ), ), } diff --git a/test/units/cli/galaxy/test_get_collection_widths.py b/test/units/cli/galaxy/test_get_collection_widths.py index 67b20926..6e1cbf5e 100644 --- a/test/units/cli/galaxy/test_get_collection_widths.py +++ b/test/units/cli/galaxy/test_get_collection_widths.py @@ -13,11 +13,11 @@ from ansible.galaxy.dependency_resolution.dataclasses import Requirement @pytest.fixture def collection_objects(): - collection_ham = Requirement('sandwiches.ham', '1.5.0', None, 'galaxy') + collection_ham = Requirement('sandwiches.ham', '1.5.0', None, 'galaxy', None) - collection_pbj = Requirement('sandwiches.pbj', '2.5', None, 'galaxy') + collection_pbj = Requirement('sandwiches.pbj', '2.5', None, 'galaxy', None) - collection_reuben = Requirement('sandwiches.reuben', '4', None, 'galaxy') + collection_reuben = Requirement('sandwiches.reuben', '4', None, 'galaxy', None) return [collection_ham, collection_pbj, collection_reuben] @@ -27,7 +27,7 @@ def test_get_collection_widths(collection_objects): def test_get_collection_widths_single_collection(mocker): - mocked_collection = Requirement('sandwiches.club', '3.0.0', None, 'galaxy') + mocked_collection = Requirement('sandwiches.club', '3.0.0', None, 'galaxy', None) # Make this look like it is not iterable mocker.patch('ansible.cli.galaxy.is_iterable', return_value=False) diff --git a/test/units/cli/test_cli.py b/test/units/cli/test_cli.py index 09445a25..26285955 100644 --- a/test/units/cli/test_cli.py +++ b/test/units/cli/test_cli.py @@ -20,7 +20,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type from units.compat import unittest -from units.compat.mock import patch, MagicMock +from mock import patch, MagicMock from units.mock.loader import DictDataLoader diff --git a/test/units/cli/test_console.py b/test/units/cli/test_console.py index 3acc4faa..fb477bf3 100644 --- a/test/units/cli/test_console.py +++ b/test/units/cli/test_console.py @@ -20,7 +20,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type from units.compat import unittest -from units.compat.mock import patch +from mock import patch from ansible.cli.console import ConsoleCLI diff --git a/test/units/cli/test_doc.py b/test/units/cli/test_doc.py index 5cdf974b..576bdb28 100644 --- a/test/units/cli/test_doc.py +++ b/test/units/cli/test_doc.py @@ -5,6 +5,7 @@ __metaclass__ = type import pytest from ansible.cli.doc import DocCLI, RoleMixin +from ansible.plugins.loader import module_loader TTY_IFY_DATA = { @@ -111,3 +112,19 @@ def test_rolemixin__build_doc_no_filter_match(): fqcn, doc = obj._build_doc(role_name, path, collection_name, argspec, entrypoint_filter) assert fqcn == '.'.join([collection_name, role_name]) assert doc is None + + +def test_builtin_modules_list(): + args = ['ansible-doc', '-l', 'ansible.builtin', '-t', 'module'] + obj = DocCLI(args=args) + obj.parse() + result = obj._list_plugins('module', module_loader) + assert len(result) > 0 + + +def test_legacy_modules_list(): + args = ['ansible-doc', '-l', 'ansible.legacy', '-t', 'module'] + obj = DocCLI(args=args) + obj.parse() + result = obj._list_plugins('module', module_loader) + assert len(result) > 0 diff --git a/test/units/cli/test_galaxy.py b/test/units/cli/test_galaxy.py index 804e1345..1a6bfe04 100644 --- a/test/units/cli/test_galaxy.py +++ b/test/units/cli/test_galaxy.py @@ -41,7 +41,7 @@ from ansible.module_utils._text import to_bytes, to_native, to_text from ansible.utils import context_objects as co from ansible.utils.display import Display from units.compat import unittest -from units.compat.mock import patch, MagicMock +from mock import patch, MagicMock @pytest.fixture(autouse='function') @@ -462,13 +462,7 @@ class TestGalaxyInitSkeleton(unittest.TestCase, ValidRoleTests): @pytest.mark.parametrize('cli_args, expected', [ (['ansible-galaxy', 'collection', 'init', 'abc._def'], 0), (['ansible-galaxy', 'collection', 'init', 'abc._def', '-vvv'], 3), - (['ansible-galaxy', '-vv', 'collection', 'init', 'abc._def'], 2), - # Due to our manual parsing we want to verify that -v set in the sub parser takes precedence. This behaviour is - # deprecated and tests should be removed when the code that handles it is removed - (['ansible-galaxy', '-vv', 'collection', 'init', 'abc._def', '-v'], 1), - (['ansible-galaxy', '-vv', 'collection', 'init', 'abc._def', '-vvvv'], 4), - (['ansible-galaxy', '-vvv', 'init', 'name'], 3), - (['ansible-galaxy', '-vvvvv', 'init', '-v', 'name'], 1), + (['ansible-galaxy', 'collection', 'init', 'abc._def', '-vv'], 2), ]) def test_verbosity_arguments(cli_args, expected, monkeypatch): # Mock out the functions so we don't actually execute anything diff --git a/test/units/cli/test_vault.py b/test/units/cli/test_vault.py index bb244a5a..76ffba2f 100644 --- a/test/units/cli/test_vault.py +++ b/test/units/cli/test_vault.py @@ -24,7 +24,7 @@ import os import pytest from units.compat import unittest -from units.compat.mock import patch, MagicMock +from mock import patch, MagicMock from units.mock.vault_helper import TextVaultSecret from ansible import context, errors @@ -70,18 +70,18 @@ class TestVaultCli(unittest.TestCase): mock_setup_vault_secrets.return_value = [] cli = VaultCLI(args=['ansible-vault', 'view', '/dev/null/foo']) cli.parse() - self.assertRaisesRegexp(errors.AnsibleOptionsError, - "A vault password is required to use Ansible's Vault", - cli.run) + self.assertRaisesRegex(errors.AnsibleOptionsError, + "A vault password is required to use Ansible's Vault", + cli.run) @patch('ansible.cli.vault.VaultCLI.setup_vault_secrets') def test_encrypt_missing_file_no_secret(self, mock_setup_vault_secrets): mock_setup_vault_secrets.return_value = [] cli = VaultCLI(args=['ansible-vault', 'encrypt', '/dev/null/foo']) cli.parse() - self.assertRaisesRegexp(errors.AnsibleOptionsError, - "A vault password is required to use Ansible's Vault", - cli.run) + self.assertRaisesRegex(errors.AnsibleOptionsError, + "A vault password is required to use Ansible's Vault", + cli.run) @patch('ansible.cli.vault.VaultCLI.setup_vault_secrets') @patch('ansible.cli.vault.VaultEditor') @@ -209,11 +209,7 @@ class TestVaultCli(unittest.TestCase): @pytest.mark.parametrize('cli_args, expected', [ (['ansible-vault', 'view', 'vault.txt'], 0), (['ansible-vault', 'view', 'vault.txt', '-vvv'], 3), - (['ansible-vault', '-vv', 'view', 'vault.txt'], 2), - # Due to our manual parsing we want to verify that -v set in the sub parser takes precedence. This behaviour is - # deprecated and tests should be removed when the code that handles it is removed - (['ansible-vault', '-vv', 'view', 'vault.txt', '-v'], 1), - (['ansible-vault', '-vv', 'view', 'vault.txt', '-vvvv'], 4), + (['ansible-vault', 'view', 'vault.txt', '-vv'], 2), ]) def test_verbosity_arguments(cli_args, expected, tmp_path_factory, monkeypatch): # Add a password file so we don't get a prompt in the test diff --git a/test/units/compat/builtins.py b/test/units/compat/builtins.py deleted file mode 100644 index f60ee678..00000000 --- a/test/units/compat/builtins.py +++ /dev/null @@ -1,33 +0,0 @@ -# (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/test/units/compat/mock.py b/test/units/compat/mock.py deleted file mode 100644 index 0972cd2e..00000000 --- a/test/units/compat/mock.py +++ /dev/null @@ -1,122 +0,0 @@ -# (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/test/units/compat/unittest.py b/test/units/compat/unittest.py index 98f08ad6..77bb4c05 100644 --- a/test/units/compat/unittest.py +++ b/test/units/compat/unittest.py @@ -36,3 +36,7 @@ if sys.version_info < (2, 7): print('You need unittest2 installed on python2.6.x to run tests') else: from unittest import * + + if not hasattr(TestCase, 'assertRaisesRegex'): + # added in Python 3.2 + TestCase.assertRaisesRegex = TestCase.assertRaisesRegexp diff --git a/test/units/errors/test_errors.py b/test/units/errors/test_errors.py index 136a2695..deb3dc0b 100644 --- a/test/units/errors/test_errors.py +++ b/test/units/errors/test_errors.py @@ -21,8 +21,7 @@ __metaclass__ = type from units.compat import unittest -from units.compat.builtins import BUILTINS -from units.compat.mock import mock_open, patch +from mock import mock_open, patch from ansible.errors import AnsibleError from ansible.parsing.yaml.objects import AnsibleBaseYAMLObject @@ -87,7 +86,7 @@ class TestErrors(unittest.TestCase): m = mock_open() m.return_value.readlines.return_value = ['this is line 1\n'] - with patch('{0}.open'.format(BUILTINS), m): + with patch('builtins.open', m): # this line will be found in the file self.obj.ansible_pos = ('foo.yml', 1, 1) e = AnsibleError(self.message, self.obj) @@ -110,7 +109,7 @@ class TestErrors(unittest.TestCase): m = mock_open() m.return_value.readlines.return_value = ['this line has unicode \xf0\x9f\x98\xa8 in it!\n'] - with patch('{0}.open'.format(BUILTINS), m): + with patch('builtins.open', m): # this line will be found in the file self.obj.ansible_pos = ('foo.yml', 1, 1) e = AnsibleError(self.unicode_message, self.obj) @@ -125,7 +124,7 @@ class TestErrors(unittest.TestCase): m = mock_open() m.return_value.readlines.return_value = ['this is line 1\n', 'this is line 2\n', 'this is line 3\n'] - with patch('{0}.open'.format(BUILTINS), m): + with patch('builtins.open', m): # If the error occurs in the last line of the file, use the correct index to get the line # and avoid the IndexError self.obj.ansible_pos = ('foo.yml', 4, 1) @@ -141,7 +140,7 @@ class TestErrors(unittest.TestCase): m = mock_open() m.return_value.readlines.return_value = ['this is line 1\n', 'this is line 2\n', 'this is line 3\n', ' \n', ' \n', ' '] - with patch('{0}.open'.format(BUILTINS), m): + with patch('builtins.open', m): self.obj.ansible_pos = ('foo.yml', 5, 1) e = AnsibleError(self.message, self.obj) self.assertEqual( diff --git a/test/units/executor/module_common/test_module_common.py b/test/units/executor/module_common/test_module_common.py index 04bae85d..fa6add8c 100644 --- a/test/units/executor/module_common/test_module_common.py +++ b/test/units/executor/module_common/test_module_common.py @@ -113,8 +113,11 @@ class TestGetShebang: with pytest.raises(InterpreterDiscoveryRequiredError): amc._get_shebang(u'/usr/bin/python', {}, templar) + def test_python_interpreter(self, templar): + assert amc._get_shebang(u'/usr/bin/python3.8', {}, templar) == ('#!/usr/bin/python3.8', u'/usr/bin/python3.8') + def test_non_python_interpreter(self, templar): - assert amc._get_shebang(u'/usr/bin/ruby', {}, templar) == (None, u'/usr/bin/ruby') + assert amc._get_shebang(u'/usr/bin/ruby', {}, templar) == ('#!/usr/bin/ruby', u'/usr/bin/ruby') def test_interpreter_set_in_task_vars(self, templar): assert amc._get_shebang(u'/usr/bin/python', {u'ansible_python_interpreter': u'/usr/bin/pypy'}, templar) == \ diff --git a/test/units/executor/test_interpreter_discovery.py b/test/units/executor/test_interpreter_discovery.py index 5919d39f..5efdd378 100644 --- a/test/units/executor/test_interpreter_discovery.py +++ b/test/units/executor/test_interpreter_discovery.py @@ -6,7 +6,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -from units.compat.mock import MagicMock +from mock import MagicMock from ansible.executor.interpreter_discovery import discover_interpreter from ansible.module_utils._text import to_text diff --git a/test/units/executor/test_play_iterator.py b/test/units/executor/test_play_iterator.py index 395ab686..3ced9e3c 100644 --- a/test/units/executor/test_play_iterator.py +++ b/test/units/executor/test_play_iterator.py @@ -20,9 +20,9 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type from units.compat import unittest -from units.compat.mock import patch, MagicMock +from mock import patch, MagicMock -from ansible.executor.play_iterator import HostState, PlayIterator +from ansible.executor.play_iterator import HostState, PlayIterator, IteratingStates, FailedStates from ansible.playbook import Playbook from ansible.playbook.play_context import PlayContext @@ -51,7 +51,6 @@ class TestPlayIterator(unittest.TestCase): @patch('ansible.playbook.role.definition.unfrackpath', mock_unfrackpath_noop) def test_play_iterator(self): - # import epdb; epdb.st() fake_loader = DictDataLoader({ "test_play.yml": """ - hosts: all @@ -429,7 +428,7 @@ class TestPlayIterator(unittest.TestCase): # iterate past first task _, task = itr.get_next_task_for_host(hosts[0]) - while(task and task.action != 'debug'): + while (task and task.action != 'debug'): _, task = itr.get_next_task_for_host(hosts[0]) if task is None: @@ -443,21 +442,51 @@ class TestPlayIterator(unittest.TestCase): res_state = itr._insert_tasks_into_state(s_copy, task_list=[]) self.assertEqual(res_state, s_copy) - s_copy.fail_state = itr.FAILED_TASKS + s_copy.fail_state = FailedStates.TASKS res_state = itr._insert_tasks_into_state(s_copy, task_list=[MagicMock()]) self.assertEqual(res_state, s_copy) # but if we've failed with a rescue/always block mock_task = MagicMock() - s_copy.run_state = itr.ITERATING_RESCUE + s_copy.run_state = IteratingStates.RESCUE res_state = itr._insert_tasks_into_state(s_copy, task_list=[mock_task]) self.assertEqual(res_state, s_copy) self.assertIn(mock_task, res_state._blocks[res_state.cur_block].rescue) - itr._host_states[hosts[0].name] = res_state + itr.set_state_for_host(hosts[0].name, res_state) (next_state, next_task) = itr.get_next_task_for_host(hosts[0], peek=True) self.assertEqual(next_task, mock_task) - itr._host_states[hosts[0].name] = s + itr.set_state_for_host(hosts[0].name, s) # test a regular insertion s_copy = s.copy() res_state = itr._insert_tasks_into_state(s_copy, task_list=[MagicMock()]) + + def test_iterating_states_deprecation_class_attr(self): + assert PlayIterator.ITERATING_SETUP == IteratingStates.SETUP + assert PlayIterator.ITERATING_TASKS == IteratingStates.TASKS + assert PlayIterator.ITERATING_RESCUE == IteratingStates.RESCUE + assert PlayIterator.ITERATING_ALWAYS == IteratingStates.ALWAYS + assert PlayIterator.ITERATING_COMPLETE == IteratingStates.COMPLETE + + def test_failed_states_deprecation_class_attr(self): + assert PlayIterator.FAILED_NONE == FailedStates.NONE + assert PlayIterator.FAILED_SETUP == FailedStates.SETUP + assert PlayIterator.FAILED_TASKS == FailedStates.TASKS + assert PlayIterator.FAILED_RESCUE == FailedStates.RESCUE + assert PlayIterator.FAILED_ALWAYS == FailedStates.ALWAYS + + def test_iterating_states_deprecation_instance_attr(self): + iterator = PlayIterator(MagicMock(), MagicMock(), MagicMock(), MagicMock(), MagicMock()) + assert iterator.ITERATING_SETUP == IteratingStates.SETUP + assert iterator.ITERATING_TASKS == IteratingStates.TASKS + assert iterator.ITERATING_RESCUE == IteratingStates.RESCUE + assert iterator.ITERATING_ALWAYS == IteratingStates.ALWAYS + assert iterator.ITERATING_COMPLETE == IteratingStates.COMPLETE + + def test_failed_states_deprecation_instance_attr(self): + iterator = PlayIterator(MagicMock(), MagicMock(), MagicMock(), MagicMock(), MagicMock()) + assert iterator.FAILED_NONE == FailedStates.NONE + assert iterator.FAILED_SETUP == FailedStates.SETUP + assert iterator.FAILED_TASKS == FailedStates.TASKS + assert iterator.FAILED_RESCUE == FailedStates.RESCUE + assert iterator.FAILED_ALWAYS == FailedStates.ALWAYS diff --git a/test/units/executor/test_playbook_executor.py b/test/units/executor/test_playbook_executor.py index 529eda36..350f7c2d 100644 --- a/test/units/executor/test_playbook_executor.py +++ b/test/units/executor/test_playbook_executor.py @@ -20,7 +20,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type from units.compat import unittest -from units.compat.mock import MagicMock +from mock import MagicMock from ansible.executor.playbook_executor import PlaybookExecutor from ansible.playbook import Playbook diff --git a/test/units/executor/test_task_executor.py b/test/units/executor/test_task_executor.py index 8c01b339..30d609a1 100644 --- a/test/units/executor/test_task_executor.py +++ b/test/units/executor/test_task_executor.py @@ -22,7 +22,7 @@ __metaclass__ = type import mock from units.compat import unittest -from units.compat.mock import patch, MagicMock +from mock import patch, MagicMock from ansible.errors import AnsibleError from ansible.executor.task_executor import TaskExecutor, remove_omit from ansible.plugins.loader import action_loader, lookup_loader diff --git a/test/units/executor/test_task_queue_manager_callbacks.py b/test/units/executor/test_task_queue_manager_callbacks.py index 6c0ceee0..b6b1159d 100644 --- a/test/units/executor/test_task_queue_manager_callbacks.py +++ b/test/units/executor/test_task_queue_manager_callbacks.py @@ -19,7 +19,7 @@ from __future__ import (absolute_import, division, print_function) from units.compat import unittest -from units.compat.mock import MagicMock +from mock import MagicMock from ansible.executor.task_queue_manager import TaskQueueManager from ansible.playbook import Playbook diff --git a/test/units/executor/test_task_result.py b/test/units/executor/test_task_result.py index 3ce210de..ee5c7198 100644 --- a/test/units/executor/test_task_result.py +++ b/test/units/executor/test_task_result.py @@ -20,7 +20,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type from units.compat import unittest -from units.compat.mock import patch, MagicMock +from mock import patch, MagicMock from ansible.executor.task_result import TaskResult diff --git a/test/units/galaxy/test_api.py b/test/units/galaxy/test_api.py index 8081c792..733f99b5 100644 --- a/test/units/galaxy/test_api.py +++ b/test/units/galaxy/test_api.py @@ -16,7 +16,7 @@ import tempfile import time from io import BytesIO, StringIO -from units.compat.mock import MagicMock +from mock import MagicMock import ansible.constants as C from ansible import context @@ -509,15 +509,15 @@ def test_wait_import_task_with_failure(server_url, api_version, token_type, toke }, 'messages': [ { - 'level': 'error', + 'level': 'ERrOR', 'message': u'Somé error', }, { - 'level': 'warning', + 'level': 'WARNiNG', 'message': u'Some wärning', }, { - 'level': 'info', + 'level': 'INFO', 'message': u'Somé info', }, ], @@ -549,7 +549,7 @@ def test_wait_import_task_with_failure(server_url, api_version, token_type, toke assert mock_display.mock_calls[0][1][0] == 'Waiting until Galaxy import task %s has completed' % full_import_uri assert mock_vvv.call_count == 1 - assert mock_vvv.mock_calls[0][1][0] == u'Galaxy import message: info - Somé info' + assert mock_vvv.mock_calls[0][1][0] == u'Galaxy import message: INFO - Somé info' assert mock_warn.call_count == 1 assert mock_warn.mock_calls[0][1][0] == u'Galaxy import warning message: Some wärning' @@ -582,15 +582,15 @@ def test_wait_import_task_with_failure_no_error(server_url, api_version, token_t 'error': {}, 'messages': [ { - 'level': 'error', + 'level': 'ERROR', 'message': u'Somé error', }, { - 'level': 'warning', + 'level': 'WARNING', 'message': u'Some wärning', }, { - 'level': 'info', + 'level': 'INFO', 'message': u'Somé info', }, ], @@ -622,7 +622,7 @@ def test_wait_import_task_with_failure_no_error(server_url, api_version, token_t assert mock_display.mock_calls[0][1][0] == 'Waiting until Galaxy import task %s has completed' % full_import_uri assert mock_vvv.call_count == 1 - assert mock_vvv.mock_calls[0][1][0] == u'Galaxy import message: info - Somé info' + assert mock_vvv.mock_calls[0][1][0] == u'Galaxy import message: INFO - Somé info' assert mock_warn.call_count == 1 assert mock_warn.mock_calls[0][1][0] == u'Galaxy import warning message: Some wärning' @@ -704,6 +704,7 @@ def test_get_collection_version_metadata_no_version(api_version, token_type, ver mock_open = MagicMock() mock_open.side_effect = [ StringIO(to_text(json.dumps({ + 'href': 'https://galaxy.server.com/api/{api}/namespace/name/versions/{version}/'.format(api=api_version, version=version), 'download_url': 'https://downloadme.com', 'artifact': { 'sha256': 'ac47b6fac117d7c171812750dacda655b04533cf56b31080b82d1c0db3c9d80f', @@ -741,6 +742,85 @@ def test_get_collection_version_metadata_no_version(api_version, token_type, ver assert mock_open.mock_calls[0][2]['headers']['Authorization'] == '%s my token' % token_type +@pytest.mark.parametrize('api_version, token_type, token_ins, version', [ + ('v2', None, None, '2.1.13'), + ('v3', 'Bearer', KeycloakToken(auth_url='https://api.test/api/automation-hub/'), '1.0.0'), +]) +def test_get_collection_signatures_backwards_compat(api_version, token_type, token_ins, version, monkeypatch): + api = get_test_galaxy_api('https://galaxy.server.com/api/', api_version, token_ins=token_ins) + + if token_ins: + mock_token_get = MagicMock() + mock_token_get.return_value = 'my token' + monkeypatch.setattr(token_ins, 'get', mock_token_get) + + mock_open = MagicMock() + mock_open.side_effect = [ + StringIO("{}") + ] + monkeypatch.setattr(galaxy_api, 'open_url', mock_open) + + actual = api.get_collection_signatures('namespace', 'collection', version) + assert actual == [] + + assert mock_open.call_count == 1 + assert mock_open.mock_calls[0][1][0] == '%s%s/collections/namespace/collection/versions/%s/' \ + % (api.api_server, api_version, version) + + # v2 calls dont need auth, so no authz header or token_type + if token_type: + assert mock_open.mock_calls[0][2]['headers']['Authorization'] == '%s my token' % token_type + + +@pytest.mark.parametrize('api_version, token_type, token_ins, version', [ + ('v2', None, None, '2.1.13'), + ('v3', 'Bearer', KeycloakToken(auth_url='https://api.test/api/automation-hub/'), '1.0.0'), +]) +def test_get_collection_signatures(api_version, token_type, token_ins, version, monkeypatch): + api = get_test_galaxy_api('https://galaxy.server.com/api/', api_version, token_ins=token_ins) + + if token_ins: + mock_token_get = MagicMock() + mock_token_get.return_value = 'my token' + monkeypatch.setattr(token_ins, 'get', mock_token_get) + + mock_open = MagicMock() + mock_open.side_effect = [ + StringIO(to_text(json.dumps({ + 'signatures': [ + { + "signature": "-----BEGIN PGP SIGNATURE-----\nSIGNATURE1\n-----END PGP SIGNATURE-----\n", + "pubkey_fingerprint": "FINGERPRINT", + "signing_service": "ansible-default", + "pulp_created": "2022-01-14T14:05:53.835605Z", + }, + { + "signature": "-----BEGIN PGP SIGNATURE-----\nSIGNATURE2\n-----END PGP SIGNATURE-----\n", + "pubkey_fingerprint": "FINGERPRINT", + "signing_service": "ansible-default", + "pulp_created": "2022-01-14T14:05:53.835605Z", + }, + ], + }))), + ] + monkeypatch.setattr(galaxy_api, 'open_url', mock_open) + + actual = api.get_collection_signatures('namespace', 'collection', version) + + assert actual == [ + "-----BEGIN PGP SIGNATURE-----\nSIGNATURE1\n-----END PGP SIGNATURE-----\n", + "-----BEGIN PGP SIGNATURE-----\nSIGNATURE2\n-----END PGP SIGNATURE-----\n" + ] + + assert mock_open.call_count == 1 + assert mock_open.mock_calls[0][1][0] == '%s%s/collections/namespace/collection/versions/%s/' \ + % (api.api_server, api_version, version) + + # v2 calls dont need auth, so no authz header or token_type + if token_type: + assert mock_open.mock_calls[0][2]['headers']['Authorization'] == '%s my token' % token_type + + @pytest.mark.parametrize('api_version, token_type, token_ins, response', [ ('v2', None, None, { 'count': 2, diff --git a/test/units/galaxy/test_collection.py b/test/units/galaxy/test_collection.py index 65243df1..53d042fe 100644 --- a/test/units/galaxy/test_collection.py +++ b/test/units/galaxy/test_collection.py @@ -15,7 +15,7 @@ import uuid from hashlib import sha256 from io import BytesIO -from units.compat.mock import MagicMock, mock_open, patch +from mock import MagicMock, mock_open, patch import ansible.constants as C from ansible import context @@ -217,6 +217,42 @@ def server_config(monkeypatch): return server1, server2, server3 +@pytest.mark.parametrize( + 'required_signature_count,valid', + [ + ("1", True), + ("+1", True), + ("all", True), + ("+all", True), + ("-1", False), + ("invalid", False), + ("1.5", False), + ("+", False), + ] +) +def test_cli_options(required_signature_count, valid, monkeypatch): + cli_args = [ + 'ansible-galaxy', + 'collection', + 'install', + 'namespace.collection:1.0.0', + '--keyring', + '~/.ansible/pubring.kbx', + '--required-valid-signature-count', + required_signature_count + ] + + galaxy_cli = GalaxyCLI(args=cli_args) + mock_execute_install = MagicMock() + monkeypatch.setattr(galaxy_cli, '_execute_install_collection', mock_execute_install) + + if valid: + galaxy_cli.run() + else: + with pytest.raises(SystemExit, match='2') as error: + galaxy_cli.run() + + @pytest.mark.parametrize('global_ignore_certs', [True, False]) def test_validate_certs(global_ignore_certs, monkeypatch): cli_args = [ diff --git a/test/units/galaxy/test_collection_install.py b/test/units/galaxy/test_collection_install.py index d4565fd5..e34472f2 100644 --- a/test/units/galaxy/test_collection_install.py +++ b/test/units/galaxy/test_collection_install.py @@ -17,7 +17,8 @@ import tarfile import yaml from io import BytesIO, StringIO -from units.compat.mock import MagicMock +from mock import MagicMock, patch +from unittest import mock import ansible.module_utils.six.moves.urllib.error as urllib_error @@ -27,6 +28,7 @@ from ansible.errors import AnsibleError from ansible.galaxy import collection, api, dependency_resolution from ansible.galaxy.dependency_resolution.dataclasses import Candidate, Requirement from ansible.module_utils._text import to_bytes, to_native, to_text +from ansible.module_utils.common.process import get_bin_path from ansible.utils import context_objects as co from ansible.utils.display import Display @@ -168,9 +170,26 @@ def collection_artifact(request, tmp_path_factory): def galaxy_server(): context.CLIARGS._store = {'ignore_certs': False} galaxy_api = api.GalaxyAPI(None, 'test_server', 'https://galaxy.ansible.com') + galaxy_api.get_collection_signatures = MagicMock(return_value=[]) return galaxy_api +def test_concrete_artifact_manager_scm_no_executable(monkeypatch): + url = 'https://github.com/org/repo' + version = 'commitish' + mock_subprocess_check_call = MagicMock() + monkeypatch.setattr(collection.concrete_artifact_manager.subprocess, 'check_call', mock_subprocess_check_call) + mock_mkdtemp = MagicMock(return_value='') + monkeypatch.setattr(collection.concrete_artifact_manager, 'mkdtemp', mock_mkdtemp) + + error = re.escape( + "Could not find git executable to extract the collection from the Git repository `https://github.com/org/repo`" + ) + with mock.patch.dict(os.environ, {"PATH": ""}): + with pytest.raises(AnsibleError, match=error): + collection.concrete_artifact_manager._extract_collection_from_git(url, version, b'path') + + @pytest.mark.parametrize( 'url,version,trailing_slash', [ @@ -193,10 +212,12 @@ def test_concrete_artifact_manager_scm_cmd(url, version, trailing_slash, monkeyp repo = 'https://github.com/org/repo' if trailing_slash: repo += '/' - clone_cmd = ('git', 'clone', repo, '') + + git_executable = get_bin_path('git') + clone_cmd = (git_executable, 'clone', repo, '') assert mock_subprocess_check_call.call_args_list[0].args[0] == clone_cmd - assert mock_subprocess_check_call.call_args_list[1].args[0] == ('git', 'checkout', 'commitish') + assert mock_subprocess_check_call.call_args_list[1].args[0] == (git_executable, 'checkout', 'commitish') @pytest.mark.parametrize( @@ -222,10 +243,11 @@ def test_concrete_artifact_manager_scm_cmd_shallow(url, version, trailing_slash, repo = 'https://github.com/org/repo' if trailing_slash: repo += '/' - shallow_clone_cmd = ('git', 'clone', '--depth=1', repo, '') + git_executable = get_bin_path('git') + shallow_clone_cmd = (git_executable, 'clone', '--depth=1', repo, '') assert mock_subprocess_check_call.call_args_list[0].args[0] == shallow_clone_cmd - assert mock_subprocess_check_call.call_args_list[1].args[0] == ('git', 'checkout', 'HEAD') + assert mock_subprocess_check_call.call_args_list[1].args[0] == (git_executable, 'checkout', 'HEAD') def test_build_requirement_from_path(collection_artifact): @@ -449,7 +471,9 @@ def test_build_requirement_from_name(galaxy_server, monkeypatch, tmp_path_factor requirements = cli._require_one_of_collections_requirements( collections, requirements_file, artifacts_manager=concrete_artifact_cm )['collections'] - actual = collection._resolve_depenency_map(requirements, [galaxy_server], concrete_artifact_cm, None, True, False, False)['namespace.collection'] + actual = collection._resolve_depenency_map( + requirements, [galaxy_server], concrete_artifact_cm, None, True, False, False, False + )['namespace.collection'] assert actual.namespace == u'namespace' assert actual.name == u'collection' @@ -466,7 +490,7 @@ def test_build_requirement_from_name_with_prerelease(galaxy_server, monkeypatch, monkeypatch.setattr(galaxy_server, 'get_collection_versions', mock_get_versions) mock_get_info = MagicMock() - mock_get_info.return_value = api.CollectionVersionMetadata('namespace', 'collection', '2.0.1', None, None, {}) + mock_get_info.return_value = api.CollectionVersionMetadata('namespace', 'collection', '2.0.1', None, None, {}, None, None) monkeypatch.setattr(galaxy_server, 'get_collection_version_metadata', mock_get_info) test_dir = to_bytes(tmp_path_factory.mktemp('test-ÅÑŚÌβŁÈ Collections Input')) @@ -476,7 +500,9 @@ def test_build_requirement_from_name_with_prerelease(galaxy_server, monkeypatch, requirements = cli._require_one_of_collections_requirements( ['namespace.collection'], None, artifacts_manager=concrete_artifact_cm )['collections'] - actual = collection._resolve_depenency_map(requirements, [galaxy_server], concrete_artifact_cm, None, True, False, False)['namespace.collection'] + actual = collection._resolve_depenency_map( + requirements, [galaxy_server], concrete_artifact_cm, None, True, False, False, False + )['namespace.collection'] assert actual.namespace == u'namespace' assert actual.name == u'collection' @@ -494,7 +520,7 @@ def test_build_requirment_from_name_with_prerelease_explicit(galaxy_server, monk mock_get_info = MagicMock() mock_get_info.return_value = api.CollectionVersionMetadata('namespace', 'collection', '2.0.1-beta.1', None, None, - {}) + {}, None, None) monkeypatch.setattr(galaxy_server, 'get_collection_version_metadata', mock_get_info) test_dir = to_bytes(tmp_path_factory.mktemp('test-ÅÑŚÌβŁÈ Collections Input')) @@ -504,7 +530,9 @@ def test_build_requirment_from_name_with_prerelease_explicit(galaxy_server, monk requirements = cli._require_one_of_collections_requirements( ['namespace.collection:2.0.1-beta.1'], None, artifacts_manager=concrete_artifact_cm )['collections'] - actual = collection._resolve_depenency_map(requirements, [galaxy_server], concrete_artifact_cm, None, True, False, False)['namespace.collection'] + actual = collection._resolve_depenency_map( + requirements, [galaxy_server], concrete_artifact_cm, None, True, False, False, False + )['namespace.collection'] assert actual.namespace == u'namespace' assert actual.name == u'collection' @@ -521,7 +549,7 @@ def test_build_requirement_from_name_second_server(galaxy_server, monkeypatch, t monkeypatch.setattr(galaxy_server, 'get_collection_versions', mock_get_versions) mock_get_info = MagicMock() - mock_get_info.return_value = api.CollectionVersionMetadata('namespace', 'collection', '1.0.3', None, None, {}) + mock_get_info.return_value = api.CollectionVersionMetadata('namespace', 'collection', '1.0.3', None, None, {}, None, None) monkeypatch.setattr(galaxy_server, 'get_collection_version_metadata', mock_get_info) broken_server = copy.copy(galaxy_server) @@ -538,7 +566,7 @@ def test_build_requirement_from_name_second_server(galaxy_server, monkeypatch, t ['namespace.collection:>1.0.1'], None, artifacts_manager=concrete_artifact_cm )['collections'] actual = collection._resolve_depenency_map( - requirements, [broken_server, galaxy_server], concrete_artifact_cm, None, True, False, False + requirements, [broken_server, galaxy_server], concrete_artifact_cm, None, True, False, False, False )['namespace.collection'] assert actual.namespace == u'namespace' @@ -569,7 +597,7 @@ def test_build_requirement_from_name_missing(galaxy_server, monkeypatch, tmp_pat expected = "Failed to resolve the requested dependencies map. Could not satisfy the following requirements:\n* namespace.collection:* (direct request)" with pytest.raises(AnsibleError, match=re.escape(expected)): - collection._resolve_depenency_map(requirements, [galaxy_server, galaxy_server], concrete_artifact_cm, None, False, True, False) + collection._resolve_depenency_map(requirements, [galaxy_server, galaxy_server], concrete_artifact_cm, None, False, True, False, False) def test_build_requirement_from_name_401_unauthorized(galaxy_server, monkeypatch, tmp_path_factory): @@ -589,7 +617,7 @@ def test_build_requirement_from_name_401_unauthorized(galaxy_server, monkeypatch expected = "error (HTTP Code: 401, Message: msg)" with pytest.raises(api.GalaxyError, match=re.escape(expected)): - collection._resolve_depenency_map(requirements, [galaxy_server, galaxy_server], concrete_artifact_cm, None, False, False, False) + collection._resolve_depenency_map(requirements, [galaxy_server, galaxy_server], concrete_artifact_cm, None, False, False, False, False) def test_build_requirement_from_name_single_version(galaxy_server, monkeypatch, tmp_path_factory): @@ -608,7 +636,7 @@ def test_build_requirement_from_name_single_version(galaxy_server, monkeypatch, mock_get_info = MagicMock() mock_get_info.return_value = api.CollectionVersionMetadata('namespace', 'collection', '2.0.0', None, None, - {}) + {}, None, None) monkeypatch.setattr(galaxy_server, 'get_collection_version_metadata', mock_get_info) cli = GalaxyCLI(args=['ansible-galaxy', 'collection', 'install', 'namespace.collection:==2.0.0']) @@ -616,7 +644,7 @@ def test_build_requirement_from_name_single_version(galaxy_server, monkeypatch, ['namespace.collection:==2.0.0'], None, artifacts_manager=concrete_artifact_cm )['collections'] - actual = collection._resolve_depenency_map(requirements, [galaxy_server], concrete_artifact_cm, None, False, True, False)['namespace.collection'] + actual = collection._resolve_depenency_map(requirements, [galaxy_server], concrete_artifact_cm, None, False, True, False, False)['namespace.collection'] assert actual.namespace == u'namespace' assert actual.name == u'collection' @@ -644,7 +672,7 @@ def test_build_requirement_from_name_multiple_versions_one_match(galaxy_server, mock_get_info = MagicMock() mock_get_info.return_value = api.CollectionVersionMetadata('namespace', 'collection', '2.0.1', None, None, - {}) + {}, None, None) monkeypatch.setattr(galaxy_server, 'get_collection_version_metadata', mock_get_info) cli = GalaxyCLI(args=['ansible-galaxy', 'collection', 'install', 'namespace.collection:>=2.0.1,<2.0.2']) @@ -652,7 +680,7 @@ def test_build_requirement_from_name_multiple_versions_one_match(galaxy_server, ['namespace.collection:>=2.0.1,<2.0.2'], None, artifacts_manager=concrete_artifact_cm )['collections'] - actual = collection._resolve_depenency_map(requirements, [galaxy_server], concrete_artifact_cm, None, False, True, False)['namespace.collection'] + actual = collection._resolve_depenency_map(requirements, [galaxy_server], concrete_artifact_cm, None, False, True, False, False)['namespace.collection'] assert actual.namespace == u'namespace' assert actual.name == u'collection' @@ -678,7 +706,7 @@ def test_build_requirement_from_name_multiple_version_results(galaxy_server, mon monkeypatch.setattr(dependency_resolution.providers.CollectionDependencyProvider, 'find_matches', mock_find_matches) mock_get_info = MagicMock() - mock_get_info.return_value = api.CollectionVersionMetadata('namespace', 'collection', '2.0.5', None, None, {}) + mock_get_info.return_value = api.CollectionVersionMetadata('namespace', 'collection', '2.0.5', None, None, {}, None, None) monkeypatch.setattr(galaxy_server, 'get_collection_version_metadata', mock_get_info) mock_get_versions = MagicMock() @@ -693,7 +721,7 @@ def test_build_requirement_from_name_multiple_version_results(galaxy_server, mon ['namespace.collection:!=2.0.2'], None, artifacts_manager=concrete_artifact_cm )['collections'] - actual = collection._resolve_depenency_map(requirements, [galaxy_server], concrete_artifact_cm, None, False, True, False)['namespace.collection'] + actual = collection._resolve_depenency_map(requirements, [galaxy_server], concrete_artifact_cm, None, False, True, False, False)['namespace.collection'] assert actual.namespace == u'namespace' assert actual.name == u'collection' @@ -712,7 +740,7 @@ def test_candidate_with_conflict(monkeypatch, tmp_path_factory, galaxy_server): concrete_artifact_cm = collection.concrete_artifact_manager.ConcreteArtifactsManager(test_dir, validate_certs=False) mock_get_info = MagicMock() - mock_get_info.return_value = api.CollectionVersionMetadata('namespace', 'collection', '2.0.5', None, None, {}) + mock_get_info.return_value = api.CollectionVersionMetadata('namespace', 'collection', '2.0.5', None, None, {}, None, None) monkeypatch.setattr(galaxy_server, 'get_collection_version_metadata', mock_get_info) mock_get_versions = MagicMock() @@ -727,7 +755,7 @@ def test_candidate_with_conflict(monkeypatch, tmp_path_factory, galaxy_server): expected = "Failed to resolve the requested dependencies map. Could not satisfy the following requirements:\n" expected += "* namespace.collection:!=2.0.5 (direct request)" with pytest.raises(AnsibleError, match=re.escape(expected)): - collection._resolve_depenency_map(requirements, [galaxy_server], concrete_artifact_cm, None, False, True, False) + collection._resolve_depenency_map(requirements, [galaxy_server], concrete_artifact_cm, None, False, True, False, False) def test_dep_candidate_with_conflict(monkeypatch, tmp_path_factory, galaxy_server): @@ -735,8 +763,8 @@ def test_dep_candidate_with_conflict(monkeypatch, tmp_path_factory, galaxy_serve concrete_artifact_cm = collection.concrete_artifact_manager.ConcreteArtifactsManager(test_dir, validate_certs=False) mock_get_info_return = [ - api.CollectionVersionMetadata('parent', 'collection', '2.0.5', None, None, {'namespace.collection': '!=1.0.0'}), - api.CollectionVersionMetadata('namespace', 'collection', '1.0.0', None, None, {}), + api.CollectionVersionMetadata('parent', 'collection', '2.0.5', None, None, {'namespace.collection': '!=1.0.0'}, None, None), + api.CollectionVersionMetadata('namespace', 'collection', '1.0.0', None, None, {}, None, None), ] mock_get_info = MagicMock(side_effect=mock_get_info_return) monkeypatch.setattr(galaxy_server, 'get_collection_version_metadata', mock_get_info) @@ -752,12 +780,12 @@ def test_dep_candidate_with_conflict(monkeypatch, tmp_path_factory, galaxy_serve expected = "Failed to resolve the requested dependencies map. Could not satisfy the following requirements:\n" expected += "* namespace.collection:!=1.0.0 (dependency of parent.collection:2.0.5)" with pytest.raises(AnsibleError, match=re.escape(expected)): - collection._resolve_depenency_map(requirements, [galaxy_server], concrete_artifact_cm, None, False, True, False) + collection._resolve_depenency_map(requirements, [galaxy_server], concrete_artifact_cm, None, False, True, False, False) def test_install_installed_collection(monkeypatch, tmp_path_factory, galaxy_server): - mock_installed_collections = MagicMock(return_value=[Candidate('namespace.collection', '1.2.3', None, 'dir')]) + mock_installed_collections = MagicMock(return_value=[Candidate('namespace.collection', '1.2.3', None, 'dir', None)]) monkeypatch.setattr(collection, 'find_existing_collections', mock_installed_collections) @@ -768,7 +796,7 @@ def test_install_installed_collection(monkeypatch, tmp_path_factory, galaxy_serv monkeypatch.setattr(Display, 'display', mock_display) mock_get_info = MagicMock() - mock_get_info.return_value = api.CollectionVersionMetadata('namespace', 'collection', '1.2.3', None, None, {}) + mock_get_info.return_value = api.CollectionVersionMetadata('namespace', 'collection', '1.2.3', None, None, {}, None, None) monkeypatch.setattr(galaxy_server, 'get_collection_version_metadata', mock_get_info) mock_get_versions = MagicMock(return_value=['1.2.3', '1.3.0']) @@ -795,7 +823,7 @@ def test_install_collection(collection_artifact, monkeypatch): collection_path = os.path.join(output_path, b'ansible_namespace', b'collection') os.makedirs(os.path.join(collection_path, b'delete_me')) # Create a folder to verify the install cleans out the dir - candidate = Candidate('ansible_namespace.collection', '0.1.0', to_text(collection_tar), 'file') + candidate = Candidate('ansible_namespace.collection', '0.1.0', to_text(collection_tar), 'file', None) collection.install(candidate, to_text(output_path), concrete_artifact_cm) # Ensure the temp directory is empty, nothing is left behind @@ -834,7 +862,7 @@ def test_install_collection_with_download(galaxy_server, collection_artifact, mo mock_download.return_value = collection_tar monkeypatch.setattr(concrete_artifact_cm, 'get_galaxy_artifact_path', mock_download) - req = Requirement('ansible_namespace.collection', '0.1.0', 'https://downloadme.com', 'galaxy') + req = Candidate('ansible_namespace.collection', '0.1.0', 'https://downloadme.com', 'galaxy', None) collection.install(req, to_text(collections_dir), concrete_artifact_cm) actual_files = os.listdir(collection_path) @@ -862,8 +890,8 @@ def test_install_collections_from_tar(collection_artifact, monkeypatch): concrete_artifact_cm = collection.concrete_artifact_manager.ConcreteArtifactsManager(temp_path, validate_certs=False) - requirements = [Requirement('ansible_namespace.collection', '0.1.0', to_text(collection_tar), 'file')] - collection.install_collections(requirements, to_text(temp_path), [], False, False, False, False, False, False, concrete_artifact_cm) + requirements = [Requirement('ansible_namespace.collection', '0.1.0', to_text(collection_tar), 'file', None)] + collection.install_collections(requirements, to_text(temp_path), [], False, False, False, False, False, False, concrete_artifact_cm, True) assert os.path.isdir(collection_path) @@ -898,8 +926,8 @@ def test_install_collections_existing_without_force(collection_artifact, monkeyp assert os.path.isdir(collection_path) - requirements = [Requirement('ansible_namespace.collection', '0.1.0', to_text(collection_tar), 'file')] - collection.install_collections(requirements, to_text(temp_path), [], False, False, False, False, False, False, concrete_artifact_cm) + requirements = [Requirement('ansible_namespace.collection', '0.1.0', to_text(collection_tar), 'file', None)] + collection.install_collections(requirements, to_text(temp_path), [], False, False, False, False, False, False, concrete_artifact_cm, True) assert os.path.isdir(collection_path) @@ -930,8 +958,8 @@ def test_install_missing_metadata_warning(collection_artifact, monkeypatch): os.unlink(b_path) concrete_artifact_cm = collection.concrete_artifact_manager.ConcreteArtifactsManager(temp_path, validate_certs=False) - requirements = [Requirement('ansible_namespace.collection', '0.1.0', to_text(collection_tar), 'file')] - collection.install_collections(requirements, to_text(temp_path), [], False, False, False, False, False, False, concrete_artifact_cm) + requirements = [Requirement('ansible_namespace.collection', '0.1.0', to_text(collection_tar), 'file', None)] + collection.install_collections(requirements, to_text(temp_path), [], False, False, False, False, False, False, concrete_artifact_cm, True) display_msgs = [m[1][0] for m in mock_display.mock_calls if 'newline' not in m[2] and len(m[1]) == 1] @@ -951,8 +979,8 @@ def test_install_collection_with_circular_dependency(collection_artifact, monkey monkeypatch.setattr(Display, 'display', mock_display) concrete_artifact_cm = collection.concrete_artifact_manager.ConcreteArtifactsManager(temp_path, validate_certs=False) - requirements = [Requirement('ansible_namespace.collection', '0.1.0', to_text(collection_tar), 'file')] - collection.install_collections(requirements, to_text(temp_path), [], False, False, False, False, False, False, concrete_artifact_cm) + requirements = [Requirement('ansible_namespace.collection', '0.1.0', to_text(collection_tar), 'file', None)] + collection.install_collections(requirements, to_text(temp_path), [], False, False, False, False, False, False, concrete_artifact_cm, True) assert os.path.isdir(collection_path) @@ -975,3 +1003,50 @@ def test_install_collection_with_circular_dependency(collection_artifact, monkey assert display_msgs[1] == "Starting collection install process" assert display_msgs[2] == "Installing 'ansible_namespace.collection:0.1.0' to '%s'" % to_text(collection_path) assert display_msgs[3] == "ansible_namespace.collection:0.1.0 was installed successfully" + + +@pytest.mark.parametrize( + "signatures,required_successful_count,ignore_errors,expected_success", + [ + ([], 'all', [], True), + (["good_signature"], 'all', [], True), + (["good_signature", collection.gpg.GpgBadArmor(status='failed')], 'all', [], False), + ([collection.gpg.GpgBadArmor(status='failed')], 'all', [], False), + # This is expected to succeed because ignored does not increment failed signatures. + # "all" signatures is not a specific number, so all == no (non-ignored) signatures in this case. + ([collection.gpg.GpgBadArmor(status='failed')], 'all', ["BADARMOR"], True), + ([collection.gpg.GpgBadArmor(status='failed'), "good_signature"], 'all', ["BADARMOR"], True), + ([], '+all', [], False), + ([collection.gpg.GpgBadArmor(status='failed')], '+all', ["BADARMOR"], False), + ([], '1', [], True), + ([], '+1', [], False), + (["good_signature"], '2', [], False), + (["good_signature", collection.gpg.GpgBadArmor(status='failed')], '2', [], False), + # This is expected to fail because ignored does not increment successful signatures. + # 2 signatures are required, but only 1 is successful. + (["good_signature", collection.gpg.GpgBadArmor(status='failed')], '2', ["BADARMOR"], False), + (["good_signature", "good_signature"], '2', [], True), + ] +) +def test_verify_file_signatures(signatures, required_successful_count, ignore_errors, expected_success): + # type: (List[bool], int, bool, bool) -> None + + def gpg_error_generator(results): + for result in results: + if isinstance(result, collection.gpg.GpgBaseError): + yield result + + fqcn = 'ns.coll' + manifest_file = 'MANIFEST.json' + keyring = '~/.ansible/pubring.kbx' + + with patch.object(collection, 'run_gpg_verify', MagicMock(return_value=("somestdout", 0,))): + with patch.object(collection, 'parse_gpg_errors', MagicMock(return_value=gpg_error_generator(signatures))): + assert collection.verify_file_signatures( + fqcn, + manifest_file, + signatures, + keyring, + required_successful_count, + ignore_errors + ) == expected_success diff --git a/test/units/galaxy/test_role_install.py b/test/units/galaxy/test_role_install.py index cf990b55..687fcac1 100644 --- a/test/units/galaxy/test_role_install.py +++ b/test/units/galaxy/test_role_install.py @@ -8,6 +8,7 @@ __metaclass__ = type import os +import functools import pytest import tempfile @@ -59,9 +60,9 @@ def mock_NamedTemporaryFile(mocker, **args): return mock_ntf -@pytest.fixture(autouse=True) -def init_test(monkeypatch): - monkeypatch.setattr(tempfile, 'NamedTemporaryFile', mock_NamedTemporaryFile) +@pytest.fixture +def init_mock_temp_file(mocker, monkeypatch): + monkeypatch.setattr(tempfile, 'NamedTemporaryFile', functools.partial(mock_NamedTemporaryFile, mocker)) @pytest.fixture(autouse=True) @@ -74,7 +75,7 @@ def mock_role_download_api(mocker, monkeypatch): return mock_role_api -def test_role_download_github(mocker, galaxy_server, mock_role_download_api, monkeypatch): +def test_role_download_github(init_mock_temp_file, mocker, galaxy_server, mock_role_download_api, monkeypatch): mock_api = mocker.MagicMock() mock_api.side_effect = [ StringIO(u'{"available_versions":{"v1":"v1/"}}'), @@ -89,7 +90,7 @@ def test_role_download_github(mocker, galaxy_server, mock_role_download_api, mon assert mock_role_download_api.mock_calls[0][1][0] == 'https://github.com/test_owner/test_role/archive/0.0.1.tar.gz' -def test_role_download_github_default_version(mocker, galaxy_server, mock_role_download_api, monkeypatch): +def test_role_download_github_default_version(init_mock_temp_file, mocker, galaxy_server, mock_role_download_api, monkeypatch): mock_api = mocker.MagicMock() mock_api.side_effect = [ StringIO(u'{"available_versions":{"v1":"v1/"}}'), @@ -104,7 +105,7 @@ def test_role_download_github_default_version(mocker, galaxy_server, mock_role_d assert mock_role_download_api.mock_calls[0][1][0] == 'https://github.com/test_owner/test_role/archive/0.0.2.tar.gz' -def test_role_download_github_no_download_url_for_version(mocker, galaxy_server, mock_role_download_api, monkeypatch): +def test_role_download_github_no_download_url_for_version(init_mock_temp_file, mocker, galaxy_server, mock_role_download_api, monkeypatch): mock_api = mocker.MagicMock() mock_api.side_effect = [ StringIO(u'{"available_versions":{"v1":"v1/"}}'), @@ -119,7 +120,7 @@ def test_role_download_github_no_download_url_for_version(mocker, galaxy_server, assert mock_role_download_api.mock_calls[0][1][0] == 'https://github.com/test_owner/test_role/archive/0.0.1.tar.gz' -def test_role_download_url(mocker, galaxy_server, mock_role_download_api, monkeypatch): +def test_role_download_url(init_mock_temp_file, mocker, galaxy_server, mock_role_download_api, monkeypatch): mock_api = mocker.MagicMock() mock_api.side_effect = [ StringIO(u'{"available_versions":{"v1":"v1/"}}'), @@ -135,7 +136,7 @@ def test_role_download_url(mocker, galaxy_server, mock_role_download_api, monkey assert mock_role_download_api.mock_calls[0][1][0] == 'http://localhost:8080/test_owner/test_role/0.0.1.tar.gz' -def test_role_download_url_default_version(mocker, galaxy_server, mock_role_download_api, monkeypatch): +def test_role_download_url_default_version(init_mock_temp_file, mocker, galaxy_server, mock_role_download_api, monkeypatch): mock_api = mocker.MagicMock() mock_api.side_effect = [ StringIO(u'{"available_versions":{"v1":"v1/"}}'), diff --git a/test/units/galaxy/test_token.py b/test/units/galaxy/test_token.py index 13426688..98dec5bf 100644 --- a/test/units/galaxy/test_token.py +++ b/test/units/galaxy/test_token.py @@ -8,7 +8,7 @@ __metaclass__ = type import os import pytest -from units.compat.mock import MagicMock +from mock import MagicMock import ansible.constants as C from ansible.cli.galaxy import GalaxyCLI, SERVER_DEF diff --git a/test/units/mock/path.py b/test/units/mock/path.py index 721dc293..dc51a143 100644 --- a/test/units/mock/path.py +++ b/test/units/mock/path.py @@ -1,7 +1,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -from units.compat.mock import MagicMock +from mock import MagicMock from ansible.utils.path import unfrackpath diff --git a/test/units/module_utils/basic/test_argument_spec.py b/test/units/module_utils/basic/test_argument_spec.py index 24bbe2e9..20bfb01e 100644 --- a/test/units/module_utils/basic/test_argument_spec.py +++ b/test/units/module_utils/basic/test_argument_spec.py @@ -12,7 +12,7 @@ import os import pytest -from units.compat.mock import MagicMock +from mock import MagicMock from ansible.module_utils import basic from ansible.module_utils.api import basic_auth_argument_spec, rate_limit_argument_spec, retry_argument_spec from ansible.module_utils.common import warnings @@ -709,3 +709,16 @@ def test_no_log_none(stdin, capfd): # makes it into am.no_log_values. Instead we can check for the warning # emitted by am._log_invocation. assert len(get_warning_messages()) > 0 + + +@pytest.mark.parametrize("stdin", [{"pass": "testing"}], indirect=["stdin"]) +def test_no_log_alias(stdin, capfd): + """Given module parameters that use an alias for a parameter that matches + PASSWORD_MATCH and has no_log=True set, a warning should not be issued. + """ + arg_spec = { + "other_pass": {"no_log": True, "aliases": ["pass"]}, + } + am = basic.AnsibleModule(arg_spec) + + assert len(get_warning_messages()) == 0 diff --git a/test/units/module_utils/basic/test_deprecate_warn.py b/test/units/module_utils/basic/test_deprecate_warn.py index 7fd54ce0..581ba6da 100644 --- a/test/units/module_utils/basic/test_deprecate_warn.py +++ b/test/units/module_utils/basic/test_deprecate_warn.py @@ -71,7 +71,7 @@ def test_deprecate_without_list(am, capfd): @pytest.mark.parametrize('stdin', [{}], indirect=['stdin']) -def test_deprecate_without_list(am, capfd): +def test_deprecate_without_list_version_date_not_set(am, capfd): with pytest.raises(AssertionError) as ctx: am.deprecate('Simple deprecation warning', date='', version='') assert ctx.value.args[0] == "implementation error -- version and date must not both be set" diff --git a/test/units/module_utils/basic/test_filesystem.py b/test/units/module_utils/basic/test_filesystem.py index 37d1c553..92e2c46e 100644 --- a/test/units/module_utils/basic/test_filesystem.py +++ b/test/units/module_utils/basic/test_filesystem.py @@ -9,7 +9,7 @@ __metaclass__ = type from units.mock.procenv import ModuleTestCase -from units.compat.mock import patch, MagicMock +from mock import patch, MagicMock from ansible.module_utils.six.moves import builtins realimport = builtins.__import__ @@ -134,3 +134,27 @@ class TestOtherFilesystem(ModuleTestCase): with patch('os.lchown', side_effect=OSError) as m: self.assertRaises(SystemExit, am.set_group_if_different, '/path/to/file', 'root', False) + + def test_module_utils_basic_ansible_module_set_directory_attributes_if_different(self): + from ansible.module_utils import basic + basic._ANSIBLE_ARGS = None + + am = basic.AnsibleModule( + argument_spec=dict(), + ) + + file_args = { + 'path': '/path/to/file', + 'mode': None, + 'owner': None, + 'group': None, + 'seuser': None, + 'serole': None, + 'setype': None, + 'selevel': None, + 'secontext': [None, None, None], + 'attributes': None, + } + + self.assertEqual(am.set_directory_attributes_if_different(file_args, True), True) + self.assertEqual(am.set_directory_attributes_if_different(file_args, False), False) diff --git a/test/units/module_utils/basic/test_get_module_path.py b/test/units/module_utils/basic/test_get_module_path.py index 6ff4a3bc..2d0b8dd0 100644 --- a/test/units/module_utils/basic/test_get_module_path.py +++ b/test/units/module_utils/basic/test_get_module_path.py @@ -9,7 +9,7 @@ __metaclass__ = type from units.mock.procenv import ModuleTestCase -from units.compat.mock import patch +from mock import patch from ansible.module_utils.six.moves import builtins realimport = builtins.__import__ diff --git a/test/units/module_utils/basic/test_imports.py b/test/units/module_utils/basic/test_imports.py index d1a5f379..79ab971f 100644 --- a/test/units/module_utils/basic/test_imports.py +++ b/test/units/module_utils/basic/test_imports.py @@ -12,7 +12,7 @@ import sys from units.mock.procenv import ModuleTestCase from units.compat import unittest -from units.compat.mock import patch +from mock import patch from ansible.module_utils.six.moves import builtins realimport = builtins.__import__ diff --git a/test/units/module_utils/basic/test_platform_distribution.py b/test/units/module_utils/basic/test_platform_distribution.py index 3c1afb7d..6579bee9 100644 --- a/test/units/module_utils/basic/test_platform_distribution.py +++ b/test/units/module_utils/basic/test_platform_distribution.py @@ -9,7 +9,7 @@ __metaclass__ = type import pytest -from units.compat.mock import patch +from mock import patch from ansible.module_utils.six.moves import builtins diff --git a/test/units/module_utils/basic/test_selinux.py b/test/units/module_utils/basic/test_selinux.py index 3a34d314..600ff6b3 100644 --- a/test/units/module_utils/basic/test_selinux.py +++ b/test/units/module_utils/basic/test_selinux.py @@ -11,7 +11,8 @@ import errno import json import pytest -from ...compat.mock import mock_open, patch +from mock import mock_open, patch + from ansible.module_utils import basic from ansible.module_utils.common.text.converters import to_bytes from ansible.module_utils.six.moves import builtins diff --git a/test/units/module_utils/basic/test_set_cwd.py b/test/units/module_utils/basic/test_set_cwd.py index 159236b7..77418601 100644 --- a/test/units/module_utils/basic/test_set_cwd.py +++ b/test/units/module_utils/basic/test_set_cwd.py @@ -13,7 +13,7 @@ import tempfile import pytest -from units.compat.mock import patch, MagicMock +from mock import patch, MagicMock from ansible.module_utils._text import to_bytes from ansible.module_utils import basic diff --git a/test/units/module_utils/basic/test_tmpdir.py b/test/units/module_utils/basic/test_tmpdir.py index 818cb9b1..eec8f62c 100644 --- a/test/units/module_utils/basic/test_tmpdir.py +++ b/test/units/module_utils/basic/test_tmpdir.py @@ -13,7 +13,7 @@ import tempfile import pytest -from units.compat.mock import patch, MagicMock +from mock import patch, MagicMock from ansible.module_utils._text import to_bytes from ansible.module_utils import basic diff --git a/test/units/module_utils/common/arg_spec/test_aliases.py b/test/units/module_utils/common/arg_spec/test_aliases.py index f4c96c74..1c1e243a 100644 --- a/test/units/module_utils/common/arg_spec/test_aliases.py +++ b/test/units/module_utils/common/arg_spec/test_aliases.py @@ -95,6 +95,11 @@ def test_aliases(arg_spec, parameters, expected, deprecation, warning): assert isinstance(result, ValidationResult) assert result.validated_parameters == expected assert result.error_messages == [] + assert result._aliases == { + alias: param + for param, value in arg_spec.items() + for alias in value.get("aliases", []) + } if deprecation: assert deprecation == result._deprecations[0] diff --git a/test/units/module_utils/common/arg_spec/test_validate_invalid.py b/test/units/module_utils/common/arg_spec/test_validate_invalid.py index 5384ee22..7302e8aa 100644 --- a/test/units/module_utils/common/arg_spec/test_validate_invalid.py +++ b/test/units/module_utils/common/arg_spec/test_validate_invalid.py @@ -100,6 +100,14 @@ INVALID_SPECS = [ {'req': None}, set(), "missing required arguments: req" + ), + ( + 'blank_values', + {'ch_param': {'elements': 'str', 'type': 'list', 'choices': ['a', 'b']}}, + {'ch_param': ['']}, + {'ch_param': ['']}, + set(), + "value of ch_param must be one or more of" ) ] diff --git a/test/units/module_utils/common/test_locale.py b/test/units/module_utils/common/test_locale.py index 9d959860..f8fea476 100644 --- a/test/units/module_utils/common/test_locale.py +++ b/test/units/module_utils/common/test_locale.py @@ -5,7 +5,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -from units.compat.mock import MagicMock +from mock import MagicMock from ansible.module_utils.common.locale import get_best_parsable_locale diff --git a/test/units/module_utils/common/test_sys_info.py b/test/units/module_utils/common/test_sys_info.py index 18aafe53..63101a81 100644 --- a/test/units/module_utils/common/test_sys_info.py +++ b/test/units/module_utils/common/test_sys_info.py @@ -9,7 +9,7 @@ __metaclass__ = type import pytest -from units.compat.mock import patch +from mock import patch from ansible.module_utils.six.moves import builtins diff --git a/test/units/module_utils/common/validation/test_check_required_if.py b/test/units/module_utils/common/validation/test_check_required_if.py index 5b4b7983..4189164a 100644 --- a/test/units/module_utils/common/validation/test_check_required_if.py +++ b/test/units/module_utils/common/validation/test_check_required_if.py @@ -53,7 +53,7 @@ def test_check_required_if_missing_multiple(): assert to_native(e.value) == expected -def test_check_required_if_missing_multiple(): +def test_check_required_if_missing_multiple_with_context(): arguments_terms = [["state", "present", ("path", "owner")]] params = { "state": "present", diff --git a/test/units/module_utils/facts/base.py b/test/units/module_utils/facts/base.py index 33d3087b..23e620cb 100644 --- a/test/units/module_utils/facts/base.py +++ b/test/units/module_utils/facts/base.py @@ -20,7 +20,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type from units.compat import unittest -from units.compat.mock import Mock, patch +from mock import Mock, patch class BaseFactsTest(unittest.TestCase): diff --git a/test/units/module_utils/facts/hardware/linux_data.py b/test/units/module_utils/facts/hardware/linux_data.py index 8e056769..3879188d 100644 --- a/test/units/module_utils/facts/hardware/linux_data.py +++ b/test/units/module_utils/facts/hardware/linux_data.py @@ -583,3 +583,51 @@ CPU_INFO_TEST_SCENARIOS = [ }, }, ] + +SG_INQ_OUTPUTS = [""" +Identify controller for /dev/nvme0n1: + Model number: Amazon Elastic Block Store + Serial number: vol0123456789 + Firmware revision: 1.0 + Version: 0.0 + No optional admin command support + No optional NVM command support + PCI vendor ID VID/SSVID: 0x1d0f/0x1d0f + IEEE OUI Identifier: 0xa002dc + Controller ID: 0x0 + Number of namespaces: 1 + Maximum data transfer size: 64 pages + Namespace 1 (deduced from device name): + Namespace size/capacity: 62914560/62914560 blocks + Namespace utilization: 0 blocks + Number of LBA formats: 1 + Index LBA size: 0 + LBA format 0 support: <-- active + Logical block size: 512 bytes + Approximate namespace size: 32 GB + Metadata size: 0 bytes + Relative performance: Best [0x0] +""", """ +Identify controller for /dev/nvme0n1: + Model number: Amazon Elastic Block Store + Unit serial number: vol0123456789 + Firmware revision: 1.0 + Version: 0.0 + No optional admin command support + No optional NVM command support + PCI vendor ID VID/SSVID: 0x1d0f/0x1d0f + IEEE OUI Identifier: 0xa002dc + Controller ID: 0x0 + Number of namespaces: 1 + Maximum data transfer size: 64 pages + Namespace 1 (deduced from device name): + Namespace size/capacity: 62914560/62914560 blocks + Namespace utilization: 0 blocks + Number of LBA formats: 1 + Index LBA size: 0 + LBA format 0 support: <-- active + Logical block size: 512 bytes + Approximate namespace size: 32 GB + Metadata size: 0 bytes + Relative performance: Best [0x0] +"""] diff --git a/test/units/module_utils/facts/hardware/test_linux.py b/test/units/module_utils/facts/hardware/test_linux.py index 6e77683a..1d584593 100644 --- a/test/units/module_utils/facts/hardware/test_linux.py +++ b/test/units/module_utils/facts/hardware/test_linux.py @@ -19,13 +19,13 @@ __metaclass__ = type import os from units.compat import unittest -from units.compat.mock import Mock, patch +from mock import Mock, patch from ansible.module_utils.facts import timeout from ansible.module_utils.facts.hardware import linux -from . linux_data import LSBLK_OUTPUT, LSBLK_OUTPUT_2, LSBLK_UUIDS, MTAB, MTAB_ENTRIES, BIND_MOUNTS, STATVFS_INFO, UDEVADM_UUID, UDEVADM_OUTPUT +from . linux_data import LSBLK_OUTPUT, LSBLK_OUTPUT_2, LSBLK_UUIDS, MTAB, MTAB_ENTRIES, BIND_MOUNTS, STATVFS_INFO, UDEVADM_UUID, UDEVADM_OUTPUT, SG_INQ_OUTPUTS with open(os.path.join(os.path.dirname(__file__), '../fixtures/findmount_output.txt')) as f: FINDMNT_OUTPUT = f.read() @@ -173,3 +173,26 @@ class TestFactsLinuxHardwareGetMountFacts(unittest.TestCase): udevadm_uuid = lh._udevadm_uuid('mock_device') self.assertEqual(udevadm_uuid, '57b1a3e7-9019-4747-9809-7ec52bba9179') + + def test_get_sg_inq_serial(self): + # Valid outputs + for sq_inq_output in SG_INQ_OUTPUTS: + module = Mock() + module.run_command = Mock(return_value=(0, sq_inq_output, '')) # (rc, out, err) + lh = linux.LinuxHardware(module=module, load_on_init=False) + sg_inq_serial = lh._get_sg_inq_serial('/usr/bin/sg_inq', 'nvme0n1') + self.assertEqual(sg_inq_serial, 'vol0123456789') + + # Invalid output + module = Mock() + module.run_command = Mock(return_value=(0, '', '')) # (rc, out, err) + lh = linux.LinuxHardware(module=module, load_on_init=False) + sg_inq_serial = lh._get_sg_inq_serial('/usr/bin/sg_inq', 'nvme0n1') + self.assertEqual(sg_inq_serial, None) + + # Non zero rc + module = Mock() + module.run_command = Mock(return_value=(42, '', 'Error 42')) # (rc, out, err) + lh = linux.LinuxHardware(module=module, load_on_init=False) + sg_inq_serial = lh._get_sg_inq_serial('/usr/bin/sg_inq', 'nvme0n1') + self.assertEqual(sg_inq_serial, None) diff --git a/test/units/module_utils/facts/network/test_fc_wwn.py b/test/units/module_utils/facts/network/test_fc_wwn.py index 32a3a43d..27d45234 100644 --- a/test/units/module_utils/facts/network/test_fc_wwn.py +++ b/test/units/module_utils/facts/network/test_fc_wwn.py @@ -6,7 +6,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type from ansible.module_utils.facts.network import fc_wwn -from units.compat.mock import Mock +from mock import Mock # AIX lsdev diff --git a/test/units/module_utils/facts/network/test_generic_bsd.py b/test/units/module_utils/facts/network/test_generic_bsd.py index afb698c5..79cc4815 100644 --- a/test/units/module_utils/facts/network/test_generic_bsd.py +++ b/test/units/module_utils/facts/network/test_generic_bsd.py @@ -18,7 +18,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -from units.compat.mock import Mock +from mock import Mock from units.compat import unittest from ansible.module_utils.facts.network import generic_bsd diff --git a/test/units/module_utils/facts/network/test_iscsi_get_initiator.py b/test/units/module_utils/facts/network/test_iscsi_get_initiator.py index 2048ba2a..78e5c960 100644 --- a/test/units/module_utils/facts/network/test_iscsi_get_initiator.py +++ b/test/units/module_utils/facts/network/test_iscsi_get_initiator.py @@ -6,7 +6,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type from ansible.module_utils.facts.network import iscsi -from units.compat.mock import Mock +from mock import Mock # AIX # lsattr -E -l iscsi0 diff --git a/test/units/module_utils/facts/other/test_facter.py b/test/units/module_utils/facts/other/test_facter.py index 7466338e..517265d3 100644 --- a/test/units/module_utils/facts/other/test_facter.py +++ b/test/units/module_utils/facts/other/test_facter.py @@ -19,7 +19,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -from units.compat.mock import Mock, patch +from mock import Mock, patch from .. base import BaseFactsTest diff --git a/test/units/module_utils/facts/other/test_ohai.py b/test/units/module_utils/facts/other/test_ohai.py index 42a72d97..38fb67f4 100644 --- a/test/units/module_utils/facts/other/test_ohai.py +++ b/test/units/module_utils/facts/other/test_ohai.py @@ -19,7 +19,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -from units.compat.mock import Mock, patch +from mock import Mock, patch from .. base import BaseFactsTest diff --git a/test/units/module_utils/facts/system/distribution/conftest.py b/test/units/module_utils/facts/system/distribution/conftest.py index d27b97f0..0282a7fc 100644 --- a/test/units/module_utils/facts/system/distribution/conftest.py +++ b/test/units/module_utils/facts/system/distribution/conftest.py @@ -8,7 +8,7 @@ __metaclass__ = type import pytest -from units.compat.mock import Mock +from mock import Mock @pytest.fixture diff --git a/test/units/module_utils/facts/system/distribution/fixtures/deepin_20.4.json b/test/units/module_utils/facts/system/distribution/fixtures/deepin_20.4.json new file mode 100644 index 00000000..ca5d50dd --- /dev/null +++ b/test/units/module_utils/facts/system/distribution/fixtures/deepin_20.4.json @@ -0,0 +1,29 @@ +{ + "name": "Deepin 20.4", + "distro": { + "codename": "apricot", + "id": "Deepin", + "name": "Deepin", + "version": "20.4", + "version_best": "20.4", + "os_release_info": {}, + "lsb_release_info": {} + }, + "input": { + "/etc/os-release": "PRETTY_NAME=\"Deepin 20.4\"\nNAME=\"Deepin\"\nVERSION_ID=\"20.4\"\nVERSION=\"20.4\"\nVERSION_CODENAME=\"apricot\"\nID=Deepin\nHOME_URL=\"https://www.deepin.org/\"\nBUG_REPORT_URL=\"https://bbs.deepin.org/\"\n", + "/etc/lsb-release": "DISTRIB_ID=Deepin\nDISTRIB_RELEASE=20.4\nDISTRIB_DESCRIPTION=\"Deepin 20.4\"\nDISTRIB_CODENAME=apricot\n", + "/usr/lib/os-release": "PRETTY_NAME=\"Deepin 20.4\"\nNAME=\"Deepin\"\nVERSION_ID=\"20.4\"\nVERSION=\"20.4\"\nVERSION_CODENAME=\"apricot\"\nID=Deepin\nHOME_URL=\"https://www.deepin.org/\"\nBUG_REPORT_URL=\"https://bbs.deepin.org/\"\n" + }, + "platform.dist": [ + "Deepin", + "20.4", + "apricot" + ], + "result": { + "distribution": "Deepin", + "distribution_version": "20.4", + "distribution_release": "apricot", + "distribution_major_version": "20", + "os_family": "Debian" + } +} diff --git a/test/units/module_utils/facts/system/distribution/fixtures/eurolinux_8.5.json b/test/units/module_utils/facts/system/distribution/fixtures/eurolinux_8.5.json new file mode 100644 index 00000000..add1b731 --- /dev/null +++ b/test/units/module_utils/facts/system/distribution/fixtures/eurolinux_8.5.json @@ -0,0 +1,46 @@ +{ + "name": "EuroLinux 8.5", + "distro": { + "codename": "Tirana", + "id": "eurolinux", + "name": "EuroLinux", + "version": "8.5", + "version_best": "8.5", + "lsb_release_info": {}, + "os_release_info": { + "name": "EuroLinux", + "version": "8.5 (Tirana)", + "id": "eurolinux", + "id_like": "rhel fedora centos", + "version_id": "8.5", + "platform_id": "platform:el8", + "pretty_name": "EuroLinux 8.5 (Tirana)", + "ansi_color": "0;34", + "cpe_name": "cpe:/o:eurolinux:eurolinux:8", + "home_url": "https://www.euro-linux.com/", + "bug_report_url": "https://github.com/EuroLinux/eurolinux-distro-bugs-and-rfc/", + "redhat_support_product": "EuroLinux", + "redhat_support_product_version": "8", + "codename": "Tirana" + } + }, + "input": { + "/etc/redhat-release": "EuroLinux release 8.5 (Tirana) \n", + "/etc/system-release": "EuroLinux release 8.5 (Tirana) \n", + "/etc/os-release": "NAME=\"EuroLinux\"\nVERSION=\"8.5 (Tirana)\"\nID=\"eurolinux\"\nID_LIKE=\"rhel fedora centos\"\nVERSION_ID=\"8.5\"\nPLATFORM_ID=\"platform:el8\"\nPRETTY_NAME=\"EuroLinux 8.5 (Tirana)\"\nANSI_COLOR=\"0;34\"\nCPE_NAME=\"cpe:/o:eurolinux:eurolinux:8\"\nHOME_URL=\"https://www.euro-linux.com/\"\nBUG_REPORT_URL=\"https://github.com/EuroLinux/eurolinux-distro-bugs-and-rfc/\"\nREDHAT_SUPPORT_PRODUCT=\"EuroLinux\"\nREDHAT_SUPPORT_PRODUCT_VERSION=\"8\"\n", + "/usr/lib/os-release": "NAME=\"EuroLinux\"\nVERSION=\"8.5 (Tirana)\"\nID=\"eurolinux\"\nID_LIKE=\"rhel fedora centos\"\nVERSION_ID=\"8.5\"\nPLATFORM_ID=\"platform:el8\"\nPRETTY_NAME=\"EuroLinux 8.5 (Tirana)\"\nANSI_COLOR=\"0;34\"\nCPE_NAME=\"cpe:/o:eurolinux:eurolinux:8\"\nHOME_URL=\"https://www.euro-linux.com/\"\nBUG_REPORT_URL=\"https://github.com/EuroLinux/eurolinux-distro-bugs-and-rfc/\"\nREDHAT_SUPPORT_PRODUCT=\"EuroLinux\"\nREDHAT_SUPPORT_PRODUCT_VERSION=\"8\"\n" + }, + "platform.dist": [ + "eurolinux", + "8.5", + "Tirana" + ], + "result": { + "distribution": "EuroLinux", + "distribution_version": "8.5", + "distribution_release": "Tirana", + "distribution_major_version": "8", + "os_family": "RedHat" + }, + "platform.release": "4.18.0-348.2.1.el8_5.x86_64" +} diff --git a/test/units/module_utils/facts/system/distribution/fixtures/tencentos_3_1.json b/test/units/module_utils/facts/system/distribution/fixtures/tencentos_3_1.json new file mode 100644 index 00000000..f1051dd6 --- /dev/null +++ b/test/units/module_utils/facts/system/distribution/fixtures/tencentos_3_1.json @@ -0,0 +1,50 @@ +{ + "name": "TencentOS 3.1", + "distro": { + "codename": "Final", + "id": "tencentos", + "name": "TencentOS Server", + "version": "3.1", + "version_best": "3.1", + "lsb_release_info": {}, + "os_release_info": { + "name": "TencentOS Server", + "version": "3.1 (Final)", + "id": "tencentos", + "id_like": "rhel fedora centos", + "version_id": "3.1", + "platform_id": "platform:el8", + "pretty_name": "TencentOS Server 3.1 (Final)", + "ansi_color": "0;31", + "cpe_name": "cpe:/o:tencentos:tencentos:3", + "home_url": "https://tlinux.qq.com/", + "bug_report_url": "https://tlinux.qq.com/", + "centos_mantisbt_project": "CentOS-8", + "centos_mantisbt_project_version": "8", + "redhat_support_product": "centos", + "redhat_support_product_version": "8", + "name_orig": "CentOS Linux", + "codename": "Final" + } + }, + "input": { + "/etc/centos-release": "NAME=\"TencentOS Server\"\nVERSION=\"3.1 (Final)\"\nID=\"tencentos\"\nID_LIKE=\"rhel fedora centos\"\nVERSION_ID=\"3.1\"\nPLATFORM_ID=\"platform:el8\"\nPRETTY_NAME=\"TencentOS Server 3.1 (Final)\"\nANSI_COLOR=\"0;31\"\nCPE_NAME=\"cpe:/o:tencentos:tencentos:3\"\nHOME_URL=\"https://tlinux.qq.com/\"\nBUG_REPORT_URL=\"https://tlinux.qq.com/\"\n\nCENTOS_MANTISBT_PROJECT=\"CentOS-8\"\nCENTOS_MANTISBT_PROJECT_VERSION=\"8\"\nREDHAT_SUPPORT_PRODUCT=\"centos\"\nREDHAT_SUPPORT_PRODUCT_VERSION=\"8\"\nNAME_ORIG=\"CentOS Linux\"\n", + "/etc/redhat-release": "CentOS Linux release 8.4.2105 (Core)\n", + "/etc/system-release": "NAME=\"TencentOS Server\"\nVERSION=\"3.1 (Final)\"\nID=\"tencentos\"\nID_LIKE=\"rhel fedora centos\"\nVERSION_ID=\"3.1\"\nPLATFORM_ID=\"platform:el8\"\nPRETTY_NAME=\"TencentOS Server 3.1 (Final)\"\nANSI_COLOR=\"0;31\"\nCPE_NAME=\"cpe:/o:tencentos:tencentos:3\"\nHOME_URL=\"https://tlinux.qq.com/\"\nBUG_REPORT_URL=\"https://tlinux.qq.com/\"\n\nCENTOS_MANTISBT_PROJECT=\"CentOS-8\"\nCENTOS_MANTISBT_PROJECT_VERSION=\"8\"\nREDHAT_SUPPORT_PRODUCT=\"centos\"\nREDHAT_SUPPORT_PRODUCT_VERSION=\"8\"\nNAME_ORIG=\"CentOS Linux\"\n", + "/etc/os-release": "NAME=\"TencentOS Server\"\nVERSION=\"3.1 (Final)\"\nID=\"tencentos\"\nID_LIKE=\"rhel fedora centos\"\nVERSION_ID=\"3.1\"\nPLATFORM_ID=\"platform:el8\"\nPRETTY_NAME=\"TencentOS Server 3.1 (Final)\"\nANSI_COLOR=\"0;31\"\nCPE_NAME=\"cpe:/o:tencentos:tencentos:3\"\nHOME_URL=\"https://tlinux.qq.com/\"\nBUG_REPORT_URL=\"https://tlinux.qq.com/\"\n\nCENTOS_MANTISBT_PROJECT=\"CentOS-8\"\nCENTOS_MANTISBT_PROJECT_VERSION=\"8\"\nREDHAT_SUPPORT_PRODUCT=\"centos\"\nREDHAT_SUPPORT_PRODUCT_VERSION=\"8\"\nNAME_ORIG=\"CentOS Linux\"\n", + "/usr/lib/os-release": "NAME=\"CentOS Linux\"\nVERSION=\"8\"\nID=\"centos\"\nID_LIKE=\"rhel fedora\"\nVERSION_ID=\"8\"\nPLATFORM_ID=\"platform:el8\"\nPRETTY_NAME=\"CentOS Linux 8\"\nANSI_COLOR=\"0;31\"\nCPE_NAME=\"cpe:/o:centos:centos:8\"\nHOME_URL=\"https://centos.org/\"\nBUG_REPORT_URL=\"https://bugs.centos.org/\"\nCENTOS_MANTISBT_PROJECT=\"CentOS-8\"\nCENTOS_MANTISBT_PROJECT_VERSION=\"8\"\n" + }, + "platform.dist": [ + "tencentos", + "3.1", + "Final" + ], + "result": { + "distribution": "TencentOS", + "distribution_version": "3.1", + "distribution_release": "Final", + "distribution_major_version": "3", + "os_family": "RedHat" + }, + "platform.release": "5.4.32-19-0001" +}
\ No newline at end of file diff --git a/test/units/module_utils/facts/system/distribution/fixtures/uos_20.json b/test/units/module_utils/facts/system/distribution/fixtures/uos_20.json new file mode 100644 index 00000000..d51f62de --- /dev/null +++ b/test/units/module_utils/facts/system/distribution/fixtures/uos_20.json @@ -0,0 +1,29 @@ +{ + "name": "Uos 20", + "distro": { + "codename": "fou", + "id": "Uos", + "name": "Uos", + "version": "20", + "version_best": "20", + "os_release_info": {}, + "lsb_release_info": {} + }, + "input": { + "/etc/os-release": "PRETTY_NAME=\"UnionTech OS Server 20\"\nNAME=\"UnionTech OS Server 20\"\nVERSION_ID=\"20\"\nVERSION=\"20\"\nID=UOS\nHOME_URL=\"https://www.chinauos.com/\"\nBUG_REPORT_URL=\"https://bbs.chinauos.com/\"\nVERSION_CODENAME=fou", + "/etc/lsb-release": "DISTRIB_ID=uos\nDISTRIB_RELEASE=20\nDISTRIB_DESCRIPTION=\"UnionTech OS Server 20\"\nDISTRIB_CODENAME=fou\n", + "/usr/lib/os-release": "PRETTY_NAME=\"UnionTech OS Server 20\"\nNAME=\"UnionTech OS Server 20\"\nVERSION_ID=\"20\"\nVERSION=\"20\"\nID=UOS\nHOME_URL=\"https://www.chinauos.com/\"\nBUG_REPORT_URL=\"https://bbs.chinauos.com/\"\nVERSION_CODENAME=fou" + }, + "platform.dist": [ + "uos", + "20", + "fou" + ], + "result": { + "distribution": "Uos", + "distribution_version": "20", + "distribution_release": "fou", + "distribution_major_version": "20", + "os_family": "Debian" + } +} diff --git a/test/units/module_utils/facts/system/test_lsb.py b/test/units/module_utils/facts/system/test_lsb.py index e2ed2ec0..890bddb6 100644 --- a/test/units/module_utils/facts/system/test_lsb.py +++ b/test/units/module_utils/facts/system/test_lsb.py @@ -19,7 +19,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -from units.compat.mock import Mock, patch +from mock import Mock, patch from .. base import BaseFactsTest diff --git a/test/units/module_utils/facts/test_ansible_collector.py b/test/units/module_utils/facts/test_ansible_collector.py index 47d88df9..e1d60c3d 100644 --- a/test/units/module_utils/facts/test_ansible_collector.py +++ b/test/units/module_utils/facts/test_ansible_collector.py @@ -21,7 +21,7 @@ __metaclass__ = type # for testing from units.compat import unittest -from units.compat.mock import Mock, patch +from mock import Mock, patch from ansible.module_utils.facts import collector from ansible.module_utils.facts import ansible_collector diff --git a/test/units/module_utils/facts/test_collector.py b/test/units/module_utils/facts/test_collector.py index 9eab89f7..4fc4bc5f 100644 --- a/test/units/module_utils/facts/test_collector.py +++ b/test/units/module_utils/facts/test_collector.py @@ -265,12 +265,12 @@ class TestGetCollectorNames(unittest.TestCase): valid_subsets = frozenset(['my_fact', 'something_else']) minimal_gather_subset = frozenset(['my_fact']) - self.assertRaisesRegexp(TypeError, - r'Bad subset .* given to Ansible.*allowed\:.*all,.*my_fact.*', - collector.get_collector_names, - valid_subsets=valid_subsets, - minimal_gather_subset=minimal_gather_subset, - gather_subset=['my_fact', 'not_a_valid_gather_subset']) + self.assertRaisesRegex(TypeError, + r'Bad subset .* given to Ansible.*allowed\:.*all,.*my_fact.*', + collector.get_collector_names, + valid_subsets=valid_subsets, + minimal_gather_subset=minimal_gather_subset, + gather_subset=['my_fact', 'not_a_valid_gather_subset']) class TestFindUnresolvedRequires(unittest.TestCase): @@ -349,10 +349,10 @@ class TestResolveRequires(unittest.TestCase): all_fact_subsets = {'env': [default_collectors.EnvFactCollector], 'network': [default_collectors.LinuxNetworkCollector], 'virtual': [default_collectors.LinuxVirtualCollector]} - self.assertRaisesRegexp(collector.UnresolvedFactDep, - 'unresolved fact dep.*required_thing2', - collector.resolve_requires, - unresolved, all_fact_subsets) + self.assertRaisesRegex(collector.UnresolvedFactDep, + 'unresolved fact dep.*required_thing2', + collector.resolve_requires, + unresolved, all_fact_subsets) def test(self): unresolved = ['env', 'network'] @@ -556,8 +556,8 @@ class TestCollectorClassesFromGatherSubset(unittest.TestCase): def test_unknown_collector(self): # something claims 'unknown_collector' is a valid gather_subset, but there is # no FactCollector mapped to 'unknown_collector' - self.assertRaisesRegexp(TypeError, - r'Bad subset.*unknown_collector.*given to Ansible.*allowed\:.*all,.*env.*', - self._classes, - all_collector_classes=default_collectors.collectors, - gather_subset=['env', 'unknown_collector']) + self.assertRaisesRegex(TypeError, + r'Bad subset.*unknown_collector.*given to Ansible.*allowed\:.*all,.*env.*', + self._classes, + all_collector_classes=default_collectors.collectors, + gather_subset=['env', 'unknown_collector']) diff --git a/test/units/module_utils/facts/test_collectors.py b/test/units/module_utils/facts/test_collectors.py index 5492582b..a6f12b56 100644 --- a/test/units/module_utils/facts/test_collectors.py +++ b/test/units/module_utils/facts/test_collectors.py @@ -19,7 +19,9 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -from units.compat.mock import Mock, patch +import pytest + +from mock import Mock, patch from . base import BaseFactsTest @@ -369,7 +371,8 @@ class TestServiceMgrFacts(BaseFactsTest): @patch('ansible.module_utils.facts.system.service_mgr.ServiceMgrFactCollector.is_systemd_managed', return_value=False) @patch('ansible.module_utils.facts.system.service_mgr.ServiceMgrFactCollector.is_systemd_managed_offline', return_value=False) @patch('ansible.module_utils.facts.system.service_mgr.os.path.exists', return_value=False) - def test_service_mgr_runit(self, mock_gfc, mock_ism, mock_ismo, mock_ope): + @pytest.mark.skip(reason='faulty test') + def test_service_mgr_runit_one(self, mock_gfc, mock_ism, mock_ismo, mock_ope): # no /proc/1/comm, ps returns non-0 # should fallback to 'service' module = self._mock_module() @@ -394,7 +397,8 @@ class TestServiceMgrFacts(BaseFactsTest): @patch('ansible.module_utils.facts.system.service_mgr.ServiceMgrFactCollector.is_systemd_managed', return_value=False) @patch('ansible.module_utils.facts.system.service_mgr.ServiceMgrFactCollector.is_systemd_managed_offline', return_value=False) @patch('ansible.module_utils.facts.system.service_mgr.os.path.exists', return_value=False) - def test_service_mgr_runit(self, mock_gfc, mock_ism, mock_ismo, mock_ope): + @pytest.mark.skip(reason='faulty test') + def test_service_mgr_runit_two(self, mock_gfc, mock_ism, mock_ismo, mock_ope): # no /proc/1/comm, ps fails, distro and system are clowncar # should end up return 'sys11' module = self._mock_module() diff --git a/test/units/module_utils/facts/test_facts.py b/test/units/module_utils/facts/test_facts.py index c794f031..a49616fc 100644 --- a/test/units/module_utils/facts/test_facts.py +++ b/test/units/module_utils/facts/test_facts.py @@ -26,7 +26,7 @@ import pytest # for testing from units.compat import unittest -from units.compat.mock import Mock, patch +from mock import Mock, patch from ansible.module_utils import facts from ansible.module_utils.facts import hardware diff --git a/test/units/module_utils/facts/test_sysctl.py b/test/units/module_utils/facts/test_sysctl.py index c369b610..66336925 100644 --- a/test/units/module_utils/facts/test_sysctl.py +++ b/test/units/module_utils/facts/test_sysctl.py @@ -26,7 +26,7 @@ import pytest # for testing from units.compat import unittest -from units.compat.mock import patch, MagicMock, mock_open, Mock +from mock import patch, MagicMock, mock_open, Mock from ansible.module_utils.facts.sysctl import get_sysctl diff --git a/test/units/module_utils/facts/test_utils.py b/test/units/module_utils/facts/test_utils.py index 28cb5d31..70db0475 100644 --- a/test/units/module_utils/facts/test_utils.py +++ b/test/units/module_utils/facts/test_utils.py @@ -18,7 +18,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type from units.compat import unittest -from units.compat.mock import patch +from mock import patch from ansible.module_utils.facts import utils diff --git a/test/units/module_utils/urls/test_RedirectHandlerFactory.py b/test/units/module_utils/urls/test_RedirectHandlerFactory.py index aa3500a1..7bbe4b5b 100644 --- a/test/units/module_utils/urls/test_RedirectHandlerFactory.py +++ b/test/units/module_utils/urls/test_RedirectHandlerFactory.py @@ -130,9 +130,11 @@ def test_redir_validate_certs(urllib_req, request_body, mocker): assert opener_mock.add_handler.call_count == int(not HAS_SSLCONTEXT) -def test_redir_http_error_308_urllib2(urllib_req, request_body): +def test_redir_http_error_308_urllib2(urllib_req, request_body, mocker): + redir_mock = mocker.patch.object(urllib_request.HTTPRedirectHandler, 'redirect_request') handler = RedirectHandlerFactory('urllib2', False) inst = handler() - with pytest.raises(urllib_error.HTTPError): - inst.redirect_request(urllib_req, request_body, 308, '308 Permanent Redirect', {}, 'https://docs.ansible.com/') + inst.redirect_request(urllib_req, request_body, 308, '308 Permanent Redirect', {}, 'https://docs.ansible.com/') + + assert redir_mock.call_count == 1 diff --git a/test/units/modules/test_apt.py b/test/units/modules/test_apt.py index 3daf3c11..78dbbade 100644 --- a/test/units/modules/test_apt.py +++ b/test/units/modules/test_apt.py @@ -4,7 +4,8 @@ __metaclass__ = type import collections import sys -from units.compat import mock +import mock + from units.compat import unittest try: diff --git a/test/units/modules/test_apt_key.py b/test/units/modules/test_apt_key.py index e348db0c..39339d76 100644 --- a/test/units/modules/test_apt_key.py +++ b/test/units/modules/test_apt_key.py @@ -3,7 +3,8 @@ __metaclass__ = type import os -from units.compat import mock +import mock + from units.compat import unittest from ansible.modules import apt_key diff --git a/test/units/modules/test_async_wrapper.py b/test/units/modules/test_async_wrapper.py index 37b1fda3..eacb9361 100644 --- a/test/units/modules/test_async_wrapper.py +++ b/test/units/modules/test_async_wrapper.py @@ -11,7 +11,7 @@ import tempfile import pytest -from units.compat.mock import patch, MagicMock +from mock import patch, MagicMock from ansible.modules import async_wrapper from pprint import pprint diff --git a/test/units/modules/test_hostname.py b/test/units/modules/test_hostname.py index 2771293e..804ecf74 100644 --- a/test/units/modules/test_hostname.py +++ b/test/units/modules/test_hostname.py @@ -1,7 +1,11 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -from units.compat.mock import patch, MagicMock, mock_open +import os +import shutil +import tempfile + +from mock import patch, MagicMock, mock_open from ansible.module_utils import basic from ansible.module_utils.common._utils import get_all_subclasses from ansible.modules import hostname @@ -33,3 +37,111 @@ class TestHostname(ModuleTestCase): self.assertFalse( m.return_value.write.called, msg='%s called write, should not have' % str(cls)) + + def test_all_named_strategies_exist(self): + """Loop through the STRATS and see if anything is missing.""" + for _name, prefix in hostname.STRATS.items(): + classname = "%sStrategy" % prefix + cls = getattr(hostname, classname, None) + + if cls is None: + self.assertFalse( + cls is None, "%s is None, should be a subclass" % classname + ) + else: + self.assertTrue(issubclass(cls, hostname.BaseStrategy)) + + +class TestRedhatStrategy(ModuleTestCase): + def setUp(self): + super(TestRedhatStrategy, self).setUp() + self.testdir = tempfile.mkdtemp(prefix='ansible-test-hostname-') + self.network_file = os.path.join(self.testdir, "network") + + def tearDown(self): + super(TestRedhatStrategy, self).tearDown() + shutil.rmtree(self.testdir, ignore_errors=True) + + @property + def instance(self): + self.module = MagicMock() + instance = hostname.RedHatStrategy(self.module) + instance.NETWORK_FILE = self.network_file + return instance + + def test_get_permanent_hostname_missing(self): + self.assertIsNone(self.instance.get_permanent_hostname()) + self.assertTrue(self.module.fail_json.called) + self.module.fail_json.assert_called_with( + "Unable to locate HOSTNAME entry in %s" % self.network_file + ) + + def test_get_permanent_hostname_line_missing(self): + with open(self.network_file, "w") as f: + f.write("# some other content\n") + self.assertIsNone(self.instance.get_permanent_hostname()) + self.module.fail_json.assert_called_with( + "Unable to locate HOSTNAME entry in %s" % self.network_file + ) + + def test_get_permanent_hostname_existing(self): + with open(self.network_file, "w") as f: + f.write( + "some other content\n" + "HOSTNAME=foobar\n" + "more content\n" + ) + self.assertEqual(self.instance.get_permanent_hostname(), "foobar") + + def test_get_permanent_hostname_existing_whitespace(self): + with open(self.network_file, "w") as f: + f.write( + "some other content\n" + " HOSTNAME=foobar \n" + "more content\n" + ) + self.assertEqual(self.instance.get_permanent_hostname(), "foobar") + + def test_set_permanent_hostname_missing(self): + self.instance.set_permanent_hostname("foobar") + with open(self.network_file) as f: + self.assertEqual(f.read(), "HOSTNAME=foobar\n") + + def test_set_permanent_hostname_line_missing(self): + with open(self.network_file, "w") as f: + f.write("# some other content\n") + self.instance.set_permanent_hostname("foobar") + with open(self.network_file) as f: + self.assertEqual(f.read(), "# some other content\nHOSTNAME=foobar\n") + + def test_set_permanent_hostname_existing(self): + with open(self.network_file, "w") as f: + f.write( + "some other content\n" + "HOSTNAME=spam\n" + "more content\n" + ) + self.instance.set_permanent_hostname("foobar") + with open(self.network_file) as f: + self.assertEqual( + f.read(), + "some other content\n" + "HOSTNAME=foobar\n" + "more content\n" + ) + + def test_set_permanent_hostname_existing_whitespace(self): + with open(self.network_file, "w") as f: + f.write( + "some other content\n" + " HOSTNAME=spam \n" + "more content\n" + ) + self.instance.set_permanent_hostname("foobar") + with open(self.network_file) as f: + self.assertEqual( + f.read(), + "some other content\n" + "HOSTNAME=foobar\n" + "more content\n" + ) diff --git a/test/units/modules/test_iptables.py b/test/units/modules/test_iptables.py index 5a55434f..5953334b 100644 --- a/test/units/modules/test_iptables.py +++ b/test/units/modules/test_iptables.py @@ -1,7 +1,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -from units.compat.mock import patch +from mock import patch from ansible.module_utils import basic from ansible.modules import iptables from units.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase, set_module_args @@ -171,8 +171,8 @@ class TestIptables(ModuleTestCase): }) commands_results = [ - (1, '', ''), - (0, '', '') + (1, '', ''), # check_rule_present + (0, '', ''), # check_chain_present ] with patch.object(basic.AnsibleModule, 'run_command') as run_command: @@ -181,7 +181,7 @@ class TestIptables(ModuleTestCase): iptables.main() self.assertTrue(result.exception.args[0]['changed']) - self.assertEqual(run_command.call_count, 1) + self.assertEqual(run_command.call_count, 2) self.assertEqual(run_command.call_args_list[0][0][0], [ '/sbin/iptables', '-t', @@ -207,8 +207,9 @@ class TestIptables(ModuleTestCase): }) commands_results = [ - (1, '', ''), - (0, '', '') + (1, '', ''), # check_rule_present + (0, '', ''), # check_chain_present + (0, '', ''), ] with patch.object(basic.AnsibleModule, 'run_command') as run_command: @@ -217,7 +218,7 @@ class TestIptables(ModuleTestCase): iptables.main() self.assertTrue(result.exception.args[0]['changed']) - self.assertEqual(run_command.call_count, 2) + self.assertEqual(run_command.call_count, 3) self.assertEqual(run_command.call_args_list[0][0][0], [ '/sbin/iptables', '-t', @@ -231,7 +232,7 @@ class TestIptables(ModuleTestCase): '-j', 'ACCEPT' ]) - self.assertEqual(run_command.call_args_list[1][0][0], [ + self.assertEqual(run_command.call_args_list[2][0][0], [ '/sbin/iptables', '-t', 'filter', @@ -261,7 +262,8 @@ class TestIptables(ModuleTestCase): }) commands_results = [ - (1, '', ''), + (1, '', ''), # check_rule_present + (0, '', ''), # check_chain_present ] with patch.object(basic.AnsibleModule, 'run_command') as run_command: @@ -270,7 +272,7 @@ class TestIptables(ModuleTestCase): iptables.main() self.assertTrue(result.exception.args[0]['changed']) - self.assertEqual(run_command.call_count, 1) + self.assertEqual(run_command.call_count, 2) self.assertEqual(run_command.call_args_list[0][0][0], [ '/sbin/iptables', '-t', @@ -308,8 +310,9 @@ class TestIptables(ModuleTestCase): }) commands_results = [ - (1, '', ''), - (0, '', '') + (1, '', ''), # check_rule_present + (0, '', ''), # check_chain_present + (0, '', ''), ] with patch.object(basic.AnsibleModule, 'run_command') as run_command: @@ -318,7 +321,7 @@ class TestIptables(ModuleTestCase): iptables.main() self.assertTrue(result.exception.args[0]['changed']) - self.assertEqual(run_command.call_count, 2) + self.assertEqual(run_command.call_count, 3) self.assertEqual(run_command.call_args_list[0][0][0], [ '/sbin/iptables', '-t', @@ -340,7 +343,7 @@ class TestIptables(ModuleTestCase): '--to-ports', '8600' ]) - self.assertEqual(run_command.call_args_list[1][0][0], [ + self.assertEqual(run_command.call_args_list[2][0][0], [ '/sbin/iptables', '-t', 'nat', @@ -1006,3 +1009,184 @@ class TestIptables(ModuleTestCase): '-m', 'set', '--match-set', 'banned_hosts', 'src,dst' ]) + + def test_chain_creation(self): + """Test chain creation when absent""" + set_module_args({ + 'chain': 'FOOBAR', + 'state': 'present', + 'chain_management': True, + }) + + commands_results = [ + (1, '', ''), # check_rule_present + (1, '', ''), # check_chain_present + (0, '', ''), # create_chain + (0, '', ''), # append_rule + ] + + with patch.object(basic.AnsibleModule, 'run_command') as run_command: + run_command.side_effect = commands_results + with self.assertRaises(AnsibleExitJson) as result: + iptables.main() + self.assertTrue(result.exception.args[0]['changed']) + + self.assertEqual(run_command.call_count, 4) + + self.assertEqual(run_command.call_args_list[0][0][0], [ + '/sbin/iptables', + '-t', 'filter', + '-C', 'FOOBAR', + ]) + + self.assertEqual(run_command.call_args_list[1][0][0], [ + '/sbin/iptables', + '-t', 'filter', + '-L', 'FOOBAR', + ]) + + self.assertEqual(run_command.call_args_list[2][0][0], [ + '/sbin/iptables', + '-t', 'filter', + '-N', 'FOOBAR', + ]) + + self.assertEqual(run_command.call_args_list[3][0][0], [ + '/sbin/iptables', + '-t', 'filter', + '-A', 'FOOBAR', + ]) + + commands_results = [ + (0, '', ''), # check_rule_present + ] + + with patch.object(basic.AnsibleModule, 'run_command') as run_command: + run_command.side_effect = commands_results + with self.assertRaises(AnsibleExitJson) as result: + iptables.main() + self.assertFalse(result.exception.args[0]['changed']) + + def test_chain_creation_check_mode(self): + """Test chain creation when absent""" + set_module_args({ + 'chain': 'FOOBAR', + 'state': 'present', + 'chain_management': True, + '_ansible_check_mode': True, + }) + + commands_results = [ + (1, '', ''), # check_rule_present + (1, '', ''), # check_chain_present + ] + + with patch.object(basic.AnsibleModule, 'run_command') as run_command: + run_command.side_effect = commands_results + with self.assertRaises(AnsibleExitJson) as result: + iptables.main() + self.assertTrue(result.exception.args[0]['changed']) + + self.assertEqual(run_command.call_count, 2) + + self.assertEqual(run_command.call_args_list[0][0][0], [ + '/sbin/iptables', + '-t', 'filter', + '-C', 'FOOBAR', + ]) + + self.assertEqual(run_command.call_args_list[1][0][0], [ + '/sbin/iptables', + '-t', 'filter', + '-L', 'FOOBAR', + ]) + + commands_results = [ + (0, '', ''), # check_rule_present + ] + + with patch.object(basic.AnsibleModule, 'run_command') as run_command: + run_command.side_effect = commands_results + with self.assertRaises(AnsibleExitJson) as result: + iptables.main() + self.assertFalse(result.exception.args[0]['changed']) + + def test_chain_deletion(self): + """Test chain deletion when present""" + set_module_args({ + 'chain': 'FOOBAR', + 'state': 'absent', + 'chain_management': True, + }) + + commands_results = [ + (0, '', ''), # check_chain_present + (0, '', ''), # delete_chain + ] + + with patch.object(basic.AnsibleModule, 'run_command') as run_command: + run_command.side_effect = commands_results + with self.assertRaises(AnsibleExitJson) as result: + iptables.main() + self.assertTrue(result.exception.args[0]['changed']) + + self.assertEqual(run_command.call_count, 2) + + self.assertEqual(run_command.call_args_list[0][0][0], [ + '/sbin/iptables', + '-t', 'filter', + '-L', 'FOOBAR', + ]) + + self.assertEqual(run_command.call_args_list[1][0][0], [ + '/sbin/iptables', + '-t', 'filter', + '-X', 'FOOBAR', + ]) + + commands_results = [ + (1, '', ''), # check_rule_present + ] + + with patch.object(basic.AnsibleModule, 'run_command') as run_command: + run_command.side_effect = commands_results + with self.assertRaises(AnsibleExitJson) as result: + iptables.main() + self.assertFalse(result.exception.args[0]['changed']) + + def test_chain_deletion_check_mode(self): + """Test chain deletion when present""" + set_module_args({ + 'chain': 'FOOBAR', + 'state': 'absent', + 'chain_management': True, + '_ansible_check_mode': True, + }) + + commands_results = [ + (0, '', ''), # check_chain_present + ] + + with patch.object(basic.AnsibleModule, 'run_command') as run_command: + run_command.side_effect = commands_results + with self.assertRaises(AnsibleExitJson) as result: + iptables.main() + self.assertTrue(result.exception.args[0]['changed']) + + self.assertEqual(run_command.call_count, 1) + + self.assertEqual(run_command.call_args_list[0][0][0], [ + '/sbin/iptables', + '-t', 'filter', + '-L', 'FOOBAR', + ]) + + commands_results = [ + (1, '', ''), # check_rule_present + ] + + with patch.object(basic.AnsibleModule, 'run_command') as run_command: + run_command.side_effect = commands_results + with self.assertRaises(AnsibleExitJson) as result: + iptables.main() + self.assertFalse(result.exception.args[0]['changed']) diff --git a/test/units/modules/test_service_facts.py b/test/units/modules/test_service_facts.py index 07f6827e..3a180dc9 100644 --- a/test/units/modules/test_service_facts.py +++ b/test/units/modules/test_service_facts.py @@ -6,7 +6,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type from units.compat import unittest -from units.compat.mock import patch +from mock import patch from ansible.module_utils import basic from ansible.modules.service_facts import AIXScanService diff --git a/test/units/modules/utils.py b/test/units/modules/utils.py index 6d169e36..92f4ceab 100644 --- a/test/units/modules/utils.py +++ b/test/units/modules/utils.py @@ -4,7 +4,7 @@ __metaclass__ = type import json from units.compat import unittest -from units.compat.mock import patch +from mock import patch from ansible.module_utils import basic from ansible.module_utils._text import to_bytes diff --git a/test/units/parsing/test_ajson.py b/test/units/parsing/test_ajson.py index c38f43ea..55e758e2 100644 --- a/test/units/parsing/test_ajson.py +++ b/test/units/parsing/test_ajson.py @@ -10,10 +10,10 @@ import json import pytest +from collections.abc import Mapping from datetime import date, datetime from pytz import timezone as tz -from ansible.module_utils.common._collections_compat import Mapping from ansible.parsing.ajson import AnsibleJSONEncoder, AnsibleJSONDecoder from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode from ansible.utils.unsafe_proxy import AnsibleUnsafeText diff --git a/test/units/parsing/test_dataloader.py b/test/units/parsing/test_dataloader.py index 3cc8d451..ed365b13 100644 --- a/test/units/parsing/test_dataloader.py +++ b/test/units/parsing/test_dataloader.py @@ -22,7 +22,7 @@ __metaclass__ = type import os from units.compat import unittest -from units.compat.mock import patch, mock_open +from mock import patch, mock_open from ansible.errors import AnsibleParserError, yaml_strings, AnsibleFileNotFound from ansible.parsing.vault import AnsibleVaultError from ansible.module_utils._text import to_text @@ -138,8 +138,8 @@ class TestDataLoader(unittest.TestCase): self.assertTrue(self._loader.is_directory(os.path.dirname(__file__))) def test_get_file_contents_none_path(self): - self.assertRaisesRegexp(AnsibleParserError, 'Invalid filename', - self._loader._get_file_contents, None) + self.assertRaisesRegex(AnsibleParserError, 'Invalid filename', + self._loader._get_file_contents, None) def test_get_file_contents_non_existent_path(self): self.assertRaises(AnsibleFileNotFound, self._loader._get_file_contents, '/non_existent_file') @@ -169,7 +169,7 @@ class TestPathDwimRelativeStackDataLoader(unittest.TestCase): self._loader = DataLoader() def test_none(self): - self.assertRaisesRegexp(AnsibleFileNotFound, 'on the Ansible Controller', self._loader.path_dwim_relative_stack, None, None, None) + self.assertRaisesRegex(AnsibleFileNotFound, 'on the Ansible Controller', self._loader.path_dwim_relative_stack, None, None, None) def test_empty_strings(self): self.assertEqual(self._loader.path_dwim_relative_stack('', '', ''), './') @@ -218,7 +218,7 @@ class TestDataLoaderWithVault(unittest.TestCase): self.assertRaises(AnsibleVaultError, self._loader.get_real_file, self.test_vault_data_path) def test_get_real_file_not_a_path(self): - self.assertRaisesRegexp(AnsibleParserError, 'Invalid filename', self._loader.get_real_file, None) + self.assertRaisesRegex(AnsibleParserError, 'Invalid filename', self._loader.get_real_file, None) @patch.multiple(DataLoader, path_exists=lambda s, x: True, is_file=lambda s, x: True) def test_parse_from_vault_1_1_file(self): diff --git a/test/units/parsing/test_mod_args.py b/test/units/parsing/test_mod_args.py index 50c3b331..5d3f5d25 100644 --- a/test/units/parsing/test_mod_args.py +++ b/test/units/parsing/test_mod_args.py @@ -118,7 +118,7 @@ class TestModArgsDwim: assert err.value.args[0] == msg - def test_multiple_actions(self): + def test_multiple_actions_ping_shell(self): args_dict = {'ping': 'data=hi', 'shell': 'echo hi'} m = ModuleArgsParser(args_dict) with pytest.raises(AnsibleParserError) as err: diff --git a/test/units/parsing/vault/test_vault.py b/test/units/parsing/vault/test_vault.py index 0a9e395b..f92d451c 100644 --- a/test/units/parsing/vault/test_vault.py +++ b/test/units/parsing/vault/test_vault.py @@ -30,7 +30,7 @@ from binascii import hexlify import pytest from units.compat import unittest -from units.compat.mock import patch, MagicMock +from mock import patch, MagicMock from ansible import errors from ansible.module_utils import six @@ -51,18 +51,18 @@ class TestUnhexlify(unittest.TestCase): def test_odd_length(self): b_data = b'123456789abcdefghijklmnopqrstuvwxyz' - self.assertRaisesRegexp(vault.AnsibleVaultFormatError, - '.*Vault format unhexlify error.*', - vault._unhexlify, - b_data) + self.assertRaisesRegex(vault.AnsibleVaultFormatError, + '.*Vault format unhexlify error.*', + vault._unhexlify, + b_data) def test_nonhex(self): b_data = b'6z36316566653264333665333637623064303639353237620a636366633565663263336335656532' - self.assertRaisesRegexp(vault.AnsibleVaultFormatError, - '.*Vault format unhexlify error.*Non-hexadecimal digit found', - vault._unhexlify, - b_data) + self.assertRaisesRegex(vault.AnsibleVaultFormatError, + '.*Vault format unhexlify error.*Non-hexadecimal digit found', + vault._unhexlify, + b_data) class TestParseVaulttext(unittest.TestCase): @@ -91,10 +91,10 @@ class TestParseVaulttext(unittest.TestCase): b_vaulttext_envelope = to_bytes(vaulttext_envelope, errors='strict', encoding='utf-8') b_vaulttext, b_version, cipher_name, vault_id = vault.parse_vaulttext_envelope(b_vaulttext_envelope) - self.assertRaisesRegexp(vault.AnsibleVaultFormatError, - '.*Vault format unhexlify error.*Non-hexadecimal digit found', - vault.parse_vaulttext, - b_vaulttext_envelope) + self.assertRaisesRegex(vault.AnsibleVaultFormatError, + '.*Vault format unhexlify error.*Non-hexadecimal digit found', + vault.parse_vaulttext, + b_vaulttext_envelope) class TestVaultSecret(unittest.TestCase): @@ -133,18 +133,18 @@ class TestPromptVaultSecret(unittest.TestCase): @patch('ansible.parsing.vault.display.prompt', side_effect=EOFError) def test_prompt_eoferror(self, mock_display_prompt): secret = vault.PromptVaultSecret(vault_id='test_id') - self.assertRaisesRegexp(vault.AnsibleVaultError, - 'EOFError.*test_id', - secret.load) + self.assertRaisesRegex(vault.AnsibleVaultError, + 'EOFError.*test_id', + secret.load) @patch('ansible.parsing.vault.display.prompt', side_effect=['first_password', 'second_password']) def test_prompt_passwords_dont_match(self, mock_display_prompt): secret = vault.PromptVaultSecret(vault_id='test_id', prompt_formats=['Vault password: ', 'Confirm Vault password: ']) - self.assertRaisesRegexp(errors.AnsibleError, - 'Passwords do not match', - secret.load) + self.assertRaisesRegex(errors.AnsibleError, + 'Passwords do not match', + secret.load) class TestFileVaultSecret(unittest.TestCase): @@ -200,9 +200,9 @@ class TestFileVaultSecret(unittest.TestCase): fake_loader = DictDataLoader({tmp_file.name: ''}) secret = vault.FileVaultSecret(loader=fake_loader, filename=tmp_file.name) - self.assertRaisesRegexp(vault.AnsibleVaultPasswordError, - 'Invalid vault password was provided from file.*%s' % tmp_file.name, - secret.load) + self.assertRaisesRegex(vault.AnsibleVaultPasswordError, + 'Invalid vault password was provided from file.*%s' % tmp_file.name, + secret.load) os.unlink(tmp_file.name) @@ -241,9 +241,9 @@ class TestFileVaultSecret(unittest.TestCase): fake_loader = DictDataLoader({filename: 'sdfadf'}) secret = vault.FileVaultSecret(loader=fake_loader, filename=filename) - self.assertRaisesRegexp(errors.AnsibleError, - '.*Could not read vault password file.*/dev/null/foobar.*Not a directory', - secret.load) + self.assertRaisesRegex(errors.AnsibleError, + '.*Could not read vault password file.*/dev/null/foobar.*Not a directory', + secret.load) def test_file_not_found(self): tmp_file = tempfile.NamedTemporaryFile() @@ -253,9 +253,9 @@ class TestFileVaultSecret(unittest.TestCase): fake_loader = DictDataLoader({filename: 'sdfadf'}) secret = vault.FileVaultSecret(loader=fake_loader, filename=filename) - self.assertRaisesRegexp(errors.AnsibleError, - '.*Could not read vault password file.*%s.*' % filename, - secret.load) + self.assertRaisesRegex(errors.AnsibleError, + '.*Could not read vault password file.*%s.*' % filename, + secret.load) class TestScriptVaultSecret(unittest.TestCase): @@ -285,9 +285,9 @@ class TestScriptVaultSecret(unittest.TestCase): secret = vault.ScriptVaultSecret() with patch.object(secret, 'loader') as mock_loader: mock_loader.is_executable = MagicMock(return_value=True) - self.assertRaisesRegexp(vault.AnsibleVaultPasswordError, - 'Invalid vault password was provided from script', - secret.load) + self.assertRaisesRegex(vault.AnsibleVaultPasswordError, + 'Invalid vault password was provided from script', + secret.load) @patch('ansible.parsing.vault.subprocess.Popen') def test_read_file_os_error(self, mock_popen): @@ -296,9 +296,9 @@ class TestScriptVaultSecret(unittest.TestCase): secret = vault.ScriptVaultSecret() with patch.object(secret, 'loader') as mock_loader: mock_loader.is_executable = MagicMock(return_value=True) - self.assertRaisesRegexp(errors.AnsibleError, - 'Problem running vault password script.*', - secret.load) + self.assertRaisesRegex(errors.AnsibleError, + 'Problem running vault password script.*', + secret.load) @patch('ansible.parsing.vault.subprocess.Popen') def test_read_file_not_executable(self, mock_popen): @@ -306,9 +306,9 @@ class TestScriptVaultSecret(unittest.TestCase): secret = vault.ScriptVaultSecret() with patch.object(secret, 'loader') as mock_loader: mock_loader.is_executable = MagicMock(return_value=False) - self.assertRaisesRegexp(vault.AnsibleVaultError, - 'The vault password script .* was not executable', - secret.load) + self.assertRaisesRegex(vault.AnsibleVaultError, + 'The vault password script .* was not executable', + secret.load) @patch('ansible.parsing.vault.subprocess.Popen') def test_read_file_non_zero_return_code(self, mock_popen): @@ -319,9 +319,9 @@ class TestScriptVaultSecret(unittest.TestCase): secret = vault.ScriptVaultSecret(filename='/dev/null/some_vault_secret') with patch.object(secret, 'loader') as mock_loader: mock_loader.is_executable = MagicMock(return_value=True) - self.assertRaisesRegexp(errors.AnsibleError, - r'Vault password script.*returned non-zero \(%s\): %s' % (rc, stderr), - secret.load) + self.assertRaisesRegex(errors.AnsibleError, + r'Vault password script.*returned non-zero \(%s\): %s' % (rc, stderr), + secret.load) class TestScriptIsClient(unittest.TestCase): @@ -382,11 +382,11 @@ class TestGetFileVaultSecret(unittest.TestCase): filename = '/dev/null/foobar' fake_loader = DictDataLoader({filename: 'sdfadf'}) - self.assertRaisesRegexp(errors.AnsibleError, - '.*The vault password file %s was not found.*' % filename, - vault.get_file_vault_secret, - filename=filename, - loader=fake_loader) + self.assertRaisesRegex(errors.AnsibleError, + '.*The vault password file %s was not found.*' % filename, + vault.get_file_vault_secret, + filename=filename, + loader=fake_loader) def test_file_not_found(self): tmp_file = tempfile.NamedTemporaryFile() @@ -395,11 +395,11 @@ class TestGetFileVaultSecret(unittest.TestCase): fake_loader = DictDataLoader({filename: 'sdfadf'}) - self.assertRaisesRegexp(errors.AnsibleError, - '.*The vault password file %s was not found.*' % filename, - vault.get_file_vault_secret, - filename=filename, - loader=fake_loader) + self.assertRaisesRegex(errors.AnsibleError, + '.*The vault password file %s was not found.*' % filename, + vault.get_file_vault_secret, + filename=filename, + loader=fake_loader) class TestVaultIsEncrypted(unittest.TestCase): @@ -645,10 +645,10 @@ class TestVaultLib(unittest.TestCase): v = vault.VaultLib(vault_secrets) plaintext = u'Some text to encrypt in a café' - self.assertRaisesRegexp(vault.AnsibleVaultError, - '.*A vault password must be specified to encrypt data.*', - v.encrypt, - plaintext) + self.assertRaisesRegex(vault.AnsibleVaultError, + '.*A vault password must be specified to encrypt data.*', + v.encrypt, + plaintext) def test_format_vaulttext_envelope(self): cipher_name = "TEST" @@ -712,10 +712,10 @@ class TestVaultLib(unittest.TestCase): v_none = vault.VaultLib(None) # so set secrets None explicitly v_none.secrets = None - self.assertRaisesRegexp(vault.AnsibleVaultError, - '.*A vault password must be specified to decrypt data.*', - v_none.decrypt, - b_vaulttext) + self.assertRaisesRegex(vault.AnsibleVaultError, + '.*A vault password must be specified to decrypt data.*', + v_none.decrypt, + b_vaulttext) def test_encrypt_decrypt_aes256_empty_secrets(self): vault_secrets = self._vault_secrets_from_password('default', 'ansible') @@ -727,10 +727,10 @@ class TestVaultLib(unittest.TestCase): vault_secrets_empty = [] v_none = vault.VaultLib(vault_secrets_empty) - self.assertRaisesRegexp(vault.AnsibleVaultError, - '.*Attempting to decrypt but no vault secrets found.*', - v_none.decrypt, - b_vaulttext) + self.assertRaisesRegex(vault.AnsibleVaultError, + '.*Attempting to decrypt but no vault secrets found.*', + v_none.decrypt, + b_vaulttext) def test_encrypt_decrypt_aes256_multiple_secrets_all_wrong(self): plaintext = u'Some text to encrypt in a café' @@ -740,11 +740,11 @@ class TestVaultLib(unittest.TestCase): ('wrong-password', TextVaultSecret('wrong-password'))] v_multi = vault.VaultLib(vault_secrets) - self.assertRaisesRegexp(errors.AnsibleError, - '.*Decryption failed.*', - v_multi.decrypt, - b_vaulttext, - filename='/dev/null/fake/filename') + self.assertRaisesRegex(errors.AnsibleError, + '.*Decryption failed.*', + v_multi.decrypt, + b_vaulttext, + filename='/dev/null/fake/filename') def test_encrypt_decrypt_aes256_multiple_secrets_one_valid(self): plaintext = u'Some text to encrypt in a café' diff --git a/test/units/parsing/vault/test_vault_editor.py b/test/units/parsing/vault/test_vault_editor.py index 1483bb52..3f19b893 100644 --- a/test/units/parsing/vault/test_vault_editor.py +++ b/test/units/parsing/vault/test_vault_editor.py @@ -27,7 +27,7 @@ from io import BytesIO, StringIO import pytest from units.compat import unittest -from units.compat.mock import patch +from mock import patch from ansible import errors from ansible.parsing import vault @@ -142,11 +142,11 @@ class TestVaultEditor(unittest.TestCase): ve = self._vault_editor() - self.assertRaisesRegexp(errors.AnsibleError, - error_txt, - ve._edit_file_helper, - src_file_path, - self.vault_secret) + self.assertRaisesRegex(errors.AnsibleError, + error_txt, + ve._edit_file_helper, + src_file_path, + self.vault_secret) @patch('ansible.parsing.vault.subprocess.call') def test_edit_file_helper_symlink_target(self, mock_sp_call): @@ -249,11 +249,11 @@ class TestVaultEditor(unittest.TestCase): ve = self._vault_editor() ve.encrypt_file(src_file_path, self.vault_secret) - self.assertRaisesRegexp(errors.AnsibleError, - 'The value for the new_password to rekey', - ve.rekey_file, - src_file_path, - None) + self.assertRaisesRegex(errors.AnsibleError, + 'The value for the new_password to rekey', + ve.rekey_file, + src_file_path, + None) def test_rekey_file_not_encrypted(self): self._test_dir = self._create_test_dir() @@ -264,10 +264,10 @@ class TestVaultEditor(unittest.TestCase): ve = self._vault_editor() new_password = 'password2:electricbugaloo' - self.assertRaisesRegexp(errors.AnsibleError, - 'input is not vault encrypted data', - ve.rekey_file, - src_file_path, new_password) + self.assertRaisesRegex(errors.AnsibleError, + 'input is not vault encrypted data', + ve.rekey_file, + src_file_path, new_password) def test_plaintext(self): self._test_dir = self._create_test_dir() @@ -288,10 +288,10 @@ class TestVaultEditor(unittest.TestCase): src_file_path = self._create_file(self._test_dir, 'src_file', content=src_file_contents) ve = self._vault_editor() - self.assertRaisesRegexp(errors.AnsibleError, - 'input is not vault encrypted data', - ve.plaintext, - src_file_path) + self.assertRaisesRegex(errors.AnsibleError, + 'input is not vault encrypted data', + ve.plaintext, + src_file_path) def test_encrypt_file(self): self._test_dir = self._create_test_dir() @@ -426,10 +426,10 @@ class TestVaultEditor(unittest.TestCase): mock_sp_call.side_effect = faux_editor ve = self._vault_editor() - self.assertRaisesRegexp(errors.AnsibleError, - 'input is not vault encrypted data', - ve.edit_file, - src_file_path) + self.assertRaisesRegex(errors.AnsibleError, + 'input is not vault encrypted data', + ve.edit_file, + src_file_path) def test_create_file_exists(self): self._test_dir = self._create_test_dir() @@ -437,11 +437,11 @@ class TestVaultEditor(unittest.TestCase): src_file_path = self._create_file(self._test_dir, 'src_file', content=src_contents) ve = self._vault_editor() - self.assertRaisesRegexp(errors.AnsibleError, - 'please use .edit. instead', - ve.create_file, - src_file_path, - self.vault_secret) + self.assertRaisesRegex(errors.AnsibleError, + 'please use .edit. instead', + ve.create_file, + src_file_path, + self.vault_secret) def test_decrypt_file_exception(self): self._test_dir = self._create_test_dir() @@ -449,10 +449,10 @@ class TestVaultEditor(unittest.TestCase): src_file_path = self._create_file(self._test_dir, 'src_file', content=src_contents) ve = self._vault_editor() - self.assertRaisesRegexp(errors.AnsibleError, - 'input is not vault encrypted data', - ve.decrypt_file, - src_file_path) + self.assertRaisesRegex(errors.AnsibleError, + 'input is not vault encrypted data', + ve.decrypt_file, + src_file_path) @patch.object(vault.VaultEditor, '_editor_shell_command') def test_create_file(self, mock_editor_shell_command): diff --git a/test/units/parsing/yaml/test_loader.py b/test/units/parsing/yaml/test_loader.py index fbe69a97..117f80a7 100644 --- a/test/units/parsing/yaml/test_loader.py +++ b/test/units/parsing/yaml/test_loader.py @@ -20,13 +20,13 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type +from collections.abc import Sequence, Set, Mapping from io import StringIO from units.compat import unittest from ansible import errors from ansible.module_utils.six import text_type, binary_type -from ansible.module_utils.common._collections_compat import Sequence, Set, Mapping from ansible.parsing.yaml.loader import AnsibleLoader from ansible.parsing import vault from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode @@ -280,11 +280,11 @@ class TestAnsibleLoaderVault(unittest.TestCase, YamlTestUtils): different_vault_string = data_from_yaml['different_secret'] self.assertEqual(vault_string, another_vault_string) - self.assertNotEquals(vault_string, different_vault_string) + self.assertNotEqual(vault_string, different_vault_string) # More testing of __eq__/__ne__ self.assertTrue('some string' != vault_string) - self.assertNotEquals('some string', vault_string) + self.assertNotEqual('some string', vault_string) # Note this is a compare of the str/unicode of these, they are different types # so we want to test self == other, and other == self etc diff --git a/test/units/parsing/yaml/test_objects.py b/test/units/parsing/yaml/test_objects.py index d4529eed..f64b708f 100644 --- a/test/units/parsing/yaml/test_objects.py +++ b/test/units/parsing/yaml/test_objects.py @@ -52,7 +52,7 @@ class TestAnsibleVaultUnicodeNoVault(unittest.TestCase, YamlTestUtils): self.assertIsInstance(avu, objects.AnsibleVaultEncryptedUnicode) self.assertTrue(avu.vault is None) # AnsibleVaultEncryptedUnicode without a vault should never == any string - self.assertNotEquals(avu, seq) + self.assertNotEqual(avu, seq) def assert_values(self, seq): avu = objects.AnsibleVaultEncryptedUnicode(seq) diff --git a/test/units/playbook/role/test_include_role.py b/test/units/playbook/role/test_include_role.py index 7a04b35f..79821b40 100644 --- a/test/units/playbook/role/test_include_role.py +++ b/test/units/playbook/role/test_include_role.py @@ -20,7 +20,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type from units.compat import unittest -from units.compat.mock import patch +from mock import patch from ansible.playbook import Play from ansible.playbook.role_include import IncludeRole diff --git a/test/units/playbook/role/test_role.py b/test/units/playbook/role/test_role.py index 3aa30b8b..dacbc79c 100644 --- a/test/units/playbook/role/test_role.py +++ b/test/units/playbook/role/test_role.py @@ -19,11 +19,12 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type +from collections.abc import Container + from units.compat import unittest -from units.compat.mock import patch, MagicMock +from mock import patch, MagicMock from ansible.errors import AnsibleError, AnsibleParserError -from ansible.module_utils.common._collections_compat import Container from ansible.playbook.block import Block from units.mock.loader import DictDataLoader diff --git a/test/units/playbook/test_base.py b/test/units/playbook/test_base.py index 648200af..de3412e5 100644 --- a/test/units/playbook/test_base.py +++ b/test/units/playbook/test_base.py @@ -480,7 +480,7 @@ class TestBaseSubClass(TestBase): def test_attr_dict_string(self): test_value = 'just_some_random_string' ds = {'test_attr_dict': test_value} - self.assertRaisesRegexp(AnsibleParserError, 'is not a dictionary', self._base_validate, ds) + self.assertRaisesRegex(AnsibleParserError, 'is not a dictionary', self._base_validate, ds) def test_attr_class(self): esc = ExampleSubClass() @@ -503,14 +503,14 @@ class TestBaseSubClass(TestBase): def test_attr_class_post_validate_class_not_instance(self): not_a_esc = ExampleSubClass ds = {'test_attr_class_post_validate': not_a_esc} - self.assertRaisesRegexp(AnsibleParserError, 'is not a valid.*got a.*Meta.*instead', - self._base_validate, ds) + self.assertRaisesRegex(AnsibleParserError, 'is not a valid.*got a.*Meta.*instead', + self._base_validate, ds) def test_attr_class_post_validate_wrong_class(self): not_a_esc = 37 ds = {'test_attr_class_post_validate': not_a_esc} - self.assertRaisesRegexp(AnsibleParserError, 'is not a valid.*got a.*int.*instead', - self._base_validate, ds) + self.assertRaisesRegex(AnsibleParserError, 'is not a valid.*got a.*int.*instead', + self._base_validate, ds) def test_attr_remote_user(self): ds = {'remote_user': 'testuser'} @@ -599,8 +599,8 @@ class TestBaseSubClass(TestBase): bsc.load_data(ds) fake_loader = DictDataLoader({}) templar = Templar(loader=fake_loader) - self.assertRaisesRegexp(AnsibleParserError, 'cannot have empty values', - bsc.post_validate, templar) + self.assertRaisesRegex(AnsibleParserError, 'cannot have empty values', + bsc.post_validate, templar) def test_attr_unknown(self): a_list = ['some string'] diff --git a/test/units/playbook/test_conditional.py b/test/units/playbook/test_conditional.py index 53811b6b..17284ca2 100644 --- a/test/units/playbook/test_conditional.py +++ b/test/units/playbook/test_conditional.py @@ -3,7 +3,7 @@ __metaclass__ = type from units.compat import unittest from units.mock.loader import DictDataLoader -from units.compat.mock import MagicMock +from mock import MagicMock from ansible.template import Templar from ansible import errors @@ -50,8 +50,8 @@ class TestConditional(unittest.TestCase): def test_undefined(self): when = [u"{{ some_undefined_thing }}"] - self.assertRaisesRegexp(errors.AnsibleError, "The conditional check '{{ some_undefined_thing }}' failed", - self._eval_con, when, {}) + self.assertRaisesRegex(errors.AnsibleError, "The conditional check '{{ some_undefined_thing }}' failed", + self._eval_con, when, {}) def test_defined(self): variables = {'some_defined_thing': True} @@ -100,12 +100,12 @@ class TestConditional(unittest.TestCase): when = [u"some_dict.some_dict_key1 == hostvars['host3']"] # self._eval_con(when, variables) - self.assertRaisesRegexp(errors.AnsibleError, - r"The conditional check 'some_dict.some_dict_key1 == hostvars\['host3'\]' failed", - # "The conditional check 'some_dict.some_dict_key1 == hostvars['host3']' failed", - # "The conditional check 'some_dict.some_dict_key1 == hostvars['host3']' failed.", - self._eval_con, - when, variables) + self.assertRaisesRegex(errors.AnsibleError, + r"The conditional check 'some_dict.some_dict_key1 == hostvars\['host3'\]' failed", + # "The conditional check 'some_dict.some_dict_key1 == hostvars['host3']' failed", + # "The conditional check 'some_dict.some_dict_key1 == hostvars['host3']' failed.", + self._eval_con, + when, variables) def test_dict_undefined_values_bare(self): variables = {'dict_value': 1, @@ -116,10 +116,10 @@ class TestConditional(unittest.TestCase): # raises an exception when a non-string conditional is passed to extract_defined_undefined() when = [u"some_defined_dict_with_undefined_values"] - self.assertRaisesRegexp(errors.AnsibleError, - "The conditional check 'some_defined_dict_with_undefined_values' failed.", - self._eval_con, - when, variables) + self.assertRaisesRegex(errors.AnsibleError, + "The conditional check 'some_defined_dict_with_undefined_values' failed.", + self._eval_con, + when, variables) def test_dict_undefined_values_is_defined(self): variables = {'dict_value': 1, @@ -129,10 +129,10 @@ class TestConditional(unittest.TestCase): }} when = [u"some_defined_dict_with_undefined_values is defined"] - self.assertRaisesRegexp(errors.AnsibleError, - "The conditional check 'some_defined_dict_with_undefined_values is defined' failed.", - self._eval_con, - when, variables) + self.assertRaisesRegex(errors.AnsibleError, + "The conditional check 'some_defined_dict_with_undefined_values is defined' failed.", + self._eval_con, + when, variables) def test_is_defined(self): variables = {'some_defined_thing': True} @@ -195,10 +195,10 @@ class TestConditional(unittest.TestCase): u'hostvars["some_host"] is defined', u"{{ compare_targets.triple }} is defined", u"{{ compare_targets.quadruple }} is defined"] - self.assertRaisesRegexp(errors.AnsibleError, - "The conditional check '{{ compare_targets.triple }} is defined' failed", - self._eval_con, - when, variables) + self.assertRaisesRegex(errors.AnsibleError, + "The conditional check '{{ compare_targets.triple }} is defined' failed", + self._eval_con, + when, variables) def test_is_hostvars_host_is_defined(self): variables = {'hostvars': {'some_host': {}, }} diff --git a/test/units/playbook/test_helpers.py b/test/units/playbook/test_helpers.py index 8574cb4c..a921a727 100644 --- a/test/units/playbook/test_helpers.py +++ b/test/units/playbook/test_helpers.py @@ -22,7 +22,7 @@ __metaclass__ = type import os from units.compat import unittest -from units.compat.mock import MagicMock +from mock import MagicMock from units.mock.loader import DictDataLoader from ansible import errors @@ -107,30 +107,30 @@ class TestLoadListOfTasks(unittest.TestCase, MixinForMocks): def test_empty_task(self): ds = [{}] - self.assertRaisesRegexp(errors.AnsibleParserError, - "no module/action detected in task", - helpers.load_list_of_tasks, - ds, play=self.mock_play, - variable_manager=self.mock_variable_manager, loader=self.fake_loader) + self.assertRaisesRegex(errors.AnsibleParserError, + "no module/action detected in task", + helpers.load_list_of_tasks, + ds, play=self.mock_play, + variable_manager=self.mock_variable_manager, loader=self.fake_loader) def test_empty_task_use_handlers(self): ds = [{}] - self.assertRaisesRegexp(errors.AnsibleParserError, - "no module/action detected in task.", - helpers.load_list_of_tasks, - ds, - use_handlers=True, - play=self.mock_play, - variable_manager=self.mock_variable_manager, - loader=self.fake_loader) + self.assertRaisesRegex(errors.AnsibleParserError, + "no module/action detected in task.", + helpers.load_list_of_tasks, + ds, + use_handlers=True, + play=self.mock_play, + variable_manager=self.mock_variable_manager, + loader=self.fake_loader) def test_one_bogus_block(self): ds = [{'block': None}] - self.assertRaisesRegexp(errors.AnsibleParserError, - "A malformed block was encountered", - helpers.load_list_of_tasks, - ds, play=self.mock_play, - variable_manager=self.mock_variable_manager, loader=self.fake_loader) + self.assertRaisesRegex(errors.AnsibleParserError, + "A malformed block was encountered", + helpers.load_list_of_tasks, + ds, play=self.mock_play, + variable_manager=self.mock_variable_manager, loader=self.fake_loader) def test_unknown_action(self): action_name = 'foo_test_unknown_action' @@ -172,11 +172,11 @@ class TestLoadListOfTasks(unittest.TestCase, MixinForMocks): def test_one_bogus_block_use_handlers(self): ds = [{'block': True}] - self.assertRaisesRegexp(errors.AnsibleParserError, - "A malformed block was encountered", - helpers.load_list_of_tasks, - ds, play=self.mock_play, use_handlers=True, - variable_manager=self.mock_variable_manager, loader=self.fake_loader) + self.assertRaisesRegex(errors.AnsibleParserError, + "A malformed block was encountered", + helpers.load_list_of_tasks, + ds, play=self.mock_play, use_handlers=True, + variable_manager=self.mock_variable_manager, loader=self.fake_loader) def test_one_bogus_include(self): ds = [{'include': 'somefile.yml'}] @@ -320,11 +320,11 @@ class TestLoadListOfRoles(unittest.TestCase, MixinForMocks): def test_empty_role(self): ds = [{}] - self.assertRaisesRegexp(errors.AnsibleError, - "role definitions must contain a role name", - helpers.load_list_of_roles, - ds, self.mock_play, - variable_manager=self.mock_variable_manager, loader=self.fake_role_loader) + self.assertRaisesRegex(errors.AnsibleError, + "role definitions must contain a role name", + helpers.load_list_of_roles, + ds, self.mock_play, + variable_manager=self.mock_variable_manager, loader=self.fake_role_loader) def test_empty_role_just_name(self): ds = [{'name': 'bogus_role'}] @@ -359,16 +359,16 @@ class TestLoadListOfBlocks(unittest.TestCase, MixinForMocks): def test_empty_block(self): ds = [{}] mock_play = MagicMock(name='MockPlay') - self.assertRaisesRegexp(errors.AnsibleParserError, - "no module/action detected in task", - helpers.load_list_of_blocks, - ds, mock_play, - parent_block=None, - role=None, - task_include=None, - use_handlers=False, - variable_manager=None, - loader=None) + self.assertRaisesRegex(errors.AnsibleParserError, + "no module/action detected in task", + helpers.load_list_of_blocks, + ds, mock_play, + parent_block=None, + role=None, + task_include=None, + use_handlers=False, + variable_manager=None, + loader=None) def test_block_unknown_action(self): ds = [{'action': 'foo', 'collections': []}] diff --git a/test/units/playbook/test_included_file.py b/test/units/playbook/test_included_file.py index f143acb9..bf79b927 100644 --- a/test/units/playbook/test_included_file.py +++ b/test/units/playbook/test_included_file.py @@ -23,7 +23,7 @@ import os import pytest -from units.compat.mock import MagicMock +from mock import MagicMock from units.mock.loader import DictDataLoader from ansible.playbook.block import Block diff --git a/test/units/playbook/test_task.py b/test/units/playbook/test_task.py index cc053885..53a66705 100644 --- a/test/units/playbook/test_task.py +++ b/test/units/playbook/test_task.py @@ -20,7 +20,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type from units.compat import unittest -from units.compat.mock import patch +from mock import patch from ansible.playbook.task import Task from ansible.parsing.yaml import objects from ansible import errors diff --git a/test/units/plugins/action/test_action.py b/test/units/plugins/action/test_action.py index 26c86bd6..70885181 100644 --- a/test/units/plugins/action/test_action.py +++ b/test/units/plugins/action/test_action.py @@ -25,7 +25,7 @@ import re from ansible import constants as C from units.compat import unittest -from units.compat.mock import patch, MagicMock, mock_open +from mock import patch, MagicMock, mock_open from ansible.errors import AnsibleError, AnsibleAuthenticationFailure from ansible.module_utils.six import text_type @@ -346,7 +346,7 @@ class TestActionBase(unittest.TestCase): self.assertEqual(runWithNoExpectation(execute), remote_paths) def assertThrowRegex(regex, execute=False): - self.assertRaisesRegexp( + self.assertRaisesRegex( AnsibleError, regex, action_base._fixup_perms2, diff --git a/test/units/plugins/action/test_gather_facts.py b/test/units/plugins/action/test_gather_facts.py index 8f860e4a..e8a607b7 100644 --- a/test/units/plugins/action/test_gather_facts.py +++ b/test/units/plugins/action/test_gather_facts.py @@ -19,7 +19,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type from units.compat import unittest -from units.compat.mock import MagicMock, patch +from mock import MagicMock, patch from ansible import constants as C from ansible.playbook.task import Task diff --git a/test/units/plugins/action/test_raw.py b/test/units/plugins/action/test_raw.py index a8bde6c1..da216385 100644 --- a/test/units/plugins/action/test_raw.py +++ b/test/units/plugins/action/test_raw.py @@ -22,7 +22,7 @@ import os from ansible.errors import AnsibleActionFail from units.compat import unittest -from units.compat.mock import MagicMock, Mock +from mock import MagicMock, Mock from ansible.plugins.action.raw import ActionModule from ansible.playbook.task import Task from ansible.plugins.loader import connection_loader diff --git a/test/units/plugins/cache/test_cache.py b/test/units/plugins/cache/test_cache.py index c4e0079a..d0a39f39 100644 --- a/test/units/plugins/cache/test_cache.py +++ b/test/units/plugins/cache/test_cache.py @@ -23,7 +23,9 @@ import os import shutil import tempfile -from units.compat import unittest, mock +import mock + +from units.compat import unittest from ansible.errors import AnsibleError from ansible.plugins.cache import CachePluginAdjudicator from ansible.plugins.cache.base import BaseCacheModule @@ -185,9 +187,9 @@ class TestFactCache(unittest.TestCase): # See https://github.com/ansible/ansible/issues/18751 # Note no fact_connection config set, so this will fail with mock.patch('ansible.constants.CACHE_PLUGIN', 'json'): - self.assertRaisesRegexp(AnsibleError, - "Unable to load the facts cache plugin.*json.*", - FactCache) + self.assertRaisesRegex(AnsibleError, + "Unable to load the facts cache plugin.*json.*", + FactCache) def test_update(self): self.cache.update({'cache_key': {'key2': 'updatedvalue'}}) diff --git a/test/units/plugins/callback/test_callback.py b/test/units/plugins/callback/test_callback.py index c2ffbb4d..81ee3745 100644 --- a/test/units/plugins/callback/test_callback.py +++ b/test/units/plugins/callback/test_callback.py @@ -25,7 +25,7 @@ import textwrap import types from units.compat import unittest -from units.compat.mock import MagicMock +from mock import MagicMock from ansible.executor.task_result import TaskResult from ansible.inventory.host import Host @@ -56,7 +56,7 @@ class TestCallback(unittest.TestCase): def test_host_label(self): result = TaskResult(host=Host('host1'), task=mock_task, return_data={}) - self.assertEquals(CallbackBase.host_label(result), 'host1') + self.assertEqual(CallbackBase.host_label(result), 'host1') def test_host_label_delegated(self): mock_task.delegate_to = 'host2' @@ -65,7 +65,7 @@ class TestCallback(unittest.TestCase): task=mock_task, return_data={'_ansible_delegated_vars': {'ansible_host': 'host2'}}, ) - self.assertEquals(CallbackBase.host_label(result), 'host1 -> host2') + self.assertEqual(CallbackBase.host_label(result), 'host1 -> host2') # TODO: import callback module so we can patch callback.cli/callback.C diff --git a/test/units/plugins/connection/test_connection.py b/test/units/plugins/connection/test_connection.py index 0f484e62..38d66910 100644 --- a/test/units/plugins/connection/test_connection.py +++ b/test/units/plugins/connection/test_connection.py @@ -20,14 +20,8 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type from io import StringIO -import sys -import pytest -from units.compat import mock from units.compat import unittest -from units.compat.mock import MagicMock -from units.compat.mock import patch -from ansible.errors import AnsibleError from ansible.playbook.play_context import PlayContext from ansible.plugins.connection import ConnectionBase from ansible.plugins.loader import become_loader diff --git a/test/units/plugins/connection/test_psrp.py b/test/units/plugins/connection/test_psrp.py index f6416751..73516cc6 100644 --- a/test/units/plugins/connection/test_psrp.py +++ b/test/units/plugins/connection/test_psrp.py @@ -10,7 +10,7 @@ import pytest import sys from io import StringIO -from units.compat.mock import MagicMock +from mock import MagicMock from ansible.playbook.play_context import PlayContext from ansible.plugins.loader import connection_loader diff --git a/test/units/plugins/connection/test_ssh.py b/test/units/plugins/connection/test_ssh.py index 9b3e3c9d..e7f4dd12 100644 --- a/test/units/plugins/connection/test_ssh.py +++ b/test/units/plugins/connection/test_ssh.py @@ -27,7 +27,7 @@ import pytest from ansible import constants as C from ansible.errors import AnsibleAuthenticationFailure from units.compat import unittest -from units.compat.mock import patch, MagicMock, PropertyMock +from mock import patch, MagicMock, PropertyMock from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleFileNotFound from ansible.module_utils.compat.selectors import SelectorKey, EVENT_READ from ansible.module_utils.six.moves import shlex_quote diff --git a/test/units/plugins/connection/test_winrm.py b/test/units/plugins/connection/test_winrm.py index e6bf9ad2..c3245ccb 100644 --- a/test/units/plugins/connection/test_winrm.py +++ b/test/units/plugins/connection/test_winrm.py @@ -6,11 +6,13 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type +import os + import pytest from io import StringIO -from units.compat.mock import MagicMock +from mock import MagicMock from ansible.errors import AnsibleConnectionFailure from ansible.module_utils._text import to_bytes from ansible.playbook.play_context import PlayContext @@ -255,8 +257,9 @@ class TestWinRMKerbAuth(object): assert len(mock_calls) == 1 assert mock_calls[0][1] == expected actual_env = mock_calls[0][2]['env'] - assert list(actual_env.keys()) == ['KRB5CCNAME'] + assert sorted(list(actual_env.keys())) == ['KRB5CCNAME', 'PATH'] assert actual_env['KRB5CCNAME'].startswith("FILE:/") + assert actual_env['PATH'] == os.environ['PATH'] @pytest.mark.parametrize('options, expected', [ [{"_extras": {}}, @@ -287,8 +290,9 @@ class TestWinRMKerbAuth(object): mock_calls = mock_pexpect.mock_calls assert mock_calls[0][1] == expected actual_env = mock_calls[0][2]['env'] - assert list(actual_env.keys()) == ['KRB5CCNAME'] + assert sorted(list(actual_env.keys())) == ['KRB5CCNAME', 'PATH'] assert actual_env['KRB5CCNAME'].startswith("FILE:/") + assert actual_env['PATH'] == os.environ['PATH'] assert mock_calls[0][2]['echo'] is False assert mock_calls[1][0] == "().expect" assert mock_calls[1][1] == (".*:",) diff --git a/test/units/plugins/filter/test_mathstuff.py b/test/units/plugins/filter/test_mathstuff.py index d44a7146..f7938714 100644 --- a/test/units/plugins/filter/test_mathstuff.py +++ b/test/units/plugins/filter/test_mathstuff.py @@ -62,26 +62,6 @@ class TestSymmetricDifference: assert sorted(ms.symmetric_difference(env, tuple(dataset1), tuple(dataset2))) == expected[2] -class TestMin: - def test_min(self): - assert ms.min(env, (1, 2)) == 1 - assert ms.min(env, (2, 1)) == 1 - assert ms.min(env, ('p', 'a', 'w', 'b', 'p')) == 'a' - assert ms.min(env, ({'key': 'a'}, {'key': 'b'}, {'key': 'c'}), attribute='key') == {'key': 'a'} - assert ms.min(env, ({'key': 1}, {'key': 2}, {'key': 3}), attribute='key') == {'key': 1} - assert ms.min(env, ('a', 'A', 'b', 'B'), case_sensitive=True) == 'A' - - -class TestMax: - def test_max(self): - assert ms.max(env, (1, 2)) == 2 - assert ms.max(env, (2, 1)) == 2 - assert ms.max(env, ('p', 'a', 'w', 'b', 'p')) == 'w' - assert ms.max(env, ({'key': 'a'}, {'key': 'b'}, {'key': 'c'}), attribute='key') == {'key': 'c'} - assert ms.max(env, ({'key': 1}, {'key': 2}, {'key': 3}), attribute='key') == {'key': 3} - assert ms.max(env, ('a', 'A', 'b', 'B'), case_sensitive=True) == 'b' - - class TestLogarithm: def test_log_non_number(self): # Message changed in python3.6 diff --git a/test/units/plugins/inventory/test_inventory.py b/test/units/plugins/inventory/test_inventory.py index 66b5ec37..08148f8b 100644 --- a/test/units/plugins/inventory/test_inventory.py +++ b/test/units/plugins/inventory/test_inventory.py @@ -22,8 +22,9 @@ __metaclass__ = type import string import textwrap +import mock + from ansible import constants as C -from units.compat import mock from units.compat import unittest from ansible.module_utils.six import string_types from ansible.module_utils._text import to_text diff --git a/test/units/plugins/inventory/test_script.py b/test/units/plugins/inventory/test_script.py index 5f054813..1a00946c 100644 --- a/test/units/plugins/inventory/test_script.py +++ b/test/units/plugins/inventory/test_script.py @@ -22,11 +22,11 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type import pytest +import mock from ansible import constants as C from ansible.errors import AnsibleError from ansible.plugins.loader import PluginLoader -from units.compat import mock from units.compat import unittest from ansible.module_utils._text import to_bytes, to_native diff --git a/test/units/plugins/lookup/test_password.py b/test/units/plugins/lookup/test_password.py index f6cf10d1..c496ee6e 100644 --- a/test/units/plugins/lookup/test_password.py +++ b/test/units/plugins/lookup/test_password.py @@ -32,7 +32,7 @@ import pytest from units.mock.loader import DictDataLoader from units.compat import unittest -from units.compat.mock import mock_open, patch +from mock import mock_open, patch from ansible.errors import AnsibleError from ansible.module_utils.six import text_type from ansible.module_utils.six.moves import builtins diff --git a/test/units/plugins/strategy/test_linear.py b/test/units/plugins/strategy/test_linear.py index 74887030..3bce4856 100644 --- a/test/units/plugins/strategy/test_linear.py +++ b/test/units/plugins/strategy/test_linear.py @@ -7,7 +7,7 @@ __metaclass__ = type from units.compat import unittest -from units.compat.mock import patch, MagicMock +from mock import patch, MagicMock from ansible.executor.play_iterator import PlayIterator from ansible.playbook import Playbook diff --git a/test/units/plugins/strategy/test_strategy.py b/test/units/plugins/strategy/test_strategy.py index 6b60e692..750e8069 100644 --- a/test/units/plugins/strategy/test_strategy.py +++ b/test/units/plugins/strategy/test_strategy.py @@ -23,12 +23,13 @@ from units.mock.loader import DictDataLoader import uuid from units.compat import unittest -from units.compat.mock import patch, MagicMock +from mock import patch, MagicMock from ansible.executor.process.worker import WorkerProcess from ansible.executor.task_queue_manager import TaskQueueManager from ansible.executor.task_result import TaskResult from ansible.inventory.host import Host from ansible.module_utils.six.moves import queue as Queue +from ansible.playbook.block import Block from ansible.playbook.handler import Handler from ansible.plugins.strategy import StrategyBase @@ -464,7 +465,15 @@ class TestStrategyBase(unittest.TestCase): mock_task = MagicMock() mock_task._block = mock_block mock_task._role = None - mock_task._parent = None + + # NOTE Mocking calls below to account for passing parent_block=ti_copy.build_parent_block() + # into load_list_of_blocks() in _load_included_file. Not doing so meant that retrieving + # `collection` attr from parent would result in getting MagicMock instance + # instead of an empty list. + mock_task._parent = MagicMock() + mock_task.copy.return_value = mock_task + mock_task.build_parent_block.return_value = mock_block + mock_block._get_parent_attribute.return_value = None mock_iterator = MagicMock() mock_iterator.mark_host_failed.return_value = None @@ -474,6 +483,8 @@ class TestStrategyBase(unittest.TestCase): mock_inc_file._filename = "test.yml" res = strategy_base._load_included_file(included_file=mock_inc_file, iterator=mock_iterator) + self.assertEqual(len(res), 1) + self.assertTrue(isinstance(res[0], Block)) mock_inc_file._filename = "bad.yml" res = strategy_base._load_included_file(included_file=mock_inc_file, iterator=mock_iterator) diff --git a/test/units/plugins/test_plugins.py b/test/units/plugins/test_plugins.py index c9d80cda..975fa420 100644 --- a/test/units/plugins/test_plugins.py +++ b/test/units/plugins/test_plugins.py @@ -23,8 +23,7 @@ __metaclass__ = type import os from units.compat import unittest -from units.compat.builtins import BUILTINS -from units.compat.mock import patch, MagicMock +from mock import patch, MagicMock from ansible.plugins.loader import PluginLoader, PluginPathContext @@ -54,7 +53,7 @@ class TestErrors(unittest.TestCase): bar.bam = bam foo.return_value.bar = bar pl = PluginLoader('test', 'foo.bar.bam', 'test', 'test_plugin') - with patch('{0}.__import__'.format(BUILTINS), foo): + with patch('builtins.__import__', foo): self.assertEqual(pl._get_package_paths(), ['/path/to/my/foo/bar/bam']) def test_plugins__get_paths(self): diff --git a/test/units/template/test_native_concat.py b/test/units/template/test_native_concat.py index 4164bc45..ee1b7df1 100644 --- a/test/units/template/test_native_concat.py +++ b/test/units/template/test_native_concat.py @@ -5,45 +5,21 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -import importlib -import sys - -import pytest - -from ansible import constants as C -from ansible.errors import AnsibleUndefinedVariable from ansible.playbook.conditional import Conditional +from ansible.template import Templar from units.mock.loader import DictDataLoader -@pytest.fixture -def native_template_mod(monkeypatch): - monkeypatch.delitem(sys.modules, 'ansible.template') - monkeypatch.setattr(C, 'DEFAULT_JINJA2_NATIVE', True) - return importlib.import_module('ansible.template') - - -# https://github.com/ansible/ansible/issues/52158 -def test_undefined_variable(native_template_mod): - fake_loader = DictDataLoader({}) - variables = {} - templar = native_template_mod.Templar(loader=fake_loader, variables=variables) - assert isinstance(templar.environment, native_template_mod.AnsibleNativeEnvironment) - - with pytest.raises(AnsibleUndefinedVariable): - templar.template("{{ missing }}") - - -def test_cond_eval(native_template_mod): +def test_cond_eval(): fake_loader = DictDataLoader({}) # True must be stored in a variable to trigger templating. Using True # directly would be caught by optimization for bools to short-circuit # templating. variables = {"foo": True} - templar = native_template_mod.Templar(loader=fake_loader, variables=variables) - assert isinstance(templar.environment, native_template_mod.AnsibleNativeEnvironment) - + templar = Templar(loader=fake_loader, variables=variables) cond = Conditional(loader=fake_loader) cond.when = ["foo"] - assert cond.evaluate_conditional(templar, variables) + + with templar.set_temporary_context(jinja2_native=True): + assert cond.evaluate_conditional(templar, variables) diff --git a/test/units/template/test_safe_eval.py b/test/units/template/test_safe_eval.py deleted file mode 100644 index 89ff8a0e..00000000 --- a/test/units/template/test_safe_eval.py +++ /dev/null @@ -1,44 +0,0 @@ -# (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 sys -from collections import defaultdict - -from units.compat import unittest -from ansible.template.safe_eval import safe_eval - - -class TestSafeEval(unittest.TestCase): - - def test_safe_eval_usage(self): - # test safe eval calls with different possible types for the - # locals dictionary, to ensure we don't run into problems like - # ansible/ansible/issues/12206 again - for locals_vars in (dict(), defaultdict(dict)): - self.assertEqual(safe_eval('True', locals=locals_vars), True) - self.assertEqual(safe_eval('False', locals=locals_vars), False) - self.assertEqual(safe_eval('0', locals=locals_vars), 0) - self.assertEqual(safe_eval('[]', locals=locals_vars), []) - self.assertEqual(safe_eval('{}', locals=locals_vars), {}) - - @unittest.skipUnless(sys.version_info[:2] >= (2, 7), "Python 2.6 has no set literals") - def test_set_literals(self): - self.assertEqual(safe_eval('{0}'), set([0])) diff --git a/test/units/template/test_templar.py b/test/units/template/test_templar.py index dd6985ce..e922f95f 100644 --- a/test/units/template/test_templar.py +++ b/test/units/template/test_templar.py @@ -22,7 +22,7 @@ __metaclass__ = type from jinja2.runtime import Context from units.compat import unittest -from units.compat.mock import patch +from mock import patch from ansible import constants as C from ansible.errors import AnsibleError, AnsibleUndefinedVariable @@ -187,8 +187,7 @@ class TestTemplarTemplate(BaseTemplar, unittest.TestCase): self.assertTrue(res) self.assertEqual(res, 'bar') - @patch('ansible.template.safe_eval', side_effect=AnsibleError) - def test_template_convert_data_template_in_data(self, mock_safe_eval): + def test_template_convert_data_template_in_data(self): res = self.templar.template('{{bam}}', convert_data=True) self.assertTrue(res) self.assertEqual(res, 'bar') @@ -220,10 +219,10 @@ class TestTemplarTemplate(BaseTemplar, unittest.TestCase): def test_weird(self): data = u'''1 2 #}huh{# %}ddfg{% }}dfdfg{{ {%what%} {{#foo#}} {%{bar}%} {#%blip%#} {{asdfsd%} 3 4 {{foo}} 5 6 7''' - self.assertRaisesRegexp(AnsibleError, - 'template error while templating string', - self.templar.template, - data) + self.assertRaisesRegex(AnsibleError, + 'template error while templating string', + self.templar.template, + data) def test_template_with_error(self): """Check that AnsibleError is raised, fail if an unhandled exception is raised""" @@ -298,21 +297,21 @@ class TestTemplarMisc(BaseTemplar, unittest.TestCase): class TestTemplarLookup(BaseTemplar, unittest.TestCase): def test_lookup_missing_plugin(self): - self.assertRaisesRegexp(AnsibleError, - r'lookup plugin \(not_a_real_lookup_plugin\) not found', - self.templar._lookup, - 'not_a_real_lookup_plugin', - 'an_arg', a_keyword_arg='a_keyword_arg_value') + self.assertRaisesRegex(AnsibleError, + r'lookup plugin \(not_a_real_lookup_plugin\) not found', + self.templar._lookup, + 'not_a_real_lookup_plugin', + 'an_arg', a_keyword_arg='a_keyword_arg_value') def test_lookup_list(self): res = self.templar._lookup('list', 'an_arg', 'another_arg') self.assertEqual(res, 'an_arg,another_arg') def test_lookup_jinja_undefined(self): - self.assertRaisesRegexp(AnsibleUndefinedVariable, - "'an_undefined_jinja_var' is undefined", - self.templar._lookup, - 'list', '{{ an_undefined_jinja_var }}') + self.assertRaisesRegex(AnsibleUndefinedVariable, + "'an_undefined_jinja_var' is undefined", + self.templar._lookup, + 'list', '{{ an_undefined_jinja_var }}') def test_lookup_jinja_defined(self): res = self.templar._lookup('list', '{{ some_var }}') @@ -320,18 +319,18 @@ class TestTemplarLookup(BaseTemplar, unittest.TestCase): # self.assertIsInstance(res, AnsibleUnsafe) def test_lookup_jinja_dict_string_passed(self): - self.assertRaisesRegexp(AnsibleError, - "with_dict expects a dict", - self.templar._lookup, - 'dict', - '{{ some_var }}') + self.assertRaisesRegex(AnsibleError, + "with_dict expects a dict", + self.templar._lookup, + 'dict', + '{{ some_var }}') def test_lookup_jinja_dict_list_passed(self): - self.assertRaisesRegexp(AnsibleError, - "with_dict expects a dict", - self.templar._lookup, - 'dict', - ['foo', 'bar']) + self.assertRaisesRegex(AnsibleError, + "with_dict expects a dict", + self.templar._lookup, + 'dict', + ['foo', 'bar']) def test_lookup_jinja_kwargs(self): res = self.templar._lookup('list', 'blip', random_keyword='12345') @@ -343,12 +342,12 @@ class TestTemplarLookup(BaseTemplar, unittest.TestCase): self.assertEqual(res, ["blip"]) def test_lookup_jinja_list_wantlist_undefined(self): - self.assertRaisesRegexp(AnsibleUndefinedVariable, - "'some_undefined_var' is undefined", - self.templar._lookup, - 'list', - '{{ some_undefined_var }}', - wantlist=True) + self.assertRaisesRegex(AnsibleUndefinedVariable, + "'some_undefined_var' is undefined", + self.templar._lookup, + 'list', + '{{ some_undefined_var }}', + wantlist=True) def test_lookup_jinja_list_wantlist_unsafe(self): res = self.templar._lookup('list', '{{ some_unsafe_var }}', wantlist=True) @@ -444,3 +443,28 @@ class TestAnsibleContext(BaseTemplar, unittest.TestCase): def test_is_unsafe(self): context = self._context() self.assertFalse(context._is_unsafe(AnsibleUndefined())) + + +def test_unsafe_lookup(): + res = Templar( + None, + variables={ + 'var0': '{{ var1 }}', + 'var1': ['unsafe'], + } + ).template('{{ lookup("list", var0) }}') + assert getattr(res[0], '__UNSAFE__', False) + + +def test_unsafe_lookup_no_conversion(): + res = Templar( + None, + variables={ + 'var0': '{{ var1 }}', + 'var1': ['unsafe'], + } + ).template( + '{{ lookup("list", var0) }}', + convert_data=False, + ) + assert getattr(res, '__UNSAFE__', False) diff --git a/test/units/template/test_vars.py b/test/units/template/test_vars.py index 74e67839..3e04ba2f 100644 --- a/test/units/template/test_vars.py +++ b/test/units/template/test_vars.py @@ -20,7 +20,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type from units.compat import unittest -from units.compat.mock import MagicMock +from mock import MagicMock from ansible.template.vars import AnsibleJ2Vars @@ -29,53 +29,13 @@ class TestVars(unittest.TestCase): def setUp(self): self.mock_templar = MagicMock(name='mock_templar') - def test(self): - ajvars = AnsibleJ2Vars(None, None) - print(ajvars) - - def test_globals_empty_2_8(self): - ajvars = AnsibleJ2Vars(self.mock_templar, {}) - res28 = self._dict_jinja28(ajvars) - self.assertIsInstance(res28, dict) - - def test_globals_empty_2_9(self): + def test_globals_empty(self): ajvars = AnsibleJ2Vars(self.mock_templar, {}) - res29 = self._dict_jinja29(ajvars) - self.assertIsInstance(res29, dict) + res = dict(ajvars) + self.assertIsInstance(res, dict) - def _assert_globals(self, res): + def test_globals(self): + res = dict(AnsibleJ2Vars(self.mock_templar, {'foo': 'bar', 'blip': [1, 2, 3]})) self.assertIsInstance(res, dict) self.assertIn('foo', res) self.assertEqual(res['foo'], 'bar') - - def test_globals_2_8(self): - ajvars = AnsibleJ2Vars(self.mock_templar, {'foo': 'bar', 'blip': [1, 2, 3]}) - res28 = self._dict_jinja28(ajvars) - self._assert_globals(res28) - - def test_globals_2_9(self): - ajvars = AnsibleJ2Vars(self.mock_templar, {'foo': 'bar', 'blip': [1, 2, 3]}) - res29 = self._dict_jinja29(ajvars) - self._assert_globals(res29) - - def _dicts(self, ajvars): - print(ajvars) - res28 = self._dict_jinja28(ajvars) - res29 = self._dict_jinja29(ajvars) - # res28_other = self._dict_jinja28(ajvars, {'other_key': 'other_value'}) - # other = {'other_key': 'other_value'} - # res29_other = self._dict_jinja29(ajvars, *other) - print('res28: %s' % res28) - print('res29: %s' % res29) - # print('res28_other: %s' % res28_other) - # print('res29_other: %s' % res29_other) - # return (res28, res29, res28_other, res29_other) - # assert ajvars == res28 - # assert ajvars == res29 - return (res28, res29) - - def _dict_jinja28(self, *args, **kwargs): - return dict(*args, **kwargs) - - def _dict_jinja29(self, the_vars): - return dict(the_vars) diff --git a/test/units/utils/collection_loader/test_collection_loader.py b/test/units/utils/collection_loader/test_collection_loader.py index 425f770c..3ae04cbd 100644 --- a/test/units/utils/collection_loader/test_collection_loader.py +++ b/test/units/utils/collection_loader/test_collection_loader.py @@ -9,6 +9,7 @@ import sys from ansible.module_utils.six import PY3, string_types from ansible.module_utils.compat.importlib import import_module +from ansible.modules import ping as ping_module from ansible.utils.collection_loader import AnsibleCollectionConfig, AnsibleCollectionRef from ansible.utils.collection_loader._collection_finder import ( _AnsibleCollectionFinder, _AnsibleCollectionLoader, _AnsibleCollectionNSPkgLoader, _AnsibleCollectionPkgLoader, @@ -16,7 +17,7 @@ from ansible.utils.collection_loader._collection_finder import ( _get_collection_name_from_path, _get_collection_role_path, _get_collection_metadata, _iter_modules_impl ) from ansible.utils.collection_loader._collection_config import _EventSource -from units.compat.mock import MagicMock, NonCallableMagicMock, patch +from mock import MagicMock, NonCallableMagicMock, patch # fixture to ensure we always clean up the import stuff when we're done @@ -28,6 +29,17 @@ def teardown(*args, **kwargs): # BEGIN STANDALONE TESTS - these exercise behaviors of the individual components without the import machinery +@pytest.mark.skipif(not PY3, reason='Testing Python 2 codepath (find_module) on Python 3') +def test_find_module_py3(): + dir_to_a_file = os.path.dirname(ping_module.__file__) + path_hook_finder = _AnsiblePathHookFinder(_AnsibleCollectionFinder(), dir_to_a_file) + + # setuptools may fall back to find_module on Python 3 if find_spec returns None + # see https://github.com/pypa/setuptools/pull/2918 + assert path_hook_finder.find_spec('missing') is None + assert path_hook_finder.find_module('missing') is None + + def test_finder_setup(): # ensure scalar path is listified f = _AnsibleCollectionFinder(paths='/bogus/bogus') diff --git a/test/units/utils/display/test_broken_cowsay.py b/test/units/utils/display/test_broken_cowsay.py new file mode 100644 index 00000000..e93065d8 --- /dev/null +++ b/test/units/utils/display/test_broken_cowsay.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2021 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.utils.display import Display +from mock import MagicMock + + +def test_display_with_fake_cowsay_binary(capsys, mocker): + mocker.patch("ansible.constants.ANSIBLE_COW_PATH", "./cowsay.sh") + + def mock_communicate(input=None, timeout=None): + return b"", b"" + + mock_popen = MagicMock() + mock_popen.return_value.communicate = mock_communicate + mock_popen.return_value.returncode = 1 + mocker.patch("subprocess.Popen", mock_popen) + + display = Display() + assert not hasattr(display, "cows_available") + assert display.b_cowsay is None diff --git a/test/units/utils/test_display.py b/test/units/utils/test_display.py index 1e73c2ad..8807b816 100644 --- a/test/units/utils/test_display.py +++ b/test/units/utils/test_display.py @@ -5,7 +5,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type -from units.compat.mock import MagicMock +from mock import MagicMock import pytest diff --git a/test/units/utils/test_vars.py b/test/units/utils/test_vars.py index c92ce4b6..1df0eab3 100644 --- a/test/units/utils/test_vars.py +++ b/test/units/utils/test_vars.py @@ -22,7 +22,9 @@ __metaclass__ = type from collections import defaultdict -from units.compat import mock, unittest +import mock + +from units.compat import unittest from ansible.errors import AnsibleError from ansible.utils.vars import combine_vars, merge_hash diff --git a/test/units/vars/test_variable_manager.py b/test/units/vars/test_variable_manager.py index 65a79286..fa68fd3b 100644 --- a/test/units/vars/test_variable_manager.py +++ b/test/units/vars/test_variable_manager.py @@ -22,7 +22,7 @@ __metaclass__ = type import os from units.compat import unittest -from units.compat.mock import MagicMock, patch +from mock import MagicMock, patch from ansible.inventory.manager import InventoryManager from ansible.module_utils.six import iteritems from ansible.playbook.play import Play |