Fix radio_id can be unavailable (#92698)

Allow radio_id to be unavailable
This commit is contained in:
Thijs W 2023-05-07 08:59:36 +02:00 committed by GitHub
parent 2c5cad4ca0
commit b22c45ea29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 105 additions and 40 deletions

View File

@ -6,7 +6,12 @@ import logging
from typing import Any from typing import Any
from urllib.parse import urlparse from urllib.parse import urlparse
from afsapi import AFSAPI, ConnectionError as FSConnectionError, InvalidPinException from afsapi import (
AFSAPI,
ConnectionError as FSConnectionError,
InvalidPinException,
NotImplementedException,
)
import voluptuous as vol import voluptuous as vol
from homeassistant import config_entries from homeassistant import config_entries
@ -68,10 +73,11 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
_LOGGER.exception(exception) _LOGGER.exception(exception)
return self.async_abort(reason="unknown") return self.async_abort(reason="unknown")
afsapi = AFSAPI(webfsapi_url, import_info[CONF_PIN])
try: try:
afsapi = AFSAPI(webfsapi_url, import_info[CONF_PIN])
unique_id = await afsapi.get_radio_id() unique_id = await afsapi.get_radio_id()
except NotImplementedException:
unique_id = None # Not all radios have this call implemented
except FSConnectionError: except FSConnectionError:
return self.async_abort(reason="cannot_connect") return self.async_abort(reason="cannot_connect")
except InvalidPinException: except InvalidPinException:
@ -141,14 +147,18 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
_LOGGER.debug(exception) _LOGGER.debug(exception)
return self.async_abort(reason="unknown") return self.async_abort(reason="unknown")
# try to login with default pin
afsapi = AFSAPI(self._webfsapi_url, DEFAULT_PIN)
try: try:
# try to login with default pin await afsapi.get_friendly_name()
afsapi = AFSAPI(self._webfsapi_url, DEFAULT_PIN)
unique_id = await afsapi.get_radio_id()
except InvalidPinException: except InvalidPinException:
return self.async_abort(reason="invalid_auth") return self.async_abort(reason="invalid_auth")
try:
unique_id = await afsapi.get_radio_id()
except NotImplementedException:
unique_id = None
await self.async_set_unique_id(unique_id) await self.async_set_unique_id(unique_id)
self._abort_if_unique_id_configured( self._abort_if_unique_id_configured(
updates={CONF_WEBFSAPI_URL: self._webfsapi_url}, reload_on_update=True updates={CONF_WEBFSAPI_URL: self._webfsapi_url}, reload_on_update=True
@ -175,7 +185,10 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
self.context["title_placeholders"] = {"name": self._name} self.context["title_placeholders"] = {"name": self._name}
unique_id = await afsapi.get_radio_id() try:
unique_id = await afsapi.get_radio_id()
except NotImplementedException:
unique_id = None
await self.async_set_unique_id(unique_id) await self.async_set_unique_id(unique_id)
self._abort_if_unique_id_configured() self._abort_if_unique_id_configured()
@ -240,7 +253,10 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
await self.hass.config_entries.async_reload(self._reauth_entry.entry_id) await self.hass.config_entries.async_reload(self._reauth_entry.entry_id)
return self.async_abort(reason="reauth_successful") return self.async_abort(reason="reauth_successful")
unique_id = await afsapi.get_radio_id() try:
unique_id = await afsapi.get_radio_id()
except NotImplementedException:
unique_id = None
await self.async_set_unique_id(unique_id, raise_on_progress=False) await self.async_set_unique_id(unique_id, raise_on_progress=False)
self._abort_if_unique_id_configured() self._abort_if_unique_id_configured()
return await self._async_create_entry(user_input[CONF_PIN]) return await self._async_create_entry(user_input[CONF_PIN])

View File

@ -1,7 +1,7 @@
"""Test the Frontier Silicon config flow.""" """Test the Frontier Silicon config flow."""
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock, patch
from afsapi import ConnectionError, InvalidPinException from afsapi import ConnectionError, InvalidPinException, NotImplementedException
import pytest import pytest
from homeassistant import config_entries from homeassistant import config_entries
@ -37,19 +37,31 @@ INVALID_MOCK_DISCOVERY = ssdp.SsdpServiceInfo(
) )
async def test_import_success(hass: HomeAssistant) -> None: @pytest.mark.parametrize(
("radio_id_return_value", "radio_id_side_effect"),
[("mock_radio_id", None), (None, NotImplementedException)],
)
async def test_import_success(
hass: HomeAssistant,
radio_id_return_value: str | None,
radio_id_side_effect: Exception | None,
) -> None:
"""Test successful import.""" """Test successful import."""
with patch(
result = await hass.config_entries.flow.async_init( "homeassistant.components.frontier_silicon.config_flow.AFSAPI.get_radio_id",
DOMAIN, return_value=radio_id_return_value,
context={"source": config_entries.SOURCE_IMPORT}, side_effect=radio_id_side_effect,
data={ ):
CONF_HOST: "1.1.1.1", result = await hass.config_entries.flow.async_init(
CONF_PORT: 80, DOMAIN,
CONF_PIN: "1234", context={"source": config_entries.SOURCE_IMPORT},
CONF_NAME: "Test name", data={
}, CONF_HOST: "1.1.1.1",
) CONF_PORT: 80,
CONF_PIN: "1234",
CONF_NAME: "Test name",
},
)
assert result["type"] == FlowResultType.CREATE_ENTRY assert result["type"] == FlowResultType.CREATE_ENTRY
assert result["title"] == "Test name" assert result["title"] == "Test name"
@ -141,8 +153,15 @@ async def test_import_already_exists(
assert result["reason"] == "already_configured" assert result["reason"] == "already_configured"
@pytest.mark.parametrize(
("radio_id_return_value", "radio_id_side_effect"),
[("mock_radio_id", None), (None, NotImplementedException)],
)
async def test_form_default_pin( async def test_form_default_pin(
hass: HomeAssistant, mock_setup_entry: AsyncMock hass: HomeAssistant,
mock_setup_entry: AsyncMock,
radio_id_return_value: str | None,
radio_id_side_effect: Exception | None,
) -> None: ) -> None:
"""Test manual device add with default pin.""" """Test manual device add with default pin."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
@ -152,10 +171,15 @@ async def test_form_default_pin(
assert result["step_id"] == "user" assert result["step_id"] == "user"
assert result["errors"] == {} assert result["errors"] == {}
result2 = await hass.config_entries.flow.async_configure( with patch(
result["flow_id"], "homeassistant.components.frontier_silicon.config_flow.AFSAPI.get_radio_id",
{CONF_HOST: "1.1.1.1", CONF_PORT: 80}, return_value=radio_id_return_value,
) side_effect=radio_id_side_effect,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_HOST: "1.1.1.1", CONF_PORT: 80},
)
await hass.async_block_till_done() await hass.async_block_till_done()
assert result2["type"] == FlowResultType.CREATE_ENTRY assert result2["type"] == FlowResultType.CREATE_ENTRY
@ -167,8 +191,15 @@ async def test_form_default_pin(
mock_setup_entry.assert_called_once() mock_setup_entry.assert_called_once()
@pytest.mark.parametrize(
("radio_id_return_value", "radio_id_side_effect"),
[("mock_radio_id", None), (None, NotImplementedException)],
)
async def test_form_nondefault_pin( async def test_form_nondefault_pin(
hass: HomeAssistant, mock_setup_entry: AsyncMock hass: HomeAssistant,
mock_setup_entry: AsyncMock,
radio_id_return_value: str | None,
radio_id_side_effect: Exception | None,
) -> None: ) -> None:
"""Test we get the form.""" """Test we get the form."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
@ -192,10 +223,15 @@ async def test_form_nondefault_pin(
assert result2["step_id"] == "device_config" assert result2["step_id"] == "device_config"
assert result2["errors"] is None assert result2["errors"] is None
result3 = await hass.config_entries.flow.async_configure( with patch(
result2["flow_id"], "homeassistant.components.frontier_silicon.config_flow.AFSAPI.get_radio_id",
{CONF_PIN: "4321"}, return_value=radio_id_return_value,
) side_effect=radio_id_side_effect,
):
result3 = await hass.config_entries.flow.async_configure(
result2["flow_id"],
{CONF_PIN: "4321"},
)
await hass.async_block_till_done() await hass.async_block_till_done()
assert result3["type"] == FlowResultType.CREATE_ENTRY assert result3["type"] == FlowResultType.CREATE_ENTRY
@ -322,14 +358,27 @@ async def test_invalid_device_url(
mock_setup_entry.assert_called_once() mock_setup_entry.assert_called_once()
async def test_ssdp(hass: HomeAssistant, mock_setup_entry: MockConfigEntry) -> None: @pytest.mark.parametrize(
("radio_id_return_value", "radio_id_side_effect"),
[("mock_radio_id", None), (None, NotImplementedException)],
)
async def test_ssdp(
hass: HomeAssistant,
mock_setup_entry: MockConfigEntry,
radio_id_return_value: str | None,
radio_id_side_effect: Exception | None,
) -> None:
"""Test a device being discovered.""" """Test a device being discovered."""
with patch(
result = await hass.config_entries.flow.async_init( "homeassistant.components.frontier_silicon.config_flow.AFSAPI.get_radio_id",
DOMAIN, return_value=radio_id_return_value,
context={"source": config_entries.SOURCE_SSDP}, side_effect=radio_id_side_effect,
data=MOCK_DISCOVERY, ):
) result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_SSDP},
data=MOCK_DISCOVERY,
)
assert result["type"] == FlowResultType.FORM assert result["type"] == FlowResultType.FORM
assert result["step_id"] == "confirm" assert result["step_id"] == "confirm"
@ -404,7 +453,7 @@ async def test_ssdp_nondefault_pin(hass: HomeAssistant) -> None:
"""Test a device being discovered.""" """Test a device being discovered."""
with patch( with patch(
"homeassistant.components.frontier_silicon.config_flow.AFSAPI.get_radio_id", "homeassistant.components.frontier_silicon.config_flow.AFSAPI.get_friendly_name",
side_effect=InvalidPinException, side_effect=InvalidPinException,
): ):
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(