From 7be5b4c8bc5a1c187edb42015c1c3ce8b8dafaaf Mon Sep 17 00:00:00 2001 From: Andrew Resch Date: Sat, 27 Mar 2010 20:05:20 -0700 Subject: [PATCH] Add 2 new states to Component: Starting and Stopping Fix issue where a Component could have it's start and stop methods called more than once while waiting for their deferreds to fire --- deluge/component.py | 32 +++++++++++++++++++++++++------- tests/test_component.py | 15 +++++++++++++++ 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/deluge/component.py b/deluge/component.py index cdeaa59ab..9ca34a14e 100644 --- a/deluge/component.py +++ b/deluge/component.py @@ -68,17 +68,23 @@ class Component(object): call to stop() will be issued prior to shutdown(). **States:** - - A Component can be in one of these 3 states. - + + A Component can be in one of these 5 states. + **Started** - The Component has been started by the :class:`ComponentRegistry` and will have it's update timer started. - + + **Starting** - The Component has had it's start method called, but it hasn't + fully started yet. + **Stopped** - The Component has either been stopped or has yet to be started. - + + **Stopping** - The Component has had it's stop method called, but it hasn't + fully stopped yet. + **Paused** - The Component has had it's update timer stopped, but will still be considered in a Started state. - + """ def __init__(self, name, interval=1, depend=None): self._component_name = name @@ -86,6 +92,8 @@ class Component(object): self._component_depend = depend self._component_state = "Stopped" self._component_timer = None + self._component_starting_deferred = None + self._component_stopping_deferred = None _ComponentRegistry.register(self) def _component_start_timer(self): @@ -96,15 +104,20 @@ class Component(object): def _component_start(self): def on_start(result): self._component_state = "Started" + self._component_starting_deferred = None self._component_start_timer() return True if self._component_state == "Stopped": if hasattr(self, "start"): + self._component_state = "Starting" d = maybeDeferred(self.start) d.addCallback(on_start) + self._component_starting_deferred = d else: d = maybeDeferred(on_start, None) + elif self._component_state == "Starting": + return self._component_starting_deferred elif self._component_state == "Started": d = succeed(True) else: @@ -119,13 +132,18 @@ class Component(object): self._component_timer.stop() return True - if self._component_state != "Stopped": + if self._component_state != "Stopped" and self._component_state != "Stopping": if hasattr(self, "stop"): + self._component_state = "Stopping" d = maybeDeferred(self.stop) d.addCallback(on_stop) + self._component_stopping_deferred = d else: d = maybeDeferred(on_stop, None) + if self._component_state == "Stopping": + return self._component_stopping_deferred + return succeed(None) def _component_pause(self): diff --git a/tests/test_component.py b/tests/test_component.py index 81022a364..f3a1e174d 100644 --- a/tests/test_component.py +++ b/tests/test_component.py @@ -6,10 +6,14 @@ class testcomponent(component.Component): def __init__(self, name): component.Component.__init__(self, name) self.start_count = 0 + self.stop_count = 0 def start(self): self.start_count += 1 + def stop(self): + self.stop_count += 1 + class testcomponent_delaystart(testcomponent): def start(self): def do_sleep(): @@ -25,18 +29,26 @@ class testcomponent_update(component.Component): component.Component.__init__(self, name) self.counter = 0 self.start_count = 0 + self.stop_count = 0 def update(self): self.counter += 1 + def stop(self): + self.stop_count += 1 + class testcomponent_shutdown(component.Component): def __init__(self, name): component.Component.__init__(self, name) self.shutdowned = False + self.stop_count = 0 def shutdown(self): self.shutdowned = True + def stop(self): + self.stop_count += 1 + class ComponentTestClass(unittest.TestCase): def tearDown(self): component._ComponentRegistry.components = {} @@ -106,6 +118,7 @@ class ComponentTestClass(unittest.TestCase): def on_stop(result, c): self.assertEquals(c._component_state, "Stopped") self.assertFalse(c._component_timer.running) + self.assertEquals(c.stop_count, 1) def on_start(result, c): self.assertEquals(c._component_state, "Started") @@ -120,6 +133,7 @@ class ComponentTestClass(unittest.TestCase): def on_stop(*args): for c in args[1:]: self.assertEquals(c._component_state, "Stopped") + self.assertEquals(c.stop_count, 1) def on_start(*args): for c in args[1:]: @@ -169,6 +183,7 @@ class ComponentTestClass(unittest.TestCase): def on_shutdown(result, c1): self.assertTrue(c1.shutdowned) self.assertEquals(c1._component_state, "Stopped") + self.assertEquals(c1.stop_count, 1) def on_start(result, c1): d = component.shutdown()