Add diagnostics to Twinkly (#100146)

This commit is contained in:
Olen
2023-09-13 13:09:57 +02:00
committed by GitHub
parent 684b2d4537
commit 7fe78fe9e4
9 changed files with 183 additions and 17 deletions

View File

@ -1324,8 +1324,8 @@ build.json @home-assistant/supervisor
/tests/components/tuya/ @Tuya @zlinoliver @frenck
/homeassistant/components/twentemilieu/ @frenck
/tests/components/twentemilieu/ @frenck
/homeassistant/components/twinkly/ @dr1rrb @Robbie1221
/tests/components/twinkly/ @dr1rrb @Robbie1221
/homeassistant/components/twinkly/ @dr1rrb @Robbie1221 @Olen
/tests/components/twinkly/ @dr1rrb @Robbie1221 @Olen
/homeassistant/components/twitch/ @joostlek
/tests/components/twitch/ @joostlek
/homeassistant/components/ukraine_alarm/ @PaulAnnekov

View File

@ -0,0 +1,40 @@
"""Diagnostics support for Twinkly."""
from __future__ import annotations
from typing import Any
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_IP_ADDRESS, CONF_MAC
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .const import DATA_DEVICE_INFO, DOMAIN
TO_REDACT = [CONF_HOST, CONF_IP_ADDRESS, CONF_MAC]
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, entry: ConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a Twinkly config entry."""
attributes = None
state = None
entity_registry = er.async_get(hass)
entity_id = entity_registry.async_get_entity_id(
LIGHT_DOMAIN, DOMAIN, str(entry.unique_id)
)
if entity_id:
state = hass.states.get(entity_id)
if state:
attributes = state.attributes
return async_redact_data(
{
"entry": entry.as_dict(),
"device_info": hass.data[DOMAIN][entry.entry_id][DATA_DEVICE_INFO],
"attributes": attributes,
},
TO_REDACT,
)

View File

@ -1,7 +1,7 @@
{
"domain": "twinkly",
"name": "Twinkly",
"codeowners": ["@dr1rrb", "@Robbie1221"],
"codeowners": ["@dr1rrb", "@Robbie1221", "@Olen"],
"config_flow": true,
"dhcp": [
{

View File

@ -1,6 +1,5 @@
"""Constants and mock for the twkinly component tests."""
from uuid import uuid4
from aiohttp.client_exceptions import ClientConnectionError
@ -8,6 +7,7 @@ from homeassistant.components.twinkly.const import DEV_NAME
TEST_HOST = "test.twinkly.com"
TEST_ID = "twinkly_test_device_id"
TEST_UID = "4c8fccf5-e08a-4173-92d5-49bf479252a2"
TEST_NAME = "twinkly_test_device_name"
TEST_NAME_ORIGINAL = "twinkly_test_original_device_name" # the original (deprecated) name stored in the conf
TEST_MODEL = "twinkly_test_device_model"
@ -28,11 +28,12 @@ class ClientMock:
self.mode = None
self.version = "2.8.10"
self.id = str(uuid4())
self.id = TEST_UID
self.device_info = {
"uuid": self.id,
"device_name": self.id, # we make sure that entity id is different for each test
"device_name": TEST_NAME,
"product_code": TEST_MODEL,
"sw_version": self.version,
}
@property

View File

@ -0,0 +1,54 @@
"""Configure tests for the Twinkly integration."""
from collections.abc import Awaitable, Callable, Coroutine
from typing import Any
from unittest.mock import patch
import pytest
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from . import TEST_MODEL, TEST_NAME, TEST_UID, ClientMock
from tests.common import MockConfigEntry
ComponentSetup = Callable[[], Awaitable[ClientMock]]
DOMAIN = "twinkly"
TITLE = "Twinkly"
@pytest.fixture(name="config_entry")
def mock_config_entry() -> MockConfigEntry:
"""Create Twinkly entry in Home Assistant."""
client = ClientMock()
return MockConfigEntry(
domain=DOMAIN,
title=TITLE,
unique_id=TEST_UID,
entry_id=TEST_UID,
data={
"host": client.host,
"id": client.id,
"name": TEST_NAME,
"model": TEST_MODEL,
"device_name": TEST_NAME,
},
)
@pytest.fixture(name="setup_integration")
async def mock_setup_integration(
hass: HomeAssistant, config_entry: MockConfigEntry
) -> Callable[[], Coroutine[Any, Any, ClientMock]]:
"""Fixture for setting up the component."""
config_entry.add_to_hass(hass)
async def func() -> ClientMock:
mock = ClientMock()
with patch("homeassistant.components.twinkly.Twinkly", return_value=mock):
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
return mock
return func

View File

@ -0,0 +1,43 @@
# serializer version: 1
# name: test_diagnostics
dict({
'attributes': dict({
'brightness': 26,
'color_mode': 'brightness',
'effect_list': list([
]),
'friendly_name': 'twinkly_test_device_name',
'icon': 'mdi:string-lights',
'supported_color_modes': list([
'brightness',
]),
'supported_features': 4,
}),
'device_info': dict({
'device_name': 'twinkly_test_device_name',
'product_code': 'twinkly_test_device_model',
'sw_version': '2.8.10',
'uuid': '4c8fccf5-e08a-4173-92d5-49bf479252a2',
}),
'entry': dict({
'data': dict({
'device_name': 'twinkly_test_device_name',
'host': '**REDACTED**',
'id': '4c8fccf5-e08a-4173-92d5-49bf479252a2',
'model': 'twinkly_test_device_model',
'name': 'twinkly_test_device_name',
}),
'disabled_by': None,
'domain': 'twinkly',
'entry_id': '4c8fccf5-e08a-4173-92d5-49bf479252a2',
'options': dict({
}),
'pref_disable_new_entities': False,
'pref_disable_polling': False,
'source': 'user',
'title': 'Twinkly',
'unique_id': '4c8fccf5-e08a-4173-92d5-49bf479252a2',
'version': 1,
}),
})
# ---

View File

@ -12,7 +12,7 @@ from homeassistant.components.twinkly.const import (
from homeassistant.const import CONF_MODEL
from homeassistant.core import HomeAssistant
from . import TEST_MODEL, ClientMock
from . import TEST_MODEL, TEST_NAME, ClientMock
from tests.common import MockConfigEntry
@ -60,11 +60,11 @@ async def test_success_flow(hass: HomeAssistant) -> None:
)
assert result["type"] == "create_entry"
assert result["title"] == client.id
assert result["title"] == TEST_NAME
assert result["data"] == {
CONF_HOST: "dummy",
CONF_ID: client.id,
CONF_NAME: client.id,
CONF_NAME: TEST_NAME,
CONF_MODEL: TEST_MODEL,
}
@ -113,11 +113,11 @@ async def test_dhcp_success(hass: HomeAssistant) -> None:
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
assert result["type"] == "create_entry"
assert result["title"] == client.id
assert result["title"] == TEST_NAME
assert result["data"] == {
CONF_HOST: "1.2.3.4",
CONF_ID: client.id,
CONF_NAME: client.id,
CONF_NAME: TEST_NAME,
CONF_MODEL: TEST_MODEL,
}
@ -131,7 +131,7 @@ async def test_dhcp_already_exists(hass: HomeAssistant) -> None:
data={
CONF_HOST: "1.2.3.4",
CONF_ID: client.id,
CONF_NAME: client.id,
CONF_NAME: TEST_NAME,
CONF_MODEL: TEST_MODEL,
},
unique_id=client.id,

View File

@ -0,0 +1,28 @@
"""Tests for the diagnostics of the twinkly component."""
from collections.abc import Awaitable, Callable
from syrupy import SnapshotAssertion
from homeassistant.core import HomeAssistant
from . import ClientMock
from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator
ComponentSetup = Callable[[], Awaitable[ClientMock]]
DOMAIN = "twinkly"
async def test_diagnostics(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
setup_integration: ComponentSetup,
snapshot: SnapshotAssertion,
) -> None:
"""Test diagnostics."""
await setup_integration()
entry = hass.config_entries.async_entries(DOMAIN)[0]
assert await get_diagnostics_for_config_entry(hass, hass_client, entry) == snapshot

View File

@ -16,7 +16,7 @@ from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.device_registry import DeviceEntry
from homeassistant.helpers.entity_registry import RegistryEntry
from . import TEST_MODEL, TEST_NAME_ORIGINAL, ClientMock
from . import TEST_MODEL, TEST_NAME, TEST_NAME_ORIGINAL, ClientMock
from tests.common import MockConfigEntry
@ -28,16 +28,16 @@ async def test_initial_state(hass: HomeAssistant) -> None:
state = hass.states.get(entity.entity_id)
# Basic state properties
assert state.name == entity.unique_id
assert state.name == TEST_NAME
assert state.state == "on"
assert state.attributes[ATTR_BRIGHTNESS] == 26
assert state.attributes["friendly_name"] == entity.unique_id
assert state.attributes["friendly_name"] == TEST_NAME
assert state.attributes["icon"] == "mdi:string-lights"
assert entity.original_name == entity.unique_id
assert entity.original_name == TEST_NAME
assert entity.original_icon == "mdi:string-lights"
assert device.name == entity.unique_id
assert device.name == TEST_NAME
assert device.model == TEST_MODEL
assert device.manufacturer == "LEDWORKS"