Fix mqtt callback exception logging (#118138)

* Fix mqtt callback exception logging

* Improve code

* Add test
This commit is contained in:
Jan Bouwhuis 2024-05-25 22:46:33 +02:00 committed by GitHub
parent 569763b7a8
commit 521ed0a220
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 43 additions and 3 deletions

View File

@ -835,8 +835,13 @@ class MQTT:
msg: ReceiveMessage, msg: ReceiveMessage,
) -> str: ) -> str:
"""Return a string with the exception message.""" """Return a string with the exception message."""
# if msg_callback is a partial we return the name of the first argument
if isinstance(msg_callback, partial):
call_back_name = getattr(msg_callback.args[0], "__name__") # type: ignore[unreachable]
else:
call_back_name = getattr(msg_callback, "__name__")
return ( return (
f"Exception in {msg_callback.__name__} when handling msg on " f"Exception in {call_back_name} when handling msg on "
f"'{msg.topic}': '{msg.payload}'" # type: ignore[str-bytes-safe] f"'{msg.topic}': '{msg.payload}'" # type: ignore[str-bytes-safe]
) )

View File

@ -4,6 +4,7 @@ import asyncio
from collections.abc import Generator from collections.abc import Generator
from copy import deepcopy from copy import deepcopy
from datetime import datetime, timedelta from datetime import datetime, timedelta
from functools import partial
import json import json
import logging import logging
import socket import socket
@ -2912,8 +2913,8 @@ async def test_message_callback_exception_gets_logged(
await mqtt_mock_entry() await mqtt_mock_entry()
@callback @callback
def bad_handler(*args) -> None: def bad_handler(msg: ReceiveMessage) -> None:
"""Record calls.""" """Handle callback."""
raise ValueError("This is a bad message callback") raise ValueError("This is a bad message callback")
await mqtt.async_subscribe(hass, "test-topic", bad_handler) await mqtt.async_subscribe(hass, "test-topic", bad_handler)
@ -2926,6 +2927,40 @@ async def test_message_callback_exception_gets_logged(
) )
@pytest.mark.no_fail_on_log_exception
async def test_message_partial_callback_exception_gets_logged(
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
mqtt_mock_entry: MqttMockHAClientGenerator,
) -> None:
"""Test exception raised by message handler."""
await mqtt_mock_entry()
@callback
def bad_handler(msg: ReceiveMessage) -> None:
"""Handle callback."""
raise ValueError("This is a bad message callback")
def parial_handler(
msg_callback: MessageCallbackType,
attributes: set[str],
msg: ReceiveMessage,
) -> None:
"""Partial callback handler."""
msg_callback(msg)
await mqtt.async_subscribe(
hass, "test-topic", partial(parial_handler, bad_handler, {"some_attr"})
)
async_fire_mqtt_message(hass, "test-topic", "test")
await hass.async_block_till_done()
assert (
"Exception in bad_handler when handling msg on 'test-topic':"
" 'test'" in caplog.text
)
async def test_mqtt_ws_subscription( async def test_mqtt_ws_subscription(
hass: HomeAssistant, hass: HomeAssistant,
hass_ws_client: WebSocketGenerator, hass_ws_client: WebSocketGenerator,