Re-run expose entities migration if first time failed (#92564)

* Re-run expose entities migration if first time failed

* Count number of exposed entities

* Add tests

---------

Co-authored-by: Erik <erik@montnemery.com>
This commit is contained in:
Paulus Schoutsen 2023-05-05 08:11:09 -04:00 committed by GitHub
parent 6f3c9324ac
commit 19dcc8c88f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 219 additions and 6 deletions

View file

@ -216,8 +216,18 @@ class CloudAlexaConfig(alexa_config.AbstractConfig):
async def on_hass_started(hass):
if self._prefs.alexa_settings_version != ALEXA_SETTINGS_VERSION:
if self._prefs.alexa_settings_version < 2:
if self._prefs.alexa_settings_version < 2 or (
# Recover from a bug we had in 2023.5.0 where entities didn't get exposed
self._prefs.alexa_settings_version < 3
and not any(
settings.get("should_expose", False)
for settings in async_get_assistant_settings(
hass, CLOUD_ALEXA
).values()
)
):
self._migrate_alexa_entity_settings_v1()
await self._prefs.async_update(
alexa_settings_version=ALEXA_SETTINGS_VERSION
)

View file

@ -12,6 +12,7 @@ from homeassistant.components.google_assistant import DOMAIN as GOOGLE_DOMAIN
from homeassistant.components.google_assistant.helpers import AbstractConfig
from homeassistant.components.homeassistant.exposed_entities import (
async_expose_entity,
async_get_assistant_settings,
async_get_entity_settings,
async_listen_entity_updates,
async_set_assistant_option,
@ -200,8 +201,18 @@ class CloudGoogleConfig(AbstractConfig):
async def on_hass_started(hass: HomeAssistant) -> None:
if self._prefs.google_settings_version != GOOGLE_SETTINGS_VERSION:
if self._prefs.google_settings_version < 2:
if self._prefs.google_settings_version < 2 or (
# Recover from a bug we had in 2023.5.0 where entities didn't get exposed
self._prefs.google_settings_version < 3
and not any(
settings.get("should_expose", False)
for settings in async_get_assistant_settings(
hass, CLOUD_GOOGLE
).values()
)
):
self._migrate_google_entity_settings_v1()
await self._prefs.async_update(
google_settings_version=GOOGLE_SETTINGS_VERSION
)

View file

@ -41,8 +41,8 @@ STORAGE_KEY = DOMAIN
STORAGE_VERSION = 1
STORAGE_VERSION_MINOR = 2
ALEXA_SETTINGS_VERSION = 2
GOOGLE_SETTINGS_VERSION = 2
ALEXA_SETTINGS_VERSION = 3
GOOGLE_SETTINGS_VERSION = 3
class CloudPreferencesStore(Store):

View file

@ -542,11 +542,13 @@ async def test_alexa_handle_logout(
assert len(mock_enable.return_value.mock_calls) == 1
@pytest.mark.parametrize("alexa_settings_version", [1, 2])
async def test_alexa_config_migrate_expose_entity_prefs(
hass: HomeAssistant,
cloud_prefs: CloudPreferences,
cloud_stub,
entity_registry: er.EntityRegistry,
alexa_settings_version: int,
) -> None:
"""Test migrating Alexa entity config."""
hass.state = CoreState.starting
@ -593,7 +595,7 @@ async def test_alexa_config_migrate_expose_entity_prefs(
await cloud_prefs.async_update(
alexa_enabled=True,
alexa_report_state=False,
alexa_settings_version=1,
alexa_settings_version=alexa_settings_version,
)
expose_entity(hass, entity_migrated.entity_id, False)
@ -641,6 +643,100 @@ async def test_alexa_config_migrate_expose_entity_prefs(
}
async def test_alexa_config_migrate_expose_entity_prefs_v2_no_exposed(
hass: HomeAssistant,
cloud_prefs: CloudPreferences,
entity_registry: er.EntityRegistry,
) -> None:
"""Test migrating Alexa entity config from v2 to v3 when no entity is exposed."""
hass.state = CoreState.starting
assert await async_setup_component(hass, "homeassistant", {})
hass.states.async_set("light.state_only", "on")
entity_migrated = entity_registry.async_get_or_create(
"light",
"test",
"light_migrated",
suggested_object_id="migrated",
)
await cloud_prefs.async_update(
alexa_enabled=True,
alexa_report_state=False,
alexa_settings_version=2,
)
expose_entity(hass, "light.state_only", False)
expose_entity(hass, entity_migrated.entity_id, False)
cloud_prefs._prefs[PREF_ALEXA_ENTITY_CONFIGS]["light.state_only"] = {
PREF_SHOULD_EXPOSE: True
}
cloud_prefs._prefs[PREF_ALEXA_ENTITY_CONFIGS][entity_migrated.entity_id] = {
PREF_SHOULD_EXPOSE: True
}
conf = alexa_config.CloudAlexaConfig(
hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, Mock(is_logged_in=False)
)
await conf.async_initialize()
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
await hass.async_block_till_done()
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
await hass.async_block_till_done()
assert async_get_entity_settings(hass, "light.state_only") == {
"cloud.alexa": {"should_expose": True}
}
assert async_get_entity_settings(hass, entity_migrated.entity_id) == {
"cloud.alexa": {"should_expose": True}
}
async def test_alexa_config_migrate_expose_entity_prefs_v2_exposed(
hass: HomeAssistant,
cloud_prefs: CloudPreferences,
entity_registry: er.EntityRegistry,
) -> None:
"""Test migrating Alexa entity config from v2 to v3 when an entity is exposed."""
hass.state = CoreState.starting
assert await async_setup_component(hass, "homeassistant", {})
hass.states.async_set("light.state_only", "on")
entity_migrated = entity_registry.async_get_or_create(
"light",
"test",
"light_migrated",
suggested_object_id="migrated",
)
await cloud_prefs.async_update(
alexa_enabled=True,
alexa_report_state=False,
alexa_settings_version=2,
)
expose_entity(hass, "light.state_only", False)
expose_entity(hass, entity_migrated.entity_id, True)
cloud_prefs._prefs[PREF_ALEXA_ENTITY_CONFIGS]["light.state_only"] = {
PREF_SHOULD_EXPOSE: True
}
cloud_prefs._prefs[PREF_ALEXA_ENTITY_CONFIGS][entity_migrated.entity_id] = {
PREF_SHOULD_EXPOSE: True
}
conf = alexa_config.CloudAlexaConfig(
hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, Mock(is_logged_in=False)
)
await conf.async_initialize()
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
await hass.async_block_till_done()
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
await hass.async_block_till_done()
assert async_get_entity_settings(hass, "light.state_only") == {
"cloud.alexa": {"should_expose": False}
}
assert async_get_entity_settings(hass, entity_migrated.entity_id) == {
"cloud.alexa": {"should_expose": True}
}
async def test_alexa_config_migrate_expose_entity_prefs_default_none(
hass: HomeAssistant,
cloud_prefs: CloudPreferences,

View file

@ -483,10 +483,12 @@ async def test_google_handle_logout(
assert len(mock_enable.return_value.mock_calls) == 1
@pytest.mark.parametrize("google_settings_version", [1, 2])
async def test_google_config_migrate_expose_entity_prefs(
hass: HomeAssistant,
cloud_prefs: CloudPreferences,
entity_registry: er.EntityRegistry,
google_settings_version: int,
) -> None:
"""Test migrating Google entity config."""
hass.state = CoreState.starting
@ -540,7 +542,7 @@ async def test_google_config_migrate_expose_entity_prefs(
await cloud_prefs.async_update(
google_enabled=True,
google_report_state=False,
google_settings_version=1,
google_settings_version=google_settings_version,
)
expose_entity(hass, entity_migrated.entity_id, False)
@ -596,6 +598,100 @@ async def test_google_config_migrate_expose_entity_prefs(
}
async def test_google_config_migrate_expose_entity_prefs_v2_no_exposed(
hass: HomeAssistant,
cloud_prefs: CloudPreferences,
entity_registry: er.EntityRegistry,
) -> None:
"""Test migrating Google entity config from v2 to v3 when no entity is exposed."""
hass.state = CoreState.starting
assert await async_setup_component(hass, "homeassistant", {})
hass.states.async_set("light.state_only", "on")
entity_migrated = entity_registry.async_get_or_create(
"light",
"test",
"light_migrated",
suggested_object_id="migrated",
)
await cloud_prefs.async_update(
google_enabled=True,
google_report_state=False,
google_settings_version=2,
)
expose_entity(hass, "light.state_only", False)
expose_entity(hass, entity_migrated.entity_id, False)
cloud_prefs._prefs[PREF_GOOGLE_ENTITY_CONFIGS]["light.state_only"] = {
PREF_SHOULD_EXPOSE: True
}
cloud_prefs._prefs[PREF_GOOGLE_ENTITY_CONFIGS][entity_migrated.entity_id] = {
PREF_SHOULD_EXPOSE: True
}
conf = CloudGoogleConfig(
hass, GACTIONS_SCHEMA({}), "mock-user-id", cloud_prefs, Mock(is_logged_in=False)
)
await conf.async_initialize()
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
await hass.async_block_till_done()
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
await hass.async_block_till_done()
assert async_get_entity_settings(hass, "light.state_only") == {
"cloud.google_assistant": {"should_expose": True}
}
assert async_get_entity_settings(hass, entity_migrated.entity_id) == {
"cloud.google_assistant": {"should_expose": True}
}
async def test_google_config_migrate_expose_entity_prefs_v2_exposed(
hass: HomeAssistant,
cloud_prefs: CloudPreferences,
entity_registry: er.EntityRegistry,
) -> None:
"""Test migrating Google entity config from v2 to v3 when an entity is exposed."""
hass.state = CoreState.starting
assert await async_setup_component(hass, "homeassistant", {})
hass.states.async_set("light.state_only", "on")
entity_migrated = entity_registry.async_get_or_create(
"light",
"test",
"light_migrated",
suggested_object_id="migrated",
)
await cloud_prefs.async_update(
google_enabled=True,
google_report_state=False,
google_settings_version=2,
)
expose_entity(hass, "light.state_only", False)
expose_entity(hass, entity_migrated.entity_id, True)
cloud_prefs._prefs[PREF_GOOGLE_ENTITY_CONFIGS]["light.state_only"] = {
PREF_SHOULD_EXPOSE: True
}
cloud_prefs._prefs[PREF_GOOGLE_ENTITY_CONFIGS][entity_migrated.entity_id] = {
PREF_SHOULD_EXPOSE: True
}
conf = CloudGoogleConfig(
hass, GACTIONS_SCHEMA({}), "mock-user-id", cloud_prefs, Mock(is_logged_in=False)
)
await conf.async_initialize()
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
await hass.async_block_till_done()
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
await hass.async_block_till_done()
assert async_get_entity_settings(hass, "light.state_only") == {
"cloud.google_assistant": {"should_expose": False}
}
assert async_get_entity_settings(hass, entity_migrated.entity_id) == {
"cloud.google_assistant": {"should_expose": True}
}
async def test_google_config_migrate_expose_entity_prefs_default_none(
hass: HomeAssistant,
cloud_prefs: CloudPreferences,