[tor-commits] [stem/master] connection_time() method for the BaseController

atagar at torproject.org atagar at torproject.org
Tue Sep 2 03:55:47 UTC 2014


commit d220b901851db31758e4f38703b31e090cbb471b
Author: Damian Johnson <atagar at torproject.org>
Date:   Mon Sep 1 14:34:11 2014 -0700

    connection_time() method for the BaseController
    
    Adding a connection_time() to our ControlSocket and BaseController to provide
    when we either connected or disconnected from the socket.
---
 docs/change_log.rst                 |    4 ++++
 run_tests.py                        |    2 ++
 stem/control.py                     |   12 ++++++++++++
 stem/socket.py                      |   16 +++++++++++++++
 test/integ/socket/control_socket.py |   37 +++++++++++++++++++++++++++++++++++
 5 files changed, 71 insertions(+)

diff --git a/docs/change_log.rst b/docs/change_log.rst
index 0e605ca..2b6964c 100644
--- a/docs/change_log.rst
+++ b/docs/change_log.rst
@@ -40,6 +40,10 @@ Unreleased
 The following are only available within Stem's `git repository
 <download.html>`_.
 
+ * **Controller**
+
+  * Added :func:`~stem.control.BaseController.connection_time` to the :class:`~stem.control.BaseController`
+
  * **Descriptors**
 
   * Improved speed for parsing consensus documents by around 30% (:trac:`12859`)
diff --git a/run_tests.py b/run_tests.py
index 3c91513..2d73457 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -279,7 +279,9 @@ def main():
       except OSError:
         error_tracker.register_error()
       finally:
+        println()
         integ_runner.stop()
+        println()
 
     if skipped_targets:
       println()
diff --git a/stem/control.py b/stem/control.py
index e2f133d..8571a7f 100644
--- a/stem/control.py
+++ b/stem/control.py
@@ -478,6 +478,18 @@ class BaseController(object):
 
     return self._socket.is_alive()
 
+  def connection_time(self):
+    """
+    Provides the unix timestamp for when our socket was either connected or
+    disconnected. That is to say, the time we connected if we're presently
+    connected and the time we disconnected if we're not connected.
+
+    :returns: **float** for when we last connected or disconnected, zero if
+      we've never connected
+    """
+
+    return self._socket.connection_time()
+
   def is_authenticated(self):
     """
     Checks if our socket is both connected and authenticated.
diff --git a/stem/socket.py b/stem/socket.py
index 1d664c0..e25f385 100644
--- a/stem/socket.py
+++ b/stem/socket.py
@@ -72,6 +72,7 @@ from __future__ import absolute_import
 import re
 import socket
 import threading
+import time
 
 import stem.prereq
 import stem.response
@@ -93,6 +94,7 @@ class ControlSocket(object):
   def __init__(self):
     self._socket, self._socket_file = None, None
     self._is_alive = False
+    self._connection_time = 0.0  # time when we last connected or disconnected
 
     # Tracks sending and receiving separately. This should be safe, and doing
     # so prevents deadlock where we block writes because we're waiting to read
@@ -203,6 +205,18 @@ class ControlSocket(object):
 
     return False
 
+  def connection_time(self):
+    """
+    Provides the unix timestamp for when our socket was either connected or
+    disconnected. That is to say, the time we connected if we're presently
+    connected and the time we disconnected if we're not connected.
+
+    :returns: **float** for when we last connected or disconnected, zero if
+      we've never connected
+    """
+
+    return self._connection_time
+
   def connect(self):
     """
     Connects to a new socket, closing our previous one if we're already
@@ -223,6 +237,7 @@ class ControlSocket(object):
         self._socket = self._make_socket()
         self._socket_file = self._socket.makefile(mode = 'rwb')
         self._is_alive = True
+        self._connection_time = time.time()
 
         # It's possible for this to have a transient failure...
         # SocketError: [Errno 4] Interrupted system call
@@ -273,6 +288,7 @@ class ControlSocket(object):
       self._socket = None
       self._socket_file = None
       self._is_alive = False
+      self._connection_time = time.time()
 
       if is_change:
         self._close()
diff --git a/test/integ/socket/control_socket.py b/test/integ/socket/control_socket.py
index 7d7b84f..f0f2e40 100644
--- a/test/integ/socket/control_socket.py
+++ b/test/integ/socket/control_socket.py
@@ -8,6 +8,7 @@ those focus on parsing and correctness of the content these are more concerned
 with the behavior of the socket itself.
 """
 
+import time
 import unittest
 
 import stem.connection
@@ -17,6 +18,42 @@ import test.runner
 
 
 class TestControlSocket(unittest.TestCase):
+  def test_connection_time(self):
+    """
+    Checks that our connection_time method tracks when our state's changed.
+    """
+
+    if test.runner.require_control(self):
+      return
+
+    test_start = time.time()
+    runner = test.runner.get_runner()
+
+    with runner.get_tor_socket() as control_socket:
+      connection_time = control_socket.connection_time()
+
+      # connection time should be between our tests start and now
+
+      self.assertTrue(test_start <= connection_time <= time.time())
+
+      # connection time should be absolute (shouldn't change as time goes on)
+
+      time.sleep(0.1)
+      self.assertEqual(connection_time, control_socket.connection_time())
+
+      # should change to the disconnection time if we detactch
+
+      control_socket.close()
+      disconnection_time = control_socket.connection_time()
+      self.assertTrue(connection_time < disconnection_time <= time.time())
+
+      # then change again if we reconnect
+
+      time.sleep(0.1)
+      control_socket.connect()
+      reconnection_time = control_socket.connection_time()
+      self.assertTrue(disconnection_time < reconnection_time <= time.time())
+
   def test_send_buffered(self):
     """
     Sends multiple requests before receiving back any of the replies.





More information about the tor-commits mailing list