Use eventloop for scheduling (#37184)

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
J. Nick Koston 2020-06-29 11:39:24 -05:00 committed by GitHub
parent 0f72008090
commit 89a9634d35
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 366 additions and 272 deletions

View file

@ -31,8 +31,7 @@ from homeassistant.const import (
SUN_EVENT_SUNRISE,
SUN_EVENT_SUNSET,
)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.event import async_track_time_interval
from homeassistant.helpers import config_validation as cv, event
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.sun import get_astral_event_date
from homeassistant.util import slugify
@ -224,7 +223,7 @@ class FluxSwitch(SwitchEntity, RestoreEntity):
if self.is_on:
return
self.unsub_tracker = async_track_time_interval(
self.unsub_tracker = event.async_track_time_interval(
self.hass,
self.async_flux_update,
datetime.timedelta(seconds=self._interval),

View file

@ -17,12 +17,8 @@ from homeassistant.const import (
STATE_UNKNOWN,
)
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers import config_validation as cv, event
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import (
async_track_point_in_utc_time,
async_track_state_change,
)
from homeassistant.util import dt as dt_util
_LOGGER = logging.getLogger(__name__)
@ -116,11 +112,11 @@ class StatisticsSensor(Entity):
self.async_schedule_update_ha_state(True)
@callback
def async_stats_sensor_startup(event):
def async_stats_sensor_startup(_):
"""Add listener and get recorded state."""
_LOGGER.debug("Startup for %s", self.entity_id)
async_track_state_change(
event.async_track_state_change(
self.hass, self._entity_id, async_stats_sensor_state_listener
)
@ -296,7 +292,7 @@ class StatisticsSensor(Entity):
self.async_schedule_update_ha_state(True)
self._update_listener = None
self._update_listener = async_track_point_in_utc_time(
self._update_listener = event.async_track_point_in_utc_time(
self.hass, _scheduled_update, next_to_purge_timestamp
)

View file

@ -9,8 +9,8 @@ from homeassistant.const import (
SUN_EVENT_SUNSET,
)
from homeassistant.core import callback
from homeassistant.helpers import event
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.helpers.sun import (
get_astral_location,
get_location_astral_event_next,
@ -99,7 +99,7 @@ class Sun(Entity):
self.rising = self.phase = None
self._next_change = None
def update_location(event):
def update_location(_event):
self.location = get_astral_location(self.hass)
self.update_events(dt_util.utcnow())
@ -135,9 +135,9 @@ class Sun(Entity):
STATE_ATTR_RISING: self.rising,
}
def _check_event(self, utc_point_in_time, event, before):
def _check_event(self, utc_point_in_time, sun_event, before):
next_utc = get_location_astral_event_next(
self.location, event, utc_point_in_time
self.location, sun_event, utc_point_in_time
)
if next_utc < self._next_change:
self._next_change = next_utc
@ -207,7 +207,9 @@ class Sun(Entity):
self.update_sun_position(utc_point_in_time)
# Set timer for the next solar event
async_track_point_in_utc_time(self.hass, self.update_events, self._next_change)
event.async_track_point_in_utc_time(
self.hass, self.update_events, self._next_change
)
_LOGGER.debug("next time: %s", self._next_change.isoformat())
@callback
@ -232,6 +234,6 @@ class Sun(Entity):
# position update just drop it
if utc_point_in_time + delta * 1.25 > self._next_change:
return
async_track_point_in_utc_time(
event.async_track_point_in_utc_time(
self.hass, self.update_sun_position, utc_point_in_time + delta
)

View file

@ -14,8 +14,7 @@ from homeassistant.const import (
SUN_EVENT_SUNSET,
)
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.helpers import config_validation as cv, event
from homeassistant.helpers.sun import get_astral_event_date, get_astral_event_next
from homeassistant.util import dt as dt_util
@ -55,9 +54,9 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
async_add_entities([sensor])
def is_sun_event(event):
def is_sun_event(sun_event):
"""Return true if event is sun event not time."""
return event in (SUN_EVENT_SUNRISE, SUN_EVENT_SUNSET)
return sun_event in (SUN_EVENT_SUNRISE, SUN_EVENT_SUNSET)
class TodSensor(BinarySensorEntity):
@ -236,6 +235,6 @@ class TodSensor(BinarySensorEntity):
self._calculate_next_update()
self.async_write_ha_state()
async_track_point_in_utc_time(
event.async_track_point_in_utc_time(
self.hass, self._point_in_time_listener, self.next_update
)

View file

@ -4,7 +4,7 @@ MINOR_VERSION = 113
PATCH_VERSION = "0.dev0"
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
__version__ = f"{__short_version__}.{PATCH_VERSION}"
REQUIRED_PYTHON_VER = (3, 7, 0)
REQUIRED_PYTHON_VER = (3, 7, 1)
# Truthy date string triggers showing related deprecation warning messages.
REQUIRED_NEXT_PYTHON_VER = (3, 8, 0)
REQUIRED_NEXT_PYTHON_DATE = ""

View file

@ -2,6 +2,7 @@
from datetime import datetime, timedelta
import functools as ft
import logging
import time
from typing import Any, Awaitable, Callable, Dict, Iterable, Optional, Union
import attr
@ -316,26 +317,21 @@ def async_track_point_in_utc_time(
point_in_time = dt_util.as_utc(point_in_time)
@callback
def point_in_time_listener(event: Event) -> None:
def point_in_time_listener() -> None:
"""Listen for matching time_changed events."""
now = event.data[ATTR_NOW]
hass.async_run_job(action, point_in_time)
if now < point_in_time or hasattr(point_in_time_listener, "run"):
return
cancel_callback = hass.loop.call_at(
hass.loop.time() + point_in_time.timestamp() - time.time(),
point_in_time_listener,
)
# Set variable so that we will never run twice.
# Because the event bus might have to wait till a thread comes
# available to execute this listener it might occur that the
# listener gets lined up twice to be executed. This will make
# sure the second time it does nothing.
setattr(point_in_time_listener, "run", True)
async_unsub()
@callback
def unsub_point_in_time_listener() -> None:
"""Cancel the call_later."""
cancel_callback.cancel()
hass.async_run_job(action, now)
async_unsub = hass.bus.async_listen(EVENT_TIME_CHANGED, point_in_time_listener)
return async_unsub
return unsub_point_in_time_listener
track_point_in_utc_time = threaded_listener_factory(async_track_point_in_utc_time)

View file

@ -8,7 +8,7 @@ from typing import Any, Awaitable, Callable, List, Optional
import aiohttp
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.helpers import event
from homeassistant.util.dt import utcnow
from .debounce import Debouncer
@ -99,7 +99,7 @@ class DataUpdateCoordinator:
# minimizing the time between the point and the real activation.
# That way we obtain a constant update frequency,
# as long as the update process takes less than a second
self._unsub_refresh = async_track_point_in_utc_time(
self._unsub_refresh = event.async_track_point_in_utc_time(
self.hass,
self._handle_refresh_interval,
utcnow().replace(microsecond=0) + self.update_interval,

View file

@ -11,6 +11,7 @@ import logging
import os
import sys
import threading
import time
import uuid
from aiohttp.test_utils import unused_port as get_test_instance_port # noqa
@ -284,9 +285,22 @@ fire_mqtt_message = threadsafe_callback_factory(async_fire_mqtt_message)
@ha.callback
def async_fire_time_changed(hass, time):
def async_fire_time_changed(hass, datetime_):
"""Fire a time changes event."""
hass.bus.async_fire(EVENT_TIME_CHANGED, {"now": date_util.as_utc(time)})
hass.bus.async_fire(EVENT_TIME_CHANGED, {"now": date_util.as_utc(datetime_)})
for task in list(hass.loop._scheduled):
if not isinstance(task, asyncio.TimerHandle):
continue
if task.cancelled():
continue
future_seconds = task.when() - hass.loop.time()
mock_seconds_into_future = datetime_.timestamp() - time.time()
if mock_seconds_into_future >= future_seconds:
task._run()
task.cancel()
fire_time_changed = threadsafe_callback_factory(async_fire_time_changed)

View file

@ -1,5 +1,5 @@
"""The tests for the AsusWrt sensor platform."""
from datetime import datetime, timedelta
from datetime import timedelta
from aioasuswrt.asuswrt import Device
@ -16,7 +16,6 @@ from homeassistant.components.asuswrt import (
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util
from homeassistant.util.dt import utcnow
from tests.async_mock import AsyncMock, patch
@ -51,7 +50,7 @@ MOCK_BYTES_TOTAL = [60000000000, 50000000000]
MOCK_CURRENT_TRANSFER_RATES = [20000000, 10000000]
async def test_sensors(hass: HomeAssistant):
async def test_sensors(hass: HomeAssistant, mock_device_tracker_conf):
"""Test creating an AsusWRT sensor."""
with patch("homeassistant.components.asuswrt.AsusWrt") as AsusWrt:
AsusWrt().connection.async_connect = AsyncMock()
@ -61,23 +60,17 @@ async def test_sensors(hass: HomeAssistant):
return_value=MOCK_CURRENT_TRANSFER_RATES
)
now = datetime(2020, 1, 1, 1, tzinfo=dt_util.UTC)
with patch(("homeassistant.helpers.event.dt_util.utcnow"), return_value=now):
assert await async_setup_component(hass, DOMAIN, VALID_CONFIG_ROUTER_SSH)
await hass.async_block_till_done()
async_fire_time_changed(hass, utcnow() + timedelta(seconds=30))
await hass.async_block_till_done()
assert await async_setup_component(hass, DOMAIN, VALID_CONFIG_ROUTER_SSH)
await hass.async_block_till_done()
async_fire_time_changed(hass, utcnow() + timedelta(seconds=30))
await hass.async_block_till_done()
assert (
hass.states.get(f"{sensor.DOMAIN}.asuswrt_devices_connected").state
== "3"
)
assert (
hass.states.get(f"{sensor.DOMAIN}.asuswrt_download_speed").state
== "160.0"
)
assert hass.states.get(f"{sensor.DOMAIN}.asuswrt_download").state == "60.0"
assert (
hass.states.get(f"{sensor.DOMAIN}.asuswrt_upload_speed").state == "80.0"
)
assert hass.states.get(f"{sensor.DOMAIN}.asuswrt_upload").state == "50.0"
assert (
hass.states.get(f"{sensor.DOMAIN}.asuswrt_devices_connected").state == "3"
)
assert (
hass.states.get(f"{sensor.DOMAIN}.asuswrt_download_speed").state == "160.0"
)
assert hass.states.get(f"{sensor.DOMAIN}.asuswrt_download").state == "60.0"
assert hass.states.get(f"{sensor.DOMAIN}.asuswrt_upload_speed").state == "80.0"
assert hass.states.get(f"{sensor.DOMAIN}.asuswrt_upload").state == "50.0"

View file

@ -37,7 +37,7 @@ def teardown():
dt_util.set_default_time_zone(ORIG_TIME_ZONE)
async def test_sunset_trigger(hass, calls):
async def test_sunset_trigger(hass, calls, legacy_patchable_time):
"""Test the sunset trigger."""
now = datetime(2015, 9, 15, 23, tzinfo=dt_util.UTC)
trigger_time = datetime(2015, 9, 16, 2, tzinfo=dt_util.UTC)
@ -70,7 +70,7 @@ async def test_sunset_trigger(hass, calls):
assert len(calls) == 1
async def test_sunrise_trigger(hass, calls):
async def test_sunrise_trigger(hass, calls, legacy_patchable_time):
"""Test the sunrise trigger."""
now = datetime(2015, 9, 13, 23, tzinfo=dt_util.UTC)
trigger_time = datetime(2015, 9, 16, 14, tzinfo=dt_util.UTC)
@ -92,7 +92,7 @@ async def test_sunrise_trigger(hass, calls):
assert len(calls) == 1
async def test_sunset_trigger_with_offset(hass, calls):
async def test_sunset_trigger_with_offset(hass, calls, legacy_patchable_time):
"""Test the sunset trigger with offset."""
now = datetime(2015, 9, 15, 23, tzinfo=dt_util.UTC)
trigger_time = datetime(2015, 9, 16, 2, 30, tzinfo=dt_util.UTC)
@ -125,7 +125,7 @@ async def test_sunset_trigger_with_offset(hass, calls):
assert calls[0].data["some"] == "sun - sunset - 0:30:00"
async def test_sunrise_trigger_with_offset(hass, calls):
async def test_sunrise_trigger_with_offset(hass, calls, legacy_patchable_time):
"""Test the sunrise trigger with offset."""
now = datetime(2015, 9, 13, 23, tzinfo=dt_util.UTC)
trigger_time = datetime(2015, 9, 16, 13, 30, tzinfo=dt_util.UTC)

View file

@ -6,7 +6,7 @@ import ssl
from homeassistant.components.cert_expiry.const import DOMAIN
from homeassistant.config_entries import ENTRY_STATE_SETUP_RETRY
from homeassistant.const import CONF_HOST, CONF_PORT, STATE_UNAVAILABLE, STATE_UNKNOWN
import homeassistant.util.dt as dt_util
from homeassistant.util.dt import utcnow
from .const import HOST, PORT
from .helpers import future_timestamp, static_datetime
@ -91,7 +91,7 @@ async def test_async_setup_entry_host_unavailable(hass):
assert entry.state == ENTRY_STATE_SETUP_RETRY
next_update = dt_util.utcnow() + timedelta(seconds=45)
next_update = utcnow() + timedelta(seconds=45)
async_fire_time_changed(hass, next_update)
with patch(
"homeassistant.components.cert_expiry.helper.get_cert",
@ -115,8 +115,6 @@ async def test_update_sensor(hass):
timestamp = future_timestamp(100)
with patch("homeassistant.util.dt.utcnow", return_value=starting_time), patch(
"homeassistant.helpers.update_coordinator.utcnow", return_value=starting_time
), patch(
"homeassistant.components.cert_expiry.get_cert_expiry_timestamp",
return_value=timestamp,
):
@ -139,14 +137,11 @@ async def test_update_sensor(hass):
assert state.attributes.get("is_valid")
next_update = starting_time + timedelta(hours=24)
with patch("homeassistant.util.dt.utcnow", return_value=next_update), patch(
"homeassistant.helpers.update_coordinator.utcnow", return_value=next_update
), patch(
"homeassistant.components.cert_expiry.get_cert_expiry_timestamp",
return_value=timestamp,
):
async_fire_time_changed(hass, next_update)
async_fire_time_changed(hass, utcnow() + timedelta(hours=24))
await hass.async_block_till_done()
state = hass.states.get("sensor.cert_expiry_example_com")
@ -176,8 +171,6 @@ async def test_update_sensor_network_errors(hass):
timestamp = future_timestamp(100)
with patch("homeassistant.util.dt.utcnow", return_value=starting_time), patch(
"homeassistant.helpers.update_coordinator.utcnow", return_value=starting_time
), patch(
"homeassistant.components.cert_expiry.get_cert_expiry_timestamp",
return_value=timestamp,
):
@ -202,12 +195,10 @@ async def test_update_sensor_network_errors(hass):
next_update = starting_time + timedelta(hours=24)
with patch("homeassistant.util.dt.utcnow", return_value=next_update), patch(
"homeassistant.helpers.update_coordinator.utcnow", return_value=next_update
), patch(
"homeassistant.components.cert_expiry.helper.get_cert",
side_effect=socket.gaierror,
):
async_fire_time_changed(hass, next_update)
async_fire_time_changed(hass, utcnow() + timedelta(hours=24))
await hass.async_block_till_done()
next_update = starting_time + timedelta(hours=48)
@ -216,12 +207,10 @@ async def test_update_sensor_network_errors(hass):
assert state.state == STATE_UNAVAILABLE
with patch("homeassistant.util.dt.utcnow", return_value=next_update), patch(
"homeassistant.helpers.update_coordinator.utcnow", return_value=next_update
), patch(
"homeassistant.components.cert_expiry.get_cert_expiry_timestamp",
return_value=timestamp,
):
async_fire_time_changed(hass, next_update)
async_fire_time_changed(hass, utcnow() + timedelta(hours=48))
await hass.async_block_till_done()
state = hass.states.get("sensor.cert_expiry_example_com")
@ -234,12 +223,10 @@ async def test_update_sensor_network_errors(hass):
next_update = starting_time + timedelta(hours=72)
with patch("homeassistant.util.dt.utcnow", return_value=next_update), patch(
"homeassistant.helpers.update_coordinator.utcnow", return_value=next_update
), patch(
"homeassistant.components.cert_expiry.helper.get_cert",
side_effect=ssl.SSLError("something bad"),
):
async_fire_time_changed(hass, next_update)
async_fire_time_changed(hass, utcnow() + timedelta(hours=72))
await hass.async_block_till_done()
state = hass.states.get("sensor.cert_expiry_example_com")
@ -258,11 +245,9 @@ async def test_update_sensor_network_errors(hass):
next_update = starting_time + timedelta(hours=96)
with patch("homeassistant.util.dt.utcnow", return_value=next_update), patch(
"homeassistant.helpers.update_coordinator.utcnow", return_value=next_update
), patch(
"homeassistant.components.cert_expiry.helper.get_cert", side_effect=Exception()
):
async_fire_time_changed(hass, next_update)
async_fire_time_changed(hass, utcnow() + timedelta(hours=96))
await hass.async_block_till_done()
state = hass.states.get("sensor.cert_expiry_example_com")

View file

@ -51,7 +51,9 @@ async def test_sync_entities(aioclient_mock, hass, cloud_prefs):
assert len(mock_request_sync.mock_calls) == 1
async def test_google_update_expose_trigger_sync(hass, cloud_prefs):
async def test_google_update_expose_trigger_sync(
hass, legacy_patchable_time, cloud_prefs
):
"""Test Google config responds to updating exposed entities."""
config = CloudGoogleConfig(
hass,

View file

@ -225,12 +225,14 @@ async def test_discover_platform(mock_demo_setup_scanner, mock_see, hass):
async def test_update_stale(hass, mock_device_tracker_conf):
"""Test stalled update."""
scanner = getattr(hass.components, "test.device_tracker").SCANNER
scanner.reset()
scanner.come_home("DEV1")
register_time = datetime(2015, 9, 15, 23, tzinfo=dt_util.UTC)
scan_time = datetime(2015, 9, 15, 23, 1, tzinfo=dt_util.UTC)
now = dt_util.utcnow()
register_time = datetime(now.year + 1, 9, 15, 23, tzinfo=dt_util.UTC)
scan_time = datetime(now.year + 1, 9, 15, 23, 1, tzinfo=dt_util.UTC)
with patch(
"homeassistant.components.device_tracker.legacy.dt_util.utcnow",
@ -433,8 +435,10 @@ async def test_see_state(hass, yaml_devices):
async def test_see_passive_zone_state(hass, mock_device_tracker_conf):
"""Test that the device tracker sets gps for passive trackers."""
register_time = datetime(2015, 9, 15, 23, tzinfo=dt_util.UTC)
scan_time = datetime(2015, 9, 15, 23, 1, tzinfo=dt_util.UTC)
now = dt_util.utcnow()
register_time = datetime(now.year + 1, 9, 15, 23, tzinfo=dt_util.UTC)
scan_time = datetime(now.year + 1, 9, 15, 23, 1, tzinfo=dt_util.UTC)
with assert_setup_component(1, zone.DOMAIN):
zone_info = {

View file

@ -159,7 +159,7 @@ async def test_async_track_time_interval_backoff(hass):
_LOGGER.debug("Backoff...")
for idx in range(1, len(intervals)):
tme += intervals[idx]
async_fire_time_changed(hass, tme)
async_fire_time_changed(hass, tme + timedelta(seconds=0.1))
await hass.async_block_till_done()
assert call_count == idx + 1
@ -167,7 +167,7 @@ async def test_async_track_time_interval_backoff(hass):
_LOGGER.debug("Max backoff reached - intervals[-1]")
for _idx in range(1, 10):
tme += intervals[-1]
async_fire_time_changed(hass, tme)
async_fire_time_changed(hass, tme + timedelta(seconds=0.1))
await hass.async_block_till_done()
assert call_count == idx + 1 + _idx
@ -176,14 +176,14 @@ async def test_async_track_time_interval_backoff(hass):
call_count = 0
ret_val = True
tme += intervals[-1]
async_fire_time_changed(hass, tme)
async_fire_time_changed(hass, tme + timedelta(seconds=0.1))
await hass.async_block_till_done()
assert call_count == 1
_LOGGER.debug("No backoff - intervals[0]")
for _idx in range(2, 10):
tme += intervals[0]
async_fire_time_changed(hass, tme)
async_fire_time_changed(hass, tme + timedelta(seconds=0.1))
await hass.async_block_till_done()
assert call_count == _idx

View file

@ -282,7 +282,7 @@ async def test_flux_before_sunrise_known_location(hass):
# pylint: disable=invalid-name
async def test_flux_after_sunrise_before_sunset(hass):
async def test_flux_after_sunrise_before_sunset(hass, legacy_patchable_time):
"""Test the flux switch after sunrise and before sunset."""
platform = getattr(hass.components, "test.light")
platform.init()
@ -336,7 +336,7 @@ async def test_flux_after_sunrise_before_sunset(hass):
# pylint: disable=invalid-name
async def test_flux_after_sunset_before_stop(hass):
async def test_flux_after_sunset_before_stop(hass, legacy_patchable_time):
"""Test the flux switch after sunset and before stop."""
platform = getattr(hass.components, "test.light")
platform.init()
@ -391,7 +391,7 @@ async def test_flux_after_sunset_before_stop(hass):
# pylint: disable=invalid-name
async def test_flux_after_stop_before_sunrise(hass):
async def test_flux_after_stop_before_sunrise(hass, legacy_patchable_time):
"""Test the flux switch after stop and before sunrise."""
platform = getattr(hass.components, "test.light")
platform.init()
@ -445,7 +445,7 @@ async def test_flux_after_stop_before_sunrise(hass):
# pylint: disable=invalid-name
async def test_flux_with_custom_start_stop_times(hass):
async def test_flux_with_custom_start_stop_times(hass, legacy_patchable_time):
"""Test the flux with custom start and stop times."""
platform = getattr(hass.components, "test.light")
platform.init()
@ -558,7 +558,9 @@ async def test_flux_before_sunrise_stop_next_day(hass):
# pylint: disable=invalid-name
async def test_flux_after_sunrise_before_sunset_stop_next_day(hass):
async def test_flux_after_sunrise_before_sunset_stop_next_day(
hass, legacy_patchable_time
):
"""
Test the flux switch after sunrise and before sunset.
@ -618,7 +620,9 @@ async def test_flux_after_sunrise_before_sunset_stop_next_day(hass):
# pylint: disable=invalid-name
@pytest.mark.parametrize("x", [0, 1])
async def test_flux_after_sunset_before_midnight_stop_next_day(hass, x):
async def test_flux_after_sunset_before_midnight_stop_next_day(
hass, legacy_patchable_time, x
):
"""Test the flux switch after sunset and before stop.
This test has the stop_time on the next day (after midnight).
@ -792,7 +796,7 @@ async def test_flux_after_stop_before_sunrise_stop_next_day(hass):
# pylint: disable=invalid-name
async def test_flux_with_custom_colortemps(hass):
async def test_flux_with_custom_colortemps(hass, legacy_patchable_time):
"""Test the flux with custom start and stop colortemps."""
platform = getattr(hass.components, "test.light")
platform.init()
@ -849,7 +853,7 @@ async def test_flux_with_custom_colortemps(hass):
# pylint: disable=invalid-name
async def test_flux_with_custom_brightness(hass):
async def test_flux_with_custom_brightness(hass, legacy_patchable_time):
"""Test the flux with custom start and stop colortemps."""
platform = getattr(hass.components, "test.light")
platform.init()
@ -904,7 +908,7 @@ async def test_flux_with_custom_brightness(hass):
assert call.data[light.ATTR_XY_COLOR] == [0.506, 0.385]
async def test_flux_with_multiple_lights(hass):
async def test_flux_with_multiple_lights(hass, legacy_patchable_time):
"""Test the flux switch with multiple light entities."""
platform = getattr(hass.components, "test.light")
platform.init()
@ -982,7 +986,7 @@ async def test_flux_with_multiple_lights(hass):
assert call.data[light.ATTR_XY_COLOR] == [0.46, 0.376]
async def test_flux_with_mired(hass):
async def test_flux_with_mired(hass, legacy_patchable_time):
"""Test the flux switch´s mode mired."""
platform = getattr(hass.components, "test.light")
platform.init()
@ -1034,7 +1038,7 @@ async def test_flux_with_mired(hass):
assert call.data[light.ATTR_COLOR_TEMP] == 269
async def test_flux_with_rgb(hass):
async def test_flux_with_rgb(hass, legacy_patchable_time):
"""Test the flux switch´s mode rgb."""
platform = getattr(hass.components, "test.light")
platform.init()

View file

@ -32,7 +32,11 @@ from homeassistant.setup import async_setup_component
from homeassistant.util.unit_system import METRIC_SYSTEM
from tests.async_mock import patch
from tests.common import assert_setup_component, mock_restore_cache
from tests.common import (
assert_setup_component,
async_fire_time_changed,
mock_restore_cache,
)
from tests.components.climate import common
ENTITY = "climate.test"
@ -949,13 +953,13 @@ async def test_temp_change_ac_trigger_on_long_enough_3(hass, setup_comp_7):
await hass.async_block_till_done()
await common.async_set_temperature(hass, 25)
test_time = datetime.datetime.now(pytz.UTC)
_send_time_changed(hass, test_time)
async_fire_time_changed(hass, test_time)
await hass.async_block_till_done()
assert 0 == len(calls)
_send_time_changed(hass, test_time + datetime.timedelta(minutes=5))
async_fire_time_changed(hass, test_time + datetime.timedelta(minutes=5))
await hass.async_block_till_done()
assert 0 == len(calls)
_send_time_changed(hass, test_time + datetime.timedelta(minutes=10))
async_fire_time_changed(hass, test_time + datetime.timedelta(minutes=10))
await hass.async_block_till_done()
assert 1 == len(calls)
call = calls[0]
@ -972,13 +976,13 @@ async def test_temp_change_ac_trigger_off_long_enough_3(hass, setup_comp_7):
await hass.async_block_till_done()
await common.async_set_temperature(hass, 25)
test_time = datetime.datetime.now(pytz.UTC)
_send_time_changed(hass, test_time)
async_fire_time_changed(hass, test_time)
await hass.async_block_till_done()
assert 0 == len(calls)
_send_time_changed(hass, test_time + datetime.timedelta(minutes=5))
async_fire_time_changed(hass, test_time + datetime.timedelta(minutes=5))
await hass.async_block_till_done()
assert 0 == len(calls)
_send_time_changed(hass, test_time + datetime.timedelta(minutes=10))
async_fire_time_changed(hass, test_time + datetime.timedelta(minutes=10))
await hass.async_block_till_done()
assert 1 == len(calls)
call = calls[0]
@ -987,11 +991,6 @@ async def test_temp_change_ac_trigger_off_long_enough_3(hass, setup_comp_7):
assert ENT_SWITCH == call.data["entity_id"]
def _send_time_changed(hass, now):
"""Send a time changed event."""
hass.bus.async_fire(ha.EVENT_TIME_CHANGED, {ha.ATTR_NOW: now})
@pytest.fixture
async def setup_comp_8(hass):
"""Initialize components."""
@ -1025,13 +1024,13 @@ async def test_temp_change_heater_trigger_on_long_enough_2(hass, setup_comp_8):
await hass.async_block_till_done()
await common.async_set_temperature(hass, 25)
test_time = datetime.datetime.now(pytz.UTC)
_send_time_changed(hass, test_time)
async_fire_time_changed(hass, test_time)
await hass.async_block_till_done()
assert 0 == len(calls)
_send_time_changed(hass, test_time + datetime.timedelta(minutes=5))
async_fire_time_changed(hass, test_time + datetime.timedelta(minutes=5))
await hass.async_block_till_done()
assert 0 == len(calls)
_send_time_changed(hass, test_time + datetime.timedelta(minutes=10))
async_fire_time_changed(hass, test_time + datetime.timedelta(minutes=10))
await hass.async_block_till_done()
assert 1 == len(calls)
call = calls[0]
@ -1048,13 +1047,13 @@ async def test_temp_change_heater_trigger_off_long_enough_2(hass, setup_comp_8):
await hass.async_block_till_done()
await common.async_set_temperature(hass, 25)
test_time = datetime.datetime.now(pytz.UTC)
_send_time_changed(hass, test_time)
async_fire_time_changed(hass, test_time)
await hass.async_block_till_done()
assert 0 == len(calls)
_send_time_changed(hass, test_time + datetime.timedelta(minutes=5))
async_fire_time_changed(hass, test_time + datetime.timedelta(minutes=5))
await hass.async_block_till_done()
assert 0 == len(calls)
_send_time_changed(hass, test_time + datetime.timedelta(minutes=10))
async_fire_time_changed(hass, test_time + datetime.timedelta(minutes=10))
await hass.async_block_till_done()
assert 1 == len(calls)
call = calls[0]

View file

@ -567,7 +567,7 @@ async def test_bicycle(hass, requests_mock_credentials_check):
assert sensor.attributes.get(ATTR_ICON) == ICON_BICYCLE
async def test_location_zone(hass, requests_mock_truck_response):
async def test_location_zone(hass, requests_mock_truck_response, legacy_patchable_time):
"""Test that origin/destination supplied by a zone works."""
utcnow = dt_util.utcnow()
# Patching 'utcnow' to gain more control over the timed update.
@ -618,7 +618,9 @@ async def test_location_zone(hass, requests_mock_truck_response):
_assert_truck_sensor(sensor)
async def test_location_sensor(hass, requests_mock_truck_response):
async def test_location_sensor(
hass, requests_mock_truck_response, legacy_patchable_time
):
"""Test that origin/destination supplied by a sensor works."""
utcnow = dt_util.utcnow()
# Patching 'utcnow' to gain more control over the timed update.
@ -658,7 +660,9 @@ async def test_location_sensor(hass, requests_mock_truck_response):
_assert_truck_sensor(sensor)
async def test_location_person(hass, requests_mock_truck_response):
async def test_location_person(
hass, requests_mock_truck_response, legacy_patchable_time
):
"""Test that origin/destination supplied by a person works."""
utcnow = dt_util.utcnow()
# Patching 'utcnow' to gain more control over the timed update.
@ -707,7 +711,9 @@ async def test_location_person(hass, requests_mock_truck_response):
_assert_truck_sensor(sensor)
async def test_location_device_tracker(hass, requests_mock_truck_response):
async def test_location_device_tracker(
hass, requests_mock_truck_response, legacy_patchable_time
):
"""Test that origin/destination supplied by a device_tracker works."""
utcnow = dt_util.utcnow()
# Patching 'utcnow' to gain more control over the timed update.
@ -757,7 +763,7 @@ async def test_location_device_tracker(hass, requests_mock_truck_response):
async def test_location_device_tracker_added_after_update(
hass, requests_mock_truck_response, caplog
hass, requests_mock_truck_response, legacy_patchable_time, caplog
):
"""Test that device_tracker added after first update works."""
caplog.set_level(logging.ERROR)

View file

@ -2,7 +2,7 @@
This includes tests for all mock object types.
"""
from datetime import datetime, timedelta
from datetime import timedelta
import pytest
@ -37,9 +37,7 @@ from homeassistant.const import (
ATTR_BATTERY_CHARGING,
ATTR_BATTERY_LEVEL,
ATTR_ENTITY_ID,
ATTR_NOW,
ATTR_SERVICE,
EVENT_TIME_CHANGED,
STATE_OFF,
STATE_ON,
STATE_UNAVAILABLE,
@ -49,7 +47,7 @@ from homeassistant.helpers.event import TRACK_STATE_CHANGE_CALLBACKS
import homeassistant.util.dt as dt_util
from tests.async_mock import Mock, patch
from tests.common import async_mock_service
from tests.common import async_fire_time_changed, async_mock_service
async def test_debounce(hass):
@ -66,11 +64,11 @@ async def test_debounce(hass):
debounce_demo = debounce(demo_func)
assert debounce_demo.__name__ == "demo_func"
now = datetime(2018, 1, 1, 20, 0, 0, tzinfo=dt_util.UTC)
now = dt_util.utcnow()
with patch("homeassistant.util.dt.utcnow", return_value=now):
await hass.async_add_executor_job(debounce_demo, mock, "value")
hass.bus.async_fire(EVENT_TIME_CHANGED, {ATTR_NOW: now + timedelta(seconds=3)})
async_fire_time_changed(hass, now + timedelta(seconds=3))
await hass.async_block_till_done()
assert counter == 1
assert len(arguments) == 2
@ -79,7 +77,7 @@ async def test_debounce(hass):
await hass.async_add_executor_job(debounce_demo, mock, "value")
await hass.async_add_executor_job(debounce_demo, mock, "value")
hass.bus.async_fire(EVENT_TIME_CHANGED, {ATTR_NOW: now + timedelta(seconds=3)})
async_fire_time_changed(hass, now + timedelta(seconds=3))
await hass.async_block_till_done()
assert counter == 2

View file

@ -5,13 +5,16 @@ from unittest import mock
from aiohomekit.testing import FakeController
import pytest
import homeassistant.util.dt as dt_util
import tests.async_mock
@pytest.fixture
def utcnow(request):
"""Freeze time at a known point."""
start_dt = datetime.datetime(2019, 1, 1, 0, 0, 0)
now = dt_util.utcnow()
start_dt = datetime.datetime(now.year + 1, 1, 1, 0, 0, 0)
with mock.patch("homeassistant.util.dt.utcnow") as dt_utcnow:
dt_utcnow.return_value = start_dt
yield dt_utcnow

View file

@ -85,7 +85,7 @@ async def test_unload_entry(hass):
assert islamic_prayer_times.DOMAIN not in hass.data
async def test_islamic_prayer_times_timestamp_format(hass):
async def test_islamic_prayer_times_timestamp_format(hass, legacy_patchable_time):
"""Test Islamic prayer times timestamp format."""
entry = MockConfigEntry(domain=islamic_prayer_times.DOMAIN, data={})
entry.add_to_hass(hass)
@ -94,7 +94,6 @@ async def test_islamic_prayer_times_timestamp_format(hass):
"prayer_times_calculator.PrayerTimesCalculator.fetch_prayer_times",
return_value=PRAYER_TIMES,
), patch("homeassistant.util.dt.now", return_value=NOW):
await hass.config_entries.async_setup(entry.entry_id)
assert (
@ -103,7 +102,7 @@ async def test_islamic_prayer_times_timestamp_format(hass):
)
async def test_update(hass):
async def test_update(hass, legacy_patchable_time):
"""Test sensors are updated with new prayer times."""
entry = MockConfigEntry(domain=islamic_prayer_times.DOMAIN, data={})
entry.add_to_hass(hass)

View file

@ -8,7 +8,7 @@ from tests.async_mock import patch
from tests.common import MockConfigEntry
async def test_islamic_prayer_times_sensors(hass):
async def test_islamic_prayer_times_sensors(hass, legacy_patchable_time):
"""Test minimum Islamic prayer times configuration."""
entry = MockConfigEntry(domain=islamic_prayer_times.DOMAIN, data={})
entry.add_to_hass(hass)
@ -17,7 +17,6 @@ async def test_islamic_prayer_times_sensors(hass):
"prayer_times_calculator.PrayerTimesCalculator.fetch_prayer_times",
return_value=PRAYER_TIMES,
), patch("homeassistant.util.dt.now", return_value=NOW):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()

View file

@ -60,7 +60,16 @@ MELACHA_TEST_IDS = [
ids=MELACHA_TEST_IDS,
)
async def test_issur_melacha_sensor(
hass, now, candle_lighting, havdalah, diaspora, tzname, latitude, longitude, result
hass,
legacy_patchable_time,
now,
candle_lighting,
havdalah,
diaspora,
tzname,
latitude,
longitude,
result,
):
"""Test Issur Melacha sensor output."""
time_zone = dt_util.get_time_zone(tzname)

View file

@ -144,7 +144,16 @@ TEST_IDS = [
ids=TEST_IDS,
)
async def test_jewish_calendar_sensor(
hass, now, tzname, latitude, longitude, language, sensor, diaspora, result
hass,
legacy_patchable_time,
now,
tzname,
latitude,
longitude,
language,
sensor,
diaspora,
result,
):
"""Test Jewish calendar sensor output."""
time_zone = dt_util.get_time_zone(tzname)
@ -478,6 +487,7 @@ SHABBAT_TEST_IDS = [
)
async def test_shabbat_times_sensor(
hass,
legacy_patchable_time,
language,
now,
candle_lighting,
@ -553,7 +563,7 @@ OMER_TEST_IDS = [
@pytest.mark.parametrize(["test_time", "result"], OMER_PARAMS, ids=OMER_TEST_IDS)
async def test_omer_sensor(hass, test_time, result):
async def test_omer_sensor(hass, legacy_patchable_time, test_time, result):
"""Test Omer Count sensor output."""
test_time = hass.config.time_zone.localize(test_time)
@ -587,7 +597,7 @@ DAFYOMI_TEST_IDS = [
@pytest.mark.parametrize(["test_time", "result"], DAFYOMI_PARAMS, ids=DAFYOMI_TEST_IDS)
async def test_dafyomi_sensor(hass, test_time, result):
async def test_dafyomi_sensor(hass, legacy_patchable_time, test_time, result):
"""Test Daf Yomi sensor output."""
test_time = hass.config.time_zone.localize(test_time)

View file

@ -1450,7 +1450,7 @@ async def test_armed_custom_bypass_with_specific_pending(hass):
assert STATE_ALARM_ARMED_CUSTOM_BYPASS == hass.states.get(entity_id).state
async def test_arm_away_after_disabled_disarmed(hass):
async def test_arm_away_after_disabled_disarmed(hass, legacy_patchable_time):
"""Test pending state with and without zero trigger time."""
assert await async_setup_component(
hass,

View file

@ -1348,7 +1348,7 @@ async def test_trigger_with_specific_pending(hass, mqtt_mock):
assert STATE_ALARM_DISARMED == hass.states.get(entity_id).state
async def test_arm_away_after_disabled_disarmed(hass, mqtt_mock):
async def test_arm_away_after_disabled_disarmed(hass, legacy_patchable_time, mqtt_mock):
"""Test pending state with and without zero trigger time."""
assert await async_setup_component(
hass,

View file

@ -23,9 +23,8 @@ from tests.common import MockConfigEntry, load_fixture
"datapoint.Forecast.datetime.datetime",
Mock(now=Mock(return_value=datetime(2020, 4, 25, 12, tzinfo=timezone.utc))),
)
async def test_one_sensor_site_running(hass, requests_mock):
async def test_one_sensor_site_running(hass, requests_mock, legacy_patchable_time):
"""Test the Met Office sensor platform."""
# all metoffice test data encapsulated in here
mock_json = json.loads(load_fixture("metoffice.json"))
all_sites = json.dumps(mock_json["all_sites"])
@ -62,7 +61,7 @@ async def test_one_sensor_site_running(hass, requests_mock):
"datapoint.Forecast.datetime.datetime",
Mock(now=Mock(return_value=datetime(2020, 4, 25, 12, tzinfo=timezone.utc))),
)
async def test_two_sensor_sites_running(hass, requests_mock):
async def test_two_sensor_sites_running(hass, requests_mock, legacy_patchable_time):
"""Test we handle two sets of sensors running for two different sites."""
# all metoffice test data encapsulated in here

View file

@ -20,7 +20,7 @@ from tests.common import MockConfigEntry, async_fire_time_changed, load_fixture
"datapoint.Forecast.datetime.datetime",
Mock(now=Mock(return_value=datetime(2020, 4, 25, 12, tzinfo=timezone.utc))),
)
async def test_site_cannot_connect(hass, requests_mock):
async def test_site_cannot_connect(hass, requests_mock, legacy_patchable_time):
"""Test we handle cannot connect error."""
requests_mock.get("/public/data/val/wxfcs/all/json/sitelist/", text="")
@ -42,7 +42,7 @@ async def test_site_cannot_connect(hass, requests_mock):
"datapoint.Forecast.datetime.datetime",
Mock(now=Mock(return_value=datetime(2020, 4, 25, 12, tzinfo=timezone.utc))),
)
async def test_site_cannot_update(hass, requests_mock):
async def test_site_cannot_update(hass, requests_mock, legacy_patchable_time):
"""Test we handle cannot connect error."""
# all metoffice test data encapsulated in here
@ -77,7 +77,7 @@ async def test_site_cannot_update(hass, requests_mock):
"datapoint.Forecast.datetime.datetime",
Mock(now=Mock(return_value=datetime(2020, 4, 25, 12, tzinfo=timezone.utc))),
)
async def test_one_weather_site_running(hass, requests_mock):
async def test_one_weather_site_running(hass, requests_mock, legacy_patchable_time):
"""Test the Met Office weather platform."""
# all metoffice test data encapsulated in here
@ -111,7 +111,7 @@ async def test_one_weather_site_running(hass, requests_mock):
"datapoint.Forecast.datetime.datetime",
Mock(now=Mock(return_value=datetime(2020, 4, 25, 12, tzinfo=timezone.utc))),
)
async def test_two_weather_sites_running(hass, requests_mock):
async def test_two_weather_sites_running(hass, requests_mock, legacy_patchable_time):
"""Test we handle two different weather sites both running."""
# all metoffice test data encapsulated in here

View file

@ -39,7 +39,7 @@ async def test_platform_manually_configured(hass):
assert mikrotik.DOMAIN not in hass.data
async def test_device_trackers(hass):
async def test_device_trackers(hass, legacy_patchable_time):
"""Test device_trackers created by mikrotik."""
# test devices are added from wireless list only

View file

@ -1,46 +1,59 @@
"""The test for the moon sensor platform."""
from datetime import datetime
import unittest
from homeassistant.setup import setup_component
from homeassistant.components.homeassistant import (
DOMAIN as HA_DOMAIN,
SERVICE_UPDATE_ENTITY,
)
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util
from tests.async_mock import patch
from tests.common import get_test_home_assistant
DAY1 = datetime(2017, 1, 1, 1, tzinfo=dt_util.UTC)
DAY2 = datetime(2017, 1, 18, 1, tzinfo=dt_util.UTC)
class TestMoonSensor(unittest.TestCase):
async def test_moon_day1(hass):
"""Test the Moon sensor."""
config = {"sensor": {"platform": "moon", "name": "moon_day1"}}
def setup_method(self, method):
"""Set up things to be run when tests are started."""
self.hass = get_test_home_assistant()
await async_setup_component(hass, HA_DOMAIN, {})
assert await async_setup_component(hass, "sensor", config)
await hass.async_block_till_done()
def teardown_method(self, method):
"""Stop everything that was started."""
self.hass.stop()
assert hass.states.get("sensor.moon_day1")
@patch("homeassistant.components.moon.sensor.dt_util.utcnow", return_value=DAY1)
def test_moon_day1(self, mock_request):
"""Test the Moon sensor."""
config = {"sensor": {"platform": "moon", "name": "moon_day1"}}
with patch(
"homeassistant.components.moon.sensor.dt_util.utcnow", return_value=DAY1
):
await async_update_entity(hass, "sensor.moon_day1")
assert setup_component(self.hass, "sensor", config)
self.hass.block_till_done()
assert hass.states.get("sensor.moon_day1").state == "waxing_crescent"
state = self.hass.states.get("sensor.moon_day1")
assert state.state == "waxing_crescent"
@patch("homeassistant.components.moon.sensor.dt_util.utcnow", return_value=DAY2)
def test_moon_day2(self, mock_request):
"""Test the Moon sensor."""
config = {"sensor": {"platform": "moon", "name": "moon_day2"}}
async def test_moon_day2(hass):
"""Test the Moon sensor."""
config = {"sensor": {"platform": "moon", "name": "moon_day2"}}
assert setup_component(self.hass, "sensor", config)
self.hass.block_till_done()
await async_setup_component(hass, HA_DOMAIN, {})
assert await async_setup_component(hass, "sensor", config)
await hass.async_block_till_done()
state = self.hass.states.get("sensor.moon_day2")
assert state.state == "waning_gibbous"
assert hass.states.get("sensor.moon_day2")
with patch(
"homeassistant.components.moon.sensor.dt_util.utcnow", return_value=DAY2
):
await async_update_entity(hass, "sensor.moon_day2")
assert hass.states.get("sensor.moon_day2").state == "waning_gibbous"
async def async_update_entity(hass, entity_id):
"""Run an update action for an entity."""
await hass.services.async_call(
HA_DOMAIN, SERVICE_UPDATE_ENTITY, {ATTR_ENTITY_ID: entity_id}, blocking=True,
)
await hass.async_block_till_done()

View file

@ -52,7 +52,9 @@ DEFAULT_CONFIG = {
}
async def test_setting_sensor_value_expires_availability_topic(hass, mqtt_mock, caplog):
async def test_setting_sensor_value_expires_availability_topic(
hass, mqtt_mock, legacy_patchable_time, caplog
):
"""Test the expiration of the value."""
assert await async_setup_component(
hass,
@ -82,7 +84,9 @@ async def test_setting_sensor_value_expires_availability_topic(hass, mqtt_mock,
await expires_helper(hass, mqtt_mock, caplog)
async def test_setting_sensor_value_expires(hass, mqtt_mock, caplog):
async def test_setting_sensor_value_expires(
hass, mqtt_mock, legacy_patchable_time, caplog
):
"""Test the expiration of the value."""
assert await async_setup_component(
hass,
@ -520,7 +524,7 @@ async def test_discovery_update_binary_sensor(hass, mqtt_mock, caplog):
async def test_expiration_on_discovery_and_discovery_update_of_binary_sensor(
hass, mqtt_mock, caplog
hass, mqtt_mock, legacy_patchable_time, caplog
):
"""Test that binary_sensor with expire_after set behaves correctly on discovery and discovery update."""
entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]

View file

@ -70,7 +70,9 @@ async def test_setting_sensor_value_via_mqtt_message(hass, mqtt_mock):
assert state.attributes.get("unit_of_measurement") == "fav unit"
async def test_setting_sensor_value_expires(hass, mqtt_mock, caplog):
async def test_setting_sensor_value_expires(
hass, mqtt_mock, legacy_patchable_time, caplog
):
"""Test the expiration of the value."""
assert await async_setup_component(
hass,
@ -91,7 +93,8 @@ async def test_setting_sensor_value_expires(hass, mqtt_mock, caplog):
state = hass.states.get("sensor.test")
assert state.state == "unknown"
now = datetime(2017, 1, 1, 1, tzinfo=dt_util.UTC)
realnow = dt_util.utcnow()
now = datetime(realnow.year + 1, 1, 1, 1, tzinfo=dt_util.UTC)
with patch(("homeassistant.helpers.event.dt_util.utcnow"), return_value=now):
async_fire_time_changed(hass, now)
async_fire_mqtt_message(hass, "test-topic", "100")

View file

@ -6,13 +6,16 @@ import unittest
import pytest
from homeassistant import core as ha
from homeassistant.components import pilight
from homeassistant.setup import setup_component
from homeassistant.util import dt as dt_util
from tests.async_mock import patch
from tests.common import assert_setup_component, get_test_home_assistant
from tests.common import (
assert_setup_component,
async_fire_time_changed,
get_test_home_assistant,
)
_LOGGER = logging.getLogger(__name__)
@ -196,13 +199,13 @@ class TestPilight(unittest.TestCase):
service_data1["protocol"] = [service_data1["protocol"]]
service_data2["protocol"] = [service_data2["protocol"]]
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {ha.ATTR_NOW: dt_util.utcnow()})
async_fire_time_changed(self.hass, dt_util.utcnow())
self.hass.block_till_done()
error_log_call = mock_pilight_error.call_args_list[-1]
assert str(service_data1) in str(error_log_call)
new_time = dt_util.utcnow() + timedelta(seconds=5)
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {ha.ATTR_NOW: new_time})
async_fire_time_changed(self.hass, new_time)
self.hass.block_till_done()
error_log_call = mock_pilight_error.call_args_list[-1]
assert str(service_data2) in str(error_log_call)
@ -407,6 +410,6 @@ class TestPilightCallrateThrottler(unittest.TestCase):
for i in range(3):
exp.append(i)
shifted_time = now + (timedelta(seconds=delay + 0.1) * i)
self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {ha.ATTR_NOW: shifted_time})
async_fire_time_changed(self.hass, shifted_time)
self.hass.block_till_done()
assert runs == exp

View file

@ -2,11 +2,12 @@
from datetime import timedelta
import io
from homeassistant import core as ha
from homeassistant.config import async_process_ha_core_config
from homeassistant.setup import async_setup_component
from homeassistant.util import dt as dt_util
from tests.common import async_fire_time_changed
async def test_bad_posting(hass, aiohttp_client):
"""Test that posting to wrong api endpoint fails."""
@ -74,7 +75,7 @@ async def test_posting_url(hass, aiohttp_client):
# await timeout
shifted_time = dt_util.utcnow() + timedelta(seconds=15)
hass.bus.async_fire(ha.EVENT_TIME_CHANGED, {ha.ATTR_NOW: shifted_time})
async_fire_time_changed(hass, shifted_time)
await hass.async_block_till_done()
# back to initial state

View file

@ -15,7 +15,9 @@ from tests.common import date_util
from tests.test_util.aiohttp import AiohttpClientMocker
async def test_config_flow(hass, pvpc_aioclient_mock: AiohttpClientMocker):
async def test_config_flow(
hass, legacy_patchable_time, pvpc_aioclient_mock: AiohttpClientMocker
):
"""
Test config flow for pvpc_hourly_pricing.

View file

@ -29,7 +29,7 @@ async def _process_time_step(
async def test_sensor_availability(
hass, caplog, pvpc_aioclient_mock: AiohttpClientMocker
hass, caplog, legacy_patchable_time, pvpc_aioclient_mock: AiohttpClientMocker
):
"""Test sensor availability and handling of cloud access."""
hass.config.time_zone = timezone("Europe/Madrid")

View file

@ -116,7 +116,7 @@ async def test_entity_availability(hass, monkeypatch):
assert hass.states.get("binary_sensor.test").state == STATE_OFF
async def test_off_delay(hass, monkeypatch):
async def test_off_delay(hass, legacy_patchable_time, monkeypatch):
"""Test off_delay option."""
# setup mocking rflink module
event_callback, create, _, _ = await mock_rflink(hass, CONFIG, DOMAIN, monkeypatch)

View file

@ -3,6 +3,8 @@ from datetime import datetime, timedelta
import statistics
import unittest
import pytest
from homeassistant.components import recorder
from homeassistant.components.statistics.sensor import StatisticsSensor
from homeassistant.const import ATTR_UNIT_OF_MEASUREMENT, STATE_UNKNOWN, TEMP_CELSIUS
@ -18,6 +20,12 @@ from tests.common import (
from tests.components.recorder.common import wait_recording_done
@pytest.fixture(autouse=True)
def mock_legacy_time(legacy_patchable_time):
"""Make time patchable for all the tests."""
yield
class TestStatisticsSensor(unittest.TestCase):
"""Test the Statistics sensor."""
@ -36,10 +44,7 @@ class TestStatisticsSensor(unittest.TestCase):
self.change = round(self.values[-1] - self.values[0], 2)
self.average_change = round(self.change / (len(self.values) - 1), 2)
self.change_rate = round(self.change / (60 * (self.count - 1)), 2)
def teardown_method(self, method):
"""Stop everything that was started."""
self.hass.stop()
self.addCleanup(self.hass.stop)
def test_binary_sensor_source(self):
"""Test if source is a sensor."""

View file

@ -12,7 +12,7 @@ import homeassistant.util.dt as dt_util
from tests.async_mock import patch
async def test_setting_rising(hass):
async def test_setting_rising(hass, legacy_patchable_time):
"""Test retrieving sun setting and rising."""
utc_now = datetime(2016, 11, 1, 8, 0, 0, tzinfo=dt_util.UTC)
with patch("homeassistant.helpers.condition.dt_util.utcnow", return_value=utc_now):
@ -103,7 +103,7 @@ async def test_setting_rising(hass):
)
async def test_state_change(hass):
async def test_state_change(hass, legacy_patchable_time):
"""Test if the state changes at next setting/rising."""
now = datetime(2016, 6, 1, 8, 0, 0, tzinfo=dt_util.UTC)
with patch("homeassistant.helpers.condition.dt_util.utcnow", return_value=now):

View file

@ -2,6 +2,7 @@
from datetime import datetime, timedelta
import unittest
import pytest
import pytz
from homeassistant import setup
@ -15,6 +16,12 @@ from tests.async_mock import patch
from tests.common import assert_setup_component, get_test_home_assistant
@pytest.fixture(autouse=True)
def mock_legacy_time(legacy_patchable_time):
"""Make time patchable for all the tests."""
yield
class TestBinarySensorTod(unittest.TestCase):
"""Test for Binary sensor tod platform."""

View file

@ -11,7 +11,7 @@ from tests.common import assert_setup_component, load_fixture
NOW = datetime(2016, 6, 9, 1, tzinfo=dt_util.UTC)
async def test_default_setup(hass, aioclient_mock):
async def test_default_setup(hass, legacy_patchable_time, aioclient_mock):
"""Test the default setup."""
aioclient_mock.get(
"https://aa015h6buqvih86i1.api.met.no/weatherapi/locationforecast/1.9/",
@ -19,6 +19,7 @@ async def test_default_setup(hass, aioclient_mock):
)
config = {"platform": "yr", "elevation": 0}
hass.allow_pool = True
with patch(
"homeassistant.components.yr.sensor.dt_util.utcnow", return_value=NOW
), assert_setup_component(1):
@ -31,7 +32,7 @@ async def test_default_setup(hass, aioclient_mock):
assert state.attributes.get("unit_of_measurement") is None
async def test_custom_setup(hass, aioclient_mock):
async def test_custom_setup(hass, legacy_patchable_time, aioclient_mock):
"""Test a custom setup."""
aioclient_mock.get(
"https://aa015h6buqvih86i1.api.met.no/weatherapi/locationforecast/1.9/",
@ -50,6 +51,7 @@ async def test_custom_setup(hass, aioclient_mock):
],
}
hass.allow_pool = True
with patch(
"homeassistant.components.yr.sensor.dt_util.utcnow", return_value=NOW
), assert_setup_component(1):
@ -77,7 +79,7 @@ async def test_custom_setup(hass, aioclient_mock):
assert state.state == "3.5"
async def test_forecast_setup(hass, aioclient_mock):
async def test_forecast_setup(hass, legacy_patchable_time, aioclient_mock):
"""Test a custom setup with 24h forecast."""
aioclient_mock.get(
"https://aa015h6buqvih86i1.api.met.no/weatherapi/locationforecast/1.9/",
@ -97,6 +99,7 @@ async def test_forecast_setup(hass, aioclient_mock):
],
}
hass.allow_pool = True
with patch(
"homeassistant.components.yr.sensor.dt_util.utcnow", return_value=NOW
), assert_setup_component(1):

View file

@ -5,7 +5,7 @@ import logging
import pytest
import requests_mock as _requests_mock
from homeassistant import core as ha, util
from homeassistant import core as ha, loader, util
from homeassistant.auth.const import GROUP_ID_ADMIN, GROUP_ID_READ_ONLY
from homeassistant.auth.providers import homeassistant, legacy_api_password
from homeassistant.components import mqtt
@ -15,7 +15,9 @@ from homeassistant.components.websocket_api.auth import (
TYPE_AUTH_REQUIRED,
)
from homeassistant.components.websocket_api.http import URL
from homeassistant.const import ATTR_NOW, EVENT_TIME_CHANGED
from homeassistant.exceptions import ServiceNotFound
from homeassistant.helpers import event
from homeassistant.setup import async_setup_component
from homeassistant.util import location
@ -315,3 +317,43 @@ async def mqtt_mock(hass, mqtt_client_mock, mqtt_config):
component = hass.data["mqtt"]
component.reset_mock()
return component
@pytest.fixture
def legacy_patchable_time():
"""Allow time to be patchable by using event listeners instead of asyncio loop."""
@ha.callback
@loader.bind_hass
def async_track_point_in_utc_time(hass, action, point_in_time):
"""Add a listener that fires once after a specific point in UTC time."""
# Ensure point_in_time is UTC
point_in_time = event.dt_util.as_utc(point_in_time)
@ha.callback
def point_in_time_listener(event):
"""Listen for matching time_changed events."""
now = event.data[ATTR_NOW]
if now < point_in_time or hasattr(point_in_time_listener, "run"):
return
# Set variable so that we will never run twice.
# Because the event bus might have to wait till a thread comes
# available to execute this listener it might occur that the
# listener gets lined up twice to be executed. This will make
# sure the second time it does nothing.
setattr(point_in_time_listener, "run", True)
async_unsub()
hass.async_run_job(action, now)
async_unsub = hass.bus.async_listen(EVENT_TIME_CHANGED, point_in_time_listener)
return async_unsub
with patch(
"homeassistant.helpers.event.async_track_point_in_utc_time",
async_track_point_in_utc_time,
):
yield

View file

@ -38,11 +38,6 @@ def teardown():
dt_util.set_default_time_zone(DEFAULT_TIME_ZONE)
def _send_time_changed(hass, now):
"""Send a time changed event."""
hass.bus.async_fire(ha.EVENT_TIME_CHANGED, {ha.ATTR_NOW: now})
async def test_track_point_in_time(hass):
"""Test track point in time."""
before_birthday = datetime(1985, 7, 9, 12, 0, 0, tzinfo=dt_util.UTC)
@ -55,16 +50,16 @@ async def test_track_point_in_time(hass):
hass, callback(lambda x: runs.append(1)), birthday_paulus
)
_send_time_changed(hass, before_birthday)
async_fire_time_changed(hass, before_birthday)
await hass.async_block_till_done()
assert len(runs) == 0
_send_time_changed(hass, birthday_paulus)
async_fire_time_changed(hass, birthday_paulus)
await hass.async_block_till_done()
assert len(runs) == 1
# A point in time tracker will only fire once, this should do nothing
_send_time_changed(hass, birthday_paulus)
async_fire_time_changed(hass, birthday_paulus)
await hass.async_block_till_done()
assert len(runs) == 1
@ -72,7 +67,7 @@ async def test_track_point_in_time(hass):
hass, callback(lambda x: runs.append(1)), birthday_paulus
)
_send_time_changed(hass, after_birthday)
async_fire_time_changed(hass, after_birthday)
await hass.async_block_till_done()
assert len(runs) == 2
@ -81,7 +76,7 @@ async def test_track_point_in_time(hass):
)
unsub()
_send_time_changed(hass, after_birthday)
async_fire_time_changed(hass, after_birthday)
await hass.async_block_till_done()
assert len(runs) == 2
@ -458,26 +453,26 @@ async def test_track_time_interval(hass):
hass, lambda x: specific_runs.append(1), timedelta(seconds=10)
)
_send_time_changed(hass, utc_now + timedelta(seconds=5))
async_fire_time_changed(hass, utc_now + timedelta(seconds=5))
await hass.async_block_till_done()
assert len(specific_runs) == 0
_send_time_changed(hass, utc_now + timedelta(seconds=13))
async_fire_time_changed(hass, utc_now + timedelta(seconds=13))
await hass.async_block_till_done()
assert len(specific_runs) == 1
_send_time_changed(hass, utc_now + timedelta(minutes=20))
async_fire_time_changed(hass, utc_now + timedelta(minutes=20))
await hass.async_block_till_done()
assert len(specific_runs) == 2
unsub()
_send_time_changed(hass, utc_now + timedelta(seconds=30))
async_fire_time_changed(hass, utc_now + timedelta(seconds=30))
await hass.async_block_till_done()
assert len(specific_runs) == 2
async def test_track_sunrise(hass):
async def test_track_sunrise(hass, legacy_patchable_time):
"""Test track the sunrise."""
latitude = 32.87336
longitude = 117.22743
@ -514,17 +509,17 @@ async def test_track_sunrise(hass):
unsub2 = async_track_sunrise(hass, lambda: offset_runs.append(1), offset)
# run tests
_send_time_changed(hass, next_rising - offset)
async_fire_time_changed(hass, next_rising - offset)
await hass.async_block_till_done()
assert len(runs) == 0
assert len(offset_runs) == 0
_send_time_changed(hass, next_rising)
async_fire_time_changed(hass, next_rising)
await hass.async_block_till_done()
assert len(runs) == 1
assert len(offset_runs) == 0
_send_time_changed(hass, next_rising + offset)
async_fire_time_changed(hass, next_rising + offset)
await hass.async_block_till_done()
assert len(runs) == 1
assert len(offset_runs) == 1
@ -532,13 +527,13 @@ async def test_track_sunrise(hass):
unsub()
unsub2()
_send_time_changed(hass, next_rising + offset)
async_fire_time_changed(hass, next_rising + offset)
await hass.async_block_till_done()
assert len(runs) == 1
assert len(offset_runs) == 1
async def test_track_sunrise_update_location(hass):
async def test_track_sunrise_update_location(hass, legacy_patchable_time):
"""Test track the sunrise."""
# Setup sun component
hass.config.latitude = 32.87336
@ -567,7 +562,7 @@ async def test_track_sunrise_update_location(hass):
async_track_sunrise(hass, lambda: runs.append(1))
# Mimic sunrise
_send_time_changed(hass, next_rising)
async_fire_time_changed(hass, next_rising)
await hass.async_block_till_done()
assert len(runs) == 1
@ -577,7 +572,7 @@ async def test_track_sunrise_update_location(hass):
await hass.async_block_till_done()
# Mimic sunrise
_send_time_changed(hass, next_rising)
async_fire_time_changed(hass, next_rising)
await hass.async_block_till_done()
# Did not increase
assert len(runs) == 1
@ -593,12 +588,12 @@ async def test_track_sunrise_update_location(hass):
mod += 1
# Mimic sunrise at new location
_send_time_changed(hass, next_rising)
async_fire_time_changed(hass, next_rising)
await hass.async_block_till_done()
assert len(runs) == 2
async def test_track_sunset(hass):
async def test_track_sunset(hass, legacy_patchable_time):
"""Test track the sunset."""
latitude = 32.87336
longitude = 117.22743
@ -635,17 +630,17 @@ async def test_track_sunset(hass):
unsub2 = async_track_sunset(hass, lambda: offset_runs.append(1), offset)
# Run tests
_send_time_changed(hass, next_setting - offset)
async_fire_time_changed(hass, next_setting - offset)
await hass.async_block_till_done()
assert len(runs) == 0
assert len(offset_runs) == 0
_send_time_changed(hass, next_setting)
async_fire_time_changed(hass, next_setting)
await hass.async_block_till_done()
assert len(runs) == 1
assert len(offset_runs) == 0
_send_time_changed(hass, next_setting + offset)
async_fire_time_changed(hass, next_setting + offset)
await hass.async_block_till_done()
assert len(runs) == 1
assert len(offset_runs) == 1
@ -653,7 +648,7 @@ async def test_track_sunset(hass):
unsub()
unsub2()
_send_time_changed(hass, next_setting + offset)
async_fire_time_changed(hass, next_setting + offset)
await hass.async_block_till_done()
assert len(runs) == 1
assert len(offset_runs) == 1
@ -669,17 +664,17 @@ async def test_async_track_time_change(hass):
hass, lambda x: specific_runs.append(1), second=[0, 30]
)
_send_time_changed(hass, datetime(2014, 5, 24, 12, 0, 0))
async_fire_time_changed(hass, datetime(2014, 5, 24, 12, 0, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 1
assert len(wildcard_runs) == 1
_send_time_changed(hass, datetime(2014, 5, 24, 12, 0, 15))
async_fire_time_changed(hass, datetime(2014, 5, 24, 12, 0, 15))
await hass.async_block_till_done()
assert len(specific_runs) == 1
assert len(wildcard_runs) == 2
_send_time_changed(hass, datetime(2014, 5, 24, 12, 0, 30))
async_fire_time_changed(hass, datetime(2014, 5, 24, 12, 0, 30))
await hass.async_block_till_done()
assert len(specific_runs) == 2
assert len(wildcard_runs) == 3
@ -687,7 +682,7 @@ async def test_async_track_time_change(hass):
unsub()
unsub_utc()
_send_time_changed(hass, datetime(2014, 5, 24, 12, 0, 30))
async_fire_time_changed(hass, datetime(2014, 5, 24, 12, 0, 30))
await hass.async_block_till_done()
assert len(specific_runs) == 2
assert len(wildcard_runs) == 3
@ -701,21 +696,21 @@ async def test_periodic_task_minute(hass):
hass, lambda x: specific_runs.append(1), minute="/5", second=0
)
_send_time_changed(hass, datetime(2014, 5, 24, 12, 0, 0))
async_fire_time_changed(hass, datetime(2014, 5, 24, 12, 0, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 1
_send_time_changed(hass, datetime(2014, 5, 24, 12, 3, 0))
async_fire_time_changed(hass, datetime(2014, 5, 24, 12, 3, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 1
_send_time_changed(hass, datetime(2014, 5, 24, 12, 5, 0))
async_fire_time_changed(hass, datetime(2014, 5, 24, 12, 5, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 2
unsub()
_send_time_changed(hass, datetime(2014, 5, 24, 12, 5, 0))
async_fire_time_changed(hass, datetime(2014, 5, 24, 12, 5, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 2
@ -728,29 +723,29 @@ async def test_periodic_task_hour(hass):
hass, lambda x: specific_runs.append(1), hour="/2", minute=0, second=0
)
_send_time_changed(hass, datetime(2014, 5, 24, 22, 0, 0))
async_fire_time_changed(hass, datetime(2014, 5, 24, 22, 0, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 1
_send_time_changed(hass, datetime(2014, 5, 24, 23, 0, 0))
async_fire_time_changed(hass, datetime(2014, 5, 24, 23, 0, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 1
_send_time_changed(hass, datetime(2014, 5, 25, 0, 0, 0))
async_fire_time_changed(hass, datetime(2014, 5, 25, 0, 0, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 2
_send_time_changed(hass, datetime(2014, 5, 25, 1, 0, 0))
async_fire_time_changed(hass, datetime(2014, 5, 25, 1, 0, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 2
_send_time_changed(hass, datetime(2014, 5, 25, 2, 0, 0))
async_fire_time_changed(hass, datetime(2014, 5, 25, 2, 0, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 3
unsub()
_send_time_changed(hass, datetime(2014, 5, 25, 2, 0, 0))
async_fire_time_changed(hass, datetime(2014, 5, 25, 2, 0, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 3
@ -764,7 +759,7 @@ async def test_periodic_task_wrong_input(hass):
hass, lambda x: specific_runs.append(1), hour="/two"
)
_send_time_changed(hass, datetime(2014, 5, 2, 0, 0, 0))
async_fire_time_changed(hass, datetime(2014, 5, 2, 0, 0, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 0
@ -777,29 +772,29 @@ async def test_periodic_task_clock_rollback(hass):
hass, lambda x: specific_runs.append(1), hour="/2", minute=0, second=0
)
_send_time_changed(hass, datetime(2014, 5, 24, 22, 0, 0))
async_fire_time_changed(hass, datetime(2014, 5, 24, 22, 0, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 1
_send_time_changed(hass, datetime(2014, 5, 24, 23, 0, 0))
async_fire_time_changed(hass, datetime(2014, 5, 24, 23, 0, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 1
_send_time_changed(hass, datetime(2014, 5, 24, 22, 0, 0))
async_fire_time_changed(hass, datetime(2014, 5, 24, 22, 0, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 2
_send_time_changed(hass, datetime(2014, 5, 24, 0, 0, 0))
async_fire_time_changed(hass, datetime(2014, 5, 24, 0, 0, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 3
_send_time_changed(hass, datetime(2014, 5, 25, 2, 0, 0))
async_fire_time_changed(hass, datetime(2014, 5, 25, 2, 0, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 4
unsub()
_send_time_changed(hass, datetime(2014, 5, 25, 2, 0, 0))
async_fire_time_changed(hass, datetime(2014, 5, 25, 2, 0, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 4
@ -812,15 +807,15 @@ async def test_periodic_task_duplicate_time(hass):
hass, lambda x: specific_runs.append(1), hour="/2", minute=0, second=0
)
_send_time_changed(hass, datetime(2014, 5, 24, 22, 0, 0))
async_fire_time_changed(hass, datetime(2014, 5, 24, 22, 0, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 1
_send_time_changed(hass, datetime(2014, 5, 24, 22, 0, 0))
async_fire_time_changed(hass, datetime(2014, 5, 24, 22, 0, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 1
_send_time_changed(hass, datetime(2014, 5, 25, 0, 0, 0))
async_fire_time_changed(hass, datetime(2014, 5, 25, 0, 0, 0))
await hass.async_block_till_done()
assert len(specific_runs) == 2
@ -837,19 +832,19 @@ async def test_periodic_task_entering_dst(hass):
hass, lambda x: specific_runs.append(1), hour=2, minute=30, second=0
)
_send_time_changed(hass, timezone.localize(datetime(2018, 3, 25, 1, 50, 0)))
async_fire_time_changed(hass, timezone.localize(datetime(2018, 3, 25, 1, 50, 0)))
await hass.async_block_till_done()
assert len(specific_runs) == 0
_send_time_changed(hass, timezone.localize(datetime(2018, 3, 25, 3, 50, 0)))
async_fire_time_changed(hass, timezone.localize(datetime(2018, 3, 25, 3, 50, 0)))
await hass.async_block_till_done()
assert len(specific_runs) == 0
_send_time_changed(hass, timezone.localize(datetime(2018, 3, 26, 1, 50, 0)))
async_fire_time_changed(hass, timezone.localize(datetime(2018, 3, 26, 1, 50, 0)))
await hass.async_block_till_done()
assert len(specific_runs) == 0
_send_time_changed(hass, timezone.localize(datetime(2018, 3, 26, 2, 50, 0)))
async_fire_time_changed(hass, timezone.localize(datetime(2018, 3, 26, 2, 50, 0)))
await hass.async_block_till_done()
assert len(specific_runs) == 1
@ -866,25 +861,25 @@ async def test_periodic_task_leaving_dst(hass):
hass, lambda x: specific_runs.append(1), hour=2, minute=30, second=0
)
_send_time_changed(
async_fire_time_changed(
hass, timezone.localize(datetime(2018, 10, 28, 2, 5, 0), is_dst=False)
)
await hass.async_block_till_done()
assert len(specific_runs) == 0
_send_time_changed(
async_fire_time_changed(
hass, timezone.localize(datetime(2018, 10, 28, 2, 55, 0), is_dst=False)
)
await hass.async_block_till_done()
assert len(specific_runs) == 1
_send_time_changed(
async_fire_time_changed(
hass, timezone.localize(datetime(2018, 10, 28, 2, 5, 0), is_dst=True)
)
await hass.async_block_till_done()
assert len(specific_runs) == 1
_send_time_changed(
async_fire_time_changed(
hass, timezone.localize(datetime(2018, 10, 28, 2, 55, 0), is_dst=True)
)
await hass.async_block_till_done()