"""Test sensor of NextDNS integration.""" from datetime import timedelta from unittest.mock import patch from nextdns import ApiError from homeassistant.components.nextdns.const import DOMAIN from homeassistant.components.sensor import ( ATTR_STATE_CLASS, DOMAIN as SENSOR_DOMAIN, SensorStateClass, ) from homeassistant.const import ATTR_UNIT_OF_MEASUREMENT, PERCENTAGE, STATE_UNAVAILABLE from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er from homeassistant.util.dt import utcnow from . import DNSSEC, ENCRYPTION, IP_VERSIONS, PROTOCOLS, STATUS, init_integration from tests.common import async_fire_time_changed async def test_sensor(hass: HomeAssistant) -> None: """Test states of sensors.""" registry = er.async_get(hass) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_doh_queries", suggested_object_id="fake_profile_dns_over_https_queries", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_doh3_queries", suggested_object_id="fake_profile_dns_over_http_3_queries", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_doh_queries_ratio", suggested_object_id="fake_profile_dns_over_https_queries_ratio", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_doh3_queries_ratio", suggested_object_id="fake_profile_dns_over_http_3_queries_ratio", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_doq_queries", suggested_object_id="fake_profile_dns_over_quic_queries", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_doq_queries_ratio", suggested_object_id="fake_profile_dns_over_quic_queries_ratio", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_dot_queries", suggested_object_id="fake_profile_dns_over_tls_queries", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_dot_queries_ratio", suggested_object_id="fake_profile_dns_over_tls_queries_ratio", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_not_validated_queries", suggested_object_id="fake_profile_dnssec_not_validated_queries", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_validated_queries", suggested_object_id="fake_profile_dnssec_validated_queries", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_validated_queries_ratio", suggested_object_id="fake_profile_dnssec_validated_queries_ratio", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_encrypted_queries", suggested_object_id="fake_profile_encrypted_queries", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_encrypted_queries_ratio", suggested_object_id="fake_profile_encrypted_queries_ratio", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_ipv4_queries", suggested_object_id="fake_profile_ipv4_queries", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_ipv6_queries", suggested_object_id="fake_profile_ipv6_queries", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_ipv6_queries_ratio", suggested_object_id="fake_profile_ipv6_queries_ratio", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_tcp_queries", suggested_object_id="fake_profile_tcp_queries", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_tcp_queries_ratio", suggested_object_id="fake_profile_tcp_queries_ratio", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_udp_queries", suggested_object_id="fake_profile_udp_queries", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_udp_queries_ratio", suggested_object_id="fake_profile_udp_queries_ratio", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_unencrypted_queries", suggested_object_id="fake_profile_unencrypted_queries", disabled_by=None, ) await init_integration(hass) state = hass.states.get("sensor.fake_profile_dns_queries") assert state assert state.state == "100" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.TOTAL assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "queries" entry = registry.async_get("sensor.fake_profile_dns_queries") assert entry assert entry.unique_id == "xyz12_all_queries" state = hass.states.get("sensor.fake_profile_dns_queries_blocked") assert state assert state.state == "20" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.TOTAL assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "queries" entry = registry.async_get("sensor.fake_profile_dns_queries_blocked") assert entry assert entry.unique_id == "xyz12_blocked_queries" state = hass.states.get("sensor.fake_profile_dns_queries_blocked_ratio") assert state assert state.state == "20.0" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE entry = registry.async_get("sensor.fake_profile_dns_queries_blocked_ratio") assert entry assert entry.unique_id == "xyz12_blocked_queries_ratio" state = hass.states.get("sensor.fake_profile_dns_queries_relayed") assert state assert state.state == "10" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.TOTAL assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "queries" entry = registry.async_get("sensor.fake_profile_dns_queries_relayed") assert entry assert entry.unique_id == "xyz12_relayed_queries" state = hass.states.get("sensor.fake_profile_dns_over_https_queries") assert state assert state.state == "20" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.TOTAL assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "queries" entry = registry.async_get("sensor.fake_profile_dns_over_https_queries") assert entry assert entry.unique_id == "xyz12_doh_queries" state = hass.states.get("sensor.fake_profile_dns_over_https_queries_ratio") assert state assert state.state == "17.4" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE entry = registry.async_get("sensor.fake_profile_dns_over_https_queries_ratio") assert entry assert entry.unique_id == "xyz12_doh_queries_ratio" state = hass.states.get("sensor.fake_profile_dns_over_http_3_queries") assert state assert state.state == "15" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.TOTAL assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "queries" entry = registry.async_get("sensor.fake_profile_dns_over_http_3_queries") assert entry assert entry.unique_id == "xyz12_doh3_queries" state = hass.states.get("sensor.fake_profile_dns_over_http_3_queries_ratio") assert state assert state.state == "13.0" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE entry = registry.async_get("sensor.fake_profile_dns_over_http_3_queries_ratio") assert entry assert entry.unique_id == "xyz12_doh3_queries_ratio" state = hass.states.get("sensor.fake_profile_dns_over_quic_queries") assert state assert state.state == "10" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.TOTAL assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "queries" entry = registry.async_get("sensor.fake_profile_dns_over_quic_queries") assert entry assert entry.unique_id == "xyz12_doq_queries" state = hass.states.get("sensor.fake_profile_dns_over_quic_queries_ratio") assert state assert state.state == "8.7" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE entry = registry.async_get("sensor.fake_profile_dns_over_quic_queries_ratio") assert entry assert entry.unique_id == "xyz12_doq_queries_ratio" state = hass.states.get("sensor.fake_profile_dns_over_tls_queries") assert state assert state.state == "30" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.TOTAL assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "queries" entry = registry.async_get("sensor.fake_profile_dns_over_tls_queries") assert entry assert entry.unique_id == "xyz12_dot_queries" state = hass.states.get("sensor.fake_profile_dns_over_tls_queries_ratio") assert state assert state.state == "26.1" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE entry = registry.async_get("sensor.fake_profile_dns_over_tls_queries_ratio") assert entry assert entry.unique_id == "xyz12_dot_queries_ratio" state = hass.states.get("sensor.fake_profile_dnssec_not_validated_queries") assert state assert state.state == "25" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.TOTAL assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "queries" entry = registry.async_get("sensor.fake_profile_dnssec_not_validated_queries") assert entry assert entry.unique_id == "xyz12_not_validated_queries" state = hass.states.get("sensor.fake_profile_dnssec_validated_queries") assert state assert state.state == "75" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.TOTAL assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "queries" entry = registry.async_get("sensor.fake_profile_dnssec_validated_queries") assert entry assert entry.unique_id == "xyz12_validated_queries" state = hass.states.get("sensor.fake_profile_dnssec_validated_queries_ratio") assert state assert state.state == "75.0" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE entry = registry.async_get("sensor.fake_profile_dnssec_validated_queries_ratio") assert entry assert entry.unique_id == "xyz12_validated_queries_ratio" state = hass.states.get("sensor.fake_profile_encrypted_queries") assert state assert state.state == "60" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.TOTAL assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "queries" entry = registry.async_get("sensor.fake_profile_encrypted_queries") assert entry assert entry.unique_id == "xyz12_encrypted_queries" state = hass.states.get("sensor.fake_profile_unencrypted_queries") assert state assert state.state == "40" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.TOTAL assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "queries" entry = registry.async_get("sensor.fake_profile_unencrypted_queries") assert entry assert entry.unique_id == "xyz12_unencrypted_queries" state = hass.states.get("sensor.fake_profile_encrypted_queries_ratio") assert state assert state.state == "60.0" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE entry = registry.async_get("sensor.fake_profile_encrypted_queries_ratio") assert entry assert entry.unique_id == "xyz12_encrypted_queries_ratio" state = hass.states.get("sensor.fake_profile_ipv4_queries") assert state assert state.state == "90" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.TOTAL assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "queries" entry = registry.async_get("sensor.fake_profile_ipv4_queries") assert entry assert entry.unique_id == "xyz12_ipv4_queries" state = hass.states.get("sensor.fake_profile_ipv6_queries") assert state assert state.state == "10" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.TOTAL assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "queries" entry = registry.async_get("sensor.fake_profile_ipv6_queries") assert entry assert entry.unique_id == "xyz12_ipv6_queries" state = hass.states.get("sensor.fake_profile_ipv6_queries_ratio") assert state assert state.state == "10.0" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE entry = registry.async_get("sensor.fake_profile_ipv6_queries_ratio") assert entry assert entry.unique_id == "xyz12_ipv6_queries_ratio" state = hass.states.get("sensor.fake_profile_tcp_queries") assert state assert state.state == "0" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.TOTAL assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "queries" entry = registry.async_get("sensor.fake_profile_tcp_queries") assert entry assert entry.unique_id == "xyz12_tcp_queries" state = hass.states.get("sensor.fake_profile_tcp_queries_ratio") assert state assert state.state == "0.0" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE entry = registry.async_get("sensor.fake_profile_tcp_queries_ratio") assert entry assert entry.unique_id == "xyz12_tcp_queries_ratio" state = hass.states.get("sensor.fake_profile_udp_queries") assert state assert state.state == "40" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.TOTAL assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "queries" entry = registry.async_get("sensor.fake_profile_udp_queries") assert entry assert entry.unique_id == "xyz12_udp_queries" state = hass.states.get("sensor.fake_profile_udp_queries_ratio") assert state assert state.state == "34.8" assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE entry = registry.async_get("sensor.fake_profile_udp_queries_ratio") assert entry assert entry.unique_id == "xyz12_udp_queries_ratio" async def test_availability(hass: HomeAssistant) -> None: """Ensure that we mark the entities unavailable correctly when service causes an error.""" registry = er.async_get(hass) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_doh_queries", suggested_object_id="fake_profile_dns_over_https_queries", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_validated_queries", suggested_object_id="fake_profile_dnssec_validated_queries", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_encrypted_queries", suggested_object_id="fake_profile_encrypted_queries", disabled_by=None, ) registry.async_get_or_create( SENSOR_DOMAIN, DOMAIN, "xyz12_ipv4_queries", suggested_object_id="fake_profile_ipv4_queries", disabled_by=None, ) await init_integration(hass) state = hass.states.get("sensor.fake_profile_dns_queries") assert state assert state.state != STATE_UNAVAILABLE assert state.state == "100" state = hass.states.get("sensor.fake_profile_dns_over_https_queries") assert state assert state.state != STATE_UNAVAILABLE assert state.state == "20" state = hass.states.get("sensor.fake_profile_dnssec_validated_queries") assert state assert state.state != STATE_UNAVAILABLE assert state.state == "75" state = hass.states.get("sensor.fake_profile_encrypted_queries") assert state assert state.state != STATE_UNAVAILABLE assert state.state == "60" state = hass.states.get("sensor.fake_profile_ipv4_queries") assert state assert state.state != STATE_UNAVAILABLE assert state.state == "90" future = utcnow() + timedelta(minutes=10) with patch( "homeassistant.components.nextdns.NextDns.get_analytics_status", side_effect=ApiError("API Error"), ), patch( "homeassistant.components.nextdns.NextDns.get_analytics_dnssec", side_effect=ApiError("API Error"), ), patch( "homeassistant.components.nextdns.NextDns.get_analytics_encryption", side_effect=ApiError("API Error"), ), patch( "homeassistant.components.nextdns.NextDns.get_analytics_ip_versions", side_effect=ApiError("API Error"), ), patch( "homeassistant.components.nextdns.NextDns.get_analytics_protocols", side_effect=ApiError("API Error"), ): async_fire_time_changed(hass, future) await hass.async_block_till_done() state = hass.states.get("sensor.fake_profile_dns_queries") assert state assert state.state == STATE_UNAVAILABLE state = hass.states.get("sensor.fake_profile_dns_over_https_queries") assert state assert state.state == STATE_UNAVAILABLE state = hass.states.get("sensor.fake_profile_dnssec_validated_queries") assert state assert state.state == STATE_UNAVAILABLE state = hass.states.get("sensor.fake_profile_encrypted_queries") assert state assert state.state == STATE_UNAVAILABLE state = hass.states.get("sensor.fake_profile_ipv4_queries") assert state assert state.state == STATE_UNAVAILABLE future = utcnow() + timedelta(minutes=20) with patch( "homeassistant.components.nextdns.NextDns.get_analytics_status", return_value=STATUS, ), patch( "homeassistant.components.nextdns.NextDns.get_analytics_encryption", return_value=ENCRYPTION, ), patch( "homeassistant.components.nextdns.NextDns.get_analytics_dnssec", return_value=DNSSEC, ), patch( "homeassistant.components.nextdns.NextDns.get_analytics_ip_versions", return_value=IP_VERSIONS, ), patch( "homeassistant.components.nextdns.NextDns.get_analytics_protocols", return_value=PROTOCOLS, ): async_fire_time_changed(hass, future) await hass.async_block_till_done() state = hass.states.get("sensor.fake_profile_dns_queries") assert state assert state.state != STATE_UNAVAILABLE assert state.state == "100" state = hass.states.get("sensor.fake_profile_dns_over_https_queries") assert state assert state.state != STATE_UNAVAILABLE assert state.state == "20" state = hass.states.get("sensor.fake_profile_dnssec_validated_queries") assert state assert state.state != STATE_UNAVAILABLE assert state.state == "75" state = hass.states.get("sensor.fake_profile_encrypted_queries") assert state assert state.state != STATE_UNAVAILABLE assert state.state == "60" state = hass.states.get("sensor.fake_profile_ipv4_queries") assert state assert state.state != STATE_UNAVAILABLE assert state.state == "90"