mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
config tests
also a couple of fixes to manager
This commit is contained in:
parent
80b0e0e05a
commit
12c8dd1893
6 changed files with 217 additions and 55 deletions
|
@ -164,7 +164,7 @@ class ConfigManager(object):
|
||||||
UNABLE = []
|
UNABLE = []
|
||||||
DEPRECATED = []
|
DEPRECATED = []
|
||||||
|
|
||||||
def __init__(self, conf_file=None):
|
def __init__(self, conf_file=None, defs_file=None):
|
||||||
|
|
||||||
self._base_defs = {}
|
self._base_defs = {}
|
||||||
self._plugins = {}
|
self._plugins = {}
|
||||||
|
@ -173,19 +173,24 @@ class ConfigManager(object):
|
||||||
self._config_file = conf_file
|
self._config_file = conf_file
|
||||||
self.data = ConfigData()
|
self.data = ConfigData()
|
||||||
|
|
||||||
# FIXME: make dynamic? scan for more? make it's own method?
|
if defs_file is None:
|
||||||
# Create configuration definitions from source
|
# Create configuration definitions from source
|
||||||
bconfig_def = to_bytes('%s/base.yml' % os.path.dirname(__file__))
|
b_defs_file = to_bytes('%s/base.yml' % os.path.dirname(__file__))
|
||||||
if os.path.exists(bconfig_def):
|
else:
|
||||||
with open(bconfig_def, 'rb') as config_def:
|
b_defs_file = to_bytes(defs_file)
|
||||||
|
|
||||||
|
# consume definitions
|
||||||
|
if os.path.exists(b_defs_file):
|
||||||
|
with open(b_defs_file, 'rb') as config_def:
|
||||||
self._base_defs = yaml.safe_load(config_def)
|
self._base_defs = yaml.safe_load(config_def)
|
||||||
else:
|
else:
|
||||||
raise AnsibleError("Missing base configuration definition file (bad install?): %s" % to_native(bconfig_def))
|
raise AnsibleError("Missing base configuration definition file (bad install?): %s" % to_native(b_defs_file))
|
||||||
|
|
||||||
if self._config_file is None:
|
if self._config_file is None:
|
||||||
# set config using ini
|
# set config using ini
|
||||||
self._config_file = find_ini_config_file()
|
self._config_file = find_ini_config_file()
|
||||||
|
|
||||||
|
# consume configuration
|
||||||
if self._config_file:
|
if self._config_file:
|
||||||
if os.path.exists(self._config_file):
|
if os.path.exists(self._config_file):
|
||||||
# initialize parser and read config
|
# initialize parser and read config
|
||||||
|
@ -270,9 +275,12 @@ class ConfigManager(object):
|
||||||
|
|
||||||
if cfile is None:
|
if cfile is None:
|
||||||
cfile = self._config_file
|
cfile = self._config_file
|
||||||
|
else:
|
||||||
|
self._parse_config_file(cfile)
|
||||||
|
|
||||||
# Note: sources that are lists listed in low to high precedence (last one wins)
|
# Note: sources that are lists listed in low to high precedence (last one wins)
|
||||||
value = None
|
value = None
|
||||||
|
origin = None
|
||||||
defs = {}
|
defs = {}
|
||||||
if plugin_type is None:
|
if plugin_type is None:
|
||||||
defs = self._base_defs
|
defs = self._base_defs
|
||||||
|
@ -281,60 +289,63 @@ class ConfigManager(object):
|
||||||
else:
|
else:
|
||||||
defs = self._plugins[plugin_type][plugin_name]
|
defs = self._plugins[plugin_type][plugin_name]
|
||||||
|
|
||||||
# Use 'variable overrides' if present, highest precedence, but only present when querying running play
|
if config in defs:
|
||||||
if variables:
|
# Use 'variable overrides' if present, highest precedence, but only present when querying running play
|
||||||
value, origin = self._loop_entries(variables, defs[config]['vars'])
|
if variables:
|
||||||
origin = 'var: %s' % origin
|
value, origin = self._loop_entries(variables, defs[config]['vars'])
|
||||||
|
origin = 'var: %s' % origin
|
||||||
|
|
||||||
# env vars are next precedence
|
# env vars are next precedence
|
||||||
if value is None and defs[config].get('env'):
|
if value is None and defs[config].get('env'):
|
||||||
value, origin = self._loop_entries(os.environ, defs[config]['env'])
|
value, origin = self._loop_entries(os.environ, defs[config]['env'])
|
||||||
origin = 'env: %s' % origin
|
origin = 'env: %s' % origin
|
||||||
|
|
||||||
# try config file entries next, if we have one
|
# try config file entries next, if we have one
|
||||||
if value is None and cfile is not None:
|
if value is None and cfile is not None:
|
||||||
ftype = get_config_type(cfile)
|
ftype = get_config_type(cfile)
|
||||||
if ftype and defs[config].get(ftype):
|
if ftype and defs[config].get(ftype):
|
||||||
if ftype == 'ini':
|
if ftype == 'ini':
|
||||||
# load from ini config
|
# load from ini config
|
||||||
try: # FIXME: generaelize _loop_entries to allow for files also, most of this code is dupe
|
try: # FIXME: generalize _loop_entries to allow for files also, most of this code is dupe
|
||||||
for ini_entry in defs[config]['ini']:
|
for ini_entry in defs[config]['ini']:
|
||||||
temp_value = get_ini_config_value(self._parser, ini_entry)
|
temp_value = get_ini_config_value(self._parser, ini_entry)
|
||||||
if temp_value is not None:
|
if temp_value is not None:
|
||||||
value = temp_value
|
value = temp_value
|
||||||
origin = cfile
|
origin = cfile
|
||||||
if 'deprecated' in ini_entry:
|
if 'deprecated' in ini_entry:
|
||||||
self.DEPRECATED.append(('[%s]%s' % (ini_entry['section'], ini_entry['key']), ini_entry['deprecated']))
|
self.DEPRECATED.append(('[%s]%s' % (ini_entry['section'], ini_entry['key']), ini_entry['deprecated']))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
sys.stderr.write("Error while loading ini config %s: %s" % (cfile, to_native(e)))
|
sys.stderr.write("Error while loading ini config %s: %s" % (cfile, to_native(e)))
|
||||||
elif ftype == 'yaml':
|
elif ftype == 'yaml':
|
||||||
# FIXME: implement, also , break down key from defs (. notation???)
|
# FIXME: implement, also , break down key from defs (. notation???)
|
||||||
origin = cfile
|
origin = cfile
|
||||||
|
|
||||||
'''
|
'''
|
||||||
# for plugins, try using existing constants, this is for backwards compatiblity
|
# for plugins, try using existing constants, this is for backwards compatiblity
|
||||||
if plugin_name and defs[config].get('constants'):
|
if plugin_name and defs[config].get('constants'):
|
||||||
value, origin = self._loop_entries(self.data, defs[config]['constants'])
|
value, origin = self._loop_entries(self.data, defs[config]['constants'])
|
||||||
origin = 'constant: %s' % origin
|
origin = 'constant: %s' % origin
|
||||||
'''
|
'''
|
||||||
|
|
||||||
# set default if we got here w/o a value
|
# set default if we got here w/o a value
|
||||||
if value is None:
|
if value is None:
|
||||||
value = defs[config].get('default')
|
value = defs[config].get('default')
|
||||||
origin = 'default'
|
origin = 'default'
|
||||||
# skip typing as this is a temlated default that will be resolved later in constants, which has needed vars
|
# skip typing as this is a temlated default that will be resolved later in constants, which has needed vars
|
||||||
if plugin_type is None and isinstance(value, string_types) and (value.startswith('{{') and value.endswith('}}')):
|
if plugin_type is None and isinstance(value, string_types) and (value.startswith('{{') and value.endswith('}}')):
|
||||||
return value, origin
|
return value, origin
|
||||||
|
|
||||||
# ensure correct type
|
# ensure correct type
|
||||||
try:
|
try:
|
||||||
value = ensure_type(value, defs[config].get('type'), origin=origin)
|
value = ensure_type(value, defs[config].get('type'), origin=origin)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.UNABLE.append(config)
|
self.UNABLE.append(config)
|
||||||
|
|
||||||
# deal with deprecation of the setting
|
# deal with deprecation of the setting
|
||||||
if 'deprecated' in defs[config] and origin != 'default':
|
if 'deprecated' in defs[config] and origin != 'default':
|
||||||
self.DEPRECATED.append((config, defs[config].get('deprecated')))
|
self.DEPRECATED.append((config, defs[config].get('deprecated')))
|
||||||
|
else:
|
||||||
|
raise AnsibleError('Requested option %s was not defined in configuration' % to_native(config))
|
||||||
|
|
||||||
return value, origin
|
return value, origin
|
||||||
|
|
||||||
|
|
4
test/units/config/test.cfg
Normal file
4
test/units/config/test.cfg
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[defaults]
|
||||||
|
inikey=fromini
|
||||||
|
matterless=lessfromini
|
||||||
|
mattermore=morefromini
|
55
test/units/config/test.yml
Normal file
55
test/units/config/test.yml
Normal file
|
@ -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
|
4
test/units/config/test2.cfg
Normal file
4
test/units/config/test2.cfg
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[defaults]
|
||||||
|
inikey=fromini2
|
||||||
|
matterless=lessfromini2
|
||||||
|
mattermore=morefromini2
|
41
test/units/config/test_data.py
Normal file
41
test/units/config/test_data.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
# Make coding more python3-ish
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
from ansible.compat.tests 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)
|
47
test/units/config/test_manager.py
Normal file
47
test/units/config/test_manager.py
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
# Make coding more python3-ish
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from ansible.compat.tests import unittest
|
||||||
|
|
||||||
|
from ansible.config.manager import ConfigManager, Setting
|
||||||
|
|
||||||
|
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')}
|
||||||
|
|
||||||
|
|
||||||
|
class TestConfigData(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.manager = ConfigManager(os.path.join(curdir, 'test.cfg'), os.path.join(curdir, 'test.yml'))
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.manager = None
|
||||||
|
|
||||||
|
def test_initial_load(self):
|
||||||
|
self.assertEquals(self.manager.data._global_settings, expected_ini)
|
||||||
|
|
||||||
|
def test_value_and_origin_from_ini(self):
|
||||||
|
self.assertEquals(self.manager.get_config_value_and_origin('config_entry'), ('fromini', cfg_file))
|
||||||
|
|
||||||
|
def test_value_from_ini(self):
|
||||||
|
self.assertEquals(self.manager.get_config_value('config_entry'), 'fromini')
|
||||||
|
|
||||||
|
def test_value_and_origin_from_alt_ini(self):
|
||||||
|
self.assertEquals(self.manager.get_config_value_and_origin('config_entry', cfile=cfg_file2), ('fromini2', cfg_file2))
|
||||||
|
|
||||||
|
def test_value_from_alt_ini(self):
|
||||||
|
self.assertEquals(self.manager.get_config_value('config_entry', cfile=cfg_file2), 'fromini2')
|
Loading…
Reference in a new issue