Fix missing validation and service definition in Mealie (#121578)

This commit is contained in:
Joost Lekkerkerker 2024-07-09 11:55:12 +02:00 committed by GitHub
parent cfabb778dd
commit a1fae0e0ce
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 65 additions and 9 deletions

View File

@ -1,5 +1,6 @@
{ {
"services": { "services": {
"get_mealplan": "mdi:food" "get_mealplan": "mdi:food",
"get_recipe": "mdi:map"
} }
} }

View File

@ -4,7 +4,7 @@ from dataclasses import asdict
from datetime import date from datetime import date
from typing import cast from typing import cast
from aiomealie.exceptions import MealieNotFoundError from aiomealie.exceptions import MealieConnectionError, MealieNotFoundError
import voluptuous as vol import voluptuous as vol
from homeassistant.config_entries import ConfigEntryState from homeassistant.config_entries import ConfigEntryState
@ -14,7 +14,7 @@ from homeassistant.core import (
ServiceResponse, ServiceResponse,
SupportsResponse, SupportsResponse,
) )
from homeassistant.exceptions import ServiceValidationError from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from .const import ( from .const import (
ATTR_CONFIG_ENTRY_ID, ATTR_CONFIG_ENTRY_ID,
@ -74,7 +74,13 @@ def setup_services(hass: HomeAssistant) -> None:
translation_key="end_date_before_start_date", translation_key="end_date_before_start_date",
) )
client = cast(MealieConfigEntry, entry).runtime_data.client client = cast(MealieConfigEntry, entry).runtime_data.client
mealplans = await client.get_mealplans(start_date, end_date) try:
mealplans = await client.get_mealplans(start_date, end_date)
except MealieConnectionError as err:
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="connection_error",
) from err
return {"mealplan": [asdict(x) for x in mealplans.items]} return {"mealplan": [asdict(x) for x in mealplans.items]}
async def async_get_recipe(call: ServiceCall) -> ServiceResponse: async def async_get_recipe(call: ServiceCall) -> ServiceResponse:
@ -84,6 +90,11 @@ def setup_services(hass: HomeAssistant) -> None:
client = entry.runtime_data.client client = entry.runtime_data.client
try: try:
recipe = await client.get_recipe(recipe_id) recipe = await client.get_recipe(recipe_id)
except MealieConnectionError as err:
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="connection_error",
) from err
except MealieNotFoundError as err: except MealieNotFoundError as err:
raise ServiceValidationError( raise ServiceValidationError(
translation_domain=DOMAIN, translation_domain=DOMAIN,

View File

@ -11,3 +11,14 @@ get_mealplan:
end_date: end_date:
selector: selector:
date: date:
get_recipe:
fields:
config_entry_id:
required: true
selector:
config_entry:
integration: mealie
recipe_id:
required: true
selector:
text:

View File

@ -46,6 +46,9 @@
"end_date_before_start_date": { "end_date_before_start_date": {
"message": "End date must be after start date." "message": "End date must be after start date."
}, },
"connection_error": {
"message": "Error connecting to Mealie instance."
},
"recipe_not_found": { "recipe_not_found": {
"message": "Recipe with ID or slug `{recipe_id}` not found." "message": "Recipe with ID or slug `{recipe_id}` not found."
} }

View File

@ -3,7 +3,7 @@
from datetime import date from datetime import date
from unittest.mock import AsyncMock from unittest.mock import AsyncMock
from aiomealie.exceptions import MealieNotFoundError from aiomealie.exceptions import MealieConnectionError, MealieNotFoundError
from freezegun.api import FrozenDateTimeFactory from freezegun.api import FrozenDateTimeFactory
import pytest import pytest
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
@ -20,7 +20,7 @@ from homeassistant.components.mealie.services import (
SERVICE_GET_RECIPE, SERVICE_GET_RECIPE,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from . import setup_integration from . import setup_integration
@ -136,18 +136,27 @@ async def test_service_recipe(
assert response == snapshot assert response == snapshot
async def test_service_recipe_not_found( @pytest.mark.parametrize(
("exception", "raised_exception"),
[
(MealieNotFoundError, ServiceValidationError),
(MealieConnectionError, HomeAssistantError),
],
)
async def test_service_recipe_exceptions(
hass: HomeAssistant, hass: HomeAssistant,
mock_mealie_client: AsyncMock, mock_mealie_client: AsyncMock,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,
exception: Exception,
raised_exception: type[Exception],
) -> None: ) -> None:
"""Test the get_recipe service.""" """Test the get_recipe service."""
await setup_integration(hass, mock_config_entry) await setup_integration(hass, mock_config_entry)
mock_mealie_client.get_recipe.side_effect = MealieNotFoundError mock_mealie_client.get_recipe.side_effect = exception
with pytest.raises(ServiceValidationError): with pytest.raises(raised_exception):
await hass.services.async_call( await hass.services.async_call(
DOMAIN, DOMAIN,
SERVICE_GET_RECIPE, SERVICE_GET_RECIPE,
@ -160,6 +169,27 @@ async def test_service_recipe_not_found(
) )
async def test_service_mealplan_connection_error(
hass: HomeAssistant,
mock_mealie_client: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test a connection error in the get_mealplans service."""
await setup_integration(hass, mock_config_entry)
mock_mealie_client.get_mealplans.side_effect = MealieConnectionError
with pytest.raises(HomeAssistantError):
await hass.services.async_call(
DOMAIN,
SERVICE_GET_MEALPLAN,
{ATTR_CONFIG_ENTRY_ID: mock_config_entry.entry_id},
blocking=True,
return_response=True,
)
async def test_service_mealplan_without_entry( async def test_service_mealplan_without_entry(
hass: HomeAssistant, hass: HomeAssistant,
mock_config_entry: MockConfigEntry, mock_config_entry: MockConfigEntry,