Add diagnostics to LinkPlay (#126768)

pull/130305/head
Simon Lamon 2024-11-10 20:31:40 +01:00 committed by GitHub
parent 0468e7e7a3
commit 784ad20fb6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 366 additions and 4 deletions

View File

@ -0,0 +1,17 @@
"""Diagnostics support for Linkplay."""
from __future__ import annotations
from typing import Any
from homeassistant.core import HomeAssistant
from . import LinkPlayConfigEntry
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, entry: LinkPlayConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
data = entry.runtime_data
return {"device_info": data.bridge.to_dict()}

View File

@ -1 +1,16 @@
"""Tests for the LinkPlay integration."""
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
async def setup_integration(
hass: HomeAssistant,
config_entry: MockConfigEntry,
) -> None:
"""Fixture for setting up the component."""
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()

View File

@ -1,12 +1,22 @@
"""Test configuration and mocks for LinkPlay component."""
from collections.abc import Generator
from collections.abc import Generator, Iterator
from contextlib import contextmanager
from typing import Any
from unittest import mock
from unittest.mock import AsyncMock, patch
from aiohttp import ClientSession
from linkplay.bridge import LinkPlayBridge, LinkPlayDevice
import pytest
from homeassistant.components.linkplay.const import DOMAIN
from homeassistant.const import CONF_HOST, EVENT_HOMEASSISTANT_CLOSE
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry, load_fixture
from tests.conftest import AiohttpClientMocker
HOST = "10.0.0.150"
HOST_REENTRY = "10.0.0.66"
UUID = "FF31F09E-5001-FBDE-0546-2DBFFF31F09E"
@ -24,15 +34,15 @@ def mock_linkplay_factory_bridge() -> Generator[AsyncMock]:
),
patch(
"homeassistant.components.linkplay.config_flow.linkplay_factory_httpapi_bridge",
) as factory,
) as conf_factory,
):
bridge = AsyncMock(spec=LinkPlayBridge)
bridge.endpoint = HOST
bridge.device = AsyncMock(spec=LinkPlayDevice)
bridge.device.uuid = UUID
bridge.device.name = NAME
factory.return_value = bridge
yield factory
conf_factory.return_value = bridge
yield conf_factory
@pytest.fixture
@ -43,3 +53,55 @@ def mock_setup_entry() -> Generator[AsyncMock]:
return_value=True,
) as mock_setup_entry:
yield mock_setup_entry
@pytest.fixture
def mock_config_entry() -> MockConfigEntry:
"""Mock a config entry."""
return MockConfigEntry(
domain=DOMAIN,
title=NAME,
data={CONF_HOST: HOST},
unique_id=UUID,
)
@pytest.fixture
def mock_player_ex(
mock_player_ex: AsyncMock,
) -> AsyncMock:
"""Mock a update_status of the LinkPlayPlayer."""
mock_player_ex.return_value = load_fixture("getPlayerEx.json", DOMAIN)
return mock_player_ex
@pytest.fixture
def mock_status_ex(
mock_status_ex: AsyncMock,
) -> AsyncMock:
"""Mock a update_status of the LinkPlayDevice."""
mock_status_ex.return_value = load_fixture("getStatusEx.json", DOMAIN)
return mock_status_ex
@contextmanager
def mock_lp_aiohttp_client() -> Iterator[AiohttpClientMocker]:
"""Context manager to mock aiohttp client."""
mocker = AiohttpClientMocker()
def create_session(hass: HomeAssistant, *args: Any, **kwargs: Any) -> ClientSession:
session = mocker.create_session(hass.loop)
async def close_session(event):
"""Close session."""
await session.close()
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_CLOSE, close_session)
return session
with mock.patch(
"homeassistant.components.linkplay.async_get_client_session",
side_effect=create_session,
):
yield mocker

View File

@ -0,0 +1,19 @@
{
"type": "0",
"ch": "0",
"mode": "0",
"loop": "0",
"eq": "0",
"status": "stop",
"curpos": "0",
"offset_pts": "0",
"totlen": "0",
"Title": "",
"Artist": "",
"Album": "",
"alarmflag": "0",
"plicount": "0",
"plicurr": "0",
"vol": "80",
"mute": "0"
}

View File

@ -0,0 +1,81 @@
{
"uuid": "FF31F09E5001FBDE05462DBFFF31F09E",
"DeviceName": "Smart Zone 1_54B9",
"GroupName": "Smart Zone 1_54B9",
"ssid": "Smart Zone 1_54B9",
"language": "en_us",
"firmware": "4.6.415145",
"hardware": "A31",
"build": "release",
"project": "SMART_ZONE4_AMP",
"priv_prj": "SMART_ZONE4_AMP",
"project_build_name": "a31rakoit",
"Release": "20220427",
"temp_uuid": "97296CE38DE8CC3D",
"hideSSID": "1",
"SSIDStrategy": "2",
"branch": "A31_stable_4.6",
"group": "0",
"wmrm_version": "4.2",
"internet": "1",
"MAC": "00:22:6C:21:7F:1D",
"STA_MAC": "00:00:00:00:00:00",
"CountryCode": "CN",
"CountryRegion": "1",
"netstat": "0",
"essid": "",
"apcli0": "",
"eth2": "192.168.168.197",
"ra0": "10.10.10.254",
"eth_dhcp": "1",
"VersionUpdate": "0",
"NewVer": "0",
"set_dns_enable": "1",
"mcu_ver": "37",
"mcu_ver_new": "0",
"dsp_ver": "0",
"dsp_ver_new": "0",
"date": "2024:10:29",
"time": "17:13:22",
"tz": "1.0000",
"dst_enable": "1",
"region": "unknown",
"prompt_status": "1",
"iot_ver": "1.0.0",
"upnp_version": "1005",
"cap1": "0x305200",
"capability": "0x28e90b80",
"languages": "0x6",
"streams_all": "0x7bff7ffe",
"streams": "0x7b9831fe",
"external": "0x0",
"plm_support": "0x40152",
"preset_key": "10",
"spotify_active": "0",
"lbc_support": "0",
"privacy_mode": "0",
"WifiChannel": "11",
"RSSI": "0",
"BSSID": "",
"battery": "0",
"battery_percent": "0",
"securemode": "1",
"auth": "WPAPSKWPA2PSK",
"encry": "AES",
"upnp_uuid": "uuid:FF31F09E-5001-FBDE-0546-2DBFFF31F09E",
"uart_pass_port": "8899",
"communication_port": "8819",
"web_firmware_update_hide": "0",
"ignore_talkstart": "0",
"web_login_result": "-1",
"silenceOTATime": "",
"ignore_silenceOTATime": "1",
"new_tunein_preset_and_alarm": "1",
"iheartradio_new": "1",
"new_iheart_podcast": "1",
"tidal_version": "2.0",
"service_version": "1.0",
"ETH_MAC": "00:22:6C:21:7F:20",
"security": "https/2.0",
"security_version": "2.0"
}

View File

@ -0,0 +1,115 @@
# serializer version: 1
# name: test_diagnostics
dict({
'device_info': dict({
'device': dict({
'properties': dict({
'BSSID': '',
'CountryCode': 'CN',
'CountryRegion': '1',
'DeviceName': 'Smart Zone 1_54B9',
'ETH_MAC': '00:22:6C:21:7F:20',
'GroupName': 'Smart Zone 1_54B9',
'MAC': '00:22:6C:21:7F:1D',
'NewVer': '0',
'RSSI': '0',
'Release': '20220427',
'SSIDStrategy': '2',
'STA_MAC': '00:00:00:00:00:00',
'VersionUpdate': '0',
'WifiChannel': '11',
'apcli0': '',
'auth': 'WPAPSKWPA2PSK',
'battery': '0',
'battery_percent': '0',
'branch': 'A31_stable_4.6',
'build': 'release',
'cap1': '0x305200',
'capability': '0x28e90b80',
'communication_port': '8819',
'date': '2024:10:29',
'dsp_ver': '0',
'dsp_ver_new': '0',
'dst_enable': '1',
'encry': 'AES',
'essid': '',
'eth2': '192.168.168.197',
'eth_dhcp': '1',
'external': '0x0',
'firmware': '4.6.415145',
'group': '0',
'hardware': 'A31',
'hideSSID': '1',
'ignore_silenceOTATime': '1',
'ignore_talkstart': '0',
'iheartradio_new': '1',
'internet': '1',
'iot_ver': '1.0.0',
'language': 'en_us',
'languages': '0x6',
'lbc_support': '0',
'mcu_ver': '37',
'mcu_ver_new': '0',
'netstat': '0',
'new_iheart_podcast': '1',
'new_tunein_preset_and_alarm': '1',
'plm_support': '0x40152',
'preset_key': '10',
'priv_prj': 'SMART_ZONE4_AMP',
'privacy_mode': '0',
'project': 'SMART_ZONE4_AMP',
'project_build_name': 'a31rakoit',
'prompt_status': '1',
'ra0': '10.10.10.254',
'region': 'unknown',
'securemode': '1',
'security': 'https/2.0',
'security_version': '2.0',
'service_version': '1.0',
'set_dns_enable': '1',
'silenceOTATime': '',
'spotify_active': '0',
'ssid': 'Smart Zone 1_54B9',
'streams': '0x7b9831fe',
'streams_all': '0x7bff7ffe',
'temp_uuid': '97296CE38DE8CC3D',
'tidal_version': '2.0',
'time': '17:13:22',
'tz': '1.0000',
'uart_pass_port': '8899',
'upnp_uuid': 'uuid:FF31F09E-5001-FBDE-0546-2DBFFF31F09E',
'upnp_version': '1005',
'uuid': 'FF31F09E5001FBDE05462DBFFF31F09E',
'web_firmware_update_hide': '0',
'web_login_result': '-1',
'wmrm_version': '4.2',
}),
}),
'endpoint': dict({
'endpoint': 'https://10.0.0.150',
}),
'multiroom': None,
'player': dict({
'properties': dict({
'Album': '',
'Artist': '',
'Title': '',
'alarmflag': '0',
'ch': '0',
'curpos': '0',
'eq': '0',
'loop': '0',
'mode': '0',
'mute': '0',
'offset_pts': '0',
'plicount': '0',
'plicurr': '0',
'status': 'stop',
'totlen': '0',
'type': '0',
'vol': '80',
}),
}),
}),
})
# ---

View File

@ -0,0 +1,53 @@
"""Tests for the LinkPlay diagnostics."""
from unittest.mock import patch
from linkplay.bridge import LinkPlayMultiroom
from linkplay.consts import API_ENDPOINT
from linkplay.endpoint import LinkPlayApiEndpoint
from syrupy import SnapshotAssertion
from homeassistant.components.linkplay.const import DOMAIN
from homeassistant.core import HomeAssistant
from . import setup_integration
from .conftest import HOST, mock_lp_aiohttp_client
from tests.common import MockConfigEntry, load_fixture
from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator
async def test_diagnostics(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
mock_config_entry: MockConfigEntry,
snapshot: SnapshotAssertion,
) -> None:
"""Test diagnostics."""
with (
mock_lp_aiohttp_client() as mock_session,
patch.object(LinkPlayMultiroom, "update_status", return_value=None),
):
endpoints = [
LinkPlayApiEndpoint(protocol="https", endpoint=HOST, session=None),
LinkPlayApiEndpoint(protocol="http", endpoint=HOST, session=None),
]
for endpoint in endpoints:
mock_session.get(
API_ENDPOINT.format(str(endpoint), "getPlayerStatusEx"),
text=load_fixture("getPlayerEx.json", DOMAIN),
)
mock_session.get(
API_ENDPOINT.format(str(endpoint), "getStatusEx"),
text=load_fixture("getStatusEx.json", DOMAIN),
)
await setup_integration(hass, mock_config_entry)
assert (
await get_diagnostics_for_config_entry(hass, hass_client, mock_config_entry)
== snapshot
)