diff --git a/homeassistant/components/cloud/google_config.py b/homeassistant/components/cloud/google_config.py index dffa1e2f306..26cb830e8c6 100644 --- a/homeassistant/components/cloud/google_config.py +++ b/homeassistant/components/cloud/google_config.py @@ -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() diff --git a/homeassistant/components/google_assistant/helpers.py b/homeassistant/components/google_assistant/helpers.py index 9b133ad6a30..f248202e5f0 100644 --- a/homeassistant/components/google_assistant/helpers.py +++ b/homeassistant/components/google_assistant/helpers.py @@ -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.""" diff --git a/homeassistant/components/google_assistant/http.py b/homeassistant/components/google_assistant/http.py index 5cf1cb14379..3787a63a514 100644 --- a/homeassistant/components/google_assistant/http.py +++ b/homeassistant/components/google_assistant/http.py @@ -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: diff --git a/tests/components/cloud/test_google_config.py b/tests/components/cloud/test_google_config.py index e1da6bbe0a8..5f29a41c6e0 100644 --- a/tests/components/cloud/test_google_config.py +++ b/tests/components/cloud/test_google_config.py @@ -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