Google assistant: disconnect user agent when not found in google (#48233)

This commit is contained in:
Bram Kragten 2021-03-23 23:04:32 +01:00 committed by GitHub
parent 9f8b697e64
commit b1d0b37d2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 62 additions and 34 deletions

View File

@ -6,11 +6,7 @@ from hass_nabucasa import Cloud, cloud_api
from hass_nabucasa.google_report_state import ErrorResponse
from homeassistant.components.google_assistant.helpers import AbstractConfig
from homeassistant.const import (
CLOUD_NEVER_EXPOSED_ENTITIES,
EVENT_HOMEASSISTANT_STARTED,
HTTP_OK,
)
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES, HTTP_OK
from homeassistant.core import CoreState, split_entity_id
from homeassistant.helpers import entity_registry
@ -87,8 +83,15 @@ class CloudGoogleConfig(AbstractConfig):
async def async_initialize(self):
"""Perform async initialization of config."""
await super().async_initialize()
# Remove bad data that was there until 0.103.6 - Jan 6, 2020
self._store.pop_agent_user_id(self._user)
# Remove old/wrong user agent ids
remove_agent_user_ids = []
for agent_user_id in self._store.agent_user_ids:
if agent_user_id != self.agent_user_id:
remove_agent_user_ids.append(agent_user_id)
for agent_user_id in remove_agent_user_ids:
await self.async_disconnect_agent_user(agent_user_id)
self._prefs.async_listen_updates(self._async_prefs_updated)
@ -198,17 +201,7 @@ class CloudGoogleConfig(AbstractConfig):
if not self._should_expose_entity_id(entity_id):
return
if self.hass.state == CoreState.running:
self.async_schedule_google_sync_all()
if self.hass.state != CoreState.running:
return
if self._sync_on_started:
return
self._sync_on_started = True
async def sync_google(_):
"""Sync entities to Google."""
await self.async_sync_entities_all()
self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, sync_google)
self.async_schedule_google_sync_all()

View File

@ -15,9 +15,10 @@ from homeassistant.const import (
ATTR_SUPPORTED_FEATURES,
CLOUD_NEVER_EXPOSED_ENTITIES,
CONF_NAME,
EVENT_HOMEASSISTANT_STARTED,
STATE_UNAVAILABLE,
)
from homeassistant.core import Context, HomeAssistant, State, callback
from homeassistant.core import Context, CoreState, HomeAssistant, State, callback
from homeassistant.helpers.area_registry import AreaEntry
from homeassistant.helpers.device_registry import DeviceEntry
from homeassistant.helpers.entity_registry import RegistryEntry
@ -104,6 +105,16 @@ class AbstractConfig(ABC):
self._store = GoogleConfigStore(self.hass)
await self._store.async_load()
if self.hass.state == CoreState.running:
await self.async_sync_entities_all()
return
async def sync_google(_):
"""Sync entities to Google."""
await self.async_sync_entities_all()
self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, sync_google)
@property
def enabled(self):
"""Return if Google is enabled."""
@ -193,7 +204,10 @@ class AbstractConfig(ABC):
"""Sync all entities to Google."""
# Remove any pending sync
self._google_sync_unsub.pop(agent_user_id, lambda: None)()
return await self._async_request_sync_devices(agent_user_id)
status = await self._async_request_sync_devices(agent_user_id)
if status == 404:
await self.async_disconnect_agent_user(agent_user_id)
return status
async def async_sync_entities_all(self):
"""Sync all entities to Google for all registered agents."""

View File

@ -135,11 +135,12 @@ class GoogleConfig(AbstractConfig):
async def _async_request_sync_devices(self, agent_user_id: str):
if CONF_SERVICE_ACCOUNT in self._config:
await self.async_call_homegraph_api(
return await self.async_call_homegraph_api(
REQUEST_SYNC_BASE_URL, {"agentUserId": agent_user_id}
)
else:
_LOGGER.error("No configuration for request_sync available")
_LOGGER.error("No configuration for request_sync available")
return HTTP_INTERNAL_SERVER_ERROR
async def _async_update_token(self, force=False):
if CONF_SERVICE_ACCOUNT not in self._config:

View File

@ -1,5 +1,5 @@
"""Test the Cloud Google Config."""
from unittest.mock import AsyncMock, Mock, patch
from unittest.mock import Mock, patch
import pytest
@ -41,21 +41,19 @@ async def test_google_update_report_state(mock_conf, hass, cloud_prefs):
assert len(mock_report_state.mock_calls) == 1
async def test_sync_entities(aioclient_mock, hass, cloud_prefs):
async def test_sync_entities(mock_conf, hass, cloud_prefs):
"""Test sync devices."""
config = CloudGoogleConfig(
hass,
GACTIONS_SCHEMA({}),
"mock-user-id",
cloud_prefs,
Mock(auth=Mock(async_check_token=AsyncMock())),
)
await mock_conf.async_initialize()
await mock_conf.async_connect_agent_user("mock-user-id")
assert len(mock_conf._store.agent_user_ids) == 1
with patch(
"hass_nabucasa.cloud_api.async_google_actions_request_sync",
return_value=Mock(status=HTTP_NOT_FOUND),
) as mock_request_sync:
assert await config.async_sync_entities("user") == HTTP_NOT_FOUND
assert await mock_conf.async_sync_entities("mock-user-id") == HTTP_NOT_FOUND
assert len(mock_conf._store.agent_user_ids) == 0
assert len(mock_request_sync.mock_calls) == 1
@ -165,7 +163,29 @@ async def test_google_entity_registry_sync(hass, mock_cloud_login, cloud_prefs):
assert len(mock_sync.mock_calls) == 3
async def test_sync_google_when_started(hass, mock_cloud_login, cloud_prefs):
"""Test Google config syncs on init."""
config = CloudGoogleConfig(
hass, GACTIONS_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data["cloud"]
)
with patch.object(config, "async_sync_entities_all") as mock_sync:
await config.async_initialize()
await config.async_connect_agent_user("mock-user-id")
assert len(mock_sync.mock_calls) == 1
async def test_sync_google_on_home_assistant_start(hass, mock_cloud_login, cloud_prefs):
"""Test Google config syncs when home assistant started."""
config = CloudGoogleConfig(
hass, GACTIONS_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data["cloud"]
)
hass.state = CoreState.starting
with patch.object(config, "async_sync_entities_all") as mock_sync:
await config.async_initialize()
await config.async_connect_agent_user("mock-user-id")
assert len(mock_sync.mock_calls) == 0
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
await hass.async_block_till_done()
assert len(mock_sync.mock_calls) == 1