Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Review AndroidTV decorator exception management #114133

Merged
merged 6 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 21 additions & 10 deletions homeassistant/components/androidtv/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,24 +77,35 @@ async def _adb_exception_catcher(
)
return None
except self.exceptions as err:
_LOGGER.error(
(
"Failed to execute an ADB command. ADB connection re-"
"establishing attempt in the next update. Error: %s"
),
err,
)
if self.available:
_LOGGER.error(
(
"Failed to execute an ADB command. ADB connection re-"
"establishing attempt in the next update. Error: %s"
),
err,
)

await self.aftv.adb_close()
# pylint: disable-next=protected-access
self._attr_available = False
return None
except Exception:
except Exception as err: # pylint: disable=broad-except
davet2001 marked this conversation as resolved.
Show resolved Hide resolved
# An unforeseen exception occurred. Close the ADB connection so that
# it doesn't happen over and over again, then raise the exception.
# it doesn't happen over and over again.
if self.available:
_LOGGER.error(
(
"Unexpected exception executing an ADB command. ADB connection"
" re-establishing attempt in the next update. Error: %s"
),
err,
)

await self.aftv.adb_close()
# pylint: disable-next=protected-access
self._attr_available = False
raise
return None

return _adb_exception_catcher

Expand Down
26 changes: 18 additions & 8 deletions tests/components/androidtv/test_media_player.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""The tests for the androidtv platform."""

from collections.abc import Generator
from datetime import timedelta
import logging
from typing import Any
Expand Down Expand Up @@ -170,7 +171,7 @@


@pytest.fixture(autouse=True)
def adb_device_tcp_fixture() -> None:
def adb_device_tcp_fixture() -> Generator[None, patchers.AdbDeviceTcpAsyncFake, None]:
"""Patch ADB Device TCP."""
with patch(
"androidtv.adb_manager.adb_manager_async.AdbDeviceTcpAsync",
Expand All @@ -180,7 +181,7 @@ def adb_device_tcp_fixture() -> None:


@pytest.fixture(autouse=True)
def load_adbkey_fixture() -> None:
def load_adbkey_fixture() -> Generator[None, str, None]:
"""Patch load_adbkey."""
with patch(
"homeassistant.components.androidtv.ADBPythonSync.load_adbkey",
Expand All @@ -190,7 +191,7 @@ def load_adbkey_fixture() -> None:


@pytest.fixture(autouse=True)
def keygen_fixture() -> None:
def keygen_fixture() -> Generator[None, Mock, None]:
"""Patch keygen."""
with patch(
"homeassistant.components.androidtv.keygen",
Expand Down Expand Up @@ -1181,7 +1182,7 @@ async def test_connection_closed_on_ha_stop(hass: HomeAssistant) -> None:
assert adb_close.called


async def test_exception(hass: HomeAssistant) -> None:
async def test_exception(hass: HomeAssistant, caplog: pytest.LogCaptureFixture) -> None:
"""Test that the ADB connection gets closed when there is an unforeseen exception.

HA will attempt to reconnect on the next update.
Expand All @@ -1201,12 +1202,21 @@ async def test_exception(hass: HomeAssistant) -> None:
assert state is not None
assert state.state == STATE_OFF

caplog.clear()
caplog.set_level(logging.ERROR)

# When an unforeseen exception occurs, we close the ADB connection and raise the exception
with patchers.PATCH_ANDROIDTV_UPDATE_EXCEPTION, pytest.raises(Exception):
with patchers.PATCH_ANDROIDTV_UPDATE_EXCEPTION:
await async_update_entity(hass, entity_id)
state = hass.states.get(entity_id)
assert state is not None
assert state.state == STATE_UNAVAILABLE

davet2001 marked this conversation as resolved.
Show resolved Hide resolved
state = hass.states.get(entity_id)
assert state is not None
assert state.state == STATE_UNAVAILABLE
assert len(caplog.record_tuples) == 1
assert caplog.record_tuples[0][1] == logging.ERROR
assert caplog.record_tuples[0][2].startswith(
"Unexpected exception executing an ADB command"
)

# On the next update, HA will reconnect to the device
await async_update_entity(hass, entity_id)
Expand Down
Loading