Teach resolution center about fixing issues (#74694)

This commit is contained in:
Erik Montnemery 2022-07-12 19:26:06 +02:00 committed by GitHub
parent cf612c4bec
commit b0fde206b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 485 additions and 17 deletions

View File

@ -4,16 +4,19 @@ from __future__ import annotations
from homeassistant.core import HomeAssistant
from homeassistant.helpers.typing import ConfigType
from . import websocket_api
from . import issue_handler, websocket_api
from .const import DOMAIN
from .issue_handler import async_create_issue, async_delete_issue
from .issue_handler import ResolutionCenterFlow, async_create_issue, async_delete_issue
from .issue_registry import async_load as async_load_issue_registry
__all__ = ["DOMAIN", "async_create_issue", "async_delete_issue"]
__all__ = ["DOMAIN", "ResolutionCenterFlow", "async_create_issue", "async_delete_issue"]
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up Resolution Center."""
hass.data[DOMAIN] = {}
issue_handler.async_setup(hass)
websocket_api.async_setup(hass)
await async_load_issue_registry(hass)

View File

@ -1,12 +1,85 @@
"""The resolution center integration."""
from __future__ import annotations
from typing import Any
from awesomeversion import AwesomeVersion, AwesomeVersionStrategy
from homeassistant import data_entry_flow
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.integration_platform import (
async_process_integration_platforms,
)
from .const import DOMAIN
from .issue_registry import async_get as async_get_issue_registry
from .models import IssueSeverity
from .models import IssueSeverity, ResolutionCenterFlow, ResolutionCenterProtocol
class ResolutionCenterFlowManager(data_entry_flow.FlowManager):
"""Manage resolution center flows."""
async def async_create_flow(
self,
handler_key: Any,
*,
context: dict[str, Any] | None = None,
data: dict[str, Any] | None = None,
) -> ResolutionCenterFlow:
"""Create a flow. platform is a resolution center module."""
if "platforms" not in self.hass.data[DOMAIN]:
await async_process_resolution_center_platforms(self.hass)
platforms: dict[str, ResolutionCenterProtocol] = self.hass.data[DOMAIN][
"platforms"
]
if handler_key not in platforms:
raise data_entry_flow.UnknownHandler
platform = platforms[handler_key]
assert data and "issue_id" in data
issue_id = data["issue_id"]
issue_registry = async_get_issue_registry(self.hass)
issue = issue_registry.async_get_issue(handler_key, issue_id)
if issue is None or not issue.is_fixable:
raise data_entry_flow.UnknownStep
return await platform.async_create_fix_flow(self.hass, issue_id)
async def async_finish_flow(
self, flow: data_entry_flow.FlowHandler, result: data_entry_flow.FlowResult
) -> data_entry_flow.FlowResult:
"""Complete a fix flow."""
async_delete_issue(self.hass, flow.handler, flow.init_data["issue_id"])
if "result" not in result:
result["result"] = None
return result
@callback
def async_setup(hass: HomeAssistant) -> None:
"""Initialize resolution center."""
hass.data[DOMAIN]["flow_manager"] = ResolutionCenterFlowManager(hass)
async def async_process_resolution_center_platforms(hass: HomeAssistant) -> None:
"""Start processing resolution center platforms."""
hass.data[DOMAIN]["platforms"] = {}
await async_process_integration_platforms(
hass, DOMAIN, _register_resolution_center_platform
)
async def _register_resolution_center_platform(
hass: HomeAssistant, integration_domain: str, platform: ResolutionCenterProtocol
) -> None:
"""Register a resolution center platform."""
if not hasattr(platform, "async_create_fix_flow"):
raise HomeAssistantError(f"Invalid resolution center platform {platform}")
hass.data[DOMAIN]["platforms"][integration_domain] = platform
@callback
@ -16,6 +89,7 @@ def async_create_issue(
issue_id: str,
*,
breaks_in_ha_version: str | None = None,
is_fixable: bool,
learn_more_url: str | None = None,
severity: IssueSeverity,
translation_key: str,
@ -35,6 +109,7 @@ def async_create_issue(
domain,
issue_id,
breaks_in_ha_version=breaks_in_ha_version,
is_fixable=is_fixable,
learn_more_url=learn_more_url,
severity=severity,
translation_key=translation_key,

View File

@ -25,6 +25,7 @@ class IssueEntry:
breaks_in_ha_version: str | None
dismissed_version: str | None
domain: str
is_fixable: bool | None
issue_id: str
learn_more_url: str | None
severity: IssueSeverity | None
@ -55,6 +56,7 @@ class IssueRegistry:
issue_id: str,
*,
breaks_in_ha_version: str | None = None,
is_fixable: bool,
learn_more_url: str | None = None,
severity: IssueSeverity,
translation_key: str,
@ -68,6 +70,7 @@ class IssueRegistry:
breaks_in_ha_version=breaks_in_ha_version,
dismissed_version=None,
domain=domain,
is_fixable=is_fixable,
issue_id=issue_id,
learn_more_url=learn_more_url,
severity=severity,
@ -81,6 +84,7 @@ class IssueRegistry:
issue,
active=True,
breaks_in_ha_version=breaks_in_ha_version,
is_fixable=is_fixable,
learn_more_url=learn_more_url,
severity=severity,
translation_key=translation_key,
@ -127,6 +131,7 @@ class IssueRegistry:
breaks_in_ha_version=None,
dismissed_version=issue["dismissed_version"],
domain=issue["domain"],
is_fixable=None,
issue_id=issue["issue_id"],
learn_more_url=None,
severity=None,

View File

@ -3,5 +3,6 @@
"name": "Resolution Center",
"config_flow": false,
"documentation": "https://www.home-assistant.io/integrations/resolution_center",
"codeowners": ["@home-assistant/core"]
"codeowners": ["@home-assistant/core"],
"dependencies": ["http"]
}

View File

@ -1,7 +1,11 @@
"""Models for Resolution Center."""
from __future__ import annotations
from typing import Protocol
from homeassistant import data_entry_flow
from homeassistant.backports.enum import StrEnum
from homeassistant.core import HomeAssistant
class IssueSeverity(StrEnum):
@ -10,3 +14,16 @@ class IssueSeverity(StrEnum):
CRITICAL = "critical"
ERROR = "error"
WARNING = "warning"
class ResolutionCenterFlow(data_entry_flow.FlowHandler):
"""Handle a flow for fixing an issue."""
class ResolutionCenterProtocol(Protocol):
"""Define the format of resolution center platforms."""
async def async_create_fix_flow(
self, hass: HomeAssistant, issue_id: str
) -> ResolutionCenterFlow:
"""Create a flow to fix a fixable issue."""

View File

@ -2,13 +2,24 @@
from __future__ import annotations
import dataclasses
from http import HTTPStatus
from typing import Any
from aiohttp import web
import voluptuous as vol
from homeassistant import data_entry_flow
from homeassistant.auth.permissions.const import POLICY_EDIT
from homeassistant.components import websocket_api
from homeassistant.components.http.data_validator import RequestDataValidator
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import Unauthorized
from homeassistant.helpers.data_entry_flow import (
FlowManagerIndexView,
FlowManagerResourceView,
)
from .const import DOMAIN
from .issue_handler import async_dismiss_issue
from .issue_registry import async_get as async_get_issue_registry
@ -19,6 +30,13 @@ def async_setup(hass: HomeAssistant) -> None:
websocket_api.async_register_command(hass, ws_dismiss_issue)
websocket_api.async_register_command(hass, ws_list_issues)
hass.http.register_view(
ResolutionCenterFlowIndexView(hass.data[DOMAIN]["flow_manager"])
)
hass.http.register_view(
ResolutionCenterFlowResourceView(hass.data[DOMAIN]["flow_manager"])
)
@callback
@websocket_api.websocket_command(
@ -60,3 +78,63 @@ def ws_list_issues(
]
connection.send_result(msg["id"], {"issues": issues})
class ResolutionCenterFlowIndexView(FlowManagerIndexView):
"""View to create issue fix flows."""
url = "/api/resolution_center/issues/fix"
name = "api:resolution_center:issues:fix"
@RequestDataValidator(
vol.Schema(
{
vol.Required("handler"): str,
vol.Required("issue_id"): str,
},
extra=vol.ALLOW_EXTRA,
)
)
async def post(self, request: web.Request, data: dict[str, Any]) -> web.Response:
"""Handle a POST request."""
if not request["hass_user"].is_admin:
raise Unauthorized(permission=POLICY_EDIT)
try:
result = await self._flow_mgr.async_init(
data["handler"],
data={"issue_id": data["issue_id"]},
)
except data_entry_flow.UnknownHandler:
return self.json_message("Invalid handler specified", HTTPStatus.NOT_FOUND)
except data_entry_flow.UnknownStep:
return self.json_message(
"Handler does not support user", HTTPStatus.BAD_REQUEST
)
result = self._prepare_result_json(result)
return self.json(result) # pylint: disable=arguments-differ
class ResolutionCenterFlowResourceView(FlowManagerResourceView):
"""View to interact with the option flow manager."""
url = "/api/resolution_center/issues/fix/{flow_id}"
name = "api:resolution_center:issues:fix:resource"
async def get(self, request: web.Request, flow_id: str) -> web.Response:
"""Get the current state of a data_entry_flow."""
if not request["hass_user"].is_admin:
raise Unauthorized(permission=POLICY_EDIT)
return await super().get(request, flow_id)
# pylint: disable=arguments-differ
async def post(self, request: web.Request, flow_id: str) -> web.Response:
"""Handle a POST request."""
if not request["hass_user"].is_admin:
raise Unauthorized(permission=POLICY_EDIT)
# pylint: disable=no-value-for-parameter
return await super().post(request, flow_id) # type: ignore[no-any-return]

View File

@ -1,4 +1,6 @@
"""Test the resolution center websocket API."""
from unittest.mock import AsyncMock, Mock
import pytest
from homeassistant.components.resolution_center import (
@ -6,11 +8,16 @@ from homeassistant.components.resolution_center import (
async_delete_issue,
)
from homeassistant.components.resolution_center.const import DOMAIN
from homeassistant.components.resolution_center.issue_handler import async_dismiss_issue
from homeassistant.components.resolution_center.issue_handler import (
async_dismiss_issue,
async_process_resolution_center_platforms,
)
from homeassistant.const import __version__ as ha_version
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from tests.common import mock_platform
async def test_create_update_issue(hass: HomeAssistant, hass_ws_client) -> None:
"""Test creating and updating issues."""
@ -29,6 +36,7 @@ async def test_create_update_issue(hass: HomeAssistant, hass_ws_client) -> None:
"breaks_in_ha_version": "2022.9.0dev0",
"domain": "test",
"issue_id": "issue_1",
"is_fixable": True,
"learn_more_url": "https://theuselessweb.com",
"severity": "error",
"translation_key": "abc_123",
@ -38,6 +46,7 @@ async def test_create_update_issue(hass: HomeAssistant, hass_ws_client) -> None:
"breaks_in_ha_version": "2022.8",
"domain": "test",
"issue_id": "issue_2",
"is_fixable": False,
"learn_more_url": "https://theuselessweb.com/abc",
"severity": "other",
"translation_key": "even_worse",
@ -51,6 +60,7 @@ async def test_create_update_issue(hass: HomeAssistant, hass_ws_client) -> None:
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"],
@ -78,6 +88,7 @@ async def test_create_update_issue(hass: HomeAssistant, hass_ws_client) -> None:
issues[0]["domain"],
issues[0]["issue_id"],
breaks_in_ha_version=issues[0]["breaks_in_ha_version"],
is_fixable=issues[0]["is_fixable"],
learn_more_url="blablabla",
severity=issues[0]["severity"],
translation_key=issues[0]["translation_key"],
@ -109,6 +120,7 @@ async def test_create_issue_invalid_version(
"breaks_in_ha_version": ha_version,
"domain": "test",
"issue_id": "issue_1",
"is_fixable": True,
"learn_more_url": "https://theuselessweb.com",
"severity": "error",
"translation_key": "abc_123",
@ -121,6 +133,7 @@ async def test_create_issue_invalid_version(
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"],
@ -150,6 +163,7 @@ async def test_dismiss_issue(hass: HomeAssistant, hass_ws_client) -> None:
{
"breaks_in_ha_version": "2022.9",
"domain": "test",
"is_fixable": True,
"issue_id": "issue_1",
"learn_more_url": "https://theuselessweb.com",
"severity": "error",
@ -164,6 +178,7 @@ async def test_dismiss_issue(hass: HomeAssistant, hass_ws_client) -> None:
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"],
@ -246,6 +261,7 @@ async def test_dismiss_issue(hass: HomeAssistant, hass_ws_client) -> None:
issues[0]["domain"],
issues[0]["issue_id"],
breaks_in_ha_version=issues[0]["breaks_in_ha_version"],
is_fixable=issues[0]["is_fixable"],
learn_more_url="blablabla",
severity=issues[0]["severity"],
translation_key=issues[0]["translation_key"],
@ -275,6 +291,7 @@ async def test_delete_issue(hass: HomeAssistant, hass_ws_client) -> None:
"breaks_in_ha_version": "2022.9",
"domain": "fake_integration",
"issue_id": "issue_1",
"is_fixable": True,
"learn_more_url": "https://theuselessweb.com",
"severity": "error",
"translation_key": "abc_123",
@ -288,6 +305,7 @@ async def test_delete_issue(hass: HomeAssistant, hass_ws_client) -> None:
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"],
@ -344,3 +362,25 @@ async def test_delete_issue(hass: HomeAssistant, hass_ws_client) -> None:
assert msg["success"]
assert msg["result"] == {"issues": []}
async def test_non_compliant_platform(hass: HomeAssistant, hass_ws_client) -> None:
"""Test non-compliant platforms are not registered."""
hass.config.components.add("fake_integration")
hass.config.components.add("integration_without_diagnostics")
mock_platform(
hass,
"fake_integration.resolution_center",
Mock(async_create_fix_flow=AsyncMock(return_value=True)),
)
mock_platform(
hass,
"integration_without_diagnostics.resolution_center",
Mock(spec=[]),
)
assert await async_setup_component(hass, DOMAIN, {})
await async_process_resolution_center_platforms(hass)
assert list(hass.data[DOMAIN]["platforms"].keys()) == ["fake_integration"]

View File

@ -20,6 +20,7 @@ async def test_load_issues(hass: HomeAssistant) -> None:
"breaks_in_ha_version": "2022.9",
"domain": "test",
"issue_id": "issue_1",
"is_fixable": True,
"learn_more_url": "https://theuselessweb.com",
"severity": "error",
"translation_key": "abc_123",
@ -29,6 +30,7 @@ async def test_load_issues(hass: HomeAssistant) -> None:
"breaks_in_ha_version": "2022.8",
"domain": "test",
"issue_id": "issue_2",
"is_fixable": True,
"learn_more_url": "https://theuselessweb.com/abc",
"severity": "other",
"translation_key": "even_worse",
@ -42,6 +44,7 @@ async def test_load_issues(hass: HomeAssistant) -> None:
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"],

View File

@ -1,22 +1,33 @@
"""Test the resolution center websocket API."""
from homeassistant.components.resolution_center import async_create_issue
from __future__ import annotations
from http import HTTPStatus
from unittest.mock import ANY, AsyncMock, Mock
import pytest
import voluptuous as vol
from homeassistant import data_entry_flow
from homeassistant.components.resolution_center import (
ResolutionCenterFlow,
async_create_issue,
)
from homeassistant.components.resolution_center.const import DOMAIN
from homeassistant.const import __version__ as ha_version
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from tests.common import mock_platform
async def test_dismiss_issue(hass: HomeAssistant, hass_ws_client) -> None:
"""Test we can dismiss an issue."""
assert await async_setup_component(hass, DOMAIN, {})
client = await hass_ws_client(hass)
async def create_issues(hass, ws_client):
"""Create issues."""
issues = [
{
"breaks_in_ha_version": "2022.9",
"domain": "test",
"domain": "fake_integration",
"issue_id": "issue_1",
"is_fixable": True,
"learn_more_url": "https://theuselessweb.com",
"severity": "error",
"translation_key": "abc_123",
@ -30,14 +41,15 @@ async def test_dismiss_issue(hass: HomeAssistant, hass_ws_client) -> None:
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": 1, "type": "resolution_center/list_issues"})
msg = await client.receive_json()
await ws_client.send_json({"id": 1, "type": "resolution_center/list_issues"})
msg = await ws_client.receive_json()
assert msg["success"]
assert msg["result"] == {
@ -51,11 +63,63 @@ async def test_dismiss_issue(hass: HomeAssistant, hass_ws_client) -> None:
]
}
return issues
class MockFixFlow(ResolutionCenterFlow):
"""Handler for an issue fixing flow."""
async def async_step_init(
self, user_input: dict[str, str] | None = None
) -> data_entry_flow.FlowResult:
"""Handle the first step of a fix flow."""
return await (self.async_step_confirm())
async def async_step_confirm(
self, user_input: dict[str, str] | None = None
) -> data_entry_flow.FlowResult:
"""Handle the confirm step of a fix flow."""
if user_input is not None:
return self.async_create_entry(title=None, data=None)
return self.async_show_form(step_id="confirm", data_schema=vol.Schema({}))
@pytest.fixture(autouse=True)
async def mock_resolution_center_integration(hass):
"""Mock a resolution_center integration."""
hass.config.components.add("fake_integration")
hass.config.components.add("integration_without_diagnostics")
def async_create_fix_flow(hass, issue_id):
return MockFixFlow()
mock_platform(
hass,
"fake_integration.resolution_center",
Mock(async_create_fix_flow=AsyncMock(wraps=async_create_fix_flow)),
)
mock_platform(
hass,
"integration_without_diagnostics.resolution_center",
Mock(spec=[]),
)
async def test_dismiss_issue(hass: HomeAssistant, hass_ws_client) -> None:
"""Test we can dismiss an issue."""
assert await async_setup_component(hass, DOMAIN, {})
client = await hass_ws_client(hass)
issues = await create_issues(hass, client)
await client.send_json(
{
"id": 2,
"type": "resolution_center/dismiss_issue",
"domain": "test",
"domain": "fake_integration",
"issue_id": "no_such_issue",
}
)
@ -66,7 +130,7 @@ async def test_dismiss_issue(hass: HomeAssistant, hass_ws_client) -> None:
{
"id": 3,
"type": "resolution_center/dismiss_issue",
"domain": "test",
"domain": "fake_integration",
"issue_id": "issue_1",
}
)
@ -90,6 +154,185 @@ async def test_dismiss_issue(hass: HomeAssistant, hass_ws_client) -> None:
}
async def test_fix_non_existing_issue(
hass: HomeAssistant, hass_client, hass_ws_client
) -> None:
"""Test trying to fix an issue that doesn't exist."""
assert await async_setup_component(hass, "http", {})
assert await async_setup_component(hass, DOMAIN, {})
ws_client = await hass_ws_client(hass)
client = await hass_client()
issues = await create_issues(hass, ws_client)
url = "/api/resolution_center/issues/fix"
resp = await client.post(
url, json={"handler": "no_such_integration", "issue_id": "no_such_issue"}
)
assert resp.status != HTTPStatus.OK
url = "/api/resolution_center/issues/fix"
resp = await client.post(
url, json={"handler": "fake_integration", "issue_id": "no_such_issue"}
)
assert resp.status != HTTPStatus.OK
await ws_client.send_json({"id": 3, "type": "resolution_center/list_issues"})
msg = await ws_client.receive_json()
assert msg["success"]
assert msg["result"] == {
"issues": [
dict(
issue,
dismissed=False,
dismissed_version=None,
)
for issue in issues
]
}
async def test_fix_issue(hass: HomeAssistant, hass_client, hass_ws_client) -> None:
"""Test we can fix an issue."""
assert await async_setup_component(hass, "http", {})
assert await async_setup_component(hass, DOMAIN, {})
ws_client = await hass_ws_client(hass)
client = await hass_client()
await create_issues(hass, ws_client)
url = "/api/resolution_center/issues/fix"
resp = await client.post(
url, json={"handler": "fake_integration", "issue_id": "issue_1"}
)
assert resp.status == HTTPStatus.OK
data = await resp.json()
flow_id = data["flow_id"]
assert data == {
"data_schema": [],
"description_placeholders": None,
"errors": None,
"flow_id": ANY,
"handler": "fake_integration",
"last_step": None,
"step_id": "confirm",
"type": "form",
}
url = f"/api/resolution_center/issues/fix/{flow_id}"
# Test we can get the status of the flow
resp2 = await client.get(url)
assert resp2.status == HTTPStatus.OK
data2 = await resp2.json()
assert data == data2
resp = await client.post(url)
assert resp.status == HTTPStatus.OK
data = await resp.json()
flow_id = data["flow_id"]
assert data == {
"description": None,
"description_placeholders": None,
"flow_id": flow_id,
"handler": "fake_integration",
"title": None,
"type": "create_entry",
"version": 1,
}
await ws_client.send_json({"id": 4, "type": "resolution_center/list_issues"})
msg = await ws_client.receive_json()
assert msg["success"]
assert msg["result"] == {"issues": []}
async def test_fix_issue_unauth(
hass: HomeAssistant, hass_client, hass_admin_user
) -> None:
"""Test we can't query the result if not authorized."""
assert await async_setup_component(hass, "http", {})
assert await async_setup_component(hass, DOMAIN, {})
hass_admin_user.groups = []
client = await hass_client()
url = "/api/resolution_center/issues/fix"
resp = await client.post(
url, json={"handler": "fake_integration", "issue_id": "issue_1"}
)
assert resp.status == HTTPStatus.UNAUTHORIZED
async def test_get_progress_unauth(
hass: HomeAssistant, hass_client, hass_ws_client, hass_admin_user
) -> None:
"""Test we can't fix an issue if not authorized."""
assert await async_setup_component(hass, "http", {})
assert await async_setup_component(hass, DOMAIN, {})
ws_client = await hass_ws_client(hass)
client = await hass_client()
await create_issues(hass, ws_client)
url = "/api/resolution_center/issues/fix"
resp = await client.post(
url, json={"handler": "fake_integration", "issue_id": "issue_1"}
)
assert resp.status == HTTPStatus.OK
data = await resp.json()
flow_id = data["flow_id"]
hass_admin_user.groups = []
url = f"/api/resolution_center/issues/fix/{flow_id}"
# Test we can't get the status of the flow
resp = await client.get(url)
assert resp.status == HTTPStatus.UNAUTHORIZED
async def test_step_unauth(
hass: HomeAssistant, hass_client, hass_ws_client, hass_admin_user
) -> None:
"""Test we can't fix an issue if not authorized."""
assert await async_setup_component(hass, "http", {})
assert await async_setup_component(hass, DOMAIN, {})
ws_client = await hass_ws_client(hass)
client = await hass_client()
await create_issues(hass, ws_client)
url = "/api/resolution_center/issues/fix"
resp = await client.post(
url, json={"handler": "fake_integration", "issue_id": "issue_1"}
)
assert resp.status == HTTPStatus.OK
data = await resp.json()
flow_id = data["flow_id"]
hass_admin_user.groups = []
url = f"/api/resolution_center/issues/fix/{flow_id}"
# Test we can't get the status of the flow
resp = await client.post(url)
assert resp.status == HTTPStatus.UNAUTHORIZED
async def test_list_issues(hass: HomeAssistant, hass_ws_client) -> None:
"""Test we can list issues."""
assert await async_setup_component(hass, DOMAIN, {})
@ -106,6 +349,7 @@ async def test_list_issues(hass: HomeAssistant, hass_ws_client) -> None:
{
"breaks_in_ha_version": "2022.9",
"domain": "test",
"is_fixable": True,
"issue_id": "issue_1",
"learn_more_url": "https://theuselessweb.com",
"severity": "error",
@ -115,6 +359,7 @@ async def test_list_issues(hass: HomeAssistant, hass_ws_client) -> None:
{
"breaks_in_ha_version": "2022.8",
"domain": "test",
"is_fixable": False,
"issue_id": "issue_2",
"learn_more_url": "https://theuselessweb.com/abc",
"severity": "other",
@ -129,6 +374,7 @@ async def test_list_issues(hass: HomeAssistant, hass_ws_client) -> None:
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"],