core/tests/components/unifi/test_update.py

214 lines
6.7 KiB
Python

"""The tests for the UniFi Network update platform."""
from copy import deepcopy
from aiounifi.models.message import MessageKey
from aiounifi.websocket import WebsocketState
from yarl import URL
from homeassistant.components.unifi.const import CONF_SITE_ID
from homeassistant.components.update import (
ATTR_IN_PROGRESS,
ATTR_INSTALLED_VERSION,
ATTR_LATEST_VERSION,
DOMAIN as UPDATE_DOMAIN,
SERVICE_INSTALL,
UpdateDeviceClass,
UpdateEntityFeature,
)
from homeassistant.const import (
ATTR_DEVICE_CLASS,
ATTR_ENTITY_ID,
ATTR_SUPPORTED_FEATURES,
CONF_HOST,
STATE_OFF,
STATE_ON,
STATE_UNAVAILABLE,
)
from homeassistant.core import HomeAssistant
from .test_controller import DESCRIPTION, setup_unifi_integration
from tests.test_util.aiohttp import AiohttpClientMocker
DEVICE_1 = {
"board_rev": 3,
"device_id": "mock-id",
"ip": "10.0.1.1",
"last_seen": 1562600145,
"mac": "00:00:00:00:01:01",
"model": "US16P150",
"name": "Device 1",
"next_interval": 20,
"state": 1,
"type": "usw",
"upgradable": True,
"version": "4.0.42.10433",
"upgrade_to_firmware": "4.3.17.11279",
}
DEVICE_2 = {
"board_rev": 3,
"device_id": "mock-id",
"ip": "10.0.1.2",
"mac": "00:00:00:00:01:02",
"model": "US16P150",
"name": "Device 2",
"next_interval": 20,
"state": 0,
"type": "usw",
"version": "4.0.42.10433",
}
async def test_no_entities(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test the update_clients function when no clients are found."""
await setup_unifi_integration(hass, aioclient_mock)
assert len(hass.states.async_entity_ids(UPDATE_DOMAIN)) == 0
async def test_device_updates(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, mock_unifi_websocket
) -> None:
"""Test the update_items function with some devices."""
device_1 = deepcopy(DEVICE_1)
await setup_unifi_integration(
hass,
aioclient_mock,
devices_response=[device_1, DEVICE_2],
)
assert len(hass.states.async_entity_ids(UPDATE_DOMAIN)) == 2
device_1_state = hass.states.get("update.device_1")
assert device_1_state.state == STATE_ON
assert device_1_state.attributes[ATTR_INSTALLED_VERSION] == "4.0.42.10433"
assert device_1_state.attributes[ATTR_LATEST_VERSION] == "4.3.17.11279"
assert device_1_state.attributes[ATTR_IN_PROGRESS] is False
assert device_1_state.attributes[ATTR_DEVICE_CLASS] == UpdateDeviceClass.FIRMWARE
assert (
device_1_state.attributes[ATTR_SUPPORTED_FEATURES]
== UpdateEntityFeature.PROGRESS | UpdateEntityFeature.INSTALL
)
device_2_state = hass.states.get("update.device_2")
assert device_2_state.state == STATE_OFF
assert device_2_state.attributes[ATTR_INSTALLED_VERSION] == "4.0.42.10433"
assert device_2_state.attributes[ATTR_LATEST_VERSION] == "4.0.42.10433"
assert device_2_state.attributes[ATTR_IN_PROGRESS] is False
assert device_2_state.attributes[ATTR_DEVICE_CLASS] == UpdateDeviceClass.FIRMWARE
assert (
device_2_state.attributes[ATTR_SUPPORTED_FEATURES]
== UpdateEntityFeature.PROGRESS | UpdateEntityFeature.INSTALL
)
# Simulate start of update
device_1["state"] = 4
mock_unifi_websocket(message=MessageKey.DEVICE, data=device_1)
await hass.async_block_till_done()
device_1_state = hass.states.get("update.device_1")
assert device_1_state.state == STATE_ON
assert device_1_state.attributes[ATTR_INSTALLED_VERSION] == "4.0.42.10433"
assert device_1_state.attributes[ATTR_LATEST_VERSION] == "4.3.17.11279"
assert device_1_state.attributes[ATTR_IN_PROGRESS] is True
# Simulate update finished
device_1["state"] = "0"
device_1["version"] = "4.3.17.11279"
device_1["upgradable"] = False
del device_1["upgrade_to_firmware"]
mock_unifi_websocket(message=MessageKey.DEVICE, data=device_1)
await hass.async_block_till_done()
device_1_state = hass.states.get("update.device_1")
assert device_1_state.state == STATE_OFF
assert device_1_state.attributes[ATTR_INSTALLED_VERSION] == "4.3.17.11279"
assert device_1_state.attributes[ATTR_LATEST_VERSION] == "4.3.17.11279"
assert device_1_state.attributes[ATTR_IN_PROGRESS] is False
async def test_not_admin(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test that the INSTALL feature is not available on a non-admin account."""
description = deepcopy(DESCRIPTION)
description[0]["site_role"] = "not admin"
await setup_unifi_integration(
hass,
aioclient_mock,
site_description=description,
devices_response=[DEVICE_1],
)
assert len(hass.states.async_entity_ids(UPDATE_DOMAIN)) == 1
device_state = hass.states.get("update.device_1")
assert device_state.state == STATE_ON
assert (
device_state.attributes[ATTR_SUPPORTED_FEATURES] == UpdateEntityFeature.PROGRESS
)
async def test_install(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test the device update install call."""
config_entry = await setup_unifi_integration(
hass, aioclient_mock, devices_response=[DEVICE_1]
)
assert len(hass.states.async_entity_ids(UPDATE_DOMAIN)) == 1
device_state = hass.states.get("update.device_1")
assert device_state.state == STATE_ON
url = f"https://{config_entry.data[CONF_HOST]}:1234/api/s/{config_entry.data[CONF_SITE_ID]}/cmd/devmgr"
aioclient_mock.clear_requests()
aioclient_mock.post(url)
await hass.services.async_call(
UPDATE_DOMAIN,
SERVICE_INSTALL,
{ATTR_ENTITY_ID: "update.device_1"},
blocking=True,
)
await hass.async_block_till_done()
assert aioclient_mock.call_count == 1
assert aioclient_mock.mock_calls[0] == (
"post",
URL(url),
{"cmd": "upgrade", "mac": "00:00:00:00:01:01"},
{},
)
async def test_controller_state_change(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, mock_unifi_websocket
) -> None:
"""Verify entities state reflect on controller becoming unavailable."""
await setup_unifi_integration(
hass,
aioclient_mock,
devices_response=[DEVICE_1],
)
assert len(hass.states.async_entity_ids(UPDATE_DOMAIN)) == 1
assert hass.states.get("update.device_1").state == STATE_ON
# Controller unavailable
mock_unifi_websocket(state=WebsocketState.DISCONNECTED)
await hass.async_block_till_done()
assert hass.states.get("update.device_1").state == STATE_UNAVAILABLE
# Controller available
mock_unifi_websocket(state=WebsocketState.RUNNING)
await hass.async_block_till_done()
assert hass.states.get("update.device_1").state == STATE_ON