From ddd198de372ee87a2b164413b48c406b00410743 Mon Sep 17 00:00:00 2001 From: Allen Porter Date: Sun, 6 Feb 2022 14:14:25 -0800 Subject: [PATCH] Fix legacy nest diagnostics to return empty rather than fail (#65824) Fix legacy nest diangostics to return gracefully, rather than a TypError by checking explicitiy for SDM in the config entry. Update diagnostics to use the common nest test fixture, and extend with support for the legacy nest config. Use the sdm test fixture in the existing legacy tests so they all share the same config files. --- homeassistant/components/nest/diagnostics.py | 5 +- tests/components/nest/common.py | 18 ++++ .../nest/test_config_flow_legacy.py | 6 +- tests/components/nest/test_diagnostics.py | 85 ++++++++++--------- tests/components/nest/test_init_legacy.py | 31 ++----- 5 files changed, 78 insertions(+), 67 deletions(-) diff --git a/homeassistant/components/nest/diagnostics.py b/homeassistant/components/nest/diagnostics.py index 0b6cfff6bae..859aa834581 100644 --- a/homeassistant/components/nest/diagnostics.py +++ b/homeassistant/components/nest/diagnostics.py @@ -12,7 +12,7 @@ from google_nest_sdm.exceptions import ApiException from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant -from .const import DATA_SUBSCRIBER, DOMAIN +from .const import DATA_SDM, DATA_SUBSCRIBER, DOMAIN REDACT_DEVICE_TRAITS = {InfoTrait.NAME} @@ -21,6 +21,9 @@ async def async_get_config_entry_diagnostics( hass: HomeAssistant, config_entry: ConfigEntry ) -> dict: """Return diagnostics for a config entry.""" + if DATA_SDM not in config_entry.data: + return {} + if DATA_SUBSCRIBER not in hass.data[DOMAIN]: return {"error": "No subscriber configured"} diff --git a/tests/components/nest/common.py b/tests/components/nest/common.py index ca761e8987f..e80ca84d58f 100644 --- a/tests/components/nest/common.py +++ b/tests/components/nest/common.py @@ -102,6 +102,24 @@ TEST_CONFIG_HYBRID = NestTestConfig( }, ) +TEST_CONFIG_LEGACY = NestTestConfig( + config={ + "nest": { + "client_id": "some-client-id", + "client_secret": "some-client-secret", + }, + }, + config_entry_data={ + "auth_implementation": "local", + "tokens": { + "expires_at": time.time() + 86400, + "access_token": { + "token": "some-token", + }, + }, + }, +) + class FakeSubscriber(GoogleNestSubscriber): """Fake subscriber that supplies a FakeDeviceManager.""" diff --git a/tests/components/nest/test_config_flow_legacy.py b/tests/components/nest/test_config_flow_legacy.py index d21920b9e6f..843c9b582ae 100644 --- a/tests/components/nest/test_config_flow_legacy.py +++ b/tests/components/nest/test_config_flow_legacy.py @@ -6,9 +6,11 @@ from homeassistant import config_entries, data_entry_flow from homeassistant.components.nest import DOMAIN, config_flow from homeassistant.setup import async_setup_component +from .common import TEST_CONFIG_LEGACY + from tests.common import MockConfigEntry -CONFIG = {DOMAIN: {"client_id": "bla", "client_secret": "bla"}} +CONFIG = TEST_CONFIG_LEGACY.config async def test_abort_if_no_implementation_registered(hass): @@ -59,7 +61,7 @@ async def test_full_flow_implementation(hass): assert ( result["description_placeholders"] .get("url") - .startswith("https://home.nest.com/login/oauth2?client_id=bla") + .startswith("https://home.nest.com/login/oauth2?client_id=some-client-id") ) def mock_login(auth): diff --git a/tests/components/nest/test_diagnostics.py b/tests/components/nest/test_diagnostics.py index b603019da81..cf6c9c5b20f 100644 --- a/tests/components/nest/test_diagnostics.py +++ b/tests/components/nest/test_diagnostics.py @@ -2,54 +2,45 @@ from unittest.mock import patch -from google_nest_sdm.device import Device from google_nest_sdm.exceptions import SubscriberException +import pytest -from homeassistant.components.nest import DOMAIN from homeassistant.config_entries import ConfigEntryState -from homeassistant.setup import async_setup_component -from .common import CONFIG, async_setup_sdm_platform, create_config_entry +from .common import TEST_CONFIG_LEGACY from tests.components.diagnostics import get_diagnostics_for_config_entry -THERMOSTAT_TYPE = "sdm.devices.types.THERMOSTAT" - -async def test_entry_diagnostics(hass, hass_client): +async def test_entry_diagnostics( + hass, hass_client, create_device, setup_platform, config_entry +): """Test config entry diagnostics.""" - devices = { - "some-device-id": Device.MakeDevice( - { - "name": "enterprises/project-id/devices/device-id", - "type": "sdm.devices.types.THERMOSTAT", - "assignee": "enterprises/project-id/structures/structure-id/rooms/room-id", - "traits": { - "sdm.devices.traits.Info": { - "customName": "My Sensor", - }, - "sdm.devices.traits.Temperature": { - "ambientTemperatureCelsius": 25.1, - }, - "sdm.devices.traits.Humidity": { - "ambientHumidityPercent": 35.0, - }, + create_device.create( + raw_data={ + "name": "enterprises/project-id/devices/device-id", + "type": "sdm.devices.types.THERMOSTAT", + "assignee": "enterprises/project-id/structures/structure-id/rooms/room-id", + "traits": { + "sdm.devices.traits.Info": { + "customName": "My Sensor", + }, + "sdm.devices.traits.Temperature": { + "ambientTemperatureCelsius": 25.1, + }, + "sdm.devices.traits.Humidity": { + "ambientHumidityPercent": 35.0, }, - "parentRelations": [ - { - "parent": "enterprises/project-id/structures/structure-id/rooms/room-id", - "displayName": "Lobby", - } - ], }, - auth=None, - ) - } - assert await async_setup_sdm_platform(hass, platform=None, devices=devices) - - entries = hass.config_entries.async_entries(DOMAIN) - assert len(entries) == 1 - config_entry = entries[0] + "parentRelations": [ + { + "parent": "enterprises/project-id/structures/structure-id/rooms/room-id", + "displayName": "Lobby", + } + ], + } + ) + await setup_platform() assert config_entry.state is ConfigEntryState.LOADED # Test that only non identifiable device information is returned @@ -76,20 +67,32 @@ async def test_entry_diagnostics(hass, hass_client): } -async def test_setup_susbcriber_failure(hass, hass_client): +async def test_setup_susbcriber_failure( + hass, hass_client, config_entry, setup_base_platform +): """Test configuration error.""" - config_entry = create_config_entry() - config_entry.add_to_hass(hass) with patch( "homeassistant.helpers.config_entry_oauth2_flow.async_get_config_entry_implementation" ), patch( "homeassistant.components.nest.api.GoogleNestSubscriber.start_async", side_effect=SubscriberException(), ): - assert await async_setup_component(hass, DOMAIN, CONFIG) + await setup_base_platform() assert config_entry.state is ConfigEntryState.SETUP_RETRY assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == { "error": "No subscriber configured" } + + +@pytest.mark.parametrize("nest_test_config", [TEST_CONFIG_LEGACY]) +async def test_legacy_config_entry_diagnostics( + hass, hass_client, config_entry, setup_base_platform +): + """Test config entry diagnostics for legacy integration doesn't fail.""" + + with patch("homeassistant.components.nest.legacy.Nest"): + await setup_base_platform() + + assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == {} diff --git a/tests/components/nest/test_init_legacy.py b/tests/components/nest/test_init_legacy.py index 3a78877a235..cbf1bfe2d48 100644 --- a/tests/components/nest/test_init_legacy.py +++ b/tests/components/nest/test_init_legacy.py @@ -1,30 +1,18 @@ """Test basic initialization for the Legacy Nest API using mocks for the Nest python library.""" -import time from unittest.mock import MagicMock, PropertyMock, patch -from homeassistant.setup import async_setup_component +import pytest -from tests.common import MockConfigEntry +from .common import TEST_CONFIG_LEGACY DOMAIN = "nest" -CONFIG = { - "nest": { - "client_id": "some-client-id", - "client_secret": "some-client-secret", - }, -} -CONFIG_ENTRY_DATA = { - "auth_implementation": "local", - "tokens": { - "expires_at": time.time() + 86400, - "access_token": { - "token": "some-token", - }, - }, -} +@pytest.fixture +def nest_test_config(): + """Fixture to specify the overall test fixture configuration.""" + return TEST_CONFIG_LEGACY def make_thermostat(): @@ -45,7 +33,7 @@ def make_thermostat(): return device -async def test_thermostat(hass): +async def test_thermostat(hass, setup_base_platform): """Test simple initialization for thermostat entities.""" thermostat = make_thermostat() @@ -58,8 +46,6 @@ async def test_thermostat(hass): nest = MagicMock() type(nest).structures = PropertyMock(return_value=[structure]) - config_entry = MockConfigEntry(domain=DOMAIN, data=CONFIG_ENTRY_DATA) - config_entry.add_to_hass(hass) with patch("homeassistant.components.nest.legacy.Nest", return_value=nest), patch( "homeassistant.components.nest.legacy.sensor._VALID_SENSOR_TYPES", ["humidity", "temperature"], @@ -67,8 +53,7 @@ async def test_thermostat(hass): "homeassistant.components.nest.legacy.binary_sensor._VALID_BINARY_SENSOR_TYPES", {"fan": None}, ): - assert await async_setup_component(hass, DOMAIN, CONFIG) - await hass.async_block_till_done() + await setup_base_platform() climate = hass.states.get("climate.my_thermostat") assert climate is not None