From 7b8bbc37dff711478c1ef1cb2d175d747e45e2ce Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Tue, 25 Jan 2022 11:11:06 +0100 Subject: [PATCH] Include entity_id in Alexa state report error log (#64898) --- .../components/alexa/state_report.py | 10 +- tests/components/alexa/test_state_report.py | 152 ++++++++++++++++++ 2 files changed, 158 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/alexa/state_report.py b/homeassistant/components/alexa/state_report.py index 78cf50a697e..161ac4072b6 100644 --- a/homeassistant/components/alexa/state_report.py +++ b/homeassistant/components/alexa/state_report.py @@ -150,7 +150,7 @@ async def async_send_changereport_message( ) except (asyncio.TimeoutError, aiohttp.ClientError): - _LOGGER.error("Timeout sending report to Alexa") + _LOGGER.error("Timeout sending report to Alexa for %s", alexa_entity.entity_id) return response_text = await response.text() @@ -177,7 +177,8 @@ async def async_send_changereport_message( await config.set_authorized(False) _LOGGER.error( - "Error when sending ChangeReport to Alexa: %s: %s", + "Error when sending ChangeReport for %s to Alexa: %s: %s", + alexa_entity.entity_id, response_json["payload"]["code"], response_json["payload"]["description"], ) @@ -286,7 +287,7 @@ async def async_send_doorbell_event_message(hass, config, alexa_entity): ) except (asyncio.TimeoutError, aiohttp.ClientError): - _LOGGER.error("Timeout sending report to Alexa") + _LOGGER.error("Timeout sending report to Alexa for %s", alexa_entity.entity_id) return response_text = await response.text() @@ -300,7 +301,8 @@ async def async_send_doorbell_event_message(hass, config, alexa_entity): response_json = json.loads(response_text) _LOGGER.error( - "Error when sending DoorbellPress event to Alexa: %s: %s", + "Error when sending DoorbellPress event for %s to Alexa: %s: %s", + alexa_entity.entity_id, response_json["payload"]["code"], response_json["payload"]["description"], ) diff --git a/tests/components/alexa/test_state_report.py b/tests/components/alexa/test_state_report.py index cbadb8697b8..06c7d051798 100644 --- a/tests/components/alexa/test_state_report.py +++ b/tests/components/alexa/test_state_report.py @@ -1,6 +1,8 @@ """Test report state.""" +import json from unittest.mock import AsyncMock, patch +import aiohttp import pytest from homeassistant import core @@ -43,6 +45,81 @@ async def test_report_state(hass, aioclient_mock): assert call_json["event"]["endpoint"]["endpointId"] == "binary_sensor#test_contact" +async def test_report_state_fail(hass, aioclient_mock, caplog): + """Test proactive state retries once.""" + aioclient_mock.post( + TEST_URL, + text=json.dumps( + { + "payload": { + "code": "THROTTLING_EXCEPTION", + "description": "Request could not be processed due to throttling", + } + } + ), + status=403, + ) + + hass.states.async_set( + "binary_sensor.test_contact", + "on", + {"friendly_name": "Test Contact Sensor", "device_class": "door"}, + ) + + await state_report.async_enable_proactive_mode(hass, get_default_config()) + + hass.states.async_set( + "binary_sensor.test_contact", + "off", + {"friendly_name": "Test Contact Sensor", "device_class": "door"}, + ) + + # To trigger event listener + await hass.async_block_till_done() + + # No retry on errors not related to expired access token + assert len(aioclient_mock.mock_calls) == 1 + + # Check we log the entity id of the failing entity + assert ( + "Error when sending ChangeReport for binary_sensor.test_contact to Alexa: " + "THROTTLING_EXCEPTION: Request could not be processed due to throttling" + ) in caplog.text + + +async def test_report_state_timeout(hass, aioclient_mock, caplog): + """Test proactive state retries once.""" + aioclient_mock.post( + TEST_URL, + exc=aiohttp.ClientError(), + ) + + hass.states.async_set( + "binary_sensor.test_contact", + "on", + {"friendly_name": "Test Contact Sensor", "device_class": "door"}, + ) + + await state_report.async_enable_proactive_mode(hass, get_default_config()) + + hass.states.async_set( + "binary_sensor.test_contact", + "off", + {"friendly_name": "Test Contact Sensor", "device_class": "door"}, + ) + + # To trigger event listener + await hass.async_block_till_done() + + # No retry on errors not related to expired access token + assert len(aioclient_mock.mock_calls) == 1 + + # Check we log the entity id of the failing entity + assert ( + "Timeout sending report to Alexa for binary_sensor.test_contact" in caplog.text + ) + + async def test_report_state_retry(hass, aioclient_mock): """Test proactive state retries once.""" aioclient_mock.post( @@ -309,6 +386,81 @@ async def test_doorbell_event(hass, aioclient_mock): assert len(aioclient_mock.mock_calls) == 2 +async def test_doorbell_event_fail(hass, aioclient_mock, caplog): + """Test proactive state retries once.""" + aioclient_mock.post( + TEST_URL, + text=json.dumps( + { + "payload": { + "code": "THROTTLING_EXCEPTION", + "description": "Request could not be processed due to throttling", + } + } + ), + status=403, + ) + + hass.states.async_set( + "binary_sensor.test_doorbell", + "off", + {"friendly_name": "Test Doorbell Sensor", "device_class": "occupancy"}, + ) + + await state_report.async_enable_proactive_mode(hass, get_default_config()) + + hass.states.async_set( + "binary_sensor.test_doorbell", + "on", + {"friendly_name": "Test Doorbell Sensor", "device_class": "occupancy"}, + ) + + # To trigger event listener + await hass.async_block_till_done() + + # No retry on errors not related to expired access token + assert len(aioclient_mock.mock_calls) == 1 + + # Check we log the entity id of the failing entity + assert ( + "Error when sending DoorbellPress event for binary_sensor.test_doorbell to Alexa: " + "THROTTLING_EXCEPTION: Request could not be processed due to throttling" + ) in caplog.text + + +async def test_doorbell_event_timeout(hass, aioclient_mock, caplog): + """Test proactive state retries once.""" + aioclient_mock.post( + TEST_URL, + exc=aiohttp.ClientError(), + ) + + hass.states.async_set( + "binary_sensor.test_doorbell", + "off", + {"friendly_name": "Test Doorbell Sensor", "device_class": "occupancy"}, + ) + + await state_report.async_enable_proactive_mode(hass, get_default_config()) + + hass.states.async_set( + "binary_sensor.test_doorbell", + "on", + {"friendly_name": "Test Doorbell Sensor", "device_class": "occupancy"}, + ) + + # To trigger event listener + await hass.async_block_till_done() + + # No retry on errors not related to expired access token + assert len(aioclient_mock.mock_calls) == 1 + + # Check we log the entity id of the failing entity + assert ( + "Timeout sending report to Alexa for binary_sensor.test_doorbell" in caplog.text + ) + + async def test_proactive_mode_filter_states(hass, aioclient_mock): """Test all the cases that filter states.""" aioclient_mock.post(TEST_URL, text="", status=202)