[stem/master] Adding support for TB_EMPTY events

commit d6a95bf778e6b90d9de9ea46aefcfce2f9103e68 Author: Damian Johnson <atagar@torproject.org> Date: Sun Nov 3 23:22:32 2013 -0800 Adding support for TB_EMPTY events Last event type from... https://gitweb.torproject.org/torspec.git/commitdiff/6f2919a --- docs/change_log.rst | 1 + stem/__init__.py | 18 +++++++++++++++++ stem/response/events.py | 44 ++++++++++++++++++++++++++++++++++++++++++ stem/version.py | 2 ++ test/unit/response/events.py | 41 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+) diff --git a/docs/change_log.rst b/docs/change_log.rst index 5c6fed2..7b71c47 100644 --- a/docs/change_log.rst +++ b/docs/change_log.rst @@ -45,6 +45,7 @@ The following are only available within stem's `git repository * Added `support for CONN_BW events <api/response.html#stem.response.events.ConnectionBandwidthEvent>`_ (:spec:`6f2919a`) * Added `support for CIRC_BW events <api/response.html#stem.response.events.CircuitBandwidthEvent>`_ (:spec:`6f2919a`) * Added `support for CELL_STATS events <api/response.html#stem.response.events.CellStatsEvent>`_ (:spec:`6f2919a`) + * Added `support for TB_EMPTY events <api/response.html#stem.response.events.TokenBucketEmptyEvent>`_ (:spec:`6f2919a`) .. _version_1.1: diff --git a/stem/__init__.py b/stem/__init__.py index 182428f..9710d24 100644 --- a/stem/__init__.py +++ b/stem/__init__.py @@ -380,6 +380,18 @@ Library for working with the tor process. **DIR** fetching or sending tor descriptor data **EXIT** carrying traffic between the tor network and an external destination =============== =========== + +.. data:: TokenBucket (enum) + + Bucket categories of TB_EMPTY events. + + =============== =========== + TokenBucket Description + =============== =========== + **GLOBAL** global token bucket + **RELAY** relay token bucket + **ORCONN** bucket used for OR connections + =============== =========== """ __version__ = '1.1.0-dev' @@ -718,3 +730,9 @@ ConnectionType = stem.util.enum.UppercaseEnum( "DIR", "EXIT", ) + +TokenBucket = stem.util.enum.UppercaseEnum( + "GLOBAL", + "RELAY", + "ORCONN", +) diff --git a/stem/response/events.py b/stem/response/events.py index 616bbfc..19e1680 100644 --- a/stem/response/events.py +++ b/stem/response/events.py @@ -1069,6 +1069,49 @@ class CellStatsEvent(Event): self.outbound_time = _parse_cell_type_mapping(self.outbound_time) +class TokenBucketEmptyEvent(Event): + """ + Event emitted when refilling an empty token bucket. **These events are only + emitted if TestingTorNetwork is set.** + + The TB_EMPTY event was introduced in tor version 0.2.5.2-alpha. + + .. versionadded:: 1.1.0-dev + + :var stem.TokenBucket bucket: bucket being refilled + :var str id: connection identifier + :var int read: time in milliseconds since the read bucket was last refilled + :var int written: time in milliseconds since the write bucket was last refilled + :var int last_refill: time in milliseconds the bucket has been empty since last refilled + """ + + _POSITIONAL_ARGS = ("bucket",) + _KEYWORD_ARGS = { + "ID": "id", + "READ": "read", + "WRITTEN": "written", + "LAST": "last_refill", + } + + _VERSION_ADDED = stem.version.Requirement.EVENT_TB_EMPTY + + def _parse(self): + if self.id and not tor_tools.is_valid_connection_id(self.id): + raise stem.ProtocolError("Connection IDs must be one to sixteen alphanumeric characters, got '%s': %s" % (self.id, self)) + elif not self.read.isdigit(): + raise stem.ProtocolError("A TB_EMPTY's READ value should be a positive numeric value, received: %s" % self) + elif not self.written.isdigit(): + raise stem.ProtocolError("A TB_EMPTY's WRITTEN value should be a positive numeric value, received: %s" % self) + elif not self.last_refill.isdigit(): + raise stem.ProtocolError("A TB_EMPTY's LAST value should be a positive numeric value, received: %s" % self) + + self.read = int(self.read) + self.written = int(self.written) + self.last_refill = int(self.last_refill) + + self._log_if_unrecognized('bucket', stem.TokenBucket) + + def _parse_cell_type_mapping(mapping): """ Parses a mapping of the form... @@ -1133,6 +1176,7 @@ EVENT_TYPE_TO_CLASS = { "STATUS_SERVER": StatusEvent, "STREAM": StreamEvent, "STREAM_BW": StreamBwEvent, + "TB_EMPTY": TokenBucketEmptyEvent, "TRANSPORT_LAUNCHED": TransportLaunchedEvent, "WARN": LogEvent, diff --git a/stem/version.py b/stem/version.py index ef1f290..b0563d5 100644 --- a/stem/version.py +++ b/stem/version.py @@ -46,6 +46,7 @@ easily parsed and compared, for instance... **EVENT_CONN_BW** CONN_BW events **EVENT_CIRC_BW** CIRC_BW events **EVENT_CELL_STATS** CELL_STATS events + **EVENT_TB_EMPTY** TB_EMPTY events **EXTENDCIRCUIT_PATH_OPTIONAL** EXTENDCIRCUIT queries can omit the path if the circuit is zero **FEATURE_EXTENDED_EVENTS** 'EXTENDED_EVENTS' optional feature **FEATURE_VERBOSE_NAMES** 'VERBOSE_NAMES' optional feature @@ -347,6 +348,7 @@ Requirement = stem.util.enum.Enum( ("EVENT_CONN_BW", Version('0.2.5.2-alpha')), ("EVENT_CIRC_BW", Version('0.2.5.2-alpha')), ("EVENT_CELL_STATS", Version('0.2.5.2-alpha')), + ("EVENT_TB_EMPTY", Version('0.2.5.2-alpha')), ("EXTENDCIRCUIT_PATH_OPTIONAL", Version("0.2.2.9")), ("FEATURE_EXTENDED_EVENTS", Version("0.2.2.1-alpha")), ("FEATURE_VERBOSE_NAMES", Version("0.2.2.1-alpha")), diff --git a/test/unit/response/events.py b/test/unit/response/events.py index 09fca4f..c3cdf7a 100644 --- a/test/unit/response/events.py +++ b/test/unit/response/events.py @@ -357,6 +357,13 @@ CELL_STATS_BAD_1 = "650 CELL_STATS OutboundAdded=create_fast:-1,relay_early:2" CELL_STATS_BAD_2 = "650 CELL_STATS OutboundAdded=create_fast:arg,relay_early:-2" CELL_STATS_BAD_3 = "650 CELL_STATS OutboundAdded=create_fast!:1,relay_early:-2" +TB_EMPTY_1 = "650 TB_EMPTY ORCONN ID=16 READ=0 WRITTEN=0 LAST=100" +TB_EMPTY_2 = "650 TB_EMPTY GLOBAL READ=93 WRITTEN=93 LAST=100" +TB_EMPTY_3 = "650 TB_EMPTY RELAY READ=93 WRITTEN=93 LAST=100" + +TB_EMPTY_BAD_1 = "650 TB_EMPTY GLOBAL READ=93 WRITTEN=blarg LAST=100" +TB_EMPTY_BAD_2 = "650 TB_EMPTY GLOBAL READ=93 WRITTEN=93 LAST=-100" + def _get_event(content): controller_event = mocking.get_message(content) @@ -1282,6 +1289,40 @@ class TestEvents(unittest.TestCase): self.assertRaises(ProtocolError, _get_event, CELL_STATS_BAD_2) self.assertRaises(ProtocolError, _get_event, CELL_STATS_BAD_3) + def test_token_bucket_empty_event(self): + event = _get_event(TB_EMPTY_1) + + self.assertTrue(isinstance(event, stem.response.events.TokenBucketEmptyEvent)) + self.assertEqual(TB_EMPTY_1.lstrip("650 "), str(event)) + self.assertEqual(stem.TokenBucket.ORCONN, event.bucket) + self.assertEqual("16", event.id) + self.assertEqual(0, event.read) + self.assertEqual(0, event.written) + self.assertEqual(100, event.last_refill) + + event = _get_event(TB_EMPTY_2) + + self.assertTrue(isinstance(event, stem.response.events.TokenBucketEmptyEvent)) + self.assertEqual(TB_EMPTY_2.lstrip("650 "), str(event)) + self.assertEqual(stem.TokenBucket.GLOBAL, event.bucket) + self.assertEqual(None, event.id) + self.assertEqual(93, event.read) + self.assertEqual(93, event.written) + self.assertEqual(100, event.last_refill) + + event = _get_event(TB_EMPTY_3) + + self.assertTrue(isinstance(event, stem.response.events.TokenBucketEmptyEvent)) + self.assertEqual(TB_EMPTY_3.lstrip("650 "), str(event)) + self.assertEqual(stem.TokenBucket.RELAY, event.bucket) + self.assertEqual(None, event.id) + self.assertEqual(93, event.read) + self.assertEqual(93, event.written) + self.assertEqual(100, event.last_refill) + + self.assertRaises(ProtocolError, _get_event, TB_EMPTY_BAD_1) + self.assertRaises(ProtocolError, _get_event, TB_EMPTY_BAD_2) + def test_unrecognized_enum_logging(self): """ Checks that when event parsing gets a value that isn't recognized by stem's
participants (1)
-
atagar@torproject.org