156 lines
5.2 KiB
Python
156 lines
5.2 KiB
Python
"""Tests for the SWS12500 config entry diagnostics.
|
|
|
|
These cover both branches of `async_get_config_entry_diagnostics`:
|
|
- `runtime_data.health_data` is populated and returned directly.
|
|
- `runtime_data.health_data` is None, so it falls back to the live
|
|
`health_coordinator.data` snapshot.
|
|
|
|
In both cases secret keys listed in `TO_REDACT` must be replaced by the
|
|
Home Assistant `async_redact_data` sentinel, while non-secret values pass
|
|
through untouched.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from types import SimpleNamespace
|
|
|
|
from pytest_homeassistant_custom_component.common import MockConfigEntry
|
|
|
|
from custom_components.sws12500.const import (
|
|
API_ID,
|
|
API_KEY,
|
|
DOMAIN,
|
|
POCASI_CZ_API_ID,
|
|
POCASI_CZ_API_KEY,
|
|
WINDY_STATION_ID,
|
|
WINDY_STATION_PW,
|
|
)
|
|
from custom_components.sws12500.data import SWSRuntimeData
|
|
from custom_components.sws12500.diagnostics import async_get_config_entry_diagnostics
|
|
|
|
REDACTED = "**REDACTED**"
|
|
|
|
|
|
def _make_runtime(*, health_data, health_coordinator) -> SWSRuntimeData:
|
|
"""Build a runtime data container with lightweight stub coordinators.
|
|
|
|
Diagnostics only ever reads `health_data` and `health_coordinator.data`,
|
|
so the real coordinators can be replaced with plain stubs.
|
|
"""
|
|
return SWSRuntimeData(
|
|
coordinator=object(), # type: ignore[arg-type]
|
|
health_coordinator=health_coordinator, # type: ignore[arg-type]
|
|
last_options={},
|
|
health_data=health_data,
|
|
)
|
|
|
|
|
|
async def test_diagnostics_uses_persisted_health_data(hass) -> None:
|
|
"""When `health_data` is present it is returned and secrets are redacted."""
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
API_ID: "secret-api-id",
|
|
API_KEY: "secret-api-key",
|
|
"name": "Station",
|
|
},
|
|
options={
|
|
WINDY_STATION_ID: "secret-windy-id",
|
|
WINDY_STATION_PW: "secret-windy-pw",
|
|
"interval": 60,
|
|
},
|
|
)
|
|
entry.add_to_hass(hass)
|
|
|
|
health_data = {
|
|
"ID": "secret-station-id",
|
|
"PASSWORD": "secret-station-pw",
|
|
POCASI_CZ_API_ID: "secret-pocasi-id",
|
|
POCASI_CZ_API_KEY: "secret-pocasi-key",
|
|
"wsid": "secret-wsid",
|
|
"wspw": "secret-wspw",
|
|
"status": "ok",
|
|
}
|
|
# A separate coordinator snapshot that must NOT be used in this branch.
|
|
health_coordinator = SimpleNamespace(data={"status": "stale-should-not-appear"})
|
|
|
|
entry.runtime_data = _make_runtime(
|
|
health_data=health_data,
|
|
health_coordinator=health_coordinator,
|
|
)
|
|
|
|
result = await async_get_config_entry_diagnostics(hass, entry)
|
|
|
|
# entry_data: secrets redacted, plain value preserved.
|
|
assert result["entry_data"][API_ID] == REDACTED
|
|
assert result["entry_data"][API_KEY] == REDACTED
|
|
assert result["entry_data"]["name"] == "Station"
|
|
|
|
# entry_options: secrets redacted, plain value preserved.
|
|
assert result["entry_options"][WINDY_STATION_ID] == REDACTED
|
|
assert result["entry_options"][WINDY_STATION_PW] == REDACTED
|
|
assert result["entry_options"]["interval"] == 60
|
|
|
|
# health_data: the persisted payload is used (not the coordinator snapshot).
|
|
assert result["health_data"]["status"] == "ok"
|
|
assert result["health_data"]["ID"] == REDACTED
|
|
assert result["health_data"]["PASSWORD"] == REDACTED
|
|
assert result["health_data"][POCASI_CZ_API_ID] == REDACTED
|
|
assert result["health_data"][POCASI_CZ_API_KEY] == REDACTED
|
|
assert result["health_data"]["wsid"] == REDACTED
|
|
assert result["health_data"]["wspw"] == REDACTED
|
|
|
|
# The original payload must be untouched (deepcopy is used internally).
|
|
assert health_data["ID"] == "secret-station-id"
|
|
|
|
|
|
async def test_diagnostics_falls_back_to_coordinator_data(hass) -> None:
|
|
"""When `health_data` is None it falls back to the coordinator snapshot."""
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={API_ID: "secret-api-id", "name": "Station"},
|
|
options={},
|
|
)
|
|
entry.add_to_hass(hass)
|
|
|
|
coordinator_data = {
|
|
"ID": "secret-station-id",
|
|
"PASSWORD": "secret-station-pw",
|
|
"status": "live",
|
|
}
|
|
health_coordinator = SimpleNamespace(data=coordinator_data)
|
|
|
|
entry.runtime_data = _make_runtime(
|
|
health_data=None,
|
|
health_coordinator=health_coordinator,
|
|
)
|
|
|
|
result = await async_get_config_entry_diagnostics(hass, entry)
|
|
|
|
assert result["entry_data"][API_ID] == REDACTED
|
|
assert result["entry_data"]["name"] == "Station"
|
|
assert result["entry_options"] == {}
|
|
|
|
# Fallback snapshot is used and redacted.
|
|
assert result["health_data"]["status"] == "live"
|
|
assert result["health_data"]["ID"] == REDACTED
|
|
assert result["health_data"]["PASSWORD"] == REDACTED
|
|
|
|
|
|
async def test_diagnostics_empty_health_data(hass) -> None:
|
|
"""A falsy fallback snapshot yields an empty health_data dict."""
|
|
entry = MockConfigEntry(domain=DOMAIN, data={}, options={})
|
|
entry.add_to_hass(hass)
|
|
|
|
health_coordinator = SimpleNamespace(data=None)
|
|
entry.runtime_data = _make_runtime(
|
|
health_data=None,
|
|
health_coordinator=health_coordinator,
|
|
)
|
|
|
|
result = await async_get_config_entry_diagnostics(hass, entry)
|
|
|
|
assert result["health_data"] == {}
|
|
assert result["entry_data"] == {}
|
|
assert result["entry_options"] == {}
|