From 8f7f3f328e01c798c271dab8b744c7641f339c1c Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Wed, 18 May 2022 19:01:56 +0200 Subject: [PATCH] Suppress Upnp error in SamsungTV resubscribe (#71925) * Suppress Upnp error in SamsungTV resubscribe * Supress UpnpCommunicationError instead * Log resubscribe errors * Add tests * Add exc_info --- .../components/samsungtv/media_player.py | 5 +- .../components/samsungtv/test_media_player.py | 48 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/samsungtv/media_player.py b/homeassistant/components/samsungtv/media_player.py index 0599115774e..423a778011d 100644 --- a/homeassistant/components/samsungtv/media_player.py +++ b/homeassistant/components/samsungtv/media_player.py @@ -12,6 +12,7 @@ from async_upnp_client.client import UpnpDevice, UpnpService, UpnpStateVariable from async_upnp_client.client_factory import UpnpFactory from async_upnp_client.exceptions import ( UpnpActionResponseError, + UpnpCommunicationError, UpnpConnectionError, UpnpError, UpnpResponseError, @@ -309,8 +310,10 @@ class SamsungTVDevice(MediaPlayerEntity): async def _async_resubscribe_dmr(self) -> None: assert self._dmr_device - with contextlib.suppress(UpnpConnectionError): + try: await self._dmr_device.async_subscribe_services(auto_resubscribe=True) + except UpnpCommunicationError as err: + LOGGER.debug("Device rejected re-subscription: %r", err, exc_info=True) async def _async_shutdown_dmr(self) -> None: """Handle removal.""" diff --git a/tests/components/samsungtv/test_media_player.py b/tests/components/samsungtv/test_media_player.py index 56cce6ebfbf..e548822f1d0 100644 --- a/tests/components/samsungtv/test_media_player.py +++ b/tests/components/samsungtv/test_media_player.py @@ -6,6 +6,8 @@ from unittest.mock import DEFAULT as DEFAULT_MOCK, AsyncMock, Mock, call, patch from async_upnp_client.exceptions import ( UpnpActionResponseError, + UpnpCommunicationError, + UpnpConnectionError, UpnpError, UpnpResponseError, ) @@ -1507,3 +1509,49 @@ async def test_upnp_re_subscribe_events( assert state.state == STATE_ON assert dmr_device.async_subscribe_services.call_count == 2 assert dmr_device.async_unsubscribe_services.call_count == 1 + + +@pytest.mark.usefixtures("rest_api", "upnp_notify_server") +@pytest.mark.parametrize( + "error", + {UpnpConnectionError(), UpnpCommunicationError(), UpnpResponseError(status=400)}, +) +async def test_upnp_failed_re_subscribe_events( + hass: HomeAssistant, + remotews: Mock, + dmr_device: Mock, + mock_now: datetime, + caplog: pytest.LogCaptureFixture, + error: Exception, +) -> None: + """Test for Upnp event feedback.""" + await setup_samsungtv_entry(hass, MOCK_ENTRY_WS) + + state = hass.states.get(ENTITY_ID) + assert state.state == STATE_ON + assert dmr_device.async_subscribe_services.call_count == 1 + assert dmr_device.async_unsubscribe_services.call_count == 0 + + with patch.object( + remotews, "start_listening", side_effect=WebSocketException("Boom") + ), patch.object(remotews, "is_alive", return_value=False): + next_update = mock_now + timedelta(minutes=5) + with patch("homeassistant.util.dt.utcnow", return_value=next_update): + async_fire_time_changed(hass, next_update) + await hass.async_block_till_done() + + state = hass.states.get(ENTITY_ID) + assert state.state == STATE_OFF + assert dmr_device.async_subscribe_services.call_count == 1 + assert dmr_device.async_unsubscribe_services.call_count == 1 + + next_update = mock_now + timedelta(minutes=10) + with patch("homeassistant.util.dt.utcnow", return_value=next_update), patch.object( + dmr_device, "async_subscribe_services", side_effect=error + ): + async_fire_time_changed(hass, next_update) + await hass.async_block_till_done() + + state = hass.states.get(ENTITY_ID) + assert state.state == STATE_ON + assert "Device rejected re-subscription" in caplog.text