core/tests/components/smlight/test_update.py
TimL e9364f4c3a
Add update platform for Smlight integration (#125943)
* Create update coordinator for update entities

* fix type errors

* update info fixture with zigbee version

* Add fixtures for Firmware objects

* mock get_firmware_version function

* Add update platform for Smlight integration

* Add strings for update platform

* Add tests for update platform

* add snapshot for update tests

* Split out base coordinator

* Update homeassistant/components/smlight/strings.json

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

* overwrite coordinator types

---------

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2024-09-16 14:14:15 +02:00

235 lines
6.5 KiB
Python

"""Tests for the SMLIGHT update platform."""
from collections.abc import Callable
from unittest.mock import MagicMock
from freezegun.api import FrozenDateTimeFactory
from pysmlight import Firmware, Info
from pysmlight.const import Events as SmEvents
from pysmlight.sse import MessageEvent
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.components.smlight.const import SCAN_FIRMWARE_INTERVAL
from homeassistant.components.update import (
ATTR_IN_PROGRESS,
ATTR_INSTALLED_VERSION,
ATTR_LATEST_VERSION,
DOMAIN as PLATFORM,
SERVICE_INSTALL,
)
from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er
from .conftest import setup_integration
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
from tests.typing import WebSocketGenerator
pytestmark = [
pytest.mark.usefixtures(
"mock_smlight_client",
)
]
MOCK_FIRMWARE_DONE = MessageEvent(
type="FW_UPD_done",
message="FW_UPD_done",
data="",
origin="http://slzb-06p10.local",
last_event_id="",
)
MOCK_FIRMWARE_PROGRESS = MessageEvent(
type="ZB_FW_prgs",
message="ZB_FW_prgs",
data="50",
origin="http://slzb-06p10.local",
last_event_id="",
)
MOCK_FIRMWARE_FAIL = MessageEvent(
type="ZB_FW_err",
message="ZB_FW_err",
data="",
origin="http://slzb-06p10.local",
last_event_id="",
)
MOCK_FIRMWARE_NOTES = [
Firmware(
ver="v2.3.6",
mode="ESP",
notes=None,
)
]
def get_callback_function(mock: MagicMock, trigger: SmEvents):
"""Extract the callback function for a given trigger."""
return next(
(
call_args[0][1]
for call_args in mock.sse.register_callback.call_args_list
if trigger == call_args[0][0]
),
None,
)
@pytest.fixture
def platforms() -> list[Platform]:
"""Platforms, which should be loaded during the test."""
return [Platform.UPDATE]
async def test_update_setup(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_config_entry: MockConfigEntry,
snapshot: SnapshotAssertion,
) -> None:
"""Test setup of SMLIGHT switches."""
entry = await setup_integration(hass, mock_config_entry)
await snapshot_platform(hass, entity_registry, snapshot, entry.entry_id)
await hass.config_entries.async_unload(entry.entry_id)
async def test_update_firmware(
hass: HomeAssistant,
freezer: FrozenDateTimeFactory,
mock_config_entry: MockConfigEntry,
mock_smlight_client: MagicMock,
) -> None:
"""Test firmware updates."""
await setup_integration(hass, mock_config_entry)
entity_id = "update.mock_title_core_firmware"
state = hass.states.get(entity_id)
assert state.state == STATE_ON
assert state.attributes[ATTR_INSTALLED_VERSION] == "v2.3.6"
assert state.attributes[ATTR_LATEST_VERSION] == "v2.5.2"
await hass.services.async_call(
PLATFORM,
SERVICE_INSTALL,
{ATTR_ENTITY_ID: entity_id},
blocking=False,
)
assert len(mock_smlight_client.fw_update.mock_calls) == 1
event_function: Callable[[MessageEvent], None] = get_callback_function(
mock_smlight_client, SmEvents.ZB_FW_prgs
)
async def _call_event_function(event: MessageEvent):
event_function(event)
await _call_event_function(MOCK_FIRMWARE_PROGRESS)
state = hass.states.get(entity_id)
assert state.attributes[ATTR_IN_PROGRESS] == 50
event_function: Callable[[MessageEvent], None] = get_callback_function(
mock_smlight_client, SmEvents.FW_UPD_done
)
await _call_event_function(MOCK_FIRMWARE_DONE)
mock_smlight_client.get_info.return_value = Info(
sw_version="v2.5.2",
)
freezer.tick(SCAN_FIRMWARE_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == STATE_OFF
assert state.attributes[ATTR_INSTALLED_VERSION] == "v2.5.2"
assert state.attributes[ATTR_LATEST_VERSION] == "v2.5.2"
async def test_update_firmware_failed(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_smlight_client: MagicMock,
) -> None:
"""Test firmware updates."""
await setup_integration(hass, mock_config_entry)
entity_id = "update.mock_title_core_firmware"
state = hass.states.get(entity_id)
assert state.state == STATE_ON
assert state.attributes[ATTR_INSTALLED_VERSION] == "v2.3.6"
assert state.attributes[ATTR_LATEST_VERSION] == "v2.5.2"
await hass.services.async_call(
PLATFORM,
SERVICE_INSTALL,
{ATTR_ENTITY_ID: entity_id},
blocking=False,
)
assert len(mock_smlight_client.fw_update.mock_calls) == 1
event_function: Callable[[MessageEvent], None] = get_callback_function(
mock_smlight_client, SmEvents.ZB_FW_err
)
async def _call_event_function(event: MessageEvent):
event_function(event)
with pytest.raises(HomeAssistantError):
await _call_event_function(MOCK_FIRMWARE_FAIL)
state = hass.states.get(entity_id)
assert state.attributes[ATTR_IN_PROGRESS] is False
async def test_update_release_notes(
hass: HomeAssistant,
freezer: FrozenDateTimeFactory,
mock_config_entry: MockConfigEntry,
mock_smlight_client: MagicMock,
hass_ws_client: WebSocketGenerator,
) -> None:
"""Test firmware release notes."""
await setup_integration(hass, mock_config_entry)
ws_client = await hass_ws_client(hass)
await hass.async_block_till_done()
entity_id = "update.mock_title_core_firmware"
state = hass.states.get(entity_id)
assert state
assert state.state == STATE_ON
await ws_client.send_json(
{
"id": 1,
"type": "update/release_notes",
"entity_id": entity_id,
}
)
result = await ws_client.receive_json()
assert result["result"] is not None
mock_smlight_client.get_firmware_version.side_effect = None
mock_smlight_client.get_firmware_version.return_value = MOCK_FIRMWARE_NOTES
freezer.tick(SCAN_FIRMWARE_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await ws_client.send_json(
{
"id": 2,
"type": "update/release_notes",
"entity_id": entity_id,
}
)
result = await ws_client.receive_json()
await hass.async_block_till_done()
assert result["result"] is None