From d6c8f3965a0cc044b86ee886b08e77fd0aa54470 Mon Sep 17 00:00:00 2001 From: Allen Porter Date: Wed, 5 Jan 2022 07:17:51 -0800 Subject: [PATCH] Improve nest camera failure handling on removal (#63207) --- homeassistant/components/nest/camera_sdm.py | 7 ++++- tests/components/nest/test_camera_sdm.py | 31 ++++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/nest/camera_sdm.py b/homeassistant/components/nest/camera_sdm.py index 175b2b8958e..31ae302f908 100644 --- a/homeassistant/components/nest/camera_sdm.py +++ b/homeassistant/components/nest/camera_sdm.py @@ -194,7 +194,12 @@ class NestCamera(Camera): """Invalidates the RTSP token when unloaded.""" if self._stream: _LOGGER.debug("Invalidating stream") - await self._stream.stop_rtsp_stream() + try: + await self._stream.stop_rtsp_stream() + except ApiException as err: + _LOGGER.debug( + "Failed to revoke stream token, will rely on ttl: %s", err + ) if self._stream_refresh_unsub: self._stream_refresh_unsub() self._event_id = None diff --git a/tests/components/nest/test_camera_sdm.py b/tests/components/nest/test_camera_sdm.py index 1ac1b4ca6f9..27c1fca4541 100644 --- a/tests/components/nest/test_camera_sdm.py +++ b/tests/components/nest/test_camera_sdm.py @@ -397,7 +397,7 @@ async def test_stream_response_already_expired(hass, auth): async def test_camera_removed(hass, auth): - """Test case where entities are removed and stream tokens expired.""" + """Test case where entities are removed and stream tokens revoked.""" subscriber = await async_setup_camera( hass, DEVICE_TRAITS, @@ -433,6 +433,35 @@ async def test_camera_removed(hass, auth): assert len(hass.states.async_all()) == 0 +async def test_camera_remove_failure(hass, auth): + """Test case where revoking the stream token fails on unload.""" + await async_setup_camera( + hass, + DEVICE_TRAITS, + auth=auth, + ) + + assert len(hass.states.async_all()) == 1 + cam = hass.states.get("camera.my_camera") + assert cam is not None + assert cam.state == STATE_STREAMING + + # Start a stream, exercising cleanup on remove + auth.responses = [ + make_stream_url_response(), + # Stop command will get a failure response + aiohttp.web.Response(status=HTTPStatus.INTERNAL_SERVER_ERROR), + ] + stream_source = await camera.async_get_stream_source(hass, "camera.my_camera") + assert stream_source == "rtsp://some/url?auth=g.0.streamingToken" + + # Unload should succeed even if an RPC fails + for config_entry in hass.config_entries.async_entries(DOMAIN): + await hass.config_entries.async_remove(config_entry.entry_id) + await hass.async_block_till_done() + assert len(hass.states.async_all()) == 0 + + async def test_refresh_expired_stream_failure(hass, auth): """Tests a failure when refreshing the stream.""" now = utcnow()