Skip to content

Commit

Permalink
[FIX] Fixed failing test on macOS
Browse files Browse the repository at this point in the history
  • Loading branch information
francis-clairicia committed Oct 28, 2023
1 parent d1ac756 commit d87b72e
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 7 deletions.
10 changes: 8 additions & 2 deletions src/easynetwork_asyncio/stream/listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from typing import TYPE_CHECKING, Any, Generic, NoReturn, TypeVar, final

from easynetwork.lowlevel.api_async.transports import abc as transports
from easynetwork.lowlevel.constants import ACCEPT_CAPACITY_ERRNOS, ACCEPT_CAPACITY_ERROR_SLEEP_TIME
from easynetwork.lowlevel.constants import ACCEPT_CAPACITY_ERRNOS, ACCEPT_CAPACITY_ERROR_SLEEP_TIME, NOT_CONNECTED_SOCKET_ERRNOS
from easynetwork.lowlevel.socket import _get_socket_extra

from ..socket import AsyncSocket
Expand Down Expand Up @@ -107,7 +107,13 @@ async def client_task(client_socket: _socket.socket) -> None:
except BaseException as exc:
client_socket.close()

self.__accepted_socket_factory.log_connection_error(logger, exc)
if isinstance(exc, OSError) and exc.errno in NOT_CONNECTED_SOCKET_ERRNOS:
# The remote host closed the connection before starting the task.
# See this test for details:
# test____serve_forever____accept_client____client_sent_RST_packet_right_after_accept
logger.warning("A client connection was interrupted just after listener.accept()")
else:
self.__accepted_socket_factory.log_connection_error(logger, exc)

# Only reraise base exceptions
if not isinstance(exc, Exception):
Expand Down
27 changes: 22 additions & 5 deletions tests/unit_test/test_async/test_asyncio_backend/test_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from socket import SHUT_RDWR, SHUT_WR
from typing import TYPE_CHECKING, Any

from easynetwork.lowlevel.constants import ACCEPT_CAPACITY_ERRNOS
from easynetwork.lowlevel.constants import ACCEPT_CAPACITY_ERRNOS, NOT_CONNECTED_SOCKET_ERRNOS
from easynetwork.lowlevel.socket import SocketAttribute, TLSAttribute
from easynetwork_asyncio.stream.listener import (
AbstractAcceptedSocketFactory,
Expand Down Expand Up @@ -426,27 +426,37 @@ async def test____serve____default(
accepted_socket_factory.connect.assert_awaited_once_with(client_socket, event_loop)
handler.assert_awaited_once_with(stream)

@pytest.mark.parametrize("exception_cls", [Exception, asyncio.CancelledError, BaseException])
@pytest.mark.parametrize(
"exc",
[
*(OSError(errno, os.strerror(errno)) for errno in sorted(NOT_CONNECTED_SOCKET_ERRNOS)),
Exception(),
asyncio.CancelledError(),
BaseException(),
],
ids=repr,
)
async def test____serve____connect____error_raised(
self,
exception_cls: type[BaseException],
exc: BaseException,
event_loop: asyncio.AbstractEventLoop,
listener: ListenerSocketAdapter[Any],
mock_async_socket: MagicMock,
accepted_socket_factory: MagicMock,
handler: AsyncMock,
mock_tcp_socket_factory: Callable[[], MagicMock],
fake_cancellation_cls: type[BaseException],
caplog: pytest.LogCaptureFixture,
mocker: MockerFixture,
) -> None:
# Arrange
caplog.set_level(logging.DEBUG)
client_socket = mock_tcp_socket_factory()
exc = exception_cls()
accepted_socket_factory.connect.side_effect = exc
mock_async_socket.accept.side_effect = [client_socket, fake_cancellation_cls]

# Act
with pytest.raises(BaseExceptionGroup) if exception_cls is BaseException else contextlib.nullcontext():
with pytest.raises(BaseExceptionGroup) if type(exc) is BaseException else contextlib.nullcontext():
async with AsyncIOTaskGroup() as task_group:
with pytest.raises(fake_cancellation_cls):
await listener.serve(handler, task_group)
Expand All @@ -458,8 +468,15 @@ async def test____serve____connect____error_raised(

match exc:
case asyncio.CancelledError():
assert len(caplog.records) == 0
accepted_socket_factory.log_connection_error.assert_not_called()
case OSError():
# ENOTCONN error should not create a big Traceback error but only a warning (at least)
assert len(caplog.records) == 1
assert caplog.records[0].levelno == logging.WARNING
assert caplog.records[0].message == "A client connection was interrupted just after listener.accept()"
case _:
assert len(caplog.records) == 0
accepted_socket_factory.log_connection_error.assert_called_once_with(
mocker.ANY, # logger
exc,
Expand Down

0 comments on commit d87b72e

Please sign in to comment.