mirror of
https://github.com/home-assistant/core.git
synced 2025-07-29 08:07:45 +00:00
Handle router initialization, connection errors, and missing interfaces in options flow (#143475)
* Handle router initialization and connection errors in options flow Added checks in the Keenetic NDMS2 options flow to handle cases where the integration is not initialized or there are connection errors. Relevant user feedback and abort reasons are now provided to ensure a better user experience. * Add filtering saved/default options for interfaces before preparing an options form
This commit is contained in:
parent
c671ff3cf1
commit
6641cb3799
@ -146,17 +146,27 @@ class KeeneticOptionsFlowHandler(OptionsFlow):
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Manage the options."""
|
||||
if (
|
||||
not hasattr(self.config_entry, "runtime_data")
|
||||
or not self.config_entry.runtime_data
|
||||
):
|
||||
return self.async_abort(reason="not_initialized")
|
||||
|
||||
router = self.config_entry.runtime_data
|
||||
|
||||
interfaces: list[InterfaceInfo] = await self.hass.async_add_executor_job(
|
||||
router.client.get_interfaces
|
||||
)
|
||||
try:
|
||||
interfaces: list[InterfaceInfo] = await self.hass.async_add_executor_job(
|
||||
router.client.get_interfaces
|
||||
)
|
||||
except ConnectionException:
|
||||
return self.async_abort(reason="cannot_connect")
|
||||
|
||||
self._interface_options = {
|
||||
interface.name: (interface.description or interface.name)
|
||||
for interface in interfaces
|
||||
if interface.type.lower() == "bridge"
|
||||
}
|
||||
|
||||
return await self.async_step_user()
|
||||
|
||||
async def async_step_user(
|
||||
@ -182,9 +192,13 @@ class KeeneticOptionsFlowHandler(OptionsFlow):
|
||||
): int,
|
||||
vol.Required(
|
||||
CONF_INTERFACES,
|
||||
default=self.config_entry.options.get(
|
||||
CONF_INTERFACES, [DEFAULT_INTERFACE]
|
||||
),
|
||||
default=[
|
||||
item
|
||||
for item in self.config_entry.options.get(
|
||||
CONF_INTERFACES, [DEFAULT_INTERFACE]
|
||||
)
|
||||
if item in self._interface_options
|
||||
],
|
||||
): cv.multi_select(self._interface_options),
|
||||
vol.Optional(
|
||||
CONF_TRY_HOTSPOT,
|
||||
|
@ -36,6 +36,10 @@
|
||||
"include_associated": "Use Wi-Fi AP associations data (ignored if hotspot data used)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"not_initialized": "The integration is not initialized yet. Can't display available options."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,10 +6,11 @@ from unittest.mock import Mock, patch
|
||||
from ndms2_client import ConnectionException
|
||||
from ndms2_client.client import InterfaceInfo, RouterInfo
|
||||
import pytest
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components import keenetic_ndms2 as keenetic
|
||||
from homeassistant.components.keenetic_ndms2 import const
|
||||
from homeassistant.components.keenetic_ndms2 import CONF_INTERFACES, const
|
||||
from homeassistant.const import CONF_HOST, CONF_SOURCE
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResultType
|
||||
@ -145,6 +146,70 @@ async def test_connection_error(hass: HomeAssistant, connect_error) -> None:
|
||||
assert result["errors"] == {"base": "cannot_connect"}
|
||||
|
||||
|
||||
async def test_options_not_initialized(hass: HomeAssistant) -> None:
|
||||
"""Test the error when the integration is not initialized."""
|
||||
|
||||
entry = MockConfigEntry(domain=keenetic.DOMAIN, data=MOCK_DATA)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
# not setting entry.runtime_data
|
||||
|
||||
result = await hass.config_entries.options.async_init(entry.entry_id)
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "not_initialized"
|
||||
|
||||
|
||||
async def test_options_connection_error(hass: HomeAssistant) -> None:
|
||||
"""Test updating options."""
|
||||
|
||||
entry = MockConfigEntry(domain=keenetic.DOMAIN, data=MOCK_DATA)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
def get_interfaces_error():
|
||||
raise ConnectionException("Mocked failure")
|
||||
|
||||
# fake with connection error
|
||||
entry.runtime_data = Mock(
|
||||
client=Mock(get_interfaces=Mock(wraps=get_interfaces_error))
|
||||
)
|
||||
|
||||
result = await hass.config_entries.options.async_init(entry.entry_id)
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "cannot_connect"
|
||||
|
||||
|
||||
async def test_options_interface_filter(hass: HomeAssistant) -> None:
|
||||
"""Test the case when the default Home interface is missing on the router."""
|
||||
|
||||
entry = MockConfigEntry(domain=keenetic.DOMAIN, data=MOCK_DATA)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
# fake interfaces
|
||||
entry.runtime_data = Mock(
|
||||
client=Mock(
|
||||
get_interfaces=Mock(
|
||||
return_value=[
|
||||
InterfaceInfo.from_dict({"id": name, "type": "bridge"})
|
||||
for name in ("not_a_home", "also_not_home")
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
result = await hass.config_entries.options.async_init(entry.entry_id)
|
||||
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
interfaces_schema = next(
|
||||
i
|
||||
for i, s in result["data_schema"].schema.items()
|
||||
if i.schema == CONF_INTERFACES
|
||||
)
|
||||
assert isinstance(interfaces_schema, vol.Required)
|
||||
assert interfaces_schema.default() == []
|
||||
|
||||
|
||||
async def test_ssdp_works(hass: HomeAssistant, connect) -> None:
|
||||
"""Test host already configured and discovered."""
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user