mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 08:47:57 +00:00
Migrate sabnzbd sensors unique ids (#71455)
* Migrate sensors unique ids 1. migrate sensors to have unique id constructed also from entry_id 2. add migration flow in init 3. bump config flow to version 2 4. add tests for migration * move migrate to async_setup_entry * 1. Use the entity registry api in tests 2. Set up the config entry and not use integration directly 3. remove patch for entity registry * fix too many lines * Update tests/components/sabnzbd/test_init.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update tests/components/sabnzbd/test_init.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update tests/components/sabnzbd/test_init.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update tests/components/sabnzbd/test_init.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
1be2438ef6
commit
f50681e3d3
@ -1,4 +1,6 @@
|
||||
"""Support for monitoring an SABnzbd NZB client."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
import logging
|
||||
|
||||
@ -19,7 +21,9 @@ from homeassistant.const import (
|
||||
from homeassistant.core import HomeAssistant, ServiceCall, callback
|
||||
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.device_registry import async_get
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
from homeassistant.helpers.entity_registry import RegistryEntry, async_migrate_entries
|
||||
from homeassistant.helpers.event import async_track_time_interval
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
@ -123,8 +127,56 @@ def async_get_entry_id_for_service_call(hass: HomeAssistant, call: ServiceCall)
|
||||
raise ValueError(f"No api for API key: {call_data_api_key}")
|
||||
|
||||
|
||||
def update_device_identifiers(hass: HomeAssistant, entry: ConfigEntry):
|
||||
"""Update device identifiers to new identifiers."""
|
||||
device_registry = async_get(hass)
|
||||
device_entry = device_registry.async_get_device({(DOMAIN, DOMAIN)})
|
||||
if device_entry and entry.entry_id in device_entry.config_entries:
|
||||
new_identifiers = {(DOMAIN, entry.entry_id)}
|
||||
_LOGGER.debug(
|
||||
"Updating device id <%s> with new identifiers <%s>",
|
||||
device_entry.id,
|
||||
new_identifiers,
|
||||
)
|
||||
device_registry.async_update_device(
|
||||
device_entry.id, new_identifiers=new_identifiers
|
||||
)
|
||||
|
||||
|
||||
async def migrate_unique_id(hass: HomeAssistant, entry: ConfigEntry):
|
||||
"""Migrate entities to new unique ids (with entry_id)."""
|
||||
|
||||
@callback
|
||||
def async_migrate_callback(entity_entry: RegistryEntry) -> dict | None:
|
||||
"""
|
||||
Define a callback to migrate appropriate SabnzbdSensor entities to new unique IDs.
|
||||
|
||||
Old: description.key
|
||||
New: {entry_id}_description.key
|
||||
"""
|
||||
entry_id = entity_entry.config_entry_id
|
||||
if entry_id is None:
|
||||
return None
|
||||
if entity_entry.unique_id.startswith(entry_id):
|
||||
return None
|
||||
|
||||
new_unique_id = f"{entry_id}_{entity_entry.unique_id}"
|
||||
|
||||
_LOGGER.debug(
|
||||
"Migrating entity %s from old unique ID '%s' to new unique ID '%s'",
|
||||
entity_entry.entity_id,
|
||||
entity_entry.unique_id,
|
||||
new_unique_id,
|
||||
)
|
||||
|
||||
return {"new_unique_id": new_unique_id}
|
||||
|
||||
await async_migrate_entries(hass, entry.entry_id, async_migrate_callback)
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up the SabNzbd Component."""
|
||||
|
||||
sab_api = await get_client(hass, entry.data)
|
||||
if not sab_api:
|
||||
raise ConfigEntryNotReady
|
||||
@ -137,6 +189,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
KEY_NAME: entry.data[CONF_NAME],
|
||||
}
|
||||
|
||||
await migrate_unique_id(hass, entry)
|
||||
update_device_identifiers(hass, entry)
|
||||
|
||||
@callback
|
||||
def extract_api(func: Callable) -> Callable:
|
||||
"""Define a decorator to get the correct api for a service call."""
|
||||
@ -188,6 +243,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
_LOGGER.error(err)
|
||||
|
||||
async_track_time_interval(hass, async_update_sabnzbd, UPDATE_INTERVAL)
|
||||
|
||||
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
|
||||
|
||||
return True
|
||||
|
@ -113,11 +113,16 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up a Sabnzbd sensor entry."""
|
||||
|
||||
sab_api_data = hass.data[DOMAIN][config_entry.entry_id][KEY_API_DATA]
|
||||
client_name = hass.data[DOMAIN][config_entry.entry_id][KEY_NAME]
|
||||
entry_id = config_entry.entry_id
|
||||
|
||||
sab_api_data = hass.data[DOMAIN][entry_id][KEY_API_DATA]
|
||||
client_name = hass.data[DOMAIN][entry_id][KEY_NAME]
|
||||
|
||||
async_add_entities(
|
||||
[SabnzbdSensor(sab_api_data, client_name, sensor) for sensor in SENSOR_TYPES]
|
||||
[
|
||||
SabnzbdSensor(sab_api_data, client_name, sensor, entry_id)
|
||||
for sensor in SENSOR_TYPES
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@ -128,17 +133,21 @@ class SabnzbdSensor(SensorEntity):
|
||||
_attr_should_poll = False
|
||||
|
||||
def __init__(
|
||||
self, sabnzbd_api_data, client_name, description: SabnzbdSensorEntityDescription
|
||||
self,
|
||||
sabnzbd_api_data,
|
||||
client_name,
|
||||
description: SabnzbdSensorEntityDescription,
|
||||
entry_id,
|
||||
):
|
||||
"""Initialize the sensor."""
|
||||
unique_id = description.key
|
||||
self._attr_unique_id = unique_id
|
||||
|
||||
self._attr_unique_id = f"{entry_id}_{description.key}"
|
||||
self.entity_description = description
|
||||
self._sabnzbd_api = sabnzbd_api_data
|
||||
self._attr_name = f"{client_name} {description.name}"
|
||||
self._attr_device_info = DeviceInfo(
|
||||
entry_type=DeviceEntryType.SERVICE,
|
||||
identifiers={(DOMAIN, DOMAIN)},
|
||||
identifiers={(DOMAIN, entry_id)},
|
||||
name=DEFAULT_NAME,
|
||||
)
|
||||
|
||||
@ -156,9 +165,11 @@ class SabnzbdSensor(SensorEntity):
|
||||
self.entity_description.key
|
||||
)
|
||||
|
||||
if self.entity_description.key == SPEED_KEY:
|
||||
self._attr_native_value = round(float(self._attr_native_value) / 1024, 1)
|
||||
elif "size" in self.entity_description.key:
|
||||
self._attr_native_value = round(float(self._attr_native_value), 2)
|
||||
|
||||
if self._attr_native_value is not None:
|
||||
if self.entity_description.key == SPEED_KEY:
|
||||
self._attr_native_value = round(
|
||||
float(self._attr_native_value) / 1024, 1
|
||||
)
|
||||
elif "size" in self.entity_description.key:
|
||||
self._attr_native_value = round(float(self._attr_native_value), 2)
|
||||
self.schedule_update_ha_state()
|
||||
|
@ -87,7 +87,6 @@ async def test_import_flow(hass) -> None:
|
||||
"homeassistant.components.sabnzbd.sab.SabnzbdApi.check_available",
|
||||
return_value=True,
|
||||
):
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": SOURCE_IMPORT},
|
||||
|
85
tests/components/sabnzbd/test_init.py
Normal file
85
tests/components/sabnzbd/test_init.py
Normal file
@ -0,0 +1,85 @@
|
||||
"""Tests for the SABnzbd Integration."""
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.sabnzbd import DEFAULT_NAME, DOMAIN, SENSOR_KEYS
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||
from homeassistant.const import CONF_API_KEY, CONF_NAME, CONF_URL
|
||||
from homeassistant.helpers.device_registry import DeviceEntryType
|
||||
|
||||
from tests.common import MockConfigEntry, mock_device_registry, mock_registry
|
||||
|
||||
MOCK_ENTRY_ID = "mock_entry_id"
|
||||
|
||||
MOCK_UNIQUE_ID = "someuniqueid"
|
||||
|
||||
MOCK_DEVICE_ID = "somedeviceid"
|
||||
|
||||
MOCK_DATA_VERSION_1 = {
|
||||
CONF_API_KEY: "api_key",
|
||||
CONF_URL: "http://127.0.0.1:8080",
|
||||
CONF_NAME: "name",
|
||||
}
|
||||
|
||||
MOCK_ENTRY_VERSION_1 = MockConfigEntry(
|
||||
domain=DOMAIN, data=MOCK_DATA_VERSION_1, entry_id=MOCK_ENTRY_ID, version=1
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def device_registry(hass):
|
||||
"""Return an empty, loaded, registry."""
|
||||
return mock_device_registry(hass)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def entity_registry(hass):
|
||||
"""Return an empty, loaded, registry."""
|
||||
return mock_registry(hass)
|
||||
|
||||
|
||||
async def test_unique_id_migrate(hass, device_registry, entity_registry):
|
||||
"""Test that config flow entry is migrated correctly."""
|
||||
# Start with the config entry at Version 1.
|
||||
mock_entry = MOCK_ENTRY_VERSION_1
|
||||
mock_entry.add_to_hass(hass)
|
||||
|
||||
mock_d_entry = device_registry.async_get_or_create(
|
||||
config_entry_id=mock_entry.entry_id,
|
||||
identifiers={(DOMAIN, DOMAIN)},
|
||||
name=DEFAULT_NAME,
|
||||
entry_type=DeviceEntryType.SERVICE,
|
||||
)
|
||||
|
||||
entity_id_sensor_key = []
|
||||
|
||||
for sensor_key in SENSOR_KEYS:
|
||||
mock_entity_id = f"{SENSOR_DOMAIN}.{DOMAIN}_{sensor_key}"
|
||||
entity_registry.async_get_or_create(
|
||||
SENSOR_DOMAIN,
|
||||
DOMAIN,
|
||||
unique_id=sensor_key,
|
||||
config_entry=mock_entry,
|
||||
device_id=mock_d_entry.id,
|
||||
)
|
||||
entity = entity_registry.async_get(mock_entity_id)
|
||||
assert entity.entity_id == mock_entity_id
|
||||
assert entity.unique_id == sensor_key
|
||||
entity_id_sensor_key.append((mock_entity_id, sensor_key))
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.sabnzbd.sab.SabnzbdApi.check_available",
|
||||
return_value=True,
|
||||
):
|
||||
await hass.config_entries.async_setup(mock_entry.entry_id)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
for mock_entity_id, sensor_key in entity_id_sensor_key:
|
||||
entity = entity_registry.async_get(mock_entity_id)
|
||||
assert entity.unique_id == f"{MOCK_ENTRY_ID}_{sensor_key}"
|
||||
|
||||
assert device_registry.async_get(mock_d_entry.id).identifiers == {
|
||||
(DOMAIN, MOCK_ENTRY_ID)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user