Send localization info on websocket_api script errors (#104638)
* Send localization info on script errors * Use connection exception hander * Keep HomeAssistantError is unknown_error * Move specific exception handling
This commit is contained in:
parent
7dbaf40f48
commit
efd330f182
6 changed files with 106 additions and 3 deletions
|
@ -17,6 +17,7 @@ from .const import ( # noqa: F401
|
|||
ERR_INVALID_FORMAT,
|
||||
ERR_NOT_FOUND,
|
||||
ERR_NOT_SUPPORTED,
|
||||
ERR_SERVICE_VALIDATION_ERROR,
|
||||
ERR_TEMPLATE_ERROR,
|
||||
ERR_TIMEOUT,
|
||||
ERR_UNAUTHORIZED,
|
||||
|
|
|
@ -778,7 +778,25 @@ async def handle_execute_script(
|
|||
|
||||
context = connection.context(msg)
|
||||
script_obj = Script(hass, script_config, f"{const.DOMAIN} script", const.DOMAIN)
|
||||
script_result = await script_obj.async_run(msg.get("variables"), context=context)
|
||||
try:
|
||||
script_result = await script_obj.async_run(
|
||||
msg.get("variables"), context=context
|
||||
)
|
||||
except ServiceValidationError as err:
|
||||
connection.logger.error(err)
|
||||
connection.logger.debug("", exc_info=err)
|
||||
connection.send_error(
|
||||
msg["id"],
|
||||
const.ERR_SERVICE_VALIDATION_ERROR,
|
||||
str(err),
|
||||
translation_domain=err.translation_domain,
|
||||
translation_key=err.translation_key,
|
||||
translation_placeholders=err.translation_placeholders,
|
||||
)
|
||||
return
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
connection.async_handle_exception(msg, exc)
|
||||
return
|
||||
connection.send_result(
|
||||
msg["id"],
|
||||
{
|
||||
|
|
|
@ -255,7 +255,10 @@ class ActiveConnection:
|
|||
log_handler = self.logger.error
|
||||
|
||||
code = const.ERR_UNKNOWN_ERROR
|
||||
err_message = None
|
||||
err_message: str | None = None
|
||||
translation_domain: str | None = None
|
||||
translation_key: str | None = None
|
||||
translation_placeholders: dict[str, Any] | None = None
|
||||
|
||||
if isinstance(err, Unauthorized):
|
||||
code = const.ERR_UNAUTHORIZED
|
||||
|
@ -268,6 +271,10 @@ class ActiveConnection:
|
|||
err_message = "Timeout"
|
||||
elif isinstance(err, HomeAssistantError):
|
||||
err_message = str(err)
|
||||
code = const.ERR_UNKNOWN_ERROR
|
||||
translation_domain = err.translation_domain
|
||||
translation_key = err.translation_key
|
||||
translation_placeholders = err.translation_placeholders
|
||||
|
||||
# This if-check matches all other errors but also matches errors which
|
||||
# result in an empty message. In that case we will also log the stack
|
||||
|
@ -276,7 +283,16 @@ class ActiveConnection:
|
|||
err_message = "Unknown error"
|
||||
log_handler = self.logger.exception
|
||||
|
||||
self.send_message(messages.error_message(msg["id"], code, err_message))
|
||||
self.send_message(
|
||||
messages.error_message(
|
||||
msg["id"],
|
||||
code,
|
||||
err_message,
|
||||
translation_domain=translation_domain,
|
||||
translation_key=translation_key,
|
||||
translation_placeholders=translation_placeholders,
|
||||
)
|
||||
)
|
||||
|
||||
if code:
|
||||
err_message += f" ({code})"
|
||||
|
|
|
@ -297,6 +297,7 @@ def async_mock_service(
|
|||
schema: vol.Schema | None = None,
|
||||
response: ServiceResponse = None,
|
||||
supports_response: SupportsResponse | None = None,
|
||||
raise_exception: Exception | None = None,
|
||||
) -> list[ServiceCall]:
|
||||
"""Set up a fake service & return a calls log list to this service."""
|
||||
calls = []
|
||||
|
@ -305,6 +306,8 @@ def async_mock_service(
|
|||
def mock_service_log(call): # pylint: disable=unnecessary-lambda
|
||||
"""Mock service call."""
|
||||
calls.append(call)
|
||||
if raise_exception is not None:
|
||||
raise raise_exception
|
||||
return response
|
||||
|
||||
if supports_response is None:
|
||||
|
|
|
@ -2317,6 +2317,65 @@ async def test_execute_script(
|
|||
assert call.context.as_dict() == msg_var["result"]["context"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("raise_exception", "err_code"),
|
||||
[
|
||||
(
|
||||
HomeAssistantError(
|
||||
"Some error",
|
||||
translation_domain="test",
|
||||
translation_key="test_error",
|
||||
translation_placeholders={"option": "bla"},
|
||||
),
|
||||
"unknown_error",
|
||||
),
|
||||
(
|
||||
ServiceValidationError(
|
||||
"Some error",
|
||||
translation_domain="test",
|
||||
translation_key="test_error",
|
||||
translation_placeholders={"option": "bla"},
|
||||
),
|
||||
"service_validation_error",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_execute_script_err_localization(
|
||||
hass: HomeAssistant,
|
||||
websocket_client: MockHAClientWebSocket,
|
||||
raise_exception: HomeAssistantError,
|
||||
err_code: str,
|
||||
) -> None:
|
||||
"""Test testing a condition."""
|
||||
async_mock_service(
|
||||
hass, "domain_test", "test_service", raise_exception=raise_exception
|
||||
)
|
||||
|
||||
await websocket_client.send_json(
|
||||
{
|
||||
"id": 5,
|
||||
"type": "execute_script",
|
||||
"sequence": [
|
||||
{
|
||||
"service": "domain_test.test_service",
|
||||
"data": {"hello": "world"},
|
||||
},
|
||||
{"stop": "done", "response_variable": "service_result"},
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
msg = await websocket_client.receive_json()
|
||||
assert msg["id"] == 5
|
||||
assert msg["type"] == const.TYPE_RESULT
|
||||
assert msg["success"] is False
|
||||
assert msg["error"]["code"] == err_code
|
||||
assert msg["error"]["message"] == "Some error"
|
||||
assert msg["error"]["translation_key"] == "test_error"
|
||||
assert msg["error"]["translation_domain"] == "test"
|
||||
assert msg["error"]["translation_placeholders"] == {"option": "bla"}
|
||||
|
||||
|
||||
async def test_execute_script_complex_response(
|
||||
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
||||
) -> None:
|
||||
|
|
|
@ -43,6 +43,12 @@ from tests.common import MockUser
|
|||
"Failed to do X",
|
||||
"Error handling message: Failed to do X (unknown_error) Mock User from 127.0.0.42 (Browser)",
|
||||
),
|
||||
(
|
||||
exceptions.ServiceValidationError("Failed to do X"),
|
||||
websocket_api.ERR_UNKNOWN_ERROR,
|
||||
"Failed to do X",
|
||||
"Error handling message: Failed to do X (unknown_error) Mock User from 127.0.0.42 (Browser)",
|
||||
),
|
||||
(
|
||||
ValueError("Really bad"),
|
||||
websocket_api.ERR_UNKNOWN_ERROR,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue