diff --git a/capnp/lib/capnp.pyx b/capnp/lib/capnp.pyx index 6f4383d..e639f66 100644 --- a/capnp/lib/capnp.pyx +++ b/capnp/lib/capnp.pyx @@ -2247,6 +2247,8 @@ cdef class TwoPartyClient: return _CapabilityClient()._init(helpers.bootstrapHelper(deref(self.thisptr)), self) cpdef on_disconnect(self) except +reraise_kj_exception: + if self.closed: + raise RuntimeError("This client is closed") return self._network.on_disconnect() @@ -2300,6 +2302,8 @@ cdef class TwoPartyServer: return _CapabilityClient()._init(helpers.bootstrapHelperServer(deref(self.thisptr)), self) cpdef on_disconnect(self) except +reraise_kj_exception: + if self.closed: + raise RuntimeError("This server is closed") return _voidpromise_to_asyncio(deref(self._network.thisptr).onDisconnect() .attach(capnp.heap[PyRefCounter](self))) diff --git a/test/test_context_manager.py b/test/test_context_manager.py index 7d38b0a..281d85e 100644 --- a/test/test_context_manager.py +++ b/test/test_context_manager.py @@ -195,11 +195,31 @@ async def test_kj_loop_partial_write_message_after_close(): assert "The KJ event-loop is not running" in str(exninfo) +async def test_client_on_disconnect_memory(): + read, _ = socket.socketpair() + async with capnp.kj_loop(): + read = await capnp.AsyncIoStream.create_connection(sock=read) + client = capnp.TwoPartyClient(read) + with pytest.raises(RuntimeError) as exninfo: + await client.on_disconnect() + assert "This client is closed" in str(exninfo) + + +async def test_server_on_disconnect_memory(): + _, write = socket.socketpair() + async with capnp.kj_loop(): + write = await capnp.AsyncIoStream.create_connection(sock=write) + server = capnp.TwoPartyServer(write, bootstrap=test_capability.Server()) + with pytest.raises(RuntimeError) as exninfo: + await server.on_disconnect() + assert "This server is closed" in str(exninfo) + + @pytest.mark.xfail( strict=True, reason="Fails because the promisefulfiller got destroyed. Possibly a bug in the C++ library.", ) -async def test_client_on_disconnect_memory(): +async def test_client_on_disconnect_memory2(): """ E capnp.lib.capnp.KjException: kj/async.c++:2813: failed: PromiseFulfiller was destroyed without fulfilling the promise. @@ -210,3 +230,16 @@ async def test_client_on_disconnect_memory(): client = capnp.TwoPartyClient(read) disc = client.on_disconnect() await disc + + +async def test_server_on_disconnect_memory2(): + """ + E capnp.lib.capnp.KjException: kj/async.c++:2813: failed: + PromiseFulfiller was destroyed without fulfilling the promise. + """ + _, write = socket.socketpair() + async with capnp.kj_loop(): + write = await capnp.AsyncIoStream.create_connection(sock=write) + server = capnp.TwoPartyServer(write, bootstrap=test_capability.Server()) + disc = server.on_disconnect() + await disc