[tor-commits] [stem/master] Support for 'flag-thresholds' lines in network status votes

atagar at torproject.org atagar at torproject.org
Tue Feb 5 19:15:18 UTC 2013


commit 4e8aaa4daadb02db1686dde57c42c15aef6821e9
Author: Damian Johnson <atagar at torproject.org>
Date:   Tue Feb 5 09:48:12 2013 -0800

    Support for 'flag-thresholds' lines in network status votes
    
    Parsing the new 'flag-thresholds' in network status votes - thanks to Karsten
    for pointing this out.
    
    metrics-lib change:
    https://gitweb.torproject.org/metrics-lib.git/commitdiff/c2a0dbf8bf100a19660ad512b88d93f3d7c18a1e
    
    dir-spec addition:
    https://trac.torproject.org/8165
---
 stem/descriptor/networkstatus.py                  |   21 ++++++++
 test/unit/descriptor/networkstatus/document_v3.py |   52 +++++++++++++++++++++
 2 files changed, 73 insertions(+), 0 deletions(-)

diff --git a/stem/descriptor/networkstatus.py b/stem/descriptor/networkstatus.py
index 9f3730c..3377f5c 100644
--- a/stem/descriptor/networkstatus.py
+++ b/stem/descriptor/networkstatus.py
@@ -87,6 +87,7 @@ HEADER_STATUS_DOCUMENT_FIELDS = (
   ("client-versions", True, True, False),
   ("server-versions", True, True, False),
   ("known-flags", True, True, True),
+  ("flag-thresholds", True, False, False),
   ("params", True, True, False),
 )
 
@@ -442,6 +443,7 @@ class NetworkStatusDocumentV3(NetworkStatusDocument):
 
   :var list consensus_methods: list of ints for the supported method versions
   :var datetime published: time when the document was published
+  :var dict flag_thresholds: **\*** mapping of internal performance thresholds used while making the vote
 
   **\*** attribute is either required when we're parsed with validation or has
   a default value, others are left as None if undefined
@@ -551,6 +553,7 @@ class _DocumentHeader(object):
     self.client_versions = []
     self.server_versions = []
     self.known_flags = []
+    self.flag_thresholds = {}
     self.params = dict(DEFAULT_PARAMS) if default_params else {}
 
     self._unrecognized_lines = []
@@ -681,6 +684,24 @@ class _DocumentHeader(object):
 
         # simply fetches the entries, excluding empty strings
         self.known_flags = [entry for entry in value.split(" ") if entry]
+      elif keyword == "flag-thresholds":
+        # "flag-thresholds" SP THRESHOLDS
+        #
+        # TODO: format is being discussed on...
+        #   https://trac.torproject.org/8165
+
+        value = value.strip()
+
+        if value:
+          for entry in value.split(" "):
+            if not '=' in entry:
+              if not validate:
+                continue
+
+              raise ValueError("Network status document's '%s' line is expected to be space separated key=value mappings, got: %s" % (keyword, line))
+
+            entry_key, entry_value = entry.split("=", 1)
+            self.flag_thresholds[entry_key] = entry_value
       elif keyword == "params":
         # "params" [Parameters]
         # Parameter ::= Keyword '=' Int32
diff --git a/test/unit/descriptor/networkstatus/document_v3.py b/test/unit/descriptor/networkstatus/document_v3.py
index 74c7fe4..71d56e5 100644
--- a/test/unit/descriptor/networkstatus/document_v3.py
+++ b/test/unit/descriptor/networkstatus/document_v3.py
@@ -65,6 +65,7 @@ class TestNetworkStatusDocument(unittest.TestCase):
     self.assertEqual([], document.client_versions)
     self.assertEqual([], document.server_versions)
     self.assertEqual(expected_known_flags, document.known_flags)
+    self.assertEqual({}, document.flag_thresholds)
     self.assertEqual(DEFAULT_PARAMS, document.params)
     self.assertEqual((), document.directory_authorities)
     self.assertEqual({}, document.bandwidth_weights)
@@ -98,6 +99,7 @@ class TestNetworkStatusDocument(unittest.TestCase):
     self.assertEqual([], document.client_versions)
     self.assertEqual([], document.server_versions)
     self.assertEqual(expected_known_flags, document.known_flags)
+    self.assertEqual({}, document.flag_thresholds)
     self.assertEqual(DEFAULT_PARAMS, document.params)
     self.assertEqual((), document.directory_authorities)
     self.assertEqual({}, document.bandwidth_weights)
@@ -472,6 +474,56 @@ class TestNetworkStatusDocument(unittest.TestCase):
       document = get_network_status_document_v3({"known-flags": test_value})
       self.assertEquals(expected_value, document.known_flags)
 
+  def test_flag_thresholds(self):
+    """
+    Parses the flag-thresholds entry.
+    """
+
+    test_values = (
+      ("", {}),
+      ("fast-speed=40960", {u"fast-speed": u"40960"}),   # numeric value
+      ("guard-wfu=94.669%", {u"guard-wfu": u"94.669%"}), # percentage value
+      ("guard-wfu=94.669% guard-tk=691200", {u"guard-wfu": u"94.669%", u"guard-tk": u"691200"}), # multiple values
+    )
+
+    for test_value, expected_value in test_values:
+      document = get_network_status_document_v3({"vote-status": "vote", "flag-thresholds": test_value})
+      self.assertEquals(expected_value, document.flag_thresholds)
+
+    # parses a full entry found in an actual vote
+
+    full_line = "stable-uptime=693369 stable-mtbf=153249 fast-speed=40960 guard-wfu=94.669% guard-tk=691200 guard-bw-inc-exits=174080 guard-bw-exc-exits=184320 enough-mtbf=1"
+
+    expected_value = {
+      u"stable-uptime": u"693369",
+      u"stable-mtbf": u"153249",
+      u"fast-speed": u"40960",
+      u"guard-wfu": u"94.669%",
+      u"guard-tk": u"691200",
+      u"guard-bw-inc-exits": u"174080",
+      u"guard-bw-exc-exits": u"184320",
+      u"enough-mtbf": u"1",
+    }
+
+    document = get_network_status_document_v3({"vote-status": "vote", "flag-thresholds": full_line})
+    self.assertEquals(expected_value, document.flag_thresholds)
+
+    # TODO: At present our validation is pretty permissive since the field
+    # doesn't yet have a formal specificiation. We should expand this test when
+    # it does.
+
+    test_values = (
+      "stable-uptime 693369", # not a key=value mapping
+      #"stable-uptime=693369\tstable-mtbf=153249", # non-space divider
+    )
+
+    for test_value in test_values:
+      content = get_network_status_document_v3({"vote-status": "vote", "flag-thresholds": test_value}, content = True)
+      self.assertRaises(ValueError, NetworkStatusDocumentV3, content)
+
+      document = NetworkStatusDocumentV3(content, False)
+      self.assertEquals({}, document.flag_thresholds)
+
   def test_params(self):
     """
     General testing for the 'params' line, exercising the happy cases.



More information about the tor-commits mailing list