summaryrefslogtreecommitdiffstats
path: root/test/units/config/test_manager.py
blob: d103e5e6618f44cf04d6a2580551e343d258311b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
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"