commit ea57e936e08400d63a423c669311643afd4dd84d
Author: Ravi Chandra Padmala <neenaoffline(a)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"))