From 43ec63eabce0dcf1fbe918723bca83265cf72125 Mon Sep 17 00:00:00 2001 From: Shay Levy Date: Wed, 8 Jan 2025 13:06:02 +0200 Subject: [PATCH] Cleanup LG webOS TV name (#135028) --- .../components/webostv/config_flow.py | 11 ++++--- homeassistant/components/webostv/const.py | 2 +- .../components/webostv/quality_scale.yaml | 6 ++-- homeassistant/components/webostv/strings.json | 7 ++-- tests/components/webostv/conftest.py | 12 +++++-- tests/components/webostv/const.py | 6 ++-- tests/components/webostv/test_config_flow.py | 32 ++++++++++++------- tests/components/webostv/test_diagnostics.py | 4 +-- tests/components/webostv/test_media_player.py | 4 +-- tests/components/webostv/test_notify.py | 24 +++++++------- 10 files changed, 67 insertions(+), 41 deletions(-) diff --git a/homeassistant/components/webostv/config_flow.py b/homeassistant/components/webostv/config_flow.py index 9a5eda7bbf7..c62ecaa78cf 100644 --- a/homeassistant/components/webostv/config_flow.py +++ b/homeassistant/components/webostv/config_flow.py @@ -16,7 +16,7 @@ from homeassistant.config_entries import ( ConfigFlowResult, OptionsFlow, ) -from homeassistant.const import CONF_CLIENT_SECRET, CONF_HOST, CONF_NAME +from homeassistant.const import CONF_CLIENT_SECRET, CONF_HOST from homeassistant.core import callback from homeassistant.helpers import config_validation as cv @@ -27,7 +27,6 @@ from .helpers import async_get_sources DATA_SCHEMA = vol.Schema( { vol.Required(CONF_HOST): cv.string, - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, }, extra=vol.ALLOW_EXTRA, ) @@ -57,7 +56,6 @@ class FlowHandler(ConfigFlow, domain=DOMAIN): errors: dict[str, str] = {} if user_input is not None: self._host = user_input[CONF_HOST] - self._name = user_input[CONF_NAME] return await self.async_step_pairing() return self.async_show_form( @@ -86,6 +84,9 @@ class FlowHandler(ConfigFlow, domain=DOMAIN): ) self._abort_if_unique_id_configured({CONF_HOST: self._host}) data = {CONF_HOST: self._host, CONF_CLIENT_SECRET: client.client_key} + + if not self._name: + self._name = f"{DEFAULT_NAME} {client.system_info["modelName"]}" return self.async_create_entry(title=self._name, data=data) return self.async_show_form(step_id="pairing", errors=errors) @@ -98,7 +99,9 @@ class FlowHandler(ConfigFlow, domain=DOMAIN): host = urlparse(discovery_info.ssdp_location).hostname assert host self._host = host - self._name = discovery_info.upnp.get(ssdp.ATTR_UPNP_FRIENDLY_NAME, DEFAULT_NAME) + self._name = discovery_info.upnp.get( + ssdp.ATTR_UPNP_FRIENDLY_NAME, DEFAULT_NAME + ).replace("[LG]", "LG") uuid = discovery_info.upnp[ssdp.ATTR_UPNP_UDN] assert uuid diff --git a/homeassistant/components/webostv/const.py b/homeassistant/components/webostv/const.py index c20060cae91..0d839568f13 100644 --- a/homeassistant/components/webostv/const.py +++ b/homeassistant/components/webostv/const.py @@ -11,7 +11,7 @@ DOMAIN = "webostv" PLATFORMS = [Platform.MEDIA_PLAYER] DATA_CONFIG_ENTRY = "config_entry" DATA_HASS_CONFIG = "hass_config" -DEFAULT_NAME = "LG webOS Smart TV" +DEFAULT_NAME = "LG webOS TV" ATTR_BUTTON = "button" ATTR_CONFIG_ENTRY_ID = "entry_id" diff --git a/homeassistant/components/webostv/quality_scale.yaml b/homeassistant/components/webostv/quality_scale.yaml index b6a6a5e99a4..693cefcdbfc 100644 --- a/homeassistant/components/webostv/quality_scale.yaml +++ b/homeassistant/components/webostv/quality_scale.yaml @@ -8,10 +8,12 @@ rules: common-modules: status: exempt comment: The integration does not use common patterns. - config-flow-test-coverage: todo + config-flow-test-coverage: + status: todo + comment: remove duplicated config flow start in tests, make sure tests ends with CREATE_ENTRY or ABORT, use hass.config_entries.async_setup instead of async_setup_component, snapshot in diagnostics (and other tests when possible), test_client_disconnected validate no error in log config-flow: status: todo - comment: remove duplicated config flow start in tests, make sure tests ends with CREATE_ENTRY or ABORT, remove name parameter, use hass.config_entries.async_setup instead of async_setup_component, snapshot in diagnostics (and other tests when possible), test_client_disconnected validate no error in log, make reauth flow more graceful + comment: make reauth flow more graceful dependency-transparency: done docs-actions: status: todo diff --git a/homeassistant/components/webostv/strings.json b/homeassistant/components/webostv/strings.json index 3ceab5f50a3..34c1b44e195 100644 --- a/homeassistant/components/webostv/strings.json +++ b/homeassistant/components/webostv/strings.json @@ -1,12 +1,11 @@ { "config": { - "flow_title": "LG webOS Smart TV", + "flow_title": "{name}", "step": { "user": { - "description": "Turn on TV, fill the following fields and select **Submit**", + "description": "Turn on the TV, fill the host field and select **Submit**", "data": { - "host": "[%key:common::config_flow::data::host%]", - "name": "[%key:common::config_flow::data::name%]" + "host": "[%key:common::config_flow::data::host%]" }, "data_description": { "host": "Hostname or IP address of your webOS TV." diff --git a/tests/components/webostv/conftest.py b/tests/components/webostv/conftest.py index a30ae933cca..1e3f7ecdc67 100644 --- a/tests/components/webostv/conftest.py +++ b/tests/components/webostv/conftest.py @@ -7,7 +7,15 @@ import pytest from homeassistant.components.webostv.const import LIVE_TV_APP_ID -from .const import CHANNEL_1, CHANNEL_2, CLIENT_KEY, FAKE_UUID, MOCK_APPS, MOCK_INPUTS +from .const import ( + CHANNEL_1, + CHANNEL_2, + CLIENT_KEY, + FAKE_UUID, + MOCK_APPS, + MOCK_INPUTS, + TV_MODEL, +) @pytest.fixture @@ -28,7 +36,7 @@ def client_fixture(): client = mock_client_class.return_value client.hello_info = {"deviceUUID": FAKE_UUID} client.software_info = {"major_ver": "major", "minor_ver": "minor"} - client.system_info = {"modelName": "TVFAKE"} + client.system_info = {"modelName": TV_MODEL} client.client_key = CLIENT_KEY client.apps = MOCK_APPS client.inputs = MOCK_INPUTS diff --git a/tests/components/webostv/const.py b/tests/components/webostv/const.py index afaed224e83..52453d4ffa9 100644 --- a/tests/components/webostv/const.py +++ b/tests/components/webostv/const.py @@ -2,10 +2,12 @@ from homeassistant.components.media_player import DOMAIN as MP_DOMAIN from homeassistant.components.webostv.const import LIVE_TV_APP_ID +from homeassistant.util import slugify FAKE_UUID = "some-fake-uuid" -TV_NAME = "fake_webos" -ENTITY_ID = f"{MP_DOMAIN}.{TV_NAME}" +TV_MODEL = "MODEL" +TV_NAME = f"LG webOS TV {TV_MODEL}" +ENTITY_ID = f"{MP_DOMAIN}.{slugify(TV_NAME)}" HOST = "1.2.3.4" CLIENT_KEY = "some-secret" diff --git a/tests/components/webostv/test_config_flow.py b/tests/components/webostv/test_config_flow.py index cc335a4fb41..1c0c0e935e5 100644 --- a/tests/components/webostv/test_config_flow.py +++ b/tests/components/webostv/test_config_flow.py @@ -10,26 +10,31 @@ from homeassistant import config_entries from homeassistant.components import ssdp from homeassistant.components.webostv.const import CONF_SOURCES, DOMAIN, LIVE_TV_APP_ID from homeassistant.config_entries import SOURCE_SSDP -from homeassistant.const import CONF_CLIENT_SECRET, CONF_HOST, CONF_NAME, CONF_SOURCE +from homeassistant.const import CONF_CLIENT_SECRET, CONF_HOST, CONF_SOURCE from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType from . import setup_webostv -from .const import CLIENT_KEY, FAKE_UUID, HOST, MOCK_APPS, MOCK_INPUTS, TV_NAME +from .const import ( + CLIENT_KEY, + FAKE_UUID, + HOST, + MOCK_APPS, + MOCK_INPUTS, + TV_MODEL, + TV_NAME, +) pytestmark = pytest.mark.usefixtures("mock_setup_entry") -MOCK_USER_CONFIG = { - CONF_HOST: HOST, - CONF_NAME: TV_NAME, -} +MOCK_USER_CONFIG = {CONF_HOST: HOST} MOCK_DISCOVERY_INFO = ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location=f"http://{HOST}", upnp={ - ssdp.ATTR_UPNP_FRIENDLY_NAME: "LG Webostv", + ssdp.ATTR_UPNP_FRIENDLY_NAME: f"[LG] webOS TV {TV_MODEL}", ssdp.ATTR_UPNP_UDN: f"uuid:{FAKE_UUID}", }, ) @@ -194,6 +199,14 @@ async def test_form_ssdp(hass: HomeAssistant, client) -> None: assert result["type"] is FlowResultType.FORM assert result["step_id"] == "pairing" + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], user_input={} + ) + await hass.async_block_till_done() + + assert result2["type"] is FlowResultType.CREATE_ENTRY + assert result2["title"] == TV_NAME + async def test_ssdp_in_progress(hass: HomeAssistant, client) -> None: """Test abort if ssdp paring is already in progress.""" @@ -253,10 +266,7 @@ async def test_form_abort_uuid_configured(hass: HomeAssistant, client) -> None: assert result["type"] is FlowResultType.FORM assert result["step_id"] == "user" - user_config = { - CONF_HOST: "new_host", - CONF_NAME: TV_NAME, - } + user_config = {CONF_HOST: "new_host"} result = await hass.config_entries.flow.async_init( DOMAIN, diff --git a/tests/components/webostv/test_diagnostics.py b/tests/components/webostv/test_diagnostics.py index 3d7cb00e021..0dfb13b0424 100644 --- a/tests/components/webostv/test_diagnostics.py +++ b/tests/components/webostv/test_diagnostics.py @@ -36,7 +36,7 @@ async def test_diagnostics( "in1": {"appId": "app0", "id": "in1", "label": "Input01"}, "in2": {"appId": "app1", "id": "in2", "label": "Input02"}, }, - "system_info": {"modelName": "TVFAKE"}, + "system_info": {"modelName": "MODEL"}, "software_info": {"major_ver": "major", "minor_ver": "minor"}, "hello_info": {"deviceUUID": "**REDACTED**"}, "sound_output": "speaker", @@ -47,7 +47,7 @@ async def test_diagnostics( "version": 1, "minor_version": 1, "domain": "webostv", - "title": "fake_webos", + "title": "LG webOS TV MODEL", "data": { "client_secret": "**REDACTED**", "host": "**REDACTED**", diff --git a/tests/components/webostv/test_media_player.py b/tests/components/webostv/test_media_player.py index e4c02e680bd..7c89b749bbe 100644 --- a/tests/components/webostv/test_media_player.py +++ b/tests/components/webostv/test_media_player.py @@ -67,7 +67,7 @@ from homeassistant.setup import async_setup_component from homeassistant.util import dt as dt_util from . import setup_webostv -from .const import CHANNEL_2, ENTITY_ID, TV_NAME +from .const import CHANNEL_2, ENTITY_ID, TV_MODEL, TV_NAME from tests.common import async_fire_time_changed, mock_restore_cache from tests.test_util.aiohttp import AiohttpClientMocker @@ -340,7 +340,7 @@ async def test_entity_attributes( assert device.manufacturer == "LG" assert device.name == TV_NAME assert device.sw_version == "major.minor" - assert device.model == "TVFAKE" + assert device.model == TV_MODEL # Sound output when off monkeypatch.setattr(client, "sound_output", None) diff --git a/tests/components/webostv/test_notify.py b/tests/components/webostv/test_notify.py index 75c2e148310..2f29281a496 100644 --- a/tests/components/webostv/test_notify.py +++ b/tests/components/webostv/test_notify.py @@ -14,22 +14,24 @@ from homeassistant.components.webostv import DOMAIN from homeassistant.const import ATTR_ICON from homeassistant.core import HomeAssistant from homeassistant.setup import async_setup_component +from homeassistant.util import slugify from . import setup_webostv from .const import TV_NAME ICON_PATH = "/some/path" MESSAGE = "one, two, testing, testing" +SERVICE_NAME = slugify(TV_NAME) async def test_notify(hass: HomeAssistant, client) -> None: """Test sending a message.""" await setup_webostv(hass) - assert hass.services.has_service(NOTIFY_DOMAIN, TV_NAME) + assert hass.services.has_service(NOTIFY_DOMAIN, SERVICE_NAME) await hass.services.async_call( NOTIFY_DOMAIN, - TV_NAME, + SERVICE_NAME, { ATTR_MESSAGE: MESSAGE, ATTR_DATA: { @@ -44,7 +46,7 @@ async def test_notify(hass: HomeAssistant, client) -> None: await hass.services.async_call( NOTIFY_DOMAIN, - TV_NAME, + SERVICE_NAME, { ATTR_MESSAGE: MESSAGE, ATTR_DATA: { @@ -59,7 +61,7 @@ async def test_notify(hass: HomeAssistant, client) -> None: await hass.services.async_call( NOTIFY_DOMAIN, - TV_NAME, + SERVICE_NAME, { ATTR_MESSAGE: "only message, no data", }, @@ -77,12 +79,12 @@ async def test_notify_not_connected( ) -> None: """Test sending a message when client is not connected.""" await setup_webostv(hass) - assert hass.services.has_service(NOTIFY_DOMAIN, TV_NAME) + assert hass.services.has_service(NOTIFY_DOMAIN, SERVICE_NAME) monkeypatch.setattr(client, "is_connected", Mock(return_value=False)) await hass.services.async_call( NOTIFY_DOMAIN, - TV_NAME, + SERVICE_NAME, { ATTR_MESSAGE: MESSAGE, ATTR_DATA: { @@ -104,12 +106,12 @@ async def test_icon_not_found( ) -> None: """Test notify icon not found error.""" await setup_webostv(hass) - assert hass.services.has_service(NOTIFY_DOMAIN, TV_NAME) + assert hass.services.has_service(NOTIFY_DOMAIN, SERVICE_NAME) monkeypatch.setattr(client, "send_message", Mock(side_effect=FileNotFoundError)) await hass.services.async_call( NOTIFY_DOMAIN, - TV_NAME, + SERVICE_NAME, { ATTR_MESSAGE: MESSAGE, ATTR_DATA: { @@ -141,13 +143,13 @@ async def test_connection_errors( ) -> None: """Test connection errors scenarios.""" await setup_webostv(hass) - assert hass.services.has_service("notify", TV_NAME) + assert hass.services.has_service("notify", SERVICE_NAME) monkeypatch.setattr(client, "is_connected", Mock(return_value=False)) monkeypatch.setattr(client, "connect", Mock(side_effect=side_effect)) await hass.services.async_call( NOTIFY_DOMAIN, - TV_NAME, + SERVICE_NAME, { ATTR_MESSAGE: MESSAGE, ATTR_DATA: { @@ -175,4 +177,4 @@ async def test_no_discovery_info( await hass.async_block_till_done() assert NOTIFY_DOMAIN in hass.config.components assert f"Failed to initialize notification service {DOMAIN}" in caplog.text - assert not hass.services.has_service("notify", TV_NAME) + assert not hass.services.has_service("notify", SERVICE_NAME)