mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Store creation timestamps for resolution center issues (#75430)
This commit is contained in:
parent
8e8c6e2394
commit
c3d536b255
@ -2,11 +2,13 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import dataclasses
|
import dataclasses
|
||||||
|
from datetime import datetime
|
||||||
from typing import Optional, cast
|
from typing import Optional, cast
|
||||||
|
|
||||||
from homeassistant.const import __version__ as ha_version
|
from homeassistant.const import __version__ as ha_version
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.storage import Store
|
from homeassistant.helpers.storage import Store
|
||||||
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
from .models import IssueSeverity
|
from .models import IssueSeverity
|
||||||
|
|
||||||
@ -14,7 +16,6 @@ DATA_REGISTRY = "issue_registry"
|
|||||||
STORAGE_KEY = "resolution_center.issue_registry"
|
STORAGE_KEY = "resolution_center.issue_registry"
|
||||||
STORAGE_VERSION = 1
|
STORAGE_VERSION = 1
|
||||||
SAVE_DELAY = 10
|
SAVE_DELAY = 10
|
||||||
SAVED_FIELDS = ("dismissed_version", "domain", "issue_id")
|
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(frozen=True)
|
@dataclasses.dataclass(frozen=True)
|
||||||
@ -23,6 +24,7 @@ class IssueEntry:
|
|||||||
|
|
||||||
active: bool
|
active: bool
|
||||||
breaks_in_ha_version: str | None
|
breaks_in_ha_version: str | None
|
||||||
|
created: datetime
|
||||||
dismissed_version: str | None
|
dismissed_version: str | None
|
||||||
domain: str
|
domain: str
|
||||||
is_fixable: bool | None
|
is_fixable: bool | None
|
||||||
@ -68,6 +70,7 @@ class IssueRegistry:
|
|||||||
issue = IssueEntry(
|
issue = IssueEntry(
|
||||||
active=True,
|
active=True,
|
||||||
breaks_in_ha_version=breaks_in_ha_version,
|
breaks_in_ha_version=breaks_in_ha_version,
|
||||||
|
created=dt_util.utcnow(),
|
||||||
dismissed_version=None,
|
dismissed_version=None,
|
||||||
domain=domain,
|
domain=domain,
|
||||||
is_fixable=is_fixable,
|
is_fixable=is_fixable,
|
||||||
@ -125,10 +128,11 @@ class IssueRegistry:
|
|||||||
|
|
||||||
if isinstance(data, dict):
|
if isinstance(data, dict):
|
||||||
for issue in data["issues"]:
|
for issue in data["issues"]:
|
||||||
assert issue["domain"] and issue["issue_id"]
|
assert issue["created"] and issue["domain"] and issue["issue_id"]
|
||||||
issues[(issue["domain"], issue["issue_id"])] = IssueEntry(
|
issues[(issue["domain"], issue["issue_id"])] = IssueEntry(
|
||||||
active=False,
|
active=False,
|
||||||
breaks_in_ha_version=None,
|
breaks_in_ha_version=None,
|
||||||
|
created=cast(datetime, dt_util.parse_datetime(issue["created"])),
|
||||||
dismissed_version=issue["dismissed_version"],
|
dismissed_version=issue["dismissed_version"],
|
||||||
domain=issue["domain"],
|
domain=issue["domain"],
|
||||||
is_fixable=None,
|
is_fixable=None,
|
||||||
@ -152,7 +156,12 @@ class IssueRegistry:
|
|||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
data["issues"] = [
|
data["issues"] = [
|
||||||
{field: getattr(entry, field) for field in SAVED_FIELDS}
|
{
|
||||||
|
"created": entry.created.isoformat(),
|
||||||
|
"dismissed_version": entry.dismissed_version,
|
||||||
|
"domain": entry.domain,
|
||||||
|
"issue_id": entry.issue_id,
|
||||||
|
}
|
||||||
for entry in self.issues.values()
|
for entry in self.issues.values()
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -67,8 +67,9 @@ def ws_list_issues(
|
|||||||
"""Return a list of issues."""
|
"""Return a list of issues."""
|
||||||
|
|
||||||
def ws_dict(kv_pairs: list[tuple[Any, Any]]) -> dict[Any, Any]:
|
def ws_dict(kv_pairs: list[tuple[Any, Any]]) -> dict[Any, Any]:
|
||||||
result = {k: v for k, v in kv_pairs if k != "active"}
|
result = {k: v for k, v in kv_pairs if k not in ("active")}
|
||||||
result["dismissed"] = result["dismissed_version"] is not None
|
result["dismissed"] = result["dismissed_version"] is not None
|
||||||
|
result["created"] = result["created"].isoformat()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
issue_registry = async_get_issue_registry(hass)
|
issue_registry = async_get_issue_registry(hass)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
"""Test the resolution center websocket API."""
|
"""Test the resolution center websocket API."""
|
||||||
from unittest.mock import AsyncMock, Mock
|
from unittest.mock import AsyncMock, Mock
|
||||||
|
|
||||||
|
from freezegun import freeze_time
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.resolution_center import (
|
from homeassistant.components.resolution_center import (
|
||||||
@ -19,6 +20,7 @@ from homeassistant.setup import async_setup_component
|
|||||||
from tests.common import mock_platform
|
from tests.common import mock_platform
|
||||||
|
|
||||||
|
|
||||||
|
@freeze_time("2022-07-19 07:53:05")
|
||||||
async def test_create_update_issue(hass: HomeAssistant, hass_ws_client) -> None:
|
async def test_create_update_issue(hass: HomeAssistant, hass_ws_client) -> None:
|
||||||
"""Test creating and updating issues."""
|
"""Test creating and updating issues."""
|
||||||
assert await async_setup_component(hass, DOMAIN, {})
|
assert await async_setup_component(hass, DOMAIN, {})
|
||||||
@ -75,6 +77,7 @@ async def test_create_update_issue(hass: HomeAssistant, hass_ws_client) -> None:
|
|||||||
"issues": [
|
"issues": [
|
||||||
dict(
|
dict(
|
||||||
issue,
|
issue,
|
||||||
|
created="2022-07-19T07:53:05+00:00",
|
||||||
dismissed=False,
|
dismissed=False,
|
||||||
dismissed_version=None,
|
dismissed_version=None,
|
||||||
)
|
)
|
||||||
@ -101,6 +104,7 @@ async def test_create_update_issue(hass: HomeAssistant, hass_ws_client) -> None:
|
|||||||
assert msg["success"]
|
assert msg["success"]
|
||||||
assert msg["result"]["issues"][0] == dict(
|
assert msg["result"]["issues"][0] == dict(
|
||||||
issues[0],
|
issues[0],
|
||||||
|
created="2022-07-19T07:53:05+00:00",
|
||||||
dismissed=False,
|
dismissed=False,
|
||||||
dismissed_version=None,
|
dismissed_version=None,
|
||||||
learn_more_url="blablabla",
|
learn_more_url="blablabla",
|
||||||
@ -147,6 +151,7 @@ async def test_create_issue_invalid_version(
|
|||||||
assert msg["result"] == {"issues": []}
|
assert msg["result"] == {"issues": []}
|
||||||
|
|
||||||
|
|
||||||
|
@freeze_time("2022-07-19 07:53:05")
|
||||||
async def test_dismiss_issue(hass: HomeAssistant, hass_ws_client) -> None:
|
async def test_dismiss_issue(hass: HomeAssistant, hass_ws_client) -> None:
|
||||||
"""Test dismissing issues."""
|
"""Test dismissing issues."""
|
||||||
assert await async_setup_component(hass, DOMAIN, {})
|
assert await async_setup_component(hass, DOMAIN, {})
|
||||||
@ -193,6 +198,7 @@ async def test_dismiss_issue(hass: HomeAssistant, hass_ws_client) -> None:
|
|||||||
"issues": [
|
"issues": [
|
||||||
dict(
|
dict(
|
||||||
issue,
|
issue,
|
||||||
|
created="2022-07-19T07:53:05+00:00",
|
||||||
dismissed=False,
|
dismissed=False,
|
||||||
dismissed_version=None,
|
dismissed_version=None,
|
||||||
)
|
)
|
||||||
@ -212,6 +218,7 @@ async def test_dismiss_issue(hass: HomeAssistant, hass_ws_client) -> None:
|
|||||||
"issues": [
|
"issues": [
|
||||||
dict(
|
dict(
|
||||||
issue,
|
issue,
|
||||||
|
created="2022-07-19T07:53:05+00:00",
|
||||||
dismissed=False,
|
dismissed=False,
|
||||||
dismissed_version=None,
|
dismissed_version=None,
|
||||||
)
|
)
|
||||||
@ -230,6 +237,7 @@ async def test_dismiss_issue(hass: HomeAssistant, hass_ws_client) -> None:
|
|||||||
"issues": [
|
"issues": [
|
||||||
dict(
|
dict(
|
||||||
issue,
|
issue,
|
||||||
|
created="2022-07-19T07:53:05+00:00",
|
||||||
dismissed=True,
|
dismissed=True,
|
||||||
dismissed_version=ha_version,
|
dismissed_version=ha_version,
|
||||||
)
|
)
|
||||||
@ -248,6 +256,7 @@ async def test_dismiss_issue(hass: HomeAssistant, hass_ws_client) -> None:
|
|||||||
"issues": [
|
"issues": [
|
||||||
dict(
|
dict(
|
||||||
issue,
|
issue,
|
||||||
|
created="2022-07-19T07:53:05+00:00",
|
||||||
dismissed=True,
|
dismissed=True,
|
||||||
dismissed_version=ha_version,
|
dismissed_version=ha_version,
|
||||||
)
|
)
|
||||||
@ -274,14 +283,16 @@ async def test_dismiss_issue(hass: HomeAssistant, hass_ws_client) -> None:
|
|||||||
assert msg["success"]
|
assert msg["success"]
|
||||||
assert msg["result"]["issues"][0] == dict(
|
assert msg["result"]["issues"][0] == dict(
|
||||||
issues[0],
|
issues[0],
|
||||||
|
created="2022-07-19T07:53:05+00:00",
|
||||||
dismissed=True,
|
dismissed=True,
|
||||||
dismissed_version=ha_version,
|
dismissed_version=ha_version,
|
||||||
learn_more_url="blablabla",
|
learn_more_url="blablabla",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_delete_issue(hass: HomeAssistant, hass_ws_client) -> None:
|
async def test_delete_issue(hass: HomeAssistant, hass_ws_client, freezer) -> None:
|
||||||
"""Test we can delete an issue."""
|
"""Test we can delete an issue."""
|
||||||
|
freezer.move_to("2022-07-19 07:53:05")
|
||||||
assert await async_setup_component(hass, DOMAIN, {})
|
assert await async_setup_component(hass, DOMAIN, {})
|
||||||
|
|
||||||
client = await hass_ws_client(hass)
|
client = await hass_ws_client(hass)
|
||||||
@ -320,6 +331,7 @@ async def test_delete_issue(hass: HomeAssistant, hass_ws_client) -> None:
|
|||||||
"issues": [
|
"issues": [
|
||||||
dict(
|
dict(
|
||||||
issue,
|
issue,
|
||||||
|
created="2022-07-19T07:53:05+00:00",
|
||||||
dismissed=False,
|
dismissed=False,
|
||||||
dismissed_version=None,
|
dismissed_version=None,
|
||||||
)
|
)
|
||||||
@ -338,6 +350,7 @@ async def test_delete_issue(hass: HomeAssistant, hass_ws_client) -> None:
|
|||||||
"issues": [
|
"issues": [
|
||||||
dict(
|
dict(
|
||||||
issue,
|
issue,
|
||||||
|
created="2022-07-19T07:53:05+00:00",
|
||||||
dismissed=False,
|
dismissed=False,
|
||||||
dismissed_version=None,
|
dismissed_version=None,
|
||||||
)
|
)
|
||||||
@ -363,6 +376,38 @@ async def test_delete_issue(hass: HomeAssistant, hass_ws_client) -> None:
|
|||||||
assert msg["success"]
|
assert msg["success"]
|
||||||
assert msg["result"] == {"issues": []}
|
assert msg["result"] == {"issues": []}
|
||||||
|
|
||||||
|
# Create the same issues again created timestamp should change
|
||||||
|
freezer.move_to("2022-07-19 08:53:05")
|
||||||
|
|
||||||
|
for issue in issues:
|
||||||
|
async_create_issue(
|
||||||
|
hass,
|
||||||
|
issue["domain"],
|
||||||
|
issue["issue_id"],
|
||||||
|
breaks_in_ha_version=issue["breaks_in_ha_version"],
|
||||||
|
is_fixable=issue["is_fixable"],
|
||||||
|
learn_more_url=issue["learn_more_url"],
|
||||||
|
severity=issue["severity"],
|
||||||
|
translation_key=issue["translation_key"],
|
||||||
|
translation_placeholders=issue["translation_placeholders"],
|
||||||
|
)
|
||||||
|
|
||||||
|
await client.send_json({"id": 5, "type": "resolution_center/list_issues"})
|
||||||
|
msg = await client.receive_json()
|
||||||
|
|
||||||
|
assert msg["success"]
|
||||||
|
assert msg["result"] == {
|
||||||
|
"issues": [
|
||||||
|
dict(
|
||||||
|
issue,
|
||||||
|
created="2022-07-19T08:53:05+00:00",
|
||||||
|
dismissed=False,
|
||||||
|
dismissed_version=None,
|
||||||
|
)
|
||||||
|
for issue in issues
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def test_non_compliant_platform(hass: HomeAssistant, hass_ws_client) -> None:
|
async def test_non_compliant_platform(hass: HomeAssistant, hass_ws_client) -> None:
|
||||||
"""Test non-compliant platforms are not registered."""
|
"""Test non-compliant platforms are not registered."""
|
||||||
|
@ -64,8 +64,10 @@ async def test_load_issues(hass: HomeAssistant) -> None:
|
|||||||
assert list(registry.issues) == list(registry2.issues)
|
assert list(registry.issues) == list(registry2.issues)
|
||||||
|
|
||||||
issue1_registry2 = registry2.async_get_issue("test", "issue_1")
|
issue1_registry2 = registry2.async_get_issue("test", "issue_1")
|
||||||
|
assert issue1_registry2.created == issue1.created
|
||||||
assert issue1_registry2.dismissed_version == issue1.dismissed_version
|
assert issue1_registry2.dismissed_version == issue1.dismissed_version
|
||||||
issue2_registry2 = registry2.async_get_issue("test", "issue_2")
|
issue2_registry2 = registry2.async_get_issue("test", "issue_2")
|
||||||
|
assert issue2_registry2.created == issue2.created
|
||||||
assert issue2_registry2.dismissed_version == issue2.dismissed_version
|
assert issue2_registry2.dismissed_version == issue2.dismissed_version
|
||||||
|
|
||||||
|
|
||||||
@ -76,11 +78,13 @@ async def test_loading_issues_from_storage(hass: HomeAssistant, hass_storage) ->
|
|||||||
"data": {
|
"data": {
|
||||||
"issues": [
|
"issues": [
|
||||||
{
|
{
|
||||||
|
"created": "2022-07-19T09:41:13.746514+00:00",
|
||||||
"dismissed_version": "2022.7.0.dev0",
|
"dismissed_version": "2022.7.0.dev0",
|
||||||
"domain": "test",
|
"domain": "test",
|
||||||
"issue_id": "issue_1",
|
"issue_id": "issue_1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"created": "2022-07-19T19:41:13.746514+00:00",
|
||||||
"dismissed_version": None,
|
"dismissed_version": None,
|
||||||
"domain": "test",
|
"domain": "test",
|
||||||
"issue_id": "issue_2",
|
"issue_id": "issue_2",
|
||||||
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from unittest.mock import ANY, AsyncMock, Mock
|
from unittest.mock import ANY, AsyncMock, Mock
|
||||||
|
|
||||||
|
from freezegun import freeze_time
|
||||||
import pytest
|
import pytest
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
@ -56,6 +57,7 @@ async def create_issues(hass, ws_client):
|
|||||||
"issues": [
|
"issues": [
|
||||||
dict(
|
dict(
|
||||||
issue,
|
issue,
|
||||||
|
created=ANY,
|
||||||
dismissed=False,
|
dismissed=False,
|
||||||
dismissed_version=None,
|
dismissed_version=None,
|
||||||
)
|
)
|
||||||
@ -146,6 +148,7 @@ async def test_dismiss_issue(hass: HomeAssistant, hass_ws_client) -> None:
|
|||||||
"issues": [
|
"issues": [
|
||||||
dict(
|
dict(
|
||||||
issue,
|
issue,
|
||||||
|
created=ANY,
|
||||||
dismissed=True,
|
dismissed=True,
|
||||||
dismissed_version=ha_version,
|
dismissed_version=ha_version,
|
||||||
)
|
)
|
||||||
@ -188,6 +191,7 @@ async def test_fix_non_existing_issue(
|
|||||||
"issues": [
|
"issues": [
|
||||||
dict(
|
dict(
|
||||||
issue,
|
issue,
|
||||||
|
created=ANY,
|
||||||
dismissed=False,
|
dismissed=False,
|
||||||
dismissed_version=None,
|
dismissed_version=None,
|
||||||
)
|
)
|
||||||
@ -333,6 +337,7 @@ async def test_step_unauth(
|
|||||||
assert resp.status == HTTPStatus.UNAUTHORIZED
|
assert resp.status == HTTPStatus.UNAUTHORIZED
|
||||||
|
|
||||||
|
|
||||||
|
@freeze_time("2022-07-19 07:53:05")
|
||||||
async def test_list_issues(hass: HomeAssistant, hass_ws_client) -> None:
|
async def test_list_issues(hass: HomeAssistant, hass_ws_client) -> None:
|
||||||
"""Test we can list issues."""
|
"""Test we can list issues."""
|
||||||
assert await async_setup_component(hass, DOMAIN, {})
|
assert await async_setup_component(hass, DOMAIN, {})
|
||||||
@ -389,6 +394,7 @@ async def test_list_issues(hass: HomeAssistant, hass_ws_client) -> None:
|
|||||||
"issues": [
|
"issues": [
|
||||||
dict(
|
dict(
|
||||||
issue,
|
issue,
|
||||||
|
created="2022-07-19T07:53:05+00:00",
|
||||||
dismissed=False,
|
dismissed=False,
|
||||||
dismissed_version=None,
|
dismissed_version=None,
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user