323 lines
10 KiB
Python
323 lines
10 KiB
Python
"""Test repairs for synology dsm."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import AsyncMock, MagicMock, Mock, patch
|
|
|
|
import pytest
|
|
from synology_dsm.api.file_station.models import SynoFileSharedFolder
|
|
|
|
from homeassistant.components.repairs import DOMAIN as REPAIRS_DOMAIN
|
|
from homeassistant.components.synology_dsm.const import (
|
|
CONF_BACKUP_PATH,
|
|
CONF_BACKUP_SHARE,
|
|
DOMAIN,
|
|
)
|
|
from homeassistant.const import (
|
|
CONF_HOST,
|
|
CONF_MAC,
|
|
CONF_PASSWORD,
|
|
CONF_PORT,
|
|
CONF_SSL,
|
|
CONF_USERNAME,
|
|
)
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers import issue_registry as ir
|
|
from homeassistant.setup import async_setup_component
|
|
|
|
from .common import mock_dsm_information
|
|
from .consts import HOST, MACS, PASSWORD, PORT, USE_SSL, USERNAME
|
|
|
|
from tests.common import ANY, MockConfigEntry
|
|
from tests.components.repairs import process_repair_fix_flow, start_repair_fix_flow
|
|
from tests.typing import ClientSessionGenerator, WebSocketGenerator
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_dsm_with_filestation():
|
|
"""Mock a successful service with filestation support."""
|
|
with patch("homeassistant.components.synology_dsm.common.SynologyDSM") as dsm:
|
|
dsm.login = AsyncMock(return_value=True)
|
|
dsm.update = AsyncMock(return_value=True)
|
|
|
|
dsm.surveillance_station.update = AsyncMock(return_value=True)
|
|
dsm.upgrade.update = AsyncMock(return_value=True)
|
|
dsm.utilisation = Mock(cpu_user_load=1, update=AsyncMock(return_value=True))
|
|
dsm.network = Mock(update=AsyncMock(return_value=True), macs=MACS)
|
|
dsm.storage = Mock(
|
|
disks_ids=["sda", "sdb", "sdc"],
|
|
volumes_ids=["volume_1"],
|
|
update=AsyncMock(return_value=True),
|
|
)
|
|
dsm.information = mock_dsm_information()
|
|
dsm.file = AsyncMock(
|
|
get_shared_folders=AsyncMock(
|
|
return_value=[
|
|
SynoFileSharedFolder(
|
|
additional=None,
|
|
is_dir=True,
|
|
name="HA Backup",
|
|
path="/ha_backup",
|
|
)
|
|
]
|
|
),
|
|
)
|
|
dsm.logout = AsyncMock(return_value=True)
|
|
yield dsm
|
|
|
|
|
|
@pytest.fixture
|
|
async def setup_dsm_with_filestation(
|
|
hass: HomeAssistant,
|
|
mock_dsm_with_filestation: MagicMock,
|
|
):
|
|
"""Mock setup of synology dsm config entry."""
|
|
with (
|
|
patch(
|
|
"homeassistant.components.synology_dsm.common.SynologyDSM",
|
|
return_value=mock_dsm_with_filestation,
|
|
),
|
|
patch("homeassistant.components.synology_dsm.PLATFORMS", return_value=[]),
|
|
):
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_HOST: HOST,
|
|
CONF_PORT: PORT,
|
|
CONF_SSL: USE_SSL,
|
|
CONF_USERNAME: USERNAME,
|
|
CONF_PASSWORD: PASSWORD,
|
|
CONF_MAC: MACS[0],
|
|
},
|
|
options={
|
|
CONF_BACKUP_PATH: None,
|
|
CONF_BACKUP_SHARE: None,
|
|
},
|
|
unique_id="my_serial",
|
|
)
|
|
entry.add_to_hass(hass)
|
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
|
assert await async_setup_component(hass, REPAIRS_DOMAIN, {})
|
|
await hass.async_block_till_done()
|
|
|
|
yield mock_dsm_with_filestation
|
|
|
|
|
|
async def test_create_issue(
|
|
hass: HomeAssistant,
|
|
setup_dsm_with_filestation: MagicMock,
|
|
hass_ws_client: WebSocketGenerator,
|
|
) -> None:
|
|
"""Test the issue is created."""
|
|
ws_client = await hass_ws_client(hass)
|
|
await ws_client.send_json({"id": 1, "type": "repairs/list_issues"})
|
|
msg = await ws_client.receive_json()
|
|
|
|
assert msg["success"]
|
|
assert len(msg["result"]["issues"]) == 1
|
|
issue = msg["result"]["issues"][0]
|
|
assert issue["breaks_in_ha_version"] is None
|
|
assert issue["domain"] == DOMAIN
|
|
assert issue["issue_id"] == "missing_backup_setup_my_serial"
|
|
assert issue["translation_key"] == "missing_backup_setup"
|
|
|
|
|
|
async def test_missing_backup_ignore(
|
|
hass: HomeAssistant,
|
|
setup_dsm_with_filestation: MagicMock,
|
|
hass_client: ClientSessionGenerator,
|
|
hass_ws_client: WebSocketGenerator,
|
|
) -> None:
|
|
"""Test missing backup location setup issue is ignored by the user."""
|
|
ws_client = await hass_ws_client(hass)
|
|
client = await hass_client()
|
|
|
|
# get repair issues
|
|
await ws_client.send_json({"id": 1, "type": "repairs/list_issues"})
|
|
msg = await ws_client.receive_json()
|
|
assert msg["success"]
|
|
assert len(msg["result"]["issues"]) == 1
|
|
issue = msg["result"]["issues"][0]
|
|
assert not issue["ignored"]
|
|
|
|
# start repair flow
|
|
data = await start_repair_fix_flow(client, DOMAIN, "missing_backup_setup_my_serial")
|
|
|
|
flow_id = data["flow_id"]
|
|
assert data["description_placeholders"] == {
|
|
"docs_url": "https://www.home-assistant.io/integrations/synology_dsm/#backup-location"
|
|
}
|
|
assert data["step_id"] == "init"
|
|
assert data["menu_options"] == ["confirm", "ignore"]
|
|
|
|
# seelct to ignore the flow
|
|
data = await process_repair_fix_flow(
|
|
client, flow_id, json={"next_step_id": "ignore"}
|
|
)
|
|
assert data["type"] == "abort"
|
|
assert data["reason"] == "ignored"
|
|
|
|
# check issue is ignored
|
|
await ws_client.send_json({"id": 2, "type": "repairs/list_issues"})
|
|
msg = await ws_client.receive_json()
|
|
assert msg["success"]
|
|
assert len(msg["result"]["issues"]) == 1
|
|
issue = msg["result"]["issues"][0]
|
|
assert issue["ignored"]
|
|
|
|
|
|
async def test_missing_backup_success(
|
|
hass: HomeAssistant,
|
|
setup_dsm_with_filestation: MagicMock,
|
|
hass_client: ClientSessionGenerator,
|
|
hass_ws_client: WebSocketGenerator,
|
|
) -> None:
|
|
"""Test the missing backup location setup repair flow is fully processed by the user."""
|
|
ws_client = await hass_ws_client(hass)
|
|
client = await hass_client()
|
|
entries = hass.config_entries.async_entries(DOMAIN)
|
|
assert len(entries) == 1
|
|
entry = entries[0]
|
|
assert entry.options == {"backup_path": None, "backup_share": None}
|
|
|
|
# get repair issues
|
|
await ws_client.send_json({"id": 1, "type": "repairs/list_issues"})
|
|
msg = await ws_client.receive_json()
|
|
assert msg["success"]
|
|
assert len(msg["result"]["issues"]) == 1
|
|
issue = msg["result"]["issues"][0]
|
|
assert not issue["ignored"]
|
|
|
|
# start repair flow
|
|
data = await start_repair_fix_flow(client, DOMAIN, "missing_backup_setup_my_serial")
|
|
|
|
flow_id = data["flow_id"]
|
|
assert data["description_placeholders"] == {
|
|
"docs_url": "https://www.home-assistant.io/integrations/synology_dsm/#backup-location"
|
|
}
|
|
assert data["step_id"] == "init"
|
|
assert data["menu_options"] == ["confirm", "ignore"]
|
|
|
|
# seelct to confirm the flow
|
|
data = await process_repair_fix_flow(
|
|
client, flow_id, json={"next_step_id": "confirm"}
|
|
)
|
|
assert data["step_id"] == "confirm"
|
|
assert data["type"] == "form"
|
|
|
|
# fill out the form and submit
|
|
data = await process_repair_fix_flow(
|
|
client,
|
|
flow_id,
|
|
json={"backup_share": "/ha_backup", "backup_path": "backup_ha_dev"},
|
|
)
|
|
assert data["type"] == "create_entry"
|
|
assert entry.options == {
|
|
"backup_path": "backup_ha_dev",
|
|
"backup_share": "/ha_backup",
|
|
}
|
|
|
|
|
|
async def test_missing_backup_no_shares(
|
|
hass: HomeAssistant,
|
|
setup_dsm_with_filestation: MagicMock,
|
|
hass_client: ClientSessionGenerator,
|
|
hass_ws_client: WebSocketGenerator,
|
|
) -> None:
|
|
"""Test the missing backup location setup repair flow errors out."""
|
|
ws_client = await hass_ws_client(hass)
|
|
client = await hass_client()
|
|
|
|
# get repair issues
|
|
await ws_client.send_json({"id": 1, "type": "repairs/list_issues"})
|
|
msg = await ws_client.receive_json()
|
|
assert msg["success"]
|
|
assert len(msg["result"]["issues"]) == 1
|
|
|
|
# start repair flow
|
|
data = await start_repair_fix_flow(client, DOMAIN, "missing_backup_setup_my_serial")
|
|
|
|
flow_id = data["flow_id"]
|
|
assert data["description_placeholders"] == {
|
|
"docs_url": "https://www.home-assistant.io/integrations/synology_dsm/#backup-location"
|
|
}
|
|
assert data["step_id"] == "init"
|
|
assert data["menu_options"] == ["confirm", "ignore"]
|
|
|
|
# inject error
|
|
setup_dsm_with_filestation.file.get_shared_folders.return_value = []
|
|
|
|
# select to confirm the flow
|
|
data = await process_repair_fix_flow(
|
|
client, flow_id, json={"next_step_id": "confirm"}
|
|
)
|
|
assert data["type"] == "abort"
|
|
assert data["reason"] == "no_shares"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"ignore_missing_translations",
|
|
["component.synology_dsm.issues.other_issue.title"],
|
|
)
|
|
async def test_other_fixable_issues(
|
|
hass: HomeAssistant,
|
|
setup_dsm_with_filestation: MagicMock,
|
|
hass_client: ClientSessionGenerator,
|
|
hass_ws_client: WebSocketGenerator,
|
|
) -> None:
|
|
"""Test fixing another issue."""
|
|
ws_client = await hass_ws_client(hass)
|
|
client = await hass_client()
|
|
|
|
await ws_client.send_json({"id": 1, "type": "repairs/list_issues"})
|
|
msg = await ws_client.receive_json()
|
|
|
|
assert msg["success"]
|
|
|
|
issue = {
|
|
"breaks_in_ha_version": None,
|
|
"domain": DOMAIN,
|
|
"issue_id": "other_issue",
|
|
"is_fixable": True,
|
|
"severity": "error",
|
|
"translation_key": "other_issue",
|
|
}
|
|
ir.async_create_issue(
|
|
hass,
|
|
issue["domain"],
|
|
issue["issue_id"],
|
|
is_fixable=issue["is_fixable"],
|
|
severity=issue["severity"],
|
|
translation_key=issue["translation_key"],
|
|
)
|
|
|
|
await ws_client.send_json({"id": 2, "type": "repairs/list_issues"})
|
|
msg = await ws_client.receive_json()
|
|
|
|
assert msg["success"]
|
|
results = msg["result"]["issues"]
|
|
assert {
|
|
"breaks_in_ha_version": None,
|
|
"created": ANY,
|
|
"dismissed_version": None,
|
|
"domain": "synology_dsm",
|
|
"ignored": False,
|
|
"is_fixable": True,
|
|
"issue_domain": None,
|
|
"issue_id": "other_issue",
|
|
"learn_more_url": None,
|
|
"severity": "error",
|
|
"translation_key": "other_issue",
|
|
"translation_placeholders": None,
|
|
} in results
|
|
|
|
data = await start_repair_fix_flow(client, DOMAIN, "other_issue")
|
|
|
|
flow_id = data["flow_id"]
|
|
assert data["step_id"] == "confirm"
|
|
|
|
data = await process_repair_fix_flow(client, flow_id)
|
|
|
|
assert data["type"] == "create_entry"
|
|
await hass.async_block_till_done()
|