"""Tests hors ligne des diagnostics Arkteos.""" from __future__ import annotations import json from pathlib import Path from types import SimpleNamespace import pytest from pytest_homeassistant_custom_component.common import MockConfigEntry from custom_components.arkteos.client import ArkteosClient from custom_components.arkteos.const import CONF_HOST, CONF_PORT, DEFAULT_PORT, DOMAIN from custom_components.arkteos.diagnostics import async_get_config_entry_diagnostics from custom_components.arkteos.parser import filter_values, parse_frame FIXTURES = Path(__file__).parent / "fixtures" MANIFEST = Path(__file__).parents[1] / "custom_components" / "arkteos" / "manifest.json" HOST = "arkteos.local" def _entry() -> MockConfigEntry: return MockConfigEntry( domain=DOMAIN, title="Arkteos arkteos.local:9641", data={CONF_HOST: "arkteos.local", CONF_PORT: DEFAULT_PORT}, ) def _client() -> ArkteosClient: return ArkteosClient(HOST, DEFAULT_PORT) def _values(name: str) -> dict[str, int | float | str]: return filter_values(parse_frame((FIXTURES / name).read_bytes())).accepted async def test_diagnostics_are_redacted_and_serializable(hass) -> None: entry = _entry() client = _client() client.available = True client.running = True client.connected = True client.bytes_received = 123 client.frames_received = 4 client.frames_rejected = 2 client.reconnect_count = 1 entry.runtime_data = client diagnostics = await async_get_config_entry_diagnostics(hass, entry) assert isinstance(diagnostics, dict) assert diagnostics["integration"]["domain"] == DOMAIN assert diagnostics["integration"]["version"] == json.loads(MANIFEST.read_text())["version"] assert diagnostics["integration"]["configuration"][CONF_PORT] == DEFAULT_PORT assert HOST not in json.dumps(diagnostics) assert diagnostics["client"] == { "available": True, "running": True, "connected": True, "bytes_received": 123, "frames_received": 4, "frames_rejected": 2, "reconnect_count": 1, "last_frame_type": None, } assert diagnostics["received_data"] == { "metadata": {"received": False, "data": {}}, "frigo": {"received": False, "data": {}}, "regulation": {"received": False, "data": {}}, } json.dumps(diagnostics) @pytest.mark.parametrize( ("attribute", "fixture_name", "section"), ( ("latest_metadata", "metadata_95.bin", "metadata"), ("latest_frigo_data", "frigo_163.bin", "frigo"), ("latest_regulation_data", "regulation_227.bin", "regulation"), ), ) async def test_decoded_data_is_separated_without_raw_frames( hass, attribute: str, fixture_name: str, section: str ) -> None: entry = _entry() client = _client() setattr(client, attribute, _values(fixture_name)) entry.runtime_data = client diagnostics = await async_get_config_entry_diagnostics(hass, entry) assert diagnostics["received_data"][section]["received"] assert diagnostics["received_data"][section]["data"] == getattr(client, attribute) assert all( not values["received"] for name, values in diagnostics["received_data"].items() if name != section ) assert (FIXTURES / fixture_name).read_bytes() not in json.dumps(diagnostics).encode() async def test_fallback_hass_data_and_missing_optional_attributes(hass) -> None: entry = SimpleNamespace( entry_id="fallback-entry", title=f"Arkteos {HOST}:9641", data={CONF_HOST: HOST}, ) client = _client() del client.connected hass.data.setdefault(DOMAIN, {})[entry.entry_id] = client diagnostics = await async_get_config_entry_diagnostics(hass, entry) assert diagnostics["client"]["available"] is False assert "connected" not in diagnostics["client"] assert diagnostics["integration"]["configuration"][CONF_PORT] == DEFAULT_PORT assert HOST not in json.dumps(diagnostics) async def test_sensitive_and_nonserializable_values_are_not_exposed(hass) -> None: entry = _entry() client = _client() client.latest_frigo_data = { "frame_type": "frigo", "exterieur_temp": 12.3, "token": "secret-token", "password": "secret-password", "raw": b"raw-frame", "reader": object(), } client._writer = object() entry.runtime_data = client diagnostics = await async_get_config_entry_diagnostics(hass, entry) serialized = json.dumps(diagnostics) assert "secret-token" not in serialized assert "secret-password" not in serialized assert "raw-frame" not in serialized assert "reader" not in diagnostics["received_data"]["frigo"]["data"] assert "writer" not in serialized assert "_task" not in serialized async def test_diagnostics_do_not_start_stop_or_connect_client(hass, monkeypatch: pytest.MonkeyPatch) -> None: entry = _entry() client = _client() entry.runtime_data = client async def forbidden(*_args, **_kwargs) -> None: raise AssertionError("accès réseau ou cycle de vie interdit") monkeypatch.setattr(client, "start", forbidden) monkeypatch.setattr(client, "stop", forbidden) diagnostics = await async_get_config_entry_diagnostics(hass, entry) assert diagnostics["client"]["frames_rejected"] == 0 assert "rejected_values" not in diagnostics