diff --git a/homeassistant/components/nextdns/diagnostics.py b/homeassistant/components/nextdns/diagnostics.py new file mode 100644 index 00000000000..4be22684395 --- /dev/null +++ b/homeassistant/components/nextdns/diagnostics.py @@ -0,0 +1,45 @@ +"""Diagnostics support for NextDNS.""" +from __future__ import annotations + +from dataclasses import asdict + +from homeassistant.components.diagnostics import async_redact_data +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_API_KEY, CONF_UNIQUE_ID +from homeassistant.core import HomeAssistant + +from .const import ( + ATTR_DNSSEC, + ATTR_ENCRYPTION, + ATTR_IP_VERSIONS, + ATTR_PROTOCOLS, + ATTR_STATUS, + CONF_PROFILE_ID, + DOMAIN, +) + +TO_REDACT = {CONF_API_KEY, CONF_PROFILE_ID, CONF_UNIQUE_ID} + + +async def async_get_config_entry_diagnostics( + hass: HomeAssistant, config_entry: ConfigEntry +) -> dict: + """Return diagnostics for a config entry.""" + coordinators = hass.data[DOMAIN][config_entry.entry_id] + + dnssec_coordinator = coordinators[ATTR_DNSSEC] + encryption_coordinator = coordinators[ATTR_ENCRYPTION] + ip_versions_coordinator = coordinators[ATTR_IP_VERSIONS] + protocols_coordinator = coordinators[ATTR_PROTOCOLS] + status_coordinator = coordinators[ATTR_STATUS] + + diagnostics_data = { + "config_entry": async_redact_data(config_entry.as_dict(), TO_REDACT), + "dnssec_coordinator_data": asdict(dnssec_coordinator.data), + "encryption_coordinator_data": asdict(encryption_coordinator.data), + "ip_versions_coordinator_data": asdict(ip_versions_coordinator.data), + "protocols_coordinator_data": asdict(protocols_coordinator.data), + "status_coordinator_data": asdict(status_coordinator.data), + } + + return diagnostics_data diff --git a/tests/components/nextdns/test_diagnostics.py b/tests/components/nextdns/test_diagnostics.py new file mode 100644 index 00000000000..73844b6a2e3 --- /dev/null +++ b/tests/components/nextdns/test_diagnostics.py @@ -0,0 +1,59 @@ +"""Test NextDNS diagnostics.""" +from homeassistant.components.diagnostics import REDACTED + +from tests.components.diagnostics import get_diagnostics_for_config_entry +from tests.components.nextdns import init_integration + + +async def test_entry_diagnostics(hass, hass_client): + """Test config entry diagnostics.""" + entry = await init_integration(hass) + + result = await get_diagnostics_for_config_entry(hass, hass_client, entry) + + assert result["config_entry"] == { + "entry_id": entry.entry_id, + "version": 1, + "domain": "nextdns", + "title": "Fake Profile", + "data": {"profile_id": REDACTED, "api_key": REDACTED}, + "options": {}, + "pref_disable_new_entities": False, + "pref_disable_polling": False, + "source": "user", + "unique_id": REDACTED, + "disabled_by": None, + } + assert result["dnssec_coordinator_data"] == { + "not_validated_queries": 25, + "validated_queries": 75, + "validated_queries_ratio": 75.0, + } + assert result["encryption_coordinator_data"] == { + "encrypted_queries": 60, + "unencrypted_queries": 40, + "encrypted_queries_ratio": 60.0, + } + assert result["ip_versions_coordinator_data"] == { + "ipv6_queries": 10, + "ipv4_queries": 90, + "ipv6_queries_ratio": 10.0, + } + assert result["protocols_coordinator_data"] == { + "doh_queries": 20, + "doq_queries": 10, + "dot_queries": 30, + "udp_queries": 40, + "doh_queries_ratio": 22.2, + "doq_queries_ratio": 11.1, + "dot_queries_ratio": 33.3, + "udp_queries_ratio": 44.4, + } + assert result["status_coordinator_data"] == { + "all_queries": 100, + "allowed_queries": 30, + "blocked_queries": 20, + "default_queries": 40, + "relayed_queries": 10, + "blocked_queries_ratio": 20.0, + }