mirror of
https://github.com/esphome/esphome.git
synced 2026-01-10 04:00:51 -07:00
Co-authored-by: J. Nick Koston <nick+github@koston.org> Co-authored-by: J. Nick Koston <nick@home-assistant.io> Co-authored-by: J. Nick Koston <nick@koston.org> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
118 lines
4.6 KiB
Python
118 lines
4.6 KiB
Python
"""Integration test for build_info values."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from datetime import datetime
|
|
import re
|
|
import time
|
|
|
|
from aioesphomeapi import EntityState, TextSensorState
|
|
import pytest
|
|
|
|
from .types import APIClientConnectedFactory, RunCompiledFunction
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_build_info(
|
|
yaml_config: str,
|
|
run_compiled: RunCompiledFunction,
|
|
api_client_connected: APIClientConnectedFactory,
|
|
) -> None:
|
|
"""Test that build_info values are sane."""
|
|
async with run_compiled(yaml_config), api_client_connected() as client:
|
|
device_info = await client.device_info()
|
|
assert device_info is not None
|
|
assert device_info.name == "build-info-test"
|
|
|
|
# Verify compilation_time from device_info is present and parseable
|
|
# The format is ISO 8601 with timezone: "YYYY-MM-DD HH:MM:SS +ZZZZ"
|
|
compilation_time = device_info.compilation_time
|
|
assert compilation_time is not None
|
|
|
|
# Validate the ISO format: "YYYY-MM-DD HH:MM:SS +ZZZZ"
|
|
parsed = datetime.strptime(compilation_time, "%Y-%m-%d %H:%M:%S %z")
|
|
assert parsed.year >= time.localtime().tm_year
|
|
|
|
# Get entities
|
|
entities, _ = await client.list_entities_services()
|
|
|
|
# Find our text sensors by object_id
|
|
config_hash_entity = next(
|
|
(e for e in entities if e.object_id == "config_hash"), None
|
|
)
|
|
build_time_entity = next(
|
|
(e for e in entities if e.object_id == "build_time"), None
|
|
)
|
|
build_time_str_entity = next(
|
|
(e for e in entities if e.object_id == "build_time_string"), None
|
|
)
|
|
|
|
assert config_hash_entity is not None, "Config Hash sensor not found"
|
|
assert build_time_entity is not None, "Build Time sensor not found"
|
|
assert build_time_str_entity is not None, "Build Time String sensor not found"
|
|
|
|
# Wait for all three text sensors to have valid states
|
|
loop = asyncio.get_running_loop()
|
|
states: dict[int, TextSensorState] = {}
|
|
all_received = loop.create_future()
|
|
expected_keys = {
|
|
config_hash_entity.key,
|
|
build_time_entity.key,
|
|
build_time_str_entity.key,
|
|
}
|
|
|
|
def on_state(state: EntityState) -> None:
|
|
if isinstance(state, TextSensorState) and not state.missing_state:
|
|
states[state.key] = state
|
|
if expected_keys <= states.keys() and not all_received.done():
|
|
all_received.set_result(True)
|
|
|
|
client.subscribe_states(on_state)
|
|
|
|
try:
|
|
await asyncio.wait_for(all_received, timeout=5.0)
|
|
except TimeoutError:
|
|
pytest.fail(
|
|
f"Timeout waiting for text sensor states. Got: {list(states.keys())}"
|
|
)
|
|
|
|
config_hash_state = states[config_hash_entity.key]
|
|
build_time_state = states[build_time_entity.key]
|
|
build_time_str_state = states[build_time_str_entity.key]
|
|
|
|
# Validate config_hash format (0x followed by 8 hex digits)
|
|
config_hash = config_hash_state.state
|
|
assert re.match(r"^0x[0-9a-f]{8}$", config_hash), (
|
|
f"config_hash should be 0x followed by 8 hex digits, got: {config_hash}"
|
|
)
|
|
|
|
# Validate build_time is a reasonable Unix timestamp
|
|
build_time = int(build_time_state.state)
|
|
current_time = int(time.time())
|
|
# Build time should be within last hour and not in the future
|
|
assert build_time <= current_time, (
|
|
f"build_time {build_time} should not be in the future (current: {current_time})"
|
|
)
|
|
assert build_time > current_time - 3600, (
|
|
f"build_time {build_time} should be within the last hour"
|
|
)
|
|
|
|
# Validate build_time_str matches the new ISO format
|
|
build_time_str = build_time_str_state.state
|
|
# Format: "YYYY-MM-DD HH:MM:SS +ZZZZ"
|
|
parsed_build_time = datetime.strptime(build_time_str, "%Y-%m-%d %H:%M:%S %z")
|
|
assert parsed_build_time.year >= time.localtime().tm_year
|
|
|
|
# Verify build_time_str matches what we get from build_time timestamp
|
|
expected_str = time.strftime("%Y-%m-%d %H:%M:%S %z", time.localtime(build_time))
|
|
assert build_time_str == expected_str, (
|
|
f"build_time_str '{build_time_str}' should match timestamp '{expected_str}'"
|
|
)
|
|
|
|
# Verify compilation_time matches build_time_str (they should be the same)
|
|
assert compilation_time == build_time_str, (
|
|
f"compilation_time '{compilation_time}' should match "
|
|
f"build_time_str '{build_time_str}'"
|
|
)
|