1
0
mirror of https://github.com/home-assistant/core.git synced 2026-05-08 17:49:37 +01:00

Make sure to clean register callbacks when mobile_app reloads (#156028)

This commit is contained in:
Timothy
2025-11-12 12:03:05 +01:00
committed by GitHub
parent 39773a022a
commit 46151456d8
4 changed files with 186 additions and 9 deletions
@@ -61,10 +61,12 @@ async def async_setup_entry(
async_add_entities([MobileAppBinarySensor(data, config_entry)])
async_dispatcher_connect(
hass,
f"{DOMAIN}_{ENTITY_TYPE}_register",
handle_sensor_registration,
config_entry.async_on_unload(
async_dispatcher_connect(
hass,
f"{DOMAIN}_{ENTITY_TYPE}_register",
handle_sensor_registration,
)
)
@@ -72,10 +72,12 @@ async def async_setup_entry(
async_add_entities([MobileAppSensor(data, config_entry)])
async_dispatcher_connect(
hass,
f"{DOMAIN}_{ENTITY_TYPE}_register",
handle_sensor_registration,
config_entry.async_on_unload(
async_dispatcher_connect(
hass,
f"{DOMAIN}_{ENTITY_TYPE}_register",
handle_sensor_registration,
)
)
@@ -6,9 +6,18 @@ from typing import Any
from aiohttp.test_utils import TestClient
import pytest
from homeassistant.const import STATE_UNKNOWN
from homeassistant.components.mobile_app.const import (
ATTR_SENSOR_ATTRIBUTES,
ATTR_SENSOR_ICON,
ATTR_SENSOR_NAME,
ATTR_SENSOR_STATE,
ATTR_SENSOR_TYPE,
ATTR_SENSOR_UNIQUE_ID,
)
from homeassistant.const import CONF_WEBHOOK_ID, STATE_UNKNOWN
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.dispatcher import async_dispatcher_send
async def test_sensor(
@@ -298,3 +307,80 @@ async def test_update_sensor_no_state(
updated_entity = hass.states.get("binary_sensor.test_1_is_charging")
assert updated_entity.state == STATE_UNKNOWN
async def test_dispatcher_cleanup_on_unload(
hass: HomeAssistant,
create_registrations: tuple[dict[str, Any], dict[str, Any]],
webhook_client: TestClient,
) -> None:
"""Test that dispatcher connections are cleaned up on config entry unload."""
webhook_id = create_registrations[1]["webhook_id"]
entry = hass.config_entries.async_entries("mobile_app")[1]
# Send a dispatcher signal when config entry is loaded
async_dispatcher_send(
hass,
"mobile_app_binary_sensor_register",
{
CONF_WEBHOOK_ID: webhook_id,
ATTR_SENSOR_NAME: "Test Before Unload",
ATTR_SENSOR_STATE: True,
ATTR_SENSOR_TYPE: "binary_sensor",
ATTR_SENSOR_UNIQUE_ID: "test_before_unload",
ATTR_SENSOR_ICON: "mdi:test",
ATTR_SENSOR_ATTRIBUTES: {},
},
)
await hass.async_block_till_done()
# Check binary sensor was created
assert hass.states.get("binary_sensor.test_before_unload") is not None
# Unload the config entry
assert await hass.config_entries.async_unload(entry.entry_id)
await hass.async_block_till_done()
# Send another dispatcher signal after unload
async_dispatcher_send(
hass,
"mobile_app_binary_sensor_register",
{
CONF_WEBHOOK_ID: webhook_id,
ATTR_SENSOR_NAME: "Test After Unload",
ATTR_SENSOR_STATE: False,
ATTR_SENSOR_TYPE: "binary_sensor",
ATTR_SENSOR_UNIQUE_ID: "test_after_unload",
ATTR_SENSOR_ICON: "mdi:test",
ATTR_SENSOR_ATTRIBUTES: {},
},
)
await hass.async_block_till_done()
# The binary sensor should not be created because dispatcher was cleaned up
assert hass.states.get("binary_sensor.test_after_unload") is None
# Reload the config entry
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
# Send dispatcher signal after reload
async_dispatcher_send(
hass,
"mobile_app_binary_sensor_register",
{
CONF_WEBHOOK_ID: webhook_id,
ATTR_SENSOR_NAME: "Test After Reload",
ATTR_SENSOR_STATE: True,
ATTR_SENSOR_TYPE: "binary_sensor",
ATTR_SENSOR_UNIQUE_ID: "test_after_reload",
ATTR_SENSOR_ICON: "mdi:test",
ATTR_SENSOR_ATTRIBUTES: {},
},
)
await hass.async_block_till_done()
# This binary sensor should be created successfully after reload
assert hass.states.get("binary_sensor.test_after_reload") is not None
assert hass.states.get("binary_sensor.test_after_reload").state == "on"
@@ -7,8 +7,17 @@ from unittest.mock import patch
from aiohttp.test_utils import TestClient
import pytest
from homeassistant.components.mobile_app.const import (
ATTR_SENSOR_ATTRIBUTES,
ATTR_SENSOR_ICON,
ATTR_SENSOR_NAME,
ATTR_SENSOR_STATE,
ATTR_SENSOR_TYPE,
ATTR_SENSOR_UNIQUE_ID,
)
from homeassistant.components.sensor import SensorDeviceClass
from homeassistant.const import (
CONF_WEBHOOK_ID,
PERCENTAGE,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
@@ -16,6 +25,7 @@ from homeassistant.const import (
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.util.unit_system import (
METRIC_SYSTEM,
US_CUSTOMARY_SYSTEM,
@@ -697,3 +707,80 @@ async def test_recreate_correct_from_entity_registry(
assert entity_entry.capabilities == {
"state_class": "measurement",
}
async def test_dispatcher_cleanup_on_unload(
hass: HomeAssistant,
create_registrations: tuple[dict[str, Any], dict[str, Any]],
webhook_client: TestClient,
) -> None:
"""Test that dispatcher connections are cleaned up on config entry unload."""
webhook_id = create_registrations[1]["webhook_id"]
entry = hass.config_entries.async_entries("mobile_app")[1]
# Send a dispatcher signal when config entry is loaded
async_dispatcher_send(
hass,
"mobile_app_sensor_register",
{
CONF_WEBHOOK_ID: webhook_id,
ATTR_SENSOR_NAME: "Test Before Unload",
ATTR_SENSOR_STATE: 42,
ATTR_SENSOR_TYPE: "sensor",
ATTR_SENSOR_UNIQUE_ID: "test_before_unload",
ATTR_SENSOR_ICON: "mdi:test",
ATTR_SENSOR_ATTRIBUTES: {},
},
)
await hass.async_block_till_done()
# Check sensor was created
assert hass.states.get("sensor.test_before_unload") is not None
# Unload the config entry
assert await hass.config_entries.async_unload(entry.entry_id)
await hass.async_block_till_done()
# Send another dispatcher signal after unload
async_dispatcher_send(
hass,
"mobile_app_sensor_register",
{
CONF_WEBHOOK_ID: webhook_id,
ATTR_SENSOR_NAME: "Test After Unload",
ATTR_SENSOR_STATE: 99,
ATTR_SENSOR_TYPE: "sensor",
ATTR_SENSOR_UNIQUE_ID: "test_after_unload",
ATTR_SENSOR_ICON: "mdi:test",
ATTR_SENSOR_ATTRIBUTES: {},
},
)
await hass.async_block_till_done()
# The sensor should not be created because dispatcher was cleaned up
assert hass.states.get("sensor.test_after_unload") is None
# Reload the config entry
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
# Send dispatcher signal after reload
async_dispatcher_send(
hass,
"mobile_app_sensor_register",
{
CONF_WEBHOOK_ID: webhook_id,
ATTR_SENSOR_NAME: "Test After Reload",
ATTR_SENSOR_STATE: 123,
ATTR_SENSOR_TYPE: "sensor",
ATTR_SENSOR_UNIQUE_ID: "test_after_reload",
ATTR_SENSOR_ICON: "mdi:test",
ATTR_SENSOR_ATTRIBUTES: {},
},
)
await hass.async_block_till_done()
# This sensor should be created successfully after reload
assert hass.states.get("sensor.test_after_reload") is not None
assert hass.states.get("sensor.test_after_reload").state == "123"