From d12118a425dd550b392556dbf46e898488a3c66c Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Tue, 8 Mar 2022 11:02:00 +0100 Subject: [PATCH] Fix reauth trigger in SamsungTV (#67850) Co-authored-by: epenet <epenet@users.noreply.github.com> --- homeassistant/components/samsungtv/bridge.py | 17 ++++-- .../components/samsungtv/test_media_player.py | 57 +++++++++++++------ 2 files changed, 52 insertions(+), 22 deletions(-) diff --git a/homeassistant/components/samsungtv/bridge.py b/homeassistant/components/samsungtv/bridge.py index 99e9f877413..62c94e17f4d 100644 --- a/homeassistant/components/samsungtv/bridge.py +++ b/homeassistant/components/samsungtv/bridge.py @@ -14,7 +14,7 @@ from samsungtvws.async_rest import SamsungTVAsyncRest from samsungtvws.command import SamsungTVCommand from samsungtvws.exceptions import ConnectionFailure, HttpApiError from samsungtvws.remote import ChannelEmitCommand, SendRemoteKey -from websockets.exceptions import WebSocketException +from websockets.exceptions import ConnectionClosedError, WebSocketException from homeassistant.const import ( CONF_HOST, @@ -461,15 +461,24 @@ class SamsungTVWSBridge(SamsungTVBridge): ) try: await self._remote.start_listening() - # This is only happening when the auth was switched to DENY - # A removed auth will lead to socket timeout because waiting for auth popup is just an open socket - except ConnectionFailure as err: + except ConnectionClosedError as err: + # This is only happening when the auth was switched to DENY + # A removed auth will lead to socket timeout because waiting + # for auth popup is just an open socket LOGGER.info( "Failed to get remote for %s, re-authentication required: %s", self.host, err.__repr__(), ) self._notify_reauth_callback() + except ConnectionFailure as err: + LOGGER.warning( + "Unexpected ConnectionFailure trying to get remote for %s, " + "please report this issue: %s", + self.host, + err.__repr__(), + ) + self._remote = None except (WebSocketException, AsyncioTimeoutError, OSError) as err: LOGGER.debug( "Failed to get remote for %s: %s", self.host, err.__repr__() diff --git a/tests/components/samsungtv/test_media_player.py b/tests/components/samsungtv/test_media_player.py index e5520098a4a..c38dd2639b1 100644 --- a/tests/components/samsungtv/test_media_player.py +++ b/tests/components/samsungtv/test_media_player.py @@ -10,7 +10,7 @@ from samsungtvws.async_remote import SamsungTVWSAsyncRemote from samsungtvws.command import SamsungTVSleepCommand from samsungtvws.exceptions import ConnectionFailure, HttpApiError from samsungtvws.remote import ChannelEmitCommand, SendRemoteKey -from websockets.exceptions import WebSocketException +from websockets.exceptions import ConnectionClosedError, WebSocketException from homeassistant.components.media_player import MediaPlayerDeviceClass from homeassistant.components.media_player.const import ( @@ -369,27 +369,48 @@ async def test_update_access_denied(hass: HomeAssistant, mock_now: datetime) -> assert state.state == STATE_UNAVAILABLE -async def test_update_connection_failure( +async def test_update_ws_connection_failure( + hass: HomeAssistant, + mock_now: datetime, + remotews: Mock, + caplog: pytest.LogCaptureFixture, +) -> None: + """Testing update tv connection failure exception.""" + await setup_samsungtv(hass, MOCK_CONFIGWS) + + with patch.object( + remotews, + "start_listening", + side_effect=ConnectionFailure('{"event": "ms.voiceApp.hide"}'), + ), 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() + + assert ( + "Unexpected ConnectionFailure trying to get remote for fake_host, please " + 'report this issue: ConnectionFailure(\'{"event": "ms.voiceApp.hide"}\')' + in caplog.text + ) + + state = hass.states.get(ENTITY_ID) + assert state.state == STATE_OFF + + +async def test_update_ws_connection_closed( hass: HomeAssistant, mock_now: datetime, remotews: Mock ) -> None: """Testing update tv connection failure exception.""" - with patch( - "homeassistant.components.samsungtv.bridge.Remote", - side_effect=[OSError("Boom"), DEFAULT_MOCK], - ): - await setup_samsungtv(hass, MOCK_CONFIGWS) + await setup_samsungtv(hass, MOCK_CONFIGWS) - with patch.object( - remotews, "start_listening", side_effect=ConnectionFailure("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() - next_update = mock_now + timedelta(minutes=10) - with patch("homeassistant.util.dt.utcnow", return_value=next_update): - async_fire_time_changed(hass, next_update) - await hass.async_block_till_done() + with patch.object( + remotews, "start_listening", side_effect=ConnectionClosedError(None, None) + ), 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() assert [ flow -- GitLab