Events when unhealthy/unsupported changes (#3951)

* Events when unhealthy/unsupported changes

* called_once_with to called_once
This commit is contained in:
Mike Degatano 2022-10-16 05:07:15 -04:00 committed by GitHub
parent bde5c938a7
commit 5d2b5bada7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 144 additions and 3 deletions

View File

@ -32,6 +32,8 @@ class WSEvent(str, Enum):
"""Websocket events.""" """Websocket events."""
ADDON = "addon" ADDON = "addon"
HEALTH_CHANGED = "health_changed"
ISSUE_CHANGED = "issue_changed" ISSUE_CHANGED = "issue_changed"
ISSUE_REMOVED = "issue_removed" ISSUE_REMOVED = "issue_removed"
SUPERVISOR_UPDATE = "supervisor_update" SUPERVISOR_UPDATE = "supervisor_update"
SUPPORTED_CHANGED = "supported_changed"

View File

@ -3,7 +3,13 @@ from uuid import UUID, uuid4
import attr import attr
from .const import ContextType, IssueType, SuggestionType from .const import (
ContextType,
IssueType,
SuggestionType,
UnhealthyReason,
UnsupportedReason,
)
@attr.s(frozen=True, slots=True) @attr.s(frozen=True, slots=True)
@ -24,3 +30,19 @@ class Suggestion:
context: ContextType = attr.ib() context: ContextType = attr.ib()
reference: str | None = attr.ib(default=None) reference: str | None = attr.ib(default=None)
uuid: UUID = attr.ib(factory=lambda: uuid4().hex, eq=False, init=False) uuid: UUID = attr.ib(factory=lambda: uuid4().hex, eq=False, init=False)
@attr.s(frozen=True, slots=True)
class HealthChanged:
"""Describe change in system health."""
healthy: bool = attr.ib()
unhealthy_reasons: list[UnhealthyReason] | None = attr.ib(default=None)
@attr.s(frozen=True, slots=True)
class SupportedChanged:
"""Describe change in system supported."""
supported: bool = attr.ib()
unsupported_reasons: list[UnsupportedReason] | None = attr.ib(default=None)

View File

@ -18,7 +18,7 @@ from .const import (
UnhealthyReason, UnhealthyReason,
UnsupportedReason, UnsupportedReason,
) )
from .data import Issue, Suggestion from .data import HealthChanged, Issue, Suggestion, SupportedChanged
from .evaluate import ResolutionEvaluation from .evaluate import ResolutionEvaluation
from .fixup import ResolutionFixup from .fixup import ResolutionFixup
from .notify import ResolutionNotify from .notify import ResolutionNotify
@ -125,6 +125,10 @@ class ResolutionManager(FileConfiguration, CoreSysAttributes):
"""Add a reason for unsupported.""" """Add a reason for unsupported."""
if reason not in self._unsupported: if reason not in self._unsupported:
self._unsupported.append(reason) self._unsupported.append(reason)
self.sys_homeassistant.websocket.supervisor_event(
WSEvent.SUPPORTED_CHANGED,
attr.asdict(SupportedChanged(False, self.unsupported)),
)
@property @property
def unhealthy(self) -> list[UnhealthyReason]: def unhealthy(self) -> list[UnhealthyReason]:
@ -136,6 +140,10 @@ class ResolutionManager(FileConfiguration, CoreSysAttributes):
"""Add a reason for unsupported.""" """Add a reason for unsupported."""
if reason not in self._unhealthy: if reason not in self._unhealthy:
self._unhealthy.append(reason) self._unhealthy.append(reason)
self.sys_homeassistant.websocket.supervisor_event(
WSEvent.HEALTH_CHANGED,
attr.asdict(HealthChanged(False, self.unhealthy)),
)
def get_suggestion(self, uuid: str) -> Suggestion: def get_suggestion(self, uuid: str) -> Suggestion:
"""Return suggestion with uuid.""" """Return suggestion with uuid."""
@ -228,6 +236,12 @@ class ResolutionManager(FileConfiguration, CoreSysAttributes):
if reason not in self._unsupported: if reason not in self._unsupported:
raise ResolutionError(f"The reason {reason} is not active", _LOGGER.warning) raise ResolutionError(f"The reason {reason} is not active", _LOGGER.warning)
self._unsupported.remove(reason) self._unsupported.remove(reason)
self.sys_homeassistant.websocket.supervisor_event(
WSEvent.SUPPORTED_CHANGED,
attr.asdict(
SupportedChanged(self.sys_core.supported, self.unsupported or None)
),
)
def suggestions_for_issue(self, issue: Issue) -> set[Suggestion]: def suggestions_for_issue(self, issue: Issue) -> set[Suggestion]:
"""Get suggestions that fix an issue.""" """Get suggestions that fix an issue."""

View File

@ -240,7 +240,7 @@ async def test_host_connectivity_disabled(coresys: CoreSys):
await asyncio.sleep(0) await asyncio.sleep(0)
assert coresys.host.network.connectivity is True assert coresys.host.network.connectivity is True
await asyncio.sleep(0) await asyncio.sleep(0)
client.async_send_command.assert_called_once_with( client.async_send_command.assert_called_with(
{ {
"type": WSType.SUPERVISOR_EVENT, "type": WSType.SUPERVISOR_EVENT,
"data": { "data": {

View File

@ -261,3 +261,106 @@ async def test_resolution_apply_suggestion_multiple_copies(coresys: CoreSys):
assert remove_store_1 in coresys.resolution.suggestions assert remove_store_1 in coresys.resolution.suggestions
assert remove_store_2 not in coresys.resolution.suggestions assert remove_store_2 not in coresys.resolution.suggestions
assert remove_store_3 in coresys.resolution.suggestions assert remove_store_3 in coresys.resolution.suggestions
async def test_events_on_unsupported_changed(coresys: CoreSys):
"""Test events fired when unsupported changes."""
with patch.object(
type(coresys.homeassistant.websocket), "async_send_message"
) as send_message:
# Marking system as unsupported tells HA
assert coresys.resolution.unsupported == []
coresys.resolution.unsupported = UnsupportedReason.CONNECTIVITY_CHECK
await asyncio.sleep(0)
assert coresys.resolution.unsupported == [UnsupportedReason.CONNECTIVITY_CHECK]
send_message.assert_called_once_with(
_supervisor_event_message(
"supported_changed",
{"supported": False, "unsupported_reasons": ["connectivity_check"]},
)
)
# Adding the same reason again does nothing
send_message.reset_mock()
coresys.resolution.unsupported = UnsupportedReason.CONNECTIVITY_CHECK
await asyncio.sleep(0)
assert coresys.resolution.unsupported == [UnsupportedReason.CONNECTIVITY_CHECK]
send_message.assert_not_called()
# Adding and removing additional reasons tells HA unsupported reasons changed
coresys.resolution.unsupported = UnsupportedReason.JOB_CONDITIONS
await asyncio.sleep(0)
assert coresys.resolution.unsupported == [
UnsupportedReason.CONNECTIVITY_CHECK,
UnsupportedReason.JOB_CONDITIONS,
]
send_message.assert_called_once_with(
_supervisor_event_message(
"supported_changed",
{
"supported": False,
"unsupported_reasons": ["connectivity_check", "job_conditions"],
},
)
)
send_message.reset_mock()
coresys.resolution.dismiss_unsupported(UnsupportedReason.CONNECTIVITY_CHECK)
await asyncio.sleep(0)
assert coresys.resolution.unsupported == [UnsupportedReason.JOB_CONDITIONS]
send_message.assert_called_once_with(
_supervisor_event_message(
"supported_changed",
{"supported": False, "unsupported_reasons": ["job_conditions"]},
)
)
# Dismissing all unsupported reasons tells HA its supported again
send_message.reset_mock()
coresys.resolution.dismiss_unsupported(UnsupportedReason.JOB_CONDITIONS)
await asyncio.sleep(0)
assert coresys.resolution.unsupported == []
send_message.assert_called_once_with(
_supervisor_event_message(
"supported_changed", {"supported": True, "unsupported_reasons": None}
)
)
async def test_events_on_unhealthy_changed(coresys: CoreSys):
"""Test events fired when unhealthy changes."""
with patch.object(
type(coresys.homeassistant.websocket), "async_send_message"
) as send_message:
# Marking system as unhealthy tells HA
assert coresys.resolution.unhealthy == []
coresys.resolution.unhealthy = UnhealthyReason.DOCKER
await asyncio.sleep(0)
assert coresys.resolution.unhealthy == [UnhealthyReason.DOCKER]
send_message.assert_called_once_with(
_supervisor_event_message(
"health_changed",
{"healthy": False, "unhealthy_reasons": ["docker"]},
)
)
# Adding the same reason again does nothing
send_message.reset_mock()
coresys.resolution.unhealthy = UnhealthyReason.DOCKER
await asyncio.sleep(0)
assert coresys.resolution.unhealthy == [UnhealthyReason.DOCKER]
send_message.assert_not_called()
# Adding an additional reason tells HA unhealthy reasons changed
coresys.resolution.unhealthy = UnhealthyReason.UNTRUSTED
await asyncio.sleep(0)
assert coresys.resolution.unhealthy == [
UnhealthyReason.DOCKER,
UnhealthyReason.UNTRUSTED,
]
send_message.assert_called_once_with(
_supervisor_event_message(
"health_changed",
{"healthy": False, "unhealthy_reasons": ["docker", "untrusted"]},
)
)