Improve exception handling in Habitica integration (#135950)
parent
ccd7b1c21a
commit
ec45cb4939
|
@ -335,16 +335,24 @@ class HabiticaButton(HabiticaBase, ButtonEntity):
|
|||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="setup_rate_limit_exception",
|
||||
translation_placeholders={"retry_after": str(e.retry_after)},
|
||||
) from e
|
||||
except NotAuthorizedError as e:
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_unallowed",
|
||||
) from e
|
||||
except (HabiticaException, ClientError) as e:
|
||||
except HabiticaException as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": e.error.message},
|
||||
) from e
|
||||
except ClientError as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": str(e)},
|
||||
) from e
|
||||
else:
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
|
|
@ -85,11 +85,19 @@ class HabiticaDataUpdateCoordinator(DataUpdateCoordinator[HabiticaData]):
|
|||
raise ConfigEntryNotReady(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="setup_rate_limit_exception",
|
||||
translation_placeholders={"retry_after": str(e.retry_after)},
|
||||
) from e
|
||||
except (HabiticaException, ClientError) as e:
|
||||
except HabiticaException as e:
|
||||
raise ConfigEntryNotReady(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": str(e.error.message)},
|
||||
) from e
|
||||
except ClientError as e:
|
||||
raise ConfigEntryNotReady(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": str(e)},
|
||||
) from e
|
||||
|
||||
if not self.config_entry.data.get(CONF_NAME):
|
||||
|
@ -108,8 +116,18 @@ class HabiticaDataUpdateCoordinator(DataUpdateCoordinator[HabiticaData]):
|
|||
except TooManyRequestsError:
|
||||
_LOGGER.debug("Rate limit exceeded, will try again later")
|
||||
return self.data
|
||||
except (HabiticaException, ClientError) as e:
|
||||
raise UpdateFailed(f"Unable to connect to Habitica: {e}") from e
|
||||
except HabiticaException as e:
|
||||
raise UpdateFailed(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": str(e.error.message)},
|
||||
) from e
|
||||
except ClientError as e:
|
||||
raise UpdateFailed(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": str(e)},
|
||||
) from e
|
||||
else:
|
||||
return HabiticaData(user=user, tasks=tasks + completed_todos)
|
||||
|
||||
|
@ -124,11 +142,19 @@ class HabiticaDataUpdateCoordinator(DataUpdateCoordinator[HabiticaData]):
|
|||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="setup_rate_limit_exception",
|
||||
translation_placeholders={"retry_after": str(e.retry_after)},
|
||||
) from e
|
||||
except (HabiticaException, ClientError) as e:
|
||||
except HabiticaException as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": e.error.message},
|
||||
) from e
|
||||
except ClientError as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": str(e)},
|
||||
) from e
|
||||
else:
|
||||
await self.async_request_refresh()
|
||||
|
|
|
@ -64,9 +64,7 @@ rules:
|
|||
entity-device-class: done
|
||||
entity-disabled-by-default: done
|
||||
entity-translations: done
|
||||
exception-translations:
|
||||
status: todo
|
||||
comment: translations for UpdateFailed missing
|
||||
exception-translations: done
|
||||
icon-translations: done
|
||||
reconfiguration-flow: todo
|
||||
repair-issues:
|
||||
|
|
|
@ -224,6 +224,7 @@ def async_setup_services(hass: HomeAssistant) -> None: # noqa: C901
|
|||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="setup_rate_limit_exception",
|
||||
translation_placeholders={"retry_after": str(e.retry_after)},
|
||||
) from e
|
||||
except NotAuthorizedError as e:
|
||||
raise ServiceValidationError(
|
||||
|
@ -243,10 +244,17 @@ def async_setup_services(hass: HomeAssistant) -> None: # noqa: C901
|
|||
translation_key="skill_not_found",
|
||||
translation_placeholders={"skill": call.data[ATTR_SKILL]},
|
||||
) from e
|
||||
except (HabiticaException, ClientError) as e:
|
||||
except HabiticaException as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": str(e.error.message)},
|
||||
) from e
|
||||
except ClientError as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": str(e)},
|
||||
) from e
|
||||
else:
|
||||
await coordinator.async_request_refresh()
|
||||
|
@ -274,6 +282,7 @@ def async_setup_services(hass: HomeAssistant) -> None: # noqa: C901
|
|||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="setup_rate_limit_exception",
|
||||
translation_placeholders={"retry_after": str(e.retry_after)},
|
||||
) from e
|
||||
except NotAuthorizedError as e:
|
||||
raise ServiceValidationError(
|
||||
|
@ -283,9 +292,17 @@ def async_setup_services(hass: HomeAssistant) -> None: # noqa: C901
|
|||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN, translation_key="quest_not_found"
|
||||
) from e
|
||||
except (HabiticaException, ClientError) as e:
|
||||
except HabiticaException as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN, translation_key="service_call_exception"
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": str(e.error.message)},
|
||||
) from e
|
||||
except ClientError as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": str(e)},
|
||||
) from e
|
||||
else:
|
||||
return asdict(response.data)
|
||||
|
@ -335,6 +352,7 @@ def async_setup_services(hass: HomeAssistant) -> None: # noqa: C901
|
|||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="setup_rate_limit_exception",
|
||||
translation_placeholders={"retry_after": str(e.retry_after)},
|
||||
) from e
|
||||
except NotAuthorizedError as e:
|
||||
if task_value is not None:
|
||||
|
@ -349,11 +367,19 @@ def async_setup_services(hass: HomeAssistant) -> None: # noqa: C901
|
|||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": e.error.message},
|
||||
) from e
|
||||
except (HabiticaException, ClientError) as e:
|
||||
except HabiticaException as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": str(e.error.message)},
|
||||
) from e
|
||||
except ClientError as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": str(e)},
|
||||
) from e
|
||||
else:
|
||||
await coordinator.async_request_refresh()
|
||||
|
@ -382,10 +408,17 @@ def async_setup_services(hass: HomeAssistant) -> None: # noqa: C901
|
|||
translation_domain=DOMAIN,
|
||||
translation_key="party_not_found",
|
||||
) from e
|
||||
except (ClientError, HabiticaException) as e:
|
||||
except HabiticaException as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": str(e.error.message)},
|
||||
) from e
|
||||
except ClientError as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": str(e)},
|
||||
) from e
|
||||
try:
|
||||
target_id = next(
|
||||
|
@ -411,6 +444,7 @@ def async_setup_services(hass: HomeAssistant) -> None: # noqa: C901
|
|||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="setup_rate_limit_exception",
|
||||
translation_placeholders={"retry_after": str(e.retry_after)},
|
||||
) from e
|
||||
except NotAuthorizedError as e:
|
||||
raise ServiceValidationError(
|
||||
|
@ -418,10 +452,17 @@ def async_setup_services(hass: HomeAssistant) -> None: # noqa: C901
|
|||
translation_key="item_not_found",
|
||||
translation_placeholders={"item": call.data[ATTR_ITEM]},
|
||||
) from e
|
||||
except (HabiticaException, ClientError) as e:
|
||||
except HabiticaException as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": str(e.error.message)},
|
||||
) from e
|
||||
except ClientError as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
translation_placeholders={"reason": str(e)},
|
||||
) from e
|
||||
else:
|
||||
return asdict(response.data)
|
||||
|
|
|
@ -375,13 +375,13 @@
|
|||
"message": "Unable to create new to-do `{name}` for Habitica, please try again"
|
||||
},
|
||||
"setup_rate_limit_exception": {
|
||||
"message": "Rate limit exceeded, try again later"
|
||||
"message": "Rate limit exceeded, try again in {retry_after} seconds"
|
||||
},
|
||||
"service_call_unallowed": {
|
||||
"message": "Unable to complete action, the required conditions are not met"
|
||||
},
|
||||
"service_call_exception": {
|
||||
"message": "Unable to connect to Habitica, try again later"
|
||||
"message": "Unable to connect to Habitica: {reason}"
|
||||
},
|
||||
"not_enough_mana": {
|
||||
"message": "Unable to cast skill, not enough mana. Your character has {mana}, but the skill costs {cost}."
|
||||
|
|
|
@ -3,11 +3,18 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from enum import StrEnum
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
from uuid import UUID
|
||||
|
||||
from aiohttp import ClientError
|
||||
from habiticalib import Direction, HabiticaException, Task, TaskType
|
||||
from habiticalib import (
|
||||
Direction,
|
||||
HabiticaException,
|
||||
Task,
|
||||
TaskType,
|
||||
TooManyRequestsError,
|
||||
)
|
||||
|
||||
from homeassistant.components import persistent_notification
|
||||
from homeassistant.components.todo import (
|
||||
|
@ -17,7 +24,7 @@ from homeassistant.components.todo import (
|
|||
TodoListEntityFeature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ServiceValidationError
|
||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||
from homeassistant.helpers.entity import EntityDescription
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
@ -28,6 +35,8 @@ from .entity import HabiticaBase
|
|||
from .types import HabiticaConfigEntry
|
||||
from .util import next_due_date
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
PARALLEL_UPDATES = 1
|
||||
|
||||
|
||||
|
@ -72,7 +81,14 @@ class BaseHabiticaListEntity(HabiticaBase, TodoListEntity):
|
|||
if len(uids) > 1 and self.entity_description.key is HabiticaTodoList.TODOS:
|
||||
try:
|
||||
await self.coordinator.habitica.delete_completed_todos()
|
||||
except TooManyRequestsError as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="setup_rate_limit_exception",
|
||||
translation_placeholders={"retry_after": str(e.retry_after)},
|
||||
) from e
|
||||
except (HabiticaException, ClientError) as e:
|
||||
_LOGGER.debug(str(e))
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="delete_completed_todos_failed",
|
||||
|
@ -81,7 +97,14 @@ class BaseHabiticaListEntity(HabiticaBase, TodoListEntity):
|
|||
for task_id in uids:
|
||||
try:
|
||||
await self.coordinator.habitica.delete_task(UUID(task_id))
|
||||
except TooManyRequestsError as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="setup_rate_limit_exception",
|
||||
translation_placeholders={"retry_after": str(e.retry_after)},
|
||||
) from e
|
||||
except (HabiticaException, ClientError) as e:
|
||||
_LOGGER.debug(str(e))
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key=f"delete_{self.entity_description.key}_failed",
|
||||
|
@ -108,7 +131,14 @@ class BaseHabiticaListEntity(HabiticaBase, TodoListEntity):
|
|||
|
||||
try:
|
||||
await self.coordinator.habitica.reorder_task(UUID(uid), pos)
|
||||
except TooManyRequestsError as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="setup_rate_limit_exception",
|
||||
translation_placeholders={"retry_after": str(e.retry_after)},
|
||||
) from e
|
||||
except (HabiticaException, ClientError) as e:
|
||||
_LOGGER.debug(str(e))
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key=f"move_{self.entity_description.key}_item_failed",
|
||||
|
@ -160,7 +190,14 @@ class BaseHabiticaListEntity(HabiticaBase, TodoListEntity):
|
|||
try:
|
||||
await self.coordinator.habitica.update_task(UUID(item.uid), task)
|
||||
refresh_required = True
|
||||
except TooManyRequestsError as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="setup_rate_limit_exception",
|
||||
translation_placeholders={"retry_after": str(e.retry_after)},
|
||||
) from e
|
||||
except (HabiticaException, ClientError) as e:
|
||||
_LOGGER.debug(str(e))
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key=f"update_{self.entity_description.key}_item_failed",
|
||||
|
@ -187,8 +224,14 @@ class BaseHabiticaListEntity(HabiticaBase, TodoListEntity):
|
|||
refresh_required = True
|
||||
else:
|
||||
score_result = None
|
||||
|
||||
except TooManyRequestsError as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="setup_rate_limit_exception",
|
||||
translation_placeholders={"retry_after": str(e.retry_after)},
|
||||
) from e
|
||||
except (HabiticaException, ClientError) as e:
|
||||
_LOGGER.debug(str(e))
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key=f"score_{self.entity_description.key}_item_failed",
|
||||
|
@ -260,7 +303,14 @@ class HabiticaTodosListEntity(BaseHabiticaListEntity):
|
|||
date=item.due,
|
||||
)
|
||||
)
|
||||
except TooManyRequestsError as e:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="setup_rate_limit_exception",
|
||||
translation_placeholders={"retry_after": str(e.retry_after)},
|
||||
) from e
|
||||
except (HabiticaException, ClientError) as e:
|
||||
_LOGGER.debug(str(e))
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key=f"create_{self.entity_description.key}_item_failed",
|
||||
|
|
|
@ -32,11 +32,13 @@ from homeassistant.core import HomeAssistant
|
|||
|
||||
from tests.common import MockConfigEntry, load_fixture
|
||||
|
||||
ERROR_RESPONSE = HabiticaErrorResponse(success=False, error="error", message="message")
|
||||
ERROR_RESPONSE = HabiticaErrorResponse(success=False, error="error", message="reason")
|
||||
ERROR_NOT_AUTHORIZED = NotAuthorizedError(error=ERROR_RESPONSE, headers={})
|
||||
ERROR_NOT_FOUND = NotFoundError(error=ERROR_RESPONSE, headers={})
|
||||
ERROR_BAD_REQUEST = BadRequestError(error=ERROR_RESPONSE, headers={})
|
||||
ERROR_TOO_MANY_REQUESTS = TooManyRequestsError(error=ERROR_RESPONSE, headers={})
|
||||
ERROR_TOO_MANY_REQUESTS = TooManyRequestsError(
|
||||
error=ERROR_RESPONSE, headers={"retry-after": 5}
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(name="config_entry")
|
||||
|
|
|
@ -4,6 +4,7 @@ from collections.abc import Generator
|
|||
from datetime import timedelta
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from aiohttp import ClientError
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
from habiticalib import HabiticaUserResponse, Skill
|
||||
import pytest
|
||||
|
@ -215,12 +216,12 @@ async def test_button_press(
|
|||
[
|
||||
(
|
||||
ERROR_TOO_MANY_REQUESTS,
|
||||
"Rate limit exceeded, try again later",
|
||||
"Rate limit exceeded, try again in 5 seconds",
|
||||
HomeAssistantError,
|
||||
),
|
||||
(
|
||||
ERROR_BAD_REQUEST,
|
||||
"Unable to connect to Habitica, try again later",
|
||||
"Unable to connect to Habitica: reason",
|
||||
HomeAssistantError,
|
||||
),
|
||||
(
|
||||
|
@ -228,6 +229,11 @@ async def test_button_press(
|
|||
"Unable to complete action, the required conditions are not met",
|
||||
ServiceValidationError,
|
||||
),
|
||||
(
|
||||
ClientError,
|
||||
"Unable to connect to Habitica: ",
|
||||
HomeAssistantError,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_button_press_exceptions(
|
||||
|
|
|
@ -4,6 +4,7 @@ import datetime
|
|||
import logging
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from aiohttp import ClientError
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
|
||||
|
@ -85,11 +86,12 @@ async def test_service_call(
|
|||
|
||||
@pytest.mark.parametrize(
|
||||
("exception"),
|
||||
[
|
||||
ERROR_BAD_REQUEST,
|
||||
ERROR_TOO_MANY_REQUESTS,
|
||||
[ERROR_BAD_REQUEST, ERROR_TOO_MANY_REQUESTS, ClientError],
|
||||
ids=[
|
||||
"BadRequestError",
|
||||
"TooManyRequestsError",
|
||||
"ClientError",
|
||||
],
|
||||
ids=["BadRequestError", "TooManyRequestsError"],
|
||||
)
|
||||
async def test_config_entry_not_ready(
|
||||
hass: HomeAssistant,
|
||||
|
@ -131,14 +133,16 @@ async def test_config_entry_auth_failed(
|
|||
assert flow["context"].get("entry_id") == config_entry.entry_id
|
||||
|
||||
|
||||
@pytest.mark.parametrize("exception", [ERROR_NOT_FOUND, ClientError])
|
||||
async def test_coordinator_update_failed(
|
||||
hass: HomeAssistant,
|
||||
config_entry: MockConfigEntry,
|
||||
habitica: AsyncMock,
|
||||
exception: Exception,
|
||||
) -> None:
|
||||
"""Test coordinator update failed."""
|
||||
|
||||
habitica.get_tasks.side_effect = ERROR_NOT_FOUND
|
||||
habitica.get_tasks.side_effect = exception
|
||||
config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
|
|
@ -5,6 +5,7 @@ from typing import Any
|
|||
from unittest.mock import AsyncMock, patch
|
||||
from uuid import UUID
|
||||
|
||||
from aiohttp import ClientError
|
||||
from habiticalib import Direction, Skill
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
@ -46,8 +47,8 @@ from .conftest import (
|
|||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
REQUEST_EXCEPTION_MSG = "Unable to connect to Habitica, try again later"
|
||||
RATE_LIMIT_EXCEPTION_MSG = "Rate limit exceeded, try again later"
|
||||
REQUEST_EXCEPTION_MSG = "Unable to connect to Habitica: reason"
|
||||
RATE_LIMIT_EXCEPTION_MSG = "Rate limit exceeded, try again in 5 seconds"
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
|
@ -235,6 +236,15 @@ async def test_cast_skill(
|
|||
HomeAssistantError,
|
||||
REQUEST_EXCEPTION_MSG,
|
||||
),
|
||||
(
|
||||
{
|
||||
ATTR_TASK: "Rechnungen bezahlen",
|
||||
ATTR_SKILL: "smash",
|
||||
},
|
||||
ClientError,
|
||||
HomeAssistantError,
|
||||
"Unable to connect to Habitica: ",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_cast_skill_exceptions(
|
||||
|
@ -360,6 +370,11 @@ async def test_handle_quests(
|
|||
HomeAssistantError,
|
||||
REQUEST_EXCEPTION_MSG,
|
||||
),
|
||||
(
|
||||
ClientError,
|
||||
HomeAssistantError,
|
||||
"Unable to connect to Habitica: ",
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
|
@ -520,6 +535,15 @@ async def test_score_task(
|
|||
HomeAssistantError,
|
||||
REQUEST_EXCEPTION_MSG,
|
||||
),
|
||||
(
|
||||
{
|
||||
ATTR_TASK: "e97659e0-2c42-4599-a7bb-00282adc410d",
|
||||
ATTR_DIRECTION: "up",
|
||||
},
|
||||
ClientError,
|
||||
HomeAssistantError,
|
||||
"Unable to connect to Habitica: ",
|
||||
),
|
||||
(
|
||||
{
|
||||
ATTR_TASK: "5e2ea1df-f6e6-4ba3-bccb-97c5ec63e99b",
|
||||
|
@ -722,7 +746,7 @@ async def test_transformation(
|
|||
ERROR_BAD_REQUEST,
|
||||
None,
|
||||
HomeAssistantError,
|
||||
"Unable to connect to Habitica, try again later",
|
||||
REQUEST_EXCEPTION_MSG,
|
||||
),
|
||||
(
|
||||
{
|
||||
|
@ -752,7 +776,27 @@ async def test_transformation(
|
|||
None,
|
||||
ERROR_BAD_REQUEST,
|
||||
HomeAssistantError,
|
||||
"Unable to connect to Habitica, try again later",
|
||||
REQUEST_EXCEPTION_MSG,
|
||||
),
|
||||
(
|
||||
{
|
||||
ATTR_TARGET: "test-partymember-username",
|
||||
ATTR_ITEM: "spooky_sparkles",
|
||||
},
|
||||
None,
|
||||
ClientError,
|
||||
HomeAssistantError,
|
||||
"Unable to connect to Habitica: ",
|
||||
),
|
||||
(
|
||||
{
|
||||
ATTR_TARGET: "test-partymember-username",
|
||||
ATTR_ITEM: "spooky_sparkles",
|
||||
},
|
||||
ClientError,
|
||||
None,
|
||||
HomeAssistantError,
|
||||
"Unable to connect to Habitica: ",
|
||||
),
|
||||
],
|
||||
)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
from collections.abc import Generator
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from aiohttp import ClientError
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
|
@ -96,6 +97,7 @@ async def test_turn_on_off_toggle(
|
|||
[
|
||||
(ERROR_TOO_MANY_REQUESTS, HomeAssistantError),
|
||||
(ERROR_BAD_REQUEST, HomeAssistantError),
|
||||
(ClientError, HomeAssistantError),
|
||||
],
|
||||
)
|
||||
async def test_turn_on_off_toggle_exceptions(
|
||||
|
|
|
@ -23,10 +23,10 @@ from homeassistant.components.todo import (
|
|||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import ATTR_ENTITY_ID, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ServiceValidationError
|
||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from .conftest import ERROR_NOT_FOUND
|
||||
from .conftest import ERROR_NOT_FOUND, ERROR_TOO_MANY_REQUESTS
|
||||
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
|
@ -183,12 +183,30 @@ async def test_uncomplete_todo_item(
|
|||
],
|
||||
ids=["completed", "needs_action"],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("exception", "exc_msg", "expected_exception"),
|
||||
[
|
||||
(
|
||||
ERROR_NOT_FOUND,
|
||||
r"Unable to update the score for your Habitica to-do `.+`, please try again",
|
||||
ServiceValidationError,
|
||||
),
|
||||
(
|
||||
ERROR_TOO_MANY_REQUESTS,
|
||||
"Rate limit exceeded, try again in 5 seconds",
|
||||
HomeAssistantError,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_complete_todo_item_exception(
|
||||
hass: HomeAssistant,
|
||||
config_entry: MockConfigEntry,
|
||||
habitica: AsyncMock,
|
||||
uid: str,
|
||||
status: str,
|
||||
exception: Exception,
|
||||
exc_msg: str,
|
||||
expected_exception: Exception,
|
||||
) -> None:
|
||||
"""Test exception when completing/uncompleting an item on the todo list."""
|
||||
|
||||
|
@ -198,10 +216,10 @@ async def test_complete_todo_item_exception(
|
|||
|
||||
assert config_entry.state is ConfigEntryState.LOADED
|
||||
|
||||
habitica.update_score.side_effect = ERROR_NOT_FOUND
|
||||
habitica.update_score.side_effect = exception
|
||||
with pytest.raises(
|
||||
expected_exception=ServiceValidationError,
|
||||
match=r"Unable to update the score for your Habitica to-do `.+`, please try again",
|
||||
expected_exception=expected_exception,
|
||||
match=exc_msg,
|
||||
):
|
||||
await hass.services.async_call(
|
||||
TODO_DOMAIN,
|
||||
|
@ -311,10 +329,28 @@ async def test_update_todo_item(
|
|||
habitica.update_task.assert_awaited_once_with(*call_args)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("exception", "exc_msg", "expected_exception"),
|
||||
[
|
||||
(
|
||||
ERROR_NOT_FOUND,
|
||||
"Unable to update the Habitica to-do `test-summary`, please try again",
|
||||
ServiceValidationError,
|
||||
),
|
||||
(
|
||||
ERROR_TOO_MANY_REQUESTS,
|
||||
"Rate limit exceeded, try again in 5 seconds",
|
||||
HomeAssistantError,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_update_todo_item_exception(
|
||||
hass: HomeAssistant,
|
||||
config_entry: MockConfigEntry,
|
||||
habitica: AsyncMock,
|
||||
exception: Exception,
|
||||
exc_msg: str,
|
||||
expected_exception: Exception,
|
||||
) -> None:
|
||||
"""Test exception when update item on the todo list."""
|
||||
uid = "88de7cd9-af2b-49ce-9afd-bf941d87336b"
|
||||
|
@ -324,11 +360,8 @@ async def test_update_todo_item_exception(
|
|||
|
||||
assert config_entry.state is ConfigEntryState.LOADED
|
||||
|
||||
habitica.update_task.side_effect = ERROR_NOT_FOUND
|
||||
with pytest.raises(
|
||||
expected_exception=ServiceValidationError,
|
||||
match="Unable to update the Habitica to-do `test-summary`, please try again",
|
||||
):
|
||||
habitica.update_task.side_effect = exception
|
||||
with pytest.raises(expected_exception=expected_exception, match=exc_msg):
|
||||
await hass.services.async_call(
|
||||
TODO_DOMAIN,
|
||||
TodoServices.UPDATE_ITEM,
|
||||
|
@ -378,10 +411,28 @@ async def test_add_todo_item(
|
|||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("exception", "exc_msg", "expected_exception"),
|
||||
[
|
||||
(
|
||||
ERROR_NOT_FOUND,
|
||||
"Unable to create new to-do `test-summary` for Habitica, please try again",
|
||||
ServiceValidationError,
|
||||
),
|
||||
(
|
||||
ERROR_TOO_MANY_REQUESTS,
|
||||
"Rate limit exceeded, try again in 5 seconds",
|
||||
HomeAssistantError,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_add_todo_item_exception(
|
||||
hass: HomeAssistant,
|
||||
config_entry: MockConfigEntry,
|
||||
habitica: AsyncMock,
|
||||
exception: Exception,
|
||||
exc_msg: str,
|
||||
expected_exception: Exception,
|
||||
) -> None:
|
||||
"""Test exception when adding a todo item to the todo list."""
|
||||
|
||||
|
@ -391,10 +442,11 @@ async def test_add_todo_item_exception(
|
|||
|
||||
assert config_entry.state is ConfigEntryState.LOADED
|
||||
|
||||
habitica.create_task.side_effect = ERROR_NOT_FOUND
|
||||
habitica.create_task.side_effect = exception
|
||||
with pytest.raises(
|
||||
expected_exception=ServiceValidationError,
|
||||
match="Unable to create new to-do `test-summary` for Habitica, please try again",
|
||||
expected_exception=expected_exception,
|
||||
# match="Unable to create new to-do `test-summary` for Habitica, please try again",
|
||||
match=exc_msg,
|
||||
):
|
||||
await hass.services.async_call(
|
||||
TODO_DOMAIN,
|
||||
|
@ -434,10 +486,28 @@ async def test_delete_todo_item(
|
|||
habitica.delete_task.assert_awaited_once_with(UUID(uid))
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("exception", "exc_msg", "expected_exception"),
|
||||
[
|
||||
(
|
||||
ERROR_NOT_FOUND,
|
||||
"Unable to delete item from Habitica to-do list, please try again",
|
||||
ServiceValidationError,
|
||||
),
|
||||
(
|
||||
ERROR_TOO_MANY_REQUESTS,
|
||||
"Rate limit exceeded, try again in 5 seconds",
|
||||
HomeAssistantError,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_delete_todo_item_exception(
|
||||
hass: HomeAssistant,
|
||||
config_entry: MockConfigEntry,
|
||||
habitica: AsyncMock,
|
||||
exception: Exception,
|
||||
exc_msg: str,
|
||||
expected_exception: Exception,
|
||||
) -> None:
|
||||
"""Test exception when deleting a todo item from the todo list."""
|
||||
|
||||
|
@ -448,11 +518,11 @@ async def test_delete_todo_item_exception(
|
|||
|
||||
assert config_entry.state is ConfigEntryState.LOADED
|
||||
|
||||
habitica.delete_task.side_effect = ERROR_NOT_FOUND
|
||||
habitica.delete_task.side_effect = exception
|
||||
|
||||
with pytest.raises(
|
||||
expected_exception=ServiceValidationError,
|
||||
match="Unable to delete item from Habitica to-do list, please try again",
|
||||
expected_exception=expected_exception,
|
||||
match=exc_msg,
|
||||
):
|
||||
await hass.services.async_call(
|
||||
TODO_DOMAIN,
|
||||
|
@ -486,10 +556,28 @@ async def test_delete_completed_todo_items(
|
|||
habitica.delete_completed_todos.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("exception", "exc_msg", "expected_exception"),
|
||||
[
|
||||
(
|
||||
ERROR_NOT_FOUND,
|
||||
"Unable to delete completed to-do items from Habitica to-do list, please try again",
|
||||
ServiceValidationError,
|
||||
),
|
||||
(
|
||||
ERROR_TOO_MANY_REQUESTS,
|
||||
"Rate limit exceeded, try again in 5 seconds",
|
||||
HomeAssistantError,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_delete_completed_todo_items_exception(
|
||||
hass: HomeAssistant,
|
||||
config_entry: MockConfigEntry,
|
||||
habitica: AsyncMock,
|
||||
exception: Exception,
|
||||
exc_msg: str,
|
||||
expected_exception: Exception,
|
||||
) -> None:
|
||||
"""Test exception when deleting completed todo items from the todo list."""
|
||||
config_entry.add_to_hass(hass)
|
||||
|
@ -498,10 +586,10 @@ async def test_delete_completed_todo_items_exception(
|
|||
|
||||
assert config_entry.state is ConfigEntryState.LOADED
|
||||
|
||||
habitica.delete_completed_todos.side_effect = ERROR_NOT_FOUND
|
||||
habitica.delete_completed_todos.side_effect = exception
|
||||
with pytest.raises(
|
||||
expected_exception=ServiceValidationError,
|
||||
match="Unable to delete completed to-do items from Habitica to-do list, please try again",
|
||||
expected_exception=expected_exception,
|
||||
match=exc_msg,
|
||||
):
|
||||
await hass.services.async_call(
|
||||
TODO_DOMAIN,
|
||||
|
@ -575,11 +663,26 @@ async def test_move_todo_item(
|
|||
habitica.reorder_task.assert_awaited_once_with(UUID(uid), 0)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("exception", "exc_msg"),
|
||||
[
|
||||
(
|
||||
ERROR_NOT_FOUND,
|
||||
"Unable to move the Habitica to-do to position 0, please try again",
|
||||
),
|
||||
(
|
||||
ERROR_TOO_MANY_REQUESTS,
|
||||
"Rate limit exceeded, try again in 5 seconds",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_move_todo_item_exception(
|
||||
hass: HomeAssistant,
|
||||
config_entry: MockConfigEntry,
|
||||
habitica: AsyncMock,
|
||||
hass_ws_client: WebSocketGenerator,
|
||||
exception: Exception,
|
||||
exc_msg: str,
|
||||
) -> None:
|
||||
"""Test exception when moving todo item."""
|
||||
|
||||
|
@ -590,7 +693,7 @@ async def test_move_todo_item_exception(
|
|||
|
||||
assert config_entry.state is ConfigEntryState.LOADED
|
||||
|
||||
habitica.reorder_task.side_effect = ERROR_NOT_FOUND
|
||||
habitica.reorder_task.side_effect = exception
|
||||
client = await hass_ws_client()
|
||||
|
||||
data = {
|
||||
|
@ -605,10 +708,7 @@ async def test_move_todo_item_exception(
|
|||
habitica.reorder_task.assert_awaited_once_with(UUID(uid), 0)
|
||||
|
||||
assert resp["success"] is False
|
||||
assert (
|
||||
resp["error"]["message"]
|
||||
== "Unable to move the Habitica to-do to position 0, please try again"
|
||||
)
|
||||
assert resp["error"]["message"] == exc_msg
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
|
Loading…
Reference in New Issue