mirror of
https://github.com/esphome/aioesphomeapi.git
synced 2024-09-27 04:22:46 +02:00
Fix client connection code swallowing unhandled exceptions as debug logging (#711)
This commit is contained in:
parent
2f49f804e5
commit
79686bf729
@ -85,7 +85,6 @@ from .core import (
|
|||||||
APIConnectionError,
|
APIConnectionError,
|
||||||
BluetoothGATTAPIError,
|
BluetoothGATTAPIError,
|
||||||
TimeoutAPIError,
|
TimeoutAPIError,
|
||||||
UnhandledAPIConnectionError,
|
|
||||||
to_human_readable_address,
|
to_human_readable_address,
|
||||||
)
|
)
|
||||||
from .model import (
|
from .model import (
|
||||||
@ -324,14 +323,9 @@ class APIClient:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
await self._connection.start_connection()
|
await self._connection.start_connection()
|
||||||
except APIConnectionError:
|
except Exception:
|
||||||
self._connection = None
|
self._connection = None
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
|
||||||
self._connection = None
|
|
||||||
raise UnhandledAPIConnectionError(
|
|
||||||
f"Unexpected error while connecting to {self.log_name}: {e}"
|
|
||||||
) from e
|
|
||||||
# If we resolved the address, we should set the log name now
|
# If we resolved the address, we should set the log name now
|
||||||
if self._connection.resolved_addr_info:
|
if self._connection.resolved_addr_info:
|
||||||
self._set_log_name()
|
self._set_log_name()
|
||||||
@ -345,14 +339,9 @@ class APIClient:
|
|||||||
assert self._connection is not None
|
assert self._connection is not None
|
||||||
try:
|
try:
|
||||||
await self._connection.finish_connection(login=login)
|
await self._connection.finish_connection(login=login)
|
||||||
except APIConnectionError:
|
except Exception:
|
||||||
self._connection = None
|
self._connection = None
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
|
||||||
self._connection = None
|
|
||||||
raise UnhandledAPIConnectionError(
|
|
||||||
f"Unexpected error while connecting to {self.log_name}: {e}"
|
|
||||||
) from e
|
|
||||||
if received_name := self._connection.received_name:
|
if received_name := self._connection.received_name:
|
||||||
self._set_name_from_device(received_name)
|
self._set_name_from_device(received_name)
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ from .api_pb2 import ( # type: ignore
|
|||||||
)
|
)
|
||||||
from .core import (
|
from .core import (
|
||||||
MESSAGE_TYPE_TO_PROTO,
|
MESSAGE_TYPE_TO_PROTO,
|
||||||
|
APIConnectionCancelledError,
|
||||||
APIConnectionError,
|
APIConnectionError,
|
||||||
BadNameAPIError,
|
BadNameAPIError,
|
||||||
ConnectionNotEstablishedAPIError,
|
ConnectionNotEstablishedAPIError,
|
||||||
@ -46,6 +47,7 @@ from .core import (
|
|||||||
ResolveAPIError,
|
ResolveAPIError,
|
||||||
SocketAPIError,
|
SocketAPIError,
|
||||||
TimeoutAPIError,
|
TimeoutAPIError,
|
||||||
|
UnhandledAPIConnectionError,
|
||||||
)
|
)
|
||||||
from .model import APIVersion
|
from .model import APIVersion
|
||||||
from .zeroconf import ZeroconfManager
|
from .zeroconf import ZeroconfManager
|
||||||
@ -540,8 +542,12 @@ class APIConnection:
|
|||||||
cause = ex
|
cause = ex
|
||||||
if isinstance(self._fatal_exception, APIConnectionError):
|
if isinstance(self._fatal_exception, APIConnectionError):
|
||||||
klass = type(self._fatal_exception)
|
klass = type(self._fatal_exception)
|
||||||
|
elif isinstance(ex, CancelledError):
|
||||||
|
klass = APIConnectionCancelledError
|
||||||
|
elif isinstance(ex, OSError):
|
||||||
|
klass = SocketAPIError
|
||||||
else:
|
else:
|
||||||
klass = APIConnectionError
|
klass = UnhandledAPIConnectionError
|
||||||
new_exc = klass(f"Error while {action} connection: {err_str}")
|
new_exc = klass(f"Error while {action} connection: {err_str}")
|
||||||
new_exc.__cause__ = cause or ex
|
new_exc.__cause__ = cause or ex
|
||||||
return new_exc
|
return new_exc
|
||||||
|
@ -160,6 +160,10 @@ class APIConnectionError(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class APIConnectionCancelledError(APIConnectionError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class InvalidAuthAPIError(APIConnectionError):
|
class InvalidAuthAPIError(APIConnectionError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@ from aioesphomeapi.core import (
|
|||||||
APIConnectionError,
|
APIConnectionError,
|
||||||
BluetoothGATTAPIError,
|
BluetoothGATTAPIError,
|
||||||
TimeoutAPIError,
|
TimeoutAPIError,
|
||||||
|
UnhandledAPIConnectionError,
|
||||||
)
|
)
|
||||||
from aioesphomeapi.model import (
|
from aioesphomeapi.model import (
|
||||||
AlarmControlPanelCommand,
|
AlarmControlPanelCommand,
|
||||||
@ -95,6 +96,7 @@ from .common import (
|
|||||||
get_mock_zeroconf,
|
get_mock_zeroconf,
|
||||||
mock_data_received,
|
mock_data_received,
|
||||||
)
|
)
|
||||||
|
from .conftest import PatchableAPIConnection
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -172,6 +174,26 @@ async def test_connect_backwards_compat() -> None:
|
|||||||
assert mock_finish_connection.mock_calls == [call(False)]
|
assert mock_finish_connection.mock_calls == [call(False)]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_finish_connection_wraps_exceptions_as_unhandled_api_error() -> None:
|
||||||
|
"""Verify finish_connect re-wraps exceptions as UnhandledAPIError."""
|
||||||
|
|
||||||
|
cli = APIClient("1.2.3.4", 1234, None)
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
with patch(
|
||||||
|
"aioesphomeapi.client.APIConnection", PatchableAPIConnection
|
||||||
|
), patch.object(loop, "sock_connect"):
|
||||||
|
await cli.start_connection()
|
||||||
|
|
||||||
|
with patch.object(
|
||||||
|
cli._connection,
|
||||||
|
"send_messages_await_response_complex",
|
||||||
|
side_effect=Exception("foo"),
|
||||||
|
):
|
||||||
|
with pytest.raises(UnhandledAPIConnectionError, match="foo"):
|
||||||
|
await cli.finish_connection(False)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_connect_while_already_connected(auth_client: APIClient) -> None:
|
async def test_connect_while_already_connected(auth_client: APIClient) -> None:
|
||||||
"""Test connecting while already connected raises."""
|
"""Test connecting while already connected raises."""
|
||||||
|
Loading…
Reference in New Issue
Block a user