mirror of
https://github.com/home-assistant/core.git
synced 2025-04-22 16:27:56 +00:00
Migrate Mastodon unique id (#123877)
* Migrate unique id * Fix unique id check * Switch to minor version and other fixes
This commit is contained in:
parent
d50bac3b3e
commit
ac223e64f9
@ -17,10 +17,11 @@ from homeassistant.const import (
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers import discovery
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from .const import CONF_BASE_URL, DOMAIN
|
||||
from .const import CONF_BASE_URL, DOMAIN, LOGGER
|
||||
from .coordinator import MastodonCoordinator
|
||||
from .utils import create_mastodon_client
|
||||
from .utils import construct_mastodon_username, create_mastodon_client
|
||||
|
||||
PLATFORMS: list[Platform] = [Platform.NOTIFY, Platform.SENSOR]
|
||||
|
||||
@ -80,6 +81,39 @@ async def async_unload_entry(hass: HomeAssistant, entry: MastodonConfigEntry) ->
|
||||
)
|
||||
|
||||
|
||||
async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Migrate old config."""
|
||||
|
||||
if entry.version == 1 and entry.minor_version == 1:
|
||||
# Version 1.1 had the unique_id as client_id, this isn't necessarily unique
|
||||
LOGGER.debug("Migrating config entry from version %s", entry.version)
|
||||
|
||||
try:
|
||||
_, instance, account = await hass.async_add_executor_job(
|
||||
setup_mastodon,
|
||||
entry,
|
||||
)
|
||||
except MastodonError as ex:
|
||||
LOGGER.error("Migration failed with error %s", ex)
|
||||
return False
|
||||
|
||||
entry.minor_version = 2
|
||||
|
||||
hass.config_entries.async_update_entry(
|
||||
entry,
|
||||
unique_id=slugify(construct_mastodon_username(instance, account)),
|
||||
)
|
||||
|
||||
LOGGER.info(
|
||||
"Entry %s successfully migrated to version %s.%s",
|
||||
entry.entry_id,
|
||||
entry.version,
|
||||
entry.minor_version,
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def setup_mastodon(entry: ConfigEntry) -> tuple[Mastodon, dict, dict]:
|
||||
"""Get mastodon details."""
|
||||
client = create_mastodon_client(
|
||||
|
@ -20,6 +20,7 @@ from homeassistant.helpers.selector import (
|
||||
TextSelectorType,
|
||||
)
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from .const import CONF_BASE_URL, DEFAULT_URL, DOMAIN, LOGGER
|
||||
from .utils import construct_mastodon_username, create_mastodon_client
|
||||
@ -47,6 +48,7 @@ class MastodonConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow."""
|
||||
|
||||
VERSION = 1
|
||||
MINOR_VERSION = 2
|
||||
config_entry: ConfigEntry
|
||||
|
||||
def check_connection(
|
||||
@ -105,10 +107,6 @@ class MastodonConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a flow initialized by the user."""
|
||||
errors: dict[str, str] | None = None
|
||||
if user_input:
|
||||
self._async_abort_entries_match(
|
||||
{CONF_CLIENT_ID: user_input[CONF_CLIENT_ID]}
|
||||
)
|
||||
|
||||
instance, account, errors = await self.hass.async_add_executor_job(
|
||||
self.check_connection,
|
||||
user_input[CONF_BASE_URL],
|
||||
@ -119,7 +117,8 @@ class MastodonConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
|
||||
if not errors:
|
||||
name = construct_mastodon_username(instance, account)
|
||||
await self.async_set_unique_id(user_input[CONF_CLIENT_ID])
|
||||
await self.async_set_unique_id(slugify(name))
|
||||
self._abort_if_unique_id_configured()
|
||||
return self.async_create_entry(
|
||||
title=name,
|
||||
data=user_input,
|
||||
@ -148,7 +147,8 @@ class MastodonConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
)
|
||||
|
||||
if not errors:
|
||||
await self.async_set_unique_id(client_id)
|
||||
name = construct_mastodon_username(instance, account)
|
||||
await self.async_set_unique_id(slugify(name))
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
if not name:
|
||||
|
@ -53,5 +53,7 @@ def mock_config_entry() -> MockConfigEntry:
|
||||
CONF_ACCESS_TOKEN: "access_token",
|
||||
},
|
||||
entry_id="01J35M4AH9HYRC2V0G6RNVNWJH",
|
||||
unique_id="client_id",
|
||||
unique_id="trwnh_mastodon_social",
|
||||
version=1,
|
||||
minor_version=2,
|
||||
)
|
||||
|
33
tests/components/mastodon/snapshots/test_init.ambr
Normal file
33
tests/components/mastodon/snapshots/test_init.ambr
Normal file
@ -0,0 +1,33 @@
|
||||
# serializer version: 1
|
||||
# name: test_device_info
|
||||
DeviceRegistryEntrySnapshot({
|
||||
'area_id': None,
|
||||
'config_entries': <ANY>,
|
||||
'configuration_url': None,
|
||||
'connections': set({
|
||||
}),
|
||||
'disabled_by': None,
|
||||
'entry_type': <DeviceEntryType.SERVICE: 'service'>,
|
||||
'hw_version': None,
|
||||
'id': <ANY>,
|
||||
'identifiers': set({
|
||||
tuple(
|
||||
'mastodon',
|
||||
'trwnh_mastodon_social',
|
||||
),
|
||||
}),
|
||||
'is_new': False,
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': 'Mastodon gGmbH',
|
||||
'model': '@trwnh@mastodon.social',
|
||||
'model_id': None,
|
||||
'name': 'Mastodon @trwnh@mastodon.social',
|
||||
'name_by_user': None,
|
||||
'primary_config_entry': <ANY>,
|
||||
'serial_number': None,
|
||||
'suggested_area': None,
|
||||
'sw_version': '4.0.0rc1',
|
||||
'via_device_id': None,
|
||||
})
|
||||
# ---
|
@ -30,7 +30,7 @@
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'followers',
|
||||
'unique_id': 'client_id_followers',
|
||||
'unique_id': 'trwnh_mastodon_social_followers',
|
||||
'unit_of_measurement': 'accounts',
|
||||
})
|
||||
# ---
|
||||
@ -80,7 +80,7 @@
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'following',
|
||||
'unique_id': 'client_id_following',
|
||||
'unique_id': 'trwnh_mastodon_social_following',
|
||||
'unit_of_measurement': 'accounts',
|
||||
})
|
||||
# ---
|
||||
@ -130,7 +130,7 @@
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'posts',
|
||||
'unique_id': 'client_id_posts',
|
||||
'unique_id': 'trwnh_mastodon_social_posts',
|
||||
'unit_of_measurement': 'posts',
|
||||
})
|
||||
# ---
|
||||
|
@ -44,7 +44,7 @@ async def test_full_flow(
|
||||
CONF_CLIENT_SECRET: "client_secret",
|
||||
CONF_ACCESS_TOKEN: "access_token",
|
||||
}
|
||||
assert result["result"].unique_id == "client_id"
|
||||
assert result["result"].unique_id == "trwnh_mastodon_social"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
@ -3,15 +3,36 @@
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from mastodon.Mastodon import MastodonError
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.mastodon.config_flow import MastodonConfigFlow
|
||||
from homeassistant.components.mastodon.const import CONF_BASE_URL, DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_CLIENT_ID, CONF_CLIENT_SECRET
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
|
||||
from . import setup_integration
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_device_info(
|
||||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
mock_mastodon_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
) -> None:
|
||||
"""Test device registry integration."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
device_entry = device_registry.async_get_device(
|
||||
identifiers={(DOMAIN, mock_config_entry.unique_id)}
|
||||
)
|
||||
assert device_entry is not None
|
||||
assert device_entry == snapshot
|
||||
|
||||
|
||||
async def test_initialization_failure(
|
||||
hass: HomeAssistant,
|
||||
mock_mastodon_client: AsyncMock,
|
||||
@ -23,3 +44,39 @@ async def test_initialization_failure(
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY
|
||||
|
||||
|
||||
async def test_migrate(
|
||||
hass: HomeAssistant,
|
||||
mock_mastodon_client: AsyncMock,
|
||||
) -> None:
|
||||
"""Test migration."""
|
||||
# Setup the config entry
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
CONF_BASE_URL: "https://mastodon.social",
|
||||
CONF_CLIENT_ID: "client_id",
|
||||
CONF_CLIENT_SECRET: "client_secret",
|
||||
CONF_ACCESS_TOKEN: "access_token",
|
||||
},
|
||||
title="@trwnh@mastodon.social",
|
||||
unique_id="client_id",
|
||||
version=1,
|
||||
minor_version=1,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Check migration was successful
|
||||
assert config_entry.state is ConfigEntryState.LOADED
|
||||
assert config_entry.data == {
|
||||
CONF_BASE_URL: "https://mastodon.social",
|
||||
CONF_CLIENT_ID: "client_id",
|
||||
CONF_CLIENT_SECRET: "client_secret",
|
||||
CONF_ACCESS_TOKEN: "access_token",
|
||||
}
|
||||
assert config_entry.version == MastodonConfigFlow.VERSION
|
||||
assert config_entry.minor_version == MastodonConfigFlow.MINOR_VERSION
|
||||
assert config_entry.unique_id == "trwnh_mastodon_social"
|
||||
|
Loading…
x
Reference in New Issue
Block a user