1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-24 21:06:19 +00:00

Fix memory leak when firing state_changed events (#72571)

This commit is contained in:
J. Nick Koston
2022-05-26 17:54:26 -10:00
committed by GitHub
parent 465210784f
commit 049c06061c
3 changed files with 84 additions and 8 deletions

View File

@@ -6,9 +6,11 @@ import array
import asyncio
from datetime import datetime, timedelta
import functools
import gc
import logging
import os
from tempfile import TemporaryDirectory
from typing import Any
from unittest.mock import MagicMock, Mock, PropertyMock, patch
import pytest
@@ -1829,3 +1831,46 @@ async def test_event_context(hass):
cancel2()
assert dummy_event2.context.origin_event == dummy_event
def _get_full_name(obj) -> str:
"""Get the full name of an object in memory."""
objtype = type(obj)
name = objtype.__name__
if module := getattr(objtype, "__module__", None):
return f"{module}.{name}"
return name
def _get_by_type(full_name: str) -> list[Any]:
"""Get all objects in memory with a specific type."""
return [obj for obj in gc.get_objects() if _get_full_name(obj) == full_name]
# The logger will hold a strong reference to the event for the life of the tests
# so we must patch it out
@pytest.mark.skipif(
not os.environ.get("DEBUG_MEMORY"),
reason="Takes too long on the CI",
)
@patch.object(ha._LOGGER, "debug", lambda *args: None)
async def test_state_changed_events_to_not_leak_contexts(hass):
"""Test state changed events do not leak contexts."""
gc.collect()
# Other tests can log Contexts which keep them in memory
# so we need to look at how many exist at the start
init_count = len(_get_by_type("homeassistant.core.Context"))
assert len(_get_by_type("homeassistant.core.Context")) == init_count
for i in range(20):
hass.states.async_set("light.switch", str(i))
await hass.async_block_till_done()
gc.collect()
assert len(_get_by_type("homeassistant.core.Context")) == init_count + 2
hass.states.async_remove("light.switch")
await hass.async_block_till_done()
gc.collect()
assert len(_get_by_type("homeassistant.core.Context")) == init_count