From 115c5d1704a04ce90cc3c7c95bdfbceb99809511 Mon Sep 17 00:00:00 2001 From: Erik Montnemery <erik@montnemery.com> Date: Fri, 16 Aug 2024 16:59:33 +0200 Subject: [PATCH] Fix threading in get_test_home_assistant test helper (#124056) --- tests/common.py | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/tests/common.py b/tests/common.py index d36df509142..684b9eb0433 100644 --- a/tests/common.py +++ b/tests/common.py @@ -13,7 +13,12 @@ from collections.abc import ( Mapping, Sequence, ) -from contextlib import asynccontextmanager, contextmanager, suppress +from contextlib import ( + AbstractAsyncContextManager, + asynccontextmanager, + contextmanager, + suppress, +) from datetime import UTC, datetime, timedelta from enum import Enum import functools as ft @@ -177,24 +182,36 @@ def get_test_config_dir(*add_path): @contextmanager def get_test_home_assistant() -> Generator[HomeAssistant]: """Return a Home Assistant object pointing at test config directory.""" - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - context_manager = async_test_home_assistant(loop) - hass = loop.run_until_complete(context_manager.__aenter__()) - + hass_created_event = threading.Event() loop_stop_event = threading.Event() + context_manager: AbstractAsyncContextManager = None + hass: HomeAssistant = None + loop: asyncio.AbstractEventLoop = None + orig_stop: Callable = None + def run_loop() -> None: - """Run event loop.""" + """Create and run event loop.""" + nonlocal context_manager, hass, loop, orig_stop + + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + context_manager = async_test_home_assistant(loop) + hass = loop.run_until_complete(context_manager.__aenter__()) + + orig_stop = hass.stop + hass._stopped = Mock(set=loop.stop) + hass.start = start_hass + hass.stop = stop_hass loop._thread_ident = threading.get_ident() + + hass_created_event.set() + hass.loop_thread_id = loop._thread_ident loop.run_forever() loop_stop_event.set() - orig_stop = hass.stop - hass._stopped = Mock(set=loop.stop) - def start_hass(*mocks: Any) -> None: """Start hass.""" asyncio.run_coroutine_threadsafe(hass.async_start(), loop).result() @@ -204,11 +221,10 @@ def get_test_home_assistant() -> Generator[HomeAssistant]: orig_stop() loop_stop_event.wait() - hass.start = start_hass - hass.stop = stop_hass - threading.Thread(name="LoopThread", target=run_loop, daemon=False).start() + hass_created_event.wait() + try: yield hass finally: -- GitLab