Abort Hue config flow if bridge can not be reached (#88893)

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
Co-authored-by: Franck Nijhof <git@frenck.dev>
This commit is contained in:
Marcel van der Veldt 2023-03-15 18:55:34 +01:00 committed by GitHub
parent 4eee626770
commit fceb208381
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 96 additions and 6 deletions

View file

@ -78,7 +78,13 @@ class HueFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
bridge = await discover_bridge(
host, websession=aiohttp_client.async_get_clientsession(self.hass)
)
except aiohttp.ClientError:
except aiohttp.ClientError as err:
LOGGER.warning(
"Error while attempting to retrieve discovery information, "
"is there a bridge alive on IP %s ?",
host,
exc_info=err,
)
return None
if bridge_id is not None:
bridge_id = normalize_bridge_id(bridge_id)
@ -147,7 +153,9 @@ class HueFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
)
self._async_abort_entries_match({"host": user_input["host"]})
self.bridge = await self._get_bridge(user_input[CONF_HOST])
if (bridge := await self._get_bridge(user_input[CONF_HOST])) is None:
return self.async_abort(reason="cannot_connect")
self.bridge = bridge
return await self.async_step_link()
async def async_step_link(
@ -224,9 +232,12 @@ class HueFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
)
# we need to query the other capabilities too
self.bridge = await self._get_bridge(
bridge = await self._get_bridge(
discovery_info.host, discovery_info.properties["bridgeid"]
)
if bridge is None:
return self.async_abort(reason="cannot_connect")
self.bridge = bridge
return await self.async_step_link()
async def async_step_homekit(
@ -238,7 +249,10 @@ class HueFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
as the unique identifier. Therefore, this method uses discovery without
a unique ID.
"""
self.bridge = await self._get_bridge(discovery_info.host)
bridge = await self._get_bridge(discovery_info.host)
if bridge is None:
return self.async_abort(reason="cannot_connect")
self.bridge = bridge
await self._async_handle_discovery_without_unique_id()
return await self.async_step_link()
@ -254,7 +268,10 @@ class HueFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
# Check if host exists, abort if so.
self._async_abort_entries_match({"host": import_info["host"]})
self.bridge = await self._get_bridge(import_info["host"])
bridge = await self._get_bridge(import_info["host"])
if bridge is None:
return self.async_abort(reason="cannot_connect")
self.bridge = bridge
return await self.async_step_link()

View file

@ -15,7 +15,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from tests.common import MockConfigEntry
from tests.test_util.aiohttp import AiohttpClientMocker
from tests.test_util.aiohttp import AiohttpClientMocker, ClientError
@pytest.fixture(name="hue_setup", autouse=True)
@ -645,3 +645,76 @@ async def test_bridge_zeroconf_ipv6(hass: HomeAssistant) -> None:
assert result["type"] == "abort"
assert result["reason"] == "invalid_host"
async def test_bridge_connection_failed(
hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test that connection errors to the bridge are handled."""
create_mock_api_discovery(aioclient_mock, [])
with patch(
"homeassistant.components.hue.config_flow.discover_bridge",
side_effect=ClientError,
):
result = await hass.config_entries.flow.async_init(
const.DOMAIN, context={"source": config_entries.SOURCE_USER}
)
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={"host": "blah"}
)
# a warning message should have been logged that the bridge could not be reached
assert "Error while attempting to retrieve discovery information" in caplog.text
assert result["type"] == "abort"
assert result["reason"] == "cannot_connect"
# test again with zeroconf discovered wrong bridge IP
result = await hass.config_entries.flow.async_init(
const.DOMAIN,
context={"source": config_entries.SOURCE_ZEROCONF},
data=zeroconf.ZeroconfServiceInfo(
host="blah",
addresses=["1.2.3.4"],
port=443,
hostname="Philips-hue.local",
type="_hue._tcp.local.",
name="Philips Hue - ABCABC._hue._tcp.local.",
properties={
"_raw": {"bridgeid": b"ecb5fafffeabcabc", "modelid": b"BSB002"},
"bridgeid": "ecb5fafffeabcabc",
"modelid": "BSB002",
},
),
)
assert result["type"] == "abort"
assert result["reason"] == "cannot_connect"
# test again with homekit discovered wrong bridge IP
result = await hass.config_entries.flow.async_init(
const.DOMAIN,
context={"source": config_entries.SOURCE_HOMEKIT},
data=zeroconf.ZeroconfServiceInfo(
host="0.0.0.0",
addresses=["0.0.0.0"],
hostname="mock_hostname",
name="mock_name",
port=None,
properties={zeroconf.ATTR_PROPERTIES_ID: "aa:bb:cc:dd:ee:ff"},
type="mock_type",
),
)
assert result["type"] == "abort"
assert result["reason"] == "cannot_connect"
# repeat test with import flow
result = await hass.config_entries.flow.async_init(
const.DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data={"host": "blah"},
)
assert result["type"] == "abort"
assert result["reason"] == "cannot_connect"