Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions homeassistant/components/hassio/issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
"issue_system_disk_lifetime",
ISSUE_KEY_SYSTEM_FREE_SPACE,
ISSUE_KEY_ADDON_PWNED,
"issue_system_ntp_sync_failed",
}

_LOGGER = logging.getLogger(__name__)
Expand Down
13 changes: 13 additions & 0 deletions homeassistant/components/hassio/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,19 @@
},
"title": "Multiple data disks detected"
},
"issue_system_ntp_sync_failed": {
"fix_flow": {
"abort": {
"apply_suggestion_fail": "Could not re-enable NTP. Check the Supervisor logs for more details."
},
"step": {
"system_enable_ntp": {
"description": "The device could not contact its configured time servers (NTP). Using a secondary online time check, we detected that the system clock was more than 1 hour incorrect. The time has been corrected and the NTP service was temporarily disabled so the correction could be applied. To keep the system time accurate, we recommend fixing the issue preventing access to the NTP servers.\n\nCheck the **Host logs** to investigate why NTP servers could not be reached. Once resolved, select **Submit** to re-enable the NTP service."
}
}
},
"title": "Time synchronization issue detected"
},
"issue_system_reboot_required": {
"fix_flow": {
"abort": {
Expand Down
55 changes: 55 additions & 0 deletions tests/components/hassio/test_issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,61 @@ async def test_supervisor_issues_detached_addon_missing(
)


@pytest.mark.usefixtures("all_setup_requests")
async def test_supervisor_issues_ntp_sync_failed(
hass: HomeAssistant,
supervisor_client: AsyncMock,
hass_ws_client: WebSocketGenerator,
) -> None:
"""Test supervisor issue for NTP sync failed."""
mock_resolution_info(supervisor_client)

result = await async_setup_component(hass, "hassio", {})
assert result

client = await hass_ws_client(hass)

await client.send_json(
{
"id": 1,
"type": "supervisor/event",
"data": {
"event": "issue_changed",
"data": {
"uuid": (issue_uuid := uuid4().hex),
"type": "ntp_sync_failed",
"context": "system",
"reference": None,
"suggestions": [
{
"uuid": uuid4().hex,
"type": "enable_ntp",
"context": "system",
"reference": None,
}
],
},
},
}
)
msg = await client.receive_json()
assert msg["success"]
await hass.async_block_till_done()

await client.send_json({"id": 2, "type": "repairs/list_issues"})
msg = await client.receive_json()
assert msg["success"]
assert len(msg["result"]["issues"]) == 1
assert_issue_repair_in_list(
msg["result"]["issues"],
uuid=issue_uuid,
context="system",
type_="ntp_sync_failed",
fixable=True,
placeholders=None,
)


@pytest.mark.usefixtures("all_setup_requests")
async def test_supervisor_issues_disk_lifetime(
hass: HomeAssistant,
Expand Down
146 changes: 146 additions & 0 deletions tests/components/hassio/test_repairs.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,152 @@ async def test_supervisor_issue_repair_flow_skip_confirmation(
supervisor_client.resolution.apply_suggestion.assert_called_once_with(sugg_uuid)


@pytest.mark.usefixtures("all_setup_requests")
async def test_supervisor_issue_ntp_sync_failed_repair_flow(
hass: HomeAssistant,
supervisor_client: AsyncMock,
hass_client: ClientSessionGenerator,
issue_registry: ir.IssueRegistry,
) -> None:
"""Test fix flow for NTP sync failed supervisor issue."""
mock_resolution_info(
supervisor_client,
issues=[
Issue(
type=IssueType.NTP_SYNC_FAILED,
context=ContextType.SYSTEM,
reference=None,
uuid=(issue_uuid := uuid4()),
),
],
suggestions_by_issue={
issue_uuid: [
Suggestion(
type=SuggestionType.ENABLE_NTP,
context=ContextType.SYSTEM,
reference=None,
uuid=(sugg_uuid := uuid4()),
auto=False,
),
]
},
)

assert await async_setup_component(hass, "hassio", {})

repair_issue = issue_registry.async_get_issue(
domain="hassio", issue_id=issue_uuid.hex
)
assert repair_issue

client = await hass_client()

resp = await client.post(
"/api/repairs/issues/fix",
json={"handler": "hassio", "issue_id": repair_issue.issue_id},
)

assert resp.status == HTTPStatus.OK
data = await resp.json()

flow_id = data["flow_id"]
assert data == {
"type": "form",
"flow_id": flow_id,
"handler": "hassio",
"step_id": "system_enable_ntp",
"data_schema": [],
"errors": None,
"description_placeholders": None,
"last_step": True,
"preview": None,
}

resp = await client.post(f"/api/repairs/issues/fix/{flow_id}")

assert resp.status == HTTPStatus.OK
data = await resp.json()

flow_id = data["flow_id"]
assert data == {
"type": "create_entry",
"flow_id": flow_id,
"handler": "hassio",
"description": None,
"description_placeholders": None,
}

assert not issue_registry.async_get_issue(domain="hassio", issue_id=issue_uuid.hex)
supervisor_client.resolution.apply_suggestion.assert_called_once_with(sugg_uuid)


@pytest.mark.usefixtures("all_setup_requests")
async def test_supervisor_issue_ntp_sync_failed_repair_flow_error(
hass: HomeAssistant,
supervisor_client: AsyncMock,
hass_client: ClientSessionGenerator,
issue_registry: ir.IssueRegistry,
) -> None:
"""Test fix flow aborts when NTP re-enable fails."""
mock_resolution_info(
supervisor_client,
issues=[
Issue(
type=IssueType.NTP_SYNC_FAILED,
context=ContextType.SYSTEM,
reference=None,
uuid=(issue_uuid := uuid4()),
),
],
suggestions_by_issue={
issue_uuid: [
Suggestion(
type=SuggestionType.ENABLE_NTP,
context=ContextType.SYSTEM,
reference=None,
uuid=uuid4(),
auto=False,
),
]
},
suggestion_result=SupervisorError("boom"),
)

assert await async_setup_component(hass, "hassio", {})

repair_issue = issue_registry.async_get_issue(
domain="hassio", issue_id=issue_uuid.hex
)
assert repair_issue

client = await hass_client()

resp = await client.post(
"/api/repairs/issues/fix",
json={"handler": "hassio", "issue_id": repair_issue.issue_id},
)

assert resp.status == HTTPStatus.OK
data = await resp.json()
flow_id = data["flow_id"]

resp = await client.post(f"/api/repairs/issues/fix/{flow_id}")

assert resp.status == HTTPStatus.OK
data = await resp.json()

flow_id = data["flow_id"]
assert data == {
"type": "abort",
"flow_id": flow_id,
"handler": "hassio",
"reason": "apply_suggestion_fail",
"description_placeholders": None,
}

assert issue_registry.async_get_issue(domain="hassio", issue_id=issue_uuid.hex)


@pytest.mark.usefixtures("all_setup_requests")
async def test_mount_failed_repair_flow_error(
hass: HomeAssistant,
Expand Down