Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #592 +/- ##
==========================================
- Coverage 85.66% 85.62% -0.04%
==========================================
Files 29 29
Lines 3480 3493 +13
Branches 601 601
==========================================
+ Hits 2981 2991 +10
- Misses 308 311 +3
Partials 191 191 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
107224c to
9302e0d
Compare
dlech
left a comment
There was a problem hiding this comment.
Unfortunately, currently this is not so simple. This is due to how sockets and connections are currently handled, which is not ideal.
The problem is that the socket is actually connected in the constructor (__init__()) instead being done in the connect() method. So disconnect() needs to be called always even if connect() fails. Otherwise we would leak resources.
I suppose we could add a try/except in the __enter__() method to call disconnect() if connect() fails. But ideally, we would address #570 first to fix that situation.
This makes it easy to disconnect the bus once you are done.
|
Thanks for the feedback. If I understand correctly, with your changes this is already an improvement even if #569 would not get fixed. |
|
Yes, I think we shouldn't be blocked by #569. And we should add a Then I think we could merge it. |
I had a quick look at this but it wasn't obvious how |
|
Two ideas:
|
|
I am sorry, I am really stuck here. I tried something like this, but @pytest.mark.asyncio
async def test_context_manager_failing():
host = "127.0.0.1"
port = "55556"
async def handle_connection(reader, writer):
writer.write(b'bogus\r\n')
await writer.drain()
writer.close()
await writer.wait_closed()
server = await asyncio.start_server(handle_connection, host, port)
bus = MessageBus(bus_address=f"tcp:host={host},port={port}")
assert not bus.connected
async with bus:
assert bus.connected
assert not bus.connected
server.close()Mocking doesn't work either because |
|
I think you are on the right track. I like the idea of making a "naughty" TCP server. 😄 I would suggest to make the server actually wait for a request and then respond to it. Something like: @pytest.mark.asyncio
async def test_context_manager_failing():
host = "127.0.0.1"
port = "55556"
tasks: list[asyncio.Task[Any]] = []
async def handle_connection(reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
async def read() -> None:
while True:
try:
data = await reader.read(100)
if not data:
break
writer.write(b"this is not the correct response\r\n")
await writer.drain()
except OSError:
break
tasks.append(asyncio.create_task(read()))
server = await asyncio.start_server(handle_connection, host, port)
bus = MessageBus(bus_address=f"tcp:host={host},port={port}")
assert not bus.connected
with pytest.raises(ValueError, match="not a valid _AuthResponse"):
async with bus:
pass
assert not bus.connected
server.close()(This needs a bit more work to cancel the reader/writer task and close the reader/writer.) Then, I think this test exposes a bug in my suggestion. It looks like it is hanging on This is really a deeper problem in dbus-fast in that this can hang under certain conditions because it requires I/O to be attempted in order to trigger an exception in a reader or writer callback that in turn triggers the finalizer that the method is waiting on. So we probably need to just call async def __aenter__(self) -> MessageBus:
try:
return await self.connect()
except BaseException:
self._finalize()
raise |
| await self.wait_for_disconnect() | ||
| raise | ||
|
|
||
| async def __aexit__(self, *args, **kwargs) -> None: |
There was a problem hiding this comment.
| async def __aexit__(self, *args, **kwargs) -> None: | |
| async def __aexit__(self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None, /) -> None: |
Let's use the proper type hints here.
This makes it easy to disconnect the bus once you are done.