Run statistics on 5-minute intervals in tests (#122592)

* Run statistics on 5-minute intervals in tests

* Fix test failing when mysql does not return rows in insert order
This commit is contained in:
Erik Montnemery 2024-07-25 17:32:49 +02:00 committed by GitHub
parent 08d7beb803
commit ec957e4a94
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 226 additions and 104 deletions

View File

@ -79,10 +79,18 @@ async def async_block_recorder(hass: HomeAssistant, seconds: float) -> None:
await event.wait() await event.wait()
def get_start_time(start: datetime) -> datetime:
"""Calculate a valid start time for statistics."""
start_minutes = start.minute - start.minute % 5
return start.replace(minute=start_minutes, second=0, microsecond=0)
def do_adhoc_statistics(hass: HomeAssistant, **kwargs: Any) -> None: def do_adhoc_statistics(hass: HomeAssistant, **kwargs: Any) -> None:
"""Trigger an adhoc statistics run.""" """Trigger an adhoc statistics run."""
if not (start := kwargs.get("start")): if not (start := kwargs.get("start")):
start = statistics.get_start_time() start = statistics.get_start_time()
elif (start.minute % 5) != 0 or start.second != 0 or start.microsecond != 0:
raise ValueError(f"Statistics must start on 5 minute boundary got {start}")
get_instance(hass).queue_task(StatisticsTask(start, False)) get_instance(hass).queue_task(StatisticsTask(start, False))
@ -291,11 +299,11 @@ def record_states(hass):
wait_recording_done(hass) wait_recording_done(hass)
return hass.states.get(entity_id) return hass.states.get(entity_id)
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
one = zero + timedelta(seconds=1 * 5) one = zero + timedelta(seconds=1 * 5)
two = one + timedelta(seconds=15 * 5) two = one + timedelta(seconds=15 * 5)
three = two + timedelta(seconds=30 * 5) three = two + timedelta(seconds=30 * 5)
four = three + timedelta(seconds=15 * 5) four = three + timedelta(seconds=14 * 5)
states = {mp: [], sns1: [], sns2: [], sns3: [], sns4: []} states = {mp: [], sns1: [], sns2: [], sns3: [], sns4: []}
with freeze_time(one) as freezer: with freeze_time(one) as freezer:

View File

@ -44,6 +44,7 @@ from .common import (
async_record_states, async_record_states,
async_wait_recording_done, async_wait_recording_done,
do_adhoc_statistics, do_adhoc_statistics,
get_start_time,
statistics_during_period, statistics_during_period,
) )
@ -342,7 +343,7 @@ async def test_compile_periodic_statistics_exception(
"""Test exception handling when compiling periodic statistics.""" """Test exception handling when compiling periodic statistics."""
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
do_adhoc_statistics(hass, start=now) do_adhoc_statistics(hass, start=now)
do_adhoc_statistics(hass, start=now + timedelta(minutes=5)) do_adhoc_statistics(hass, start=now + timedelta(minutes=5))
await async_wait_recording_done(hass) await async_wait_recording_done(hass)

View File

@ -35,6 +35,7 @@ from .common import (
async_wait_recording_done, async_wait_recording_done,
create_engine_test, create_engine_test,
do_adhoc_statistics, do_adhoc_statistics,
get_start_time,
statistics_during_period, statistics_during_period,
) )
from .conftest import InstrumentedMigration from .conftest import InstrumentedMigration
@ -155,12 +156,17 @@ async def test_statistics_during_period(
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
) -> None: ) -> None:
"""Test statistics_during_period.""" """Test statistics_during_period."""
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
hass.config.units = US_CUSTOMARY_SYSTEM hass.config.units = US_CUSTOMARY_SYSTEM
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
hass.states.async_set("sensor.test", 10, attributes=POWER_SENSOR_KW_ATTRIBUTES) hass.states.async_set(
"sensor.test",
10,
attributes=POWER_SENSOR_KW_ATTRIBUTES,
timestamp=now.timestamp(),
)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
do_adhoc_statistics(hass, start=now) do_adhoc_statistics(hass, start=now)
@ -608,7 +614,12 @@ async def test_statistic_during_period(
} }
# Test we can automatically convert units # Test we can automatically convert units
hass.states.async_set("sensor.test", None, attributes=ENERGY_SENSOR_WH_ATTRIBUTES) hass.states.async_set(
"sensor.test",
None,
attributes=ENERGY_SENSOR_WH_ATTRIBUTES,
timestamp=now.timestamp(),
)
await client.send_json_auto_id( await client.send_json_auto_id(
{ {
"type": "recorder/statistic_during_period", "type": "recorder/statistic_during_period",
@ -1265,11 +1276,13 @@ async def test_statistics_during_period_unit_conversion(
converted_value, converted_value,
) -> None: ) -> None:
"""Test statistics_during_period.""" """Test statistics_during_period."""
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
hass.states.async_set("sensor.test", state, attributes=attributes) hass.states.async_set(
"sensor.test", state, attributes=attributes, timestamp=now.timestamp()
)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
do_adhoc_statistics(hass, start=now) do_adhoc_statistics(hass, start=now)
@ -1350,12 +1363,16 @@ async def test_sum_statistics_during_period_unit_conversion(
converted_value, converted_value,
) -> None: ) -> None:
"""Test statistics_during_period.""" """Test statistics_during_period."""
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
hass.states.async_set("sensor.test", 0, attributes=attributes) hass.states.async_set(
hass.states.async_set("sensor.test", state, attributes=attributes) "sensor.test", 0, attributes=attributes, timestamp=now.timestamp()
)
hass.states.async_set(
"sensor.test", state, attributes=attributes, timestamp=now.timestamp()
)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
do_adhoc_statistics(hass, start=now) do_adhoc_statistics(hass, start=now)
@ -1471,7 +1488,7 @@ async def test_statistics_during_period_in_the_past(
) -> None: ) -> None:
"""Test statistics_during_period in the past.""" """Test statistics_during_period in the past."""
await hass.config.async_set_time_zone("UTC") await hass.config.async_set_time_zone("UTC")
now = dt_util.utcnow().replace() now = get_start_time(dt_util.utcnow())
hass.config.units = US_CUSTOMARY_SYSTEM hass.config.units = US_CUSTOMARY_SYSTEM
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
@ -1726,7 +1743,7 @@ async def test_list_statistic_ids(
unit_class, unit_class,
) -> None: ) -> None:
"""Test list_statistic_ids.""" """Test list_statistic_ids."""
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
has_mean = attributes["state_class"] == "measurement" has_mean = attributes["state_class"] == "measurement"
has_sum = not has_mean has_sum = not has_mean
@ -1740,7 +1757,9 @@ async def test_list_statistic_ids(
assert response["success"] assert response["success"]
assert response["result"] == [] assert response["result"] == []
hass.states.async_set("sensor.test", 10, attributes=attributes) hass.states.async_set(
"sensor.test", 10, attributes=attributes, timestamp=now.timestamp()
)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
await client.send_json_auto_id({"type": "recorder/list_statistic_ids"}) await client.send_json_auto_id({"type": "recorder/list_statistic_ids"})
@ -1890,7 +1909,7 @@ async def test_list_statistic_ids_unit_change(
unit_class, unit_class,
) -> None: ) -> None:
"""Test list_statistic_ids.""" """Test list_statistic_ids."""
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
has_mean = attributes["state_class"] == "measurement" has_mean = attributes["state_class"] == "measurement"
has_sum = not has_mean has_sum = not has_mean
@ -1903,7 +1922,9 @@ async def test_list_statistic_ids_unit_change(
assert response["success"] assert response["success"]
assert response["result"] == [] assert response["result"] == []
hass.states.async_set("sensor.test", 10, attributes=attributes) hass.states.async_set(
"sensor.test", 10, attributes=attributes, timestamp=now.timestamp()
)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
do_adhoc_statistics(hass, start=now) do_adhoc_statistics(hass, start=now)
@ -1926,7 +1947,9 @@ async def test_list_statistic_ids_unit_change(
] ]
# Change the state unit # Change the state unit
hass.states.async_set("sensor.test", 10, attributes=attributes2) hass.states.async_set(
"sensor.test", 10, attributes=attributes2, timestamp=now.timestamp()
)
await client.send_json_auto_id({"type": "recorder/list_statistic_ids"}) await client.send_json_auto_id({"type": "recorder/list_statistic_ids"})
response = await client.receive_json() response = await client.receive_json()
@ -1965,7 +1988,7 @@ async def test_clear_statistics(
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
) -> None: ) -> None:
"""Test removing statistics.""" """Test removing statistics."""
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
units = METRIC_SYSTEM units = METRIC_SYSTEM
attributes = POWER_SENSOR_KW_ATTRIBUTES attributes = POWER_SENSOR_KW_ATTRIBUTES
@ -1975,9 +1998,15 @@ async def test_clear_statistics(
hass.config.units = units hass.config.units = units
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
hass.states.async_set("sensor.test1", state, attributes=attributes) hass.states.async_set(
hass.states.async_set("sensor.test2", state * 2, attributes=attributes) "sensor.test1", state, attributes=attributes, timestamp=now.timestamp()
hass.states.async_set("sensor.test3", state * 3, attributes=attributes) )
hass.states.async_set(
"sensor.test2", state * 2, attributes=attributes, timestamp=now.timestamp()
)
hass.states.async_set(
"sensor.test3", state * 3, attributes=attributes, timestamp=now.timestamp()
)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
do_adhoc_statistics(hass, start=now) do_adhoc_statistics(hass, start=now)
@ -2088,7 +2117,7 @@ async def test_update_statistics_metadata(
new_display_unit, new_display_unit,
) -> None: ) -> None:
"""Test removing statistics.""" """Test removing statistics."""
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
units = METRIC_SYSTEM units = METRIC_SYSTEM
attributes = POWER_SENSOR_KW_ATTRIBUTES | {"device_class": None} attributes = POWER_SENSOR_KW_ATTRIBUTES | {"device_class": None}
@ -2097,7 +2126,9 @@ async def test_update_statistics_metadata(
hass.config.units = units hass.config.units = units
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
hass.states.async_set("sensor.test", state, attributes=attributes) hass.states.async_set(
"sensor.test", state, attributes=attributes, timestamp=now.timestamp()
)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
do_adhoc_statistics(hass, period="hourly", start=now) do_adhoc_statistics(hass, period="hourly", start=now)
@ -2177,7 +2208,7 @@ async def test_change_statistics_unit(
recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator recorder_mock: Recorder, hass: HomeAssistant, hass_ws_client: WebSocketGenerator
) -> None: ) -> None:
"""Test change unit of recorded statistics.""" """Test change unit of recorded statistics."""
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
units = METRIC_SYSTEM units = METRIC_SYSTEM
attributes = POWER_SENSOR_KW_ATTRIBUTES | {"device_class": None} attributes = POWER_SENSOR_KW_ATTRIBUTES | {"device_class": None}
@ -2186,7 +2217,9 @@ async def test_change_statistics_unit(
hass.config.units = units hass.config.units = units
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
hass.states.async_set("sensor.test", state, attributes=attributes) hass.states.async_set(
"sensor.test", state, attributes=attributes, timestamp=now.timestamp()
)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
do_adhoc_statistics(hass, period="hourly", start=now) do_adhoc_statistics(hass, period="hourly", start=now)
@ -2322,7 +2355,7 @@ async def test_change_statistics_unit_errors(
caplog: pytest.LogCaptureFixture, caplog: pytest.LogCaptureFixture,
) -> None: ) -> None:
"""Test change unit of recorded statistics.""" """Test change unit of recorded statistics."""
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
units = METRIC_SYSTEM units = METRIC_SYSTEM
attributes = POWER_SENSOR_KW_ATTRIBUTES | {"device_class": None} attributes = POWER_SENSOR_KW_ATTRIBUTES | {"device_class": None}
@ -2376,7 +2409,9 @@ async def test_change_statistics_unit_errors(
hass.config.units = units hass.config.units = units
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
hass.states.async_set("sensor.test", state, attributes=attributes) hass.states.async_set(
"sensor.test", state, attributes=attributes, timestamp=now.timestamp()
)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
do_adhoc_statistics(hass, period="hourly", start=now) do_adhoc_statistics(hass, period="hourly", start=now)
@ -2599,7 +2634,7 @@ async def test_get_statistics_metadata(
unit_class, unit_class,
) -> None: ) -> None:
"""Test get_statistics_metadata.""" """Test get_statistics_metadata."""
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
has_mean = attributes["state_class"] == "measurement" has_mean = attributes["state_class"] == "measurement"
has_sum = not has_mean has_sum = not has_mean
@ -2678,10 +2713,14 @@ async def test_get_statistics_metadata(
} }
] ]
hass.states.async_set("sensor.test", 10, attributes=attributes) hass.states.async_set(
"sensor.test", 10, attributes=attributes, timestamp=now.timestamp()
)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
hass.states.async_set("sensor.test2", 10, attributes=attributes) hass.states.async_set(
"sensor.test2", 10, attributes=attributes, timestamp=now.timestamp()
)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
await client.send_json_auto_id( await client.send_json_auto_id(

View File

@ -50,6 +50,7 @@ from tests.components.recorder.common import (
async_recorder_block_till_done, async_recorder_block_till_done,
async_wait_recording_done, async_wait_recording_done,
do_adhoc_statistics, do_adhoc_statistics,
get_start_time,
statistics_during_period, statistics_during_period,
) )
from tests.typing import ( from tests.typing import (
@ -194,7 +195,7 @@ async def test_compile_hourly_statistics(
max, max,
) -> None: ) -> None:
"""Test compiling hourly statistics.""" """Test compiling hourly statistics."""
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -278,7 +279,7 @@ async def test_compile_hourly_statistics_with_some_same_last_updated(
If the last updated value is the same we will have a zero duration. If the last updated value is the same we will have a zero duration.
""" """
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -392,7 +393,7 @@ async def test_compile_hourly_statistics_with_all_same_last_updated(
If the last updated value is the same we will have a zero duration. If the last updated value is the same we will have a zero duration.
""" """
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -498,7 +499,7 @@ async def test_compile_hourly_statistics_only_state_is_and_end_of_period(
max, max,
) -> None: ) -> None:
"""Test compiling hourly statistics when the only state at end of period.""" """Test compiling hourly statistics when the only state at end of period."""
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -592,7 +593,7 @@ async def test_compile_hourly_statistics_purged_state_changes(
unit_class, unit_class,
) -> None: ) -> None:
"""Test compiling hourly statistics.""" """Test compiling hourly statistics."""
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -663,7 +664,7 @@ async def test_compile_hourly_statistics_wrong_unit(
attributes, attributes,
) -> None: ) -> None:
"""Test compiling hourly statistics for sensor with unit not matching device class.""" """Test compiling hourly statistics for sensor with unit not matching device class."""
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -887,7 +888,7 @@ async def test_compile_hourly_sum_statistics_amount(
factor, factor,
) -> None: ) -> None:
"""Test compiling hourly statistics.""" """Test compiling hourly statistics."""
period0 = dt_util.utcnow() period0 = get_start_time(dt_util.utcnow())
period0_end = period1 = period0 + timedelta(minutes=5) period0_end = period1 = period0 + timedelta(minutes=5)
period1_end = period2 = period0 + timedelta(minutes=10) period1_end = period2 = period0 + timedelta(minutes=10)
period2_end = period0 + timedelta(minutes=15) period2_end = period0 + timedelta(minutes=15)
@ -1071,7 +1072,7 @@ async def test_compile_hourly_sum_statistics_amount_reset_every_state_change(
factor, factor,
) -> None: ) -> None:
"""Test compiling hourly statistics.""" """Test compiling hourly statistics."""
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -1194,7 +1195,7 @@ async def test_compile_hourly_sum_statistics_amount_invalid_last_reset(
factor, factor,
) -> None: ) -> None:
"""Test compiling hourly statistics.""" """Test compiling hourly statistics."""
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -1294,7 +1295,7 @@ async def test_compile_hourly_sum_statistics_nan_inf_state(
factor, factor,
) -> None: ) -> None:
"""Test compiling hourly statistics with nan and inf states.""" """Test compiling hourly statistics with nan and inf states."""
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -1429,7 +1430,7 @@ async def test_compile_hourly_sum_statistics_negative_state(
offset, offset,
) -> None: ) -> None:
"""Test compiling hourly statistics with negative states.""" """Test compiling hourly statistics with negative states."""
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
hass.data.pop(loader.DATA_CUSTOM_COMPONENTS) hass.data.pop(loader.DATA_CUSTOM_COMPONENTS)
mocksensor = MockSensor(name="custom_sensor") mocksensor = MockSensor(name="custom_sensor")
@ -1437,6 +1438,7 @@ async def test_compile_hourly_sum_statistics_negative_state(
setup_test_component_platform(hass, DOMAIN, [mocksensor], built_in=False) setup_test_component_platform(hass, DOMAIN, [mocksensor], built_in=False)
await async_setup_component(hass, "homeassistant", {}) await async_setup_component(hass, "homeassistant", {})
with freeze_time(zero) as freezer:
await async_setup_component( await async_setup_component(
hass, "sensor", {"sensor": [{"platform": "demo"}, {"platform": "test"}]} hass, "sensor", {"sensor": [{"platform": "demo"}, {"platform": "test"}]}
) )
@ -1541,7 +1543,7 @@ async def test_compile_hourly_sum_statistics_total_no_reset(
factor, factor,
) -> None: ) -> None:
"""Test compiling hourly statistics.""" """Test compiling hourly statistics."""
period0 = dt_util.utcnow() period0 = get_start_time(dt_util.utcnow())
period0_end = period1 = period0 + timedelta(minutes=5) period0_end = period1 = period0 + timedelta(minutes=5)
period1_end = period2 = period0 + timedelta(minutes=10) period1_end = period2 = period0 + timedelta(minutes=10)
period2_end = period0 + timedelta(minutes=15) period2_end = period0 + timedelta(minutes=15)
@ -1654,7 +1656,7 @@ async def test_compile_hourly_sum_statistics_total_increasing(
factor, factor,
) -> None: ) -> None:
"""Test compiling hourly statistics.""" """Test compiling hourly statistics."""
period0 = dt_util.utcnow() period0 = get_start_time(dt_util.utcnow())
period0_end = period1 = period0 + timedelta(minutes=5) period0_end = period1 = period0 + timedelta(minutes=5)
period1_end = period2 = period0 + timedelta(minutes=10) period1_end = period2 = period0 + timedelta(minutes=10)
period2_end = period0 + timedelta(minutes=15) period2_end = period0 + timedelta(minutes=15)
@ -1767,7 +1769,7 @@ async def test_compile_hourly_sum_statistics_total_increasing_small_dip(
factor, factor,
) -> None: ) -> None:
"""Test small dips in sensor readings do not trigger a reset.""" """Test small dips in sensor readings do not trigger a reset."""
period0 = dt_util.utcnow() period0 = get_start_time(dt_util.utcnow())
period0_end = period1 = period0 + timedelta(minutes=5) period0_end = period1 = period0 + timedelta(minutes=5)
period1_end = period2 = period0 + timedelta(minutes=10) period1_end = period2 = period0 + timedelta(minutes=10)
period2_end = period0 + timedelta(minutes=15) period2_end = period0 + timedelta(minutes=15)
@ -1869,7 +1871,7 @@ async def test_compile_hourly_energy_statistics_unsupported(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None: ) -> None:
"""Test compiling hourly statistics.""" """Test compiling hourly statistics."""
period0 = dt_util.utcnow() period0 = get_start_time(dt_util.utcnow())
period0_end = period1 = period0 + timedelta(minutes=5) period0_end = period1 = period0 + timedelta(minutes=5)
period1_end = period2 = period0 + timedelta(minutes=10) period1_end = period2 = period0 + timedelta(minutes=10)
period2_end = period0 + timedelta(minutes=15) period2_end = period0 + timedelta(minutes=15)
@ -1973,7 +1975,7 @@ async def test_compile_hourly_energy_statistics_multiple(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None: ) -> None:
"""Test compiling multiple hourly statistics.""" """Test compiling multiple hourly statistics."""
period0 = dt_util.utcnow() period0 = get_start_time(dt_util.utcnow())
period0_end = period1 = period0 + timedelta(minutes=5) period0_end = period1 = period0 + timedelta(minutes=5)
period1_end = period2 = period0 + timedelta(minutes=10) period1_end = period2 = period0 + timedelta(minutes=10)
period2_end = period0 + timedelta(minutes=15) period2_end = period0 + timedelta(minutes=15)
@ -2187,7 +2189,7 @@ async def test_compile_hourly_statistics_unchanged(
value, value,
) -> None: ) -> None:
"""Test compiling hourly statistics, with no changes during the hour.""" """Test compiling hourly statistics, with no changes during the hour."""
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -2230,7 +2232,7 @@ async def test_compile_hourly_statistics_partially_unavailable(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None: ) -> None:
"""Test compiling hourly statistics, with the sensor being partially unavailable.""" """Test compiling hourly statistics, with the sensor being partially unavailable."""
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -2299,7 +2301,7 @@ async def test_compile_hourly_statistics_unavailable(
sensor.test1 is unavailable and should not have statistics generated sensor.test1 is unavailable and should not have statistics generated
sensor.test2 should have statistics generated sensor.test2 should have statistics generated
""" """
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -2346,7 +2348,7 @@ async def test_compile_hourly_statistics_fails(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None: ) -> None:
"""Test compiling hourly statistics throws.""" """Test compiling hourly statistics throws."""
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -2523,7 +2525,7 @@ async def test_compile_hourly_statistics_changing_units_1(
This tests the case where the recorder cannot convert between the units. This tests the case where the recorder cannot convert between the units.
""" """
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -2652,7 +2654,7 @@ async def test_compile_hourly_statistics_changing_units_2(
This tests the behaviour when the sensor units are note supported by any unit This tests the behaviour when the sensor units are note supported by any unit
converter. converter.
""" """
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow()) - timedelta(seconds=30 * 5)
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -2731,7 +2733,7 @@ async def test_compile_hourly_statistics_changing_units_3(
This tests the behaviour when the sensor units are note supported by any unit This tests the behaviour when the sensor units are note supported by any unit
converter. converter.
""" """
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -2852,7 +2854,7 @@ async def test_compile_hourly_statistics_convert_units_1(
This tests the case where the recorder can convert between the units. This tests the case where the recorder can convert between the units.
""" """
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -3011,7 +3013,7 @@ async def test_compile_hourly_statistics_equivalent_units_1(
max, max,
) -> None: ) -> None:
"""Test compiling hourly statistics where units change from one hour to the next.""" """Test compiling hourly statistics where units change from one hour to the next."""
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -3136,7 +3138,7 @@ async def test_compile_hourly_statistics_equivalent_units_2(
max, max,
) -> None: ) -> None:
"""Test compiling hourly statistics where units change during an hour.""" """Test compiling hourly statistics where units change during an hour."""
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -3160,7 +3162,7 @@ async def test_compile_hourly_statistics_equivalent_units_2(
) )
assert_dict_of_states_equal_without_context_and_last_changed(states, hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
do_adhoc_statistics(hass, start=zero + timedelta(seconds=30 * 5)) do_adhoc_statistics(hass, start=zero + timedelta(seconds=30 * 10))
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
assert "The unit of sensor.test1 is changing" not in caplog.text assert "The unit of sensor.test1 is changing" not in caplog.text
assert "and matches the unit of already compiled statistics" not in caplog.text assert "and matches the unit of already compiled statistics" not in caplog.text
@ -3182,9 +3184,9 @@ async def test_compile_hourly_statistics_equivalent_units_2(
"sensor.test1": [ "sensor.test1": [
{ {
"start": process_timestamp( "start": process_timestamp(
zero + timedelta(seconds=30 * 5) zero + timedelta(seconds=30 * 10)
).timestamp(), ).timestamp(),
"end": process_timestamp(zero + timedelta(seconds=30 * 15)).timestamp(), "end": process_timestamp(zero + timedelta(seconds=30 * 20)).timestamp(),
"mean": pytest.approx(mean), "mean": pytest.approx(mean),
"min": pytest.approx(min), "min": pytest.approx(min),
"max": pytest.approx(max), "max": pytest.approx(max),
@ -3229,7 +3231,7 @@ async def test_compile_hourly_statistics_changing_device_class_1(
Device class is ignored, meaning changing device class should not influence the statistics. Device class is ignored, meaning changing device class should not influence the statistics.
""" """
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -3440,7 +3442,7 @@ async def test_compile_hourly_statistics_changing_device_class_2(
Device class is ignored, meaning changing device class should not influence the statistics. Device class is ignored, meaning changing device class should not influence the statistics.
""" """
zero = dt_util.utcnow() zero = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
# Wait for the sensor recorder platform to be added # Wait for the sensor recorder platform to be added
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -3578,7 +3580,7 @@ async def test_compile_hourly_statistics_changing_state_class(
max, max,
) -> None: ) -> None:
"""Test compiling hourly statistics where state class changes.""" """Test compiling hourly statistics where state class changes."""
period0 = dt_util.utcnow() period0 = get_start_time(dt_util.utcnow())
period0_end = period1 = period0 + timedelta(minutes=5) period0_end = period1 = period0 + timedelta(minutes=5)
period1_end = period0 + timedelta(minutes=10) period1_end = period0 + timedelta(minutes=10)
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
@ -4148,7 +4150,7 @@ async def async_record_states(
one = zero + timedelta(seconds=1 * 5) one = zero + timedelta(seconds=1 * 5)
two = one + timedelta(seconds=10 * 5) two = one + timedelta(seconds=10 * 5)
three = two + timedelta(seconds=40 * 5) three = two + timedelta(seconds=40 * 5)
four = three + timedelta(seconds=10 * 5) four = three + timedelta(seconds=9 * 5)
states = {entity_id: []} states = {entity_id: []}
freezer.move_to(one) freezer.move_to(one)
@ -4210,7 +4212,7 @@ async def test_validate_unit_change_convertible(
The test also asserts that the sensor's device class is ignored. The test also asserts that the sensor's device class is ignored.
""" """
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
hass.config.units = units hass.config.units = units
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
@ -4222,14 +4224,20 @@ async def test_validate_unit_change_convertible(
# No statistics, unit in state matching device class - empty response # No statistics, unit in state matching device class - empty response
hass.states.async_set( hass.states.async_set(
"sensor.test", 10, attributes={**attributes, "unit_of_measurement": unit} "sensor.test",
10,
attributes={**attributes, "unit_of_measurement": unit},
timestamp=now.timestamp(),
) )
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await assert_validation_result(client, {}) await assert_validation_result(client, {})
# No statistics, unit in state not matching device class - empty response # No statistics, unit in state not matching device class - empty response
hass.states.async_set( hass.states.async_set(
"sensor.test", 11, attributes={**attributes, "unit_of_measurement": "dogs"} "sensor.test",
11,
attributes={**attributes, "unit_of_measurement": "dogs"},
timestamp=now.timestamp(),
) )
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await assert_validation_result(client, {}) await assert_validation_result(client, {})
@ -4238,7 +4246,10 @@ async def test_validate_unit_change_convertible(
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
do_adhoc_statistics(hass, start=now) do_adhoc_statistics(hass, start=now)
hass.states.async_set( hass.states.async_set(
"sensor.test", 12, attributes={**attributes, "unit_of_measurement": "dogs"} "sensor.test",
12,
attributes={**attributes, "unit_of_measurement": "dogs"},
timestamp=now.timestamp(),
) )
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
expected = { expected = {
@ -4258,7 +4269,10 @@ async def test_validate_unit_change_convertible(
# Valid state - empty response # Valid state - empty response
hass.states.async_set( hass.states.async_set(
"sensor.test", 13, attributes={**attributes, "unit_of_measurement": unit} "sensor.test",
13,
attributes={**attributes, "unit_of_measurement": unit},
timestamp=now.timestamp(),
) )
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await assert_validation_result(client, {}) await assert_validation_result(client, {})
@ -4270,7 +4284,10 @@ async def test_validate_unit_change_convertible(
# Valid state in compatible unit - empty response # Valid state in compatible unit - empty response
hass.states.async_set( hass.states.async_set(
"sensor.test", 13, attributes={**attributes, "unit_of_measurement": unit2} "sensor.test",
13,
attributes={**attributes, "unit_of_measurement": unit2},
timestamp=now.timestamp(),
) )
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await assert_validation_result(client, {}) await assert_validation_result(client, {})
@ -4309,7 +4326,7 @@ async def test_validate_statistics_unit_ignore_device_class(
The test asserts that the sensor's device class is ignored. The test asserts that the sensor's device class is ignored.
""" """
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
hass.config.units = units hass.config.units = units
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
@ -4321,7 +4338,9 @@ async def test_validate_statistics_unit_ignore_device_class(
# No statistics, no device class - empty response # No statistics, no device class - empty response
initial_attributes = {"state_class": "measurement", "unit_of_measurement": "dogs"} initial_attributes = {"state_class": "measurement", "unit_of_measurement": "dogs"}
hass.states.async_set("sensor.test", 10, attributes=initial_attributes) hass.states.async_set(
"sensor.test", 10, attributes=initial_attributes, timestamp=now.timestamp()
)
await hass.async_block_till_done() await hass.async_block_till_done()
await assert_validation_result(client, {}) await assert_validation_result(client, {})
@ -4329,7 +4348,10 @@ async def test_validate_statistics_unit_ignore_device_class(
do_adhoc_statistics(hass, start=now) do_adhoc_statistics(hass, start=now)
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
hass.states.async_set( hass.states.async_set(
"sensor.test", 12, attributes={**attributes, "unit_of_measurement": "dogs"} "sensor.test",
12,
attributes={**attributes, "unit_of_measurement": "dogs"},
timestamp=now.timestamp(),
) )
await hass.async_block_till_done() await hass.async_block_till_done()
await assert_validation_result(client, {}) await assert_validation_result(client, {})
@ -4389,7 +4411,7 @@ async def test_validate_statistics_unit_change_no_device_class(
attributes = dict(attributes) attributes = dict(attributes)
attributes.pop("device_class") attributes.pop("device_class")
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
hass.config.units = units hass.config.units = units
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
@ -4401,14 +4423,20 @@ async def test_validate_statistics_unit_change_no_device_class(
# No statistics, sensor state set - empty response # No statistics, sensor state set - empty response
hass.states.async_set( hass.states.async_set(
"sensor.test", 10, attributes={**attributes, "unit_of_measurement": unit} "sensor.test",
10,
attributes={**attributes, "unit_of_measurement": unit},
timestamp=now.timestamp(),
) )
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await assert_validation_result(client, {}) await assert_validation_result(client, {})
# No statistics, sensor state set to an incompatible unit - empty response # No statistics, sensor state set to an incompatible unit - empty response
hass.states.async_set( hass.states.async_set(
"sensor.test", 11, attributes={**attributes, "unit_of_measurement": "dogs"} "sensor.test",
11,
attributes={**attributes, "unit_of_measurement": "dogs"},
timestamp=now.timestamp(),
) )
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await assert_validation_result(client, {}) await assert_validation_result(client, {})
@ -4417,7 +4445,10 @@ async def test_validate_statistics_unit_change_no_device_class(
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
do_adhoc_statistics(hass, start=now) do_adhoc_statistics(hass, start=now)
hass.states.async_set( hass.states.async_set(
"sensor.test", 12, attributes={**attributes, "unit_of_measurement": "dogs"} "sensor.test",
12,
attributes={**attributes, "unit_of_measurement": "dogs"},
timestamp=now.timestamp(),
) )
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
expected = { expected = {
@ -4437,7 +4468,10 @@ async def test_validate_statistics_unit_change_no_device_class(
# Valid state - empty response # Valid state - empty response
hass.states.async_set( hass.states.async_set(
"sensor.test", 13, attributes={**attributes, "unit_of_measurement": unit} "sensor.test",
13,
attributes={**attributes, "unit_of_measurement": unit},
timestamp=now.timestamp(),
) )
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await assert_validation_result(client, {}) await assert_validation_result(client, {})
@ -4449,7 +4483,10 @@ async def test_validate_statistics_unit_change_no_device_class(
# Valid state in compatible unit - empty response # Valid state in compatible unit - empty response
hass.states.async_set( hass.states.async_set(
"sensor.test", 13, attributes={**attributes, "unit_of_measurement": unit2} "sensor.test",
13,
attributes={**attributes, "unit_of_measurement": unit2},
timestamp=now.timestamp(),
) )
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await assert_validation_result(client, {}) await assert_validation_result(client, {})
@ -4486,7 +4523,7 @@ async def test_validate_statistics_unsupported_state_class(
unit, unit,
) -> None: ) -> None:
"""Test validate_statistics.""" """Test validate_statistics."""
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
hass.config.units = units hass.config.units = units
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
@ -4497,7 +4534,9 @@ async def test_validate_statistics_unsupported_state_class(
await assert_validation_result(client, {}) await assert_validation_result(client, {})
# No statistics, valid state - empty response # No statistics, valid state - empty response
hass.states.async_set("sensor.test", 10, attributes=attributes) hass.states.async_set(
"sensor.test", 10, attributes=attributes, timestamp=now.timestamp()
)
await hass.async_block_till_done() await hass.async_block_till_done()
await assert_validation_result(client, {}) await assert_validation_result(client, {})
@ -4509,7 +4548,9 @@ async def test_validate_statistics_unsupported_state_class(
# State update with invalid state class, expect error # State update with invalid state class, expect error
_attributes = dict(attributes) _attributes = dict(attributes)
_attributes.pop("state_class") _attributes.pop("state_class")
hass.states.async_set("sensor.test", 12, attributes=_attributes) hass.states.async_set(
"sensor.test", 12, attributes=_attributes, timestamp=now.timestamp()
)
await hass.async_block_till_done() await hass.async_block_till_done()
expected = { expected = {
"sensor.test": [ "sensor.test": [
@ -4539,7 +4580,7 @@ async def test_validate_statistics_sensor_no_longer_recorded(
unit, unit,
) -> None: ) -> None:
"""Test validate_statistics.""" """Test validate_statistics."""
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
hass.config.units = units hass.config.units = units
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
@ -4550,7 +4591,9 @@ async def test_validate_statistics_sensor_no_longer_recorded(
await assert_validation_result(client, {}) await assert_validation_result(client, {})
# No statistics, valid state - empty response # No statistics, valid state - empty response
hass.states.async_set("sensor.test", 10, attributes=attributes) hass.states.async_set(
"sensor.test", 10, attributes=attributes, timestamp=now.timestamp()
)
await hass.async_block_till_done() await hass.async_block_till_done()
await assert_validation_result(client, {}) await assert_validation_result(client, {})
@ -4591,7 +4634,7 @@ async def test_validate_statistics_sensor_not_recorded(
unit, unit,
) -> None: ) -> None:
"""Test validate_statistics.""" """Test validate_statistics."""
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
hass.config.units = units hass.config.units = units
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
@ -4616,7 +4659,9 @@ async def test_validate_statistics_sensor_not_recorded(
"entity_filter", "entity_filter",
return_value=False, return_value=False,
): ):
hass.states.async_set("sensor.test", 10, attributes=attributes) hass.states.async_set(
"sensor.test", 10, attributes=attributes, timestamp=now.timestamp()
)
await hass.async_block_till_done() await hass.async_block_till_done()
await assert_validation_result(client, expected) await assert_validation_result(client, expected)
@ -4640,7 +4685,7 @@ async def test_validate_statistics_sensor_removed(
unit, unit,
) -> None: ) -> None:
"""Test validate_statistics.""" """Test validate_statistics."""
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
hass.config.units = units hass.config.units = units
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
@ -4651,7 +4696,9 @@ async def test_validate_statistics_sensor_removed(
await assert_validation_result(client, {}) await assert_validation_result(client, {})
# No statistics, valid state - empty response # No statistics, valid state - empty response
hass.states.async_set("sensor.test", 10, attributes=attributes) hass.states.async_set(
"sensor.test", 10, attributes=attributes, timestamp=now.timestamp()
)
await hass.async_block_till_done() await hass.async_block_till_done()
await assert_validation_result(client, {}) await assert_validation_result(client, {})
@ -4688,7 +4735,7 @@ async def test_validate_statistics_unit_change_no_conversion(
unit2, unit2,
) -> None: ) -> None:
"""Test validate_statistics.""" """Test validate_statistics."""
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -4699,13 +4746,19 @@ async def test_validate_statistics_unit_change_no_conversion(
# No statistics, original unit - empty response # No statistics, original unit - empty response
hass.states.async_set( hass.states.async_set(
"sensor.test", 10, attributes={**attributes, "unit_of_measurement": unit1} "sensor.test",
10,
attributes={**attributes, "unit_of_measurement": unit1},
timestamp=now.timestamp(),
) )
await assert_validation_result(client, {}) await assert_validation_result(client, {})
# No statistics, changed unit - empty response # No statistics, changed unit - empty response
hass.states.async_set( hass.states.async_set(
"sensor.test", 11, attributes={**attributes, "unit_of_measurement": unit2} "sensor.test",
11,
attributes={**attributes, "unit_of_measurement": unit2},
timestamp=now.timestamp(),
) )
await assert_validation_result(client, {}) await assert_validation_result(client, {})
@ -4717,7 +4770,10 @@ async def test_validate_statistics_unit_change_no_conversion(
# No statistics, original unit - empty response # No statistics, original unit - empty response
hass.states.async_set( hass.states.async_set(
"sensor.test", 12, attributes={**attributes, "unit_of_measurement": unit1} "sensor.test",
12,
attributes={**attributes, "unit_of_measurement": unit1},
timestamp=now.timestamp(),
) )
await assert_validation_result(client, {}) await assert_validation_result(client, {})
@ -4732,7 +4788,10 @@ async def test_validate_statistics_unit_change_no_conversion(
# Change unit - expect error # Change unit - expect error
hass.states.async_set( hass.states.async_set(
"sensor.test", 13, attributes={**attributes, "unit_of_measurement": unit2} "sensor.test",
13,
attributes={**attributes, "unit_of_measurement": unit2},
timestamp=now.timestamp(),
) )
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
expected = { expected = {
@ -4752,7 +4811,10 @@ async def test_validate_statistics_unit_change_no_conversion(
# Original unit - empty response # Original unit - empty response
hass.states.async_set( hass.states.async_set(
"sensor.test", 14, attributes={**attributes, "unit_of_measurement": unit1} "sensor.test",
14,
attributes={**attributes, "unit_of_measurement": unit1},
timestamp=now.timestamp(),
) )
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await assert_validation_result(client, {}) await assert_validation_result(client, {})
@ -4796,7 +4858,7 @@ async def test_validate_statistics_unit_change_equivalent_units(
This tests no validation issue is created when a sensor's unit changes to an This tests no validation issue is created when a sensor's unit changes to an
equivalent unit. equivalent unit.
""" """
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -4807,7 +4869,10 @@ async def test_validate_statistics_unit_change_equivalent_units(
# No statistics, original unit - empty response # No statistics, original unit - empty response
hass.states.async_set( hass.states.async_set(
"sensor.test", 10, attributes={**attributes, "unit_of_measurement": unit1} "sensor.test",
10,
attributes={**attributes, "unit_of_measurement": unit1},
timestamp=now.timestamp(),
) )
await assert_validation_result(client, {}) await assert_validation_result(client, {})
@ -4821,7 +4886,10 @@ async def test_validate_statistics_unit_change_equivalent_units(
# Units changed to an equivalent unit - empty response # Units changed to an equivalent unit - empty response
hass.states.async_set( hass.states.async_set(
"sensor.test", 12, attributes={**attributes, "unit_of_measurement": unit2} "sensor.test",
12,
attributes={**attributes, "unit_of_measurement": unit2},
timestamp=now.timestamp() + 1,
) )
await assert_validation_result(client, {}) await assert_validation_result(client, {})
@ -4854,7 +4922,7 @@ async def test_validate_statistics_unit_change_equivalent_units_2(
This tests a validation issue is created when a sensor's unit changes to an This tests a validation issue is created when a sensor's unit changes to an
equivalent unit which is not known to the unit converters. equivalent unit which is not known to the unit converters.
""" """
now = dt_util.utcnow() now = get_start_time(dt_util.utcnow())
await async_setup_component(hass, "sensor", {}) await async_setup_component(hass, "sensor", {})
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -4865,7 +4933,10 @@ async def test_validate_statistics_unit_change_equivalent_units_2(
# No statistics, original unit - empty response # No statistics, original unit - empty response
hass.states.async_set( hass.states.async_set(
"sensor.test", 10, attributes={**attributes, "unit_of_measurement": unit1} "sensor.test",
10,
attributes={**attributes, "unit_of_measurement": unit1},
timestamp=now.timestamp(),
) )
await assert_validation_result(client, {}) await assert_validation_result(client, {})
@ -4879,7 +4950,10 @@ async def test_validate_statistics_unit_change_equivalent_units_2(
# Units changed to an equivalent unit which is not known by the unit converters # Units changed to an equivalent unit which is not known by the unit converters
hass.states.async_set( hass.states.async_set(
"sensor.test", 12, attributes={**attributes, "unit_of_measurement": unit2} "sensor.test",
12,
attributes={**attributes, "unit_of_measurement": unit2},
timestamp=now.timestamp(),
) )
expected = { expected = {
"sensor.test": [ "sensor.test": [
@ -5045,7 +5119,7 @@ async def async_record_states_partially_unavailable(hass, zero, entity_id, attri
one = zero + timedelta(seconds=1 * 5) one = zero + timedelta(seconds=1 * 5)
two = one + timedelta(seconds=15 * 5) two = one + timedelta(seconds=15 * 5)
three = two + timedelta(seconds=30 * 5) three = two + timedelta(seconds=30 * 5)
four = three + timedelta(seconds=15 * 5) four = three + timedelta(seconds=14 * 5)
states = {entity_id: []} states = {entity_id: []}
with freeze_time(one) as freezer: with freeze_time(one) as freezer: