diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-14 20:03:01 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-14 20:03:01 +0000 |
commit | a453ac31f3428614cceb99027f8efbdb9258a40b (patch) | |
tree | f61f87408f32a8511cbd91799f9cececb53e0374 /test/units/config | |
parent | Initial commit. (diff) | |
download | ansible-a453ac31f3428614cceb99027f8efbdb9258a40b.tar.xz ansible-a453ac31f3428614cceb99027f8efbdb9258a40b.zip |
Adding upstream version 2.10.7+merged+base+2.10.8+dfsg.upstream/2.10.7+merged+base+2.10.8+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'test/units/config')
-rw-r--r-- | test/units/config/manager/__init__.py | 0 | ||||
-rw-r--r-- | test/units/config/manager/test_find_ini_config_file.py | 253 | ||||
-rw-r--r-- | test/units/config/test.cfg | 4 | ||||
-rw-r--r-- | test/units/config/test.yml | 55 | ||||
-rw-r--r-- | test/units/config/test2.cfg | 4 | ||||
-rw-r--r-- | test/units/config/test_data.py | 41 | ||||
-rw-r--r-- | test/units/config/test_manager.py | 145 |
7 files changed, 502 insertions, 0 deletions
diff --git a/test/units/config/manager/__init__.py b/test/units/config/manager/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/units/config/manager/__init__.py diff --git a/test/units/config/manager/test_find_ini_config_file.py b/test/units/config/manager/test_find_ini_config_file.py new file mode 100644 index 00000000..df411388 --- /dev/null +++ b/test/units/config/manager/test_find_ini_config_file.py @@ -0,0 +1,253 @@ +# -*- coding: utf-8 -*- +# Copyright: (c) 2017, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import os.path +import stat + +import pytest + +from ansible.config.manager import find_ini_config_file +from ansible.module_utils._text import to_text + +real_exists = os.path.exists +real_isdir = os.path.isdir + +working_dir = os.path.dirname(__file__) +cfg_in_cwd = os.path.join(working_dir, 'ansible.cfg') + +cfg_dir = os.path.join(working_dir, 'data') +cfg_file = os.path.join(cfg_dir, 'ansible.cfg') +alt_cfg_file = os.path.join(cfg_dir, 'test.cfg') +cfg_in_homedir = os.path.expanduser('~/.ansible.cfg') + + +@pytest.fixture +def setup_env(request): + cur_config = os.environ.get('ANSIBLE_CONFIG', None) + cfg_path = request.param[0] + + if cfg_path is None and cur_config: + del os.environ['ANSIBLE_CONFIG'] + else: + os.environ['ANSIBLE_CONFIG'] = request.param[0] + + yield + + if cur_config is None and cfg_path: + del os.environ['ANSIBLE_CONFIG'] + else: + os.environ['ANSIBLE_CONFIG'] = cur_config + + +@pytest.fixture +def setup_existing_files(request, monkeypatch): + def _os_path_exists(path): + if to_text(path) in (request.param[0]): + return True + else: + return False + + def _os_access(path, access): + if to_text(path) in (request.param[0]): + return True + else: + return False + + # Enable user and system dirs so that we know cwd takes precedence + monkeypatch.setattr("os.path.exists", _os_path_exists) + monkeypatch.setattr("os.access", _os_access) + monkeypatch.setattr("os.getcwd", lambda: os.path.dirname(cfg_dir)) + monkeypatch.setattr("os.path.isdir", lambda path: True if to_text(path) == cfg_dir else real_isdir(path)) + + +class TestFindIniFile: + # This tells us to run twice, once with a file specified and once with a directory + @pytest.mark.parametrize('setup_env, expected', (([alt_cfg_file], alt_cfg_file), ([cfg_dir], cfg_file)), indirect=['setup_env']) + # This just passes the list of files that exist to the fixture + @pytest.mark.parametrize('setup_existing_files', + [[('/etc/ansible/ansible.cfg', cfg_in_homedir, cfg_in_cwd, alt_cfg_file, cfg_file)]], + indirect=['setup_existing_files']) + def test_env_has_cfg_file(self, setup_env, setup_existing_files, expected): + """ANSIBLE_CONFIG is specified, use it""" + warnings = set() + assert find_ini_config_file(warnings) == expected + assert warnings == set() + + @pytest.mark.parametrize('setup_env', ([alt_cfg_file], [cfg_dir]), indirect=['setup_env']) + @pytest.mark.parametrize('setup_existing_files', + [[('/etc/ansible/ansible.cfg', cfg_in_homedir, cfg_in_cwd)]], + indirect=['setup_existing_files']) + def test_env_has_no_cfg_file(self, setup_env, setup_existing_files): + """ANSIBLE_CONFIG is specified but the file does not exist""" + + warnings = set() + # since the cfg file specified by ANSIBLE_CONFIG doesn't exist, the one at cwd that does + # exist should be returned + assert find_ini_config_file(warnings) == cfg_in_cwd + assert warnings == set() + + # ANSIBLE_CONFIG not specified + @pytest.mark.parametrize('setup_env', [[None]], indirect=['setup_env']) + # All config files are present + @pytest.mark.parametrize('setup_existing_files', + [[('/etc/ansible/ansible.cfg', cfg_in_homedir, cfg_in_cwd, cfg_file, alt_cfg_file)]], + indirect=['setup_existing_files']) + def test_ini_in_cwd(self, setup_env, setup_existing_files): + """ANSIBLE_CONFIG not specified. Use the cwd cfg""" + warnings = set() + assert find_ini_config_file(warnings) == cfg_in_cwd + assert warnings == set() + + # ANSIBLE_CONFIG not specified + @pytest.mark.parametrize('setup_env', [[None]], indirect=['setup_env']) + # No config in cwd + @pytest.mark.parametrize('setup_existing_files', + [[('/etc/ansible/ansible.cfg', cfg_in_homedir, cfg_file, alt_cfg_file)]], + indirect=['setup_existing_files']) + def test_ini_in_homedir(self, setup_env, setup_existing_files): + """First config found is in the homedir""" + warnings = set() + assert find_ini_config_file(warnings) == cfg_in_homedir + assert warnings == set() + + # ANSIBLE_CONFIG not specified + @pytest.mark.parametrize('setup_env', [[None]], indirect=['setup_env']) + # No config in cwd + @pytest.mark.parametrize('setup_existing_files', [[('/etc/ansible/ansible.cfg', cfg_file, alt_cfg_file)]], indirect=['setup_existing_files']) + def test_ini_in_systemdir(self, setup_env, setup_existing_files): + """First config found is the system config""" + warnings = set() + assert find_ini_config_file(warnings) == '/etc/ansible/ansible.cfg' + assert warnings == set() + + # ANSIBLE_CONFIG not specified + @pytest.mark.parametrize('setup_env', [[None]], indirect=['setup_env']) + # No config in cwd + @pytest.mark.parametrize('setup_existing_files', + [[('/etc/ansible/ansible.cfg', cfg_in_homedir, cfg_file, alt_cfg_file)]], + indirect=['setup_existing_files']) + def test_cwd_does_not_exist(self, setup_env, setup_existing_files, monkeypatch): + """Smoketest current working directory doesn't exist""" + def _os_stat(path): + raise OSError('%s does not exist' % path) + monkeypatch.setattr('os.stat', _os_stat) + + warnings = set() + assert find_ini_config_file(warnings) == cfg_in_homedir + assert warnings == set() + + @pytest.mark.parametrize('setup_env', [[None]], indirect=['setup_env']) + # No config in cwd + @pytest.mark.parametrize('setup_existing_files', [[list()]], indirect=['setup_existing_files']) + def test_no_config(self, setup_env, setup_existing_files): + """No config present, no config found""" + warnings = set() + assert find_ini_config_file(warnings) is None + assert warnings == set() + + # ANSIBLE_CONFIG not specified + @pytest.mark.parametrize('setup_env', [[None]], indirect=['setup_env']) + # All config files are present except in cwd + @pytest.mark.parametrize('setup_existing_files', + [[('/etc/ansible/ansible.cfg', cfg_in_homedir, cfg_file, alt_cfg_file)]], + indirect=['setup_existing_files']) + def test_no_cwd_cfg_no_warning_on_writable(self, setup_env, setup_existing_files, monkeypatch): + """If the cwd is writable but there is no config file there, move on with no warning""" + real_stat = os.stat + + def _os_stat(path): + if path == working_dir: + from posix import stat_result + stat_info = list(real_stat(path)) + stat_info[stat.ST_MODE] |= stat.S_IWOTH + return stat_result(stat_info) + else: + return real_stat(path) + + monkeypatch.setattr('os.stat', _os_stat) + + warnings = set() + assert find_ini_config_file(warnings) == cfg_in_homedir + assert len(warnings) == 0 + + # ANSIBLE_CONFIG not specified + @pytest.mark.parametrize('setup_env', [[None]], indirect=['setup_env']) + # All config files are present + @pytest.mark.parametrize('setup_existing_files', + [[('/etc/ansible/ansible.cfg', cfg_in_homedir, cfg_in_cwd, cfg_file, alt_cfg_file)]], + indirect=['setup_existing_files']) + def test_cwd_warning_on_writable(self, setup_env, setup_existing_files, monkeypatch): + """If the cwd is writable, warn and skip it """ + real_stat = os.stat + + def _os_stat(path): + if path == working_dir: + from posix import stat_result + stat_info = list(real_stat(path)) + stat_info[stat.ST_MODE] |= stat.S_IWOTH + return stat_result(stat_info) + else: + return real_stat(path) + + monkeypatch.setattr('os.stat', _os_stat) + + warnings = set() + assert find_ini_config_file(warnings) == cfg_in_homedir + assert len(warnings) == 1 + warning = warnings.pop() + assert u'Ansible is being run in a world writable directory' in warning + assert u'ignoring it as an ansible.cfg source' in warning + + # ANSIBLE_CONFIG is sepcified + @pytest.mark.parametrize('setup_env, expected', (([alt_cfg_file], alt_cfg_file), ([cfg_in_cwd], cfg_in_cwd)), indirect=['setup_env']) + # All config files are present + @pytest.mark.parametrize('setup_existing_files', + [[('/etc/ansible/ansible.cfg', cfg_in_homedir, cfg_in_cwd, cfg_file, alt_cfg_file)]], + indirect=['setup_existing_files']) + def test_no_warning_on_writable_if_env_used(self, setup_env, setup_existing_files, monkeypatch, expected): + """If the cwd is writable but ANSIBLE_CONFIG was used, no warning should be issued""" + real_stat = os.stat + + def _os_stat(path): + if path == working_dir: + from posix import stat_result + stat_info = list(real_stat(path)) + stat_info[stat.ST_MODE] |= stat.S_IWOTH + return stat_result(stat_info) + else: + return real_stat(path) + + monkeypatch.setattr('os.stat', _os_stat) + + warnings = set() + assert find_ini_config_file(warnings) == expected + assert warnings == set() + + # ANSIBLE_CONFIG not specified + @pytest.mark.parametrize('setup_env', [[None]], indirect=['setup_env']) + # All config files are present + @pytest.mark.parametrize('setup_existing_files', + [[('/etc/ansible/ansible.cfg', cfg_in_homedir, cfg_in_cwd, cfg_file, alt_cfg_file)]], + indirect=['setup_existing_files']) + def test_cwd_warning_on_writable_no_warning_set(self, setup_env, setup_existing_files, monkeypatch): + """Smoketest that the function succeeds even though no warning set was passed in""" + real_stat = os.stat + + def _os_stat(path): + if path == working_dir: + from posix import stat_result + stat_info = list(real_stat(path)) + stat_info[stat.ST_MODE] |= stat.S_IWOTH + return stat_result(stat_info) + else: + return real_stat(path) + + monkeypatch.setattr('os.stat', _os_stat) + + assert find_ini_config_file() == cfg_in_homedir diff --git a/test/units/config/test.cfg b/test/units/config/test.cfg new file mode 100644 index 00000000..57958d87 --- /dev/null +++ b/test/units/config/test.cfg @@ -0,0 +1,4 @@ +[defaults] +inikey=fromini +matterless=lessfromini +mattermore=morefromini diff --git a/test/units/config/test.yml b/test/units/config/test.yml new file mode 100644 index 00000000..384a055b --- /dev/null +++ b/test/units/config/test.yml @@ -0,0 +1,55 @@ +# mock config defs with diff use cases +config_entry: &entry + name: test config + default: DEFAULT + description: + - This does nothing, its for testing + env: + - name: ENVVAR + ini: + - section: defaults + key: inikey + type: string +config_entry_multi: &entry_multi + name: has more than one entry per config source + default: DEFAULT + description: + - This does nothing, its for testing + env: + - name: MATTERLESS + - name: MATTERMORE + ini: + - section: defaults + key: matterless + - section: defaults + key: mattermore + type: string +config_entry_bool: + <<: *entry + type: bool + default: False +config_entry_list: + <<: *entry + type: list + default: [DEFAULT] +config_entry_deprecated: + <<: *entry + deprecated: &dep + why: 'cause i wanna' + version: 9.2 + alternative: 'none whatso ever' +config_entry_multi_deprecated: + <<: *entry_multi + deprecated: *dep +config_entry_multi_deprecated_source: + <<: *entry_multi + env: + - name: MATTERLESS + deprecated: *dep + - name: MATTERMORE + ini: + - section: defaults + key: matterless + deprecated: *dep + - section: defaults + key: mattermore diff --git a/test/units/config/test2.cfg b/test/units/config/test2.cfg new file mode 100644 index 00000000..da2d77b0 --- /dev/null +++ b/test/units/config/test2.cfg @@ -0,0 +1,4 @@ +[defaults] +inikey=fromini2 +matterless=lessfromini2 +mattermore=morefromini2 diff --git a/test/units/config/test_data.py b/test/units/config/test_data.py new file mode 100644 index 00000000..da043e7b --- /dev/null +++ b/test/units/config/test_data.py @@ -0,0 +1,41 @@ +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from units.compat import unittest + +from ansible.config.data import ConfigData +from ansible.config.manager import Setting + + +mykey = Setting('mykey', 'myvalue', 'test', 'string') +mykey2 = Setting('mykey2', 'myvalue2', ['test', 'test2'], 'list') +mykey3 = Setting('mykey3', 'myvalue3', 11111111111, 'integer') + + +class TestConfigData(unittest.TestCase): + + def setUp(self): + self.cdata = ConfigData() + + def tearDown(self): + self.cdata = None + + def test_update_setting(self): + for setting in [mykey, mykey2, mykey3]: + self.cdata.update_setting(setting) + self.assertEqual(setting, self.cdata._global_settings.get(setting.name)) + + def test_update_setting_with_plugin(self): + pass + + def test_get_setting(self): + self.cdata._global_settings = {'mykey': mykey} + self.assertEqual(mykey, self.cdata.get_setting('mykey')) + + def test_get_settings(self): + all_settings = {'mykey': mykey, 'mykey2': mykey2} + self.cdata._global_settings = all_settings + + for setting in self.cdata.get_settings(): + self.assertEqual(all_settings[setting.name], setting) diff --git a/test/units/config/test_manager.py b/test/units/config/test_manager.py new file mode 100644 index 00000000..d103e5e6 --- /dev/null +++ b/test/units/config/test_manager.py @@ -0,0 +1,145 @@ +# -*- coding: utf-8 -*- +# Copyright: (c) 2017, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import os.path +import pytest + +from ansible.config.manager import ConfigManager, Setting, ensure_type, resolve_path, get_config_type +from ansible.errors import AnsibleOptionsError, AnsibleError +from ansible.module_utils.six import integer_types, string_types +from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode + +curdir = os.path.dirname(__file__) +cfg_file = os.path.join(curdir, 'test.cfg') +cfg_file2 = os.path.join(curdir, 'test2.cfg') + +expected_ini = {'CONFIG_FILE': Setting(name='CONFIG_FILE', value=cfg_file, origin='', type='string'), + 'config_entry': Setting(name='config_entry', value=u'fromini', origin=cfg_file, type='string'), + 'config_entry_bool': Setting(name='config_entry_bool', value=False, origin=cfg_file, type='bool'), + 'config_entry_list': Setting(name='config_entry_list', value=['fromini'], origin=cfg_file, type='list'), + 'config_entry_deprecated': Setting(name='config_entry_deprecated', value=u'fromini', origin=cfg_file, type='string'), + 'config_entry_multi': Setting(name='config_entry_multi', value=u'morefromini', origin=cfg_file, type='string'), + 'config_entry_multi_deprecated': Setting(name='config_entry_multi_deprecated', value=u'morefromini', origin=cfg_file, type='string'), + 'config_entry_multi_deprecated_source': Setting(name='config_entry_multi_deprecated_source', value=u'morefromini', + origin=cfg_file, type='string')} + +ensure_test_data = [ + ('a,b', 'list', list), + (['a', 'b'], 'list', list), + ('y', 'bool', bool), + ('yes', 'bool', bool), + ('on', 'bool', bool), + ('1', 'bool', bool), + ('true', 'bool', bool), + ('t', 'bool', bool), + (1, 'bool', bool), + (1.0, 'bool', bool), + (True, 'bool', bool), + ('n', 'bool', bool), + ('no', 'bool', bool), + ('off', 'bool', bool), + ('0', 'bool', bool), + ('false', 'bool', bool), + ('f', 'bool', bool), + (0, 'bool', bool), + (0.0, 'bool', bool), + (False, 'bool', bool), + ('10', 'int', integer_types), + (20, 'int', integer_types), + ('0.10', 'float', float), + (0.2, 'float', float), + ('/tmp/test.yml', 'pathspec', list), + ('/tmp/test.yml,/home/test2.yml', 'pathlist', list), + ('a', 'str', string_types), + ('a', 'string', string_types), + ('Café', 'string', string_types), + ('', 'string', string_types), + ('None', 'none', type(None)) +] + + +class TestConfigManager: + @classmethod + def setup_class(cls): + cls.manager = ConfigManager(cfg_file, os.path.join(curdir, 'test.yml')) + + @classmethod + def teardown_class(cls): + cls.manager = None + + def test_initial_load(self): + assert self.manager.data._global_settings == expected_ini + + @pytest.mark.parametrize("value, expected_type, python_type", ensure_test_data) + def test_ensure_type(self, value, expected_type, python_type): + assert isinstance(ensure_type(value, expected_type), python_type) + + def test_resolve_path(self): + assert os.path.join(curdir, 'test.yml') == resolve_path('./test.yml', cfg_file) + + def test_resolve_path_cwd(self): + assert os.path.join(os.getcwd(), 'test.yml') == resolve_path('{{CWD}}/test.yml') + assert os.path.join(os.getcwd(), 'test.yml') == resolve_path('./test.yml') + + def test_value_and_origin_from_ini(self): + assert self.manager.get_config_value_and_origin('config_entry') == ('fromini', cfg_file) + + def test_value_from_ini(self): + assert self.manager.get_config_value('config_entry') == 'fromini' + + def test_value_and_origin_from_alt_ini(self): + assert self.manager.get_config_value_and_origin('config_entry', cfile=cfg_file2) == ('fromini2', cfg_file2) + + def test_value_from_alt_ini(self): + assert self.manager.get_config_value('config_entry', cfile=cfg_file2) == 'fromini2' + + def test_config_types(self): + assert get_config_type('/tmp/ansible.ini') == 'ini' + assert get_config_type('/tmp/ansible.cfg') == 'ini' + assert get_config_type('/tmp/ansible.yaml') == 'yaml' + assert get_config_type('/tmp/ansible.yml') == 'yaml' + + def test_config_types_negative(self): + with pytest.raises(AnsibleOptionsError) as exec_info: + get_config_type('/tmp/ansible.txt') + assert "Unsupported configuration file extension for" in str(exec_info.value) + + def test_read_config_yaml_file(self): + assert isinstance(self.manager._read_config_yaml_file(os.path.join(curdir, 'test.yml')), dict) + + def test_read_config_yaml_file_negative(self): + with pytest.raises(AnsibleError) as exec_info: + self.manager._read_config_yaml_file(os.path.join(curdir, 'test_non_existent.yml')) + + assert "Missing base YAML definition file (bad install?)" in str(exec_info.value) + + def test_entry_as_vault_var(self): + class MockVault: + + def decrypt(self, value): + return value + + vault_var = AnsibleVaultEncryptedUnicode(b"vault text") + vault_var.vault = MockVault() + + actual_value, actual_origin = self.manager._loop_entries({'name': vault_var}, [{'name': 'name'}]) + assert actual_value == "vault text" + assert actual_origin == "name" + + @pytest.mark.parametrize("value_type", ("str", "string", None)) + def test_ensure_type_with_vaulted_str(self, value_type): + class MockVault: + def decrypt(self, value): + return value + + vault_var = AnsibleVaultEncryptedUnicode(b"vault text") + vault_var.vault = MockVault() + + actual_value = ensure_type(vault_var, value_type) + assert actual_value == "vault text" |