1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2024-10-05 18:31:12 +01:00

framework, tests: Correct signal disconnection

While the Louie system operated on weakrefs for the callback
functions, the priority list wrapper did not. This difference led to
weakrefs to callback functions being compared to strong references in
list element operations within Louie's disconnect method, so that
handler methods were not disconnected from signals.

Converting the receiver to a weakref then allowed Louie to operate as
normal, which may include deleting and re-appending the handler method
to the receivers list. As ``append`` is a dummy method that allows the
priority list implementation, the handler method is then never added
back to the list of connected functions, so we must ``add`` it after
``connect`` is called.

Also included is a testcase to confirm the proper disconnection of
signals.
This commit is contained in:
Jonathan Paynter 2020-07-10 18:34:09 +01:00 committed by Marc Bonnici
parent 3f5a31de96
commit 7cf5fbd8af
2 changed files with 31 additions and 5 deletions

View File

@ -30,6 +30,27 @@ class Callable(object):
return self.val return self.val
class TestSignalDisconnect(unittest.TestCase):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.callback_ctr = 0
def setUp(self):
signal.connect(self._call_me_once, 'first')
signal.connect(self._call_me_once, 'second')
def test_handler_disconnected(self):
signal.send('first')
signal.send('second')
def _call_me_once(self):
assert_equal(self.callback_ctr, 0)
self.callback_ctr += 1
signal.disconnect(self._call_me_once, 'first')
signal.disconnect(self._call_me_once, 'second')
class TestPriorityDispatcher(unittest.TestCase): class TestPriorityDispatcher(unittest.TestCase):
def setUp(self): def setUp(self):
@ -61,12 +82,16 @@ class TestPriorityDispatcher(unittest.TestCase):
def test_wrap_propagate(self): def test_wrap_propagate(self):
d = {'before': False, 'after': False, 'success': False} d = {'before': False, 'after': False, 'success': False}
def before(): def before():
d['before'] = True d['before'] = True
def after(): def after():
d['after'] = True d['after'] = True
def success(): def success():
d['success'] = True d['success'] = True
signal.connect(before, signal.BEFORE_WORKLOAD_SETUP) signal.connect(before, signal.BEFORE_WORKLOAD_SETUP)
signal.connect(after, signal.AFTER_WORKLOAD_SETUP) signal.connect(after, signal.AFTER_WORKLOAD_SETUP)
signal.connect(success, signal.SUCCESSFUL_WORKLOAD_SETUP) signal.connect(success, signal.SUCCESSFUL_WORKLOAD_SETUP)
@ -76,7 +101,7 @@ class TestPriorityDispatcher(unittest.TestCase):
with signal.wrap('WORKLOAD_SETUP'): with signal.wrap('WORKLOAD_SETUP'):
raise RuntimeError() raise RuntimeError()
except RuntimeError: except RuntimeError:
caught=True caught = True
assert_true(d['before']) assert_true(d['before'])
assert_true(d['after']) assert_true(d['after'])

View File

@ -15,7 +15,7 @@
""" """
This module wraps louie signalling mechanism. It relies on modified version of loiue This module wraps louie signalling mechanism. It relies on modified version of louie
that has prioritization added to handler invocation. that has prioritization added to handler invocation.
""" """
@ -23,8 +23,9 @@ import sys
import logging import logging
from contextlib import contextmanager from contextlib import contextmanager
from louie import dispatcher, saferef # pylint: disable=wrong-import-order
from louie.dispatcher import _remove_receiver
import wrapt import wrapt
from louie import dispatcher # pylint: disable=wrong-import-order
from wa.utils.types import prioritylist, enum from wa.utils.types import prioritylist, enum
@ -242,8 +243,8 @@ def connect(handler, signal, sender=dispatcher.Any, priority=0):
receivers = signals[signal] receivers = signals[signal]
else: else:
receivers = signals[signal] = _prioritylist_wrapper() receivers = signals[signal] = _prioritylist_wrapper()
receivers.add(handler, priority)
dispatcher.connect(handler, signal, sender) dispatcher.connect(handler, signal, sender)
receivers.add(saferef.safe_ref(handler, on_delete=_remove_receiver), priority)
def disconnect(handler, signal, sender=dispatcher.Any): def disconnect(handler, signal, sender=dispatcher.Any):
@ -268,7 +269,7 @@ def send(signal, sender=dispatcher.Anonymous, *args, **kwargs):
""" """
Sends a signal, causing connected handlers to be invoked. Sends a signal, causing connected handlers to be invoked.
Paramters: Parameters:
:signal: Signal to be sent. This must be an instance of :class:`wa.core.signal.Signal` :signal: Signal to be sent. This must be an instance of :class:`wa.core.signal.Signal`
or its subclasses. or its subclasses.