Regenerate instance ID on error (#94898)
parent
2b1660c0f7
commit
609a573b55
|
@ -1,6 +1,7 @@
|
|||
"""Helper to create a unique instance ID."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import uuid
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
@ -12,17 +13,30 @@ DATA_VERSION = 1
|
|||
|
||||
LEGACY_UUID_FILE = ".uuid"
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@singleton.singleton(DATA_KEY)
|
||||
async def async_get(hass: HomeAssistant) -> str:
|
||||
"""Get unique ID for the hass instance."""
|
||||
store = storage.Store[dict[str, str]](hass, DATA_VERSION, DATA_KEY, True)
|
||||
|
||||
data: dict[str, str] | None = await storage.async_migrator(
|
||||
hass,
|
||||
hass.config.path(LEGACY_UUID_FILE),
|
||||
store,
|
||||
)
|
||||
data: dict[str, str] | None = None
|
||||
try:
|
||||
data = await storage.async_migrator(
|
||||
hass,
|
||||
hass.config.path(LEGACY_UUID_FILE),
|
||||
store,
|
||||
)
|
||||
except Exception: # pylint: disable=broad-exception-caught
|
||||
_LOGGER.exception(
|
||||
(
|
||||
"Could not read hass instance ID from '%s' or '%s', a new instance ID "
|
||||
"will be generated"
|
||||
),
|
||||
DATA_KEY,
|
||||
LEGACY_UUID_FILE,
|
||||
)
|
||||
|
||||
if data is not None:
|
||||
return data["uuid"]
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
"""Tests for instance ID helper."""
|
||||
from json import JSONDecodeError
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import instance_id
|
||||
|
||||
|
@ -14,6 +17,25 @@ async def test_get_id_empty(hass: HomeAssistant, hass_storage: dict[str, Any]) -
|
|||
assert hass_storage["core.uuid"]["data"]["uuid"] == uuid
|
||||
|
||||
|
||||
async def test_get_id_load_fail(
|
||||
hass: HomeAssistant, hass_storage: dict[str, Any], caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Migrate existing file with error."""
|
||||
hass_storage["core.uuid"] = None # Invalid, will make store.async_load raise
|
||||
|
||||
uuid = await instance_id.async_get(hass)
|
||||
|
||||
assert uuid is not None
|
||||
|
||||
# Assert it's stored
|
||||
assert hass_storage["core.uuid"]["data"]["uuid"] == uuid
|
||||
|
||||
assert (
|
||||
"Could not read hass instance ID from 'core.uuid' or '.uuid', a "
|
||||
"new instance ID will be generated" in caplog.text
|
||||
)
|
||||
|
||||
|
||||
async def test_get_id_migrate(
|
||||
hass: HomeAssistant, hass_storage: dict[str, Any]
|
||||
) -> None:
|
||||
|
@ -30,3 +52,27 @@ async def test_get_id_migrate(
|
|||
|
||||
# assert old deleted
|
||||
assert len(mock_remove.mock_calls) == 1
|
||||
|
||||
|
||||
async def test_get_id_migrate_fail(
|
||||
hass: HomeAssistant, hass_storage: dict[str, Any], caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Migrate existing file with error."""
|
||||
with patch(
|
||||
"homeassistant.util.json.load_json",
|
||||
side_effect=JSONDecodeError("test_error", "test", 1),
|
||||
), patch("os.path.isfile", return_value=True), patch("os.remove") as mock_remove:
|
||||
uuid = await instance_id.async_get(hass)
|
||||
|
||||
assert uuid is not None
|
||||
|
||||
# Assert it's stored
|
||||
assert hass_storage["core.uuid"]["data"]["uuid"] == uuid
|
||||
|
||||
# assert old not deleted
|
||||
assert len(mock_remove.mock_calls) == 0
|
||||
|
||||
assert (
|
||||
"Could not read hass instance ID from 'core.uuid' or '.uuid', a "
|
||||
"new instance ID will be generated" in caplog.text
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue