[tor-commits] [stem/master] Add a Controller.get_streams method and its tests
atagar at torproject.org
atagar at torproject.org
Sat Jan 5 03:17:46 UTC 2013
commit 7e5377906b6b0e0bcc20fb442fb11554df929868
Author: Sean Robinson <seankrobinson at gmail.com>
Date: Wed Jan 2 05:52:29 2013 -0700
Add a Controller.get_streams method and its tests
Re-use Ravi's idea for parsing get_info("circuit-status") responses with
get_info("stream-status"). The stream status GETINFO reply contains just
the mandatory parts of a STREAM event, so the event optional keyword
arguments are not (yet) used.
Signed-off-by: Sean Robinson <seankrobinson at gmail.com>
---
stem/control.py | 20 ++++++++++++++++++++
test/integ/control/controller.py | 25 +++++++++++++++++++++++++
test/unit/control/controller.py | 31 ++++++++++++++++++++++++++++++-
3 files changed, 75 insertions(+), 1 deletions(-)
diff --git a/stem/control.py b/stem/control.py
index d8ee940..8bb3a10 100644
--- a/stem/control.py
+++ b/stem/control.py
@@ -51,6 +51,7 @@ providing its own for interacting at a higher level.
|- close_circuit - close a circuit
|
|- attach_stream - attach a stream to a circuit
+ |- get_streams - provides a list of active streams
|- close_stream - close a stream
|
|- signal - sends a signal to the tor client
@@ -1716,6 +1717,25 @@ class Controller(BaseController):
else:
raise stem.ProtocolError("ATTACHSTREAM returned unexpected response code: %s" % response.code)
+ def get_streams(self):
+ """
+ Provides the list of streams tor is currently handling.
+
+ :returns: list of :class:`stem.events.StreamEvent` objects
+
+ :raises: :class:`stem.ControllerError` if the call fails
+ """
+
+ streams = []
+ response = self.get_info("stream-status")
+
+ for stream in response.splitlines():
+ message = stem.socket.recv_message(StringIO.StringIO("650 STREAM " + stream + "\r\n"))
+ stem.response.convert("EVENT", message, arrived_at = 0)
+ streams.append(message)
+
+ return streams
+
def close_stream(self, stream_id, reason = stem.RelayEndReason.MISC, flag = ''):
"""
Closes the specified stream.
diff --git a/test/integ/control/controller.py b/test/integ/control/controller.py
index 534bba2..25fc431 100644
--- a/test/integ/control/controller.py
+++ b/test/integ/control/controller.py
@@ -20,6 +20,7 @@ import stem.descriptor.router_status_entry
import stem.response.protocolinfo
import stem.socket
import stem.version
+import test.network
import test.runner
import test.util
@@ -580,6 +581,30 @@ class TestController(unittest.TestCase):
self.assertRaises(stem.InvalidArguments, controller.close_circuit, str(int(circ_id) + 1024))
self.assertRaises(stem.InvalidRequest, controller.close_circuit, "")
+ def test_get_streams(self):
+ """
+ Tests Controller.get_streams().
+ """
+
+ if test.runner.require_control(self): return
+ elif test.runner.require_online(self): return
+
+ host = "38.229.72.14" # www.torproject.org
+ port = 443
+ target = host + ":" + str(port)
+
+ runner = test.runner.get_runner()
+ with runner.get_tor_controller() as controller:
+ # we only need one proxy port, so take the first
+ socks_listener = controller.get_socks_listeners()[0]
+ with test.network.Socks(socks_listener) as s:
+ s.settimeout(30)
+ s.connect((host, port))
+ streams = controller.get_streams()
+ # Because we do not get a stream id when opening a stream,
+ # try to match the target for which we asked a stream.
+ self.assertTrue(target in [stream.target for stream in streams])
+
def test_mapaddress(self):
if test.runner.require_control(self): return
elif test.runner.require_online(self): return
diff --git a/test/unit/control/controller.py b/test/unit/control/controller.py
index 695c2de..a6fc372 100644
--- a/test/unit/control/controller.py
+++ b/test/unit/control/controller.py
@@ -10,6 +10,7 @@ import stem.version
from stem import InvalidArguments, InvalidRequest, ProtocolError
from stem.control import _parse_circ_path, Controller, EventType
+from stem.response import events
from test import mocking
class TestControl(unittest.TestCase):
@@ -167,4 +168,32 @@ class TestControl(unittest.TestCase):
for response in invalid_responses:
mocking.mock_method(Controller, "get_info", mocking.return_value(response))
self.assertRaises(stem.ProtocolError, self.controller.get_socks_listeners)
-
+
+ def test_get_streams(self):
+ """
+ Exercises the get_streams() method.
+ """
+
+ # get a list of fake, but good looking, streams
+ valid_streams = (
+ ("1", "NEW", "4", "10.10.10.1:80"),
+ ("2", "SUCCEEDED", "4", "10.10.10.1:80"),
+ ("3", "SUCCEEDED", "4", "10.10.10.1:80")
+ )
+ response = []
+ for stream_parts in valid_streams:
+ stream = mocking.get_object(events.StreamEvent)
+ (stream.id, stream.status, stream.circ_id, stream.target) = stream_parts
+ line = "%s\r\n" % " ".join(stream_parts)
+ response.append(line)
+
+ mocking.mock_method(Controller, "get_info", mocking.return_value(
+ "".join(response)
+ ))
+ streams = self.controller.get_streams()
+ self.assertEqual(len(valid_streams), len(streams))
+ for index in range(len(streams)):
+ self.assertEqual(valid_streams[index][0], streams[index].id)
+ self.assertEqual(valid_streams[index][1], streams[index].status)
+ self.assertEqual(valid_streams[index][2], streams[index].circ_id)
+ self.assertEqual(valid_streams[index][3], streams[index].target)
More information about the tor-commits
mailing list