commit 1fb3a96c75f5eb6f1706ab7d34d582df3ee2cce7 Author: Damian Johnson atagar@torproject.org Date: Wed Jan 16 09:27:27 2013 -0800
Notifying status listeners of SIGHUPs
Our status listeners should be notified when three things happen...
* we newly connect to a controller * we disconnect from a controller * tor's state is reset by a SIGHUP signal
We had implemented the first two, but not the third. Correcting this oversight. --- stem/control.py | 8 ++++++- test/integ/control/controller.py | 42 +++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-)
diff --git a/stem/control.py b/stem/control.py index 8d6f1b7..10bc667 100644 --- a/stem/control.py +++ b/stem/control.py @@ -146,7 +146,7 @@ import stem.util.enum import stem.util.tor_tools import stem.version
-from stem import UNDEFINED, CircStatus +from stem import UNDEFINED, CircStatus, Signal from stem.util import log
# state changes a control socket can have @@ -675,6 +675,12 @@ class Controller(BaseController): self._geoip_failure_count = 0 self._enabled_features = []
+ def _sighup_listener(event): + if event.signal == Signal.RELOAD: + self._notify_status_listeners(State.RESET) + + self.add_event_listener(_sighup_listener, EventType.SIGNAL) + def connect(self): super(Controller, self).connect() self.clear_cache() diff --git a/test/integ/control/controller.py b/test/integ/control/controller.py index 4d39a8b..600403b 100644 --- a/test/integ/control/controller.py +++ b/test/integ/control/controller.py @@ -9,6 +9,7 @@ import shutil import socket import tempfile import threading +import time import unittest
import stem.connection @@ -22,7 +23,8 @@ import test.network import test.runner import test.util
-from stem.control import EventType +from stem import Signal +from stem.control import EventType, State from stem.exit_policy import ExitPolicy from stem.version import Requirement
@@ -56,6 +58,44 @@ class TestController(unittest.TestCase): else: self.assertRaises(stem.SocketError, stem.control.Controller.from_socket_file, test.runner.CONTROL_SOCKET_PATH)
+ def test_reset_notification(self): + """ + Checks that a notificiation listener is... well, notified of SIGHUPs. + """ + + if test.runner.require_control(self): + return + elif test.runner.require_version(self, stem.version.Requirement.EVENT_SIGNAL): + return + + with test.runner.get_runner().get_tor_controller() as controller: + received_events = [] + + def status_listener(my_controller, state, timestamp): + received_events.append((my_controller, state, timestamp)) + + controller.add_status_listener(status_listener) + + before = time.time() + controller.signal(Signal.HUP) + + # I really hate adding a sleep here, but signal() is non-blocking. + while len(received_events) == 0: + if (time.time() - before) > 2: + self.fail("We've waited a couple seconds for SIGHUP to generate an event, but it didn't come") + + time.sleep(0.1) + + after = time.time() + + self.assertEqual(1, len(received_events)) + + state_controller, state_type, state_timestamp = received_events[0] + + self.assertEqual(controller, state_controller) + self.assertEqual(State.RESET, state_type) + self.assertTrue(state_timestamp > before and state_timestamp < after) + def test_event_handling(self): """ Add a couple listeners for various events and make sure that they receive