diff --git a/test/model/test_controller.py b/test/model/test_controller.py index e47ace2d..d6d4b62c 100644 --- a/test/model/test_controller.py +++ b/test/model/test_controller.py @@ -2,6 +2,7 @@ from copy import deepcopy import json +import logging from unittest.mock import patch import pytest @@ -2286,12 +2287,14 @@ async def test_inclusion_aborted(controller): assert {k: v for k, v in event.data.items() if k != "controller"} == event_data -async def test_unknown_event(controller): - """Test that an unknown event type causes an exception.""" - with pytest.raises(KeyError): - assert controller.receive_event( - Event("unknown_event", {"source": "controller"}) - ) +async def test_unknown_event(controller, caplog): + """Test that an unknown event type logs a message but does not raise.""" + caplog.set_level(logging.INFO) + event = Event("unknown_event", {"source": "controller", "event": "unknown_event"}) + controller.receive_event(event) + assert len(caplog.records) == 1 + assert "Unhandled controller event: unknown_event" in caplog.records[0].message + assert caplog.records[0].levelno == logging.INFO async def test_additional_events(controller: Controller) -> None: diff --git a/test/model/test_driver.py b/test/model/test_driver.py index 5739d03b..d35a1195 100644 --- a/test/model/test_driver.py +++ b/test/model/test_driver.py @@ -1,6 +1,7 @@ """Test the driver model.""" import json +import logging from typing import Any import pytest @@ -383,10 +384,14 @@ async def test_shutdown(driver, uuid4, mock_command): } -async def test_unknown_event(driver): - """Test that an unknown event type causes an exception.""" - with pytest.raises(KeyError): - assert driver.receive_event(Event("unknown_event", {"source": "driver"})) +async def test_unknown_event(driver, caplog): + """Test that an unknown event type logs a message but does not raise.""" + caplog.set_level(logging.INFO) + event = Event("unknown_event", {"source": "driver", "event": "unknown_event"}) + driver.receive_event(event) + assert len(caplog.records) == 1 + assert "Unhandled driver event: unknown_event" in caplog.records[0].message + assert caplog.records[0].levelno == logging.INFO async def test_all_nodes_ready_event(driver): diff --git a/test/model/test_node.py b/test/model/test_node.py index b048a933..53696b0d 100644 --- a/test/model/test_node.py +++ b/test/model/test_node.py @@ -4,6 +4,7 @@ from copy import deepcopy from datetime import UTC, datetime import json +import logging from typing import Any from unittest.mock import AsyncMock, patch @@ -2565,10 +2566,14 @@ async def test_abort_health_check(multisensor_6: node_pkg.Node, uuid4, mock_comm } -async def test_unknown_event(multisensor_6: node_pkg.Node): - """Test that an unknown event type causes an exception.""" - with pytest.raises(KeyError): - assert multisensor_6.receive_event(Event("unknown_event", {"source": "node"})) +async def test_unknown_event(multisensor_6: node_pkg.Node, caplog): + """Test that an unknown event type logs a message but does not raise.""" + caplog.set_level(logging.INFO) + event = Event("unknown_event", {"source": "node", "event": "unknown_event"}) + multisensor_6.receive_event(event) + assert len(caplog.records) == 1 + assert "Unhandled node event: unknown_event" in caplog.records[0].message + assert caplog.records[0].levelno == logging.INFO async def test_default_volume(multisensor_6: node_pkg.Node, uuid4, mock_command): diff --git a/zwave_js_server/model/controller/__init__.py b/zwave_js_server/model/controller/__init__.py index ea3fd536..5cfdeae5 100644 --- a/zwave_js_server/model/controller/__init__.py +++ b/zwave_js_server/model/controller/__init__.py @@ -3,6 +3,7 @@ from __future__ import annotations from dataclasses import dataclass +import logging from typing import TYPE_CHECKING, Any, Literal, cast from zwave_js_server.model.node.firmware import NodeFirmwareUpdateInfo @@ -46,6 +47,7 @@ if TYPE_CHECKING: from ...client import Client +_LOGGER = logging.getLogger(__package__) DEFAULT_CONTROLLER_STATISTICS = ( # pylint: disable=invalid-name ControllerStatisticsDataType( @@ -903,12 +905,15 @@ def receive_event(self, event: Event) -> None: f"{event.data}" ) - CONTROLLER_EVENT_MODEL_MAP[event.type].from_dict(event.data) + if (event_type := event.type) not in CONTROLLER_EVENT_MODEL_MAP: + _LOGGER.info("Unhandled controller event: %s", event_type) + return + CONTROLLER_EVENT_MODEL_MAP[event_type].from_dict(event.data) self._handle_event_protocol(event) event.data["controller"] = self - self.emit(event.type, event.data) + self.emit(event_type, event.data) def handle_inclusion_failed(self, event: Event) -> None: """Process an inclusion failed event.""" diff --git a/zwave_js_server/model/driver/__init__.py b/zwave_js_server/model/driver/__init__.py index 6c5f9a28..5b2253da 100644 --- a/zwave_js_server/model/driver/__init__.py +++ b/zwave_js_server/model/driver/__init__.py @@ -2,6 +2,7 @@ from __future__ import annotations +import logging from typing import TYPE_CHECKING, Any, Literal, cast from zwave_js_server.model.firmware import ( @@ -26,6 +27,8 @@ if TYPE_CHECKING: from ...client import Client +_LOGGER = logging.getLogger(__package__) + class BaseDriverEventModel(BaseEventModel): """Base model for a driver event.""" @@ -184,11 +187,14 @@ def receive_event(self, event: Event) -> None: self.controller.receive_event(event) return - DRIVER_EVENT_MODEL_MAP[event.type].from_dict(event.data) + if (event_type := event.type) not in DRIVER_EVENT_MODEL_MAP: + _LOGGER.info("Unhandled driver event: %s", event_type) + return + DRIVER_EVENT_MODEL_MAP[event_type].from_dict(event.data) self._handle_event_protocol(event) - self.emit(event.type, event.data) + self.emit(event_type, event.data) async def _async_send_command( self, command: str, require_schema: int | None = None, **kwargs: Any diff --git a/zwave_js_server/model/node/__init__.py b/zwave_js_server/model/node/__init__.py index 9f9c502e..87a57c67 100644 --- a/zwave_js_server/model/node/__init__.py +++ b/zwave_js_server/model/node/__init__.py @@ -475,12 +475,15 @@ def get_configuration_values(self) -> dict[str, ConfigurationValue]: def receive_event(self, event: Event) -> None: """Receive an event.""" - NODE_EVENT_MODEL_MAP[event.type].from_dict(event.data) + if (event_type := event.type) not in NODE_EVENT_MODEL_MAP: + _LOGGER.info("Unhandled node event: %s", event_type) + return + NODE_EVENT_MODEL_MAP[event_type].from_dict(event.data) self._handle_event_protocol(event) event.data["node"] = self - self.emit(event.type, event.data) + self.emit(event_type, event.data) async def async_send_command( self,