commit ea57e936e08400d63a423c669311643afd4dd84d Author: Ravi Chandra Padmala neenaoffline@gmail.com Date: Tue Jun 26 10:04:52 2012 +0530
Add Controller.reset_conf and fix Controller.set_conf --- stem/control.py | 96 +++++++++++++++++++++++++++++--------- test/integ/control/controller.py | 65 ++++++++++++++++++++++---- 2 files changed, 128 insertions(+), 33 deletions(-)
diff --git a/stem/control.py b/stem/control.py index 0e0d611..dfa79c7 100644 --- a/stem/control.py +++ b/stem/control.py @@ -14,6 +14,10 @@ interacting at a higher level.
Controller - General controller class intended for direct use. |- get_info - issues a GETINFO query + |- get_conf - issues a GETCONF query for a single parameter + |- get_conf_mapping - issues a GETCONF query for multiple parameters + |- set_conf - issues a SETCONF query + |- reset_conf - issues a RESETCONF query |- get_version - convenience method to get tor version |- authenticate - convenience method to authenticate the controller +- protocolinfo - convenience method to get the protocol info @@ -560,7 +564,7 @@ class Controller(BaseController): Response depends upon how we were called as follows...
* str with the response if multiple was False - * list with the response strings multiple was True + * list with the response strings if multiple was True * default if one was provided and our call failed
:raises: @@ -662,13 +666,40 @@ class Controller(BaseController): if default != UNDEFINED: return default else: raise exc
- def set_conf(self, *args): + def _set_conf(self, params, command="SETCONF"): + controlitems = [command] + + for key, value in params: + if type(value) in (list, tuple): + controlitems.extend(["%s="%s"" % (key, val.strip()) for val in value]) + elif value: + controlitems.append("%s="%s"" % (key, value.strip())) + else: + controlitems.append(key) + + response = self.msg(" ".join(controlitems)) + stem.response.convert("SINGLELINE", response) + + if response.is_ok(): + return True + elif response.code == "552": + if response.message.startswith("Unrecognized option: Unknown option '"): + key = response.message[37:response.message.find("'", 37)] + raise stem.socket.InvalidArguments(response.code, response.message, [key]) + raise stem.socket.InvalidRequest(response.code, response.message) + elif response.code in ("513", "553"): + raise stem.socket.InvalidRequest(response.code, response.message) + else: + raise stem.socket.ProtocolError("%s returned unexpected status code" % command) + + def set_conf(self, *params): """ Changes the configuration of one or more configuration variables using the control socket.
- :param dict options: a dictionary containing a mapping of configuration keys (string) - to the corresponding values (string or list of strings) + :param list,dict params: a list containing tuples of configuration keys (string) + and their corresponding values (string or list of strings) or a dict + containing config-key: config-value pairs.
Or
@@ -684,31 +715,50 @@ class Controller(BaseController): impossible or if there's a syntax error in the configuration values """
- if len(args) == 2: - args = {args[0]: args[1]} - elif len(args) == 1: - args = args[0] + if len(params) == 2: + arg = [params] + elif len(params) == 1: + if type(params[0]) == dict: + arg = params[0].items() + else: + arg = params[0] else: raise TypeError("set_conf expected 1 or 2 arguments, got %d", len(args))
- options = [] - for key, value in args.iteritems(): - options.append(key + "="" + value + """) + self._set_conf(arg, "SETCONF") + + def reset_conf(self, params): + """ + Resets the configuration of one or more configuration variables using the + control socket. + + :param str,list,dict params: + This could be...
- response = self.msg("SETCONF %s" % " ".join(options)) - stem.response.convert("SINGLELINE", response) + * a single configuration key (str) + * a list of configuration keys to be reset and/or tuples of configuration + keys (string) and their corresponding values (string or list of strings) + * a dict containing configuration key/value pairs.
- if response.is_ok(): - return True - elif response.code == "552": - if response.message.startswith("Unrecognized option: Unknown option '"): - key = response.message[37:response.message.find("'", 37)] - raise stem.socket.InvalidArguments(response.code, response.message, [key]) - raise stem.socket.InvalidRequest(response.code, response.message) - elif response.code in ("513", "553"): - raise stem.socket.InvalidRequest(response.code, response.message) + :param list params: a list of configuration keys to be reset + + :returns: True on successfully resetting the values + + :raises: + :class:`stem.socket.ControllerError` if the call fails + :class:`stem.socket.InvalidArguments` if configuration options requested was invalid + :class:`stem.socket.InvalidRequest` if the configuration setting is + impossible or if there's a syntax error in the configuration values + """ + + if type(params) == str: + arg = [(params, None)] + elif type(params) == dict: + arg = params.items() else: - raise stem.socket.ProtocolError("SETCONF returned unexpected status code") + arg = map(lambda item: (item, None) if type(item) == str else item, params) + + self._set_conf(arg, "RESETCONF")
def _case_insensitive_lookup(entries, key): """ diff --git a/test/integ/control/controller.py b/test/integ/control/controller.py index 4a517dd..a407904 100644 --- a/test/integ/control/controller.py +++ b/test/integ/control/controller.py @@ -193,18 +193,17 @@ class TestController(unittest.TestCase): self.assertEqual({}, controller.get_conf_map([], "la-di-dah"))
# context-sensitive keys - - keys = { - "HiddenServiceDir": "/tmp/stemtestdir", - "HiddenServicePort": "17234 127.0.0.1:17235" - } + keys = [ + ("HiddenServiceDir", "/tmp/stemtestdir"), + ("HiddenServicePort", "17234 127.0.0.1:17235") + ] controller.set_conf(keys) self.assertEqual("/tmp/stemtestdir", controller.get_conf("HiddenServiceDir")) - self.assertEqual("17234 127.0.0.1:17235", controller.get_conf("HiddenServiceDir")) + self.assertEqual("17234 127.0.0.1:17235", controller.get_conf("HiddenServicePort"))
def test_setconf(self): """ - Exercises SETCONF with valid and invalid requests. + Exercises Controller.set_conf with valid and invalid requests. """
runner = test.runner.get_runner() @@ -233,11 +232,57 @@ class TestController(unittest.TestCase): except stem.socket.InvalidArguments, exc: self.assertEqual(["bombay"], exc.arguments)
+ settings = [ + ("HiddenServiceDir", "/tmp/stemtestdir"), + ("HiddenServicePort", "17234 127.0.0.1:17235") + ] + controller.set_conf(settings) + self.assertEqual("17234 127.0.0.1:17235", controller.get_conf("hiddenserviceport")) + self.assertEqual("/tmp/stemtestdir", controller.get_conf("hiddenservicedir")) + + def test_resetconf(self): + """ + Exercises Controller.reset_conf with valid and invalid requests. + """ + + runner = test.runner.get_runner() + + with runner.get_tor_controller() as controller: + # Single valid key + controller.set_conf("contactinfo", "stem@testing") + self.assertEqual("stem@testing", controller.get_conf("contactinfo")) + controller.reset_conf("contactinfo") + self.assertEqual(None, controller.get_conf("contactinfo")) + + # Invalid key + try: + controller.reset_conf(("invalidkeyboo", "abcde")) + except stem.socket.InvalidArguments, exc: + self.assertEqual(["invalidkeyboo"], exc.arguments) + + # Multiple keys, list & dict settings = { - "HiddenServiceDir": "/tmp/stemtestdir", - "HiddenServicePort": "17234 127.0.0.1:17235" + "connlimit": "314", + "contactinfo": "stem@testing" } - controller.set_conf(settings) + controller.reset_conf(settings) + self.assertEqual("314", controller.get_conf("ConnLimit")) + self.assertEqual("stem@testing", controller.get_conf("contactinfo")) + + settings = [ + ("connlimit", "786"), + ("contactinfo", "stem testing") + ] + controller.reset_conf(settings) + self.assertEqual("786", controller.get_conf("ConnLimit")) + self.assertEqual("stem testing", controller.get_conf("contactinfo")) + + # context-sensitive keys + settings = [ + ("HiddenServiceDir", "/tmp/stemtestdir"), + ("HiddenServicePort", "17234 127.0.0.1:17235") + ] + controller.reset_conf(settings) self.assertEqual("17234 127.0.0.1:17235", controller.get_conf("hiddenserviceport")) self.assertEqual("/tmp/stemtestdir", controller.get_conf("hiddenservicedir"))
tor-commits@lists.torproject.org