Fix HomematicIP Cloud config flow advancing on a rejected PIN (#182601)

This commit is contained in:
Franck Nijhof
2026-09-21 13:30:42 +02:00
committed by GitHub
parent facae81125
commit 37b44a6636
3 changed files with 63 additions and 1 deletions
@@ -105,6 +105,9 @@ class HomematicipAuth:
_LOGGER.debug("Connection request result: %s", result)
except HmipConnectionError:
return None
# a rejected SGTIN or PIN comes back as a failed result, not an exception
if not result.success:
return None
return auth
@@ -1,6 +1,9 @@
"""Tests for HomematicIP Cloud config flow."""
from unittest.mock import patch
from unittest.mock import AsyncMock, patch
from homematicip.connection.connection_context import ConnectionContext
from homematicip.connection.rest_connection import RestResult
from homeassistant import config_entries
from homeassistant.components.homematicip_cloud.const import (
@@ -104,6 +107,37 @@ async def test_flow_init_connection_error(hass: HomeAssistant) -> None:
assert result["errors"] == {"base": "invalid_sgtin_or_pin"}
async def test_flow_init_rejected_pin(
hass: HomeAssistant, simple_mock_auth: AsyncMock
) -> None:
"""Test the flow stays on the first step when the cloud rejects the PIN."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
# the library hands a 400 back as a failed result instead of raising
simple_mock_auth.connection_request.return_value = RestResult(
status=400, text='{"errorCode":"INVALID_PIN"}'
)
with (
patch(
"homeassistant.components.homematicip_cloud.hap.Auth",
return_value=simple_mock_auth,
),
patch(
"homeassistant.components.homematicip_cloud.hap.ConnectionContextBuilder.build_context_async",
return_value=ConnectionContext(),
),
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=DEFAULT_CONFIG
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "init"
assert result["errors"] == {"base": "invalid_sgtin_or_pin"}
async def test_flow_link_connection_error(hass: HomeAssistant) -> None:
"""Test config flow client registration connection error."""
result = await hass.config_entries.flow.async_init(
@@ -5,6 +5,7 @@ from unittest.mock import AsyncMock, MagicMock, Mock, patch
from homematicip.auth import Auth
from homematicip.connection.connection_context import ConnectionContext
from homematicip.connection.rest_connection import RestResult
from homematicip.exceptions.connection_exceptions import (
HmipAuthenticationError,
HmipConnectionError,
@@ -197,6 +198,7 @@ async def test_auth_create(hass: HomeAssistant, simple_mock_auth) -> None:
"""Mock AsyncAuth to execute get_auth."""
config = {HMIPC_HAPID: HAPID, HMIPC_PIN: HAPPIN, HMIPC_NAME: "hmip"}
hmip_auth = HomematicipAuth(hass, config)
simple_mock_auth.connection_request.return_value = RestResult(status=200)
assert hmip_auth
with (
@@ -245,6 +247,29 @@ async def test_auth_create_exception(hass: HomeAssistant, simple_mock_auth) -> N
assert not await hmip_auth.get_auth(hass, HAPID, HAPPIN)
async def test_auth_create_rejected(
hass: HomeAssistant, simple_mock_auth: AsyncMock
) -> None:
"""Test a connection request the cloud rejects does not yield an auth."""
config = {HMIPC_HAPID: HAPID, HMIPC_PIN: HAPPIN, HMIPC_NAME: "hmip"}
hmip_auth = HomematicipAuth(hass, config)
# a wrong or missing PIN is answered with a 400, which the library returns
simple_mock_auth.connection_request.return_value = RestResult(
status=400, text='{"errorCode":"INVALID_PIN"}'
)
with (
patch(
"homeassistant.components.homematicip_cloud.hap.Auth",
return_value=simple_mock_auth,
),
patch(
"homeassistant.components.homematicip_cloud.hap.ConnectionContextBuilder.build_context_async",
return_value=ConnectionContext(),
),
):
assert not await hmip_auth.async_setup()
async def test_get_state_after_disconnect(
hass: HomeAssistant, hmip_config_entry: MockConfigEntry, simple_mock_home
) -> None: