From 697b566971ef855d83292a7c8f954275100d6803 Mon Sep 17 00:00:00 2001 From: Matt Martz Date: Mon, 12 Aug 2019 15:13:07 -0500 Subject: [PATCH] Update units to pass on macOS (#60435) * Update units to pass on macOS. Fixes #27810 * raising=False --- .../_data/requirements/constraints.txt | 2 +- .../ansible_test/_data/requirements/units.txt | 1 + .../units/module_utils/basic/test_atomic_move.py | 6 +++++- .../basic/test_set_mode_if_different.py | 16 ++++------------ test/units/module_utils/facts/base.py | 12 +++++++++--- .../module_utils/facts/test_ansible_collector.py | 4 +++- test/units/parsing/vault/test_vault.py | 4 ++-- test/units/parsing/vault/test_vault_editor.py | 2 +- test/units/playbook/test_helpers.py | 3 ++- test/units/utils/test_encrypt.py | 8 +++++++- 10 files changed, 35 insertions(+), 23 deletions(-) diff --git a/test/lib/ansible_test/_data/requirements/constraints.txt b/test/lib/ansible_test/_data/requirements/constraints.txt index 4e55c477151..d619be6367d 100644 --- a/test/lib/ansible_test/_data/requirements/constraints.txt +++ b/test/lib/ansible_test/_data/requirements/constraints.txt @@ -11,7 +11,7 @@ wheel < 0.30.0 ; python_version < '2.7' # wheel 0.30.0 and later require python yamllint != 1.8.0, < 1.14.0 ; python_version < '2.7' # yamllint 1.8.0 and 1.14.0+ require python 2.7+ pycrypto >= 2.6 # Need features found in 2.6 and greater ncclient >= 0.5.2 # Need features added in 0.5.2 and greater -idna < 2.6 # requests requires idna < 2.6, but cryptography will cause the latest version to be installed instead +idna < 2.6, >= 2.5 # linode requires idna < 2.9, >= 2.5, requests requires idna < 2.6, but cryptography will cause the latest version to be installed instead paramiko < 2.4.0 ; python_version < '2.7' # paramiko 2.4.0 drops support for python 2.6 paramiko < 2.5.0 ; python_version >= '2.7' # paramiko 2.5.0 requires cryptography 2.5.0+ pytest < 3.3.0 ; python_version < '2.7' # pytest 3.3.0 drops support for python 2.6 diff --git a/test/lib/ansible_test/_data/requirements/units.txt b/test/lib/ansible_test/_data/requirements/units.txt index b198cbebcfd..32c311c72d2 100644 --- a/test/lib/ansible_test/_data/requirements/units.txt +++ b/test/lib/ansible_test/_data/requirements/units.txt @@ -10,6 +10,7 @@ pytest pytest-mock pytest-xdist python-memcached +pytz pyvmomi pyyaml redis diff --git a/test/units/module_utils/basic/test_atomic_move.py b/test/units/module_utils/basic/test_atomic_move.py index dce3941906e..7bd9496eddf 100644 --- a/test/units/module_utils/basic/test_atomic_move.py +++ b/test/units/module_utils/basic/test_atomic_move.py @@ -7,6 +7,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type +import os import errno import json from itertools import product @@ -27,7 +28,7 @@ def atomic_am(am, mocker): @pytest.fixture -def atomic_mocks(mocker): +def atomic_mocks(mocker, monkeypatch): environ = dict() mocks = { 'chmod': mocker.patch('os.chmod'), @@ -53,6 +54,9 @@ def atomic_mocks(mocker): mocks['umask'].side_effect = [18, 0] mocks['rename'].return_value = None + # normalize OS specific features + monkeypatch.delattr(os, 'chflags', raising=False) + yield mocks diff --git a/test/units/module_utils/basic/test_set_mode_if_different.py b/test/units/module_utils/basic/test_set_mode_if_different.py index e9446cd83e3..fcc4691ed52 100644 --- a/test/units/module_utils/basic/test_set_mode_if_different.py +++ b/test/units/module_utils/basic/test_set_mode_if_different.py @@ -101,19 +101,15 @@ def test_mode_unchanged_when_already_0660(am, mock_stats, mocker, mode, check_mo @pytest.mark.parametrize('check_mode, stdin', product((True, False), ({},)), indirect=['stdin']) -def test_missing_lchmod_is_not_link(am, mock_stats, mocker, check_mode): +def test_missing_lchmod_is_not_link(am, mock_stats, mocker, monkeypatch, check_mode): """Some platforms have lchmod (*BSD) others do not (Linux)""" am.check_mode = check_mode original_hasattr = hasattr - def _hasattr(obj, name): - if obj == os and name == 'lchmod': - return False - return original_hasattr(obj, name) + monkeypatch.delattr(os, 'lchmod', raising=False) mocker.patch('os.lstat', side_effect=[mock_stats['before'], mock_stats['after']]) - mocker.patch.object(builtins, 'hasattr', side_effect=_hasattr) mocker.patch('os.path.islink', return_value=False) mocker.patch('os.path.exists', return_value=True) m_chmod = mocker.patch('os.chmod', return_value=None) @@ -128,19 +124,15 @@ def test_missing_lchmod_is_not_link(am, mock_stats, mocker, check_mode): @pytest.mark.parametrize('check_mode, stdin', product((True, False), ({},)), indirect=['stdin']) -def test_missing_lchmod_is_link(am, mock_stats, mocker, check_mode): +def test_missing_lchmod_is_link(am, mock_stats, mocker, monkeypatch, check_mode): """Some platforms have lchmod (*BSD) others do not (Linux)""" am.check_mode = check_mode original_hasattr = hasattr - def _hasattr(obj, name): - if obj == os and name == 'lchmod': - return False - return original_hasattr(obj, name) + monkeypatch.delattr(os, 'lchmod', raising=False) mocker.patch('os.lstat', side_effect=[mock_stats['before'], mock_stats['after']]) - mocker.patch.object(builtins, 'hasattr', side_effect=_hasattr) mocker.patch('os.path.islink', return_value=True) mocker.patch('os.path.exists', return_value=True) m_chmod = mocker.patch('os.chmod', return_value=None) diff --git a/test/units/module_utils/facts/base.py b/test/units/module_utils/facts/base.py index 04e00d12d8b..edaf3495dc6 100644 --- a/test/units/module_utils/facts/base.py +++ b/test/units/module_utils/facts/base.py @@ -19,8 +19,10 @@ from __future__ import (absolute_import, division) __metaclass__ = type +import os + from units.compat import unittest -from units.compat.mock import Mock +from units.compat.mock import Mock, patch class BaseFactsTest(unittest.TestCase): @@ -45,14 +47,18 @@ class BaseFactsTest(unittest.TestCase): mock_module.get_bin_path = Mock(return_value=None) return mock_module - def test_collect(self): + @patch('platform.system', return_value='Linux') + @patch('ansible.module_utils.facts.system.service_mgr.get_file_content', return_value='systemd') + def test_collect(self, mock_gfc, mock_ps): module = self._mock_module() fact_collector = self.collector_class() facts_dict = fact_collector.collect(module=module, collected_facts=self.collected_facts) self.assertIsInstance(facts_dict, dict) return facts_dict - def test_collect_with_namespace(self): + @patch('platform.system', return_value='Linux') + @patch('ansible.module_utils.facts.system.service_mgr.get_file_content', return_value='systemd') + def test_collect_with_namespace(self, mock_gfc, mock_ps): module = self._mock_module() fact_collector = self.collector_class() facts_dict = fact_collector.collect_with_namespace(module=module, diff --git a/test/units/module_utils/facts/test_ansible_collector.py b/test/units/module_utils/facts/test_ansible_collector.py index 781a8968105..bc743e6ca55 100644 --- a/test/units/module_utils/facts/test_ansible_collector.py +++ b/test/units/module_utils/facts/test_ansible_collector.py @@ -207,7 +207,9 @@ class TestCollectedFacts(unittest.TestCase): def _mock_module(self, gather_subset=None): return mock_module(gather_subset=self.gather_subset) - def setUp(self): + @patch('platform.system', return_value='Linux') + @patch('ansible.module_utils.facts.system.service_mgr.get_file_content', return_value='systemd') + def setUp(self, mock_gfc, mock_ps): mock_module = self._mock_module() collectors = self._collectors(mock_module) diff --git a/test/units/parsing/vault/test_vault.py b/test/units/parsing/vault/test_vault.py index 1c103751ca2..c7d6b8d8430 100644 --- a/test/units/parsing/vault/test_vault.py +++ b/test/units/parsing/vault/test_vault.py @@ -247,7 +247,7 @@ class TestFileVaultSecret(unittest.TestCase): def test_file_not_found(self): tmp_file = tempfile.NamedTemporaryFile() - filename = tmp_file.name + filename = os.path.realpath(tmp_file.name) tmp_file.close() fake_loader = DictDataLoader({filename: 'sdfadf'}) @@ -390,7 +390,7 @@ class TestGetFileVaultSecret(unittest.TestCase): def test_file_not_found(self): tmp_file = tempfile.NamedTemporaryFile() - filename = tmp_file.name + filename = os.path.realpath(tmp_file.name) tmp_file.close() fake_loader = DictDataLoader({filename: 'sdfadf'}) diff --git a/test/units/parsing/vault/test_vault_editor.py b/test/units/parsing/vault/test_vault_editor.py index 6a93896a218..8aa9b37c31a 100644 --- a/test/units/parsing/vault/test_vault_editor.py +++ b/test/units/parsing/vault/test_vault_editor.py @@ -492,7 +492,7 @@ class TestVaultEditor(unittest.TestCase): self.assertEqual(res, '/dev/null') def test_real_path_symlink(self): - self._test_dir = self._create_test_dir() + self._test_dir = os.path.realpath(self._create_test_dir()) file_path = self._create_file(self._test_dir, 'test_file', content=b'this is a test file') file_link_path = os.path.join(self._test_dir, 'a_link_to_test_file') diff --git a/test/units/playbook/test_helpers.py b/test/units/playbook/test_helpers.py index 60ed2664308..22b2718c39b 100644 --- a/test/units/playbook/test_helpers.py +++ b/test/units/playbook/test_helpers.py @@ -62,7 +62,8 @@ class MixinForMocks(object): self.mock_block = MagicMock(name='MockBlock') - self.fake_role_loader = DictDataLoader({"/etc/ansible/roles/bogus_role/tasks/main.yml": """ + # On macOS /etc is actually /private/etc, tests fail when performing literal /etc checks + self.fake_role_loader = DictDataLoader({os.path.join(os.path.realpath("/etc"), "ansible/roles/bogus_role/tasks/main.yml"): """ - shell: echo 'hello world' """}) diff --git a/test/units/utils/test_encrypt.py b/test/units/utils/test_encrypt.py index e0037afa00c..91fbf349947 100644 --- a/test/units/utils/test_encrypt.py +++ b/test/units/utils/test_encrypt.py @@ -15,6 +15,8 @@ # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . +import sys + import pytest from ansible.errors import AnsibleError, AnsibleFilterError @@ -46,6 +48,7 @@ def assert_hash(expected, secret, algorithm, **settings): assert excinfo.value.args[0] == "passlib must be installed to hash with '%s'" % algorithm +@pytest.mark.skipif(sys.platform.startswith('darwin'), reason='macOS requires passlib') def test_encrypt_with_rounds_no_passlib(): with passlib_off(): assert_hash("$5$12345678$uAZsE3BenI2G.nA8DpTl.9Dc8JiqacI53pEqRr5ppT7", @@ -67,6 +70,7 @@ def test_encrypt_with_rounds(): secret="123", algorithm="sha512_crypt", salt="12345678", rounds=5000) +@pytest.mark.skipif(sys.platform.startswith('darwin'), reason='macOS requires passlib') def test_encrypt_default_rounds_no_passlib(): with passlib_off(): assert_hash("$1$12345678$tRy4cXc3kmcfRZVj4iFXr/", @@ -89,9 +93,10 @@ def test_encrypt_default_rounds(): assert_hash("$6$12345678$LcV9LQiaPekQxZ.OfkMADjFdSO2k9zfbDQrHPVcYjSLqSdjLYpsgqviYvTEP/R41yPmhH3CCeEDqVhW1VHr3L.", secret="123", algorithm="sha512_crypt", salt="12345678") - assert encrypt.CryptHash("md5_crypt").hash("123") + assert encrypt.PasslibHash("md5_crypt").hash("123") +@pytest.mark.skipif(sys.platform.startswith('darwin'), reason='macOS requires passlib') def test_password_hash_filter_no_passlib(): with passlib_off(): assert not encrypt.PASSLIB_AVAILABLE @@ -127,6 +132,7 @@ def test_password_hash_filter_passlib(): assert get_encrypted_password("123", "pbkdf2_sha256") +@pytest.mark.skipif(sys.platform.startswith('darwin'), reason='macOS requires passlib') def test_do_encrypt_no_passlib(): with passlib_off(): assert not encrypt.PASSLIB_AVAILABLE