From c6ff79aa0e4d58503cbbecae8635da7382d883cf Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 22 Feb 2023 14:58:11 -0500 Subject: [PATCH] Error checking for OTBR (#88620) * Error checking for OTBR * Other errors in flow too * Tests --- homeassistant/components/otbr/__init__.py | 10 +++++-- homeassistant/components/otbr/config_flow.py | 8 ++++- tests/components/otbr/test_config_flow.py | 31 ++++++++++++++++++++ tests/components/otbr/test_init.py | 20 +++++++++---- 4 files changed, 60 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/otbr/__init__.py b/homeassistant/components/otbr/__init__.py index 19eaa55f00e..ebe2ab00257 100644 --- a/homeassistant/components/otbr/__init__.py +++ b/homeassistant/components/otbr/__init__.py @@ -1,11 +1,13 @@ """The Open Thread Border Router integration.""" from __future__ import annotations +import asyncio from collections.abc import Callable, Coroutine import dataclasses from functools import wraps from typing import Any, Concatenate, ParamSpec, TypeVar +import aiohttp import python_otbr_api from homeassistant.components.thread import async_add_dataset @@ -63,8 +65,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: otbrdata = OTBRData(entry.data["url"], api) try: dataset = await otbrdata.get_active_dataset_tlvs() - except HomeAssistantError as err: - raise ConfigEntryNotReady from err + except ( + HomeAssistantError, + aiohttp.ClientError, + asyncio.TimeoutError, + ) as err: + raise ConfigEntryNotReady("Unable to connect") from err if dataset: await async_add_dataset(hass, entry.title, dataset.hex()) diff --git a/homeassistant/components/otbr/config_flow.py b/homeassistant/components/otbr/config_flow.py index 1d54084969b..00aae5b8a07 100644 --- a/homeassistant/components/otbr/config_flow.py +++ b/homeassistant/components/otbr/config_flow.py @@ -1,8 +1,10 @@ """Config flow for the Open Thread Border Router integration.""" from __future__ import annotations +import asyncio import logging +import aiohttp import python_otbr_api import voluptuous as vol @@ -48,7 +50,11 @@ class OTBRConfigFlow(ConfigFlow, domain=DOMAIN): url = user_input[CONF_URL] try: await self._connect_and_create_dataset(url) - except python_otbr_api.OTBRError: + except ( + python_otbr_api.OTBRError, + aiohttp.ClientError, + asyncio.TimeoutError, + ): errors["base"] = "cannot_connect" else: await self.async_set_unique_id(DOMAIN) diff --git a/tests/components/otbr/test_config_flow.py b/tests/components/otbr/test_config_flow.py index 918d1504653..a3cdefe2b75 100644 --- a/tests/components/otbr/test_config_flow.py +++ b/tests/components/otbr/test_config_flow.py @@ -1,8 +1,11 @@ """Test the Open Thread Border Router config flow.""" +import asyncio from http import HTTPStatus from unittest.mock import patch +import aiohttp import pytest +import python_otbr_api from homeassistant.components import hassio, otbr from homeassistant.core import HomeAssistant @@ -137,6 +140,34 @@ async def test_user_flow_404( assert result["errors"] == {"base": "cannot_connect"} +@pytest.mark.parametrize( + "error", + [ + asyncio.TimeoutError, + python_otbr_api.OTBRError, + aiohttp.ClientError, + ], +) +async def test_user_flow_connect_error(hass: HomeAssistant, error) -> None: + """Test the user flow.""" + result = await hass.config_entries.flow.async_init( + otbr.DOMAIN, context={"source": "user"} + ) + + assert result["type"] == FlowResultType.FORM + assert result["errors"] == {} + + with patch("python_otbr_api.OTBR.get_active_dataset_tlvs", side_effect=error): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + "url": "http://custom_url:1234", + }, + ) + assert result["type"] == FlowResultType.FORM + assert result["errors"] == {"base": "cannot_connect"} + + async def test_hassio_discovery_flow( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker ) -> None: diff --git a/tests/components/otbr/test_init.py b/tests/components/otbr/test_init.py index 10affab0786..7818d736e0e 100644 --- a/tests/components/otbr/test_init.py +++ b/tests/components/otbr/test_init.py @@ -1,9 +1,11 @@ """Test the Open Thread Border Router integration.""" - +import asyncio from http import HTTPStatus from unittest.mock import patch +import aiohttp import pytest +import python_otbr_api from homeassistant.components import otbr from homeassistant.core import HomeAssistant @@ -35,9 +37,15 @@ async def test_import_dataset(hass: HomeAssistant) -> None: mock_add.assert_called_once_with(config_entry.title, DATASET.hex()) -async def test_config_entry_not_ready( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker -) -> None: +@pytest.mark.parametrize( + "error", + [ + asyncio.TimeoutError, + python_otbr_api.OTBRError, + aiohttp.ClientError, + ], +) +async def test_config_entry_not_ready(hass: HomeAssistant, error) -> None: """Test raising ConfigEntryNotReady .""" config_entry = MockConfigEntry( @@ -47,8 +55,8 @@ async def test_config_entry_not_ready( title="My OTBR", ) config_entry.add_to_hass(hass) - aioclient_mock.get(f"{BASE_URL}/node/dataset/active", status=HTTPStatus.CREATED) - assert not await hass.config_entries.async_setup(config_entry.entry_id) + with patch("python_otbr_api.OTBR.get_active_dataset_tlvs", side_effect=error): + assert not await hass.config_entries.async_setup(config_entry.entry_id) async def test_remove_entry(