commit d220b901851db31758e4f38703b31e090cbb471b Author: Damian Johnson atagar@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.
tor-commits@lists.torproject.org