From 61e57872c3efe2de9a670fdafb1c61c0acfbb0b1 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 25 May 2023 20:52:44 -0500 Subject: [PATCH] Fix not retrying on connection reset during nexia config entry setup (#93576) * Fix not retrying on connection reset during nexia config entry setup fixes ``` 2023-05-26 00:15:39.129 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry Alexander for nexia Traceback (most recent call last): File "/usr/local/lib/python3.11/site-packages/aiohttp/client.py", line 558, in _request resp = await req.send(conn) ^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/aiohttp/client_reqrep.py", line 670, in send await writer.write_headers(status_line, self.headers) File "/usr/local/lib/python3.11/site-packages/aiohttp/http_writer.py", line 130, in write_headers self._write(buf) File "/usr/local/lib/python3.11/site-packages/aiohttp/http_writer.py", line 75, in _write raise ConnectionResetError("Cannot write to closing transport") ConnectionResetError: Cannot write to closing transport The above exception was the direct cause of the following exception: Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/config_entries.py", line 387, in async_setup result = await component.async_setup_entry(hass, self) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/homeassistant/homeassistant/components/nexia/__init__.py", line 47, in async_setup_entry await nexia_home.login() File "/usr/local/lib/python3.11/site-packages/nexia/home.py", line 385, in login request = await self.post_url(self.API_MOBILE_ACCOUNTS_SIGN_IN_URL, payload) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/nexia/home.py", line 157, in post_url response: aiohttp.ClientResponse = await self.session.post( ^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/aiohttp/client.py", line 572, in _request raise ClientOSError(*exc.args) from exc aiohttp.client_exceptions.ClientOSError: Cannot write to closing transport ``` * coverage --- homeassistant/components/nexia/__init__.py | 4 ++++ tests/components/nexia/test_init.py | 9 +++++++++ tests/components/nexia/util.py | 16 +++++++++++++--- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/nexia/__init__.py b/homeassistant/components/nexia/__init__.py index b221f440ff8..0644de58ee7 100644 --- a/homeassistant/components/nexia/__init__.py +++ b/homeassistant/components/nexia/__init__.py @@ -56,6 +56,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: ) return False raise ConfigEntryNotReady(f"Error from Nexia service: {http_ex}") from http_ex + except aiohttp.ClientOSError as os_error: + raise ConfigEntryNotReady( + f"Error connecting to Nexia service: {os_error}" + ) from os_error coordinator = NexiaDataUpdateCoordinator(hass, nexia_home) await coordinator.async_config_entry_first_refresh() diff --git a/tests/components/nexia/test_init.py b/tests/components/nexia/test_init.py index dd147c4cb21..5409181f00e 100644 --- a/tests/components/nexia/test_init.py +++ b/tests/components/nexia/test_init.py @@ -1,5 +1,8 @@ """The init tests for the nexia platform.""" +import aiohttp + from homeassistant.components.nexia.const import DOMAIN +from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers.entity_registry import EntityRegistry @@ -10,6 +13,12 @@ from .util import async_init_integration from tests.typing import WebSocketGenerator +async def test_setup_retry_client_os_error(hass: HomeAssistant) -> None: + """Verify we retry setup on aiohttp.ClientOSError.""" + config_entry = await async_init_integration(hass, exception=aiohttp.ClientOSError) + assert config_entry.state == ConfigEntryState.SETUP_RETRY + + async def remove_device(ws_client, device_id, config_entry_id): """Remove config entry from a device.""" await ws_client.send_json( diff --git a/tests/components/nexia/util.py b/tests/components/nexia/util.py index d564ccc351c..318a317fae4 100644 --- a/tests/components/nexia/util.py +++ b/tests/components/nexia/util.py @@ -15,6 +15,7 @@ from tests.test_util.aiohttp import mock_aiohttp_client async def async_init_integration( hass: HomeAssistant, skip_setup: bool = False, + exception: Exception | None = None, ) -> MockConfigEntry: """Set up the nexia integration in Home Assistant.""" @@ -25,9 +26,18 @@ async def async_init_integration( "nexia.home.load_or_create_uuid", return_value=uuid.uuid4() ): nexia = NexiaHome(mock_session) - mock_session.post( - nexia.API_MOBILE_SESSION_URL, text=load_fixture(session_fixture) - ) + if exception: + + async def _raise_exception(*args, **kwargs): + raise exception + + mock_session.post( + nexia.API_MOBILE_SESSION_URL, side_effect=_raise_exception + ) + else: + mock_session.post( + nexia.API_MOBILE_SESSION_URL, text=load_fixture(session_fixture) + ) mock_session.get( nexia.API_MOBILE_HOUSES_URL.format(house_id=123456), text=load_fixture(house_fixture),