-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
LIU-284: Add exception logging in EventFirer
Event sources will generally not be aware of the exceptions that a listener could throw and should not be handling them. To preserve existing behaviour, exceptions are logged and immediately rethrown. However arguably they should be swallowed at this point to prevent other listeners from being affected.
- Loading branch information
1 parent
b27c1aa
commit dc6cda1
Showing
2 changed files
with
59 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
from typing import Optional | ||
from dlg.event import EventFirer, EventHandler, Event | ||
import pytest | ||
|
||
|
||
class MockEventSource(EventFirer): | ||
def fireEvent(self, eventType, **kwargs): | ||
self._fireEvent(eventType, **kwargs) | ||
|
||
|
||
class MockThrowingEventHandler(EventHandler): | ||
def __init__(self) -> None: | ||
self.wasCalled = False | ||
|
||
def handleEvent(self, e: Event) -> None: | ||
self.wasCalled = True | ||
raise RuntimeError("MockThrow", e) | ||
|
||
|
||
class MockEventHandler(EventHandler): | ||
def __init__(self) -> None: | ||
self.lastEvent: Optional[Event] = None | ||
|
||
def handleEvent(self, e: Event) -> None: | ||
self.lastEvent = e | ||
|
||
|
||
def test_listener_exception_interrupts_later_handlers(): | ||
eventSource = MockEventSource() | ||
handler1 = MockEventHandler() | ||
handler2 = MockEventHandler() | ||
throwingHandler = MockThrowingEventHandler() | ||
eventSource.subscribe(handler1, "raise") | ||
eventSource.subscribe(throwingHandler, "raise") | ||
eventSource.subscribe(handler2, "raise") | ||
|
||
with pytest.raises(RuntimeError): | ||
eventSource.fireEvent("raise", prop="value") | ||
|
||
assert throwingHandler.wasCalled | ||
assert handler1.lastEvent is not None | ||
assert getattr(handler1.lastEvent, "prop") == "value" | ||
assert handler2.lastEvent is None | ||
|
||
|
||
def test_listener_exception_is_logged(caplog: pytest.LogCaptureFixture): | ||
eventSource = MockEventSource() | ||
eventSource.subscribe(MockThrowingEventHandler(), "raise") | ||
|
||
with pytest.raises(RuntimeError) as excinfo: | ||
eventSource.fireEvent("raise") | ||
|
||
assert "MockThrow" in str(excinfo.value) | ||
assert "MockThrow" in caplog.text, "Expected exception to have been logged" |