From a6b7641d477699029f82bc075c9e2d5132c85831 Mon Sep 17 00:00:00 2001 From: bkobus-bbx Date: Thu, 4 Jun 2026 17:35:27 +0200 Subject: [PATCH] Add diagnostics for Blebox integration (#172556) Co-authored-by: Joost Lekkerkerker --- .../components/blebox/diagnostics.py | 33 ++++++++ tests/components/blebox/conftest.py | 6 ++ .../blebox/snapshots/test_diagnostics.ambr | 79 +++++++++++++++++++ tests/components/blebox/test_diagnostics.py | 58 ++++++++++++++ 4 files changed, 176 insertions(+) create mode 100644 homeassistant/components/blebox/diagnostics.py create mode 100644 tests/components/blebox/snapshots/test_diagnostics.ambr create mode 100644 tests/components/blebox/test_diagnostics.py diff --git a/homeassistant/components/blebox/diagnostics.py b/homeassistant/components/blebox/diagnostics.py new file mode 100644 index 000000000000..bb9a0728dab5 --- /dev/null +++ b/homeassistant/components/blebox/diagnostics.py @@ -0,0 +1,33 @@ +"""Diagnostics support for BleBox devices.""" + +from typing import Any + +from homeassistant.components.diagnostics import async_redact_data +from homeassistant.const import CONF_PASSWORD, CONF_USERNAME +from homeassistant.core import HomeAssistant + +from . import BleBoxConfigEntry + +TO_REDACT = {CONF_PASSWORD, CONF_USERNAME} + + +async def async_get_config_entry_diagnostics( + hass: HomeAssistant, entry: BleBoxConfigEntry +) -> dict[str, Any]: + """Return diagnostics for a config entry.""" + product = entry.runtime_data.box + + return { + "entry": async_redact_data(entry.as_dict(), TO_REDACT), + "device": { + "name": product.name, + "type": product.type, + "model": product.model, + "unique_id": product.unique_id, + "firmware_version": product.firmware_version, + "hardware_version": product.hardware_version, + "available_firmware_version": product.available_firmware_version, + "api_version": product.api_version, + "last_data": product.last_data, + }, + } diff --git a/tests/components/blebox/conftest.py b/tests/components/blebox/conftest.py index 890b4a2046ab..39e599b95a8c 100644 --- a/tests/components/blebox/conftest.py +++ b/tests/components/blebox/conftest.py @@ -55,6 +55,12 @@ def mock_feature(category, spec, set_spec: bool = True, **kwargs): type(feature_mock.product).model = PropertyMock(return_value="some model") type(feature_mock.product).brand = PropertyMock(return_value="BleBox") type(feature_mock.product).firmware_version = PropertyMock(return_value="1.23") + type(feature_mock.product).hardware_version = PropertyMock(return_value="0.1") + type(feature_mock.product).available_firmware_version = PropertyMock( + return_value="1.0.1" + ) + type(feature_mock.product).api_version = PropertyMock(return_value=20200229) + type(feature_mock.product).last_data = PropertyMock(return_value={"state": 1}) type(feature_mock.product).unique_id = PropertyMock(return_value="abcd0123ef5678") type(feature_mock).product = PropertyMock(return_value=product) return feature_mock diff --git a/tests/components/blebox/snapshots/test_diagnostics.ambr b/tests/components/blebox/snapshots/test_diagnostics.ambr new file mode 100644 index 000000000000..326885368ae9 --- /dev/null +++ b/tests/components/blebox/snapshots/test_diagnostics.ambr @@ -0,0 +1,79 @@ +# serializer version: 1 +# name: test_diagnostics[no_credentials] + dict({ + 'device': dict({ + 'api_version': 20200229, + 'available_firmware_version': '1.0.1', + 'firmware_version': '1.23', + 'hardware_version': '0.1', + 'last_data': dict({ + 'state': 1, + }), + 'model': 'some model', + 'name': 'Some name', + 'type': 'some type', + 'unique_id': 'abcd0123ef5678', + }), + 'entry': dict({ + 'data': dict({ + 'host': '172.100.123.4', + 'port': 80, + }), + 'disabled_by': None, + 'discovery_keys': dict({ + }), + 'domain': 'blebox', + 'minor_version': 1, + 'options': dict({ + }), + 'pref_disable_new_entities': False, + 'pref_disable_polling': False, + 'source': 'user', + 'subentries': list([ + ]), + 'title': 'Mock Title', + 'unique_id': None, + 'version': 1, + }), + }) +# --- +# name: test_diagnostics[with_credentials] + dict({ + 'device': dict({ + 'api_version': 20200229, + 'available_firmware_version': '1.0.1', + 'firmware_version': '1.23', + 'hardware_version': '0.1', + 'last_data': dict({ + 'state': 1, + }), + 'model': 'some model', + 'name': 'Some name', + 'type': 'some type', + 'unique_id': 'abcd0123ef5678', + }), + 'entry': dict({ + 'data': dict({ + 'host': '172.100.123.4', + 'password': '**REDACTED**', + 'port': 80, + 'username': '**REDACTED**', + }), + 'disabled_by': None, + 'discovery_keys': dict({ + }), + 'domain': 'blebox', + 'minor_version': 1, + 'options': dict({ + }), + 'pref_disable_new_entities': False, + 'pref_disable_polling': False, + 'source': 'user', + 'subentries': list([ + ]), + 'title': 'Mock Title', + 'unique_id': None, + 'version': 1, + }), + }) +# --- diff --git a/tests/components/blebox/test_diagnostics.py b/tests/components/blebox/test_diagnostics.py new file mode 100644 index 000000000000..bc098c7e698e --- /dev/null +++ b/tests/components/blebox/test_diagnostics.py @@ -0,0 +1,58 @@ +"""Tests for BleBox diagnostics.""" + +import blebox_uniapi.switch +import pytest +from syrupy.assertion import SnapshotAssertion +from syrupy.filters import props + +from homeassistant.components.blebox.const import DOMAIN +from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME +from homeassistant.core import HomeAssistant + +from .conftest import mock_feature + +from tests.common import MockConfigEntry +from tests.components.diagnostics import get_diagnostics_for_config_entry +from tests.typing import ClientSessionGenerator + + +@pytest.fixture(name="switchbox", autouse=True) +def switchbox_fixture() -> None: + """Set up a switch product mock.""" + mock_feature("switches", blebox_uniapi.switch.Switch) + + +@pytest.mark.parametrize( + "entry_data", + [ + pytest.param( + {CONF_HOST: "172.100.123.4", CONF_PORT: 80}, + id="no_credentials", + ), + pytest.param( + { + CONF_HOST: "172.100.123.4", + CONF_PORT: 80, + CONF_USERNAME: "user", + CONF_PASSWORD: "secret", + }, + id="with_credentials", + ), + ], +) +async def test_diagnostics( + hass: HomeAssistant, + hass_client: ClientSessionGenerator, + snapshot: SnapshotAssertion, + entry_data: dict, +) -> None: + """Test diagnostics output, including credential redaction.""" + entry = MockConfigEntry(domain=DOMAIN, data=entry_data) + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + assert await get_diagnostics_for_config_entry(hass, hass_client, entry) == snapshot( + exclude=props("entry_id", "created_at", "modified_at") + )