mirror of
https://github.com/home-assistant/core.git
synced 2025-12-20 02:48:57 +00:00
Store unique user configurations for HomeLink integration (#159111)
This commit is contained in:
@@ -5,6 +5,7 @@ from typing import Any
|
||||
|
||||
import botocore.exceptions
|
||||
from homelink.auth.srp_auth import SRPAuth
|
||||
import jwt
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigFlowResult
|
||||
@@ -38,8 +39,6 @@ class SRPFlowHandler(AbstractOAuth2FlowHandler, domain=DOMAIN):
|
||||
"""Ask for username and password."""
|
||||
errors: dict[str, str] = {}
|
||||
if user_input is not None:
|
||||
self._async_abort_entries_match({CONF_EMAIL: user_input[CONF_EMAIL]})
|
||||
|
||||
srp_auth = SRPAuth()
|
||||
try:
|
||||
tokens = await self.hass.async_add_executor_job(
|
||||
@@ -48,12 +47,17 @@ class SRPFlowHandler(AbstractOAuth2FlowHandler, domain=DOMAIN):
|
||||
user_input[CONF_PASSWORD],
|
||||
)
|
||||
except botocore.exceptions.ClientError:
|
||||
_LOGGER.exception("Error authenticating homelink account")
|
||||
errors["base"] = "srp_auth_failed"
|
||||
except Exception:
|
||||
_LOGGER.exception("An unexpected error occurred")
|
||||
errors["base"] = "unknown"
|
||||
else:
|
||||
access_token = jwt.decode(
|
||||
tokens["AuthenticationResult"]["AccessToken"],
|
||||
options={"verify_signature": False},
|
||||
)
|
||||
await self.async_set_unique_id(access_token["sub"])
|
||||
self._abort_if_unique_id_configured()
|
||||
self.external_data = {"tokens": tokens}
|
||||
return await self.async_step_creation()
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
"""Makes requests to the state server and stores the resulting data so that the buttons can access it."""
|
||||
"""Establish MQTT connection and listen for event data."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from functools import partial
|
||||
import logging
|
||||
from typing import TypedDict
|
||||
|
||||
from homelink.model.device import Device
|
||||
@@ -14,8 +13,6 @@ from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.util.ssl import get_default_context
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
type HomeLinkConfigEntry = ConfigEntry[HomeLinkCoordinator]
|
||||
type EventCallback = Callable[[HomeLinkEventData], None]
|
||||
|
||||
|
||||
@@ -3,10 +3,17 @@
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
import jwt
|
||||
|
||||
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
TEST_CREDENTIALS = {CONF_EMAIL: "test@test.com", CONF_PASSWORD: "SomePassword"}
|
||||
|
||||
TEST_ACCESS_JWT = jwt.encode({"sub": "some-uuid"}, key="secret")
|
||||
|
||||
|
||||
async def setup_integration(hass: HomeAssistant, entry: MockConfigEntry) -> None:
|
||||
"""Set up the homelink integration for testing."""
|
||||
|
||||
@@ -9,6 +9,8 @@ import pytest
|
||||
|
||||
from homeassistant.components.gentex_homelink import DOMAIN
|
||||
|
||||
from . import TEST_ACCESS_JWT
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
@@ -21,7 +23,7 @@ def mock_srp_auth() -> Generator[AsyncMock]:
|
||||
instance = mock_srp_auth.return_value
|
||||
instance.async_get_access_token.return_value = {
|
||||
"AuthenticationResult": {
|
||||
"AccessToken": "access",
|
||||
"AccessToken": TEST_ACCESS_JWT,
|
||||
"RefreshToken": "refresh",
|
||||
"TokenType": "bearer",
|
||||
"ExpiresIn": 3600,
|
||||
@@ -60,6 +62,8 @@ def mock_device() -> AsyncMock:
|
||||
def mock_config_entry() -> MockConfigEntry:
|
||||
"""Mock setup entry."""
|
||||
return MockConfigEntry(
|
||||
unique_id="some-uuid",
|
||||
version=1,
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
"auth_implementation": "gentex_homelink",
|
||||
|
||||
@@ -7,10 +7,13 @@ import pytest
|
||||
|
||||
from homeassistant.components.gentex_homelink.const import DOMAIN
|
||||
from homeassistant.config_entries import SOURCE_USER
|
||||
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResultType
|
||||
|
||||
from . import TEST_ACCESS_JWT, TEST_CREDENTIALS, setup_integration
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_full_flow(
|
||||
hass: HomeAssistant, mock_srp_auth: AsyncMock, mock_setup_entry: AsyncMock
|
||||
@@ -26,13 +29,13 @@ async def test_full_flow(
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={CONF_EMAIL: "test@test.com", CONF_PASSWORD: "SomePassword"},
|
||||
user_input=TEST_CREDENTIALS,
|
||||
)
|
||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||
assert result["data"] == {
|
||||
"auth_implementation": "gentex_homelink",
|
||||
"token": {
|
||||
"access_token": "access",
|
||||
"access_token": TEST_ACCESS_JWT,
|
||||
"refresh_token": "refresh",
|
||||
"expires_in": 3600,
|
||||
"token_type": "bearer",
|
||||
@@ -40,6 +43,31 @@ async def test_full_flow(
|
||||
},
|
||||
}
|
||||
assert result["title"] == "SRPAuth"
|
||||
assert result["result"].unique_id == "some-uuid"
|
||||
|
||||
|
||||
async def test_unique_configurations(
|
||||
hass: HomeAssistant,
|
||||
mock_srp_auth: AsyncMock,
|
||||
mock_setup_entry: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Check full flow."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}
|
||||
)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "user"
|
||||
assert not result["errors"]
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input=TEST_CREDENTIALS,
|
||||
)
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -69,7 +97,7 @@ async def test_exceptions(
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={CONF_EMAIL: "test@test.com", CONF_PASSWORD: "SomePassword"},
|
||||
user_input=TEST_CREDENTIALS,
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
@@ -79,6 +107,6 @@ async def test_exceptions(
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={CONF_EMAIL: "test@test.com", CONF_PASSWORD: "SomePassword"},
|
||||
user_input=TEST_CREDENTIALS,
|
||||
)
|
||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||
|
||||
Reference in New Issue
Block a user