From d54f59478fc3ff8a0b535815386815f24283dfff Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 13 Feb 2023 23:16:59 -0500 Subject: [PATCH] Keep task references while running (#87970) * Keep task references while running * Update pilight tests pointing at correct logger call * Fix graphite tests * Fix profiler tests * More graphite test fixes * Remove extra sleep * Fix tests * Shutdown background tasks as part of stage 1 * Remove unnecessary sleep in test * Remove unused method on mock hass * Skip on cancelled too * Remove background tasks * Test trigger variables without actually sleeping * Fix graphite * One more graphite grrrrrrr --- homeassistant/components/graphite/__init__.py | 2 +- homeassistant/core.py | 82 +++++++---------- tests/common.py | 90 +------------------ .../device_sun_light_trigger/test_init.py | 1 + tests/components/graphite/test_init.py | 33 ++++--- .../components/hardware/test_websocket_api.py | 1 + tests/components/pilight/test_init.py | 10 +-- tests/components/profiler/test_init.py | 27 +++--- tests/helpers/test_script.py | 11 +-- tests/test_bootstrap.py | 4 +- tests/test_config_entries.py | 11 ++- tests/test_core.py | 35 ++------ 12 files changed, 97 insertions(+), 210 deletions(-) diff --git a/homeassistant/components/graphite/__init__.py b/homeassistant/components/graphite/__init__.py index 0a6f6fcc1a9..0f541712d3c 100644 --- a/homeassistant/components/graphite/__init__.py +++ b/homeassistant/components/graphite/__init__.py @@ -69,7 +69,7 @@ def setup(hass: HomeAssistant, config: ConfigType) -> bool: else: _LOGGER.debug("No connection check for UDP possible") - GraphiteFeeder(hass, host, port, protocol, prefix) + hass.data[DOMAIN] = GraphiteFeeder(hass, host, port, protocol, prefix) return True diff --git a/homeassistant/core.py b/homeassistant/core.py index c94e56c6b57..15f05ff608c 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -278,8 +278,7 @@ class HomeAssistant: def __init__(self) -> None: """Initialize new Home Assistant object.""" self.loop = asyncio.get_running_loop() - self._pending_tasks: list[asyncio.Future[Any]] = [] - self._track_task = True + self._tasks: set[asyncio.Future[Any]] = set() self.bus = EventBus(self) self.services = ServiceRegistry(self) self.states = StateMachine(self.bus, self.loop) @@ -355,12 +354,14 @@ class HomeAssistant: self.bus.async_fire(EVENT_CORE_CONFIG_UPDATE) self.bus.async_fire(EVENT_HOMEASSISTANT_START) - try: - # Only block for EVENT_HOMEASSISTANT_START listener - self.async_stop_track_tasks() - async with self.timeout.async_timeout(TIMEOUT_EVENT_START): - await self.async_block_till_done() - except asyncio.TimeoutError: + if not self._tasks: + pending: set[asyncio.Future[Any]] | None = None + else: + _done, pending = await asyncio.wait( + self._tasks, timeout=TIMEOUT_EVENT_START + ) + + if pending: _LOGGER.warning( ( "Something is blocking Home Assistant from wrapping up the start up" @@ -496,9 +497,8 @@ class HomeAssistant: hassjob.target = cast(Callable[..., _R], hassjob.target) task = self.loop.run_in_executor(None, hassjob.target, *args) - # If a task is scheduled - if self._track_task: - self._pending_tasks.append(task) + self._tasks.add(task) + task.add_done_callback(self._tasks.remove) return task @@ -518,9 +518,8 @@ class HomeAssistant: target: target to call. """ task = self.loop.create_task(target) - - if self._track_task: - self._pending_tasks.append(task) + self._tasks.add(task) + task.add_done_callback(self._tasks.remove) return task @@ -530,23 +529,11 @@ class HomeAssistant: ) -> asyncio.Future[_T]: """Add an executor job from within the event loop.""" task = self.loop.run_in_executor(None, target, *args) - - # If a task is scheduled - if self._track_task: - self._pending_tasks.append(task) + self._tasks.add(task) + task.add_done_callback(self._tasks.remove) return task - @callback - def async_track_tasks(self) -> None: - """Track tasks so you can wait for all tasks to be done.""" - self._track_task = True - - @callback - def async_stop_track_tasks(self) -> None: - """Stop track tasks so you can't wait for all tasks to be done.""" - self._track_task = False - @overload @callback def async_run_hass_job( @@ -640,29 +627,25 @@ class HomeAssistant: # To flush out any call_soon_threadsafe await asyncio.sleep(0) start_time: float | None = None + current_task = asyncio.current_task() - while self._pending_tasks: - pending = [task for task in self._pending_tasks if not task.done()] - self._pending_tasks.clear() - if pending: - await self._await_and_log_pending(pending) + while tasks := [task for task in self._tasks if task is not current_task]: + await self._await_and_log_pending(tasks) - if start_time is None: - # Avoid calling monotonic() until we know - # we may need to start logging blocked tasks. - start_time = 0 - elif start_time == 0: - # If we have waited twice then we set the start - # time - start_time = monotonic() - elif monotonic() - start_time > BLOCK_LOG_TIMEOUT: - # We have waited at least three loops and new tasks - # continue to block. At this point we start - # logging all waiting tasks. - for task in pending: - _LOGGER.debug("Waiting for task: %s", task) - else: - await asyncio.sleep(0) + if start_time is None: + # Avoid calling monotonic() until we know + # we may need to start logging blocked tasks. + start_time = 0 + elif start_time == 0: + # If we have waited twice then we set the start + # time + start_time = monotonic() + elif monotonic() - start_time > BLOCK_LOG_TIMEOUT: + # We have waited at least three loops and new tasks + # continue to block. At this point we start + # logging all waiting tasks. + for task in tasks: + _LOGGER.debug("Waiting for task: %s", task) async def _await_and_log_pending(self, pending: Collection[Awaitable[Any]]) -> None: """Await and log tasks that take a long time.""" @@ -706,7 +689,6 @@ class HomeAssistant: # stage 1 self.state = CoreState.stopping - self.async_track_tasks() self.bus.async_fire(EVENT_HOMEASSISTANT_STOP) try: async with self.timeout.async_timeout(STAGE_1_SHUTDOWN_TIMEOUT): diff --git a/tests/common.py b/tests/common.py index e45efb028e6..0424a5707e2 100644 --- a/tests/common.py +++ b/tests/common.py @@ -3,14 +3,7 @@ from __future__ import annotations import asyncio from collections import OrderedDict -from collections.abc import ( - Awaitable, - Callable, - Collection, - Generator, - Mapping, - Sequence, -) +from collections.abc import Awaitable, Callable, Generator, Mapping, Sequence from contextlib import contextmanager from datetime import datetime, timedelta, timezone import functools as ft @@ -22,8 +15,6 @@ import os import pathlib import threading import time -from time import monotonic -import types from typing import Any, NoReturn from unittest.mock import AsyncMock, Mock, patch @@ -51,7 +42,6 @@ from homeassistant.const import ( STATE_ON, ) from homeassistant.core import ( - BLOCK_LOG_TIMEOUT, CoreState, Event, HomeAssistant, @@ -221,76 +211,9 @@ async def async_test_home_assistant(event_loop, load_registries=True): return orig_async_create_task(coroutine) - async def async_wait_for_task_count(self, max_remaining_tasks: int = 0) -> None: - """Block until at most max_remaining_tasks remain. - - Based on HomeAssistant.async_block_till_done - """ - # To flush out any call_soon_threadsafe - await asyncio.sleep(0) - start_time: float | None = None - - while len(self._pending_tasks) > max_remaining_tasks: - pending: Collection[Awaitable[Any]] = [ - task for task in self._pending_tasks if not task.done() - ] - self._pending_tasks.clear() - if len(pending) > max_remaining_tasks: - remaining_pending = await self._await_count_and_log_pending( - pending, max_remaining_tasks=max_remaining_tasks - ) - self._pending_tasks.extend(remaining_pending) - - if start_time is None: - # Avoid calling monotonic() until we know - # we may need to start logging blocked tasks. - start_time = 0 - elif start_time == 0: - # If we have waited twice then we set the start - # time - start_time = monotonic() - elif monotonic() - start_time > BLOCK_LOG_TIMEOUT: - # We have waited at least three loops and new tasks - # continue to block. At this point we start - # logging all waiting tasks. - for task in pending: - _LOGGER.debug("Waiting for task: %s", task) - else: - self._pending_tasks.extend(pending) - await asyncio.sleep(0) - - async def _await_count_and_log_pending( - self, pending: Collection[Awaitable[Any]], max_remaining_tasks: int = 0 - ) -> Collection[Awaitable[Any]]: - """Block at most max_remaining_tasks remain and log tasks that take a long time. - - Based on HomeAssistant._await_and_log_pending - """ - wait_time = 0 - - return_when = asyncio.ALL_COMPLETED - if max_remaining_tasks: - return_when = asyncio.FIRST_COMPLETED - - while len(pending) > max_remaining_tasks: - _, pending = await asyncio.wait( - pending, timeout=BLOCK_LOG_TIMEOUT, return_when=return_when - ) - if not pending or max_remaining_tasks: - return pending - wait_time += BLOCK_LOG_TIMEOUT - for task in pending: - _LOGGER.debug("Waited %s seconds for task: %s", wait_time, task) - - return [] - hass.async_add_job = async_add_job hass.async_add_executor_job = async_add_executor_job hass.async_create_task = async_create_task - hass.async_wait_for_task_count = types.MethodType(async_wait_for_task_count, hass) - hass._await_count_and_log_pending = types.MethodType( - _await_count_and_log_pending, hass - ) hass.data[loader.DATA_CUSTOM_COMPONENTS] = {} @@ -328,17 +251,6 @@ async def async_test_home_assistant(event_loop, load_registries=True): hass.state = CoreState.running - # Mock async_start - orig_start = hass.async_start - - async def mock_async_start(): - """Start the mocking.""" - # We only mock time during tests and we want to track tasks - with patch.object(hass, "async_stop_track_tasks"): - await orig_start() - - hass.async_start = mock_async_start - @callback def clear_instance(event): """Clear global instance.""" diff --git a/tests/components/device_sun_light_trigger/test_init.py b/tests/components/device_sun_light_trigger/test_init.py index 0744002d10c..0c5a9ccab14 100644 --- a/tests/components/device_sun_light_trigger/test_init.py +++ b/tests/components/device_sun_light_trigger/test_init.py @@ -239,5 +239,6 @@ async def test_initialize_start(hass: HomeAssistant) -> None: ) as mock_activate: hass.bus.fire(EVENT_HOMEASSISTANT_START) await hass.async_block_till_done() + await hass.async_block_till_done() assert len(mock_activate.mock_calls) == 1 diff --git a/tests/components/graphite/test_init.py b/tests/components/graphite/test_init.py index 395cfbf0a8b..1370b6c46eb 100644 --- a/tests/components/graphite/test_init.py +++ b/tests/components/graphite/test_init.py @@ -1,5 +1,4 @@ """The tests for the Graphite component.""" -import asyncio import socket from unittest import mock from unittest.mock import patch @@ -91,9 +90,11 @@ async def test_start(hass: HomeAssistant, mock_socket, mock_time) -> None: mock_socket.reset_mock() await hass.async_start() + await hass.async_block_till_done() hass.states.async_set("test.entity", STATE_ON) - await asyncio.sleep(0.1) + await hass.async_block_till_done() + hass.data[graphite.DOMAIN]._queue.join() assert mock_socket.return_value.connect.call_count == 1 assert mock_socket.return_value.connect.call_args == mock.call(("localhost", 2003)) @@ -114,9 +115,11 @@ async def test_shutdown(hass: HomeAssistant, mock_socket, mock_time) -> None: mock_socket.reset_mock() await hass.async_start() + await hass.async_block_till_done() hass.states.async_set("test.entity", STATE_ON) - await asyncio.sleep(0.1) + await hass.async_block_till_done() + hass.data[graphite.DOMAIN]._queue.join() assert mock_socket.return_value.connect.call_count == 1 assert mock_socket.return_value.connect.call_args == mock.call(("localhost", 2003)) @@ -134,7 +137,7 @@ async def test_shutdown(hass: HomeAssistant, mock_socket, mock_time) -> None: await hass.async_block_till_done() hass.states.async_set("test.entity", STATE_OFF) - await asyncio.sleep(0.1) + await hass.async_block_till_done() assert mock_socket.return_value.connect.call_count == 0 assert mock_socket.return_value.sendall.call_count == 0 @@ -156,9 +159,11 @@ async def test_report_attributes(hass: HomeAssistant, mock_socket, mock_time) -> mock_socket.reset_mock() await hass.async_start() + await hass.async_block_till_done() hass.states.async_set("test.entity", STATE_ON, attrs) - await asyncio.sleep(0.1) + await hass.async_block_till_done() + hass.data[graphite.DOMAIN]._queue.join() assert mock_socket.return_value.connect.call_count == 1 assert mock_socket.return_value.connect.call_args == mock.call(("localhost", 2003)) @@ -186,9 +191,11 @@ async def test_report_with_string_state( mock_socket.reset_mock() await hass.async_start() + await hass.async_block_till_done() hass.states.async_set("test.entity", "above_horizon", {"foo": 1.0}) - await asyncio.sleep(0.1) + await hass.async_block_till_done() + hass.data[graphite.DOMAIN]._queue.join() assert mock_socket.return_value.connect.call_count == 1 assert mock_socket.return_value.connect.call_args == mock.call(("localhost", 2003)) @@ -203,7 +210,8 @@ async def test_report_with_string_state( mock_socket.reset_mock() hass.states.async_set("test.entity", "not_float") - await asyncio.sleep(0.1) + await hass.async_block_till_done() + hass.data[graphite.DOMAIN]._queue.join() assert mock_socket.return_value.connect.call_count == 0 assert mock_socket.return_value.sendall.call_count == 0 @@ -221,13 +229,15 @@ async def test_report_with_binary_state( mock_socket.reset_mock() await hass.async_start() + await hass.async_block_till_done() expected = [ "ha.test.entity.foo 1.000000 12345", "ha.test.entity.state 1.000000 12345", ] hass.states.async_set("test.entity", STATE_ON, {"foo": 1.0}) - await asyncio.sleep(0.1) + await hass.async_block_till_done() + hass.data[graphite.DOMAIN]._queue.join() assert mock_socket.return_value.connect.call_count == 1 assert mock_socket.return_value.connect.call_args == mock.call(("localhost", 2003)) @@ -246,7 +256,8 @@ async def test_report_with_binary_state( "ha.test.entity.state 0.000000 12345", ] hass.states.async_set("test.entity", STATE_OFF, {"foo": 1.0}) - await asyncio.sleep(0.1) + await hass.async_block_till_done() + hass.data[graphite.DOMAIN]._queue.join() assert mock_socket.return_value.connect.call_count == 1 assert mock_socket.return_value.connect.call_args == mock.call(("localhost", 2003)) @@ -282,10 +293,12 @@ async def test_send_to_graphite_errors( mock_socket.reset_mock() await hass.async_start() + await hass.async_block_till_done() mock_socket.return_value.connect.side_effect = error hass.states.async_set("test.entity", STATE_ON) - await asyncio.sleep(0.1) + await hass.async_block_till_done() + hass.data[graphite.DOMAIN]._queue.join() assert log_text in caplog.text diff --git a/tests/components/hardware/test_websocket_api.py b/tests/components/hardware/test_websocket_api.py index 72076cf1964..b3a3e9ba114 100644 --- a/tests/components/hardware/test_websocket_api.py +++ b/tests/components/hardware/test_websocket_api.py @@ -71,6 +71,7 @@ async def test_system_status_subscription( ): freezer.tick(TEST_TIME_ADVANCE_INTERVAL) await hass.async_block_till_done() + await hass.async_block_till_done() response = await client.receive_json() assert response["event"] == { diff --git a/tests/components/pilight/test_init.py b/tests/components/pilight/test_init.py index 8d7b8172d0d..cca9843dd04 100644 --- a/tests/components/pilight/test_init.py +++ b/tests/components/pilight/test_init.py @@ -239,7 +239,7 @@ async def test_receive_code(mock_debug, hass): }, **PilightDaemonSim.test_message["message"], ) - debug_log_call = mock_debug.call_args_list[-3] + debug_log_call = mock_debug.call_args_list[-1] # Check if all message parts are put on event bus for key, value in expected_message.items(): @@ -272,7 +272,7 @@ async def test_whitelist_exact_match(mock_debug, hass): }, **PilightDaemonSim.test_message["message"], ) - debug_log_call = mock_debug.call_args_list[-3] + debug_log_call = mock_debug.call_args_list[-1] # Check if all message parts are put on event bus for key, value in expected_message.items(): @@ -303,7 +303,7 @@ async def test_whitelist_partial_match(mock_debug, hass): }, **PilightDaemonSim.test_message["message"], ) - debug_log_call = mock_debug.call_args_list[-3] + debug_log_call = mock_debug.call_args_list[-1] # Check if all message parts are put on event bus for key, value in expected_message.items(): @@ -337,7 +337,7 @@ async def test_whitelist_or_match(mock_debug, hass): }, **PilightDaemonSim.test_message["message"], ) - debug_log_call = mock_debug.call_args_list[-3] + debug_log_call = mock_debug.call_args_list[-1] # Check if all message parts are put on event bus for key, value in expected_message.items(): @@ -360,7 +360,7 @@ async def test_whitelist_no_match(mock_debug, hass): await hass.async_start() await hass.async_block_till_done() - debug_log_call = mock_debug.call_args_list[-3] + debug_log_call = mock_debug.call_args_list[-1] assert "Event pilight_received" not in debug_log_call diff --git a/tests/components/profiler/test_init.py b/tests/components/profiler/test_init.py index 52f15e318e8..0fc70d3ce0d 100644 --- a/tests/components/profiler/test_init.py +++ b/tests/components/profiler/test_init.py @@ -43,8 +43,9 @@ async def test_basic_usage(hass, tmpdir): return last_filename with patch("cProfile.Profile"), patch.object(hass.config, "path", _mock_path): - await hass.services.async_call(DOMAIN, SERVICE_START, {CONF_SECONDS: 0.000001}) - await hass.async_block_till_done() + await hass.services.async_call( + DOMAIN, SERVICE_START, {CONF_SECONDS: 0.000001}, blocking=True + ) assert os.path.exists(last_filename) @@ -72,8 +73,9 @@ async def test_memory_usage(hass, tmpdir): return last_filename with patch("guppy.hpy") as mock_hpy, patch.object(hass.config, "path", _mock_path): - await hass.services.async_call(DOMAIN, SERVICE_MEMORY, {CONF_SECONDS: 0.000001}) - await hass.async_block_till_done() + await hass.services.async_call( + DOMAIN, SERVICE_MEMORY, {CONF_SECONDS: 0.000001}, blocking=True + ) mock_hpy.assert_called_once() @@ -97,9 +99,8 @@ async def test_object_growth_logging( with patch("objgraph.growth"): await hass.services.async_call( - DOMAIN, SERVICE_START_LOG_OBJECTS, {CONF_SCAN_INTERVAL: 10} + DOMAIN, SERVICE_START_LOG_OBJECTS, {CONF_SCAN_INTERVAL: 10}, blocking=True ) - await hass.async_block_till_done() assert "Growth" in caplog.text caplog.clear() @@ -108,8 +109,7 @@ async def test_object_growth_logging( await hass.async_block_till_done() assert "Growth" in caplog.text - await hass.services.async_call(DOMAIN, SERVICE_STOP_LOG_OBJECTS, {}) - await hass.async_block_till_done() + await hass.services.async_call(DOMAIN, SERVICE_STOP_LOG_OBJECTS, {}, blocking=True) caplog.clear() async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=21)) @@ -150,9 +150,8 @@ async def test_dump_log_object( assert hass.services.has_service(DOMAIN, SERVICE_DUMP_LOG_OBJECTS) await hass.services.async_call( - DOMAIN, SERVICE_DUMP_LOG_OBJECTS, {CONF_TYPE: "DumpLogDummy"} + DOMAIN, SERVICE_DUMP_LOG_OBJECTS, {CONF_TYPE: "DumpLogDummy"}, blocking=True ) - await hass.async_block_till_done() assert "" in caplog.text assert "Failed to serialize" in caplog.text @@ -174,8 +173,7 @@ async def test_log_thread_frames( assert hass.services.has_service(DOMAIN, SERVICE_LOG_THREAD_FRAMES) - await hass.services.async_call(DOMAIN, SERVICE_LOG_THREAD_FRAMES, {}) - await hass.async_block_till_done() + await hass.services.async_call(DOMAIN, SERVICE_LOG_THREAD_FRAMES, {}, blocking=True) assert "SyncWorker_0" in caplog.text caplog.clear() @@ -197,8 +195,9 @@ async def test_log_scheduled( assert hass.services.has_service(DOMAIN, SERVICE_LOG_EVENT_LOOP_SCHEDULED) - await hass.services.async_call(DOMAIN, SERVICE_LOG_EVENT_LOOP_SCHEDULED, {}) - await hass.async_block_till_done() + await hass.services.async_call( + DOMAIN, SERVICE_LOG_EVENT_LOOP_SCHEDULED, {}, blocking=True + ) assert "Scheduled" in caplog.text caplog.clear() diff --git a/tests/helpers/test_script.py b/tests/helpers/test_script.py index cd6cba56ba5..a2c0f0b373f 100644 --- a/tests/helpers/test_script.py +++ b/tests/helpers/test_script.py @@ -815,15 +815,13 @@ async def test_wait_for_trigger_variables(hass: HomeAssistant) -> None: actions = [ { "alias": "variables", - "variables": {"seconds": 5}, + "variables": {"state": "off"}, }, { "alias": wait_alias, "wait_for_trigger": { - "platform": "state", - "entity_id": "switch.test", - "to": "off", - "for": {"seconds": "{{ seconds }}"}, + "platform": "template", + "value_template": "{{ states.switch.test.state == state }}", }, }, ] @@ -839,9 +837,6 @@ async def test_wait_for_trigger_variables(hass: HomeAssistant) -> None: assert script_obj.is_running assert script_obj.last_action == wait_alias hass.states.async_set("switch.test", "off") - # the script task + 2 tasks created by wait_for_trigger script step - await hass.async_wait_for_task_count(3) - async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=10)) await hass.async_block_till_done() except (AssertionError, asyncio.TimeoutError): await script_obj.async_stop() diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py index cbe33bab6c4..48d161d5b57 100644 --- a/tests/test_bootstrap.py +++ b/tests/test_bootstrap.py @@ -774,12 +774,10 @@ async def test_warning_logged_on_wrap_up_timeout(hass, caplog): def gen_domain_setup(domain): async def async_setup(hass, config): - await asyncio.sleep(0.1) - async def _background_task(): await asyncio.sleep(0.2) - await hass.async_create_task(_background_task()) + hass.async_create_task(_background_task()) return True return async_setup diff --git a/tests/test_config_entries.py b/tests/test_config_entries.py index be9c47c8b29..63881631b87 100644 --- a/tests/test_config_entries.py +++ b/tests/test_config_entries.py @@ -3559,14 +3559,17 @@ async def test_initializing_flows_canceled_on_shutdown(hass: HomeAssistant, mana """Mock Reauth.""" await asyncio.sleep(1) + mock_integration(hass, MockModule("test")) + mock_entity_platform(hass, "config_flow.test", None) + with patch.dict( config_entries.HANDLERS, {"comp": MockFlowHandler, "test": MockFlowHandler} ): task = asyncio.create_task( manager.flow.async_init("test", context={"source": "reauth"}) ) - await hass.async_block_till_done() - await manager.flow.async_shutdown() + await hass.async_block_till_done() + await manager.flow.async_shutdown() - with pytest.raises(asyncio.exceptions.CancelledError): - await task + with pytest.raises(asyncio.exceptions.CancelledError): + await task diff --git a/tests/test_core.py b/tests/test_core.py index db89bac36f6..1e0e69cc3af 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -124,7 +124,7 @@ def test_async_add_job_add_hass_threaded_job_to_pool() -> None: ha.HomeAssistant.async_add_hass_job(hass, ha.HassJob(job)) assert len(hass.loop.call_soon.mock_calls) == 0 assert len(hass.loop.create_task.mock_calls) == 0 - assert len(hass.loop.run_in_executor.mock_calls) == 1 + assert len(hass.loop.run_in_executor.mock_calls) == 2 def test_async_create_task_schedule_coroutine(event_loop): @@ -205,7 +205,7 @@ async def test_shutdown_calls_block_till_done_after_shutdown_run_callback_thread assert stop_calls[-1] == "async_block_till_done" -async def test_pending_sheduler(hass: HomeAssistant) -> None: +async def test_pending_scheduler(hass: HomeAssistant) -> None: """Add a coro to pending tasks.""" call_count = [] @@ -216,9 +216,9 @@ async def test_pending_sheduler(hass: HomeAssistant) -> None: for _ in range(3): hass.async_add_job(test_coro()) - await asyncio.wait(hass._pending_tasks) + await asyncio.wait(hass._tasks) - assert len(hass._pending_tasks) == 3 + assert len(hass._tasks) == 0 assert len(call_count) == 3 @@ -240,7 +240,7 @@ async def test_async_add_job_pending_tasks_coro(hass: HomeAssistant) -> None: await wait_finish_callback() - assert len(hass._pending_tasks) == 2 + assert len(hass._tasks) == 2 await hass.async_block_till_done() assert len(call_count) == 2 @@ -263,7 +263,7 @@ async def test_async_create_task_pending_tasks_coro(hass: HomeAssistant) -> None await wait_finish_callback() - assert len(hass._pending_tasks) == 2 + assert len(hass._tasks) == 2 await hass.async_block_till_done() assert len(call_count) == 2 @@ -286,7 +286,6 @@ async def test_async_add_job_pending_tasks_executor(hass: HomeAssistant) -> None await wait_finish_callback() - assert len(hass._pending_tasks) == 2 await hass.async_block_till_done() assert len(call_count) == 2 @@ -312,7 +311,7 @@ async def test_async_add_job_pending_tasks_callback(hass: HomeAssistant) -> None await hass.async_block_till_done() - assert len(hass._pending_tasks) == 0 + assert len(hass._tasks) == 0 assert len(call_count) == 2 @@ -1144,11 +1143,10 @@ async def test_start_taking_too_long(event_loop, caplog): """Test when async_start takes too long.""" hass = ha.HomeAssistant() caplog.set_level(logging.WARNING) + hass.async_create_task(asyncio.sleep(0)) try: - with patch.object( - hass, "async_block_till_done", side_effect=asyncio.TimeoutError - ): + with patch("asyncio.wait", return_value=(set(), {asyncio.Future()})): await hass.async_start() assert hass.state == ha.CoreState.running @@ -1159,21 +1157,6 @@ async def test_start_taking_too_long(event_loop, caplog): assert hass.state == ha.CoreState.stopped -async def test_track_task_functions(event_loop): - """Test function to start/stop track task and initial state.""" - hass = ha.HomeAssistant() - try: - assert hass._track_task - - hass.async_stop_track_tasks() - assert not hass._track_task - - hass.async_track_tasks() - assert hass._track_task - finally: - await hass.async_stop() - - async def test_service_executed_with_subservices(hass: HomeAssistant) -> None: """Test we block correctly till all services done.""" calls = async_mock_service(hass, "test", "inner")