Handle the correct exception type when subscribing to the router service returns an error in the upnp component (#127006)

* Catch the right exception when handling subscription errors

* Assert device is forced to poll
This commit is contained in:
Steven Looman 2024-10-02 20:55:25 +02:00 committed by GitHub
parent 4c6ab3921a
commit f8b192bd94
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 52 additions and 4 deletions

View File

@ -11,7 +11,7 @@ from urllib.parse import urlparse
from async_upnp_client.aiohttp import AiohttpNotifyServer, AiohttpSessionRequester
from async_upnp_client.client_factory import UpnpFactory
from async_upnp_client.const import AddressTupleVXType
from async_upnp_client.exceptions import UpnpConnectionError
from async_upnp_client.exceptions import UpnpCommunicationError
from async_upnp_client.profiles.igd import IgdDevice, IgdStateItem
from async_upnp_client.utils import async_get_local_ip
from getmac import get_mac_address
@ -206,7 +206,7 @@ class Device:
"""Subscribe to services."""
try:
await self._igd_device.async_subscribe_services(auto_resubscribe=True)
except UpnpConnectionError as ex:
except UpnpCommunicationError as ex:
_LOGGER.debug(
"Error subscribing to services, falling back to forced polling: %s", ex
)
@ -214,7 +214,10 @@ class Device:
async def async_unsubscribe_services(self) -> None:
"""Unsubscribe from services."""
await self._igd_device.async_unsubscribe_services()
try:
await self._igd_device.async_unsubscribe_services()
except UpnpCommunicationError as ex:
_LOGGER.debug("Error unsubscribing to services: %s", ex)
async def async_get_data(
self, entity_description_keys: list[str] | None

View File

@ -7,6 +7,7 @@ import copy
from typing import Any
from unittest.mock import AsyncMock, MagicMock, patch
from async_upnp_client.exceptions import UpnpCommunicationError
from async_upnp_client.profiles.igd import IgdDevice
import pytest
@ -179,7 +180,7 @@ async def test_async_setup_udn_mismatch(
async def test_async_setup_entry_force_poll(
hass: HomeAssistant, mock_igd_device: IgdDevice
) -> None:
"""Test async_setup_entry."""
"""Test async_setup_entry with forced polling."""
entry = MockConfigEntry(
domain=DOMAIN,
unique_id=TEST_USN,
@ -200,3 +201,47 @@ async def test_async_setup_entry_force_poll(
assert await hass.config_entries.async_setup(entry.entry_id) is True
mock_igd_device.async_subscribe_services.assert_not_called()
# Ensure that the device is forced to poll.
mock_igd_device.async_get_traffic_and_status_data.assert_called_with(
None, force_poll=True
)
@pytest.mark.usefixtures(
"ssdp_instant_discovery",
"mock_get_source_ip",
"mock_mac_address_from_host",
)
async def test_async_setup_entry_force_poll_subscribe_error(
hass: HomeAssistant, mock_igd_device: IgdDevice
) -> None:
"""Test async_setup_entry where subscribing fails."""
entry = MockConfigEntry(
domain=DOMAIN,
unique_id=TEST_USN,
data={
CONFIG_ENTRY_ST: TEST_ST,
CONFIG_ENTRY_UDN: TEST_UDN,
CONFIG_ENTRY_ORIGINAL_UDN: TEST_UDN,
CONFIG_ENTRY_LOCATION: TEST_LOCATION,
CONFIG_ENTRY_MAC_ADDRESS: TEST_MAC_ADDRESS,
},
options={
CONFIG_ENTRY_FORCE_POLL: False,
},
)
# Subscribing partially succeeds, but not completely.
# Unsubscribing will fail for the subscribed services afterwards.
mock_igd_device.async_subscribe_services.side_effect = UpnpCommunicationError
mock_igd_device.async_unsubscribe_services.side_effect = UpnpCommunicationError
# Load config_entry, should still be able to load, falling back to polling/the old functionality.
entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(entry.entry_id) is True
# Ensure that the device is forced to poll.
mock_igd_device.async_get_traffic_and_status_data.assert_called_with(
None, force_poll=True
)