mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
Add diagnostics to LinkPlay (#126768)
This commit is contained in:
parent
0468e7e7a3
commit
784ad20fb6
17
homeassistant/components/linkplay/diagnostics.py
Normal file
17
homeassistant/components/linkplay/diagnostics.py
Normal 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()}
|
@ -1 +1,16 @@
|
|||||||
"""Tests for the LinkPlay integration."""
|
"""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()
|
||||||
|
@ -1,12 +1,22 @@
|
|||||||
"""Test configuration and mocks for LinkPlay component."""
|
"""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 unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
from aiohttp import ClientSession
|
from aiohttp import ClientSession
|
||||||
from linkplay.bridge import LinkPlayBridge, LinkPlayDevice
|
from linkplay.bridge import LinkPlayBridge, LinkPlayDevice
|
||||||
import pytest
|
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 = "10.0.0.150"
|
||||||
HOST_REENTRY = "10.0.0.66"
|
HOST_REENTRY = "10.0.0.66"
|
||||||
UUID = "FF31F09E-5001-FBDE-0546-2DBFFF31F09E"
|
UUID = "FF31F09E-5001-FBDE-0546-2DBFFF31F09E"
|
||||||
@ -24,15 +34,15 @@ def mock_linkplay_factory_bridge() -> Generator[AsyncMock]:
|
|||||||
),
|
),
|
||||||
patch(
|
patch(
|
||||||
"homeassistant.components.linkplay.config_flow.linkplay_factory_httpapi_bridge",
|
"homeassistant.components.linkplay.config_flow.linkplay_factory_httpapi_bridge",
|
||||||
) as factory,
|
) as conf_factory,
|
||||||
):
|
):
|
||||||
bridge = AsyncMock(spec=LinkPlayBridge)
|
bridge = AsyncMock(spec=LinkPlayBridge)
|
||||||
bridge.endpoint = HOST
|
bridge.endpoint = HOST
|
||||||
bridge.device = AsyncMock(spec=LinkPlayDevice)
|
bridge.device = AsyncMock(spec=LinkPlayDevice)
|
||||||
bridge.device.uuid = UUID
|
bridge.device.uuid = UUID
|
||||||
bridge.device.name = NAME
|
bridge.device.name = NAME
|
||||||
factory.return_value = bridge
|
conf_factory.return_value = bridge
|
||||||
yield factory
|
yield conf_factory
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -43,3 +53,55 @@ def mock_setup_entry() -> Generator[AsyncMock]:
|
|||||||
return_value=True,
|
return_value=True,
|
||||||
) as mock_setup_entry:
|
) as mock_setup_entry:
|
||||||
yield 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
|
||||||
|
19
tests/components/linkplay/fixtures/getPlayerEx.json
Normal file
19
tests/components/linkplay/fixtures/getPlayerEx.json
Normal 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"
|
||||||
|
}
|
81
tests/components/linkplay/fixtures/getStatusEx.json
Normal file
81
tests/components/linkplay/fixtures/getStatusEx.json
Normal 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"
|
||||||
|
}
|
115
tests/components/linkplay/snapshots/test_diagnostics.ambr
Normal file
115
tests/components/linkplay/snapshots/test_diagnostics.ambr
Normal 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',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
# ---
|
53
tests/components/linkplay/test_diagnostics.py
Normal file
53
tests/components/linkplay/test_diagnostics.py
Normal 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
|
||||||
|
)
|
Loading…
x
Reference in New Issue
Block a user