commit 9b1897578aca4a8befda999efcc5ad64aaf646ed Author: Damian Johnson atagar@torproject.org Date: Tue Apr 2 11:05:22 2019 -0700
Add a get_start_time() method
On reflection, process initialization time is cachable whereas uptime is not. Adding a get_start_time() method, not only for its own usefulness but because it inherrantly lets us make get_uptime() a cached method. --- docs/change_log.rst | 1 + stem/control.py | 72 +++++++++++++++++++++++++++++------------ test/unit/control/controller.py | 7 ++-- 3 files changed, 58 insertions(+), 22 deletions(-)
diff --git a/docs/change_log.rst b/docs/change_log.rst index 5c0208cb..f188c885 100644 --- a/docs/change_log.rst +++ b/docs/change_log.rst @@ -47,6 +47,7 @@ The following are only available within Stem's `git repository
* **Controller**
+ * Added :func:`~stem.control.Controller.get_start_time` method to the :class:`~stem.control.Controller` * Added :func:`~stem.control.Controller.get_uptime` method to the :class:`~stem.control.Controller` * Controller events could fail to be delivered in a timely fashion (:trac:`27173`) * Adjusted :func:`~stem.control.Controller.get_microdescriptors` fallback to also use '.new' cache files (:trac:`28508`) diff --git a/stem/control.py b/stem/control.py index b4436af0..3ea3752f 100644 --- a/stem/control.py +++ b/stem/control.py @@ -84,6 +84,7 @@ If you're fine with allowing your script to raise exceptions then this can be mo |- get_protocolinfo - information about the controller interface |- get_user - provides the user tor is running as |- get_pid - provides the pid of our tor process + |- get_start_time - timestamp when the tor process began |- get_uptime - duration tor has been running |- is_user_traffic_allowed - checks if we send or receive direct user traffic | @@ -1582,8 +1583,10 @@ class Controller(BaseController):
user = self._get_cache('user')
- if not user: - user = self.get_info('process/user', None) + if user: + return user + + user = self.get_info('process/user', None)
if not user and self.is_localhost(): pid = self.get_pid(None) @@ -1618,11 +1621,13 @@ class Controller(BaseController):
pid = self._get_cache('pid')
- if not pid: - getinfo_pid = self.get_info('process/pid', None) + if pid: + return pid
- if getinfo_pid and getinfo_pid.isdigit(): - pid = int(getinfo_pid) + getinfo_pid = self.get_info('process/pid', None) + + if getinfo_pid and getinfo_pid.isdigit(): + pid = int(getinfo_pid)
if not pid and self.is_localhost(): pid_file_path = self.get_conf('PidFile', None) @@ -1652,30 +1657,37 @@ class Controller(BaseController): raise ValueError("Unable to resolve tor's pid" if self.is_localhost() else "Tor isn't running locally")
@with_default() - def get_uptime(self, default = UNDEFINED): + def get_start_time(self, default = UNDEFINED): """ - get_uptime(default = UNDEFINED) + get_start_time(default = UNDEFINED)
- Provides the duration in seconds that tor has been running. + Provides when the tor process began.
.. versionadded:: 1.8.0
:param object default: response if the query fails
- :returns: **int** for the number of seconds tor has been running + :returns: **float** for the unix timestamp of when the tor process began
- :raises: **ValueError** if unable to determine the uptime and no default - was provided + :raises: **ValueError** if unable to determine when the process began and + no default was provided """
+ start_time = self._get_cache('start_time') + + if start_time: + return start_time + if self.get_version() >= stem.version.Requirement.GETINFO_UPTIME: uptime = self.get_info('uptime', None)
- if uptime and uptime.isdigit(): - return int(uptime) - else: - raise ValueError("'GETINFO uptime' did not provide a valid numeric response: %s" % uptime) - else: + if uptime: + if not uptime.isdigit(): + raise ValueError("'GETINFO uptime' did not provide a valid numeric response: %s" % uptime) + + start_time = time.time() - float(uptime) + + if not start_time and self.is_localhost(): # Tor doesn't yet support this GETINFO option, attempt to determine the # uptime of the process ourselves.
@@ -1689,10 +1701,30 @@ class Controller(BaseController):
start_time = stem.util.system.start_time(pid)
- if not start_time: - raise ValueError('Unable to determine when the tor process began') + if start_time: + self._set_cache({'start_time': start_time}) + return start_time + else: + raise ValueError("Unable to resolve when tor began" if self.is_localhost() else "Tor isn't running locally") + + @with_default() + def get_uptime(self, default = UNDEFINED): + """ + get_uptime(default = UNDEFINED) + + Provides the duration in seconds that tor has been running. + + .. versionadded:: 1.8.0 + + :param object default: response if the query fails + + :returns: **float** for the number of seconds tor has been running + + :raises: **ValueError** if unable to determine the uptime and no default + was provided + """
- return time.time() - start_time + return time.time() - self.get_start_time()
def is_user_traffic_allowed(self): """ diff --git a/test/unit/control/controller.py b/test/unit/control/controller.py index f5e63771..94c1b65f 100644 --- a/test/unit/control/controller.py +++ b/test/unit/control/controller.py @@ -563,14 +563,17 @@ class TestControl(unittest.TestCase): self.assertEqual(432, self.controller.get_pid())
@patch('stem.control.Controller.get_version', Mock(return_value = stem.version.Version('0.5.0.14'))) + @patch('stem.socket.ControlSocket.is_localhost', Mock(return_value = False)) @patch('stem.control.Controller.get_info') + @patch('time.time', Mock(return_value = 1000.0)) def test_get_uptime_by_getinfo(self, getinfo_mock): """ Exercise the get_uptime() resolution via a GETINFO query. """
getinfo_mock.return_value = '321' - self.assertEqual(321, self.controller.get_uptime()) + self.assertEqual(321.0, self.controller.get_uptime()) + self.controller.clear_cache()
getinfo_mock.return_value = 'abc' self.assertRaisesWith(ValueError, "'GETINFO uptime' did not provide a valid numeric response: abc", self.controller.get_uptime) @@ -585,7 +588,7 @@ class TestControl(unittest.TestCase): Exercise the get_uptime() resolution via process age. """
- self.assertEqual(200, self.controller.get_uptime()) + self.assertEqual(200.0, self.controller.get_uptime())
@patch('stem.control.Controller.get_info') def test_get_network_status_for_ourselves(self, get_info_mock):
tor-commits@lists.torproject.org