1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-26 22:18:40 +00:00

Improve helpers.trigger.async_subscribe_platform_events (#157709)

This commit is contained in:
Erik Montnemery
2025-12-02 10:37:19 +01:00
committed by Franck Nijhof
parent e31cce5d9b
commit ef4062a565
2 changed files with 135 additions and 1 deletions

View File

@@ -169,7 +169,12 @@ def async_subscribe_platform_events(
async def _register_trigger_platform(
hass: HomeAssistant, integration_domain: str, platform: TriggerProtocol
) -> None:
"""Register a trigger platform."""
"""Register a trigger platform and notify listeners.
If the trigger platform does not provide any triggers, or it is disabled,
listeners will not be notified.
"""
from homeassistant.components import automation # noqa: PLC0415
new_triggers: set[str] = set()
@@ -178,6 +183,12 @@ async def _register_trigger_platform(
trigger_key = get_absolute_description_key(integration_domain, trigger_key)
hass.data[TRIGGERS][trigger_key] = integration_domain
new_triggers.add(trigger_key)
if not new_triggers:
_LOGGER.debug(
"Integration %s returned no triggers in async_get_triggers",
integration_domain,
)
return
elif hasattr(platform, "async_validate_trigger_config") or hasattr(
platform, "TRIGGER_SCHEMA"
):
@@ -190,6 +201,10 @@ async def _register_trigger_platform(
)
return
if automation.is_disabled_experimental_trigger(hass, integration_domain):
_LOGGER.debug("Triggers for integration %s are disabled", integration_domain)
return
# We don't use gather here because gather adds additional overhead
# when wrapping each coroutine in a task, and we expect our listeners
# to call trigger.async_get_all_descriptions which will only yield

View File

@@ -1006,3 +1006,122 @@ async def test_subscribe_triggers(
assert await async_setup_component(hass, "sun", {})
assert trigger_events == [{"sun"}]
assert "Error while notifying trigger platform listener" in caplog.text
@patch("annotatedyaml.loader.load_yaml")
@patch.object(Integration, "has_triggers", return_value=True)
@pytest.mark.parametrize(
("new_triggers_conditions_enabled", "expected_events"),
[
(True, [{"light.turned_off", "light.turned_on"}]),
(False, []),
],
)
async def test_subscribe_triggers_experimental_triggers(
mock_has_triggers: Mock,
mock_load_yaml: Mock,
hass: HomeAssistant,
hass_ws_client: WebSocketGenerator,
caplog: pytest.LogCaptureFixture,
new_triggers_conditions_enabled: bool,
expected_events: list[set[str]],
) -> None:
"""Test trigger.async_subscribe_platform_events doesn't send events for disabled triggers."""
# Return empty triggers.yaml for light integration, the actual trigger descriptions
# are irrelevant for this test
light_trigger_descriptions = ""
def _load_yaml(fname, secrets=None):
if fname.endswith("light/triggers.yaml"):
trigger_descriptions = light_trigger_descriptions
else:
raise FileNotFoundError
with io.StringIO(trigger_descriptions) as file:
return parse_yaml(file)
mock_load_yaml.side_effect = _load_yaml
trigger_events = []
async def good_subscriber(new_triggers: set[str]):
"""Simulate a working subscriber."""
trigger_events.append(new_triggers)
ws_client = await hass_ws_client(hass)
assert await async_setup_component(hass, "labs", {})
await ws_client.send_json_auto_id(
{
"type": "labs/update",
"domain": "automation",
"preview_feature": "new_triggers_conditions",
"enabled": new_triggers_conditions_enabled,
}
)
msg = await ws_client.receive_json()
assert msg["success"]
await hass.async_block_till_done()
trigger.async_subscribe_platform_events(hass, good_subscriber)
assert await async_setup_component(hass, "light", {})
await hass.async_block_till_done()
assert trigger_events == expected_events
@patch("annotatedyaml.loader.load_yaml")
@patch.object(Integration, "has_triggers", return_value=True)
@patch(
"homeassistant.components.light.trigger.async_get_triggers",
new=AsyncMock(return_value={}),
)
async def test_subscribe_triggers_no_triggers(
mock_has_triggers: Mock,
mock_load_yaml: Mock,
hass: HomeAssistant,
hass_ws_client: WebSocketGenerator,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test trigger.async_subscribe_platform_events doesn't send events for platforms without triggers."""
# Return empty triggers.yaml for light integration, the actual trigger descriptions
# are irrelevant for this test
light_trigger_descriptions = ""
def _load_yaml(fname, secrets=None):
if fname.endswith("light/triggers.yaml"):
trigger_descriptions = light_trigger_descriptions
else:
raise FileNotFoundError
with io.StringIO(trigger_descriptions) as file:
return parse_yaml(file)
mock_load_yaml.side_effect = _load_yaml
trigger_events = []
async def good_subscriber(new_triggers: set[str]):
"""Simulate a working subscriber."""
trigger_events.append(new_triggers)
ws_client = await hass_ws_client(hass)
assert await async_setup_component(hass, "labs", {})
await ws_client.send_json_auto_id(
{
"type": "labs/update",
"domain": "automation",
"preview_feature": "new_triggers_conditions",
"enabled": True,
}
)
msg = await ws_client.receive_json()
assert msg["success"]
await hass.async_block_till_done()
trigger.async_subscribe_platform_events(hass, good_subscriber)
assert await async_setup_component(hass, "light", {})
await hass.async_block_till_done()
assert trigger_events == []