Test connection in config flow for Husqvarna Automower (#131557)

This commit is contained in:
Thomas55555 2024-11-26 11:06:48 +01:00 committed by GitHub
parent 5f7c7b323e
commit 5da7b1dd05
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 54 additions and 11 deletions

View File

@ -7,6 +7,7 @@ from aioautomower.auth import AbstractAuth
from aioautomower.const import API_BASE_URL from aioautomower.const import API_BASE_URL
from aiohttp import ClientSession from aiohttp import ClientSession
from homeassistant.const import CONF_ACCESS_TOKEN
from homeassistant.helpers import config_entry_oauth2_flow from homeassistant.helpers import config_entry_oauth2_flow
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -28,3 +29,16 @@ class AsyncConfigEntryAuth(AbstractAuth):
"""Return a valid access token.""" """Return a valid access token."""
await self._oauth_session.async_ensure_token_valid() await self._oauth_session.async_ensure_token_valid()
return cast(str, self._oauth_session.token["access_token"]) return cast(str, self._oauth_session.token["access_token"])
class AsyncConfigFlowAuth(AbstractAuth):
"""Provide Automower AbstractAuth for the config flow."""
def __init__(self, websession: ClientSession, token: dict) -> None:
"""Initialize Husqvarna Automower auth."""
super().__init__(websession, API_BASE_URL)
self.token: dict = token
async def async_get_access_token(self) -> str:
"""Return a valid access token."""
return cast(str, self.token[CONF_ACCESS_TOKEN])

View File

@ -4,12 +4,15 @@ from collections.abc import Mapping
import logging import logging
from typing import Any from typing import Any
from aioautomower.session import AutomowerSession
from aioautomower.utils import structure_token from aioautomower.utils import structure_token
from homeassistant.config_entries import SOURCE_REAUTH, ConfigFlowResult from homeassistant.config_entries import SOURCE_REAUTH, ConfigFlowResult
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_NAME, CONF_TOKEN from homeassistant.const import CONF_ACCESS_TOKEN, CONF_NAME, CONF_TOKEN
from homeassistant.helpers import config_entry_oauth2_flow from homeassistant.helpers import aiohttp_client, config_entry_oauth2_flow
from homeassistant.util import dt as dt_util
from .api import AsyncConfigFlowAuth
from .const import DOMAIN, NAME from .const import DOMAIN, NAME
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -46,9 +49,20 @@ class HusqvarnaConfigFlowHandler(
self._abort_if_unique_id_configured() self._abort_if_unique_id_configured()
websession = aiohttp_client.async_get_clientsession(self.hass)
tz = await dt_util.async_get_time_zone(str(dt_util.DEFAULT_TIME_ZONE))
automower_api = AutomowerSession(AsyncConfigFlowAuth(websession, token), tz)
try:
data = await automower_api.get_status()
except Exception: # noqa: BLE001
return self.async_abort(reason="unknown")
if data == {}:
return self.async_abort(reason="no_mower_connected")
structured_token = structure_token(token[CONF_ACCESS_TOKEN]) structured_token = structure_token(token[CONF_ACCESS_TOKEN])
first_name = structured_token.user.first_name first_name = structured_token.user.first_name
last_name = structured_token.user.last_name last_name = structured_token.user.last_name
return self.async_create_entry( return self.async_create_entry(
title=f"{NAME} of {first_name} {last_name}", title=f"{NAME} of {first_name} {last_name}",
data=data, data=data,

View File

@ -27,7 +27,9 @@
"oauth_failed": "[%key:common::config_flow::abort::oauth2_failed%]", "oauth_failed": "[%key:common::config_flow::abort::oauth2_failed%]",
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]", "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]",
"wrong_account": "You can only reauthenticate this entry with the same Husqvarna account.", "wrong_account": "You can only reauthenticate this entry with the same Husqvarna account.",
"missing_amc_scope": "The `Authentication API` and the `Automower Connect API` are not connected to your application in the Husqvarna Developer Portal." "no_mower_connected": "No mowers connected to this account.",
"missing_amc_scope": "The `Authentication API` and the `Automower Connect API` are not connected to your application in the Husqvarna Developer Portal.",
"unknown": "[%key:common::config_flow::error::unknown%]"
}, },
"create_entry": { "create_entry": {
"default": "[%key:common::config_flow::create_entry::authenticated%]" "default": "[%key:common::config_flow::create_entry::authenticated%]"

View File

@ -0,0 +1 @@
{ "data": [] }

View File

@ -2,6 +2,8 @@
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock, patch
from aioautomower.const import API_BASE_URL
from aioautomower.session import AutomowerEndpoint
import pytest import pytest
from homeassistant import config_entries from homeassistant import config_entries
@ -18,16 +20,18 @@ from homeassistant.helpers import config_entry_oauth2_flow
from . import setup_integration from . import setup_integration
from .const import CLIENT_ID, USER_ID from .const import CLIENT_ID, USER_ID
from tests.common import MockConfigEntry from tests.common import MockConfigEntry, load_fixture
from tests.test_util.aiohttp import AiohttpClientMocker from tests.test_util.aiohttp import AiohttpClientMocker
from tests.typing import ClientSessionGenerator from tests.typing import ClientSessionGenerator
@pytest.mark.parametrize( @pytest.mark.parametrize(
("new_scope", "amount"), ("new_scope", "fixture", "exception", "amount"),
[ [
("iam:read amc:api", 1), ("iam:read amc:api", "mower.json", None, 1),
("iam:read", 0), ("iam:read amc:api", "mower.json", Exception, 0),
("iam:read", "mower.json", None, 0),
("iam:read amc:api", "empty.json", None, 0),
], ],
) )
@pytest.mark.usefixtures("current_request_with_host") @pytest.mark.usefixtures("current_request_with_host")
@ -38,6 +42,8 @@ async def test_full_flow(
jwt: str, jwt: str,
new_scope: str, new_scope: str,
amount: int, amount: int,
fixture: str,
exception: Exception | None,
) -> None: ) -> None:
"""Check full flow.""" """Check full flow."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
@ -76,11 +82,17 @@ async def test_full_flow(
"expires_at": 1697753347, "expires_at": 1697753347,
}, },
) )
aioclient_mock.get(
with patch( f"{API_BASE_URL}/{AutomowerEndpoint.mowers}",
text=load_fixture(fixture, DOMAIN),
exc=exception,
)
with (
patch(
"homeassistant.components.husqvarna_automower.async_setup_entry", "homeassistant.components.husqvarna_automower.async_setup_entry",
return_value=True, return_value=True,
) as mock_setup: ) as mock_setup,
):
await hass.config_entries.flow.async_configure(result["flow_id"]) await hass.config_entries.flow.async_configure(result["flow_id"])
assert len(hass.config_entries.async_entries(DOMAIN)) == amount assert len(hass.config_entries.async_entries(DOMAIN)) == amount