From 32104b7b1527c02836e9894f8a78ad8e71e4e0b3 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Wed, 9 Jul 2025 09:57:30 +0000 Subject: [PATCH] Add migration test --- .../scrape/snapshots/test_init.ambr | 112 +++++++++++++++ tests/components/scrape/test_init.py | 131 +++++++++++++++++- 2 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 tests/components/scrape/snapshots/test_init.ambr diff --git a/tests/components/scrape/snapshots/test_init.ambr b/tests/components/scrape/snapshots/test_init.ambr new file mode 100644 index 00000000000..a3613883f46 --- /dev/null +++ b/tests/components/scrape/snapshots/test_init.ambr @@ -0,0 +1,112 @@ +# serializer version: 1 +# name: test_migrate_from_version_1_to_2[config_entry] + ConfigEntrySnapshot({ + 'data': dict({ + }), + 'disabled_by': None, + 'discovery_keys': dict({ + }), + 'domain': 'scrape', + 'entry_id': , + 'minor_version': 1, + 'options': dict({ + 'advanced': dict({ + 'encoding': 'UTF-8', + 'timeout': 10.0, + 'verify_ssl': True, + }), + 'auth': dict({ + }), + 'method': 'GET', + 'resource': 'http://www.home-assistant.io', + }), + 'pref_disable_new_entities': False, + 'pref_disable_polling': False, + 'source': 'user', + 'subentries': list([ + dict({ + 'data': dict({ + 'advanced': dict({ + }), + 'index': 0, + 'select': '.release-date', + }), + 'subentry_id': '01JZQ1G63X2DX66GZ9ZTFY9PEH', + 'subentry_type': 'entity', + 'title': 'Current version', + 'unique_id': None, + }), + ]), + 'title': 'Mock Title', + 'unique_id': None, + 'version': 2, + }) +# --- +# name: test_migrate_from_version_1_to_2[device_registry] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': , + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'scrape', + '01JZQ1G63X2DX66GZ9ZTFY9PEH', + ), + }), + 'is_new': False, + 'labels': set({ + }), + 'manufacturer': 'Scrape', + 'model': None, + 'model_id': None, + 'name': 'Current version', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'suggested_area': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- +# name: test_migrate_from_version_1_to_2[entity_registry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.current_version', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Current version', + 'platform': 'scrape', + 'previous_unique_id': 'a0bde946-5c96-11f0-b55f-0242ac110002', + 'suggested_object_id': 'current_version', + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '01JZQ1G63X2DX66GZ9ZTFY9PEH', + 'unit_of_measurement': None, + }) +# --- diff --git a/tests/components/scrape/test_init.py b/tests/components/scrape/test_init.py index 363e30b9269..45d569841e4 100644 --- a/tests/components/scrape/test_init.py +++ b/tests/components/scrape/test_init.py @@ -2,12 +2,16 @@ from __future__ import annotations +from dataclasses import dataclass +from typing import Any from unittest.mock import patch import pytest +from syrupy.assertion import SnapshotAssertion from homeassistant.components.scrape.const import DEFAULT_SCAN_INTERVAL, DOMAIN -from homeassistant.config_entries import ConfigEntryState +from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN +from homeassistant.config_entries import SOURCE_USER, ConfigEntryState, ConfigSubentry from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.setup import async_setup_component @@ -152,3 +156,128 @@ async def test_device_remove_devices( ) response = await client.remove_device(dead_device_entry.id, loaded_entry.entry_id) assert response["success"] + + +async def test_migrate_from_future( + hass: HomeAssistant, + get_resource_config: dict[str, Any], + get_sensor_config: tuple[dict[str, Any], ...], + get_data: MockRestData, +) -> None: + """Test migration from future version fails.""" + config_entry = MockConfigEntry( + domain=DOMAIN, + source=SOURCE_USER, + options=get_resource_config, + entry_id="01JZN04ZJ9BQXXGXDS05WS7D6P", + subentries_data=get_sensor_config, + version=3, + ) + + config_entry.add_to_hass(hass) + + with patch( + "homeassistant.components.rest.RestData", + return_value=get_data, + ): + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + assert config_entry.state is ConfigEntryState.MIGRATION_ERROR + + +async def test_migrate_from_version_1_to_2( + hass: HomeAssistant, + get_data: MockRestData, + device_registry: dr.DeviceRegistry, + entity_registry: er.EntityRegistry, + snapshot: SnapshotAssertion, +) -> None: + """Test migration to config subentries.""" + + @dataclass(frozen=True, kw_only=True) + class MockConfigSubentry(ConfigSubentry): + """Container for a configuration subentry.""" + + subentry_id: str = "01JZQ1G63X2DX66GZ9ZTFY9PEH" + + config_entry = MockConfigEntry( + domain=DOMAIN, + source=SOURCE_USER, + options={ + "encoding": "UTF-8", + "method": "GET", + "resource": "http://www.home-assistant.io", + "sensor": [ + { + "index": 0, + "name": "Current version", + "select": ".release-date", + "unique_id": "a0bde946-5c96-11f0-b55f-0242ac110002", + } + ], + "timeout": 10.0, + "verify_ssl": True, + }, + entry_id="01JZN04ZJ9BQXXGXDS05WS7D6P", + version=1, + ) + config_entry.add_to_hass(hass) + device = device_registry.async_get_or_create( + config_entry_id=config_entry.entry_id, + entry_type=dr.DeviceEntryType.SERVICE, + identifiers={(DOMAIN, "a0bde946-5c96-11f0-b55f-0242ac110002")}, + manufacturer="Scrape", + name="Current version", + ) + entity_registry.async_get_or_create( + SENSOR_DOMAIN, + DOMAIN, + "a0bde946-5c96-11f0-b55f-0242ac110002", + config_entry=config_entry, + device_id=device.id, + original_name="Current version", + has_entity_name=True, + suggested_object_id="current_version", + ) + with ( + patch( + "homeassistant.components.rest.RestData", + return_value=get_data, + ), + patch("homeassistant.components.scrape.ConfigSubentry", MockConfigSubentry), + ): + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done(wait_background_tasks=True) + + assert config_entry.state is ConfigEntryState.LOADED + + assert hass.config_entries.async_get_entry(config_entry.entry_id) == snapshot( + name="config_entry" + ) + device = device_registry.async_get(device.id) + assert device == snapshot(name="device_registry") + entity = entity_registry.async_get("sensor.current_version") + assert entity == snapshot(name="entity_registry") + + assert config_entry.subentries == { + "01JZQ1G63X2DX66GZ9ZTFY9PEH": MockConfigSubentry( + data={ + "advanced": {}, + "index": 0, + "select": ".release-date", + }, + subentry_id="01JZQ1G63X2DX66GZ9ZTFY9PEH", + subentry_type="entity", + title="Current version", + unique_id=None, + ), + } + assert device.config_entries == {"01JZN04ZJ9BQXXGXDS05WS7D6P"} + assert device.config_entries_subentries == { + "01JZN04ZJ9BQXXGXDS05WS7D6P": { + "01JZQ1G63X2DX66GZ9ZTFY9PEH", + }, + } + assert entity.config_entry_id == config_entry.entry_id + assert entity.config_subentry_id == "01JZQ1G63X2DX66GZ9ZTFY9PEH"