Add created_at/modified_at to config entries (#122456)

pull/122808/head
Robert Resch 2024-07-29 22:08:46 +02:00 committed by GitHub
parent 20c4f84a4e
commit ad50136dbd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
67 changed files with 440 additions and 392 deletions

View File

@ -15,6 +15,7 @@ from collections.abc import (
) )
from contextvars import ContextVar from contextvars import ContextVar
from copy import deepcopy from copy import deepcopy
from datetime import datetime
from enum import Enum, StrEnum from enum import Enum, StrEnum
import functools import functools
from functools import cached_property from functools import cached_property
@ -69,6 +70,7 @@ from .setup import (
from .util import ulid as ulid_util from .util import ulid as ulid_util
from .util.async_ import create_eager_task from .util.async_ import create_eager_task
from .util.decorator import Registry from .util.decorator import Registry
from .util.dt import utc_from_timestamp, utcnow
from .util.enum import try_parse_enum from .util.enum import try_parse_enum
if TYPE_CHECKING: if TYPE_CHECKING:
@ -118,7 +120,7 @@ HANDLERS: Registry[str, type[ConfigFlow]] = Registry()
STORAGE_KEY = "core.config_entries" STORAGE_KEY = "core.config_entries"
STORAGE_VERSION = 1 STORAGE_VERSION = 1
STORAGE_VERSION_MINOR = 2 STORAGE_VERSION_MINOR = 3
SAVE_DELAY = 1 SAVE_DELAY = 1
@ -303,15 +305,19 @@ class ConfigEntry(Generic[_DataT]):
_background_tasks: set[asyncio.Future[Any]] _background_tasks: set[asyncio.Future[Any]]
_integration_for_domain: loader.Integration | None _integration_for_domain: loader.Integration | None
_tries: int _tries: int
created_at: datetime
modified_at: datetime
def __init__( def __init__(
self, self,
*, *,
created_at: datetime | None = None,
data: Mapping[str, Any], data: Mapping[str, Any],
disabled_by: ConfigEntryDisabler | None = None, disabled_by: ConfigEntryDisabler | None = None,
domain: str, domain: str,
entry_id: str | None = None, entry_id: str | None = None,
minor_version: int, minor_version: int,
modified_at: datetime | None = None,
options: Mapping[str, Any] | None, options: Mapping[str, Any] | None,
pref_disable_new_entities: bool | None = None, pref_disable_new_entities: bool | None = None,
pref_disable_polling: bool | None = None, pref_disable_polling: bool | None = None,
@ -415,6 +421,8 @@ class ConfigEntry(Generic[_DataT]):
_setter(self, "_integration_for_domain", None) _setter(self, "_integration_for_domain", None)
_setter(self, "_tries", 0) _setter(self, "_tries", 0)
_setter(self, "created_at", created_at or utcnow())
_setter(self, "modified_at", modified_at or utcnow())
def __repr__(self) -> str: def __repr__(self) -> str:
"""Representation of ConfigEntry.""" """Representation of ConfigEntry."""
@ -483,8 +491,10 @@ class ConfigEntry(Generic[_DataT]):
def as_json_fragment(self) -> json_fragment: def as_json_fragment(self) -> json_fragment:
"""Return JSON fragment of a config entry.""" """Return JSON fragment of a config entry."""
json_repr = { json_repr = {
"created_at": self.created_at.timestamp(),
"entry_id": self.entry_id, "entry_id": self.entry_id,
"domain": self.domain, "domain": self.domain,
"modified_at": self.modified_at.timestamp(),
"title": self.title, "title": self.title,
"source": self.source, "source": self.source,
"state": self.state.value, "state": self.state.value,
@ -831,6 +841,10 @@ class ConfigEntry(Generic[_DataT]):
async def async_remove(self, hass: HomeAssistant) -> None: async def async_remove(self, hass: HomeAssistant) -> None:
"""Invoke remove callback on component.""" """Invoke remove callback on component."""
old_modified_at = self.modified_at
object.__setattr__(self, "modified_at", utcnow())
self.clear_cache()
if self.source == SOURCE_IGNORE: if self.source == SOURCE_IGNORE:
return return
@ -862,6 +876,8 @@ class ConfigEntry(Generic[_DataT]):
self.title, self.title,
integration.domain, integration.domain,
) )
# Restore modified_at
object.__setattr__(self, "modified_at", old_modified_at)
@callback @callback
def _async_set_state( def _async_set_state(
@ -950,11 +966,13 @@ class ConfigEntry(Generic[_DataT]):
def as_dict(self) -> dict[str, Any]: def as_dict(self) -> dict[str, Any]:
"""Return dictionary version of this entry.""" """Return dictionary version of this entry."""
return { return {
"created_at": self.created_at.isoformat(),
"data": dict(self.data), "data": dict(self.data),
"disabled_by": self.disabled_by, "disabled_by": self.disabled_by,
"domain": self.domain, "domain": self.domain,
"entry_id": self.entry_id, "entry_id": self.entry_id,
"minor_version": self.minor_version, "minor_version": self.minor_version,
"modified_at": self.modified_at.isoformat(),
"options": dict(self.options), "options": dict(self.options),
"pref_disable_new_entities": self.pref_disable_new_entities, "pref_disable_new_entities": self.pref_disable_new_entities,
"pref_disable_polling": self.pref_disable_polling, "pref_disable_polling": self.pref_disable_polling,
@ -1599,25 +1617,34 @@ class ConfigEntryStore(storage.Store[dict[str, list[dict[str, Any]]]]):
) -> dict[str, Any]: ) -> dict[str, Any]:
"""Migrate to the new version.""" """Migrate to the new version."""
data = old_data data = old_data
if old_major_version == 1 and old_minor_version < 2: if old_major_version == 1:
# Version 1.2 implements migration and freezes the available keys if old_minor_version < 2:
for entry in data["entries"]: # Version 1.2 implements migration and freezes the available keys
# Populate keys which were introduced before version 1.2 for entry in data["entries"]:
# Populate keys which were introduced before version 1.2
pref_disable_new_entities = entry.get("pref_disable_new_entities") pref_disable_new_entities = entry.get("pref_disable_new_entities")
if pref_disable_new_entities is None and "system_options" in entry: if pref_disable_new_entities is None and "system_options" in entry:
pref_disable_new_entities = entry.get("system_options", {}).get( pref_disable_new_entities = entry.get("system_options", {}).get(
"disable_new_entities" "disable_new_entities"
)
entry.setdefault("disabled_by", entry.get("disabled_by"))
entry.setdefault("minor_version", entry.get("minor_version", 1))
entry.setdefault("options", entry.get("options", {}))
entry.setdefault(
"pref_disable_new_entities", pref_disable_new_entities
) )
entry.setdefault(
"pref_disable_polling", entry.get("pref_disable_polling")
)
entry.setdefault("unique_id", entry.get("unique_id"))
entry.setdefault("disabled_by", entry.get("disabled_by")) if old_minor_version < 3:
entry.setdefault("minor_version", entry.get("minor_version", 1)) # Version 1.3 adds the created_at and modified_at fields
entry.setdefault("options", entry.get("options", {})) created_at = utc_from_timestamp(0).isoformat()
entry.setdefault("pref_disable_new_entities", pref_disable_new_entities) for entry in data["entries"]:
entry.setdefault( entry["created_at"] = entry["modified_at"] = created_at
"pref_disable_polling", entry.get("pref_disable_polling")
)
entry.setdefault("unique_id", entry.get("unique_id"))
if old_major_version > 1: if old_major_version > 1:
raise NotImplementedError raise NotImplementedError
@ -1793,11 +1820,13 @@ class ConfigEntries:
entry_id = entry["entry_id"] entry_id = entry["entry_id"]
config_entry = ConfigEntry( config_entry = ConfigEntry(
created_at=datetime.fromisoformat(entry["created_at"]),
data=entry["data"], data=entry["data"],
disabled_by=try_parse_enum(ConfigEntryDisabler, entry["disabled_by"]), disabled_by=try_parse_enum(ConfigEntryDisabler, entry["disabled_by"]),
domain=entry["domain"], domain=entry["domain"],
entry_id=entry_id, entry_id=entry_id,
minor_version=entry["minor_version"], minor_version=entry["minor_version"],
modified_at=datetime.fromisoformat(entry["modified_at"]),
options=entry["options"], options=entry["options"],
pref_disable_new_entities=entry["pref_disable_new_entities"], pref_disable_new_entities=entry["pref_disable_new_entities"],
pref_disable_polling=entry["pref_disable_polling"], pref_disable_polling=entry["pref_disable_polling"],
@ -2014,6 +2043,8 @@ class ConfigEntries:
if not changed: if not changed:
return False return False
_setter(entry, "modified_at", utcnow())
for listener in entry.update_listeners: for listener in entry.update_listeners:
self.hass.async_create_task( self.hass.async_create_task(
listener(self.hass, entry), listener(self.hass, entry),

View File

@ -4,6 +4,7 @@ from unittest.mock import patch
import pytest import pytest
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.components.aemet.const import DOMAIN from homeassistant.components.aemet.const import DOMAIN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -30,4 +31,4 @@ async def test_config_entry_diagnostics(
return_value={}, return_value={},
): ):
result = await get_diagnostics_for_config_entry(hass, hass_client, config_entry) result = await get_diagnostics_for_config_entry(hass, hass_client, config_entry)
assert result == snapshot assert result == snapshot(exclude=props("created_at", "modified_at"))

View File

@ -1,6 +1,7 @@
"""Test Airly diagnostics.""" """Test Airly diagnostics."""
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -22,4 +23,4 @@ async def test_entry_diagnostics(
result = await get_diagnostics_for_config_entry(hass, hass_client, entry) result = await get_diagnostics_for_config_entry(hass, hass_client, entry)
assert result == snapshot assert result == snapshot(exclude=props("created_at", "modified_at"))

View File

@ -4,6 +4,7 @@ from unittest.mock import patch
import pytest import pytest
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -27,7 +28,6 @@ async def test_entry_diagnostics(
return_value="PST", return_value="PST",
): ):
assert await hass.config_entries.async_setup(config_entry.entry_id) assert await hass.config_entries.async_setup(config_entry.entry_id)
assert ( assert await get_diagnostics_for_config_entry(
await get_diagnostics_for_config_entry(hass, hass_client, config_entry) hass, hass_client, config_entry
== snapshot ) == snapshot(exclude=props("created_at", "modified_at"))
)

View File

@ -1,6 +1,7 @@
"""Test AirVisual diagnostics.""" """Test AirVisual diagnostics."""
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -16,7 +17,6 @@ async def test_entry_diagnostics(
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
) -> None: ) -> None:
"""Test config entry diagnostics.""" """Test config entry diagnostics."""
assert ( assert await get_diagnostics_for_config_entry(
await get_diagnostics_for_config_entry(hass, hass_client, config_entry) hass, hass_client, config_entry
== snapshot ) == snapshot(exclude=props("created_at", "modified_at"))
)

View File

@ -1,6 +1,7 @@
"""Test AirVisual Pro diagnostics.""" """Test AirVisual Pro diagnostics."""
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -16,7 +17,6 @@ async def test_entry_diagnostics(
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
) -> None: ) -> None:
"""Test config entry diagnostics.""" """Test config entry diagnostics."""
assert ( assert await get_diagnostics_for_config_entry(
await get_diagnostics_for_config_entry(hass, hass_client, config_entry) hass, hass_client, config_entry
== snapshot ) == snapshot(exclude=props("created_at", "modified_at"))
)

View File

@ -4,6 +4,7 @@ from unittest.mock import patch
from aioairzone.const import RAW_HVAC, RAW_VERSION, RAW_WEBSERVER from aioairzone.const import RAW_HVAC, RAW_VERSION, RAW_WEBSERVER
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.components.airzone.const import DOMAIN from homeassistant.components.airzone.const import DOMAIN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -37,4 +38,4 @@ async def test_config_entry_diagnostics(
}, },
): ):
result = await get_diagnostics_for_config_entry(hass, hass_client, config_entry) result = await get_diagnostics_for_config_entry(hass, hass_client, config_entry)
assert result == snapshot assert result == snapshot(exclude=props("created_at", "modified_at"))

View File

@ -15,6 +15,7 @@ from aioairzone_cloud.const import (
RAW_WEBSERVERS, RAW_WEBSERVERS,
) )
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.components.airzone_cloud.const import DOMAIN from homeassistant.components.airzone_cloud.const import DOMAIN
from homeassistant.const import CONF_ID from homeassistant.const import CONF_ID
@ -111,4 +112,4 @@ async def test_config_entry_diagnostics(
return_value=RAW_DATA_MOCK, return_value=RAW_DATA_MOCK,
): ):
result = await get_diagnostics_for_config_entry(hass, hass_client, config_entry) result = await get_diagnostics_for_config_entry(hass, hass_client, config_entry)
assert result == snapshot assert result == snapshot(exclude=props("created_at", "modified_at"))

View File

@ -1,6 +1,7 @@
"""Test Ambient PWS diagnostics.""" """Test Ambient PWS diagnostics."""
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.components.ambient_station import AmbientStationConfigEntry from homeassistant.components.ambient_station import AmbientStationConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -20,7 +21,6 @@ async def test_entry_diagnostics(
"""Test config entry diagnostics.""" """Test config entry diagnostics."""
ambient = config_entry.runtime_data ambient = config_entry.runtime_data
ambient.stations = data_station ambient.stations = data_station
assert ( assert await get_diagnostics_for_config_entry(
await get_diagnostics_for_config_entry(hass, hass_client, config_entry) hass, hass_client, config_entry
== snapshot ) == snapshot(exclude=props("created_at", "modified_at"))
)

View File

@ -2,6 +2,7 @@
import pytest import pytest
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -20,7 +21,6 @@ async def test_entry_diagnostics(
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
) -> None: ) -> None:
"""Test config entry diagnostics.""" """Test config entry diagnostics."""
assert ( assert await get_diagnostics_for_config_entry(
await get_diagnostics_for_config_entry(hass, hass_client, config_entry_setup) hass, hass_client, config_entry_setup
== snapshot ) == snapshot(exclude=props("created_at", "modified_at"))
)

View File

@ -31,4 +31,4 @@ async def test_entry_diagnostics(
hass, hass_client, mock_config_entry hass, hass_client, mock_config_entry
) )
assert result == snapshot(exclude=props("entry_id")) assert result == snapshot(exclude=props("entry_id", "created_at", "modified_at"))

View File

@ -3,6 +3,7 @@
from unittest.mock import patch from unittest.mock import patch
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.components.braviatv.const import CONF_USE_PSK, DOMAIN from homeassistant.components.braviatv.const import CONF_USE_PSK, DOMAIN
from homeassistant.const import CONF_HOST, CONF_MAC, CONF_PIN from homeassistant.const import CONF_HOST, CONF_MAC, CONF_PIN
@ -71,4 +72,4 @@ async def test_entry_diagnostics(
assert await async_setup_component(hass, DOMAIN, {}) assert await async_setup_component(hass, DOMAIN, {})
result = await get_diagnostics_for_config_entry(hass, hass_client, config_entry) result = await get_diagnostics_for_config_entry(hass, hass_client, config_entry)
assert result == snapshot assert result == snapshot(exclude=props("created_at", "modified_at"))

View File

@ -2,6 +2,7 @@
import pytest import pytest
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -20,4 +21,4 @@ async def test_entry_diagnostics(
"""Test config entry diagnostics.""" """Test config entry diagnostics."""
result = await get_diagnostics_for_config_entry(hass, hass_client, config_entry) result = await get_diagnostics_for_config_entry(hass, hass_client, config_entry)
assert result == snapshot assert result == snapshot(exclude=props("created_at", "modified_at"))

View File

@ -3,6 +3,7 @@
from unittest.mock import patch from unittest.mock import patch
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -40,4 +41,4 @@ async def test_entry_diagnostics(
result = await get_diagnostics_for_config_entry(hass, hass_client, config_entry) result = await get_diagnostics_for_config_entry(hass, hass_client, config_entry)
assert result == snapshot assert result == snapshot(exclude=props("created_at", "modified_at"))

View File

@ -6,6 +6,7 @@ from http import HTTPStatus
from unittest.mock import ANY, AsyncMock, patch from unittest.mock import ANY, AsyncMock, patch
from aiohttp.test_utils import TestClient from aiohttp.test_utils import TestClient
from freezegun.api import FrozenDateTimeFactory
import pytest import pytest
import voluptuous as vol import voluptuous as vol
@ -18,6 +19,7 @@ from homeassistant.data_entry_flow import FlowResultType
from homeassistant.helpers import config_entry_flow, config_validation as cv from homeassistant.helpers import config_entry_flow, config_validation as cv
from homeassistant.loader import IntegrationNotFound from homeassistant.loader import IntegrationNotFound
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from homeassistant.util.dt import utcnow
from tests.common import ( from tests.common import (
MockConfigEntry, MockConfigEntry,
@ -69,6 +71,7 @@ def mock_flow() -> Generator[None]:
yield yield
@pytest.mark.usefixtures("freezer")
@pytest.mark.usefixtures("clear_handlers", "mock_flow") @pytest.mark.usefixtures("clear_handlers", "mock_flow")
async def test_get_entries(hass: HomeAssistant, client: TestClient) -> None: async def test_get_entries(hass: HomeAssistant, client: TestClient) -> None:
"""Test get entries.""" """Test get entries."""
@ -124,12 +127,15 @@ async def test_get_entries(hass: HomeAssistant, client: TestClient) -> None:
data = await resp.json() data = await resp.json()
for entry in data: for entry in data:
entry.pop("entry_id") entry.pop("entry_id")
timestamp = utcnow().timestamp()
assert data == [ assert data == [
{ {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "comp1", "domain": "comp1",
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -142,10 +148,12 @@ async def test_get_entries(hass: HomeAssistant, client: TestClient) -> None:
"title": "Test 1", "title": "Test 1",
}, },
{ {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "comp2", "domain": "comp2",
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": "Unsupported API", "reason": "Unsupported API",
@ -158,10 +166,12 @@ async def test_get_entries(hass: HomeAssistant, client: TestClient) -> None:
"title": "Test 2", "title": "Test 2",
}, },
{ {
"created_at": timestamp,
"disabled_by": core_ce.ConfigEntryDisabler.USER, "disabled_by": core_ce.ConfigEntryDisabler.USER,
"domain": "comp3", "domain": "comp3",
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -174,10 +184,12 @@ async def test_get_entries(hass: HomeAssistant, client: TestClient) -> None:
"title": "Test 3", "title": "Test 3",
}, },
{ {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "comp4", "domain": "comp4",
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -190,10 +202,12 @@ async def test_get_entries(hass: HomeAssistant, client: TestClient) -> None:
"title": "Test 4", "title": "Test 4",
}, },
{ {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "comp5", "domain": "comp5",
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -509,7 +523,7 @@ async def test_abort(hass: HomeAssistant, client: TestClient) -> None:
} }
@pytest.mark.usefixtures("enable_custom_integrations") @pytest.mark.usefixtures("enable_custom_integrations", "freezer")
async def test_create_account(hass: HomeAssistant, client: TestClient) -> None: async def test_create_account(hass: HomeAssistant, client: TestClient) -> None:
"""Test a flow that creates an account.""" """Test a flow that creates an account."""
mock_platform(hass, "test.config_flow", None) mock_platform(hass, "test.config_flow", None)
@ -536,6 +550,7 @@ async def test_create_account(hass: HomeAssistant, client: TestClient) -> None:
entries = hass.config_entries.async_entries("test") entries = hass.config_entries.async_entries("test")
assert len(entries) == 1 assert len(entries) == 1
timestamp = utcnow().timestamp()
data = await resp.json() data = await resp.json()
data.pop("flow_id") data.pop("flow_id")
assert data == { assert data == {
@ -544,11 +559,13 @@ async def test_create_account(hass: HomeAssistant, client: TestClient) -> None:
"type": "create_entry", "type": "create_entry",
"version": 1, "version": 1,
"result": { "result": {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "test", "domain": "test",
"entry_id": entries[0].entry_id, "entry_id": entries[0].entry_id,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -567,7 +584,7 @@ async def test_create_account(hass: HomeAssistant, client: TestClient) -> None:
} }
@pytest.mark.usefixtures("enable_custom_integrations") @pytest.mark.usefixtures("enable_custom_integrations", "freezer")
async def test_two_step_flow(hass: HomeAssistant, client: TestClient) -> None: async def test_two_step_flow(hass: HomeAssistant, client: TestClient) -> None:
"""Test we can finish a two step flow.""" """Test we can finish a two step flow."""
mock_integration( mock_integration(
@ -616,6 +633,7 @@ async def test_two_step_flow(hass: HomeAssistant, client: TestClient) -> None:
entries = hass.config_entries.async_entries("test") entries = hass.config_entries.async_entries("test")
assert len(entries) == 1 assert len(entries) == 1
timestamp = utcnow().timestamp()
data = await resp.json() data = await resp.json()
data.pop("flow_id") data.pop("flow_id")
assert data == { assert data == {
@ -624,11 +642,13 @@ async def test_two_step_flow(hass: HomeAssistant, client: TestClient) -> None:
"title": "user-title", "title": "user-title",
"version": 1, "version": 1,
"result": { "result": {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "test", "domain": "test",
"entry_id": entries[0].entry_id, "entry_id": entries[0].entry_id,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1059,6 +1079,7 @@ async def test_options_flow_with_invalid_data(
assert data == {"errors": {"choices": "invalid is not a valid option"}} assert data == {"errors": {"choices": "invalid is not a valid option"}}
@pytest.mark.usefixtures("freezer")
async def test_get_single( async def test_get_single(
hass: HomeAssistant, hass_ws_client: WebSocketGenerator hass: HomeAssistant, hass_ws_client: WebSocketGenerator
) -> None: ) -> None:
@ -1080,13 +1101,16 @@ async def test_get_single(
) )
response = await ws_client.receive_json() response = await ws_client.receive_json()
timestamp = utcnow().timestamp()
assert response["success"] assert response["success"]
assert response["result"]["config_entry"] == { assert response["result"]["config_entry"] == {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "test", "domain": "test",
"entry_id": entry.entry_id, "entry_id": entry.entry_id,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1366,7 +1390,7 @@ async def test_ignore_flow_nonexisting(
assert response["error"]["code"] == "not_found" assert response["error"]["code"] == "not_found"
@pytest.mark.usefixtures("clear_handlers") @pytest.mark.usefixtures("clear_handlers", "freezer")
async def test_get_matching_entries_ws( async def test_get_matching_entries_ws(
hass: HomeAssistant, hass_ws_client: WebSocketGenerator hass: HomeAssistant, hass_ws_client: WebSocketGenerator
) -> None: ) -> None:
@ -1420,13 +1444,16 @@ async def test_get_matching_entries_ws(
await ws_client.send_json_auto_id({"type": "config_entries/get"}) await ws_client.send_json_auto_id({"type": "config_entries/get"})
response = await ws_client.receive_json() response = await ws_client.receive_json()
timestamp = utcnow().timestamp()
assert response["result"] == [ assert response["result"] == [
{ {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "comp1", "domain": "comp1",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1439,11 +1466,13 @@ async def test_get_matching_entries_ws(
"title": "Test 1", "title": "Test 1",
}, },
{ {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "comp2", "domain": "comp2",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": "Unsupported API", "reason": "Unsupported API",
@ -1456,11 +1485,13 @@ async def test_get_matching_entries_ws(
"title": "Test 2", "title": "Test 2",
}, },
{ {
"created_at": timestamp,
"disabled_by": "user", "disabled_by": "user",
"domain": "comp3", "domain": "comp3",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1473,11 +1504,13 @@ async def test_get_matching_entries_ws(
"title": "Test 3", "title": "Test 3",
}, },
{ {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "comp4", "domain": "comp4",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1490,11 +1523,13 @@ async def test_get_matching_entries_ws(
"title": "Test 4", "title": "Test 4",
}, },
{ {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "comp5", "domain": "comp5",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1518,11 +1553,13 @@ async def test_get_matching_entries_ws(
response = await ws_client.receive_json() response = await ws_client.receive_json()
assert response["result"] == [ assert response["result"] == [
{ {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "comp1", "domain": "comp1",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1545,11 +1582,13 @@ async def test_get_matching_entries_ws(
response = await ws_client.receive_json() response = await ws_client.receive_json()
assert response["result"] == [ assert response["result"] == [
{ {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "comp4", "domain": "comp4",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1562,11 +1601,13 @@ async def test_get_matching_entries_ws(
"title": "Test 4", "title": "Test 4",
}, },
{ {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "comp5", "domain": "comp5",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1589,11 +1630,13 @@ async def test_get_matching_entries_ws(
response = await ws_client.receive_json() response = await ws_client.receive_json()
assert response["result"] == [ assert response["result"] == [
{ {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "comp1", "domain": "comp1",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1606,11 +1649,13 @@ async def test_get_matching_entries_ws(
"title": "Test 1", "title": "Test 1",
}, },
{ {
"created_at": timestamp,
"disabled_by": "user", "disabled_by": "user",
"domain": "comp3", "domain": "comp3",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1639,11 +1684,13 @@ async def test_get_matching_entries_ws(
assert response["result"] == [ assert response["result"] == [
{ {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "comp1", "domain": "comp1",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1656,11 +1703,13 @@ async def test_get_matching_entries_ws(
"title": "Test 1", "title": "Test 1",
}, },
{ {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "comp2", "domain": "comp2",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": "Unsupported API", "reason": "Unsupported API",
@ -1673,11 +1722,13 @@ async def test_get_matching_entries_ws(
"title": "Test 2", "title": "Test 2",
}, },
{ {
"created_at": timestamp,
"disabled_by": "user", "disabled_by": "user",
"domain": "comp3", "domain": "comp3",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1690,11 +1741,13 @@ async def test_get_matching_entries_ws(
"title": "Test 3", "title": "Test 3",
}, },
{ {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "comp4", "domain": "comp4",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1707,11 +1760,13 @@ async def test_get_matching_entries_ws(
"title": "Test 4", "title": "Test 4",
}, },
{ {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "comp5", "domain": "comp5",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1759,7 +1814,9 @@ async def test_get_matching_entries_ws(
@pytest.mark.usefixtures("clear_handlers") @pytest.mark.usefixtures("clear_handlers")
async def test_subscribe_entries_ws( async def test_subscribe_entries_ws(
hass: HomeAssistant, hass_ws_client: WebSocketGenerator hass: HomeAssistant,
hass_ws_client: WebSocketGenerator,
freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test subscribe entries with the websocket api.""" """Test subscribe entries with the websocket api."""
assert await async_setup_component(hass, "config", {}) assert await async_setup_component(hass, "config", {})
@ -1805,15 +1862,18 @@ async def test_subscribe_entries_ws(
assert response["type"] == "result" assert response["type"] == "result"
response = await ws_client.receive_json() response = await ws_client.receive_json()
assert response["id"] == 5 assert response["id"] == 5
created = utcnow().timestamp()
assert response["event"] == [ assert response["event"] == [
{ {
"type": None, "type": None,
"entry": { "entry": {
"created_at": created,
"disabled_by": None, "disabled_by": None,
"domain": "comp1", "domain": "comp1",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": created,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1829,11 +1889,13 @@ async def test_subscribe_entries_ws(
{ {
"type": None, "type": None,
"entry": { "entry": {
"created_at": created,
"disabled_by": None, "disabled_by": None,
"domain": "comp2", "domain": "comp2",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": created,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": "Unsupported API", "reason": "Unsupported API",
@ -1849,11 +1911,13 @@ async def test_subscribe_entries_ws(
{ {
"type": None, "type": None,
"entry": { "entry": {
"created_at": created,
"disabled_by": "user", "disabled_by": "user",
"domain": "comp3", "domain": "comp3",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": created,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1867,17 +1931,21 @@ async def test_subscribe_entries_ws(
}, },
}, },
] ]
freezer.tick()
modified = utcnow().timestamp()
assert hass.config_entries.async_update_entry(entry, title="changed") assert hass.config_entries.async_update_entry(entry, title="changed")
response = await ws_client.receive_json() response = await ws_client.receive_json()
assert response["id"] == 5 assert response["id"] == 5
assert response["event"] == [ assert response["event"] == [
{ {
"entry": { "entry": {
"created_at": created,
"disabled_by": None, "disabled_by": None,
"domain": "comp1", "domain": "comp1",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": modified,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1892,17 +1960,21 @@ async def test_subscribe_entries_ws(
"type": "updated", "type": "updated",
} }
] ]
freezer.tick()
modified = utcnow().timestamp()
await hass.config_entries.async_remove(entry.entry_id) await hass.config_entries.async_remove(entry.entry_id)
response = await ws_client.receive_json() response = await ws_client.receive_json()
assert response["id"] == 5 assert response["id"] == 5
assert response["event"] == [ assert response["event"] == [
{ {
"entry": { "entry": {
"created_at": created,
"disabled_by": None, "disabled_by": None,
"domain": "comp1", "domain": "comp1",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": modified,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1917,17 +1989,20 @@ async def test_subscribe_entries_ws(
"type": "removed", "type": "removed",
} }
] ]
freezer.tick()
await hass.config_entries.async_add(entry) await hass.config_entries.async_add(entry)
response = await ws_client.receive_json() response = await ws_client.receive_json()
assert response["id"] == 5 assert response["id"] == 5
assert response["event"] == [ assert response["event"] == [
{ {
"entry": { "entry": {
"created_at": entry.created_at.timestamp(),
"disabled_by": None, "disabled_by": None,
"domain": "comp1", "domain": "comp1",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": entry.modified_at.timestamp(),
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -1946,9 +2021,12 @@ async def test_subscribe_entries_ws(
@pytest.mark.usefixtures("clear_handlers") @pytest.mark.usefixtures("clear_handlers")
async def test_subscribe_entries_ws_filtered( async def test_subscribe_entries_ws_filtered(
hass: HomeAssistant, hass_ws_client: WebSocketGenerator hass: HomeAssistant,
hass_ws_client: WebSocketGenerator,
freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test subscribe entries with the websocket api with a type filter.""" """Test subscribe entries with the websocket api with a type filter."""
created = utcnow().timestamp()
assert await async_setup_component(hass, "config", {}) assert await async_setup_component(hass, "config", {})
mock_integration(hass, MockModule("comp1")) mock_integration(hass, MockModule("comp1"))
mock_integration( mock_integration(
@ -2008,11 +2086,13 @@ async def test_subscribe_entries_ws_filtered(
{ {
"type": None, "type": None,
"entry": { "entry": {
"created_at": created,
"disabled_by": None, "disabled_by": None,
"domain": "comp1", "domain": "comp1",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": created,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -2028,11 +2108,13 @@ async def test_subscribe_entries_ws_filtered(
{ {
"type": None, "type": None,
"entry": { "entry": {
"created_at": created,
"disabled_by": "user", "disabled_by": "user",
"domain": "comp3", "domain": "comp3",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": created,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -2046,6 +2128,8 @@ async def test_subscribe_entries_ws_filtered(
}, },
}, },
] ]
freezer.tick()
modified = utcnow().timestamp()
assert hass.config_entries.async_update_entry(entry, title="changed") assert hass.config_entries.async_update_entry(entry, title="changed")
assert hass.config_entries.async_update_entry(entry3, title="changed too") assert hass.config_entries.async_update_entry(entry3, title="changed too")
assert hass.config_entries.async_update_entry(entry4, title="changed but ignored") assert hass.config_entries.async_update_entry(entry4, title="changed but ignored")
@ -2054,11 +2138,13 @@ async def test_subscribe_entries_ws_filtered(
assert response["event"] == [ assert response["event"] == [
{ {
"entry": { "entry": {
"created_at": created,
"disabled_by": None, "disabled_by": None,
"domain": "comp1", "domain": "comp1",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": modified,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -2078,11 +2164,13 @@ async def test_subscribe_entries_ws_filtered(
assert response["event"] == [ assert response["event"] == [
{ {
"entry": { "entry": {
"created_at": created,
"disabled_by": "user", "disabled_by": "user",
"domain": "comp3", "domain": "comp3",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": modified,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -2097,6 +2185,8 @@ async def test_subscribe_entries_ws_filtered(
"type": "updated", "type": "updated",
} }
] ]
freezer.tick()
modified = utcnow().timestamp()
await hass.config_entries.async_remove(entry.entry_id) await hass.config_entries.async_remove(entry.entry_id)
await hass.config_entries.async_remove(entry2.entry_id) await hass.config_entries.async_remove(entry2.entry_id)
response = await ws_client.receive_json() response = await ws_client.receive_json()
@ -2104,11 +2194,13 @@ async def test_subscribe_entries_ws_filtered(
assert response["event"] == [ assert response["event"] == [
{ {
"entry": { "entry": {
"created_at": created,
"disabled_by": None, "disabled_by": None,
"domain": "comp1", "domain": "comp1",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": modified,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -2123,17 +2215,20 @@ async def test_subscribe_entries_ws_filtered(
"type": "removed", "type": "removed",
} }
] ]
freezer.tick()
await hass.config_entries.async_add(entry) await hass.config_entries.async_add(entry)
response = await ws_client.receive_json() response = await ws_client.receive_json()
assert response["id"] == 5 assert response["id"] == 5
assert response["event"] == [ assert response["event"] == [
{ {
"entry": { "entry": {
"created_at": entry.created_at.timestamp(),
"disabled_by": None, "disabled_by": None,
"domain": "comp1", "domain": "comp1",
"entry_id": ANY, "entry_id": ANY,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": entry.modified_at.timestamp(),
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,
@ -2238,8 +2333,11 @@ async def test_flow_with_multiple_schema_errors_base(
} }
@pytest.mark.usefixtures("enable_custom_integrations") @pytest.mark.usefixtures("enable_custom_integrations", "freezer")
async def test_supports_reconfigure(hass: HomeAssistant, client: TestClient) -> None: async def test_supports_reconfigure(
hass: HomeAssistant,
client: TestClient,
) -> None:
"""Test a flow that support reconfigure step.""" """Test a flow that support reconfigure step."""
mock_platform(hass, "test.config_flow", None) mock_platform(hass, "test.config_flow", None)
@ -2297,6 +2395,7 @@ async def test_supports_reconfigure(hass: HomeAssistant, client: TestClient) ->
assert len(entries) == 1 assert len(entries) == 1
data = await resp.json() data = await resp.json()
timestamp = utcnow().timestamp()
data.pop("flow_id") data.pop("flow_id")
assert data == { assert data == {
"handler": "test", "handler": "test",
@ -2304,11 +2403,13 @@ async def test_supports_reconfigure(hass: HomeAssistant, client: TestClient) ->
"type": "create_entry", "type": "create_entry",
"version": 1, "version": 1,
"result": { "result": {
"created_at": timestamp,
"disabled_by": None, "disabled_by": None,
"domain": "test", "domain": "test",
"entry_id": entries[0].entry_id, "entry_id": entries[0].entry_id,
"error_reason_translation_key": None, "error_reason_translation_key": None,
"error_reason_translation_placeholders": None, "error_reason_translation_placeholders": None,
"modified_at": timestamp,
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
"reason": None, "reason": None,

View File

@ -2,6 +2,7 @@
from pydeconz.websocket import State from pydeconz.websocket import State
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -23,7 +24,6 @@ async def test_entry_diagnostics(
await mock_websocket_state(State.RUNNING) await mock_websocket_state(State.RUNNING)
await hass.async_block_till_done() await hass.async_block_till_done()
assert ( assert await get_diagnostics_for_config_entry(
await get_diagnostics_for_config_entry(hass, hass_client, config_entry_setup) hass, hass_client, config_entry_setup
== snapshot ) == snapshot(exclude=props("created_at", "modified_at"))
)

View File

@ -5,6 +5,7 @@ from __future__ import annotations
from unittest.mock import patch from unittest.mock import patch
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from syrupy.filters import props
from homeassistant.config_entries import ConfigEntryState from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -35,4 +36,4 @@ async def test_entry_diagnostics(
assert entry.state is ConfigEntryState.LOADED assert entry.state is ConfigEntryState.LOADED
result = await get_diagnostics_for_config_entry(hass, hass_client, entry) result = await get_diagnostics_for_config_entry(hass, hass_client, entry)
assert result == snapshot assert result == snapshot(exclude=props("created_at", "modified_at"))

View File

@ -4,6 +4,7 @@ from __future__ import annotations
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from syrupy.filters import props
from homeassistant.config_entries import ConfigEntryState from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -28,4 +29,4 @@ async def test_entry_diagnostics(
assert entry.state is ConfigEntryState.LOADED assert entry.state is ConfigEntryState.LOADED
result = await get_diagnostics_for_config_entry(hass, hass_client, entry) result = await get_diagnostics_for_config_entry(hass, hass_client, entry)
assert result == snapshot assert result == snapshot(exclude=props("created_at", "modified_at"))

View File

@ -3,6 +3,7 @@
from unittest.mock import patch from unittest.mock import patch
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.components.dsmr_reader.const import DOMAIN from homeassistant.components.dsmr_reader.const import DOMAIN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -36,4 +37,4 @@ async def test_get_config_entry_diagnostics(
diagnostics = await get_diagnostics_for_config_entry( diagnostics = await get_diagnostics_for_config_entry(
hass, hass_client, config_entry hass, hass_client, config_entry
) )
assert diagnostics == snapshot assert diagnostics == snapshot(exclude=props("created_at", "modified_at"))

View File

@ -28,4 +28,4 @@ async def test_diagnostics(
"""Test diagnostics.""" """Test diagnostics."""
assert await get_diagnostics_for_config_entry( assert await get_diagnostics_for_config_entry(
hass, hass_client, init_integration hass, hass_client, init_integration
) == snapshot(exclude=props("entry_id")) ) == snapshot(exclude=props("entry_id", "created_at", "modified_at"))

View File

@ -5,6 +5,7 @@ from unittest.mock import ANY
import pytest import pytest
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.components import bluetooth from homeassistant.components import bluetooth
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -27,7 +28,7 @@ async def test_diagnostics(
"""Test diagnostics for config entry.""" """Test diagnostics for config entry."""
result = await get_diagnostics_for_config_entry(hass, hass_client, init_integration) result = await get_diagnostics_for_config_entry(hass, hass_client, init_integration)
assert result == snapshot assert result == snapshot(exclude=props("created_at", "modified_at"))
async def test_diagnostics_with_bluetooth( async def test_diagnostics_with_bluetooth(
@ -61,6 +62,7 @@ async def test_diagnostics_with_bluetooth(
}, },
}, },
"config": { "config": {
"created_at": ANY,
"data": { "data": {
"device_name": "test", "device_name": "test",
"host": "test.local", "host": "test.local",
@ -71,6 +73,7 @@ async def test_diagnostics_with_bluetooth(
"domain": "esphome", "domain": "esphome",
"entry_id": ANY, "entry_id": ANY,
"minor_version": 1, "minor_version": 1,
"modified_at": ANY,
"options": {"allow_service_calls": False}, "options": {"allow_service_calls": False},
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,

View File

@ -1,6 +1,7 @@
"""Tests for the diagnostics data provided by the Fronius integration.""" """Tests for the diagnostics data provided by the Fronius integration."""
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -21,11 +22,8 @@ async def test_diagnostics(
mock_responses(aioclient_mock) mock_responses(aioclient_mock)
entry = await setup_fronius_integration(hass) entry = await setup_fronius_integration(hass)
assert ( assert await get_diagnostics_for_config_entry(
await get_diagnostics_for_config_entry( hass,
hass, hass_client,
hass_client, entry,
entry, ) == snapshot(exclude=props("created_at", "modified_at"))
)
== snapshot
)

View File

@ -3,6 +3,7 @@
from unittest.mock import AsyncMock from unittest.mock import AsyncMock
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.const import Platform from homeassistant.const import Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -28,4 +29,4 @@ async def test_entry_diagnostics(
hass, hass_client, mock_config_entry hass, hass_client, mock_config_entry
) )
assert result == snapshot assert result == snapshot(exclude=props("created_at", "modified_at"))

View File

@ -1,6 +1,7 @@
"""Test GIOS diagnostics.""" """Test GIOS diagnostics."""
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -18,4 +19,6 @@ async def test_entry_diagnostics(
"""Test config entry diagnostics.""" """Test config entry diagnostics."""
entry = await init_integration(hass) entry = await init_integration(hass)
assert await get_diagnostics_for_config_entry(hass, hass_client, entry) == snapshot assert await get_diagnostics_for_config_entry(hass, hass_client, entry) == snapshot(
exclude=props("created_at", "modified_at")
)

View File

@ -3,6 +3,7 @@
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.components.goodwe import CONF_MODEL_FAMILY, DOMAIN from homeassistant.components.goodwe import CONF_MODEL_FAMILY, DOMAIN
from homeassistant.const import CONF_HOST from homeassistant.const import CONF_HOST
@ -32,4 +33,4 @@ async def test_entry_diagnostics(
assert await async_setup_component(hass, DOMAIN, {}) assert await async_setup_component(hass, DOMAIN, {})
result = await get_diagnostics_for_config_entry(hass, hass_client, config_entry) result = await get_diagnostics_for_config_entry(hass, hass_client, config_entry)
assert result == snapshot assert result == snapshot(exclude=props("created_at", "modified_at"))

View File

@ -50,4 +50,4 @@ async def test_diagnostics(
config_entry = hass.config_entries.async_entries("google_assistant")[0] config_entry = hass.config_entries.async_entries("google_assistant")[0]
assert await get_diagnostics_for_config_entry( assert await get_diagnostics_for_config_entry(
hass, hass_client, config_entry hass, hass_client, config_entry
) == snapshot(exclude=props("entry_id")) ) == snapshot(exclude=props("entry_id", "created_at", "modified_at"))

View File

@ -4,7 +4,7 @@ from homeassistant.components.diagnostics import REDACTED
from homeassistant.components.guardian import DOMAIN, GuardianData from homeassistant.components.guardian import DOMAIN, GuardianData
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry from tests.common import ANY, MockConfigEntry
from tests.components.diagnostics import get_diagnostics_for_config_entry from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator from tests.typing import ClientSessionGenerator
@ -39,6 +39,8 @@ async def test_entry_diagnostics(
"source": "user", "source": "user",
"unique_id": REDACTED, "unique_id": REDACTED,
"disabled_by": None, "disabled_by": None,
"created_at": ANY,
"modified_at": ANY,
}, },
"data": { "data": {
"valve_controller": { "valve_controller": {

View File

@ -5,6 +5,7 @@ from unittest.mock import AsyncMock
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from syrupy.filters import props
from homeassistant.components.husqvarna_automower.const import DOMAIN from homeassistant.components.husqvarna_automower.const import DOMAIN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -36,7 +37,7 @@ async def test_entry_diagnostics(
result = await get_diagnostics_for_config_entry( result = await get_diagnostics_for_config_entry(
hass, hass_client, mock_config_entry hass, hass_client, mock_config_entry
) )
assert result == snapshot assert result == snapshot(exclude=props("created_at", "modified_at"))
@pytest.mark.freeze_time(datetime.datetime(2024, 2, 29, 11, tzinfo=datetime.UTC)) @pytest.mark.freeze_time(datetime.datetime(2024, 2, 29, 11, tzinfo=datetime.UTC))

View File

@ -28,4 +28,4 @@ async def test_entry_diagnostics(
hass, hass_client, mock_config_entry hass, hass_client, mock_config_entry
) )
assert result == snapshot(exclude=props("entry_id")) assert result == snapshot(exclude=props("entry_id", "created_at", "modified_at"))

View File

@ -1,6 +1,7 @@
"""Test IQVIA diagnostics.""" """Test IQVIA diagnostics."""
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -18,7 +19,6 @@ async def test_entry_diagnostics(
) -> None: ) -> None:
"""Test config entry diagnostics.""" """Test config entry diagnostics."""
assert ( assert await get_diagnostics_for_config_entry(
await get_diagnostics_for_config_entry(hass, hass_client, config_entry) hass, hass_client, config_entry
== snapshot ) == snapshot(exclude=props("created_at", "modified_at"))
)

View File

@ -6,7 +6,7 @@ from homeassistant.components.diagnostics import REDACTED
from homeassistant.components.kostal_plenticore.coordinator import Plenticore from homeassistant.components.kostal_plenticore.coordinator import Plenticore
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry from tests.common import ANY, MockConfigEntry
from tests.components.diagnostics import get_diagnostics_for_config_entry from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator from tests.typing import ClientSessionGenerator
@ -54,6 +54,8 @@ async def test_entry_diagnostics(
"source": "user", "source": "user",
"unique_id": None, "unique_id": None,
"disabled_by": None, "disabled_by": None,
"created_at": ANY,
"modified_at": ANY,
}, },
"client": { "client": {
"version": "api_version='0.2.0' hostname='scb' name='PUCK RESTful API' sw_version='01.16.05025'", "version": "api_version='0.2.0' hostname='scb' name='PUCK RESTful API' sw_version='01.16.05025'",

View File

@ -3,6 +3,7 @@
from unittest.mock import patch from unittest.mock import patch
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from syrupy.filters import props
from homeassistant.components.lacrosse_view import DOMAIN from homeassistant.components.lacrosse_view import DOMAIN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -32,7 +33,6 @@ async def test_entry_diagnostics(
assert await hass.config_entries.async_setup(config_entry.entry_id) assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
assert ( assert await get_diagnostics_for_config_entry(
await get_diagnostics_for_config_entry(hass, hass_client, config_entry) hass, hass_client, config_entry
== snapshot ) == snapshot(exclude=props("created_at", "modified_at"))
)

View File

@ -3,6 +3,7 @@
from unittest.mock import AsyncMock from unittest.mock import AsyncMock
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -25,4 +26,4 @@ async def test_entry_diagnostics(
result = await get_diagnostics_for_config_entry( result = await get_diagnostics_for_config_entry(
hass, hass_client, mock_config_entry hass, hass_client, mock_config_entry
) )
assert result == snapshot assert result == snapshot(exclude=props("created_at", "modified_at"))

View File

@ -3,6 +3,7 @@
from unittest.mock import patch from unittest.mock import patch
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.components.melcloud.const import DOMAIN from homeassistant.components.melcloud.const import DOMAIN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -36,4 +37,4 @@ async def test_get_config_entry_diagnostics(
diagnostics = await get_diagnostics_for_config_entry( diagnostics = await get_diagnostics_for_config_entry(
hass, hass_client, config_entry hass, hass_client, config_entry
) )
assert diagnostics == snapshot assert diagnostics == snapshot(exclude=props("created_at", "modified_at"))

View File

@ -42,4 +42,11 @@ async def test_entry_diagnostics(
assert await get_diagnostics_for_config_entry( assert await get_diagnostics_for_config_entry(
hass, hass_client, config_entry hass, hass_client, config_entry
) == snapshot(exclude=paths("info.data.token.expires_at", "info.entry_id")) ) == snapshot(
exclude=paths(
"info.data.token.expires_at",
"info.entry_id",
"info.created_at",
"info.modified_at",
)
)

View File

@ -1,6 +1,7 @@
"""Test NextDNS diagnostics.""" """Test NextDNS diagnostics."""
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -18,4 +19,6 @@ async def test_entry_diagnostics(
"""Test config entry diagnostics.""" """Test config entry diagnostics."""
entry = await init_integration(hass) entry = await init_integration(hass)
assert await get_diagnostics_for_config_entry(hass, hass_client, entry) == snapshot assert await get_diagnostics_for_config_entry(hass, hass_client, entry) == snapshot(
exclude=props("created_at", "modified_at")
)

View File

@ -4,6 +4,7 @@ from homeassistant.components.diagnostics import REDACTED
from homeassistant.components.notion import DOMAIN from homeassistant.components.notion import DOMAIN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from tests.common import ANY
from tests.components.diagnostics import get_diagnostics_for_config_entry from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator from tests.typing import ClientSessionGenerator
@ -33,6 +34,8 @@ async def test_entry_diagnostics(
"source": "user", "source": "user",
"unique_id": REDACTED, "unique_id": REDACTED,
"disabled_by": None, "disabled_by": None,
"created_at": ANY,
"modified_at": ANY,
}, },
"data": { "data": {
"bridges": [ "bridges": [

View File

@ -1,6 +1,7 @@
"""Test ONVIF diagnostics.""" """Test ONVIF diagnostics."""
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -19,4 +20,6 @@ async def test_diagnostics(
entry, _, _ = await setup_onvif_integration(hass) entry, _, _ = await setup_onvif_integration(hass)
assert await get_diagnostics_for_config_entry(hass, hass_client, entry) == snapshot assert await get_diagnostics_for_config_entry(hass, hass_client, entry) == snapshot(
exclude=props("created_at", "modified_at")
)

View File

@ -4,6 +4,7 @@ from homeassistant.components.diagnostics import REDACTED
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from tests.common import ANY
from tests.components.diagnostics import get_diagnostics_for_config_entry from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator from tests.typing import ClientSessionGenerator
@ -35,6 +36,8 @@ async def test_entry_diagnostics(
"source": "user", "source": "user",
"unique_id": REDACTED, "unique_id": REDACTED,
"disabled_by": None, "disabled_by": None,
"created_at": ANY,
"modified_at": ANY,
}, },
"data": { "data": {
"protection_window": { "protection_window": {

View File

@ -63,4 +63,4 @@ async def test_entry_diagnostics(
hass, hass_client, mock_config_entry hass, hass_client, mock_config_entry
) )
assert result == snapshot(exclude=props("entry_id")) assert result == snapshot(exclude=props("entry_id", "created_at", "modified_at"))

View File

@ -1,6 +1,7 @@
"""Test pi_hole component.""" """Test pi_hole component."""
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from syrupy.filters import props
from homeassistant.components import pi_hole from homeassistant.components import pi_hole
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -28,4 +29,6 @@ async def test_diagnostics(
await hass.async_block_till_done() await hass.async_block_till_done()
assert await get_diagnostics_for_config_entry(hass, hass_client, entry) == snapshot assert await get_diagnostics_for_config_entry(hass, hass_client, entry) == snapshot(
exclude=props("created_at", "modified_at")
)

View File

@ -72,5 +72,12 @@ async def test_entry_diagnostics(
assert await get_diagnostics_for_config_entry( assert await get_diagnostics_for_config_entry(
hass, hass_client, mock_entry hass, hass_client, mock_entry
) == snapshot( ) == snapshot(
exclude=props("entry_id", "last_changed", "last_reported", "last_updated") exclude=props(
"entry_id",
"last_changed",
"last_reported",
"last_updated",
"created_at",
"modified_at",
)
) )

View File

@ -3,6 +3,7 @@
from homeassistant.components.diagnostics import REDACTED from homeassistant.components.diagnostics import REDACTED
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from tests.common import ANY
from tests.components.diagnostics import get_diagnostics_for_config_entry from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator from tests.typing import ClientSessionGenerator
@ -34,6 +35,8 @@ async def test_entry_diagnostics(
"source": "user", "source": "user",
"unique_id": REDACTED, "unique_id": REDACTED,
"disabled_by": None, "disabled_by": None,
"created_at": ANY,
"modified_at": ANY,
}, },
"data": { "data": {
"fields": [ "fields": [

View File

@ -2,6 +2,7 @@
from regenmaschine.errors import RainMachineError from regenmaschine.errors import RainMachineError
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -17,10 +18,9 @@ async def test_entry_diagnostics(
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
) -> None: ) -> None:
"""Test config entry diagnostics.""" """Test config entry diagnostics."""
assert ( assert await get_diagnostics_for_config_entry(
await get_diagnostics_for_config_entry(hass, hass_client, config_entry) hass, hass_client, config_entry
== snapshot ) == snapshot(exclude=props("created_at", "modified_at"))
)
async def test_entry_diagnostics_failed_controller_diagnostics( async def test_entry_diagnostics_failed_controller_diagnostics(
@ -33,7 +33,6 @@ async def test_entry_diagnostics_failed_controller_diagnostics(
) -> None: ) -> None:
"""Test config entry diagnostics when the controller diagnostics API call fails.""" """Test config entry diagnostics when the controller diagnostics API call fails."""
controller.diagnostics.current.side_effect = RainMachineError controller.diagnostics.current.side_effect = RainMachineError
assert ( assert await get_diagnostics_for_config_entry(
await get_diagnostics_for_config_entry(hass, hass_client, config_entry) hass, hass_client, config_entry
== snapshot ) == snapshot(exclude=props("created_at", "modified_at"))
)

View File

@ -5,6 +5,7 @@ from homeassistant.core import HomeAssistant
from .conftest import TEST_SERVICE_ID from .conftest import TEST_SERVICE_ID
from tests.common import ANY
from tests.components.diagnostics import get_diagnostics_for_config_entry from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator from tests.typing import ClientSessionGenerator
@ -30,6 +31,8 @@ async def test_entry_diagnostics(
"source": "user", "source": "user",
"unique_id": REDACTED, "unique_id": REDACTED,
"disabled_by": None, "disabled_by": None,
"created_at": ANY,
"modified_at": ANY,
}, },
"data": [ "data": [
{ {

View File

@ -1,6 +1,7 @@
"""Test Ridwell diagnostics.""" """Test Ridwell diagnostics."""
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -16,7 +17,6 @@ async def test_entry_diagnostics(
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
) -> None: ) -> None:
"""Test config entry diagnostics.""" """Test config entry diagnostics."""
assert ( assert await get_diagnostics_for_config_entry(
await get_diagnostics_for_config_entry(hass, hass_client, config_entry) hass, hass_client, config_entry
== snapshot ) == snapshot(exclude=props("created_at", "modified_at"))
)

View File

@ -16,6 +16,7 @@ from .const import (
SAMPLE_DEVICE_INFO_WIFI, SAMPLE_DEVICE_INFO_WIFI,
) )
from tests.common import ANY
from tests.components.diagnostics import get_diagnostics_for_config_entry from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator from tests.typing import ClientSessionGenerator
@ -29,6 +30,7 @@ async def test_entry_diagnostics(
assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == { assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == {
"entry": { "entry": {
"created_at": ANY,
"data": { "data": {
"host": "fake_host", "host": "fake_host",
"ip_address": "test", "ip_address": "test",
@ -43,6 +45,7 @@ async def test_entry_diagnostics(
"domain": "samsungtv", "domain": "samsungtv",
"entry_id": "123456", "entry_id": "123456",
"minor_version": 2, "minor_version": 2,
"modified_at": ANY,
"options": {}, "options": {},
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
@ -65,6 +68,7 @@ async def test_entry_diagnostics_encrypted(
assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == { assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == {
"entry": { "entry": {
"created_at": ANY,
"data": { "data": {
"host": "fake_host", "host": "fake_host",
"ip_address": "test", "ip_address": "test",
@ -80,6 +84,7 @@ async def test_entry_diagnostics_encrypted(
"domain": "samsungtv", "domain": "samsungtv",
"entry_id": "123456", "entry_id": "123456",
"minor_version": 2, "minor_version": 2,
"modified_at": ANY,
"options": {}, "options": {},
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,
@ -102,6 +107,7 @@ async def test_entry_diagnostics_encrypte_offline(
assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == { assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == {
"entry": { "entry": {
"created_at": ANY,
"data": { "data": {
"host": "fake_host", "host": "fake_host",
"ip_address": "test", "ip_address": "test",
@ -116,6 +122,7 @@ async def test_entry_diagnostics_encrypte_offline(
"domain": "samsungtv", "domain": "samsungtv",
"entry_id": "123456", "entry_id": "123456",
"minor_version": 2, "minor_version": 2,
"modified_at": ANY,
"options": {}, "options": {},
"pref_disable_new_entities": False, "pref_disable_new_entities": False,
"pref_disable_polling": False, "pref_disable_polling": False,

View File

@ -4,6 +4,7 @@ from unittest.mock import DEFAULT, patch
from screenlogicpy import ScreenLogicGateway from screenlogicpy import ScreenLogicGateway
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr from homeassistant.helpers import device_registry as dr
@ -56,4 +57,4 @@ async def test_diagnostics(
hass, hass_client, mock_config_entry hass, hass_client, mock_config_entry
) )
assert diag == snapshot assert diag == snapshot(exclude=props("created_at", "modified_at"))

View File

@ -1,246 +1,5 @@
# serializer version: 1 # serializer version: 1
# name: test_diagnostics # name: test_diagnostics
dict({
'modes': dict({
'auto': dict({
'fanLevels': list([
'quiet',
'low',
'medium',
]),
'horizontalSwing': list([
'stopped',
'fixedLeft',
'fixedCenterLeft',
]),
'light': list([
'on',
'off',
]),
'swing': list([
'stopped',
'fixedTop',
'fixedMiddleTop',
]),
'temperatures': dict({
'C': dict({
'isNative': True,
'values': list([
10,
16,
17,
18,
19,
20,
]),
}),
'F': dict({
'isNative': False,
'values': list([
64,
66,
68,
]),
}),
}),
}),
'cool': dict({
'fanLevels': list([
'quiet',
'low',
'medium',
]),
'horizontalSwing': list([
'stopped',
'fixedLeft',
'fixedCenterLeft',
]),
'light': list([
'on',
'off',
]),
'swing': list([
'stopped',
'fixedTop',
'fixedMiddleTop',
]),
'temperatures': dict({
'C': dict({
'isNative': True,
'values': list([
10,
16,
17,
18,
19,
20,
]),
}),
'F': dict({
'isNative': False,
'values': list([
64,
66,
68,
]),
}),
}),
}),
'dry': dict({
'horizontalSwing': list([
'stopped',
'fixedLeft',
'fixedCenterLeft',
]),
'light': list([
'on',
'off',
]),
'swing': list([
'stopped',
'fixedTop',
'fixedMiddleTop',
]),
'temperatures': dict({
'C': dict({
'isNative': True,
'values': list([
10,
16,
17,
18,
19,
20,
]),
}),
'F': dict({
'isNative': False,
'values': list([
64,
66,
68,
]),
}),
}),
}),
'fan': dict({
'fanLevels': list([
'quiet',
'low',
'medium',
]),
'horizontalSwing': list([
'stopped',
'fixedLeft',
'fixedCenterLeft',
]),
'light': list([
'on',
'off',
]),
'swing': list([
'stopped',
'fixedTop',
'fixedMiddleTop',
]),
'temperatures': dict({
}),
}),
'heat': dict({
'fanLevels': list([
'quiet',
'low',
'medium',
]),
'horizontalSwing': list([
'stopped',
'fixedLeft',
'fixedCenterLeft',
]),
'light': list([
'on',
'off',
]),
'swing': list([
'stopped',
'fixedTop',
'fixedMiddleTop',
]),
'temperatures': dict({
'C': dict({
'isNative': True,
'values': list([
10,
16,
17,
18,
19,
20,
]),
}),
'F': dict({
'isNative': False,
'values': list([
63,
64,
66,
]),
}),
}),
}),
}),
})
# ---
# name: test_diagnostics.1
dict({
'low': 'low',
'medium': 'medium',
'quiet': 'quiet',
})
# ---
# name: test_diagnostics.2
dict({
'fixedmiddletop': 'fixedMiddleTop',
'fixedtop': 'fixedTop',
'stopped': 'stopped',
})
# ---
# name: test_diagnostics.3
dict({
'fixedcenterleft': 'fixedCenterLeft',
'fixedleft': 'fixedLeft',
'stopped': 'stopped',
})
# ---
# name: test_diagnostics.4
dict({
'fanlevel': 'low',
'horizontalswing': 'stopped',
'light': 'on',
'mode': 'heat',
'on': True,
'swing': 'stopped',
'targettemperature': 21,
'temperatureunit': 'c',
})
# ---
# name: test_diagnostics.5
dict({
'fanlevel': 'high',
'horizontalswing': 'stopped',
'light': 'on',
'mode': 'cool',
'on': True,
'swing': 'stopped',
'targettemperature': 21,
'temperatureunit': 'c',
})
# ---
# name: test_diagnostics.6
dict({
})
# ---
# name: test_diagnostics[full_snapshot]
dict({ dict({
'AAZZAAZZ': dict({ 'AAZZAAZZ': dict({
'ac_states': dict({ 'ac_states': dict({

View File

@ -3,6 +3,7 @@
from __future__ import annotations from __future__ import annotations
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from syrupy.filters import props
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -10,8 +11,6 @@ from homeassistant.core import HomeAssistant
from tests.components.diagnostics import get_diagnostics_for_config_entry from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator from tests.typing import ClientSessionGenerator
EXCLUDE_ATTRIBUTES = {"full_features"}
async def test_diagnostics( async def test_diagnostics(
hass: HomeAssistant, hass: HomeAssistant,
@ -24,16 +23,6 @@ async def test_diagnostics(
diag = await get_diagnostics_for_config_entry(hass, hass_client, entry) diag = await get_diagnostics_for_config_entry(hass, hass_client, entry)
assert diag["ABC999111"]["full_capabilities"] == snapshot assert diag == snapshot(
assert diag["ABC999111"]["fan_modes_translated"] == snapshot exclude=props("full_features", "created_at", "modified_at"),
assert diag["ABC999111"]["swing_modes_translated"] == snapshot )
assert diag["ABC999111"]["horizontal_swing_modes_translated"] == snapshot
assert diag["ABC999111"]["smart_low_state"] == snapshot
assert diag["ABC999111"]["smart_high_state"] == snapshot
assert diag["ABC999111"]["pure_conf"] == snapshot
def limit_attrs(prop, path):
exclude_attrs = EXCLUDE_ATTRIBUTES
return prop in exclude_attrs
assert diag == snapshot(name="full_snapshot", exclude=limit_attrs)

View File

@ -3,6 +3,7 @@
from homeassistant.components.diagnostics import REDACTED from homeassistant.components.diagnostics import REDACTED
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from tests.common import ANY
from tests.components.diagnostics import get_diagnostics_for_config_entry from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator from tests.typing import ClientSessionGenerator
@ -28,6 +29,8 @@ async def test_entry_diagnostics(
"source": "user", "source": "user",
"unique_id": REDACTED, "unique_id": REDACTED,
"disabled_by": None, "disabled_by": None,
"created_at": ANY,
"modified_at": ANY,
}, },
"subscription_data": { "subscription_data": {
"12345": { "12345": {

View File

@ -8,6 +8,7 @@ from homeassistant.core import HomeAssistant
from . import init_integration from . import init_integration
from .consts import DUMMY_WATER_HEATER_DEVICE from .consts import DUMMY_WATER_HEATER_DEVICE
from tests.common import ANY
from tests.components.diagnostics import get_diagnostics_for_config_entry from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator from tests.typing import ClientSessionGenerator
@ -64,5 +65,7 @@ async def test_diagnostics(
"source": "user", "source": "user",
"unique_id": "switcher_kis", "unique_id": "switcher_kis",
"disabled_by": None, "disabled_by": None,
"created_at": ANY,
"modified_at": ANY,
}, },
} }

View File

@ -23,4 +23,4 @@ async def test_diagnostics(
"""Test diagnostics.""" """Test diagnostics."""
assert await get_diagnostics_for_config_entry( assert await get_diagnostics_for_config_entry(
hass, hass_client, mock_added_config_entry hass, hass_client, mock_added_config_entry
) == snapshot(exclude=props("last_update", "entry_id")) ) == snapshot(exclude=props("last_update", "entry_id", "created_at", "modified_at"))

View File

@ -4,6 +4,7 @@ from __future__ import annotations
import pytest import pytest
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -21,4 +22,4 @@ async def test_entry_diagnostics(
) -> None: ) -> None:
"""Test config entry diagnostics.""" """Test config entry diagnostics."""
result = await get_diagnostics_for_config_entry(hass, hass_client, config_entry) result = await get_diagnostics_for_config_entry(hass, hass_client, config_entry)
assert result == snapshot assert result == snapshot(exclude=props("created_at", "modified_at"))

View File

@ -3,6 +3,7 @@
from unittest.mock import AsyncMock from unittest.mock import AsyncMock
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -27,4 +28,4 @@ async def test_entry_diagnostics(
hass, hass_client, mock_config_entry hass, hass_client, mock_config_entry
) )
assert result == snapshot assert result == snapshot(exclude=props("created_at", "modified_at"))

View File

@ -3,6 +3,7 @@
from collections.abc import Awaitable, Callable from collections.abc import Awaitable, Callable
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -26,4 +27,6 @@ async def test_diagnostics(
await setup_integration() await setup_integration()
entry = hass.config_entries.async_entries(DOMAIN)[0] entry = hass.config_entries.async_entries(DOMAIN)[0]
assert await get_diagnostics_for_config_entry(hass, hass_client, entry) == snapshot assert await get_diagnostics_for_config_entry(hass, hass_client, entry) == snapshot(
exclude=props("created_at", "modified_at")
)

View File

@ -2,6 +2,7 @@
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from syrupy.filters import props
from homeassistant.components.unifi.const import ( from homeassistant.components.unifi.const import (
CONF_ALLOW_BANDWIDTH_SENSORS, CONF_ALLOW_BANDWIDTH_SENSORS,
@ -125,7 +126,6 @@ async def test_entry_diagnostics(
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
) -> None: ) -> None:
"""Test config entry diagnostics.""" """Test config entry diagnostics."""
assert ( assert await get_diagnostics_for_config_entry(
await get_diagnostics_for_config_entry(hass, hass_client, config_entry_setup) hass, hass_client, config_entry_setup
== snapshot ) == snapshot(exclude=props("created_at", "modified_at"))
)

View File

@ -4,6 +4,7 @@ from aiohttp.test_utils import TestClient
from freezegun import freeze_time from freezegun import freeze_time
import pytest import pytest
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.auth.models import Credentials from homeassistant.auth.models import Credentials
from homeassistant.components.utility_meter.const import DOMAIN from homeassistant.components.utility_meter.const import DOMAIN
@ -45,11 +46,6 @@ def _get_test_client_generator(
return auth_client return auth_client
def limit_diagnostic_attrs(prop, path) -> bool:
"""Mark attributes to exclude from diagnostic snapshot."""
return prop in {"entry_id"}
@freeze_time("2024-04-06 00:00:00+00:00") @freeze_time("2024-04-06 00:00:00+00:00")
@pytest.mark.usefixtures("socket_enabled") @pytest.mark.usefixtures("socket_enabled")
async def test_diagnostics( async def test_diagnostics(
@ -125,4 +121,4 @@ async def test_diagnostics(
hass, _get_test_client_generator(hass, aiohttp_client, new_token), config_entry hass, _get_test_client_generator(hass, aiohttp_client, new_token), config_entry
) )
assert diag == snapshot(exclude=limit_diagnostic_attrs) assert diag == snapshot(exclude=props("entry_id", "created_at", "modified_at"))

View File

@ -3,6 +3,7 @@
from unittest.mock import AsyncMock from unittest.mock import AsyncMock
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -24,7 +25,6 @@ async def test_entry_diagnostics(
await init_integration(hass, mock_config_entry) await init_integration(hass, mock_config_entry)
assert ( assert await get_diagnostics_for_config_entry(
await get_diagnostics_for_config_entry(hass, hass_client, mock_config_entry) hass, hass_client, mock_config_entry
== snapshot() ) == snapshot(exclude=props("created_at", "modified_at"))
)

View File

@ -3,6 +3,7 @@
from unittest.mock import MagicMock from unittest.mock import MagicMock
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -21,4 +22,4 @@ async def test_diagnostics(
hass, hass_client, mock_vicare_gas_boiler hass, hass_client, mock_vicare_gas_boiler
) )
assert diag == snapshot assert diag == snapshot(exclude=props("created_at", "modified_at"))

View File

@ -19,4 +19,4 @@ async def test_entry_diagnostics(
"""Test config entry diagnostics.""" """Test config entry diagnostics."""
assert await get_diagnostics_for_config_entry( assert await get_diagnostics_for_config_entry(
hass, hass_client, config_entry hass, hass_client, config_entry
) == snapshot(exclude=props("entry_id")) ) == snapshot(exclude=props("entry_id", "created_at", "modified_at"))

View File

@ -1,6 +1,7 @@
"""Tests for the diagnostics data provided by the Webmin integration.""" """Tests for the diagnostics data provided by the Webmin integration."""
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from syrupy.filters import props
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -16,9 +17,6 @@ async def test_diagnostics(
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
) -> None: ) -> None:
"""Test diagnostics.""" """Test diagnostics."""
assert ( assert await get_diagnostics_for_config_entry(
await get_diagnostics_for_config_entry( hass, hass_client, await async_init_integration(hass)
hass, hass_client, await async_init_integration(hass) ) == snapshot(exclude=props("created_at", "modified_at"))
)
== snapshot
)

View File

@ -58,5 +58,7 @@ async def test_diagnostics(
"source": "user", "source": "user",
"unique_id": REDACTED, "unique_id": REDACTED,
"disabled_by": None, "disabled_by": None,
"created_at": entry.created_at.isoformat(),
"modified_at": entry.modified_at.isoformat(),
}, },
} }

View File

@ -29,4 +29,4 @@ async def test_entry_diagnostics(
result = await get_diagnostics_for_config_entry(hass, hass_client, mock_entry) result = await get_diagnostics_for_config_entry(hass, hass_client, mock_entry)
assert result == snapshot(exclude=props("entry_id")) assert result == snapshot(exclude=props("entry_id", "created_at", "modified_at"))

View File

@ -1,12 +1,14 @@
# serializer version: 1 # serializer version: 1
# name: test_as_dict # name: test_as_dict
dict({ dict({
'created_at': '2024-02-14T12:00:00+00:00',
'data': dict({ 'data': dict({
}), }),
'disabled_by': None, 'disabled_by': None,
'domain': 'test', 'domain': 'test',
'entry_id': 'mock-entry', 'entry_id': 'mock-entry',
'minor_version': 1, 'minor_version': 1,
'modified_at': '2024-02-14T12:00:00+00:00',
'options': dict({ 'options': dict({
}), }),
'pref_disable_new_entities': False, 'pref_disable_new_entities': False,

View File

@ -137,7 +137,8 @@ class HomeAssistantSnapshotSerializer(AmberDataSerializer):
@classmethod @classmethod
def _serializable_config_entry(cls, data: ConfigEntry) -> SerializableData: def _serializable_config_entry(cls, data: ConfigEntry) -> SerializableData:
"""Prepare a Home Assistant config entry for serialization.""" """Prepare a Home Assistant config entry for serialization."""
return ConfigEntrySnapshot(data.as_dict() | {"entry_id": ANY}) entry = ConfigEntrySnapshot(data.as_dict() | {"entry_id": ANY})
return cls._remove_created_and_modified_at(entry)
@classmethod @classmethod
def _serializable_device_registry_entry( def _serializable_device_registry_entry(

View File

@ -10,6 +10,7 @@ import logging
from typing import Any from typing import Any
from unittest.mock import ANY, AsyncMock, Mock, patch from unittest.mock import ANY, AsyncMock, Mock, patch
from freezegun import freeze_time
from freezegun.api import FrozenDateTimeFactory from freezegun.api import FrozenDateTimeFactory
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
@ -51,6 +52,7 @@ from .common import (
async_capture_events, async_capture_events,
async_fire_time_changed, async_fire_time_changed,
async_get_persistent_notifications, async_get_persistent_notifications,
flush_store,
mock_config_flow, mock_config_flow,
mock_integration, mock_integration,
mock_platform, mock_platform,
@ -912,6 +914,7 @@ async def test_saving_and_loading(
assert orig.as_dict() == loaded.as_dict() assert orig.as_dict() == loaded.as_dict()
@freeze_time("2024-02-14 12:00:00")
async def test_as_dict(snapshot: SnapshotAssertion) -> None: async def test_as_dict(snapshot: SnapshotAssertion) -> None:
"""Test ConfigEntry.as_dict.""" """Test ConfigEntry.as_dict."""
@ -1251,8 +1254,11 @@ async def test_loading_default_config(hass: HomeAssistant) -> None:
assert len(manager.async_entries()) == 0 assert len(manager.async_entries()) == 0
async def test_updating_entry_data(manager: config_entries.ConfigEntries) -> None: async def test_updating_entry_data(
manager: config_entries.ConfigEntries, freezer: FrozenDateTimeFactory
) -> None:
"""Test that we can update an entry data.""" """Test that we can update an entry data."""
created = dt_util.utcnow()
entry = MockConfigEntry( entry = MockConfigEntry(
domain="test", domain="test",
data={"first": True}, data={"first": True},
@ -1260,17 +1266,32 @@ async def test_updating_entry_data(manager: config_entries.ConfigEntries) -> Non
) )
entry.add_to_manager(manager) entry.add_to_manager(manager)
assert len(manager.async_entries()) == 1
assert manager.async_entries()[0] == entry
assert entry.created_at == created
assert entry.modified_at == created
freezer.tick()
assert manager.async_update_entry(entry) is False assert manager.async_update_entry(entry) is False
assert entry.data == {"first": True} assert entry.data == {"first": True}
assert entry.modified_at == created
assert manager.async_entries()[0].modified_at == created
freezer.tick()
modified = dt_util.utcnow()
assert manager.async_update_entry(entry, data={"second": True}) is True assert manager.async_update_entry(entry, data={"second": True}) is True
assert entry.data == {"second": True} assert entry.data == {"second": True}
assert entry.modified_at == modified
assert manager.async_entries()[0].modified_at == modified
async def test_updating_entry_system_options( async def test_updating_entry_system_options(
manager: config_entries.ConfigEntries, manager: config_entries.ConfigEntries, freezer: FrozenDateTimeFactory
) -> None: ) -> None:
"""Test that we can update an entry data.""" """Test that we can update an entry data."""
created = dt_util.utcnow()
entry = MockConfigEntry( entry = MockConfigEntry(
domain="test", domain="test",
data={"first": True}, data={"first": True},
@ -1281,6 +1302,11 @@ async def test_updating_entry_system_options(
assert entry.pref_disable_new_entities is True assert entry.pref_disable_new_entities is True
assert entry.pref_disable_polling is False assert entry.pref_disable_polling is False
assert entry.created_at == created
assert entry.modified_at == created
freezer.tick()
modified = dt_util.utcnow()
manager.async_update_entry( manager.async_update_entry(
entry, pref_disable_new_entities=False, pref_disable_polling=True entry, pref_disable_new_entities=False, pref_disable_polling=True
@ -1288,6 +1314,8 @@ async def test_updating_entry_system_options(
assert entry.pref_disable_new_entities is False assert entry.pref_disable_new_entities is False
assert entry.pref_disable_polling is True assert entry.pref_disable_polling is True
assert entry.created_at == created
assert entry.modified_at == modified
async def test_update_entry_options_and_trigger_listener( async def test_update_entry_options_and_trigger_listener(
@ -5908,3 +5936,67 @@ async def test_config_entry_late_platform_setup(
"entry_id test2 cannot forward setup for light because it is " "entry_id test2 cannot forward setup for light because it is "
"not loaded in the ConfigEntryState.NOT_LOADED state" "not loaded in the ConfigEntryState.NOT_LOADED state"
) not in caplog.text ) not in caplog.text
@pytest.mark.parametrize("load_registries", [False])
async def test_migration_from_1_2(
hass: HomeAssistant, hass_storage: dict[str, Any]
) -> None:
"""Test migration from version 1.2."""
hass_storage[config_entries.STORAGE_KEY] = {
"version": 1,
"minor_version": 2,
"data": {
"entries": [
{
"data": {},
"disabled_by": None,
"domain": "sun",
"entry_id": "0a8bd02d0d58c7debf5daf7941c9afe2",
"minor_version": 1,
"options": {},
"pref_disable_new_entities": False,
"pref_disable_polling": False,
"source": "import",
"title": "Sun",
"unique_id": None,
"version": 1,
},
]
},
}
manager = config_entries.ConfigEntries(hass, {})
await manager.async_initialize()
# Test data was loaded
entries = manager.async_entries()
assert len(entries) == 1
# Check we store migrated data
await flush_store(manager._store)
assert hass_storage[config_entries.STORAGE_KEY] == {
"version": config_entries.STORAGE_VERSION,
"minor_version": config_entries.STORAGE_VERSION_MINOR,
"key": config_entries.STORAGE_KEY,
"data": {
"entries": [
{
"created_at": "1970-01-01T00:00:00+00:00",
"data": {},
"disabled_by": None,
"domain": "sun",
"entry_id": "0a8bd02d0d58c7debf5daf7941c9afe2",
"minor_version": 1,
"modified_at": "1970-01-01T00:00:00+00:00",
"options": {},
"pref_disable_new_entities": False,
"pref_disable_polling": False,
"source": "import",
"title": "Sun",
"unique_id": None,
"version": 1,
},
]
},
}