From 6009bdf3b4dd929fe59d5347ef56e678cef1fe50 Mon Sep 17 00:00:00 2001 From: jolorke <165886222+jolorke@users.noreply.github.com> Date: Wed, 3 Apr 2024 09:44:34 +0200 Subject: [PATCH 1/3] add testcases for unsubsribe --- tests/test_unsubscribe.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/test_unsubscribe.py diff --git a/tests/test_unsubscribe.py b/tests/test_unsubscribe.py new file mode 100644 index 0000000..ddfd349 --- /dev/null +++ b/tests/test_unsubscribe.py @@ -0,0 +1,29 @@ +import pytest +from broadcaster import Broadcast + + +@pytest.mark.asyncio +async def test_unsubscribe(): + """The queue should be removed when the context manager is left.""" + broadcast = Broadcast("memory://") + await broadcast.connect() + + async with broadcast.subscribe("chatroom"): + pass + + assert "chatroom" not in broadcast._subscribers + + +@pytest.mark.asyncio +async def test_unsubscribe_w_exception(): + """In case an exception is raised inside the context manager, the queue should be removed.""" + broadcast = Broadcast("memory://") + await broadcast.connect() + + try: + async with broadcast.subscribe("chatroom"): + raise RuntimeError("MyException") + except RuntimeError: + pass + + assert "chatroom" not in broadcast._subscribers From 3015fffa5a928c69a70f9f8f2b58304404e111e6 Mon Sep 17 00:00:00 2001 From: jolorke <165886222+jolorke@users.noreply.github.com> Date: Tue, 2 Apr 2024 17:00:37 +0200 Subject: [PATCH 2/3] fix the context manager of the function "subscribe" not removing the associated queue from the channel in case of a raised exception inside the context manager (e.g. being used inside a generator that gets closed raising GeneratorExit) --- broadcaster/_base.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/broadcaster/_base.py b/broadcaster/_base.py index 4de1417..c8dc221 100644 --- a/broadcaster/_base.py +++ b/broadcaster/_base.py @@ -90,12 +90,11 @@ async def subscribe(self, channel: str) -> AsyncIterator["Subscriber"]: self._subscribers[channel].add(queue) yield Subscriber(queue) - + finally: self._subscribers[channel].remove(queue) if not self._subscribers.get(channel): del self._subscribers[channel] await self._backend.unsubscribe(channel) - finally: await queue.put(None) From 1694033e41d0f34dd1f2ea4dcd8877fbe352c667 Mon Sep 17 00:00:00 2001 From: "alex.oleshkevich" Date: Wed, 3 Apr 2024 21:20:00 +0200 Subject: [PATCH 3/3] activate broadcaster via context manager --- tests/test_unsubscribe.py | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/tests/test_unsubscribe.py b/tests/test_unsubscribe.py index ddfd349..30f928b 100644 --- a/tests/test_unsubscribe.py +++ b/tests/test_unsubscribe.py @@ -5,25 +5,21 @@ @pytest.mark.asyncio async def test_unsubscribe(): """The queue should be removed when the context manager is left.""" - broadcast = Broadcast("memory://") - await broadcast.connect() - - async with broadcast.subscribe("chatroom"): - pass + async with Broadcast("memory://") as broadcast: + async with broadcast.subscribe("chatroom"): + pass - assert "chatroom" not in broadcast._subscribers + assert "chatroom" not in broadcast._subscribers @pytest.mark.asyncio async def test_unsubscribe_w_exception(): """In case an exception is raised inside the context manager, the queue should be removed.""" - broadcast = Broadcast("memory://") - await broadcast.connect() - - try: - async with broadcast.subscribe("chatroom"): - raise RuntimeError("MyException") - except RuntimeError: - pass - - assert "chatroom" not in broadcast._subscribers + async with Broadcast("memory://") as broadcast: + try: + async with broadcast.subscribe("chatroom"): + raise RuntimeError("MyException") + except RuntimeError: + pass + + assert "chatroom" not in broadcast._subscribers