diff --git a/tests/components/time_date/test_sensor.py b/tests/components/time_date/test_sensor.py index 150ea4e8225..4989a65984b 100644 --- a/tests/components/time_date/test_sensor.py +++ b/tests/components/time_date/test_sensor.py @@ -1,181 +1,275 @@ """The tests for time_date sensor platform.""" +from unittest.mock import ANY, Mock, patch + from freezegun.api import FrozenDateTimeFactory import pytest from homeassistant.components.time_date.const import DOMAIN import homeassistant.components.time_date.sensor as time_date from homeassistant.core import HomeAssistant -from homeassistant.helpers import issue_registry as ir +from homeassistant.helpers import event, issue_registry as ir from homeassistant.setup import async_setup_component import homeassistant.util.dt as dt_util +from tests.common import async_fire_time_changed -async def test_intervals(hass: HomeAssistant, freezer: FrozenDateTimeFactory) -> None: - """Test timing intervals of sensors.""" - device = time_date.TimeDateSensor(hass, "time") - now = dt_util.utc_from_timestamp(45.5) - freezer.move_to(now) - next_time = device.get_next_interval() - assert next_time == dt_util.utc_from_timestamp(60) - - device = time_date.TimeDateSensor(hass, "beat") - now = dt_util.parse_datetime("2020-11-13 00:00:29+01:00") - freezer.move_to(now) - next_time = device.get_next_interval() - assert next_time == dt_util.parse_datetime("2020-11-13 00:01:26.4+01:00") - - device = time_date.TimeDateSensor(hass, "date_time") - now = dt_util.utc_from_timestamp(1495068899) - freezer.move_to(now) - next_time = device.get_next_interval() - assert next_time == dt_util.utc_from_timestamp(1495068900) - - now = dt_util.utcnow() - device = time_date.TimeDateSensor(hass, "time_date") - next_time = device.get_next_interval() - assert next_time > now +ALL_DISPLAY_OPTIONS = list(time_date.OPTION_TYPES.keys()) +CONFIG = {"sensor": {"platform": "time_date", "display_options": ALL_DISPLAY_OPTIONS}} -async def test_states(hass: HomeAssistant) -> None: +@patch("homeassistant.components.time_date.sensor.async_track_point_in_utc_time") +@pytest.mark.parametrize( + ("display_option", "start_time", "tracked_time"), + [ + ( + "time", + dt_util.utc_from_timestamp(45.5), + dt_util.utc_from_timestamp(60), + ), + ( + "beat", + dt_util.parse_datetime("2020-11-13 00:00:29+01:00"), + dt_util.parse_datetime("2020-11-13 00:01:26.4+01:00"), + ), + ( + "date_time", + dt_util.utc_from_timestamp(1495068899), + dt_util.utc_from_timestamp(1495068900), + ), + ( + "time_date", + dt_util.utc_from_timestamp(1495068899), + dt_util.utc_from_timestamp(1495068900), + ), + ], +) +async def test_intervals( + mock_track_interval: Mock, + hass: HomeAssistant, + freezer: FrozenDateTimeFactory, + display_option: str, + start_time, + tracked_time, +) -> None: + """Test timing intervals of sensors when time zone is UTC.""" + hass.config.set_time_zone("UTC") + config = {"sensor": {"platform": "time_date", "display_options": [display_option]}} + + freezer.move_to(start_time) + + await async_setup_component(hass, "sensor", config) + await hass.async_block_till_done() + + mock_track_interval.assert_called_once_with(hass, ANY, tracked_time) + + +async def test_states(hass: HomeAssistant, freezer: FrozenDateTimeFactory) -> None: """Test states of sensors.""" hass.config.set_time_zone("UTC") - now = dt_util.utc_from_timestamp(1495068856) - device = time_date.TimeDateSensor(hass, "time") - device._update_internal_state(now) - assert device.state == "00:54" + freezer.move_to(now) - device = time_date.TimeDateSensor(hass, "date") - device._update_internal_state(now) - assert device.state == "2017-05-18" + await async_setup_component(hass, "sensor", CONFIG) + await hass.async_block_till_done() - device = time_date.TimeDateSensor(hass, "time_utc") - device._update_internal_state(now) - assert device.state == "00:54" + state = hass.states.get("sensor.time") + assert state.state == "00:54" - device = time_date.TimeDateSensor(hass, "date_time") - device._update_internal_state(now) - assert device.state == "2017-05-18, 00:54" + state = hass.states.get("sensor.date") + assert state.state == "2017-05-18" - device = time_date.TimeDateSensor(hass, "date_time_utc") - device._update_internal_state(now) - assert device.state == "2017-05-18, 00:54" + state = hass.states.get("sensor.time_utc") + assert state.state == "00:54" - device = time_date.TimeDateSensor(hass, "beat") - device._update_internal_state(now) - assert device.state == "@079" - device._update_internal_state(dt_util.utc_from_timestamp(1602952963.2)) - assert device.state == "@738" + state = hass.states.get("sensor.date_time") + assert state.state == "2017-05-18, 00:54" - device = time_date.TimeDateSensor(hass, "date_time_iso") - device._update_internal_state(now) - assert device.state == "2017-05-18T00:54:00" + state = hass.states.get("sensor.date_time_utc") + assert state.state == "2017-05-18, 00:54" + + state = hass.states.get("sensor.internet_time") + assert state.state == "@079" + + state = hass.states.get("sensor.date_time_iso") + assert state.state == "2017-05-18T00:54:00" + + now = dt_util.utc_from_timestamp(1602952963.2) + freezer.move_to(now) + async_fire_time_changed(hass, now) + await hass.async_block_till_done() + + # The time should be 2020-10-17 18:42 / @738, however the time_date sensor + # does not check the current time when calculating the state, it instead checks + # the time when it expected an update + state = hass.states.get("sensor.time") + assert state.state == "00:55" + + state = hass.states.get("sensor.date") + assert state.state == "2017-05-19" + + state = hass.states.get("sensor.time_utc") + assert state.state == "00:55" + + state = hass.states.get("sensor.date_time") + assert state.state == "2017-05-18, 00:55" + + state = hass.states.get("sensor.date_time_utc") + assert state.state == "2017-05-18, 00:55" + + state = hass.states.get("sensor.internet_time") + assert state.state == "@080" + + state = hass.states.get("sensor.date_time_iso") + assert state.state == "2017-05-18T00:55:00" -async def test_states_non_default_timezone(hass: HomeAssistant) -> None: +async def test_states_non_default_timezone( + hass: HomeAssistant, freezer: FrozenDateTimeFactory +) -> None: """Test states of sensors in a timezone other than UTC.""" hass.config.set_time_zone("America/New_York") - now = dt_util.utc_from_timestamp(1495068856) - device = time_date.TimeDateSensor(hass, "time") - device._update_internal_state(now) - assert device.state == "20:54" + freezer.move_to(now) - device = time_date.TimeDateSensor(hass, "date") - device._update_internal_state(now) - assert device.state == "2017-05-17" + await async_setup_component(hass, "sensor", CONFIG) + await hass.async_block_till_done() - device = time_date.TimeDateSensor(hass, "time_utc") - device._update_internal_state(now) - assert device.state == "00:54" + state = hass.states.get("sensor.time") + assert state.state == "20:54" - device = time_date.TimeDateSensor(hass, "date_time") - device._update_internal_state(now) - assert device.state == "2017-05-17, 20:54" + state = hass.states.get("sensor.date") + assert state.state == "2017-05-17" - device = time_date.TimeDateSensor(hass, "date_time_utc") - device._update_internal_state(now) - assert device.state == "2017-05-18, 00:54" + state = hass.states.get("sensor.time_utc") + assert state.state == "00:54" - device = time_date.TimeDateSensor(hass, "beat") - device._update_internal_state(now) - assert device.state == "@079" + state = hass.states.get("sensor.date_time") + assert state.state == "2017-05-17, 20:54" - device = time_date.TimeDateSensor(hass, "date_time_iso") - device._update_internal_state(now) - assert device.state == "2017-05-17T20:54:00" + state = hass.states.get("sensor.date_time_utc") + assert state.state == "2017-05-18, 00:54" + + state = hass.states.get("sensor.internet_time") + assert state.state == "@079" + + state = hass.states.get("sensor.date_time_iso") + assert state.state == "2017-05-17T20:54:00" + + now = dt_util.utc_from_timestamp(1602952963.2) + freezer.move_to(now) + async_fire_time_changed(hass, now) + await hass.async_block_till_done() + + # The time should be 2020-10-17 12:42 / @738, however the time_date sensor + # does not check the current time when calculating the state, it instead checks + # the time when it expected an update + state = hass.states.get("sensor.time") + assert state.state == "20:55" + + state = hass.states.get("sensor.date") + assert state.state == "2017-05-18" + + state = hass.states.get("sensor.time_utc") + assert state.state == "00:55" + + state = hass.states.get("sensor.date_time") + assert state.state == "2017-05-17, 20:55" + + state = hass.states.get("sensor.date_time_utc") + assert state.state == "2017-05-18, 00:55" + + state = hass.states.get("sensor.internet_time") + assert state.state == "@080" + + state = hass.states.get("sensor.date_time_iso") + assert state.state == "2017-05-17T20:55:00" +@patch( + "homeassistant.components.time_date.sensor.async_track_point_in_utc_time", + side_effect=event.async_track_point_in_utc_time, +) +@pytest.mark.parametrize( + ("time_zone", "start_time", "tracked_time"), + [ + ( + "America/New_York", + dt_util.utc_from_timestamp(50000), + # start of local day in EST was 18000.0 + # so the second day was 18000 + 86400 + 104400, + ), + ( + "America/Edmonton", + dt_util.parse_datetime("2017-11-13 19:47:19-07:00"), + dt_util.as_timestamp("2017-11-14 00:00:00-07:00"), + ), + # Entering DST + ( + "Europe/Prague", + dt_util.parse_datetime("2020-03-29 00:00+01:00"), + dt_util.as_timestamp("2020-03-30 00:00+02:00"), + ), + ( + "Europe/Prague", + dt_util.parse_datetime("2020-03-29 03:00+02:00"), + dt_util.as_timestamp("2020-03-30 00:00+02:00"), + ), + # Leaving DST + ( + "Europe/Prague", + dt_util.parse_datetime("2020-10-25 00:00+02:00"), + dt_util.as_timestamp("2020-10-26 00:00+01:00"), + ), + ( + "Europe/Prague", + dt_util.parse_datetime("2020-10-25 23:59+01:00"), + dt_util.as_timestamp("2020-10-26 00:00+01:00"), + ), + ], +) async def test_timezone_intervals( - hass: HomeAssistant, freezer: FrozenDateTimeFactory + mock_track_interval: Mock, + hass: HomeAssistant, + freezer: FrozenDateTimeFactory, + time_zone: str, + start_time, + tracked_time, ) -> None: - """Test date sensor behavior in a timezone besides UTC.""" - hass.config.set_time_zone("America/New_York") + """Test timing intervals of sensors in timezone other than UTC.""" + hass.config.set_time_zone(time_zone) + freezer.move_to(start_time) - device = time_date.TimeDateSensor(hass, "date") - now = dt_util.utc_from_timestamp(50000) - freezer.move_to(now) - next_time = device.get_next_interval() - # start of local day in EST was 18000.0 - # so the second day was 18000 + 86400 - assert next_time.timestamp() == 104400 + config = {"sensor": {"platform": "time_date", "display_options": ["date"]}} + await async_setup_component(hass, "sensor", config) + await hass.async_block_till_done() - hass.config.set_time_zone("America/Edmonton") - now = dt_util.parse_datetime("2017-11-13 19:47:19-07:00") - device = time_date.TimeDateSensor(hass, "date") - freezer.move_to(now) - next_time = device.get_next_interval() - assert next_time.timestamp() == dt_util.as_timestamp("2017-11-14 00:00:00-07:00") + mock_track_interval.assert_called_once() + next_time = mock_track_interval.mock_calls[0][1][2] - # Entering DST - hass.config.set_time_zone("Europe/Prague") - - now = dt_util.parse_datetime("2020-03-29 00:00+01:00") - freezer.move_to(now) - next_time = device.get_next_interval() - assert next_time.timestamp() == dt_util.as_timestamp("2020-03-30 00:00+02:00") - - now = dt_util.parse_datetime("2020-03-29 03:00+02:00") - freezer.move_to(now) - next_time = device.get_next_interval() - assert next_time.timestamp() == dt_util.as_timestamp("2020-03-30 00:00+02:00") - - # Leaving DST - now = dt_util.parse_datetime("2020-10-25 00:00+02:00") - freezer.move_to(now) - next_time = device.get_next_interval() - assert next_time.timestamp() == dt_util.as_timestamp("2020-10-26 00:00:00+01:00") - - now = dt_util.parse_datetime("2020-10-25 23:59+01:00") - freezer.move_to(now) - next_time = device.get_next_interval() - assert next_time.timestamp() == dt_util.as_timestamp("2020-10-26 00:00:00+01:00") - - -async def test_timezone_intervals_empty_parameter( - hass: HomeAssistant, freezer: FrozenDateTimeFactory -) -> None: - """Test get_interval() without parameters.""" - freezer.move_to(dt_util.parse_datetime("2017-11-14 02:47:19-00:00")) - hass.config.set_time_zone("America/Edmonton") - device = time_date.TimeDateSensor(hass, "date") - next_time = device.get_next_interval() - assert next_time.timestamp() == dt_util.as_timestamp("2017-11-14 00:00:00-07:00") + assert next_time.timestamp() == tracked_time async def test_icons(hass: HomeAssistant) -> None: """Test attributes of sensors.""" - device = time_date.TimeDateSensor(hass, "time") - assert device.icon == "mdi:clock" - device = time_date.TimeDateSensor(hass, "date") - assert device.icon == "mdi:calendar" - device = time_date.TimeDateSensor(hass, "date_time") - assert device.icon == "mdi:calendar-clock" - device = time_date.TimeDateSensor(hass, "date_time_utc") - assert device.icon == "mdi:calendar-clock" - device = time_date.TimeDateSensor(hass, "date_time_iso") - assert device.icon == "mdi:calendar-clock" + await async_setup_component(hass, "sensor", CONFIG) + await hass.async_block_till_done() + + state = hass.states.get("sensor.time") + assert state.attributes["icon"] == "mdi:clock" + state = hass.states.get("sensor.date") + assert state.attributes["icon"] == "mdi:calendar" + state = hass.states.get("sensor.time_utc") + assert state.attributes["icon"] == "mdi:clock" + state = hass.states.get("sensor.date_time") + assert state.attributes["icon"] == "mdi:calendar-clock" + state = hass.states.get("sensor.date_time_utc") + assert state.attributes["icon"] == "mdi:calendar-clock" + state = hass.states.get("sensor.internet_time") + assert state.attributes["icon"] == "mdi:clock" + state = hass.states.get("sensor.date_time_iso") + assert state.attributes["icon"] == "mdi:calendar-clock" @pytest.mark.parametrize(