diff options
author | RaNaN <Mast3rRaNaN@hotmail.de> | 2013-01-02 18:11:31 +0100 |
---|---|---|
committer | RaNaN <Mast3rRaNaN@hotmail.de> | 2013-01-02 18:11:31 +0100 |
commit | 6b20f5f6c063e4e6c94d719b607ad5a028b8beee (patch) | |
tree | a8c3dfa9962aa819507870553700a35b7dcc4c74 | |
parent | Remove '/' from filename to avoid filepath exception (diff) | |
download | pyload-6b20f5f6c063e4e6c94d719b607ad5a028b8beee.tar.xz |
new configManager for multi user configs
-rw-r--r-- | module/AddonManager.py | 9 | ||||
-rw-r--r-- | module/Api.py | 4 | ||||
-rw-r--r-- | module/PluginManager.py | 3 | ||||
-rw-r--r-- | module/config/ConfigManager.py | 118 | ||||
-rw-r--r-- | module/config/ConfigParser.py | 130 | ||||
-rw-r--r-- | module/config/default.py | 30 | ||||
-rw-r--r-- | module/database/ConfigDatabase.py | 5 | ||||
-rw-r--r-- | module/datatypes/User.py | 5 | ||||
-rw-r--r-- | module/remote/pyload.thrift | 4 | ||||
-rw-r--r-- | module/remote/ttypes.py | 6 | ||||
-rw-r--r-- | module/remote/ttypes_debug.py | 1 | ||||
-rwxr-xr-x | pyLoadCore.py | 15 | ||||
-rw-r--r-- | tests/api/test_WebSocketBackend.py (renamed from tests/api/test_WebSocketAPI.py) | 2 | ||||
-rw-r--r-- | tests/api/test_noargs.py | 2 | ||||
-rw-r--r-- | tests/helper/Stubs.py | 14 | ||||
-rw-r--r-- | tests/manager/test_configManager.py | 101 | ||||
-rw-r--r-- | tests/other/test_configparser.py | 50 |
17 files changed, 330 insertions, 169 deletions
diff --git a/module/AddonManager.py b/module/AddonManager.py index 4283b4652..ad6daaf83 100644 --- a/module/AddonManager.py +++ b/module/AddonManager.py @@ -45,9 +45,6 @@ class AddonManager: self.lock = RLock() self.createIndex() - #registering callback for config event - self.config.changeCB = MethodType(self.dispatchEvent, "configChanged", basestring) - # manage addons an config change self.addEvent("configChanged", self.manageAddons) @@ -64,8 +61,7 @@ class AddonManager: return func(*args) except Exception, e: addon.logError(_("Error when executing %s" % f), e) - if self.core.debug: - print_exc() + self.core.print_exc() def addRPC(self, plugin, func, doc): doc = doc.strip() if doc else "" @@ -114,8 +110,7 @@ class AddonManager: except: self.log.warning(_("Failed activating %(name)s") % {"name": pluginname}) - if self.core.debug: - print_exc() + self.core.print_exc() self.log.info(_("Activated addons: %s") % ", ".join(sorted(active))) self.log.info(_("Deactivate addons: %s") % ", ".join(sorted(deactive))) diff --git a/module/Api.py b/module/Api.py index 0b777a659..fb3c59483 100644 --- a/module/Api.py +++ b/module/Api.py @@ -302,7 +302,8 @@ class Api(Iface): def getConfig(self): """Retrieves complete config of core. - :return: map of `ConfigHolder` + :rtype : ConfigHolder + :return: dict with section mapped to config """ # TODO return dict([(section, ConfigHolder(section, data.name, data.description, data.long_desc, [ @@ -765,6 +766,7 @@ class Api(Iface): p = self.core.files.getPackage(pid) if not p: raise PackageDoesNotExists(pid) + #TODO: fix for key, value in data.iteritems(): if key == "id": continue setattr(p, key, value) diff --git a/module/PluginManager.py b/module/PluginManager.py index 2bd438c37..31ad38625 100644 --- a/module/PluginManager.py +++ b/module/PluginManager.py @@ -62,7 +62,8 @@ class PluginManager: self.history = [] # match history to speedup parsing (type, name) self.createIndex() - self.core.config.parseValues(self.core.config.PLUGIN) + # TODO, replacement for this? + #self.core.config.parseValues(self.core.config.PLUGIN) #register for import addon sys.meta_path.append(self) diff --git a/module/config/ConfigManager.py b/module/config/ConfigManager.py new file mode 100644 index 000000000..3ee66bc85 --- /dev/null +++ b/module/config/ConfigManager.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from new_collections import OrderedDict + +from module.Api import InvalidConfigSection +from module.common.json_layer import json +from module.utils import from_string + +from ConfigParser import ConfigParser + + +def convertKeyError(func): + """ converts KeyError into InvalidConfigSection """ + + def conv(*args, **kwargs): + try: + return func(*args, **kwargs) + except KeyError: + raise InvalidConfigSection(args[1]) + + return conv + + +class ConfigManager(ConfigParser): + """ Manages the core config and configs for addons and single user. + Has similar interface to ConfigParser. """ + + def __init__(self, core, parser): + # No __init__ call to super class is needed! + + self.core = core + self.db = core.db + # The config parser, holding the core config + self.parser = parser + + # similar to parser, separated meta data and values + self.config = OrderedDict() + + # Value cache for multiple user configs + # Values are populated from db on first access + # Entries are saved as (user, section) keys + self.values = {} + # TODO: similar to a cache, could be deleted periodically + + def save(self): + self.parser.save() + + @convertKeyError + def get(self, section, option, user=None): + """get config value, core config only available for admins. + if user is not valid default value will be returned""" + + # Core config loaded from parser, when no user is given or he is admin + if section in self.parser and (not user or(user and user.isAdmin())): + return self.parser.get(section, option) + else: + # We need the id and not the instance + # Will be None for admin user and so the same as internal access + user = user.handle if user else None + try: + # Check if this config exists + # Configs without meta data can not be loaded! + data = self.config[section].config[option] + self.loadValues(user, section) + return self.values[user, section][option] + except KeyError: + pass # Returns default value later + + return self.config[section].config[option].default + + def loadValues(self, user, section): + if (user, section) not in self.values: + conf = self.db.loadConfig(section, user) + try: + self.values[user, section] = json.loads(conf) if conf else {} + except ValueError: # Something did go wrong when parsing + self.values[user, section] = {} + self.core.print_exc() + + @convertKeyError + def set(self, section, option, value, sync=True, user=None): + """ set config value """ + + changed = False + if section in self.parser and (not user or (user and user.isAdmin())): + changed = self.parser.set(section, option, value, sync) + else: + # associated id + user = user.handle if user else None + data = self.config[section].config[option] + value = from_string(value, data.type) + old_value = self.get(section, option) + + # Values will always be saved to db, sync is ignored + if value != old_value: + changed = True + self.values[user, section][option] = value + self.saveValues(user, section) + + if changed: self.core.evm.dispatchEvent("configChanged", value) + return changed + + def saveValues(self, user, section): + self.db.saveConfig(section, json.dumps(self.values[user, section]), user) + + def delete(self, section, user=False): + """ Deletes values saved in db and cached values for given user, NOT meta data + Does not trigger an error when nothing was deleted. """ + user = user.handle if user else None + if (user, section) in self.values: + del self.values[user, section] + + self.db.deleteConfig(section, user) + + + def iterSections(self): + pass
\ No newline at end of file diff --git a/module/config/ConfigParser.py b/module/config/ConfigParser.py index 3cad67bc2..135e84bbc 100644 --- a/module/config/ConfigParser.py +++ b/module/config/ConfigParser.py @@ -17,25 +17,20 @@ ConfigData = namedtuple("ConfigData", "name type description default") class ConfigParser: """ - Holds and manages the configuration + meta data for core and every user. + Holds and manages the configuration + meta data for config read from file. """ CONFIG = "pyload.conf" - PLUGIN = "plugin.conf" - def __init__(self): - """Constructor""" + def __init__(self, config=None): - # core config sections from pyload - self.baseSections = [] + if config: self.CONFIG = config # Meta data information self.config = OrderedDict() # The actual config values self.values = {} - self.changeCB = None # callback when config value was changed - self.checkVersion() self.loadDefault() @@ -50,22 +45,21 @@ class ConfigParser: # workaround conflict, with GUI (which also accesses the config) so try read in 3 times for i in range(0, 3): try: - for conf in (self.CONFIG, self.PLUGIN): - if exists(conf): - f = open(conf, "rb") - v = f.readline() - f.close() - v = v[v.find(":") + 1:].strip() - - if not v or int(v) < CONF_VERSION: - f = open(conf, "wb") - f.write("version: " + str(CONF_VERSION)) - f.close() - print "Old version of %s deleted" % conf - else: - f = open(conf, "wb") - f.write("version:" + str(CONF_VERSION)) + if exists(self.CONFIG): + f = open(self.CONFIG, "rb") + v = f.readline() + f.close() + v = v[v.find(":") + 1:].strip() + + if not v or int(v) < CONF_VERSION: + f = open(self.CONFIG, "wb") + f.write("version: " + str(CONF_VERSION)) f.close() + print "Old version of %s deleted" % self.CONFIG + else: + f = open(self.CONFIG, "wb") + f.write("version:" + str(CONF_VERSION)) + f.close() except Exception, ex: e = ex @@ -112,19 +106,13 @@ class ConfigParser: def save(self): """saves config to filename""" - # separate pyload and plugin conf configs = [] - for c in (self.CONFIG, self.PLUGIN): - f = open(c, "wb") - configs.append(f) - chmod(c, 0600) - f.write("version: %i\n\n" % CONF_VERSION) - + f = open(self.CONFIG, "wb") + configs.append(f) + chmod(self.CONFIG, 0600) + f.write("version: %i\n\n" % CONF_VERSION) - # write on 2 files for section, data in self.config.iteritems(): - f = configs[0] if section in self.baseSections else configs[1] - f.write("[%s]\n" % section) for option, data in data.config.iteritems(): @@ -136,17 +124,21 @@ class ConfigParser: f.write("\n") - [f.close() for f in configs] + f.close() def __getitem__(self, section): """provides dictionary like access: c['section']['option']""" return Section(self, section) + def __contains__(self, section): + """ checks if parser contains section """ + return section in self.config + def get(self, section, option): - """get value""" - if option in self.values[section]: + """get value or default""" + try: return self.values[section][option] - else: + except KeyError: return self.config[section].config[option].default def set(self, section, option, value, sync=True): @@ -154,45 +146,27 @@ class ConfigParser: data = self.config[section].config[option] value = from_string(value, data.type) + old_value = self.get(section, option) - # only save when different to default values - if value != data.default or (option in self.values[section] and value != self.values[section][option]): + # only save when different values + if value != old_value: + if section not in self.values: self.values[section] = {} self.values[section][option] = value if sync: - if self.changeCB: self.changeCB(section, option, value) self.save() + return True - def getPlugin(self, *args): - """gets a value for a plugin""" - ret = self.get(*args) - print "Deprecated method getPlugin%s -> %s" % (str(args), ret) - return ret - - def setPlugin(self, *args): - """sets a value for a plugin""" - print "Deprecated method setPlugin%s" % str(args) - self.set(*args) + return False def getMetaData(self, section, option): """ get all config data for an option """ return self.config[section].config[option] - def getBaseSections(self): - for section, data in self.config.iteritems(): - if section in self.baseSections: - yield section, data - return - - def getPluginSections(self): - for section, data in self.config.iteritems(): - if section not in self.baseSections: - yield section, data - return + def iterSections(self): + return self.config.iteritems() - def addConfigSection(self, section, name, desc, long_desc, config, base=False): + def addConfigSection(self, section, name, desc, long_desc, config): """Adds a section to the config. `config` is a list of config tuples as used in plugin api defined as: - Either (name, type, verbose_name, default_value) or - (name, type, verbose_name, short_description, default_value) The order of the config elements is preserved with OrderedDict """ d = OrderedDict() @@ -200,23 +174,15 @@ class ConfigParser: for entry in config: if len(entry) == 5: conf_name, type, conf_desc, conf_verbose, default = entry - else: # config options without tooltip / description + else: # config options without description conf_name, type, conf_desc, default = entry conf_verbose = "" d[conf_name] = ConfigData(gettext(conf_desc), type, gettext(conf_verbose), from_string(default, type)) - if base: - if section not in self.baseSections: self.baseSections.append(section) - elif section in self.baseSections: - return # would overwrite base section - data = SectionTuple(gettext(name), gettext(desc), gettext(long_desc), d) self.config[section] = data - if section not in self.values: - self.values[section] = {} - class Section: """provides dictionary like access for configparser""" @@ -232,21 +198,3 @@ class Section: def __setitem__(self, item, value): """setitem""" self.parser.set(self.section, item, value) - - -if __name__ == "__main__": - pypath = "" - - from time import time - - a = time() - - c = ConfigParser() - - b = time() - - print "sec", b - a - - print c.config - - c.saveConfig(c.config, "user.conf") diff --git a/module/config/default.py b/module/config/default.py index a9fad675c..e55ba6593 100644 --- a/module/config/default.py +++ b/module/config/default.py @@ -16,8 +16,7 @@ def make_config(config): ("activated", "bool", _("Activated"), _("Tooltip"), True), ("port", "int", _("Port"), _("Tooltip"), 7227), ("listenaddr", "ip", _("Adress"), _("Tooltip"), "0.0.0.0"), - ], - True) + ]) config.addConfigSection("log", _("Log"), _("Description"), _("Long description"), [ @@ -26,8 +25,7 @@ def make_config(config): ("file_log", "bool", _("File Log"), _("Tooltip"), True), ("log_count", "int", _("Count"), _("Tooltip"), 5), ("log_rotate", "bool", _("Log Rotate"), _("Tooltip"), True), - ], - True) + ]) config.addConfigSection("permission", _("Permissions"), _("Description"), _("Long description"), [ @@ -39,8 +37,7 @@ def make_config(config): ("change_group", "bool", _("Change group of running process"), _("Tooltip"), False), ("folder", "str", _("Folder Permission mode"), _("Tooltip"), "0755"), ("change_user", "bool", _("Change user of running process"), _("Tooltip"), False), - ], - True) + ]) config.addConfigSection("general", _("General"), _("Description"), _("Long description"), [ @@ -51,16 +48,14 @@ def make_config(config): ("debug_mode", "bool", _("Debug Mode"), _("Tooltip"), False), ("min_free_space", "int", _("Min Free Space (MB)"), _("Tooltip"), 200), ("renice", "int", _("CPU Priority"), _("Tooltip"), 0), - ], - True) + ]) config.addConfigSection("ssl", _("SSL"), _("Description"), _("Long description"), [ ("cert", "file", _("SSL Certificate"), _("Tooltip"), "ssl.crt"), ("activated", "bool", _("Activated"), _("Tooltip"), False), ("key", "file", _("SSL Key"), _("Tooltip"), "ssl.key"), - ], - True) + ]) config.addConfigSection("webinterface", _("Webinterface"), _("Description"), _("Long description"), [ @@ -71,8 +66,7 @@ def make_config(config): ("host", "ip", _("IP"), _("Tooltip"), "0.0.0.0"), ("https", "bool", _("Use HTTPS"), _("Tooltip"), False), ("port", "int", _("Port"), _("Tooltip"), 8001), - ], - True) + ]) config.addConfigSection("proxy", _("Proxy"), _("Description"), _("Long description"), [ @@ -82,8 +76,7 @@ def make_config(config): ("password", "password", _("Password"), _("Tooltip"), ""), ("type", "http;socks4;socks5", _("Protocol"), _("Tooltip"), "http"), ("port", "int", _("Port"), _("Tooltip"), 7070), - ], - True) + ]) config.addConfigSection("reconnect", _("Reconnect"), _("Description"), _("Long description"), [ @@ -91,8 +84,7 @@ def make_config(config): ("activated", "bool", _("Use Reconnect"), _("Tooltip"), False), ("method", "str", _("Method"), _("Tooltip"), "./reconnect.sh"), ("startTime", "time", _("Start"), _("Tooltip"), "0:00"), - ], - True) + ]) config.addConfigSection("download", _("Download"), _("Description"), _("Long description"), [ @@ -104,12 +96,10 @@ def make_config(config): ("ipv6", "bool", _("Allow IPv6"), _("Tooltip"), False), ("chunks", "int", _("Max connections for one download"), _("Tooltip"), 3), ("restart_failed", "bool", _("Restart failed downloads on startup"), _("Tooltip"), False), - ], - True) + ]) config.addConfigSection("downloadTime", _("Download Time"), _("Description"), _("Long description"), [ ("start", "time", _("Start"), _("Tooltip"), "0:00"), ("end", "time", _("End"), _("Tooltip"), "0:00"), - ], - True) + ]) diff --git a/module/database/ConfigDatabase.py b/module/database/ConfigDatabase.py index 198ae0173..7dd5909b8 100644 --- a/module/database/ConfigDatabase.py +++ b/module/database/ConfigDatabase.py @@ -16,11 +16,12 @@ class ConfigMethods(DatabaseMethods): @queue def loadConfig(self, plugin, user=None): if user is None: - self.c.execute('SELECT config FROM settings WHERE plugin=?', (plugin, )) + self.c.execute('SELECT config FROM settings WHERE plugin=? AND user=-1', (plugin, )) else: self.c.execute('SELECT config FROM settings WHERE plugin=? AND user=?', (plugin, user)) - return self.c.fetchone()[0] + r = self.c.fetchone() + return r[0] if r else "" @async def deleteConfig(self, plugin, user=None): diff --git a/module/datatypes/User.py b/module/datatypes/User.py index d48111182..3832653c7 100644 --- a/module/datatypes/User.py +++ b/module/datatypes/User.py @@ -28,12 +28,13 @@ class User(UserData): return User(api, user.uid, user.name, user.email, user.role, user.permission, user.folder, user.traffic, user.dllimit, user.dlquota, user.hddquota, user.user, user.templateName) - def __init__(self, api, *args): - UserData.__init__(self, *args) + def __init__(self, api, *args, **kwargs): + UserData.__init__(self, *args, **kwargs) self.api = api def toUserData(self): + # TODO return UserData() def hasPermission(self, perms): diff --git a/module/remote/pyload.thrift b/module/remote/pyload.thrift index 183fd3af8..47c371904 100644 --- a/module/remote/pyload.thrift +++ b/module/remote/pyload.thrift @@ -315,6 +315,10 @@ exception ServiceException { 1: string msg } +exception InvalidConfigSection { + 1: string section +} + exception Unauthorized { } diff --git a/module/remote/ttypes.py b/module/remote/ttypes.py index eb990f2e8..d661c684a 100644 --- a/module/remote/ttypes.py +++ b/module/remote/ttypes.py @@ -220,6 +220,12 @@ class InteractionTask(BaseObject): self.description = description self.plugin = plugin +class InvalidConfigSection(Exception): + __slots__ = ['section'] + + def __init__(self, section=None): + self.section = section + class LinkStatus(BaseObject): __slots__ = ['url', 'name', 'plugin', 'size', 'status', 'packagename'] diff --git a/module/remote/ttypes_debug.py b/module/remote/ttypes_debug.py index 807a8451b..1e04624d9 100644 --- a/module/remote/ttypes_debug.py +++ b/module/remote/ttypes_debug.py @@ -18,6 +18,7 @@ classes = { 'FileDoesNotExists' : [int], 'FileInfo' : [int, basestring, int, int, int, int, int, int, int, (None, DownloadInfo)], 'InteractionTask' : [int, int, (list, basestring), int, (None, basestring), basestring, basestring, basestring], + 'InvalidConfigSection' : [basestring], 'LinkStatus' : [basestring, basestring, basestring, int, int, basestring], 'OnlineCheck' : [int, (dict, basestring, LinkStatus)], 'PackageDoesNotExists' : [int], diff --git a/pyLoadCore.py b/pyLoadCore.py index f47999a1e..4e249e22f 100755 --- a/pyLoadCore.py +++ b/pyLoadCore.py @@ -42,6 +42,7 @@ subprocess.__doc__ = None # the module with the largest doc we are using from module import InitHomeDir from module.AccountManager import AccountManager from module.config.ConfigParser import ConfigParser +from module.config.ConfigManager import ConfigManager from module.PluginManager import PluginManager from module.interaction.EventManager import EventManager from module.network.RequestFactory import RequestFactory @@ -365,7 +366,6 @@ class Core(object): if not tests: self.writePidFile() - self.check_install("Crypto", _("pycrypto to decode container files")) self.captcha = True # checks seems to fail, although tesseract is available @@ -373,10 +373,12 @@ class Core(object): if self.config['ssl']['activated']: self.check_install("OpenSSL", _("OpenSSL for secure connection")) - - self.eventManager = EventManager(self) + self.eventManager = self.evm = EventManager(self) self.setupDB() + # Upgrade to configManager + self.config = ConfigManager(self, self.config) + if self.deleteLinks: self.log.info(_("All links removed")) self.db.purgeLinks() @@ -384,7 +386,7 @@ class Core(object): self.requestFactory = RequestFactory(self) __builtin__.pyreq = self.requestFactory - # later imported because they would trigger api import, and remote value not set correctly + # deferred import, could improve start-up time from module import Api from module.AddonManager import AddonManager from module.interaction.InteractionManager import InteractionManager @@ -396,7 +398,7 @@ class Core(object): #hell yeah, so many important managers :D self.pluginManager = PluginManager(self) - self.interactionManager = InteractionManager(self) + self.interactionManager = self.im = InteractionManager(self) self.accountManager = AccountManager(self) self.threadManager = ThreadManager(self) self.addonManager = AddonManager(self) @@ -569,7 +571,8 @@ class Core(object): self.eventManager.dispatchEvent("coreShutdown") try: if self.config['webinterface']['activated'] and hasattr(self, "webserver"): - self.webserver.quit() + pass # TODO: quit webserver? +# self.webserver.quit() for thread in self.threadManager.threads: thread.put("quit") diff --git a/tests/api/test_WebSocketAPI.py b/tests/api/test_WebSocketBackend.py index ac22d044e..be465e3d4 100644 --- a/tests/api/test_WebSocketAPI.py +++ b/tests/api/test_WebSocketBackend.py @@ -5,7 +5,7 @@ from nose.tools import raises from module.remote.ttypes import Forbidden from module.remote.WSClient import WSClient -class TestWebSocketAPI: +class TestWebSocketBackend: def setUp(self): self.client = WSClient() diff --git a/tests/api/test_noargs.py b/tests/api/test_noargs.py index 02e49cf13..aa010f293 100644 --- a/tests/api/test_noargs.py +++ b/tests/api/test_noargs.py @@ -6,7 +6,7 @@ from ApiTester import ApiTester from module.remote.ttypes import Iface -IGNORE = ('kill', 'restart') +IGNORE = ('stop', 'restart') class TestNoArgs(ApiTester): def setUp(self): diff --git a/tests/helper/Stubs.py b/tests/helper/Stubs.py index 4ebd12592..f0e8d0614 100644 --- a/tests/helper/Stubs.py +++ b/tests/helper/Stubs.py @@ -11,6 +11,8 @@ sys.path.append(abspath(join(dirname(__file__), "..", ".."))) import __builtin__ +from module.Api import Role +from module.datatypes.User import User from module.datatypes.PyPackage import PyPackage from module.threads.BaseThread import BaseThread from module.config.ConfigParser import ConfigParser @@ -69,7 +71,8 @@ class Core: __builtin__.pyreq = self.requestFactory self.accountManager = AccountManager() self.addonManager = AddonManager() - self.eventManager = self.interActionManager = NoopClass() + self.eventManager = self.evm = NoopClass() + self.interActionManager = self.im = NoopClass() self.js = JsEngine() self.cache = {} self.packageCache = {} @@ -95,7 +98,7 @@ class Core: def getPackage(self, id): return PyPackage(self, 0, "tmp", "tmp", "", "", 0, 0) - + def print_exc(self): log(ERROR, format_exc()) @@ -104,15 +107,17 @@ class NoopClass: def __getattr__(self, item): return noop + class AddonManager(NoopClass): def activePlugins(self): return [] -class AccountManager: +class AccountManager: def getAccountForPlugin(self, name): return None + class Thread(BaseThread): def __init__(self, core): BaseThread.__init__(self, core) @@ -131,3 +136,6 @@ __builtin__._ = lambda x: x __builtin__.pypath = abspath(join(dirname(__file__), "..", "..")) __builtin__.addonManager = AddonManager() __builtin__.pyreq = None + +adminUser = User(None, uid=0, role=Role.Admin) +normalUser = User(None, uid=1, role=Role.User)
\ No newline at end of file diff --git a/tests/manager/test_configManager.py b/tests/manager/test_configManager.py new file mode 100644 index 000000000..1cfb6a5de --- /dev/null +++ b/tests/manager/test_configManager.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- + +from unittest import TestCase +from collections import defaultdict + +from nose.tools import raises + +from tests.helper.Stubs import Core, adminUser, normalUser + +from module.Api import InvalidConfigSection +from module.database import DatabaseBackend +from module.config.ConfigParser import ConfigParser +from module.config.ConfigManager import ConfigManager + +class TestConfigManager(TestCase): + + @classmethod + def setUpClass(cls): + cls.core = Core() + cls.db = DatabaseBackend(cls.core) + cls.core.db = cls.db + cls.db.manager = cls.core + cls.db.manager.statusMsg = defaultdict(lambda: "statusmsg") + cls.parser = ConfigParser() + cls.config = ConfigManager(cls.core, cls.parser) + cls.db.setup() + + def setUp(self): + self.db.clearAllConfigs() + + def addConfig(self): + self.config.addConfigSection("plugin", "Name", "desc", "something", + [("value", "str", "label", "desc", "default")]) + + def test_db(self): + + self.db.saveConfig("plugin", "some value", 0) + self.db.saveConfig("plugin", "some other value", 1) + + assert self.db.loadConfig("plugin", 0) == "some value" + assert self.db.loadConfig("plugin", 1) == "some other value" + + d = self.db.loadAllConfigs() + assert d[0]["plugin"] == "some value" + + self.db.deleteConfig("plugin", 0) + + assert 0 not in self.db.loadAllConfigs() + + self.db.deleteConfig("plugin") + + assert not self.db.loadAllConfigs() + assert self.db.loadConfig("plugin") == "" + + def test_parser(self): + assert self.config.get("general", "language") + self.config["general"]["language"] = "de" + assert self.config["general"]["language"] == "de" + assert self.config.get("general", "language", adminUser) == "de" + + def test_user(self): + self.addConfig() + + assert self.config["plugin"]["value"] == "default" + assert self.config.get("plugin", "value", adminUser) == "default" + assert self.config.get("plugin", "value", normalUser) == "default" + + assert self.config.set("plugin", "value", False, user=normalUser) + assert self.config.get("plugin", "value", normalUser) is False + assert self.config["plugin"]["value"] == "default" + + assert self.config.set("plugin", "value", True, user=adminUser) + assert self.config.get("plugin", "value", adminUser) is True + assert self.config["plugin"]["value"] is True + assert self.config.get("plugin", "value", normalUser) is False + + self.config.delete("plugin", normalUser) + assert self.config.get("plugin", "value", normalUser) == "default" + + self.config.delete("plugin") + assert self.config.get("plugin", "value", adminUser) == "default" + assert self.config["plugin"]["value"] == "default" + + # should not trigger something + self.config.delete("foo") + + + def test_sections(self): + pass + + @raises(InvalidConfigSection) + def test_restricted_access(self): + self.config.get("general", "language", normalUser) + + @raises(InvalidConfigSection) + def test_error(self): + self.config.get("foo", "bar") + + @raises(InvalidConfigSection) + def test_error_set(self): + self.config.set("foo", "bar", True)
\ No newline at end of file diff --git a/tests/other/test_configparser.py b/tests/other/test_configparser.py index acb05c63e..51ffc5a68 100644 --- a/tests/other/test_configparser.py +++ b/tests/other/test_configparser.py @@ -1,44 +1,18 @@ # -*- coding: utf-8 -*- -from collections import defaultdict +from nose.tools import raises + from tests.helper.Stubs import Core -from module.database import DatabaseBackend from module.config.ConfigParser import ConfigParser -# TODO class TestConfigParser(): - db = None - @classmethod def setUpClass(cls): - cls.db = DatabaseBackend(Core()) - cls.db.manager = cls.db.core - cls.db.manager.statusMsg = defaultdict(lambda: "statusmsg") + # Only needed to get imports right + cls.core = Core() cls.config = ConfigParser() - cls.db.setup() - cls.db.clearAllConfigs() - - @classmethod - def tearDownClass(cls): - cls.db.shutdown() - - def test_db(self): - - self.db.saveConfig("plugin", "some value", 0) - self.db.saveConfig("plugin", "some other value", 1) - - assert self.db.loadConfig("plugin", 0) == "some value" - assert self.db.loadConfig("plugin", 1) == "some other value" - - d = self.db.loadAllConfigs() - assert d[0]["plugin"] == "some value" - - self.db.deleteConfig("plugin") - - assert not self.db.loadAllConfigs() - def test_dict(self): @@ -46,8 +20,16 @@ class TestConfigParser(): self.config["general"]["language"] = "de" assert self.config["general"]["language"] == "de" - def test_config(self): - pass + def test_contains(self): + + assert "general" in self.config + assert "foobaar" not in self.config + + + @raises(KeyError) + def test_invalid_config(self): + print self.config["invalid"]["config"] - def test_userconfig(self): - pass
\ No newline at end of file + @raises(KeyError) + def test_invalid_section(self): + print self.config["general"]["invalid"]
\ No newline at end of file |