|
|
|
# -*- 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)
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
import os
|
|
|
|
import os.path
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
from ansible.config.manager import ConfigManager, ensure_type, resolve_path, get_config_type
|
|
|
|
from ansible.errors import AnsibleOptionsError, AnsibleError
|
|
|
|
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')
|
|
|
|
cfg_file3 = os.path.join(curdir, 'test3.cfg')
|
|
|
|
|
|
|
|
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', int),
|
|
|
|
(20, 'int', int),
|
|
|
|
('0.10', 'float', float),
|
|
|
|
(0.2, 'float', float),
|
|
|
|
('/tmp/test.yml', 'pathspec', list),
|
|
|
|
('/tmp/test.yml,/home/test2.yml', 'pathlist', list),
|
|
|
|
('a', 'str', str),
|
|
|
|
('a', 'string', str),
|
|
|
|
('Café', 'string', str),
|
|
|
|
('', 'string', str),
|
|
|
|
('29', 'str', str),
|
|
|
|
('13.37', 'str', str),
|
|
|
|
('123j', 'string', str),
|
|
|
|
('0x123', 'string', str),
|
|
|
|
('true', 'string', str),
|
|
|
|
('True', 'string', str),
|
|
|
|
(0, 'str', str),
|
|
|
|
(29, 'str', str),
|
|
|
|
(13.37, 'str', str),
|
|
|
|
(123j, 'string', str),
|
|
|
|
(0x123, 'string', str),
|
|
|
|
(True, 'string', str),
|
|
|
|
('None', 'none', type(None))
|
|
|
|
]
|
|
|
|
|
|
|
|
ensure_unquoting_test_data = [
|
|
|
|
('"value"', '"value"', 'str', 'env: ENVVAR', None),
|
|
|
|
('"value"', '"value"', 'str', os.path.join(curdir, 'test.yml'), 'yaml'),
|
|
|
|
('"value"', 'value', 'str', cfg_file, 'ini'),
|
|
|
|
('\'value\'', 'value', 'str', cfg_file, 'ini'),
|
|
|
|
('\'\'value\'\'', '\'value\'', 'str', cfg_file, 'ini'),
|
|
|
|
('""value""', '"value"', 'str', cfg_file, 'ini')
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
@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)
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("value, expected_value, value_type, origin, origin_ftype", ensure_unquoting_test_data)
|
|
|
|
def test_ensure_type_unquoting(self, value, expected_value, value_type, origin, origin_ftype):
|
|
|
|
actual_value = ensure_type(value, value_type, origin, origin_ftype)
|
|
|
|
assert actual_value == expected_value
|
|
|
|
|
|
|
|
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, filename=None, obj=None):
|
|
|
|
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, filename=None, obj=None):
|
|
|
|
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"
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(("key", "expected_value"), (
|
|
|
|
("COLOR_UNREACHABLE", "bright red"),
|
|
|
|
("COLOR_VERBOSE", "rgb013"),
|
|
|
|
("COLOR_DEBUG", "gray10")))
|
|
|
|
def test_256color_support(key, expected_value):
|
|
|
|
# GIVEN: a config file containing 256-color values with default definitions
|
|
|
|
manager = ConfigManager(cfg_file3)
|
|
|
|
# WHEN: get config values
|
|
|
|
actual_value = manager.get_config_value(key)
|
|
|
|
# THEN: no error
|
|
|
|
assert actual_value == expected_value
|