diff options
author | Toshio Kuratomi <a.badger@gmail.com> | 2019-06-28 13:09:36 -0700 |
---|---|---|
committer | Toshio Kuratomi <a.badger@gmail.com> | 2019-07-01 07:43:51 -0700 |
commit | 7d4e9b279e15286b51a8d50fbb80a84cdf1c865a (patch) | |
tree | 29eb14678a0ee6e50d55b32e277256e0422c8dbe | |
parent | 28816088e4d815d5997d0eaa9f3f4b89c4a149bc (diff) | |
download | ansible-7d4e9b279e15286b51a8d50fbb80a84cdf1c865a.tar.gz |
[stable-2.7] Skip tests with unsatisfied deps (#55853)
* Skip gitlab tests if dependencies aren't met
* Skip certain unittests if passlib is not installed
* Fix tests with deps on paramiko to skip if paramiko is not installed
* Use pytest to skip for cloudstack
If either on Python-2.6 or the cs library is not installed we cannot run
this test so skip it.
(cherry picked from commit 8acf71f78fce89d70a58fc45ee528003c4785e6b)
Co-authored-by: Toshio Kuratomi <a.badger@gmail.com>
-rw-r--r-- | test/units/plugins/filter/test_network.py | 8 | ||||
-rw-r--r-- | test/units/plugins/lookup/test_password.py | 117 | ||||
-rw-r--r-- | test/units/utils/test_encrypt.py | 31 |
3 files changed, 103 insertions, 53 deletions
diff --git a/test/units/plugins/filter/test_network.py b/test/units/plugins/filter/test_network.py index d1f4b49282..b184ab1236 100644 --- a/test/units/plugins/filter/test_network.py +++ b/test/units/plugins/filter/test_network.py @@ -23,7 +23,9 @@ import sys import pytest from ansible.compat.tests import unittest -from ansible.plugins.filter.network import parse_xml, type5_pw, hash_salt, comp_type5 +from ansible.plugins.filter.network import (HAS_PASSLIB, parse_xml, type5_pw, hash_salt, + comp_type5) + from ansible.errors import AnsibleFilterError fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures', 'network') @@ -83,6 +85,7 @@ class TestNetworkParseFilter(unittest.TestCase): self.assertEqual("parse_xml works on string input, but given input of : %s" % type(output), str(e.exception)) +@pytest.mark.skipif(not HAS_PASSLIB, reason="Current type5_pw filter needs passlib to function") class TestNetworkType5(unittest.TestCase): def test_defined_salt_success(self): @@ -146,6 +149,7 @@ class TestHashSalt(unittest.TestCase): self.assertEqual("Could not parse salt out password correctly from $nTc1$Z28sUTcWfXlvVe2x.3XAa.", str(e.exception)) +@pytest.mark.skipif(not HAS_PASSLIB, reason="Current comp_type5 filter needs passlib to function") class TestCompareType5(unittest.TestCase): def test_compare_type5_boolean(self): @@ -160,7 +164,7 @@ class TestCompareType5(unittest.TestCase): parsed = comp_type5(unencrypted_password, encrypted_password, True) self.assertEqual(parsed, '$1$nTc1$Z28sUTcWfXlvVe2x.3XAa.') - def test_compate_type5_fail(self): + def test_compare_type5_fail(self): unencrypted_password = 'invalid_password' encrypted_password = '$1$nTc1$Z28sUTcWfXlvVe2x.3XAa.' parsed = comp_type5(unencrypted_password, encrypted_password) diff --git a/test/units/plugins/lookup/test_password.py b/test/units/plugins/lookup/test_password.py index 8f3e31750d..7a11689dee 100644 --- a/test/units/plugins/lookup/test_password.py +++ b/test/units/plugins/lookup/test_password.py @@ -20,8 +20,15 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -import passlib -from passlib.handlers import pbkdf2 +try: + import passlib + from passlib.handlers import pbkdf2 +except ImportError: + passlib = None + pbkdf2 = None + +import pytest + from units.mock.loader import DictDataLoader from ansible.compat.tests import unittest @@ -359,7 +366,7 @@ class TestWritePasswordFile(unittest.TestCase): m().write.assert_called_once_with(u'Testing Café\n'.encode('utf-8')) -class TestLookupModule(unittest.TestCase): +class BaseTestLookupModule(unittest.TestCase): def setUp(self): self.fake_loader = DictDataLoader({'/path/to/somewhere': 'sdfsdf'}) self.password_lookup = password.LookupModule(loader=self.fake_loader) @@ -373,19 +380,15 @@ class TestLookupModule(unittest.TestCase): self.makedirs_safe = password.makedirs_safe password.makedirs_safe = lambda path, mode: None - # Different releases of passlib default to a different number of rounds - self.sha256 = passlib.registry.get_crypt_handler('pbkdf2_sha256') - sha256_for_tests = pbkdf2.create_pbkdf2_hash("sha256", 32, 20000) - passlib.registry.register_crypt_handler(sha256_for_tests, force=True) - def tearDown(self): password.os.path.exists = self.os_path_exists password.os.open = self.os_open password.os.close = self.os_close password.os.remove = self.os_remove password.makedirs_safe = self.makedirs_safe - passlib.registry.register_crypt_handler(self.sha256, force=True) + +class TestLookupModuleWithoutPasslib(BaseTestLookupModule): @patch.object(PluginLoader, '_get_paths') @patch('ansible.plugins.lookup.password._write_password_file') def test_no_encrypt(self, mock_get_paths, mock_write_file): @@ -395,46 +398,8 @@ class TestLookupModule(unittest.TestCase): # FIXME: assert something useful for result in results: - self.assertEquals(len(result), password.DEFAULT_LENGTH) - self.assertIsInstance(result, text_type) - - @patch.object(PluginLoader, '_get_paths') - @patch('ansible.plugins.lookup.password._write_password_file') - def test_encrypt(self, mock_get_paths, mock_write_file): - mock_get_paths.return_value = ['/path/one', '/path/two', '/path/three'] - - results = self.password_lookup.run([u'/path/to/somewhere encrypt=pbkdf2_sha256'], None) - - # pbkdf2 format plus hash - expected_password_length = 76 - - for result in results: - self.assertEquals(len(result), expected_password_length) - # result should have 5 parts split by '$' - str_parts = result.split('$', 5) - - # verify the result is parseable by the passlib - crypt_parts = passlib.hash.pbkdf2_sha256.parsehash(result) - - # verify it used the right algo type - self.assertEquals(str_parts[1], 'pbkdf2-sha256') - - self.assertEquals(len(str_parts), 5) - - # verify the string and parsehash agree on the number of rounds - self.assertEquals(int(str_parts[2]), crypt_parts['rounds']) - self.assertIsInstance(result, text_type) - - @patch.object(PluginLoader, '_get_paths') - @patch('ansible.plugins.lookup.password._write_password_file') - def test_password_already_created_encrypt(self, mock_get_paths, mock_write_file): - mock_get_paths.return_value = ['/path/one', '/path/two', '/path/three'] - password.os.path.exists = lambda x: x == to_bytes('/path/to/somewhere') - - with patch.object(builtins, 'open', mock_open(read_data=b'hunter42 salt=87654321\n')) as m: - results = self.password_lookup.run([u'/path/to/somewhere chars=anything encrypt=pbkdf2_sha256'], None) - for result in results: - self.assertEqual(result, u'$pbkdf2-sha256$20000$ODc2NTQzMjE$Uikde0cv0BKaRaAXMrUQB.zvG4GmnjClwjghwIRf2gU') + assert len(result) == password.DEFAULT_LENGTH + assert isinstance(result, text_type) @patch.object(PluginLoader, '_get_paths') @patch('ansible.plugins.lookup.password._write_password_file') @@ -480,3 +445,57 @@ class TestLookupModule(unittest.TestCase): for result in results: self.assertEqual(result, u'hunter42') + + +@pytest.mark.skipif(passlib is None, reason='passlib must be installed to run these tests') +class TestLookupModuleWithPasslib(BaseTestLookupModule): + def setUp(self): + super(TestLookupModuleWithPasslib, self).setUp() + + # Different releases of passlib default to a different number of rounds + self.sha256 = passlib.registry.get_crypt_handler('pbkdf2_sha256') + sha256_for_tests = pbkdf2.create_pbkdf2_hash("sha256", 32, 20000) + passlib.registry.register_crypt_handler(sha256_for_tests, force=True) + + def tearDown(self): + super(TestLookupModuleWithPasslib, self).tearDown() + + passlib.registry.register_crypt_handler(self.sha256, force=True) + + @patch.object(PluginLoader, '_get_paths') + @patch('ansible.plugins.lookup.password._write_password_file') + def test_encrypt(self, mock_get_paths, mock_write_file): + mock_get_paths.return_value = ['/path/one', '/path/two', '/path/three'] + + results = self.password_lookup.run([u'/path/to/somewhere encrypt=pbkdf2_sha256'], None) + + # pbkdf2 format plus hash + expected_password_length = 76 + + for result in results: + self.assertEquals(len(result), expected_password_length) + # result should have 5 parts split by '$' + str_parts = result.split('$', 5) + + # verify the result is parseable by the passlib + crypt_parts = passlib.hash.pbkdf2_sha256.parsehash(result) + + # verify it used the right algo type + self.assertEquals(str_parts[1], 'pbkdf2-sha256') + + self.assertEquals(len(str_parts), 5) + + # verify the string and parsehash agree on the number of rounds + self.assertEquals(int(str_parts[2]), crypt_parts['rounds']) + self.assertIsInstance(result, text_type) + + @patch.object(PluginLoader, '_get_paths') + @patch('ansible.plugins.lookup.password._write_password_file') + def test_password_already_created_encrypt(self, mock_get_paths, mock_write_file): + mock_get_paths.return_value = ['/path/one', '/path/two', '/path/three'] + password.os.path.exists = lambda x: x == to_bytes('/path/to/somewhere') + + with patch.object(builtins, 'open', mock_open(read_data=b'hunter42 salt=87654321\n')) as m: + results = self.password_lookup.run([u'/path/to/somewhere chars=anything encrypt=pbkdf2_sha256'], None) + for result in results: + self.assertEqual(result, u'$pbkdf2-sha256$20000$ODc2NTQzMjE$Uikde0cv0BKaRaAXMrUQB.zvG4GmnjClwjghwIRf2gU') diff --git a/test/units/utils/test_encrypt.py b/test/units/utils/test_encrypt.py index 22dd76287f..64c092f94f 100644 --- a/test/units/utils/test_encrypt.py +++ b/test/units/utils/test_encrypt.py @@ -36,16 +36,29 @@ class passlib_off(object): def assert_hash(expected, secret, algorithm, **settings): - assert encrypt.CryptHash(algorithm).hash(secret, **settings) == expected if encrypt.PASSLIB_AVAILABLE: assert encrypt.passlib_or_crypt(secret, algorithm, **settings) == expected assert encrypt.PasslibHash(algorithm).hash(secret, **settings) == expected else: - with pytest.raises(AnsibleFilterError): + assert encrypt.passlib_or_crypt(secret, algorithm, **settings) == expected + with pytest.raises(AnsibleError) as excinfo: encrypt.PasslibHash(algorithm).hash(secret, **settings) + assert excinfo.value.args[0] == "passlib must be installed to hash with '%s'" % algorithm + + +def test_encrypt_with_rounds_no_passlib(): + with passlib_off(): + assert_hash("$5$12345678$uAZsE3BenI2G.nA8DpTl.9Dc8JiqacI53pEqRr5ppT7", + secret="123", algorithm="sha256_crypt", salt="12345678", rounds=5000) + assert_hash("$5$rounds=10000$12345678$JBinliYMFEcBeAXKZnLjenhgEhTmJBvZn3aR8l70Oy/", + secret="123", algorithm="sha256_crypt", salt="12345678", rounds=10000) + assert_hash("$6$12345678$LcV9LQiaPekQxZ.OfkMADjFdSO2k9zfbDQrHPVcYjSLqSdjLYpsgqviYvTEP/R41yPmhH3CCeEDqVhW1VHr3L.", + secret="123", algorithm="sha512_crypt", salt="12345678", rounds=5000) +# If passlib is not installed. this is identical to the test_encrypt_with_rounds_no_passlib() test +@pytest.mark.skipif(not encrypt.PASSLIB_AVAILABLE, reason='passlib must be installed to run this test') def test_encrypt_with_rounds(): assert_hash("$5$12345678$uAZsE3BenI2G.nA8DpTl.9Dc8JiqacI53pEqRr5ppT7", secret="123", algorithm="sha256_crypt", salt="12345678", rounds=5000) @@ -55,6 +68,20 @@ def test_encrypt_with_rounds(): secret="123", algorithm="sha512_crypt", salt="12345678", rounds=5000) +def test_encrypt_default_rounds_no_passlib(): + with passlib_off(): + assert_hash("$1$12345678$tRy4cXc3kmcfRZVj4iFXr/", + secret="123", algorithm="md5_crypt", salt="12345678") + assert_hash("$5$12345678$uAZsE3BenI2G.nA8DpTl.9Dc8JiqacI53pEqRr5ppT7", + secret="123", algorithm="sha256_crypt", salt="12345678") + assert_hash("$6$12345678$LcV9LQiaPekQxZ.OfkMADjFdSO2k9zfbDQrHPVcYjSLqSdjLYpsgqviYvTEP/R41yPmhH3CCeEDqVhW1VHr3L.", + secret="123", algorithm="sha512_crypt", salt="12345678") + + assert encrypt.CryptHash("md5_crypt").hash("123") + + +# If passlib is not installed. this is identical to the test_encrypt_default_rounds_no_passlib() test +@pytest.mark.skipif(not encrypt.PASSLIB_AVAILABLE, reason='passlib must be installed to run this test') def test_encrypt_default_rounds(): assert_hash("$1$12345678$tRy4cXc3kmcfRZVj4iFXr/", secret="123", algorithm="md5_crypt", salt="12345678") |