Replace periodic tasks with background tasks (#112726)

* Phase out periodic tasks

* false by default or some tests will block forever, will need to fix each one manually

* kwarg works

* kwarg works

* kwarg works

* fixes

* fix more tests

* fix more tests

* fix lifx

* opensky

* pvpc_hourly_pricing

* adjust more

* adjust more

* smarttub

* adjust more

* adjust more

* adjust more

* adjust more

* adjust

* no eager executor

* zha

* qnap_qsw

* fix more

* fix fix

* docs

* its a wrapper now

* add more coverage

* coverage

* cover all combos

* more fixes

* more fixes

* more fixes

* remaining issues are legit bugs in tests

* make tplink test more predictable

* more fixes

* feedreader

* grind out some more

* make test race safe

* one more
This commit is contained in:
J. Nick Koston 2024-03-08 16:45:10 -10:00 committed by GitHub
parent 08416974c9
commit 65358c129a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
48 changed files with 413 additions and 333 deletions

View file

@ -878,7 +878,7 @@ async def _async_set_up_integrations(
_LOGGER.debug("Waiting for startup to wrap up") _LOGGER.debug("Waiting for startup to wrap up")
try: try:
async with hass.timeout.async_timeout(WRAP_UP_TIMEOUT, cool_down=COOLDOWN_TIME): async with hass.timeout.async_timeout(WRAP_UP_TIMEOUT, cool_down=COOLDOWN_TIME):
await hass.async_block_till_done(wait_periodic_tasks=False) await hass.async_block_till_done()
except TimeoutError: except TimeoutError:
_LOGGER.warning( _LOGGER.warning(
"Setup timed out for bootstrap waiting on %s - moving forward", "Setup timed out for bootstrap waiting on %s - moving forward",

View file

@ -18,7 +18,6 @@ from contextvars import ContextVar
from copy import deepcopy from copy import deepcopy
from enum import Enum, StrEnum from enum import Enum, StrEnum
import functools import functools
from itertools import chain
import logging import logging
from random import randint from random import randint
from types import MappingProxyType from types import MappingProxyType
@ -379,7 +378,6 @@ class ConfigEntry:
self._tasks: set[asyncio.Future[Any]] = set() self._tasks: set[asyncio.Future[Any]] = set()
self._background_tasks: set[asyncio.Future[Any]] = set() self._background_tasks: set[asyncio.Future[Any]] = set()
self._periodic_tasks: set[asyncio.Future[Any]] = set()
self._integration_for_domain: loader.Integration | None = None self._integration_for_domain: loader.Integration | None = None
self._tries = 0 self._tries = 0
@ -857,15 +855,15 @@ class ConfigEntry:
if job := self._on_unload.pop()(): if job := self._on_unload.pop()():
self.async_create_task(hass, job) self.async_create_task(hass, job)
if not self._tasks and not self._background_tasks and not self._periodic_tasks: if not self._tasks and not self._background_tasks:
return return
cancel_message = f"Config entry {self.title} with {self.domain} unloading" cancel_message = f"Config entry {self.title} with {self.domain} unloading"
for task in chain(self._background_tasks, self._periodic_tasks): for task in self._background_tasks:
task.cancel(cancel_message) task.cancel(cancel_message)
_, pending = await asyncio.wait( _, pending = await asyncio.wait(
[*self._tasks, *self._background_tasks, *self._periodic_tasks], timeout=10 [*self._tasks, *self._background_tasks], timeout=10
) )
for task in pending: for task in pending:
@ -1044,35 +1042,6 @@ class ConfigEntry:
task.add_done_callback(self._background_tasks.remove) task.add_done_callback(self._background_tasks.remove)
return task return task
@callback
def async_create_periodic_task(
self,
hass: HomeAssistant,
target: Coroutine[Any, Any, _R],
name: str,
eager_start: bool = False,
) -> asyncio.Task[_R]:
"""Create a periodic task tied to the config entry lifecycle.
Periodic tasks are automatically canceled when config entry is unloaded.
This type of task is typically used for polling.
A periodic task is different from a normal task:
- Will not block startup
- Will be automatically cancelled on shutdown
- Calls to async_block_till_done will wait for completion by default
This method must be run in the event loop.
"""
task = hass.async_create_periodic_task(target, name, eager_start)
if task.done():
return task
self._periodic_tasks.add(task)
task.add_done_callback(self._periodic_tasks.remove)
return task
current_entry: ContextVar[ConfigEntry | None] = ContextVar( current_entry: ContextVar[ConfigEntry | None] = ContextVar(
"current_entry", default=None "current_entry", default=None

View file

@ -375,7 +375,6 @@ class HomeAssistant:
self.loop = asyncio.get_running_loop() self.loop = asyncio.get_running_loop()
self._tasks: set[asyncio.Future[Any]] = set() self._tasks: set[asyncio.Future[Any]] = set()
self._background_tasks: set[asyncio.Future[Any]] = set() self._background_tasks: set[asyncio.Future[Any]] = set()
self._periodic_tasks: set[asyncio.Future[Any]] = set()
self.bus = EventBus(self) self.bus = EventBus(self)
self.services = ServiceRegistry(self) self.services = ServiceRegistry(self)
self.states = StateMachine(self.bus, self.loop) self.states = StateMachine(self.bus, self.loop)
@ -585,23 +584,38 @@ class HomeAssistant:
@overload @overload
@callback @callback
def async_add_hass_job( def async_add_hass_job(
self, hassjob: HassJob[..., Coroutine[Any, Any, _R]], *args: Any self,
hassjob: HassJob[..., Coroutine[Any, Any, _R]],
*args: Any,
eager_start: bool = False,
background: bool = False,
) -> asyncio.Future[_R] | None: ) -> asyncio.Future[_R] | None:
... ...
@overload @overload
@callback @callback
def async_add_hass_job( def async_add_hass_job(
self, hassjob: HassJob[..., Coroutine[Any, Any, _R] | _R], *args: Any self,
hassjob: HassJob[..., Coroutine[Any, Any, _R] | _R],
*args: Any,
eager_start: bool = False,
background: bool = False,
) -> asyncio.Future[_R] | None: ) -> asyncio.Future[_R] | None:
... ...
@callback @callback
def async_add_hass_job( def async_add_hass_job(
self, hassjob: HassJob[..., Coroutine[Any, Any, _R] | _R], *args: Any self,
hassjob: HassJob[..., Coroutine[Any, Any, _R] | _R],
*args: Any,
eager_start: bool = False,
background: bool = False,
) -> asyncio.Future[_R] | None: ) -> asyncio.Future[_R] | None:
"""Add a HassJob from within the event loop. """Add a HassJob from within the event loop.
If eager_start is True, coroutine functions will be scheduled eagerly.
If background is True, the task will created as a background task.
This method must be run in the event loop. This method must be run in the event loop.
hassjob: HassJob to call. hassjob: HassJob to call.
args: parameters for method to call. args: parameters for method to call.
@ -618,6 +632,13 @@ class HomeAssistant:
) )
# Use loop.create_task # Use loop.create_task
# to avoid the extra function call in asyncio.create_task. # to avoid the extra function call in asyncio.create_task.
if eager_start:
task = create_eager_task(
hassjob.target(*args), name=hassjob.name, loop=self.loop
)
if task.done():
return task
else:
task = self.loop.create_task(hassjob.target(*args), name=hassjob.name) task = self.loop.create_task(hassjob.target(*args), name=hassjob.name)
elif hassjob.job_type is HassJobType.Callback: elif hassjob.job_type is HassJobType.Callback:
if TYPE_CHECKING: if TYPE_CHECKING:
@ -629,58 +650,9 @@ class HomeAssistant:
hassjob.target = cast(Callable[..., _R], hassjob.target) hassjob.target = cast(Callable[..., _R], hassjob.target)
task = self.loop.run_in_executor(None, hassjob.target, *args) task = self.loop.run_in_executor(None, hassjob.target, *args)
self._tasks.add(task) task_bucket = self._background_tasks if background else self._tasks
task.add_done_callback(self._tasks.remove) task_bucket.add(task)
task.add_done_callback(task_bucket.remove)
return task
@overload
@callback
def async_run_periodic_hass_job(
self, hassjob: HassJob[..., Coroutine[Any, Any, _R]], *args: Any
) -> asyncio.Future[_R] | None:
...
@overload
@callback
def async_run_periodic_hass_job(
self, hassjob: HassJob[..., Coroutine[Any, Any, _R] | _R], *args: Any
) -> asyncio.Future[_R] | None:
...
@callback
def async_run_periodic_hass_job(
self, hassjob: HassJob[..., Coroutine[Any, Any, _R] | _R], *args: Any
) -> asyncio.Future[_R] | None:
"""Add a periodic HassJob from within the event loop.
This method must be run in the event loop.
hassjob: HassJob to call.
args: parameters for method to call.
"""
task: asyncio.Future[_R]
# This code path is performance sensitive and uses
# if TYPE_CHECKING to avoid the overhead of constructing
# the type used for the cast. For history see:
# https://github.com/home-assistant/core/pull/71960
if hassjob.job_type is HassJobType.Coroutinefunction:
if TYPE_CHECKING:
hassjob.target = cast(
Callable[..., Coroutine[Any, Any, _R]], hassjob.target
)
task = create_eager_task(hassjob.target(*args), name=hassjob.name)
elif hassjob.job_type is HassJobType.Callback:
if TYPE_CHECKING:
hassjob.target = cast(Callable[..., _R], hassjob.target)
hassjob.target(*args)
return None
else:
if TYPE_CHECKING:
hassjob.target = cast(Callable[..., _R], hassjob.target)
task = self.loop.run_in_executor(None, hassjob.target, *args)
self._periodic_tasks.add(task)
task.add_done_callback(self._periodic_tasks.remove)
return task return task
@ -751,37 +723,6 @@ class HomeAssistant:
task.add_done_callback(self._background_tasks.remove) task.add_done_callback(self._background_tasks.remove)
return task return task
@callback
def async_create_periodic_task(
self, target: Coroutine[Any, Any, _R], name: str, eager_start: bool = False
) -> asyncio.Task[_R]:
"""Create a task from within the event loop.
This type of task is typically used for polling.
A periodic task is different from a normal task:
- Will not block startup
- Will be automatically cancelled on shutdown
- Calls to async_block_till_done will wait for completion by default
If you are using this in your integration, use the create task
methods on the config entry instead.
This method must be run in the event loop.
"""
if eager_start:
task = create_eager_task(target, name=name, loop=self.loop)
if task.done():
return task
else:
# Use loop.create_task
# to avoid the extra function call in asyncio.create_task.
task = self.loop.create_task(target, name=name)
self._periodic_tasks.add(task)
task.add_done_callback(self._periodic_tasks.remove)
return task
@callback @callback
def async_add_executor_job( def async_add_executor_job(
self, target: Callable[..., _T], *args: Any self, target: Callable[..., _T], *args: Any
@ -806,25 +747,40 @@ class HomeAssistant:
@overload @overload
@callback @callback
def async_run_hass_job( def async_run_hass_job(
self, hassjob: HassJob[..., Coroutine[Any, Any, _R]], *args: Any self,
hassjob: HassJob[..., Coroutine[Any, Any, _R]],
*args: Any,
eager_start: bool = False,
background: bool = False,
) -> asyncio.Future[_R] | None: ) -> asyncio.Future[_R] | None:
... ...
@overload @overload
@callback @callback
def async_run_hass_job( def async_run_hass_job(
self, hassjob: HassJob[..., Coroutine[Any, Any, _R] | _R], *args: Any self,
hassjob: HassJob[..., Coroutine[Any, Any, _R] | _R],
*args: Any,
eager_start: bool = False,
background: bool = False,
) -> asyncio.Future[_R] | None: ) -> asyncio.Future[_R] | None:
... ...
@callback @callback
def async_run_hass_job( def async_run_hass_job(
self, hassjob: HassJob[..., Coroutine[Any, Any, _R] | _R], *args: Any self,
hassjob: HassJob[..., Coroutine[Any, Any, _R] | _R],
*args: Any,
eager_start: bool = False,
background: bool = False,
) -> asyncio.Future[_R] | None: ) -> asyncio.Future[_R] | None:
"""Run a HassJob from within the event loop. """Run a HassJob from within the event loop.
This method must be run in the event loop. This method must be run in the event loop.
If eager_start is True, coroutine functions will be scheduled eagerly.
If background is True, the task will created as a background task.
hassjob: HassJob hassjob: HassJob
args: parameters for method to call. args: parameters for method to call.
""" """
@ -838,7 +794,9 @@ class HomeAssistant:
hassjob.target(*args) hassjob.target(*args)
return None return None
return self.async_add_hass_job(hassjob, *args) return self.async_add_hass_job(
hassjob, *args, eager_start=eager_start, background=background
)
@overload @overload
@callback @callback
@ -891,7 +849,7 @@ class HomeAssistant:
self.async_block_till_done(), self.loop self.async_block_till_done(), self.loop
).result() ).result()
async def async_block_till_done(self, wait_periodic_tasks: bool = True) -> None: async def async_block_till_done(self, wait_background_tasks: bool = False) -> None:
"""Block until all pending work is done.""" """Block until all pending work is done."""
# To flush out any call_soon_threadsafe # To flush out any call_soon_threadsafe
await asyncio.sleep(0) await asyncio.sleep(0)
@ -900,8 +858,8 @@ class HomeAssistant:
while tasks := [ while tasks := [
task task
for task in ( for task in (
self._tasks | self._periodic_tasks self._tasks | self._background_tasks
if wait_periodic_tasks if wait_background_tasks
else self._tasks else self._tasks
) )
if task is not current_task and not cancelling(task) if task is not current_task and not cancelling(task)
@ -1034,7 +992,7 @@ class HomeAssistant:
self._tasks = set() self._tasks = set()
# Cancel all background tasks # Cancel all background tasks
for task in self._background_tasks | self._periodic_tasks: for task in self._background_tasks:
self._tasks.add(task) self._tasks.add(task)
task.add_done_callback(self._tasks.remove) task.add_done_callback(self._tasks.remove)
task.cancel("Home Assistant is stopping") task.cancel("Home Assistant is stopping")
@ -1046,7 +1004,7 @@ class HomeAssistant:
self.bus.async_fire(EVENT_HOMEASSISTANT_STOP) self.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
try: try:
async with self.timeout.async_timeout(STOP_STAGE_SHUTDOWN_TIMEOUT): async with self.timeout.async_timeout(STOP_STAGE_SHUTDOWN_TIMEOUT):
await self.async_block_till_done(wait_periodic_tasks=False) await self.async_block_till_done()
except TimeoutError: except TimeoutError:
_LOGGER.warning( _LOGGER.warning(
"Timed out waiting for integrations to stop, the shutdown will" "Timed out waiting for integrations to stop, the shutdown will"
@ -1059,7 +1017,7 @@ class HomeAssistant:
self.bus.async_fire(EVENT_HOMEASSISTANT_FINAL_WRITE) self.bus.async_fire(EVENT_HOMEASSISTANT_FINAL_WRITE)
try: try:
async with self.timeout.async_timeout(FINAL_WRITE_STAGE_SHUTDOWN_TIMEOUT): async with self.timeout.async_timeout(FINAL_WRITE_STAGE_SHUTDOWN_TIMEOUT):
await self.async_block_till_done(wait_periodic_tasks=False) await self.async_block_till_done()
except TimeoutError: except TimeoutError:
_LOGGER.warning( _LOGGER.warning(
"Timed out waiting for final writes to complete, the shutdown will" "Timed out waiting for final writes to complete, the shutdown will"
@ -1111,7 +1069,7 @@ class HomeAssistant:
try: try:
async with self.timeout.async_timeout(CLOSE_STAGE_SHUTDOWN_TIMEOUT): async with self.timeout.async_timeout(CLOSE_STAGE_SHUTDOWN_TIMEOUT):
await self.async_block_till_done(wait_periodic_tasks=False) await self.async_block_till_done()
except TimeoutError: except TimeoutError:
_LOGGER.warning( _LOGGER.warning(
"Timed out waiting for close event to be processed, the shutdown will" "Timed out waiting for close event to be processed, the shutdown will"

View file

@ -643,14 +643,14 @@ class EntityPlatform:
def _async_handle_interval_callback(self, now: datetime) -> None: def _async_handle_interval_callback(self, now: datetime) -> None:
"""Update all the entity states in a single platform.""" """Update all the entity states in a single platform."""
if self.config_entry: if self.config_entry:
self.config_entry.async_create_periodic_task( self.config_entry.async_create_background_task(
self.hass, self.hass,
self._update_entity_states(now), self._update_entity_states(now),
name=f"EntityPlatform poll {self.domain}.{self.platform_name}", name=f"EntityPlatform poll {self.domain}.{self.platform_name}",
eager_start=True, eager_start=True,
) )
else: else:
self.hass.async_create_periodic_task( self.hass.async_create_background_task(
self._update_entity_states(now), self._update_entity_states(now),
name=f"EntityPlatform poll {self.domain}.{self.platform_name}", name=f"EntityPlatform poll {self.domain}.{self.platform_name}",
eager_start=True, eager_start=True,

View file

@ -1599,7 +1599,7 @@ class _TrackTimeInterval:
self._track_job, self._track_job,
hass.loop.time() + self.seconds, hass.loop.time() + self.seconds,
) )
hass.async_run_periodic_hass_job(self._run_job, now) hass.async_run_hass_job(self._run_job, now, eager_start=True, background=True)
@callback @callback
def async_cancel(self) -> None: def async_cancel(self) -> None:
@ -1684,7 +1684,7 @@ class SunListener:
"""Handle solar event.""" """Handle solar event."""
self._unsub_sun = None self._unsub_sun = None
self._listen_next_sun_event() self._listen_next_sun_event()
self.hass.async_run_periodic_hass_job(self.job) self.hass.async_run_hass_job(self.job, eager_start=True, background=True)
@callback @callback
def _handle_config_event(self, _event: Any) -> None: def _handle_config_event(self, _event: Any) -> None:
@ -1770,7 +1770,9 @@ class _TrackUTCTimeChange:
# time when the timer was scheduled # time when the timer was scheduled
utc_now = time_tracker_utcnow() utc_now = time_tracker_utcnow()
localized_now = dt_util.as_local(utc_now) if self.local else utc_now localized_now = dt_util.as_local(utc_now) if self.local else utc_now
hass.async_run_periodic_hass_job(self.job, localized_now) hass.async_run_hass_job(
self.job, localized_now, eager_start=True, background=True
)
if TYPE_CHECKING: if TYPE_CHECKING:
assert self._pattern_time_change_listener_job is not None assert self._pattern_time_change_listener_job is not None
self._cancel_callback = async_track_point_in_utc_time( self._cancel_callback = async_track_point_in_utc_time(

View file

@ -258,14 +258,14 @@ class DataUpdateCoordinator(BaseDataUpdateCoordinatorProtocol, Generic[_DataT]):
def __wrap_handle_refresh_interval(self) -> None: def __wrap_handle_refresh_interval(self) -> None:
"""Handle a refresh interval occurrence.""" """Handle a refresh interval occurrence."""
if self.config_entry: if self.config_entry:
self.config_entry.async_create_periodic_task( self.config_entry.async_create_background_task(
self.hass, self.hass,
self._handle_refresh_interval(), self._handle_refresh_interval(),
name=f"{self.name} - {self.config_entry.title} - refresh", name=f"{self.name} - {self.config_entry.title} - refresh",
eager_start=True, eager_start=True,
) )
else: else:
self.hass.async_create_periodic_task( self.hass.async_create_background_task(
self._handle_refresh_interval(), self._handle_refresh_interval(),
name=f"{self.name} - refresh", name=f"{self.name} - refresh",
eager_start=True, eager_start=True,

View file

@ -30,7 +30,7 @@ async def test_coordinator_error(
): ):
freezer.tick(WEATHER_UPDATE_INTERVAL) freezer.tick(WEATHER_UPDATE_INTERVAL)
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("weather.aemet") state = hass.states.get("weather.aemet")
assert state.state == STATE_UNAVAILABLE assert state.state == STATE_UNAVAILABLE

View file

@ -62,7 +62,7 @@ async def test_coordinator_client_connector_error(hass: HomeAssistant) -> None:
mock_device_status.side_effect = AirzoneCloudError mock_device_status.side_effect = AirzoneCloudError
async_fire_time_changed(hass, utcnow() + SCAN_INTERVAL) async_fire_time_changed(hass, utcnow() + SCAN_INTERVAL)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
mock_device_status.assert_called() mock_device_status.assert_called()

View file

@ -51,7 +51,7 @@ async def test_heartbeat_trigger_right_time(hass: HomeAssistant) -> None:
async_fire_time_changed( async_fire_time_changed(
hass, dt_util.utcnow() + BroadlinkHeartbeat.HEARTBEAT_INTERVAL hass, dt_util.utcnow() + BroadlinkHeartbeat.HEARTBEAT_INTERVAL
) )
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert mock_ping.call_count == 1 assert mock_ping.call_count == 1
assert mock_ping.call_args == call(device.host) assert mock_ping.call_args == call(device.host)
@ -69,7 +69,7 @@ async def test_heartbeat_do_not_trigger_before_time(hass: HomeAssistant) -> None
hass, hass,
dt_util.utcnow() + BroadlinkHeartbeat.HEARTBEAT_INTERVAL // 2, dt_util.utcnow() + BroadlinkHeartbeat.HEARTBEAT_INTERVAL // 2,
) )
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert mock_ping.call_count == 0 assert mock_ping.call_count == 0
@ -88,6 +88,7 @@ async def test_heartbeat_unload(hass: HomeAssistant) -> None:
async_fire_time_changed( async_fire_time_changed(
hass, dt_util.utcnow() + BroadlinkHeartbeat.HEARTBEAT_INTERVAL hass, dt_util.utcnow() + BroadlinkHeartbeat.HEARTBEAT_INTERVAL
) )
await hass.async_block_till_done(wait_background_tasks=True)
assert mock_ping.call_count == 0 assert mock_ping.call_count == 0
@ -108,7 +109,7 @@ async def test_heartbeat_do_not_unload(hass: HomeAssistant) -> None:
async_fire_time_changed( async_fire_time_changed(
hass, dt_util.utcnow() + BroadlinkHeartbeat.HEARTBEAT_INTERVAL hass, dt_util.utcnow() + BroadlinkHeartbeat.HEARTBEAT_INTERVAL
) )
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert mock_ping.call_count == 1 assert mock_ping.call_count == 1
assert mock_ping.call_args == call(device_b.host) assert mock_ping.call_args == call(device_b.host)

View file

@ -209,7 +209,7 @@ async def test_integration_update_interval(
async_fire_time_changed( async_fire_time_changed(
hass, dt_util.utcnow() + timedelta(minutes=DEFAULT_UPDATE_INTERVAL) hass, dt_util.utcnow() + timedelta(minutes=DEFAULT_UPDATE_INTERVAL)
) )
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert len(instance.update_dns_record.mock_calls) == 2 assert len(instance.update_dns_record.mock_calls) == 2
assert "All target records are up to date" not in caplog.text assert "All target records are up to date" not in caplog.text
@ -217,12 +217,12 @@ async def test_integration_update_interval(
async_fire_time_changed( async_fire_time_changed(
hass, dt_util.utcnow() + timedelta(minutes=DEFAULT_UPDATE_INTERVAL) hass, dt_util.utcnow() + timedelta(minutes=DEFAULT_UPDATE_INTERVAL)
) )
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert len(instance.update_dns_record.mock_calls) == 2 assert len(instance.update_dns_record.mock_calls) == 2
instance.list_dns_records.side_effect = pycfdns.ComunicationException() instance.list_dns_records.side_effect = pycfdns.ComunicationException()
async_fire_time_changed( async_fire_time_changed(
hass, dt_util.utcnow() + timedelta(minutes=DEFAULT_UPDATE_INTERVAL) hass, dt_util.utcnow() + timedelta(minutes=DEFAULT_UPDATE_INTERVAL)
) )
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert len(instance.update_dns_record.mock_calls) == 2 assert len(instance.update_dns_record.mock_calls) == 2

View file

@ -324,7 +324,7 @@ async def test_availability(
hass.states.async_set("sensor.input1", "on") hass.states.async_set("sensor.input1", "on")
freezer.tick(timedelta(minutes=1)) freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
entity_state = hass.states.get("binary_sensor.test") entity_state = hass.states.get("binary_sensor.test")
assert entity_state assert entity_state
@ -335,7 +335,7 @@ async def test_availability(
with mock_asyncio_subprocess_run(b"0"): with mock_asyncio_subprocess_run(b"0"):
freezer.tick(timedelta(minutes=1)) freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
entity_state = hass.states.get("binary_sensor.test") entity_state = hass.states.get("binary_sensor.test")
assert entity_state assert entity_state

View file

@ -265,7 +265,7 @@ async def test_updating_to_often(
not in caplog.text not in caplog.text
) )
async_fire_time_changed(hass, dt_util.now() + timedelta(seconds=11)) async_fire_time_changed(hass, dt_util.now() + timedelta(seconds=11))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert called assert called
called.clear() called.clear()
@ -282,7 +282,7 @@ async def test_updating_to_often(
wait_till_event.set() wait_till_event.set()
# Finish processing update # Finish processing update
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert called assert called
assert ( assert (
"Updating Command Line Cover Test took longer than the scheduled update interval" "Updating Command Line Cover Test took longer than the scheduled update interval"
@ -327,7 +327,7 @@ async def test_updating_manually(
await hass.async_block_till_done() await hass.async_block_till_done()
async_fire_time_changed(hass, dt_util.now() + timedelta(seconds=10)) async_fire_time_changed(hass, dt_util.now() + timedelta(seconds=10))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert called assert called
called.clear() called.clear()
@ -367,7 +367,7 @@ async def test_availability(
hass.states.async_set("sensor.input1", "on") hass.states.async_set("sensor.input1", "on")
freezer.tick(timedelta(minutes=1)) freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
entity_state = hass.states.get("cover.test") entity_state = hass.states.get("cover.test")
assert entity_state assert entity_state
@ -378,7 +378,7 @@ async def test_availability(
with mock_asyncio_subprocess_run(b"50\n"): with mock_asyncio_subprocess_run(b"50\n"):
freezer.tick(timedelta(minutes=1)) freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
entity_state = hass.states.get("cover.test") entity_state = hass.states.get("cover.test")
assert entity_state assert entity_state

View file

@ -20,7 +20,7 @@ async def test_setup_config(hass: HomeAssistant, load_yaml_integration: None) ->
"""Test setup from yaml.""" """Test setup from yaml."""
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=10)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=10))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state_binary_sensor = hass.states.get("binary_sensor.test") state_binary_sensor = hass.states.get("binary_sensor.test")
state_sensor = hass.states.get("sensor.test") state_sensor = hass.states.get("sensor.test")

View file

@ -108,7 +108,7 @@ async def test_template_render(
hass, hass,
dt_util.utcnow() + timedelta(minutes=1), dt_util.utcnow() + timedelta(minutes=1),
) )
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
entity_state = hass.states.get("sensor.test") entity_state = hass.states.get("sensor.test")
assert entity_state assert entity_state
@ -140,7 +140,7 @@ async def test_template_render_with_quote(hass: HomeAssistant) -> None:
hass, hass,
dt_util.utcnow() + timedelta(minutes=1), dt_util.utcnow() + timedelta(minutes=1),
) )
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert len(mock_subprocess_run.mock_calls) == 1 assert len(mock_subprocess_run.mock_calls) == 1
mock_subprocess_run.assert_called_with( mock_subprocess_run.assert_called_with(
@ -734,7 +734,7 @@ async def test_availability(
hass.states.async_set("sensor.input1", "on") hass.states.async_set("sensor.input1", "on")
freezer.tick(timedelta(minutes=1)) freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
entity_state = hass.states.get("sensor.test") entity_state = hass.states.get("sensor.test")
assert entity_state assert entity_state
@ -745,7 +745,7 @@ async def test_availability(
with mock_asyncio_subprocess_run(b"January 17, 2022"): with mock_asyncio_subprocess_run(b"January 17, 2022"):
freezer.tick(timedelta(minutes=1)) freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
entity_state = hass.states.get("sensor.test") entity_state = hass.states.get("sensor.test")
assert entity_state assert entity_state

View file

@ -350,7 +350,7 @@ async def test_switch_command_state_fail(
await hass.async_block_till_done() await hass.async_block_till_done()
async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL) async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
entity_state = hass.states.get("switch.test") entity_state = hass.states.get("switch.test")
assert entity_state assert entity_state
@ -734,7 +734,7 @@ async def test_availability(
hass.states.async_set("sensor.input1", "on") hass.states.async_set("sensor.input1", "on")
freezer.tick(timedelta(minutes=1)) freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
entity_state = hass.states.get("switch.test") entity_state = hass.states.get("switch.test")
assert entity_state assert entity_state
@ -745,7 +745,7 @@ async def test_availability(
with mock_asyncio_subprocess_run(b"50\n"): with mock_asyncio_subprocess_run(b"50\n"):
freezer.tick(timedelta(minutes=1)) freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
entity_state = hass.states.get("switch.test") entity_state = hass.states.get("switch.test")
assert entity_state assert entity_state

View file

@ -129,11 +129,11 @@ async def test_failed_update_and_reconnection(
await mock_responses(hass, aioclient_mock, error=True) await mock_responses(hass, aioclient_mock, error=True)
next_update = dt_util.utcnow() + timedelta(seconds=30) next_update = dt_util.utcnow() + timedelta(seconds=30)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get("sensor.efergy_power_usage").state == STATE_UNAVAILABLE assert hass.states.get("sensor.efergy_power_usage").state == STATE_UNAVAILABLE
aioclient_mock.clear_requests() aioclient_mock.clear_requests()
await mock_responses(hass, aioclient_mock) await mock_responses(hass, aioclient_mock)
next_update = dt_util.utcnow() + timedelta(seconds=30) next_update = dt_util.utcnow() + timedelta(seconds=30)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get("sensor.efergy_power_usage").state == "1580" assert hass.states.get("sensor.efergy_power_usage").state == "1580"

View file

@ -370,14 +370,14 @@ async def test_feed_updates(
# Change time and fetch more entries # Change time and fetch more entries
future = dt_util.utcnow() + timedelta(hours=1, seconds=1) future = dt_util.utcnow() + timedelta(hours=1, seconds=1)
async_fire_time_changed(hass, future) async_fire_time_changed(hass, future)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert len(events) == 2 assert len(events) == 2
# Change time but no new entries # Change time but no new entries
future = dt_util.utcnow() + timedelta(hours=2, seconds=2) future = dt_util.utcnow() + timedelta(hours=2, seconds=2)
async_fire_time_changed(hass, future) async_fire_time_changed(hass, future)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert len(events) == 2 assert len(events) == 2

View file

@ -79,7 +79,7 @@ async def test_binary_sensors(
mock_fully_kiosk.getDeviceInfo.return_value = {} mock_fully_kiosk.getDeviceInfo.return_value = {}
freezer.tick(UPDATE_INTERVAL) freezer.tick(UPDATE_INTERVAL)
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("binary_sensor.amazon_fire_plugged_in") state = hass.states.get("binary_sensor.amazon_fire_plugged_in")
assert state assert state
@ -89,7 +89,7 @@ async def test_binary_sensors(
mock_fully_kiosk.getDeviceInfo.side_effect = FullyKioskError("error", "status") mock_fully_kiosk.getDeviceInfo.side_effect = FullyKioskError("error", "status")
freezer.tick(UPDATE_INTERVAL) freezer.tick(UPDATE_INTERVAL)
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("binary_sensor.amazon_fire_plugged_in") state = hass.states.get("binary_sensor.amazon_fire_plugged_in")
assert state assert state

View file

@ -53,7 +53,7 @@ async def test_numbers(
# Test invalid numeric data # Test invalid numeric data
mock_fully_kiosk.getSettings.return_value = {"screenBrightness": "invalid"} mock_fully_kiosk.getSettings.return_value = {"screenBrightness": "invalid"}
async_fire_time_changed(hass, dt_util.utcnow() + UPDATE_INTERVAL) async_fire_time_changed(hass, dt_util.utcnow() + UPDATE_INTERVAL)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("number.amazon_fire_screen_brightness") state = hass.states.get("number.amazon_fire_screen_brightness")
assert state assert state
@ -62,7 +62,7 @@ async def test_numbers(
# Test unknown/missing data # Test unknown/missing data
mock_fully_kiosk.getSettings.return_value = {} mock_fully_kiosk.getSettings.return_value = {}
async_fire_time_changed(hass, dt_util.utcnow() + UPDATE_INTERVAL) async_fire_time_changed(hass, dt_util.utcnow() + UPDATE_INTERVAL)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("number.amazon_fire_screensaver_timer") state = hass.states.get("number.amazon_fire_screensaver_timer")
assert state assert state

View file

@ -145,7 +145,7 @@ async def test_sensors_sensors(
mock_fully_kiosk.getDeviceInfo.return_value = {} mock_fully_kiosk.getDeviceInfo.return_value = {}
freezer.tick(UPDATE_INTERVAL) freezer.tick(UPDATE_INTERVAL)
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.amazon_fire_internal_storage_free_space") state = hass.states.get("sensor.amazon_fire_internal_storage_free_space")
assert state assert state
@ -155,7 +155,7 @@ async def test_sensors_sensors(
mock_fully_kiosk.getDeviceInfo.side_effect = FullyKioskError("error", "status") mock_fully_kiosk.getDeviceInfo.side_effect = FullyKioskError("error", "status")
freezer.tick(UPDATE_INTERVAL) freezer.tick(UPDATE_INTERVAL)
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.amazon_fire_internal_storage_free_space") state = hass.states.get("sensor.amazon_fire_internal_storage_free_space")
assert state assert state
@ -181,7 +181,7 @@ async def test_url_sensor_truncating(
"currentPage": long_url, "currentPage": long_url,
} }
async_fire_time_changed(hass, dt_util.utcnow() + UPDATE_INTERVAL) async_fire_time_changed(hass, dt_util.utcnow() + UPDATE_INTERVAL)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.amazon_fire_current_page") state = hass.states.get("sensor.amazon_fire_current_page")
assert state assert state

View file

@ -831,11 +831,11 @@ async def test_device_registry_calls(hass: HomeAssistant) -> None:
return_value=os_mock_data, return_value=os_mock_data,
): ):
async_fire_time_changed(hass, dt_util.now() + timedelta(hours=1)) async_fire_time_changed(hass, dt_util.now() + timedelta(hours=1))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert len(dev_reg.devices) == 5 assert len(dev_reg.devices) == 5
async_fire_time_changed(hass, dt_util.now() + timedelta(hours=2)) async_fire_time_changed(hass, dt_util.now() + timedelta(hours=2))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert len(dev_reg.devices) == 5 assert len(dev_reg.devices) == 5
supervisor_mock_data = { supervisor_mock_data = {

View file

@ -298,7 +298,7 @@ async def test_stats_addon_sensor(
freezer.tick(HASSIO_UPDATE_INTERVAL + timedelta(seconds=1)) freezer.tick(HASSIO_UPDATE_INTERVAL + timedelta(seconds=1))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert "Could not fetch stats" not in caplog.text assert "Could not fetch stats" not in caplog.text
@ -308,7 +308,7 @@ async def test_stats_addon_sensor(
freezer.tick(HASSIO_UPDATE_INTERVAL + timedelta(seconds=1)) freezer.tick(HASSIO_UPDATE_INTERVAL + timedelta(seconds=1))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert "Could not fetch stats" not in caplog.text assert "Could not fetch stats" not in caplog.text
@ -316,7 +316,7 @@ async def test_stats_addon_sensor(
entity_registry.async_update_entity(entity_id, disabled_by=None) entity_registry.async_update_entity(entity_id, disabled_by=None)
freezer.tick(config_entries.RELOAD_AFTER_UPDATE_DELAY) freezer.tick(config_entries.RELOAD_AFTER_UPDATE_DELAY)
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert config_entry.state is config_entries.ConfigEntryState.LOADED assert config_entry.state is config_entries.ConfigEntryState.LOADED
# Verify the entity is still enabled # Verify the entity is still enabled
assert entity_registry.async_get(entity_id).disabled_by is None assert entity_registry.async_get(entity_id).disabled_by is None
@ -324,13 +324,13 @@ async def test_stats_addon_sensor(
# The config entry just reloaded, so we need to wait for the next update # The config entry just reloaded, so we need to wait for the next update
freezer.tick(HASSIO_UPDATE_INTERVAL + timedelta(seconds=1)) freezer.tick(HASSIO_UPDATE_INTERVAL + timedelta(seconds=1))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get(entity_id) is not None assert hass.states.get(entity_id) is not None
freezer.tick(HASSIO_UPDATE_INTERVAL + timedelta(seconds=1)) freezer.tick(HASSIO_UPDATE_INTERVAL + timedelta(seconds=1))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
# Verify that the entity have the expected state. # Verify that the entity have the expected state.
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
assert state.state == expected assert state.state == expected
@ -341,7 +341,7 @@ async def test_stats_addon_sensor(
freezer.tick(HASSIO_UPDATE_INTERVAL + timedelta(seconds=1)) freezer.tick(HASSIO_UPDATE_INTERVAL + timedelta(seconds=1))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
assert state.state == STATE_UNAVAILABLE assert state.state == STATE_UNAVAILABLE

View file

@ -1003,7 +1003,7 @@ async def test_does_not_work_into_the_future(
one_hour_in = start_time + timedelta(minutes=60) one_hour_in = start_time + timedelta(minutes=60)
with freeze_time(one_hour_in): with freeze_time(one_hour_in):
async_fire_time_changed(hass, one_hour_in) async_fire_time_changed(hass, one_hour_in)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get("sensor.sensor1").state == STATE_UNKNOWN assert hass.states.get("sensor.sensor1").state == STATE_UNKNOWN
assert hass.states.get("sensor.sensor2").state == STATE_UNKNOWN assert hass.states.get("sensor.sensor2").state == STATE_UNKNOWN
@ -1013,7 +1013,7 @@ async def test_does_not_work_into_the_future(
hass.states.async_set("binary_sensor.state", "off") hass.states.async_set("binary_sensor.state", "off")
await hass.async_block_till_done() await hass.async_block_till_done()
async_fire_time_changed(hass, turn_off_time) async_fire_time_changed(hass, turn_off_time)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get("sensor.sensor1").state == STATE_UNKNOWN assert hass.states.get("sensor.sensor1").state == STATE_UNKNOWN
assert hass.states.get("sensor.sensor2").state == STATE_UNKNOWN assert hass.states.get("sensor.sensor2").state == STATE_UNKNOWN
@ -1021,7 +1021,7 @@ async def test_does_not_work_into_the_future(
turn_back_on_time = start_time + timedelta(minutes=105) turn_back_on_time = start_time + timedelta(minutes=105)
with freeze_time(turn_back_on_time): with freeze_time(turn_back_on_time):
async_fire_time_changed(hass, turn_back_on_time) async_fire_time_changed(hass, turn_back_on_time)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get("sensor.sensor1").state == STATE_UNKNOWN assert hass.states.get("sensor.sensor1").state == STATE_UNKNOWN
assert hass.states.get("sensor.sensor2").state == STATE_UNKNOWN assert hass.states.get("sensor.sensor2").state == STATE_UNKNOWN
@ -1036,7 +1036,7 @@ async def test_does_not_work_into_the_future(
end_time = start_time + timedelta(minutes=120) end_time = start_time + timedelta(minutes=120)
with freeze_time(end_time): with freeze_time(end_time):
async_fire_time_changed(hass, end_time) async_fire_time_changed(hass, end_time)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get("sensor.sensor1").state == STATE_UNKNOWN assert hass.states.get("sensor.sensor1").state == STATE_UNKNOWN
assert hass.states.get("sensor.sensor2").state == STATE_UNKNOWN assert hass.states.get("sensor.sensor2").state == STATE_UNKNOWN
@ -1044,7 +1044,7 @@ async def test_does_not_work_into_the_future(
in_the_window = start_time + timedelta(hours=23, minutes=5) in_the_window = start_time + timedelta(hours=23, minutes=5)
with freeze_time(in_the_window): with freeze_time(in_the_window):
async_fire_time_changed(hass, in_the_window) async_fire_time_changed(hass, in_the_window)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get("sensor.sensor1").state == "0.08" assert hass.states.get("sensor.sensor1").state == "0.08"
assert hass.states.get("sensor.sensor2").state == "0.0833333333333333" assert hass.states.get("sensor.sensor2").state == "0.0833333333333333"
@ -1055,7 +1055,7 @@ async def test_does_not_work_into_the_future(
return_value=[], return_value=[],
), freeze_time(past_the_window): ), freeze_time(past_the_window):
async_fire_time_changed(hass, past_the_window) async_fire_time_changed(hass, past_the_window)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get("sensor.sensor1").state == STATE_UNKNOWN assert hass.states.get("sensor.sensor1").state == STATE_UNKNOWN
@ -1077,7 +1077,7 @@ async def test_does_not_work_into_the_future(
_fake_off_states, _fake_off_states,
), freeze_time(past_the_window_with_data): ), freeze_time(past_the_window_with_data):
async_fire_time_changed(hass, past_the_window_with_data) async_fire_time_changed(hass, past_the_window_with_data)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get("sensor.sensor1").state == STATE_UNKNOWN assert hass.states.get("sensor.sensor1").state == STATE_UNKNOWN
@ -1087,7 +1087,7 @@ async def test_does_not_work_into_the_future(
_fake_off_states, _fake_off_states,
), freeze_time(at_the_next_window_with_data): ), freeze_time(at_the_next_window_with_data):
async_fire_time_changed(hass, at_the_next_window_with_data) async_fire_time_changed(hass, at_the_next_window_with_data)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get("sensor.sensor1").state == "0.0" assert hass.states.get("sensor.sensor1").state == "0.0"
@ -1487,7 +1487,7 @@ async def test_end_time_with_microseconds_zeroed(
) )
async_fire_time_changed(hass, time_200) async_fire_time_changed(hass, time_200)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get("sensor.heatpump_compressor_today").state == "1.83" assert hass.states.get("sensor.heatpump_compressor_today").state == "1.83"
assert ( assert (
hass.states.get("sensor.heatpump_compressor_today2").state hass.states.get("sensor.heatpump_compressor_today2").state
@ -1499,7 +1499,7 @@ async def test_end_time_with_microseconds_zeroed(
time_400 = start_of_today + timedelta(hours=4) time_400 = start_of_today + timedelta(hours=4)
with freeze_time(time_400): with freeze_time(time_400):
async_fire_time_changed(hass, time_400) async_fire_time_changed(hass, time_400)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get("sensor.heatpump_compressor_today").state == "1.83" assert hass.states.get("sensor.heatpump_compressor_today").state == "1.83"
assert ( assert (
hass.states.get("sensor.heatpump_compressor_today2").state hass.states.get("sensor.heatpump_compressor_today2").state
@ -1510,7 +1510,7 @@ async def test_end_time_with_microseconds_zeroed(
time_600 = start_of_today + timedelta(hours=6) time_600 = start_of_today + timedelta(hours=6)
with freeze_time(time_600): with freeze_time(time_600):
async_fire_time_changed(hass, time_600) async_fire_time_changed(hass, time_600)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get("sensor.heatpump_compressor_today").state == "3.83" assert hass.states.get("sensor.heatpump_compressor_today").state == "3.83"
assert ( assert (
hass.states.get("sensor.heatpump_compressor_today2").state hass.states.get("sensor.heatpump_compressor_today2").state
@ -1525,7 +1525,7 @@ async def test_end_time_with_microseconds_zeroed(
with freeze_time(rolled_to_next_day): with freeze_time(rolled_to_next_day):
async_fire_time_changed(hass, rolled_to_next_day) async_fire_time_changed(hass, rolled_to_next_day)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get("sensor.heatpump_compressor_today").state == "0.0" assert hass.states.get("sensor.heatpump_compressor_today").state == "0.0"
assert hass.states.get("sensor.heatpump_compressor_today2").state == "0.0" assert hass.states.get("sensor.heatpump_compressor_today2").state == "0.0"
@ -1534,7 +1534,7 @@ async def test_end_time_with_microseconds_zeroed(
) )
with freeze_time(rolled_to_next_day_plus_12): with freeze_time(rolled_to_next_day_plus_12):
async_fire_time_changed(hass, rolled_to_next_day_plus_12) async_fire_time_changed(hass, rolled_to_next_day_plus_12)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get("sensor.heatpump_compressor_today").state == "12.0" assert hass.states.get("sensor.heatpump_compressor_today").state == "12.0"
assert hass.states.get("sensor.heatpump_compressor_today2").state == "12.0" assert hass.states.get("sensor.heatpump_compressor_today2").state == "12.0"
@ -1543,7 +1543,7 @@ async def test_end_time_with_microseconds_zeroed(
) )
with freeze_time(rolled_to_next_day_plus_14): with freeze_time(rolled_to_next_day_plus_14):
async_fire_time_changed(hass, rolled_to_next_day_plus_14) async_fire_time_changed(hass, rolled_to_next_day_plus_14)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get("sensor.heatpump_compressor_today").state == "14.0" assert hass.states.get("sensor.heatpump_compressor_today").state == "14.0"
assert hass.states.get("sensor.heatpump_compressor_today2").state == "14.0" assert hass.states.get("sensor.heatpump_compressor_today2").state == "14.0"
@ -1554,12 +1554,12 @@ async def test_end_time_with_microseconds_zeroed(
hass.states.async_set("binary_sensor.heatpump_compressor_state", "off") hass.states.async_set("binary_sensor.heatpump_compressor_state", "off")
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
async_fire_time_changed(hass, rolled_to_next_day_plus_16_860000) async_fire_time_changed(hass, rolled_to_next_day_plus_16_860000)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
rolled_to_next_day_plus_18 = start_of_today + timedelta(days=1, hours=18) rolled_to_next_day_plus_18 = start_of_today + timedelta(days=1, hours=18)
with freeze_time(rolled_to_next_day_plus_18): with freeze_time(rolled_to_next_day_plus_18):
async_fire_time_changed(hass, rolled_to_next_day_plus_18) async_fire_time_changed(hass, rolled_to_next_day_plus_18)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get("sensor.heatpump_compressor_today").state == "16.0" assert hass.states.get("sensor.heatpump_compressor_today").state == "16.0"
assert ( assert (
hass.states.get("sensor.heatpump_compressor_today2").state hass.states.get("sensor.heatpump_compressor_today2").state

View file

@ -177,7 +177,7 @@ async def test_setup(hass: HomeAssistant, freezer: FrozenDateTimeFactory) -> Non
[mock_entry_1, mock_entry_4, mock_entry_3], [mock_entry_1, mock_entry_4, mock_entry_3],
) )
async_fire_time_changed(hass, utcnow + SCAN_INTERVAL) async_fire_time_changed(hass, utcnow + SCAN_INTERVAL)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
all_states = hass.states.async_all() all_states = hass.states.async_all()
assert len(all_states) == 3 assert len(all_states) == 3
@ -186,7 +186,7 @@ async def test_setup(hass: HomeAssistant, freezer: FrozenDateTimeFactory) -> Non
# so no changes to entities. # so no changes to entities.
mock_feed_update.return_value = "OK_NO_DATA", None mock_feed_update.return_value = "OK_NO_DATA", None
async_fire_time_changed(hass, utcnow + 2 * SCAN_INTERVAL) async_fire_time_changed(hass, utcnow + 2 * SCAN_INTERVAL)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
all_states = hass.states.async_all() all_states = hass.states.async_all()
assert len(all_states) == 3 assert len(all_states) == 3
@ -194,7 +194,7 @@ async def test_setup(hass: HomeAssistant, freezer: FrozenDateTimeFactory) -> Non
# Simulate an update - empty data, removes all entities # Simulate an update - empty data, removes all entities
mock_feed_update.return_value = "ERROR", None mock_feed_update.return_value = "ERROR", None
async_fire_time_changed(hass, utcnow + 3 * SCAN_INTERVAL) async_fire_time_changed(hass, utcnow + 3 * SCAN_INTERVAL)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
all_states = hass.states.async_all() all_states = hass.states.async_all()
assert len(all_states) == 0 assert len(all_states) == 0

View file

@ -6,9 +6,18 @@ import pytest
from homeassistant.components.lifx import config_flow, coordinator, util from homeassistant.components.lifx import config_flow, coordinator, util
from . import _patch_discovery
from tests.common import mock_device_registry, mock_registry from tests.common import mock_device_registry, mock_registry
@pytest.fixture
def mock_discovery():
"""Mock discovery."""
with _patch_discovery():
yield
@pytest.fixture @pytest.fixture
def mock_effect_conductor(): def mock_effect_conductor():
"""Mock the effect conductor.""" """Mock the effect conductor."""

View file

@ -4,6 +4,8 @@ from __future__ import annotations
from datetime import timedelta from datetime import timedelta
import pytest
from homeassistant.components import lifx from homeassistant.components import lifx
from homeassistant.components.binary_sensor import BinarySensorDeviceClass from homeassistant.components.binary_sensor import BinarySensorDeviceClass
from homeassistant.const import ( from homeassistant.const import (
@ -32,6 +34,7 @@ from . import (
from tests.common import MockConfigEntry, async_fire_time_changed from tests.common import MockConfigEntry, async_fire_time_changed
@pytest.mark.usefixtures("mock_discovery")
async def test_hev_cycle_state( async def test_hev_cycle_state(
hass: HomeAssistant, entity_registry: er.EntityRegistry hass: HomeAssistant, entity_registry: er.EntityRegistry
) -> None: ) -> None:
@ -65,11 +68,11 @@ async def test_hev_cycle_state(
bulb.hev_cycle = {"duration": 7200, "remaining": 0, "last_power": False} bulb.hev_cycle = {"duration": 7200, "remaining": 0, "last_power": False}
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get(entity_id).state == STATE_OFF assert hass.states.get(entity_id).state == STATE_OFF
bulb.hev_cycle = None bulb.hev_cycle = None
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get(entity_id).state == STATE_UNKNOWN assert hass.states.get(entity_id).state == STATE_UNKNOWN

View file

@ -64,15 +64,15 @@ async def test_configuring_lifx_causes_discovery(hass: HomeAssistant) -> None:
assert start_calls == 1 assert start_calls == 1
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert start_calls == 2 assert start_calls == 2
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=15)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=15))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert start_calls == 3 assert start_calls == 3
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=30)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=30))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert start_calls == 4 assert start_calls == 4

View file

@ -663,6 +663,7 @@ async def test_extended_multizone_messages(hass: HomeAssistant) -> None:
) )
@pytest.mark.usefixtures("mock_discovery")
async def test_matrix_flame_morph_effects(hass: HomeAssistant) -> None: async def test_matrix_flame_morph_effects(hass: HomeAssistant) -> None:
"""Test the firmware flame and morph effects on a matrix device.""" """Test the firmware flame and morph effects on a matrix device."""
config_entry = MockConfigEntry( config_entry = MockConfigEntry(
@ -721,7 +722,7 @@ async def test_matrix_flame_morph_effects(hass: HomeAssistant) -> None:
], ],
} }
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
assert state.state == STATE_ON assert state.state == STATE_ON
@ -777,7 +778,7 @@ async def test_matrix_flame_morph_effects(hass: HomeAssistant) -> None:
], ],
} }
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
assert state.state == STATE_ON assert state.state == STATE_ON
@ -803,6 +804,7 @@ async def test_matrix_flame_morph_effects(hass: HomeAssistant) -> None:
bulb.set_power.reset_mock() bulb.set_power.reset_mock()
@pytest.mark.usefixtures("mock_discovery")
async def test_lightstrip_move_effect(hass: HomeAssistant) -> None: async def test_lightstrip_move_effect(hass: HomeAssistant) -> None:
"""Test the firmware move effect on a light strip.""" """Test the firmware move effect on a light strip."""
config_entry = MockConfigEntry( config_entry = MockConfigEntry(
@ -859,7 +861,7 @@ async def test_lightstrip_move_effect(hass: HomeAssistant) -> None:
bulb.power_level = 65535 bulb.power_level = 65535
bulb.effect = {"name": "MOVE", "speed": 4.5, "direction": "Left"} bulb.effect = {"name": "MOVE", "speed": 4.5, "direction": "Left"}
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
assert state.state == STATE_ON assert state.state == STATE_ON
@ -1119,6 +1121,7 @@ async def test_white_bulb(hass: HomeAssistant) -> None:
bulb.set_color.reset_mock() bulb.set_color.reset_mock()
@pytest.mark.usefixtures("mock_discovery")
async def test_config_zoned_light_strip_fails( async def test_config_zoned_light_strip_fails(
hass: HomeAssistant, entity_registry: er.EntityRegistry hass: HomeAssistant, entity_registry: er.EntityRegistry
) -> None: ) -> None:
@ -1154,7 +1157,7 @@ async def test_config_zoned_light_strip_fails(
assert hass.states.get(entity_id).state == STATE_OFF assert hass.states.get(entity_id).state == STATE_OFF
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get(entity_id).state == STATE_UNAVAILABLE assert hass.states.get(entity_id).state == STATE_UNAVAILABLE

View file

@ -144,15 +144,15 @@ async def test_discovery_is_more_frequent_during_migration(
assert start_calls == 1 assert start_calls == 1
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert start_calls == 3 assert start_calls == 3
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=10)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=10))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert start_calls == 4 assert start_calls == 4
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=15)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=15))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert start_calls == 5 assert start_calls == 5

View file

@ -2,6 +2,8 @@
from datetime import timedelta from datetime import timedelta
import pytest
from homeassistant.components import lifx from homeassistant.components import lifx
from homeassistant.components.lifx.const import DOMAIN from homeassistant.components.lifx.const import DOMAIN
from homeassistant.components.select import DOMAIN as SELECT_DOMAIN from homeassistant.components.select import DOMAIN as SELECT_DOMAIN
@ -95,6 +97,7 @@ async def test_infrared_brightness(
assert state.state == "100%" assert state.state == "100%"
@pytest.mark.usefixtures("mock_discovery")
async def test_set_infrared_brightness_25_percent(hass: HomeAssistant) -> None: async def test_set_infrared_brightness_25_percent(hass: HomeAssistant) -> None:
"""Test getting and setting infrared brightness.""" """Test getting and setting infrared brightness."""
@ -124,7 +127,7 @@ async def test_set_infrared_brightness_25_percent(hass: HomeAssistant) -> None:
bulb.get_infrared = MockLifxCommand(bulb, infrared_brightness=16383) bulb.get_infrared = MockLifxCommand(bulb, infrared_brightness=16383)
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert bulb.set_infrared.calls[0][0][0] == 16383 assert bulb.set_infrared.calls[0][0][0] == 16383
@ -134,6 +137,7 @@ async def test_set_infrared_brightness_25_percent(hass: HomeAssistant) -> None:
bulb.set_infrared.reset_mock() bulb.set_infrared.reset_mock()
@pytest.mark.usefixtures("mock_discovery")
async def test_set_infrared_brightness_50_percent(hass: HomeAssistant) -> None: async def test_set_infrared_brightness_50_percent(hass: HomeAssistant) -> None:
"""Test getting and setting infrared brightness.""" """Test getting and setting infrared brightness."""
@ -163,7 +167,7 @@ async def test_set_infrared_brightness_50_percent(hass: HomeAssistant) -> None:
bulb.get_infrared = MockLifxCommand(bulb, infrared_brightness=32767) bulb.get_infrared = MockLifxCommand(bulb, infrared_brightness=32767)
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert bulb.set_infrared.calls[0][0][0] == 32767 assert bulb.set_infrared.calls[0][0][0] == 32767
@ -173,6 +177,7 @@ async def test_set_infrared_brightness_50_percent(hass: HomeAssistant) -> None:
bulb.set_infrared.reset_mock() bulb.set_infrared.reset_mock()
@pytest.mark.usefixtures("mock_discovery")
async def test_set_infrared_brightness_100_percent(hass: HomeAssistant) -> None: async def test_set_infrared_brightness_100_percent(hass: HomeAssistant) -> None:
"""Test getting and setting infrared brightness.""" """Test getting and setting infrared brightness."""
@ -202,7 +207,7 @@ async def test_set_infrared_brightness_100_percent(hass: HomeAssistant) -> None:
bulb.get_infrared = MockLifxCommand(bulb, infrared_brightness=65535) bulb.get_infrared = MockLifxCommand(bulb, infrared_brightness=65535)
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert bulb.set_infrared.calls[0][0][0] == 65535 assert bulb.set_infrared.calls[0][0][0] == 65535
@ -212,6 +217,7 @@ async def test_set_infrared_brightness_100_percent(hass: HomeAssistant) -> None:
bulb.set_infrared.reset_mock() bulb.set_infrared.reset_mock()
@pytest.mark.usefixtures("mock_discovery")
async def test_disable_infrared(hass: HomeAssistant) -> None: async def test_disable_infrared(hass: HomeAssistant) -> None:
"""Test getting and setting infrared brightness.""" """Test getting and setting infrared brightness."""
@ -241,7 +247,7 @@ async def test_disable_infrared(hass: HomeAssistant) -> None:
bulb.get_infrared = MockLifxCommand(bulb, infrared_brightness=0) bulb.get_infrared = MockLifxCommand(bulb, infrared_brightness=0)
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert bulb.set_infrared.calls[0][0][0] == 0 assert bulb.set_infrared.calls[0][0][0] == 0
@ -251,6 +257,7 @@ async def test_disable_infrared(hass: HomeAssistant) -> None:
bulb.set_infrared.reset_mock() bulb.set_infrared.reset_mock()
@pytest.mark.usefixtures("mock_discovery")
async def test_invalid_infrared_brightness(hass: HomeAssistant) -> None: async def test_invalid_infrared_brightness(hass: HomeAssistant) -> None:
"""Test getting and setting infrared brightness.""" """Test getting and setting infrared brightness."""
@ -273,7 +280,7 @@ async def test_invalid_infrared_brightness(hass: HomeAssistant) -> None:
bulb.get_infrared = MockLifxCommand(bulb, infrared_brightness=12345) bulb.get_infrared = MockLifxCommand(bulb, infrared_brightness=12345)
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
assert state.state == STATE_UNKNOWN assert state.state == STATE_UNKNOWN

View file

@ -73,7 +73,7 @@ async def test_sensor_updating(
async def skip_time_and_check_events() -> None: async def skip_time_and_check_events() -> None:
freezer.tick(timedelta(minutes=15)) freezer.tick(timedelta(minutes=15))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert events == snapshot assert events == snapshot

View file

@ -275,7 +275,7 @@ async def test_coordinator_error(
ourgroceries.get_list_items.side_effect = exception ourgroceries.get_list_items.side_effect = exception
freezer.tick(SCAN_INTERVAL) freezer.tick(SCAN_INTERVAL)
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("todo.test_list") state = hass.states.get("todo.test_list")
assert state.state == STATE_UNAVAILABLE assert state.state == STATE_UNAVAILABLE

View file

@ -223,7 +223,7 @@ async def test_reauth(
# check reauth trigger with bad-auth responses # check reauth trigger with bad-auth responses
freezer.move_to(_MOCK_TIME_BAD_AUTH_RESPONSES) freezer.move_to(_MOCK_TIME_BAD_AUTH_RESPONSES)
async_fire_time_changed(hass, _MOCK_TIME_BAD_AUTH_RESPONSES) async_fire_time_changed(hass, _MOCK_TIME_BAD_AUTH_RESPONSES)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert pvpc_aioclient_mock.call_count == 6 assert pvpc_aioclient_mock.call_count == 6
result = hass.config_entries.flow.async_progress_by_handler(DOMAIN)[0] result = hass.config_entries.flow.async_progress_by_handler(DOMAIN)[0]
@ -252,5 +252,5 @@ async def test_reauth(
assert result["reason"] == "reauth_successful" assert result["reason"] == "reauth_successful"
assert pvpc_aioclient_mock.call_count == 8 assert pvpc_aioclient_mock.call_count == 8
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert pvpc_aioclient_mock.call_count == 10 assert pvpc_aioclient_mock.call_count == 10

View file

@ -178,7 +178,7 @@ async def test_setup(hass: HomeAssistant, freezer: FrozenDateTimeFactory) -> Non
# so no changes to entities. # so no changes to entities.
mock_feed_update.return_value = "OK_NO_DATA", None mock_feed_update.return_value = "OK_NO_DATA", None
async_fire_time_changed(hass, utcnow + 2 * SCAN_INTERVAL) async_fire_time_changed(hass, utcnow + 2 * SCAN_INTERVAL)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
all_states = hass.states.async_all() all_states = hass.states.async_all()
assert len(all_states) == 3 assert len(all_states) == 3
@ -186,7 +186,7 @@ async def test_setup(hass: HomeAssistant, freezer: FrozenDateTimeFactory) -> Non
# Simulate an update - empty data, removes all entities # Simulate an update - empty data, removes all entities
mock_feed_update.return_value = "ERROR", None mock_feed_update.return_value = "ERROR", None
async_fire_time_changed(hass, utcnow + 3 * SCAN_INTERVAL) async_fire_time_changed(hass, utcnow + 3 * SCAN_INTERVAL)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
all_states = hass.states.async_all() all_states = hass.states.async_all()
assert len(all_states) == 0 assert len(all_states) == 0

View file

@ -103,7 +103,7 @@ async def test_coordinator_client_connector_error(
mock_system_sensor.side_effect = QswError mock_system_sensor.side_effect = QswError
freezer.tick(DATA_SCAN_INTERVAL) freezer.tick(DATA_SCAN_INTERVAL)
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
mock_system_sensor.assert_called_once() mock_system_sensor.assert_called_once()
mock_users_verification.assert_called() mock_users_verification.assert_called()
@ -115,7 +115,7 @@ async def test_coordinator_client_connector_error(
mock_firmware_update_check.side_effect = APIError mock_firmware_update_check.side_effect = APIError
freezer.tick(FW_SCAN_INTERVAL) freezer.tick(FW_SCAN_INTERVAL)
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
mock_firmware_update_check.assert_called_once() mock_firmware_update_check.assert_called_once()
mock_firmware_update_check.reset_mock() mock_firmware_update_check.reset_mock()
@ -123,7 +123,7 @@ async def test_coordinator_client_connector_error(
mock_firmware_update_check.side_effect = QswError mock_firmware_update_check.side_effect = QswError
freezer.tick(FW_SCAN_INTERVAL) freezer.tick(FW_SCAN_INTERVAL)
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
mock_firmware_update_check.assert_called_once() mock_firmware_update_check.assert_called_once()

View file

@ -147,7 +147,7 @@ async def test_auth_failure_on_device_update(
side_effect=AuthenticationError, side_effect=AuthenticationError,
): ):
async_fire_time_changed(hass, dt_util.now() + timedelta(minutes=20)) async_fire_time_changed(hass, dt_util.now() + timedelta(minutes=20))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert "Authentication failed while fetching devices data: " in [ assert "Authentication failed while fetching devices data: " in [
record.message record.message
@ -191,7 +191,7 @@ async def test_error_on_global_update(
side_effect=error_type, side_effect=error_type,
): ):
async_fire_time_changed(hass, dt_util.now() + timedelta(minutes=20)) async_fire_time_changed(hass, dt_util.now() + timedelta(minutes=20))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert log_msg in [ assert log_msg in [
record.message for record in caplog.records if record.levelname == "ERROR" record.message for record in caplog.records if record.levelname == "ERROR"
@ -232,7 +232,7 @@ async def test_error_on_device_update(
side_effect=error_type, side_effect=error_type,
): ):
async_fire_time_changed(hass, dt_util.now() + timedelta(minutes=20)) async_fire_time_changed(hass, dt_util.now() + timedelta(minutes=20))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert log_msg in [ assert log_msg in [
record.message for record in caplog.records if record.levelname == "ERROR" record.message for record in caplog.records if record.levelname == "ERROR"

View file

@ -326,7 +326,7 @@ async def test_update_off_ws_with_power_state(
next_update = mock_now + timedelta(minutes=1) next_update = mock_now + timedelta(minutes=1)
freezer.move_to(next_update) freezer.move_to(next_update)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
remotews.start_listening.assert_called_once() remotews.start_listening.assert_called_once()
rest_api.rest_device_info.assert_called_once() rest_api.rest_device_info.assert_called_once()
@ -342,7 +342,7 @@ async def test_update_off_ws_with_power_state(
next_update = mock_now + timedelta(minutes=2) next_update = mock_now + timedelta(minutes=2)
freezer.move_to(next_update) freezer.move_to(next_update)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
rest_api.rest_device_info.assert_called_once() rest_api.rest_device_info.assert_called_once()
@ -355,7 +355,7 @@ async def test_update_off_ws_with_power_state(
next_update = mock_now + timedelta(minutes=3) next_update = mock_now + timedelta(minutes=3)
freezer.move_to(next_update) freezer.move_to(next_update)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
rest_api.rest_device_info.assert_called_once() rest_api.rest_device_info.assert_called_once()
@ -386,7 +386,7 @@ async def test_update_off_encryptedws(
next_update = mock_now + timedelta(minutes=5) next_update = mock_now + timedelta(minutes=5)
freezer.move_to(next_update) freezer.move_to(next_update)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID) state = hass.states.get(ENTITY_ID)
assert state.state == STATE_OFF assert state.state == STATE_OFF
@ -407,12 +407,12 @@ async def test_update_access_denied(
next_update = mock_now + timedelta(minutes=5) next_update = mock_now + timedelta(minutes=5)
freezer.move_to(next_update) freezer.move_to(next_update)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
next_update = mock_now + timedelta(minutes=10) next_update = mock_now + timedelta(minutes=10)
freezer.move_to(next_update) freezer.move_to(next_update)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert [ assert [
flow flow
@ -442,7 +442,7 @@ async def test_update_ws_connection_failure(
next_update = mock_now + timedelta(minutes=5) next_update = mock_now + timedelta(minutes=5)
freezer.move_to(next_update) freezer.move_to(next_update)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert ( assert (
"Unexpected ConnectionFailure trying to get remote for fake_host, please " "Unexpected ConnectionFailure trying to get remote for fake_host, please "
@ -470,7 +470,7 @@ async def test_update_ws_connection_closed(
next_update = mock_now + timedelta(minutes=5) next_update = mock_now + timedelta(minutes=5)
freezer.move_to(next_update) freezer.move_to(next_update)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID) state = hass.states.get(ENTITY_ID)
assert state.state == STATE_OFF assert state.state == STATE_OFF
@ -492,7 +492,7 @@ async def test_update_ws_unauthorized_error(
next_update = mock_now + timedelta(minutes=5) next_update = mock_now + timedelta(minutes=5)
freezer.move_to(next_update) freezer.move_to(next_update)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert [ assert [
flow flow
@ -517,7 +517,7 @@ async def test_update_unhandled_response(
next_update = mock_now + timedelta(minutes=5) next_update = mock_now + timedelta(minutes=5)
freezer.move_to(next_update) freezer.move_to(next_update)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID) state = hass.states.get(ENTITY_ID)
assert state.state == STATE_ON assert state.state == STATE_ON
@ -537,7 +537,7 @@ async def test_connection_closed_during_update_can_recover(
next_update = mock_now + timedelta(minutes=5) next_update = mock_now + timedelta(minutes=5)
freezer.move_to(next_update) freezer.move_to(next_update)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID) state = hass.states.get(ENTITY_ID)
assert state.state == STATE_UNAVAILABLE assert state.state == STATE_UNAVAILABLE
@ -545,7 +545,7 @@ async def test_connection_closed_during_update_can_recover(
next_update = mock_now + timedelta(minutes=10) next_update = mock_now + timedelta(minutes=10)
freezer.move_to(next_update) freezer.move_to(next_update)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID) state = hass.states.get(ENTITY_ID)
assert state.state == STATE_ON assert state.state == STATE_ON
@ -705,7 +705,7 @@ async def test_state(hass: HomeAssistant, freezer: FrozenDateTimeFactory) -> Non
): ):
freezer.move_to(next_update) freezer.move_to(next_update)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID) state = hass.states.get(ENTITY_ID)
# Should be STATE_UNAVAILABLE since there is no way to turn it back on # Should be STATE_UNAVAILABLE since there is no way to turn it back on
@ -1444,7 +1444,7 @@ async def test_upnp_re_subscribe_events(
next_update = mock_now + timedelta(minutes=5) next_update = mock_now + timedelta(minutes=5)
freezer.move_to(next_update) freezer.move_to(next_update)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID) state = hass.states.get(ENTITY_ID)
assert state.state == STATE_OFF assert state.state == STATE_OFF
@ -1454,7 +1454,7 @@ async def test_upnp_re_subscribe_events(
next_update = mock_now + timedelta(minutes=10) next_update = mock_now + timedelta(minutes=10)
freezer.move_to(next_update) freezer.move_to(next_update)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID) state = hass.states.get(ENTITY_ID)
assert state.state == STATE_ON assert state.state == STATE_ON
@ -1490,7 +1490,7 @@ async def test_upnp_failed_re_subscribe_events(
next_update = mock_now + timedelta(minutes=5) next_update = mock_now + timedelta(minutes=5)
freezer.move_to(next_update) freezer.move_to(next_update)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID) state = hass.states.get(ENTITY_ID)
assert state.state == STATE_OFF assert state.state == STATE_OFF
@ -1501,7 +1501,7 @@ async def test_upnp_failed_re_subscribe_events(
with patch.object(dmr_device, "async_subscribe_services", side_effect=error): with patch.object(dmr_device, "async_subscribe_services", side_effect=error):
freezer.move_to(next_update) freezer.move_to(next_update)
async_fire_time_changed(hass, next_update) async_fire_time_changed(hass, next_update)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID) state = hass.states.get(ENTITY_ID)
assert state.state == STATE_ON assert state.state == STATE_ON

View file

@ -139,15 +139,15 @@ async def _setup_seventeentrack(hass, config=None, summary_data=None):
await hass.async_block_till_done() await hass.async_block_till_done()
async def _goto_future(hass, future=None): async def _goto_future(hass: HomeAssistant, future=None):
"""Move to future.""" """Move to future."""
if not future: if not future:
future = utcnow() + datetime.timedelta(minutes=10) future = utcnow() + datetime.timedelta(minutes=10)
with patch("homeassistant.util.utcnow", return_value=future): with patch("homeassistant.util.utcnow", return_value=future):
async_fire_time_changed(hass, future) async_fire_time_changed(hass, future)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
async_fire_time_changed(hass, future) async_fire_time_changed(hass, future)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
async def test_full_valid_config(hass: HomeAssistant) -> None: async def test_full_valid_config(hass: HomeAssistant) -> None:

View file

@ -64,7 +64,7 @@ async def test_switch_get_states(hass: HomeAssistant, mock_asyncsleepiq) -> None
mock_asyncsleepiq.beds[BED_ID].foundation.lights[0].is_on = True mock_asyncsleepiq.beds[BED_ID].foundation.lights[0].is_on = True
async_fire_time_changed(hass, utcnow() + LONGER_UPDATE_INTERVAL) async_fire_time_changed(hass, utcnow() + LONGER_UPDATE_INTERVAL)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert ( assert (
hass.states.get(f"light.sleepnumber_{BED_NAME_LOWER}_light_1").state == STATE_ON hass.states.get(f"light.sleepnumber_{BED_NAME_LOWER}_light_1").state == STATE_ON

View file

@ -59,7 +59,7 @@ async def test_switch_get_states(hass: HomeAssistant, mock_asyncsleepiq) -> None
mock_asyncsleepiq.beds[BED_ID].paused = True mock_asyncsleepiq.beds[BED_ID].paused = True
async_fire_time_changed(hass, utcnow() + LONGER_UPDATE_INTERVAL) async_fire_time_changed(hass, utcnow() + LONGER_UPDATE_INTERVAL)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert ( assert (
hass.states.get(f"switch.sleepnumber_{BED_NAME_LOWER}_pause_mode").state hass.states.get(f"switch.sleepnumber_{BED_NAME_LOWER}_pause_mode").state

View file

@ -3,13 +3,14 @@
from datetime import timedelta from datetime import timedelta
from homeassistant.components.smarttub.const import SCAN_INTERVAL from homeassistant.components.smarttub.const import SCAN_INTERVAL
from homeassistant.core import HomeAssistant
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from tests.common import async_fire_time_changed from tests.common import async_fire_time_changed
async def trigger_update(hass): async def trigger_update(hass: HomeAssistant) -> None:
"""Trigger a polling update by moving time forward.""" """Trigger a polling update by moving time forward."""
new_time = dt_util.utcnow() + timedelta(seconds=SCAN_INTERVAL + 1) new_time = dt_util.utcnow() + timedelta(seconds=SCAN_INTERVAL + 1)
async_fire_time_changed(hass, new_time) async_fire_time_changed(hass, new_time)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)

View file

@ -248,7 +248,7 @@ async def test_invalid_url_on_update(
hass, hass,
dt_util.utcnow() + timedelta(minutes=1), dt_util.utcnow() + timedelta(minutes=1),
) )
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert "sqlite://****:****@homeassistant.local" in caplog.text assert "sqlite://****:****@homeassistant.local" in caplog.text
@ -287,7 +287,7 @@ async def test_templates_with_yaml(
hass, hass,
dt_util.utcnow() + timedelta(minutes=1), dt_util.utcnow() + timedelta(minutes=1),
) )
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.get_values_with_template") state = hass.states.get("sensor.get_values_with_template")
assert state.state == "5" assert state.state == "5"
@ -301,7 +301,7 @@ async def test_templates_with_yaml(
hass, hass,
dt_util.utcnow() + timedelta(minutes=2), dt_util.utcnow() + timedelta(minutes=2),
) )
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.get_values_with_template") state = hass.states.get("sensor.get_values_with_template")
assert state.state == STATE_UNAVAILABLE assert state.state == STATE_UNAVAILABLE
@ -314,7 +314,7 @@ async def test_templates_with_yaml(
hass, hass,
dt_util.utcnow() + timedelta(minutes=3), dt_util.utcnow() + timedelta(minutes=3),
) )
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.get_values_with_template") state = hass.states.get("sensor.get_values_with_template")
assert state.state == "5" assert state.state == "5"
@ -488,7 +488,7 @@ async def test_no_issue_when_view_has_the_text_entity_id_in_it(
hass, hass,
dt_util.utcnow() + timedelta(minutes=1), dt_util.utcnow() + timedelta(minutes=1),
) )
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert ( assert (
"Query contains entity_id but does not reference states_meta" not in caplog.text "Query contains entity_id but does not reference states_meta" not in caplog.text
@ -622,7 +622,7 @@ async def test_query_recover_from_rollback(
): ):
freezer.tick(timedelta(minutes=1)) freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert "sqlite3.OperationalError" in caplog.text assert "sqlite3.OperationalError" in caplog.text
state = hass.states.get("sensor.select_value_sql_query") state = hass.states.get("sensor.select_value_sql_query")
@ -631,7 +631,7 @@ async def test_query_recover_from_rollback(
freezer.tick(timedelta(minutes=1)) freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.select_value_sql_query") state = hass.states.get("sensor.select_value_sql_query")
assert state.state == "5" assert state.state == "5"

View file

@ -5,6 +5,7 @@ from __future__ import annotations
from unittest.mock import AsyncMock, MagicMock, patch from unittest.mock import AsyncMock, MagicMock, patch
from discovery30303 import AIODiscovery30303 from discovery30303 import AIODiscovery30303
from freezegun.api import FrozenDateTimeFactory
import pytest import pytest
from homeassistant.components import steamist from homeassistant.components import steamist
@ -113,7 +114,9 @@ async def test_config_entry_fills_unique_id_with_directed_discovery(
@pytest.mark.usefixtures("mock_single_broadcast_address") @pytest.mark.usefixtures("mock_single_broadcast_address")
async def test_discovery_happens_at_interval(hass: HomeAssistant) -> None: async def test_discovery_happens_at_interval(
hass: HomeAssistant, freezer: FrozenDateTimeFactory
) -> None:
"""Test that discovery happens at interval.""" """Test that discovery happens at interval."""
config_entry = MockConfigEntry( config_entry = MockConfigEntry(
domain=DOMAIN, data=DEFAULT_ENTRY_DATA, unique_id=FORMATTED_MAC_ADDRESS domain=DOMAIN, data=DEFAULT_ENTRY_DATA, unique_id=FORMATTED_MAC_ADDRESS
@ -126,10 +129,11 @@ async def test_discovery_happens_at_interval(hass: HomeAssistant) -> None:
return_value=mock_aio_discovery, return_value=mock_aio_discovery,
), _patch_status(MOCK_ASYNC_GET_STATUS_ACTIVE): ), _patch_status(MOCK_ASYNC_GET_STATUS_ACTIVE):
await async_setup_component(hass, steamist.DOMAIN, {steamist.DOMAIN: {}}) await async_setup_component(hass, steamist.DOMAIN, {steamist.DOMAIN: {}})
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert len(mock_aio_discovery.async_scan.mock_calls) == 2 assert len(mock_aio_discovery.async_scan.mock_calls) == 2
async_fire_time_changed(hass, utcnow() + steamist.DISCOVERY_INTERVAL) freezer.move_to(utcnow() + steamist.DISCOVERY_INTERVAL)
await hass.async_block_till_done() async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
assert len(mock_aio_discovery.async_scan.mock_calls) == 3 assert len(mock_aio_discovery.async_scan.mock_calls) == 3

View file

@ -6,6 +6,7 @@ import copy
from datetime import timedelta from datetime import timedelta
from unittest.mock import AsyncMock, MagicMock, patch from unittest.mock import AsyncMock, MagicMock, patch
from freezegun.api import FrozenDateTimeFactory
from kasa.exceptions import AuthenticationException from kasa.exceptions import AuthenticationException
import pytest import pytest
@ -41,23 +42,28 @@ from . import (
from tests.common import MockConfigEntry, async_fire_time_changed from tests.common import MockConfigEntry, async_fire_time_changed
async def test_configuring_tplink_causes_discovery(hass: HomeAssistant) -> None: async def test_configuring_tplink_causes_discovery(
hass: HomeAssistant, freezer: FrozenDateTimeFactory
) -> None:
"""Test that specifying empty config does discovery.""" """Test that specifying empty config does discovery."""
with patch("homeassistant.components.tplink.Discover.discover") as discover, patch( with patch("homeassistant.components.tplink.Discover.discover") as discover, patch(
"homeassistant.components.tplink.Discover.discover_single" "homeassistant.components.tplink.Discover.discover_single"
): ):
discover.return_value = {MagicMock(): MagicMock()} discover.return_value = {MagicMock(): MagicMock()}
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}}) await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
# call_count will differ based on number of broadcast addresses
call_count = len(discover.mock_calls) call_count = len(discover.mock_calls)
assert discover.mock_calls assert discover.mock_calls
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=15)) freezer.tick(tplink.DISCOVERY_INTERVAL)
await hass.async_block_till_done() async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
assert len(discover.mock_calls) == call_count * 2 assert len(discover.mock_calls) == call_count * 2
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=30)) freezer.tick(tplink.DISCOVERY_INTERVAL)
await hass.async_block_till_done() async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
assert len(discover.mock_calls) == call_count * 3 assert len(discover.mock_calls) == call_count * 3

View file

@ -1118,7 +1118,7 @@ async def test_elec_measurement_sensor_polling(
# let the polling happen # let the polling happen
future = dt_util.utcnow() + timedelta(seconds=90) future = dt_util.utcnow() + timedelta(seconds=90)
async_fire_time_changed(hass, future) async_fire_time_changed(hass, future)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
# ensure the state has been updated to 6.0 # ensure the state has been updated to 6.0
state = hass.states.get(entity_id) state = hass.states.get(entity_id)

View file

@ -72,7 +72,7 @@ async def test_polling_only_updates_entities_it_should_poll(
poll_ent.async_update.reset_mock() poll_ent.async_update.reset_mock()
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=20)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=20))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert not no_poll_ent.async_update.called assert not no_poll_ent.async_update.called
assert poll_ent.async_update.called assert poll_ent.async_update.called
@ -121,7 +121,7 @@ async def test_polling_updates_entities_with_exception(hass: HomeAssistant) -> N
update_err.clear() update_err.clear()
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=20)) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=20))
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert len(update_ok) == 3 assert len(update_ok) == 3
assert len(update_err) == 1 assert len(update_err) == 1
@ -140,7 +140,7 @@ async def test_update_state_adds_entities(hass: HomeAssistant) -> None:
ent2.update = lambda *_: component.add_entities([ent1]) ent2.update = lambda *_: component.add_entities([ent1])
async_fire_time_changed(hass, dt_util.utcnow() + DEFAULT_SCAN_INTERVAL) async_fire_time_changed(hass, dt_util.utcnow() + DEFAULT_SCAN_INTERVAL)
await hass.async_block_till_done() await hass.async_block_till_done(wait_background_tasks=True)
assert len(hass.states.async_entity_ids()) == 2 assert len(hass.states.async_entity_ids()) == 2

View file

@ -4330,12 +4330,6 @@ async def test_task_tracking(hass: HomeAssistant) -> None:
entry.async_create_background_task( entry.async_create_background_task(
hass, test_task(), "background-task-name", eager_start=False hass, test_task(), "background-task-name", eager_start=False
) )
entry.async_create_periodic_task(
hass, test_task(), "periodic-task-name", eager_start=False
)
entry.async_create_periodic_task(
hass, test_task(), "periodic-task-name", eager_start=True
)
await asyncio.sleep(0) await asyncio.sleep(0)
hass.loop.call_soon(event.set) hass.loop.call_soon(event.set)
await entry._async_process_on_unload(hass) await entry._async_process_on_unload(hass)
@ -4343,8 +4337,6 @@ async def test_task_tracking(hass: HomeAssistant) -> None:
"on_unload", "on_unload",
"background", "background",
"background", "background",
"background",
"background",
"normal", "normal",
] ]

View file

@ -57,6 +57,7 @@ from homeassistant.exceptions import (
ServiceNotFound, ServiceNotFound,
) )
from homeassistant.helpers.json import json_dumps from homeassistant.helpers.json import json_dumps
from homeassistant.util.async_ import create_eager_task
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from homeassistant.util.read_only_dict import ReadOnlyDict from homeassistant.util.read_only_dict import ReadOnlyDict
from homeassistant.util.unit_system import METRIC_SYSTEM from homeassistant.util.unit_system import METRIC_SYSTEM
@ -97,6 +98,134 @@ async def test_async_add_hass_job_schedule_callback() -> None:
assert len(hass.add_job.mock_calls) == 0 assert len(hass.add_job.mock_calls) == 0
async def test_async_add_hass_job_eager_start_coro_suspends(
hass: HomeAssistant,
) -> None:
"""Test scheduling a coro as a task that will suspend with eager_start."""
async def job_that_suspends():
await asyncio.sleep(0)
task = hass.async_add_hass_job(
ha.HassJob(ha.callback(job_that_suspends)), eager_start=True
)
assert not task.done()
assert task in hass._tasks
await task
assert task not in hass._tasks
async def test_async_run_hass_job_eager_start_coro_suspends(
hass: HomeAssistant,
) -> None:
"""Test scheduling a coro as a task that will suspend with eager_start."""
async def job_that_suspends():
await asyncio.sleep(0)
task = hass.async_run_hass_job(
ha.HassJob(ha.callback(job_that_suspends)), eager_start=True
)
assert not task.done()
assert task in hass._tasks
await task
assert task not in hass._tasks
async def test_async_add_hass_job_background(hass: HomeAssistant) -> None:
"""Test scheduling a coro as a background task with async_add_hass_job."""
async def job_that_suspends():
await asyncio.sleep(0)
task = hass.async_add_hass_job(
ha.HassJob(ha.callback(job_that_suspends)), background=True
)
assert not task.done()
assert task in hass._background_tasks
await task
assert task not in hass._background_tasks
async def test_async_run_hass_job_background(hass: HomeAssistant) -> None:
"""Test scheduling a coro as a background task with async_run_hass_job."""
async def job_that_suspends():
await asyncio.sleep(0)
task = hass.async_run_hass_job(
ha.HassJob(ha.callback(job_that_suspends)), background=True
)
assert not task.done()
assert task in hass._background_tasks
await task
assert task not in hass._background_tasks
async def test_async_add_hass_job_eager_background(hass: HomeAssistant) -> None:
"""Test scheduling a coro as an eager background task with async_add_hass_job."""
async def job_that_suspends():
await asyncio.sleep(0)
task = hass.async_add_hass_job(
ha.HassJob(ha.callback(job_that_suspends)), eager_start=True, background=True
)
assert not task.done()
assert task in hass._background_tasks
await task
assert task not in hass._background_tasks
async def test_async_run_hass_job_eager_background(hass: HomeAssistant) -> None:
"""Test scheduling a coro as an eager background task with async_run_hass_job."""
async def job_that_suspends():
await asyncio.sleep(0)
task = hass.async_run_hass_job(
ha.HassJob(ha.callback(job_that_suspends)), eager_start=True, background=True
)
assert not task.done()
assert task in hass._background_tasks
await task
assert task not in hass._background_tasks
async def test_async_run_hass_job_background_synchronous(hass: HomeAssistant) -> None:
"""Test scheduling a coro as an eager background task with async_run_hass_job."""
async def job_that_does_not_suspends():
pass
task = hass.async_run_hass_job(
ha.HassJob(ha.callback(job_that_does_not_suspends)),
eager_start=True,
background=True,
)
assert task.done()
assert task not in hass._background_tasks
assert task not in hass._tasks
await task
async def test_async_run_hass_job_synchronous(hass: HomeAssistant) -> None:
"""Test scheduling a coro as an eager task with async_run_hass_job."""
async def job_that_does_not_suspends():
pass
task = hass.async_run_hass_job(
ha.HassJob(ha.callback(job_that_does_not_suspends)),
eager_start=True,
background=False,
)
assert task.done()
assert task not in hass._background_tasks
assert task not in hass._tasks
await task
async def test_async_add_hass_job_coro_named(hass: HomeAssistant) -> None: async def test_async_add_hass_job_coro_named(hass: HomeAssistant) -> None:
"""Test that we schedule coroutines and add jobs to the job pool with a name.""" """Test that we schedule coroutines and add jobs to the job pool with a name."""
@ -110,6 +239,19 @@ async def test_async_add_hass_job_coro_named(hass: HomeAssistant) -> None:
assert "named coro" in str(task) assert "named coro" in str(task)
async def test_async_add_hass_job_eager_start(hass: HomeAssistant) -> None:
"""Test eager_start with async_add_hass_job."""
async def mycoro():
pass
job = ha.HassJob(mycoro, "named coro")
assert "named coro" in str(job)
assert job.name == "named coro"
task = ha.HomeAssistant.async_add_hass_job(hass, job, eager_start=True)
assert "named coro" in str(task)
async def test_async_add_hass_job_schedule_partial_callback() -> None: async def test_async_add_hass_job_schedule_partial_callback() -> None:
"""Test that we schedule partial coros and add jobs to the job pool.""" """Test that we schedule partial coros and add jobs to the job pool."""
hass = MagicMock() hass = MagicMock()
@ -135,6 +277,24 @@ async def test_async_add_hass_job_schedule_coroutinefunction() -> None:
assert len(hass.add_job.mock_calls) == 0 assert len(hass.add_job.mock_calls) == 0
async def test_async_add_hass_job_schedule_corofunction_eager_start() -> None:
"""Test that we schedule coroutines and add jobs to the job pool."""
hass = MagicMock(loop=MagicMock(wraps=asyncio.get_running_loop()))
async def job():
pass
with patch(
"homeassistant.core.create_eager_task", wraps=create_eager_task
) as mock_create_eager_task:
hass_job = ha.HassJob(job)
task = ha.HomeAssistant.async_add_hass_job(hass, hass_job, eager_start=True)
assert len(hass.loop.call_soon.mock_calls) == 0
assert len(hass.add_job.mock_calls) == 0
assert mock_create_eager_task.mock_calls
await task
async def test_async_add_hass_job_schedule_partial_coroutinefunction() -> None: async def test_async_add_hass_job_schedule_partial_coroutinefunction() -> None:
"""Test that we schedule partial coros and add jobs to the job pool.""" """Test that we schedule partial coros and add jobs to the job pool."""
hass = MagicMock(loop=MagicMock(wraps=asyncio.get_running_loop())) hass = MagicMock(loop=MagicMock(wraps=asyncio.get_running_loop()))
@ -224,7 +384,7 @@ async def test_async_create_task_schedule_coroutine_with_name() -> None:
assert "named task" in str(task) assert "named task" in str(task)
async def test_async_run_periodic_hass_job_calls_callback() -> None: async def test_async_run_eager_hass_job_calls_callback() -> None:
"""Test that the callback annotation is respected.""" """Test that the callback annotation is respected."""
hass = MagicMock() hass = MagicMock()
calls = [] calls = []
@ -233,36 +393,21 @@ async def test_async_run_periodic_hass_job_calls_callback() -> None:
asyncio.get_running_loop() # ensure we are in the event loop asyncio.get_running_loop() # ensure we are in the event loop
calls.append(1) calls.append(1)
ha.HomeAssistant.async_run_periodic_hass_job(hass, ha.HassJob(ha.callback(job))) ha.HomeAssistant.async_run_hass_job(
hass, ha.HassJob(ha.callback(job)), eager_start=True
)
assert len(calls) == 1 assert len(calls) == 1
async def test_async_run_periodic_hass_job_calls_coro_function() -> None: async def test_async_run_eager_hass_job_calls_coro_function() -> None:
"""Test running coros from async_run_periodic_hass_job.""" """Test running coros from async_run_hass_job with eager_start."""
hass = MagicMock() hass = MagicMock()
calls = []
async def job(): async def job():
calls.append(1) pass
await ha.HomeAssistant.async_run_periodic_hass_job(hass, ha.HassJob(job)) ha.HomeAssistant.async_run_hass_job(hass, ha.HassJob(job), eager_start=True)
assert len(calls) == 1 assert len(hass.async_add_hass_job.mock_calls) == 1
async def test_async_run_periodic_hass_job_calls_executor_function() -> None:
"""Test running in the executor from async_run_periodic_hass_job."""
hass = MagicMock()
hass.loop = asyncio.get_running_loop()
calls = []
def job():
try:
asyncio.get_running_loop() # ensure we are not in the event loop
except RuntimeError:
calls.append(1)
await ha.HomeAssistant.async_run_periodic_hass_job(hass, ha.HassJob(job))
assert len(calls) == 1
async def test_async_run_hass_job_calls_callback() -> None: async def test_async_run_hass_job_calls_callback() -> None:
@ -556,7 +701,7 @@ async def test_shutdown_calls_block_till_done_after_shutdown_run_callback_thread
"""Ensure shutdown_run_callback_threadsafe is called before the final async_block_till_done.""" """Ensure shutdown_run_callback_threadsafe is called before the final async_block_till_done."""
stop_calls = [] stop_calls = []
async def _record_block_till_done(wait_periodic_tasks: bool = True): async def _record_block_till_done(wait_background_tasks: bool = False):
nonlocal stop_calls nonlocal stop_calls
stop_calls.append("async_block_till_done") stop_calls.append("async_block_till_done")
@ -2142,7 +2287,7 @@ async def test_chained_logging_hits_log_timeout(
with patch.object(ha, "BLOCK_LOG_TIMEOUT", 0.0): with patch.object(ha, "BLOCK_LOG_TIMEOUT", 0.0):
hass.async_create_task(_task_chain_1()) hass.async_create_task(_task_chain_1())
await hass.async_block_till_done(wait_periodic_tasks=False) await hass.async_block_till_done(wait_background_tasks=False)
assert "_task_chain_" in caplog.text assert "_task_chain_" in caplog.text
@ -2696,27 +2841,6 @@ async def test_background_task(hass: HomeAssistant, eager_start: bool) -> None:
assert result.result() == ha.CoreState.stopping assert result.result() == ha.CoreState.stopping
@pytest.mark.parametrize("eager_start", (True, False))
async def test_periodic_task(hass: HomeAssistant, eager_start: bool) -> None:
"""Test periodic tasks being quit."""
result = asyncio.Future()
async def test_task():
try:
await asyncio.sleep(1)
except asyncio.CancelledError:
result.set_result(hass.state)
raise
task = hass.async_create_periodic_task(
test_task(), "happy task", eager_start=eager_start
)
assert "happy task" in str(task)
await asyncio.sleep(0)
await hass.async_stop()
assert result.result() == ha.CoreState.stopping
async def test_shutdown_does_not_block_on_normal_tasks( async def test_shutdown_does_not_block_on_normal_tasks(
hass: HomeAssistant, hass: HomeAssistant,
) -> None: ) -> None:
@ -2767,14 +2891,15 @@ async def test_shutdown_does_not_block_on_shielded_tasks(
sleep_task.cancel() sleep_task.cancel()
async def test_cancellable_hassjob(hass: HomeAssistant) -> None: @pytest.mark.parametrize("eager_start", (True, False))
async def test_cancellable_hassjob(hass: HomeAssistant, eager_start: bool) -> None:
"""Simulate a shutdown, ensure cancellable jobs are cancelled.""" """Simulate a shutdown, ensure cancellable jobs are cancelled."""
job = MagicMock() job = MagicMock()
@ha.callback @ha.callback
def run_job(job: HassJob) -> None: def run_job(job: HassJob) -> None:
"""Call the action.""" """Call the action."""
hass.async_run_hass_job(job) hass.async_run_hass_job(job, eager_start=True)
timer1 = hass.loop.call_later( timer1 = hass.loop.call_later(
60, run_job, HassJob(ha.callback(job), cancel_on_shutdown=True) 60, run_job, HassJob(ha.callback(job), cancel_on_shutdown=True)