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.
This commit is contained in:
Allen Porter 2022-02-06 14:14:25 -08:00 committed by Paulus Schoutsen
parent a4d59aa599
commit 619a52a387
5 changed files with 78 additions and 67 deletions

View File

@ -12,7 +12,7 @@ from google_nest_sdm.exceptions import ApiException
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from .const import DATA_SUBSCRIBER, DOMAIN from .const import DATA_SDM, DATA_SUBSCRIBER, DOMAIN
REDACT_DEVICE_TRAITS = {InfoTrait.NAME} REDACT_DEVICE_TRAITS = {InfoTrait.NAME}
@ -21,6 +21,9 @@ async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry hass: HomeAssistant, config_entry: ConfigEntry
) -> dict: ) -> dict:
"""Return diagnostics for a config entry.""" """Return diagnostics for a config entry."""
if DATA_SDM not in config_entry.data:
return {}
if DATA_SUBSCRIBER not in hass.data[DOMAIN]: if DATA_SUBSCRIBER not in hass.data[DOMAIN]:
return {"error": "No subscriber configured"} return {"error": "No subscriber configured"}

View File

@ -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): class FakeSubscriber(GoogleNestSubscriber):
"""Fake subscriber that supplies a FakeDeviceManager.""" """Fake subscriber that supplies a FakeDeviceManager."""

View File

@ -6,9 +6,11 @@ from homeassistant import config_entries, data_entry_flow
from homeassistant.components.nest import DOMAIN, config_flow from homeassistant.components.nest import DOMAIN, config_flow
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from .common import TEST_CONFIG_LEGACY
from tests.common import MockConfigEntry 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): async def test_abort_if_no_implementation_registered(hass):
@ -59,7 +61,7 @@ async def test_full_flow_implementation(hass):
assert ( assert (
result["description_placeholders"] result["description_placeholders"]
.get("url") .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): def mock_login(auth):

View File

@ -2,54 +2,45 @@
from unittest.mock import patch from unittest.mock import patch
from google_nest_sdm.device import Device
from google_nest_sdm.exceptions import SubscriberException from google_nest_sdm.exceptions import SubscriberException
import pytest
from homeassistant.components.nest import DOMAIN
from homeassistant.config_entries import ConfigEntryState 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 from tests.components.diagnostics import get_diagnostics_for_config_entry
THERMOSTAT_TYPE = "sdm.devices.types.THERMOSTAT"
async def test_entry_diagnostics(
async def test_entry_diagnostics(hass, hass_client): hass, hass_client, create_device, setup_platform, config_entry
):
"""Test config entry diagnostics.""" """Test config entry diagnostics."""
devices = { create_device.create(
"some-device-id": Device.MakeDevice( raw_data={
{ "name": "enterprises/project-id/devices/device-id",
"name": "enterprises/project-id/devices/device-id", "type": "sdm.devices.types.THERMOSTAT",
"type": "sdm.devices.types.THERMOSTAT", "assignee": "enterprises/project-id/structures/structure-id/rooms/room-id",
"assignee": "enterprises/project-id/structures/structure-id/rooms/room-id", "traits": {
"traits": { "sdm.devices.traits.Info": {
"sdm.devices.traits.Info": { "customName": "My Sensor",
"customName": "My Sensor", },
}, "sdm.devices.traits.Temperature": {
"sdm.devices.traits.Temperature": { "ambientTemperatureCelsius": 25.1,
"ambientTemperatureCelsius": 25.1, },
}, "sdm.devices.traits.Humidity": {
"sdm.devices.traits.Humidity": { "ambientHumidityPercent": 35.0,
"ambientHumidityPercent": 35.0,
},
}, },
"parentRelations": [
{
"parent": "enterprises/project-id/structures/structure-id/rooms/room-id",
"displayName": "Lobby",
}
],
}, },
auth=None, "parentRelations": [
) {
} "parent": "enterprises/project-id/structures/structure-id/rooms/room-id",
assert await async_setup_sdm_platform(hass, platform=None, devices=devices) "displayName": "Lobby",
}
entries = hass.config_entries.async_entries(DOMAIN) ],
assert len(entries) == 1 }
config_entry = entries[0] )
await setup_platform()
assert config_entry.state is ConfigEntryState.LOADED assert config_entry.state is ConfigEntryState.LOADED
# Test that only non identifiable device information is returned # 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.""" """Test configuration error."""
config_entry = create_config_entry()
config_entry.add_to_hass(hass)
with patch( with patch(
"homeassistant.helpers.config_entry_oauth2_flow.async_get_config_entry_implementation" "homeassistant.helpers.config_entry_oauth2_flow.async_get_config_entry_implementation"
), patch( ), patch(
"homeassistant.components.nest.api.GoogleNestSubscriber.start_async", "homeassistant.components.nest.api.GoogleNestSubscriber.start_async",
side_effect=SubscriberException(), side_effect=SubscriberException(),
): ):
assert await async_setup_component(hass, DOMAIN, CONFIG) await setup_base_platform()
assert config_entry.state is ConfigEntryState.SETUP_RETRY assert config_entry.state is ConfigEntryState.SETUP_RETRY
assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == { assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == {
"error": "No subscriber configured" "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) == {}

View File

@ -1,30 +1,18 @@
"""Test basic initialization for the Legacy Nest API using mocks for the Nest python library.""" """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 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" DOMAIN = "nest"
CONFIG = {
"nest": {
"client_id": "some-client-id",
"client_secret": "some-client-secret",
},
}
CONFIG_ENTRY_DATA = { @pytest.fixture
"auth_implementation": "local", def nest_test_config():
"tokens": { """Fixture to specify the overall test fixture configuration."""
"expires_at": time.time() + 86400, return TEST_CONFIG_LEGACY
"access_token": {
"token": "some-token",
},
},
}
def make_thermostat(): def make_thermostat():
@ -45,7 +33,7 @@ def make_thermostat():
return device return device
async def test_thermostat(hass): async def test_thermostat(hass, setup_base_platform):
"""Test simple initialization for thermostat entities.""" """Test simple initialization for thermostat entities."""
thermostat = make_thermostat() thermostat = make_thermostat()
@ -58,8 +46,6 @@ async def test_thermostat(hass):
nest = MagicMock() nest = MagicMock()
type(nest).structures = PropertyMock(return_value=[structure]) 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( with patch("homeassistant.components.nest.legacy.Nest", return_value=nest), patch(
"homeassistant.components.nest.legacy.sensor._VALID_SENSOR_TYPES", "homeassistant.components.nest.legacy.sensor._VALID_SENSOR_TYPES",
["humidity", "temperature"], ["humidity", "temperature"],
@ -67,8 +53,7 @@ async def test_thermostat(hass):
"homeassistant.components.nest.legacy.binary_sensor._VALID_BINARY_SENSOR_TYPES", "homeassistant.components.nest.legacy.binary_sensor._VALID_BINARY_SENSOR_TYPES",
{"fan": None}, {"fan": None},
): ):
assert await async_setup_component(hass, DOMAIN, CONFIG) await setup_base_platform()
await hass.async_block_till_done()
climate = hass.states.get("climate.my_thermostat") climate = hass.states.get("climate.my_thermostat")
assert climate is not None assert climate is not None