...
 
Commits (4)
......@@ -14,11 +14,10 @@ function(CopyFilesFromSource TARGET SOURCE_FILES)
if (NOT IN_SOURCE_BUILD)
add_custom_target(${TARGET} ALL SOURCES ${SOURCE_FILES})
foreach (infile ${SOURCE_FILES})
string(REPLACE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} outfile ${infile})
#message("-- staging for copy: ${CMAKE_CURRENT_SOURCE_DIR}/${infile} -> ${CMAKE_CURRENT_BINARY_DIR}/${outfile}")
#message("-- staging for copy: ${CMAKE_CURRENT_SOURCE_DIR}/${infile} -> ${CMAKE_CURRENT_BINARY_DIR}/${infile}")
add_custom_command(
TARGET ${TARGET}
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${infile} ${outfile}
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${infile} ${infile}
VERBATIM
)
endforeach()
......
......@@ -16,6 +16,8 @@ foreach (infile ${INIT_FILES})
endforeach (infile)
CopyFilesFromSource(augeas_lens "agocontrol.aug")
add_subdirectory (conf.d)
add_subdirectory (schema.d)
add_subdirectory (sysvinit)
......
cmake_minimum_required (VERSION 3.0)
file (GLOB CONFD_FILES *.in)
file (GLOB CONFD_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.in)
foreach (infile ${CONFD_FILES})
string(REGEX REPLACE ".in$" "" outfile ${infile})
string(REGEX REPLACE ".*/" "" outfile ${outfile})
configure_file(
"${infile}"
"${CMAKE_CURRENT_BINARY_DIR}/${outfile}"
@ONLY
)
LIST(APPEND CONFD_FILES_DONE ${CMAKE_CURRENT_BINARY_DIR}/${outfile})
LIST(APPEND CONFD_FILES_DONE ${outfile})
endforeach (infile)
file (GLOB CONFD_FILES *.conf)
install (FILES ${CONFD_FILES_DONE} ${CONFD_FILES} DESTINATION ${CONFDIR}/conf.d)
file (GLOB CONFD_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.conf)
CopyFilesFromSource(conf_files "${CONFD_FILES}")
InstallFiles(${CONFDIR}/conf.d "${CONFD_FILES_DONE};${CONFD_FILES}")
......@@ -3,6 +3,7 @@ from __future__ import print_function
import agoclient._logging
import argparse
from . import config
import logging
import os.path
......@@ -424,6 +425,29 @@ class AgoApp:
return config.get_config_option(section, option, default_value, app)
def get_config_section(self, section=None, app=None):
"""Read all options in the given section(s) from the configuration subsystem.
Same as get_config_option, but will return a dict with all defined values under the given
section(s). If more than one section/app is defined, all will be looked at, in the order
specified. If an option is set in multiple sections/app, the last one seen will be used.
Returns a dict with key/values.
"""
if section is None:
section = self.app_short_name
if app is None:
if type(section) == str:
app = [self.app_short_name, section]
else:
app = [self.app_short_name] + section
config._iterable_replace_none(section, self.app_short_name)
config._iterable_replace_none(app, self.app_short_name)
return config.get_config_section(section, app)
def set_config_option(self, option, value, section=None, app=None):
"""Write a config option to the configuration subsystem.
......
......@@ -20,7 +20,6 @@ try:
HAS_MQTT = True
except ImportError:
HAS_MQTT = False
raise
class AgoConnection:
......
......@@ -77,7 +77,6 @@ def _conf_file_path(filename):
def _augeas_path(path, section, option):
return "/files%s/%s/%s" % (path, section, option)
return "/files%s/%s/%s" % (path, section, option)
def get_config_option(section, option, default_value=None, app=None):
......@@ -110,7 +109,28 @@ def get_config_option(section, option, default_value=None, app=None):
A unicode object with the value found in the data store, if found.
If not found, default_value is passed through unmodified.
"""
if not augeas: _augeas_init()
value = _get_config_option(section, option, app)
if not value:
return default_value
return value
def get_config_section(section, app=None):
"""Read all options in the given section(s) from the configuration subsystem.
Same as get_config_option, but will return a dict with all defined values under the given
section(s). If more than one section/app is defined, all will be looked at, in the order
specified. If an option is set in multiple sections/app, the last one seen will be used.
Returns a dict with key/values.
"""
return _get_config_option(section, None, app)
def _get_config_option(section, option=None, app=None):
if not augeas:
_augeas_init()
if type(section) == str:
section = (section,)
......@@ -120,25 +140,47 @@ def get_config_option(section, option, default_value=None, app=None):
elif type(app) == str:
app = (app,)
CONFIG_LOCK.acquire(True)
try:
results = {} # Only used for multi-match
with CONFIG_LOCK:
for fn in app:
for s in section:
path = _conf_file_path(fn)
aug_path = _augeas_path(path, s, option)
for s in section:
if option:
try:
aug_path = _augeas_path(path, s, option)
value = augeas.get(aug_path)
if value:
# First match
return value
except ValueError as e:
logging.error("Failed to read configuration from %s: %s",
aug_path, e)
finally:
CONFIG_LOCK.release()
logging.error("Failed to read configuration from %s: %s", aug_path, e)
else:
# list find all options in section
base_path = _augeas_path(path, s, '')
try:
matches = augeas.match(base_path + '*')
# match returns a list of full paths; figure out each key and put in dict
for path in matches:
key = path[len(base_path):]
# Fall back on default value
return default_value
# First found takes precedence, just as get_config_option behaves.
if key[0] == '#' or key in results:
continue
try:
value = augeas.get(path)
results[key] = value
except ValueError as e:
logging.error("Failed to read configuration from %s: %s", path, e)
except ValueError as e:
logging.error("Failed to read configuration from %s: %s", aug_path, e)
if not option:
return results
return None
def set_config_option(section, option, value, app=None):
......
import unittest
import agoclient.config as config
from agoclient.agoapp import AgoApp
import tempfile
import os, os.path, shutil
# Find checkedout code dir:
# We're in subdir shared/agoclient/
devdir = os.path.realpath(os.path.dirname(os.path.realpath(__file__)) + "/../..")
class AgoTest(AgoApp):
pass
class ConfigTestBase(unittest.TestCase):
def setUp(self):
# Create dummy conf
self.tempdir = tempfile.mkdtemp()
os.mkdir("%s/conf.d" % self.tempdir)
# Custom dir, we must place agocontrol.aug into this dir
# TODO: or add some dir in loadpath?
shutil.copyfile("%s/conf/agocontrol.aug" % devdir, "%s/agocontrol.aug" % self.tempdir)
shutil.copyfile("%s/conf/conf.d/system.conf" % devdir, "%s/conf.d/system.conf" % self.tempdir)
config.set_config_dir(self.tempdir)
with open(config.get_config_path('conf.d/test.conf'), 'w') as f:
f.write("[test]\n"+
"test_value_0=100\n"+
"test_value_blank=\n"+
"local=4\n"+
"units=inv\n"+
"[system]\n"+
"password=testpwd\n"+
"[sec2]\n"+
"some=value\n"+
"test_value_blank=not blank\n")
# Kill augeas
config.augeas = None
def tearDown(self):
shutil.rmtree(self.tempdir)
class ConfigTest(ConfigTestBase):
def setUp(self):
super(ConfigTest, self).setUp()
global gco, sco
gco = config.get_config_option
sco = config.set_config_option
def test_get_path(self):
self.assertEqual(config.get_config_path("conf.d"), "%s/conf.d" % self.tempdir)
self.assertEqual(config.get_config_path("conf.d/"), "%s/conf.d/" % self.tempdir)
self.assertEqual(config.get_config_path("/conf.d/"), "%s/conf.d/" % self.tempdir)
def test_get_basic(self):
self.assertEqual(gco('system', 'broker'), 'localhost')
self.assertEqual(gco('system', 'not_set'), None)
self.assertEqual(gco('test', 'test_value_blank'), None)
self.assertEqual(gco('test', 'local'), '4')
# Test with defaults
self.assertEqual(gco('system', 'broker', 'def'), 'localhost')
self.assertEqual(gco('system', 'not_set', 'def'), 'def')
def test_get_multiapp(self):
self.assertEqual(gco('system', 'broker', app="test"), None)
self.assertEqual(gco('system', 'broker', app=["test", "system"]), 'localhost')
self.assertEqual(gco('system', 'password', app=["test", "system"]), 'testpwd')
def test_get_multisection(self):
# Must explicitly tell app=test, with differnet section name
self.assertEqual(gco('sec2', 'some', app='test'), 'value')
self.assertEqual(gco(['sec2', 'test'], 'test_value_blank', app='test'), 'not blank')
self.assertEqual(gco(['system'], 'units'), 'SI')
self.assertEqual(gco(['test', 'system'], 'units'), 'inv')
def test_set_basic(self):
self.assertEqual(sco('system', 'new_value', '666'), True)
self.assertEqual(gco('system', 'new_value'), '666')
self.assertEqual(sco('system', 'test_string', 'goodbye'), True)
self.assertEqual(gco('system', 'test_string'), 'goodbye')
def test_set_new(self):
self.assertFalse(os.path.exists(config.get_config_path("conf.d/newfile.conf")))
self.assertEqual(sco('newfile', 'new_value', '666'), True)
self.assertTrue(os.path.exists(config.get_config_path("conf.d/newfile.conf")))
self.assertEqual(gco('newfile', 'new_value'), '666')
def test_unwritable(self):
if os.getuid() == 0:
# TODO: Fix builders so they dont run as root, then change to self.fail instead.
#self.fail("You cannot run this test as. Also, do not develop as root!")
print("You cannot run this test as. Also, do not develop as root!")
return
with open(config.get_config_path('conf.d/blocked.conf'), 'w') as f:
f.write("[blocked]\nnop=nop\n")
os.chmod(config.get_config_path('conf.d/blocked.conf'), 0o444)
self.assertEqual(gco('blocked', 'nop'), 'nop')
# This shall fail, and write log msg
self.assertEqual(sco('blocked', 'new_value', '666'), False)
os.chmod(config.get_config_path('conf.d/blocked.conf'), 0)
# reload
config.augeas = None
self.assertEqual(gco('blocked', 'nop'), None)
self.assertEqual(gco('blocked', 'nop', 'def'), 'def')
class AppConfigTest(ConfigTestBase):
def setUp(self):
super(AppConfigTest, self).setUp()
self.app = AgoTest()
global gco, sco
gco = self.app.get_config_option
sco = self.app.set_config_option
def test_get_basic(self):
self.assertEqual(gco('test_value_0'), '100')
self.assertEqual(gco('test_value_1'), None)
self.assertEqual(gco('units'), 'inv')
def test_get_section(self):
# from system.conf:
self.assertEqual(gco('broker', section='system'), 'localhost')
# from test.conf:
self.assertEqual(gco('password', section='system'), 'testpwd')
def test_get_app(self):
# Will give None, since we're looking in section test, which is not in system.conf
self.assertEqual(gco('test_value_0', app=['other', 'system']), None)
# Will give system.confs password
self.assertEqual(gco('password', app=['other', 'system'], section='system'), 'letmein')
def test_set_basic(self):
self.assertEqual(sco('new_value', '666'), True)
self.assertEqual(gco('new_value'), '666')
self.assertEqual(sco('test_string', 'goodbye'), True)
self.assertEqual(gco('test_string'), 'goodbye')
def test_set_section(self):
self.assertEqual(sco('some_value', '0', 'sec2'), True)
self.assertEqual(gco('some_value'), None)
self.assertEqual(gco('some_value', section='sec2'), '0')
def test_set_new_file(self):
self.assertFalse(os.path.exists(config.get_config_path("conf.d/newfile.conf")))
self.assertEqual(sco('new_value', '666', section='newfile'), True)
self.assertTrue(os.path.exists(config.get_config_path("conf.d/newfile.conf")))
self.assertEqual(gco('new_value', section='newfile'), '666')
......@@ -216,6 +216,31 @@ namespace agocontrol {
return getConfigSectionOption(section_, option, defaultValue, app_);
}
/**
* Read all options in the given section from the configuration subsystem.
*
* Returns a map of all found values in the given section/app.
* If an explicit section/app is set, we only look in those.
* If extra section is used, we look in apps own section first, then on the given extra section.
* If extra app is used, we look in the apps own file first, then in the given extra file.
*
* Note that we do not automaticall set app = section in this method!
*/
std::map<std::string, std::string> getConfigSection(const ConfigNameList &section=BLANK_CONFIG_NAME_LIST, const ConfigNameList &app = BLANK_CONFIG_NAME_LIST) {
ConfigNameList section_(section, appConfigSection);
ConfigNameList app_;
if(!app.empty() && !app.isExtra()) {
app_.addAll(app);
}else if(!app.empty()) {
app_.add(appConfigSection);
app_.addAll(app);
}else
app_.add(appConfigSection);
return agocontrol::getConfigSection(section_, app_);
}
/**
* Write a config option to the configuration subsystem.
*
......
......@@ -257,6 +257,7 @@ const ConfigNameList BLANK_CONFIG_NAME_LIST = ConfigNameList();
ConfigNameList::ConfigNameList(const char* name) {
extra = false;
if(name != nullptr)
add(name);
}
......@@ -359,6 +360,49 @@ std::string getConfigSectionOption(const ConfigNameList& section, const std::str
return std::string();
}
std::map<std::string, std::string> getConfigSection(const ConfigNameList& section, const ConfigNameList &app) {
std::map<std::string, std::string> result;
if (augeas==NULL){
if(!augeas_init()) {
return result;
}
}
// If app has no values, default to section
ConfigNameList app_(app, section);
AGO_TRACE() << "Augeas: get all " << app_ << " / " << section;
BOOST_FOREACH(const std::string & a, app_.names()) {
BOOST_FOREACH(const std::string & s, section.names()) {
char **paths = NULL;
std::string match_path = augeasPath(confPathFromApp(a), s, "*");
int ret = aug_match(augeas, match_path.c_str(), &paths);
for(int i=0; i < ret; i++) {
char *path = paths[i];
const char *value;
if(aug_get(augeas, path, &value) == 1 && value) {
std::string key(path + match_path.size()-1);
if(key[0] == '#')
continue;
// First found takes precedence, just as getConfigSectionOption behaves.
if(result.find(key) != result.end())
continue;
AGO_TRACE() << "Augeas: found matching option in " << path << ", " << key << "=" << value;
result[key] = value;
}
free(path);
}
free(paths);
}
}
return result;
}
bool setConfigSectionOption(const std::string& section, const std::string& option, float value, const std::string& app) {
std::stringstream stringvalue;
stringvalue << value;
......
......@@ -57,8 +57,6 @@ namespace agocontrol {
std::list<std::string> name_list;
protected:
bool extra;
bool isExtra() const { return extra; }
ConfigNameList& addAll(const ConfigNameList& names) ;
public:
ConfigNameList() : extra(false) {}
......@@ -67,8 +65,10 @@ namespace agocontrol {
ConfigNameList(const ConfigNameList &names) ;
ConfigNameList(const ConfigNameList &names1, const ConfigNameList &names2) ;
ConfigNameList& add(const std::string &name) ;
ConfigNameList& addAll(const ConfigNameList& names) ;
int empty() const { return name_list.empty(); }
int size() const { return name_list.size(); }
bool isExtra() const { return extra; }
const std::list<std::string>& names() const { return name_list; }
friend std::ostream& operator<< (std::ostream& os, const ConfigNameList &list) ;
......@@ -81,7 +81,19 @@ namespace agocontrol {
public:
ExtraConfigNameList(const std::string& name)
: ConfigNameList(name)
{extra = true;}
{
extra = true;
}
static ExtraConfigNameList toExtra(const ConfigNameList& existing) {
ExtraConfigNameList n;
n.addAll(existing);
return n;
}
private:
ExtraConfigNameList() {
extra = true;
}
};
/* Use this for default values */
......@@ -103,7 +115,7 @@ namespace agocontrol {
* section -- A ConfigNameList section to look for the option in.
* Note that a regular string can be passed, it will create an implicit ConfigNameList.
*
* option -- The name of the option to retreive
* option -- The name of the option to retrieve
*
* defaultValue -- If the option can not be found in any of the specified
* sections, fall back to this value.
......@@ -123,6 +135,19 @@ namespace agocontrol {
std::string getConfigSectionOption(const ConfigNameList& section, const std::string& option, const char* defaultValue, const ConfigNameList& app = BLANK_CONFIG_NAME_LIST);
std::string getConfigSectionOption(const ConfigNameList& section, const std::string& option, const std::string& defaultValue, const ConfigNameList& app = BLANK_CONFIG_NAME_LIST);
boost::filesystem::path getConfigSectionOption(const ConfigNameList& section, const std::string& option, const boost::filesystem::path& defaultValue, const ConfigNameList& app = BLANK_CONFIG_NAME_LIST);
/**
* Read one or more configuration sections, and return all options as a map.
*
* Section and app arguments behaves same way as for getConfigSectionOption.
* If the key is found in multiple locations, the first match is used (same way as getConfigSectionOption would
* return that specific option).
*
* @param section
* @param app
* @return
*/
std::map<std::string, std::string> getConfigSection(const ConfigNameList& section, const ConfigNameList &app);
Json::Value getConfigTree();
/**
......
......@@ -17,7 +17,9 @@ target_link_libraries (testrunner ${TEST_LIBRARIES})
add_test( cpp-test testrunner )
add_test( python-test python -m unittest discover -s ../shared/ )
add_test( python-test pytest -v ${CMAKE_CURRENT_SOURCE_DIR}/python/)
set_tests_properties(python-test PROPERTIES
ENVIRONMENT PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}/../python/)
# Shortcut to build and run all tests
add_custom_target(check
......
import pytest
import agoclient.config as config
from agoclient.agoapp import AgoApp
import os, os.path, shutil
# Find checkedout code dir:
# We're in subdir python/agoclient/
devdir = os.path.realpath(os.path.dirname(os.path.realpath(__file__)) + "/../..")
class AgoTest(AgoApp):
pass
@pytest.fixture
def setup_config(tmpdir):
# Create dummy conf
conf_d = tmpdir.mkdir('conf.d')
# Custom dir, we must place agocontrol.aug into this dir
# TODO: or add some dir in loadpath?
shutil.copyfile("%s/conf/agocontrol.aug" % devdir, str(tmpdir.join("agocontrol.aug")))
shutil.copyfile("%s/conf/conf.d/system.conf" % devdir, str(conf_d.join("system.conf")))
config.set_config_dir(str(tmpdir))
with open(config.get_config_path('conf.d/test.conf'), 'w') as f:
f.write("[test]\n"+
"test_value_0=100\n"+
"test_value_blank=\n"+
"local=4\n"+
"units=inv\n"+
"[system]\n"+
"password=testpwd\n"+
"[sec2]\n"+
"some=value\n"+
"test_value_blank=not blank\n")
# Kill augeas
config.augeas = None
yield str(tmpdir)
tmpdir.remove()
@pytest.fixture
def app_sut(setup_config):
app = AgoTest()
yield app
gco = config.get_config_option
sco = config.set_config_option
class TestConfig:
def test_get_path(self, setup_config):
assert config.get_config_path("conf.d") == "%s/conf.d" % setup_config
assert config.get_config_path("conf.d/") == "%s/conf.d/" % setup_config
assert config.get_config_path("/conf.d/") == "%s/conf.d/" % setup_config
def test_get_basic(self, setup_config):
assert gco('system', 'broker') == 'localhost'
assert gco('system', 'not_set') is None
assert gco('test', 'test_value_blank') is None
assert gco('test', 'local') == '4'
# Test with defaults
assert gco('system', 'broker', 'def') == 'localhost'
assert gco('system', 'not_set', 'def') == 'def'
def test_get_multiapp(self, setup_config):
assert gco('system', 'broker', app="test") is None
assert gco('system', 'broker', app=["test", "system"]) == 'localhost'
assert gco('system', 'password', app=["test", "system"]) == 'testpwd'
def test_get_multisection(self, setup_config):
# Must explicitly tell app=test, with differnet section name
assert gco('sec2', 'some', app='test') == 'value'
assert gco(['sec2', 'test'], 'test_value_blank', app='test') == 'not blank'
assert gco(['system'], 'units') == 'SI'
assert gco(['test', 'system'], 'units') == 'inv'
def test_get_section(self, setup_config):
d = config.get_config_section(['system'], ['system'])
assert d['broker'] == 'localhost'
assert d['password'] == 'letmein'
assert d['uuid'] == '00000000-0000-0000-000000000000'
d = config.get_config_section(['system'], ['test', 'system'])
assert d['password'] == 'testpwd'
assert d['broker'] == 'localhost'
assert d['uuid'] == '00000000-0000-0000-000000000000'
def test_set_basic(self, setup_config):
assert sco('system', 'new_value', '666')
assert gco('system', 'new_value') == '666'
assert sco('system', 'test_string', 'goodbye')
assert gco('system', 'test_string') == 'goodbye'
def test_set_new(self, setup_config):
assert not os.path.exists(config.get_config_path("conf.d/newfile.conf"))
assert sco('newfile', 'new_value', '666') == True
assert os.path.exists(config.get_config_path("conf.d/newfile.conf"))
assert gco('newfile', 'new_value') == '666'
def test_unwritable(self, setup_config):
if os.getuid() == 0:
# TODO: Fix builders so they dont run as root, then change to self.fail instead.
#self.fail("You cannot run this test as. Also, do not develop as root!")
print("You cannot run this test as. Also, do not develop as root!")
return
with open(config.get_config_path('conf.d/blocked.conf'), 'w') as f:
f.write("[blocked]\nnop=nop\n")
os.chmod(config.get_config_path('conf.d/blocked.conf'), 0o444)
assert gco('blocked', 'nop') == 'nop'
# This shall fail, and write log msg
assert not sco('blocked', 'new_value', '666')
os.chmod(config.get_config_path('conf.d/blocked.conf'), 0)
# reload
config.augeas = None
assert gco('blocked', 'nop') == None
assert gco('blocked', 'nop', 'def') == 'def'
class TestAppConfig:
def test_get_basic(self, app_sut):
assert app_sut.get_config_option('test_value_0') == '100'
assert app_sut.get_config_option('test_value_1') is None
assert app_sut.get_config_option('units') == 'inv'
def test_get_section(self, app_sut):
# from system.conf:
assert app_sut.get_config_option('broker', section='system') == 'localhost'
# from test.conf:
assert app_sut.get_config_option('password', section='system') == 'testpwd'
def test_get_app(self, app_sut):
# Will give None, since we're looking in section test, which is not in system.conf
assert app_sut.get_config_option('test_value_0', app=['other', 'system']) is None
# Will give system.confs password
assert app_sut.get_config_option('password', app=['other', 'system'], section='system') == 'letmein'
def test_get_section(self, app_sut):
d = app_sut.get_config_section()
assert d == dict(test_value_0='100',
test_value_blank=None,
local='4',
units='inv')
d = app_sut.get_config_section(['system'], ['system'])
assert d['broker'] == 'localhost'
assert d['password'] == 'letmein'
assert d['uuid'] == '00000000-0000-0000-000000000000'
d = app_sut.get_config_section(['system'], ['test', 'system'])
assert d['password'] == 'testpwd'
assert d['broker'] == 'localhost'
assert d['uuid'] == '00000000-0000-0000-000000000000'
assert 'test_value_blank' not in d # from test section
def test_set_basic(self, app_sut):
assert app_sut.set_config_option('new_value', '666') == True
assert app_sut.get_config_option('new_value') == '666'
assert app_sut.set_config_option('test_string', 'goodbye') == True
assert app_sut.get_config_option('test_string') == 'goodbye'
def test_set_section(self, app_sut):
assert app_sut.set_config_option('some_value', '0', 'sec2') == True
assert app_sut.get_config_option('some_value') is None
assert app_sut.get_config_option('some_value', section='sec2') == '0'
def test_set_new_file(self, app_sut):
assert not os.path.exists(config.get_config_path("conf.d/newfile.conf"))
assert app_sut.set_config_option('new_value', '666', section='newfile')
assert os.path.exists(config.get_config_path("conf.d/newfile.conf"))
assert app_sut.get_config_option('new_value', section='newfile') == '666'
......@@ -21,6 +21,7 @@ class TestAgoConfig : public CppUnit::TestFixture
CPPUNIT_TEST( testSetError );
CPPUNIT_TEST( testAppSet );
CPPUNIT_TEST( testAppGet );
CPPUNIT_TEST( testAppGetSection );
CPPUNIT_TEST_SUITE_END();
ConfigNameList empty;
......@@ -39,6 +40,7 @@ public:
void testSetError();
void testAppGet();
void testAppGetSection();
void testAppSet();
};
......@@ -56,6 +58,9 @@ public:
CPPUNIT_ASSERT_EQUAL(std::string(expected), (actual))
#define ASSERT_NOSTR(actual) \
CPPUNIT_ASSERT_EQUAL(std::string(), (actual))
#define ASSERT_MAP_STR(expected, key, map) \
CPPUNIT_ASSERT(map.find(key) != map.end()); \
ASSERT_STR(expected, map.find(key)->second)
void TestAgoConfig::setUp() {
tempDir = fs::temp_directory_path() / fs::unique_path();
......@@ -102,6 +107,11 @@ void TestAgoConfig::testBasicGet() {
ASSERT_STR("localhost", getConfigSectionOption("system", "broker", nullptr));
ASSERT_STR("value", getConfigSectionOption("test", "existing_key", nullptr));
auto map = getConfigSection("test", nullptr);
CPPUNIT_ASSERT_EQUAL((size_t)1, map.size());
ASSERT_MAP_STR("value", "existing_key", map);
}
void TestAgoConfig::testFallbackGet() {
......@@ -136,6 +146,10 @@ void TestAgoConfig::testSimulatedAppGet() {
// Overriden in test.conf
ASSERT_STR("testpwd", getConfigSectionOption(section, "password", nullptr, app));
auto map = getConfigSection(section, app);
CPPUNIT_ASSERT_EQUAL((size_t)2, map.size());
ASSERT_MAP_STR("testpwd", "password", map);
ASSERT_MAP_STR("value", "existing_key", map);
// from system.conf; will not be found since we only look in app test
ASSERT_NOSTR(getConfigSectionOption(section, "broker", nullptr, app));
......@@ -146,6 +160,13 @@ void TestAgoConfig::testSimulatedAppGet() {
// Add system to app, and make sure we now can read broker
app.add("system");
ASSERT_STR("localhost", getConfigSectionOption(section, "broker", nullptr));
map = getConfigSection(section, app);
CPPUNIT_ASSERT_GREATEREQUAL((size_t)8, map.size());
ASSERT_MAP_STR("testpwd", "password", map);
ASSERT_MAP_STR("value", "existing_key", map);
ASSERT_MAP_STR("00000000-0000-0000-000000000000", "uuid", map);
ASSERT_MAP_STR("SI", "units", map);
}
void TestAgoConfig::testBasicSet() {
......@@ -191,15 +212,38 @@ void TestAgoConfig::testAppGet() {
// This should go directly to system.conf, only
ASSERT_STR("localhost", app.getConfigOption("broker", nullptr, "system"));
ASSERT_STR("letmein", app.getConfigOption("password", nullptr, "system"));
ASSERT_NOSTR(app.getConfigOption("nonexisting_key", nullptr, "system"));
ASSERT_NOSTR(app.getConfigOption("existing_key", nullptr, "system"));
// This shall fall back on system.conf
ASSERT_STR("localhost", app.getConfigOption("broker", nullptr, ExtraConfigNameList("system")));
ASSERT_STR("testpwd", app.getConfigOption("password", nullptr, ExtraConfigNameList("system")));
ASSERT_NOSTR(app.getConfigOption("nonexisting_key", nullptr, ExtraConfigNameList("system")));
ASSERT_STR("value", app.getConfigOption("existing_key", nullptr, ExtraConfigNameList("system")));
}
void TestAgoConfig::testAppGetSection() {
DummyUnitTestApp app;
// This should get the app only
auto map = app.getConfigSection(nullptr, nullptr);
CPPUNIT_ASSERT_EQUAL((size_t)1, map.size());
ASSERT_MAP_STR("value", "existing_key", map);
// This sould only get system
map = app.getConfigSection("system", "system");
ASSERT_MAP_STR("letmein", "password", map);
// This should fall back on system
map = app.getConfigSection("system", ExtraConfigNameList("system"));
ASSERT_MAP_STR("testpwd", "password", map);
ASSERT_MAP_STR("00000000-0000-0000-000000000000", "uuid", map);
ASSERT_MAP_STR("SI", "units", map);
CPPUNIT_ASSERT(map.find("existing_key") == map.end());
}
void TestAgoConfig::testAppSet() {
DummyUnitTestApp app;
ASSERT_NOSTR(app.getConfigOption("nonexisting_key", nullptr));
......