From 19bf4b28324fd46f7d95da975ab222381f15bf79 Mon Sep 17 00:00:00 2001 From: Mike Kazantsev Date: Sat, 15 Jan 2022 01:50:49 +0500 Subject: [PATCH] Raise RuntimeError if watcher.cancel() is called after client.close() --- aetcd/client.py | 6 +++++- tests/integration/test_watch.py | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/aetcd/client.py b/aetcd/client.py index db6279f..d3a38e3 100644 --- a/aetcd/client.py +++ b/aetcd/client.py @@ -644,13 +644,17 @@ async def response_callback(response): canceled = asyncio.Event() async def cancel(): + if not self._watcher: + raise RuntimeError('Calling watcher.cancel() on a closed client') canceled.set() await events.put(None) await self._watcher.cancel(watcher_callback.watch_id) @_handle_errors async def iterator(): - while not canceled.is_set(): + if not self._watcher: + raise RuntimeError('Using watcher as iterator on a closed client') + while not canceled.is_set(): event = await events.get() if event is None: canceled.set() diff --git a/tests/integration/test_watch.py b/tests/integration/test_watch.py index 5b68e65..14d42d1 100644 --- a/tests/integration/test_watch.py +++ b/tests/integration/test_watch.py @@ -234,3 +234,16 @@ async def test_watch_key_ignores_global_timeout(client, etcdctl_put): break await w.cancel() + + +@pytest.mark.asyncio +async def test_watch_for_closed_client(etcd, etcdctl_put): + w = await etcd.watch(b'key') + etcdctl_put('key', '1') + await etcd.close() + etcdctl_put('key', '2') + with pytest.raises(RuntimeError): + async for kv in w: + raise AssertionError('non-empty watcher iterator with closed client') + with pytest.raises(RuntimeError): + await w.cancel()