Mealie min version check (#121677)

This commit is contained in:
Andrew Jackson 2024-07-10 20:25:49 +01:00 committed by GitHub
parent 71e5ffb2bd
commit a9c9963f0f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 126 additions and 11 deletions

View File

@ -12,7 +12,7 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.helpers.typing import ConfigType
from .const import DOMAIN
from .const import DOMAIN, MIN_REQUIRED_MEALIE_VERSION
from .coordinator import (
MealieConfigEntry,
MealieData,
@ -20,6 +20,7 @@ from .coordinator import (
MealieShoppingListCoordinator,
)
from .services import setup_services
from .utils import create_version
PLATFORMS: list[Platform] = [Platform.CALENDAR, Platform.TODO]
@ -41,11 +42,22 @@ async def async_setup_entry(hass: HomeAssistant, entry: MealieConfigEntry) -> bo
)
try:
about = await client.get_about()
version = create_version(about.version)
except MealieAuthenticationError as error:
raise ConfigEntryError("Authentication failed") from error
except MealieConnectionError as error:
raise ConfigEntryNotReady(error) from error
if not version.valid or version < MIN_REQUIRED_MEALIE_VERSION:
raise ConfigEntryError(
translation_domain=DOMAIN,
translation_key="version_error",
translation_placeholders={
"mealie_version": about.version,
"min_version": MIN_REQUIRED_MEALIE_VERSION,
},
)
assert entry.unique_id
device_registry = dr.async_get(hass)
device_registry.async_get_or_create(

View File

@ -9,7 +9,8 @@ from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_API_TOKEN, CONF_HOST
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import DOMAIN, LOGGER
from .const import DOMAIN, LOGGER, MIN_REQUIRED_MEALIE_VERSION
from .utils import create_version
SCHEMA = vol.Schema(
{
@ -35,6 +36,8 @@ class MealieConfigFlow(ConfigFlow, domain=DOMAIN):
)
try:
info = await client.get_user_info()
about = await client.get_about()
version = create_version(about.version)
except MealieConnectionError:
errors["base"] = "cannot_connect"
except MealieAuthenticationError:
@ -43,12 +46,15 @@ class MealieConfigFlow(ConfigFlow, domain=DOMAIN):
LOGGER.exception("Unexpected error")
errors["base"] = "unknown"
else:
await self.async_set_unique_id(info.user_id)
self._abort_if_unique_id_configured()
return self.async_create_entry(
title="Mealie",
data=user_input,
)
if not version.valid or version < MIN_REQUIRED_MEALIE_VERSION:
errors["base"] = "mealie_version"
else:
await self.async_set_unique_id(info.user_id)
self._abort_if_unique_id_configured()
return self.async_create_entry(
title="Mealie",
data=user_input,
)
return self.async_show_form(
step_id="user",
data_schema=SCHEMA,

View File

@ -2,6 +2,8 @@
import logging
from awesomeversion import AwesomeVersion
DOMAIN = "mealie"
LOGGER = logging.getLogger(__package__)
@ -12,3 +14,5 @@ ATTR_END_DATE = "end_date"
ATTR_RECIPE_ID = "recipe_id"
ATTR_URL = "url"
ATTR_INCLUDE_TAGS = "include_tags"
MIN_REQUIRED_MEALIE_VERSION = AwesomeVersion("v1.0.0")

View File

@ -14,7 +14,8 @@
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
"unknown": "[%key:common::config_flow::error::unknown%]"
"unknown": "[%key:common::config_flow::error::unknown%]",
"mealie_version": "Minimum required version is v1.0.0. Please upgrade Mealie and then retry."
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_service%]"
@ -66,6 +67,9 @@
},
"item_not_found_error": {
"message": "Item {shopping_list_item} not found."
},
"version_error": {
"message": "You are running {mealie_version} of Mealie. Minimum required version is {min_version}. Please upgrade Mealie and then retry."
}
},
"services": {

View File

@ -0,0 +1,10 @@
"""Mealie util functions."""
from __future__ import annotations
from awesomeversion import AwesomeVersion
def create_version(version: str) -> AwesomeVersion:
"""Convert beta versions to PEP440."""
return AwesomeVersion(version.replace("beta-", "b"))

View File

@ -2,7 +2,7 @@
from unittest.mock import AsyncMock
from aiomealie import MealieAuthenticationError, MealieConnectionError
from aiomealie import About, MealieAuthenticationError, MealieConnectionError
import pytest
from homeassistant.components.mealie.const import DOMAIN
@ -83,6 +83,40 @@ async def test_flow_errors(
assert result["type"] is FlowResultType.CREATE_ENTRY
@pytest.mark.parametrize(
("version"),
[
("v1.0.0beta-5"),
("v1.0.0-RC2"),
("v0.1.0"),
("something"),
],
)
async def test_flow_version_error(
hass: HomeAssistant,
mock_mealie_client: AsyncMock,
mock_setup_entry: AsyncMock,
version,
) -> None:
"""Test flow version error."""
mock_mealie_client.get_about.return_value = About(version=version)
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_USER},
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_HOST: "demo.mealie.io", CONF_API_TOKEN: "token"},
)
assert result["type"] is FlowResultType.FORM
assert result["errors"] == {"base": "mealie_version"}
async def test_duplicate(
hass: HomeAssistant,
mock_mealie_client: AsyncMock,

View File

@ -2,7 +2,7 @@
from unittest.mock import AsyncMock
from aiomealie import MealieAuthenticationError, MealieConnectionError
from aiomealie import About, MealieAuthenticationError, MealieConnectionError
import pytest
from syrupy import SnapshotAssertion
@ -32,6 +32,51 @@ async def test_device_info(
assert device_entry == snapshot
@pytest.mark.parametrize(
("exc", "state"),
[
(MealieConnectionError, ConfigEntryState.SETUP_RETRY),
(MealieAuthenticationError, ConfigEntryState.SETUP_ERROR),
],
)
async def test_setup_failure(
hass: HomeAssistant,
mock_mealie_client: AsyncMock,
mock_config_entry: MockConfigEntry,
exc: Exception,
state: ConfigEntryState,
) -> None:
"""Test setup failure."""
mock_mealie_client.get_about.side_effect = exc
await setup_integration(hass, mock_config_entry)
assert mock_config_entry.state is state
@pytest.mark.parametrize(
("version"),
[
("v1.0.0beta-5"),
("v1.0.0-RC2"),
("v0.1.0"),
("something"),
],
)
async def test_setup_too_old(
hass: HomeAssistant,
mock_mealie_client: AsyncMock,
mock_config_entry: MockConfigEntry,
version,
) -> None:
"""Test setup of Mealie entry with too old version of Mealie."""
mock_mealie_client.get_about.return_value = About(version=version)
await setup_integration(hass, mock_config_entry)
assert mock_config_entry.state is ConfigEntryState.SETUP_ERROR
async def test_load_unload_entry(
hass: HomeAssistant,
mock_mealie_client: AsyncMock,