A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/python-trio/pytest-trio/issues/30 below:

Reduce danger of accidental exception suppression · Issue #30 · python-trio/pytest-trio · GitHub

Consider the following code. It consists of an echo server with a bug, and a unit test for the server:

#!/usr/bin/env python3

import pytest
import pytest_trio
import trio
import logging

log = logging.getLogger(__name__)
PORT = 12346
BUFSIZE = 16384
async def echo_server(server_sock):
    try:
        with server_sock:
            await server_sock.recv(BUFSIZE)
            raise RuntimeError('Damn!')
    except Exception as exc:
        await trio.sleep(0.1) # make problem deterministic
        log.exception('Things went wrong...')

async def echo_listener(nursery):
    with trio.socket.socket() as listen_sock:
        await listen_sock.bind(("127.0.0.1", PORT))
        listen_sock.listen()
        while True:
            server_sock, _ = await listen_sock.accept()
            nursery.start_soon(echo_server, server_sock)

async def parent():
    async with trio.open_nursery() as nursery:
        nursery.start_soon(echo_listener, nursery)

@pytest.mark.trio
async def test_server(nursery):
    nursery.start_soon(parent)
    await trio.sleep(0.5) # wait for server to listen
    with trio.socket.socket() as client_sock:
        await client_sock.connect(("127.0.0.1", PORT))
        await client_sock.send(b'hello, world')
        resp = await client_sock.recv(BUFSIZE)
        assert resp == b'hello, world'

As expected, the unittest fails - but the root cause is nowhere to be seen:

$ python3 -m pytest tests/lograce.py 
==================================== test session starts =====================================
platform linux -- Python 3.6.4, pytest-3.3.2, py-1.5.2, pluggy-0.6.0 -- /home/nikratio/consulting/iofabric/venv/bin/python3
cachedir: tests/.cache
rootdir: /home/nikratio/consulting/iofabric/gruagach/tests, inifile: pytest.ini
plugins: trio-0.3.0
collected 1 item                                                                             

tests/lograce.py::test_server FAILED                                                   [100%]

========================================== FAILURES ==========================================
________________________________________ test_server _________________________________________
Traceback (most recent call last):
  File "/home/nikratio/consulting/iofabric/gruagach/tests/lograce.py", line 41, in test_server
    assert resp == b'hello, world'
AssertionError: assert b'' == b'hello, world'
  Right contains more items, first extra item: 104
  Full diff:
  - b''
  + b'hello, world'
================================== 1 failed in 0.63 seconds ==================================

If we force the test to wait a moment before failing...

@pytest.mark.trio
async def test_server(nursery):
    nursery.start_soon(parent)
    await trio.sleep(0.5)  # wait for server to listen
    try:
        with trio.socket.socket() as client_sock:
            await client_sock.connect(("127.0.0.1", PORT))
            await client_sock.send(b'hello, world')
            resp = await client_sock.recv(BUFSIZE)
            assert resp == b'hello, world'
    finally:
        await trio.sleep(0.5)

...we get much better results:

$ python3 -m pytest tests/lograce.py 
[...]
collected 1 item                                                                             

tests/lograce.py::test_server FAILED                                                   [100%]

========================================== FAILURES ==========================================
________________________________________ test_server _________________________________________
Traceback (most recent call last):
  File "/home/nikratio/consulting/iofabric/gruagach/tests/lograce.py", line 42, in test_server
    assert resp == b'hello, world'
AssertionError: assert b'' == b'hello, world'
  Right contains more items, first extra item: 104
  Full diff:
  - b''
  + b'hello, world'
------------------------------------- Captured log call --------------------------------------
21:55:13.383 ERROR    lograce.echo_server: Things went wrong...
Traceback (most recent call last):
  File "/home/nikratio/consulting/iofabric/gruagach/tests/lograce.py", line 15, in echo_server
    raise RuntimeError('Damn!')
RuntimeError: Damn!
================================== 1 failed in 1.13 seconds ==================================

I believe the problem is that the failing test causes trio to cancel the server tasks before it has a chance to log its exception. Note that the call to trio.wait in echo_server is not necessay for the problem to occur, it just makes it much more likely.

I am not sure how to best fix this. Maybe the trio test runner could, if the test fails, give the other nursery task a short grace period in which they have a chance to report any errors before cancelling them?


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4