From 24b1eeb900e064481b72eadcd1cbaea49b9412fa Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Mon, 9 Dec 2024 10:15:01 +0100 Subject: [PATCH] Remove YAML support from vizio (#132351) --- homeassistant/components/vizio/__init__.py | 43 +-- homeassistant/components/vizio/config_flow.py | 94 +---- homeassistant/components/vizio/const.py | 48 --- tests/components/vizio/const.py | 25 -- tests/components/vizio/test_config_flow.py | 331 +----------------- tests/components/vizio/test_init.py | 11 - tests/components/vizio/test_media_player.py | 24 +- 7 files changed, 11 insertions(+), 565 deletions(-) diff --git a/homeassistant/components/vizio/__init__.py b/homeassistant/components/vizio/__init__.py index 09d6f3be090..4af42d76b62 100644 --- a/homeassistant/components/vizio/__init__.py +++ b/homeassistant/components/vizio/__init__.py @@ -4,55 +4,18 @@ from __future__ import annotations from typing import Any -import voluptuous as vol - from homeassistant.components.media_player import MediaPlayerDeviceClass -from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry, ConfigEntryState -from homeassistant.const import Platform +from homeassistant.config_entries import ConfigEntry, ConfigEntryState +from homeassistant.const import CONF_DEVICE_CLASS, Platform from homeassistant.core import HomeAssistant -from homeassistant.helpers import config_validation as cv from homeassistant.helpers.storage import Store -from homeassistant.helpers.typing import ConfigType -from .const import CONF_APPS, CONF_DEVICE_CLASS, DOMAIN, VIZIO_SCHEMA +from .const import CONF_APPS, DOMAIN from .coordinator import VizioAppsDataUpdateCoordinator - -def validate_apps(config: ConfigType) -> ConfigType: - """Validate CONF_APPS is only used when CONF_DEVICE_CLASS is MediaPlayerDeviceClass.TV.""" - if ( - config.get(CONF_APPS) is not None - and config[CONF_DEVICE_CLASS] != MediaPlayerDeviceClass.TV - ): - raise vol.Invalid( - f"'{CONF_APPS}' can only be used if {CONF_DEVICE_CLASS}' is" - f" '{MediaPlayerDeviceClass.TV}'" - ) - - return config - - -CONFIG_SCHEMA = vol.Schema( - {DOMAIN: vol.All(cv.ensure_list, [vol.All(VIZIO_SCHEMA, validate_apps)])}, - extra=vol.ALLOW_EXTRA, -) - PLATFORMS = [Platform.MEDIA_PLAYER] -async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: - """Component setup, run import config flow for each entry in config.""" - if DOMAIN in config: - for entry in config[DOMAIN]: - hass.async_create_task( - hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_IMPORT}, data=entry - ) - ) - - return True - - async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Load the saved entities.""" diff --git a/homeassistant/components/vizio/config_flow.py b/homeassistant/components/vizio/config_flow.py index 54031930503..d3921061d8e 100644 --- a/homeassistant/components/vizio/config_flow.py +++ b/homeassistant/components/vizio/config_flow.py @@ -14,8 +14,6 @@ import voluptuous as vol from homeassistant.components import zeroconf from homeassistant.components.media_player import MediaPlayerDeviceClass from homeassistant.config_entries import ( - SOURCE_IGNORE, - SOURCE_IMPORT, SOURCE_ZEROCONF, ConfigEntry, ConfigFlow, @@ -231,7 +229,7 @@ class VizioConfigFlow(ConfigFlow, domain=DOMAIN): errors[CONF_HOST] = "existing_config_entry_found" if not errors: - if self._must_show_form and self.source == SOURCE_ZEROCONF: + if self._must_show_form and self.context["source"] == SOURCE_ZEROCONF: # Discovery should always display the config form before trying to # create entry so that user can update default config options self._must_show_form = False @@ -251,98 +249,13 @@ class VizioConfigFlow(ConfigFlow, domain=DOMAIN): if not errors: return await self._create_entry(user_input) - elif self._must_show_form and self.source == SOURCE_IMPORT: - # Import should always display the config form if CONF_ACCESS_TOKEN - # wasn't included but is needed so that the user can choose to update - # their configuration.yaml or to proceed with config flow pairing. We - # will also provide contextual message to user explaining why - _LOGGER.warning( - ( - "Couldn't complete configuration.yaml import: '%s' key is " - "missing. Either provide '%s' key in configuration.yaml or " - "finish setup by completing configuration via frontend" - ), - CONF_ACCESS_TOKEN, - CONF_ACCESS_TOKEN, - ) - self._must_show_form = False else: self._data = copy.deepcopy(user_input) return await self.async_step_pair_tv() schema = self._user_schema or _get_config_schema() - - if errors and self.source == SOURCE_IMPORT: - # Log an error message if import config flow fails since otherwise failure is silent - _LOGGER.error( - "Importing from configuration.yaml failed: %s", - ", ".join(errors.values()), - ) - return self.async_show_form(step_id="user", data_schema=schema, errors=errors) - async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResult: - """Import a config entry from configuration.yaml.""" - # Check if new config entry matches any existing config entries - for entry in self._async_current_entries(): - # If source is ignore bypass host check and continue through loop - if entry.source == SOURCE_IGNORE: - continue - - if await self.hass.async_add_executor_job( - _host_is_same, entry.data[CONF_HOST], import_data[CONF_HOST] - ): - updated_options: dict[str, Any] = {} - updated_data: dict[str, Any] = {} - remove_apps = False - - if entry.data[CONF_HOST] != import_data[CONF_HOST]: - updated_data[CONF_HOST] = import_data[CONF_HOST] - - if entry.data[CONF_NAME] != import_data[CONF_NAME]: - updated_data[CONF_NAME] = import_data[CONF_NAME] - - # Update entry.data[CONF_APPS] if import_config[CONF_APPS] differs, and - # pop entry.data[CONF_APPS] if import_config[CONF_APPS] is not specified - if entry.data.get(CONF_APPS) != import_data.get(CONF_APPS): - if not import_data.get(CONF_APPS): - remove_apps = True - else: - updated_options[CONF_APPS] = import_data[CONF_APPS] - - if entry.data.get(CONF_VOLUME_STEP) != import_data[CONF_VOLUME_STEP]: - updated_options[CONF_VOLUME_STEP] = import_data[CONF_VOLUME_STEP] - - if updated_options or updated_data or remove_apps: - new_data = entry.data.copy() - new_options = entry.options.copy() - - if remove_apps: - new_data.pop(CONF_APPS) - new_options.pop(CONF_APPS) - - if updated_data: - new_data.update(updated_data) - - # options are stored in entry options and data so update both - if updated_options: - new_data.update(updated_options) - new_options.update(updated_options) - - self.hass.config_entries.async_update_entry( - entry=entry, data=new_data, options=new_options - ) - return self.async_abort(reason="updated_entry") - - return self.async_abort(reason="already_configured_device") - - self._must_show_form = True - # Store config key/value pairs that are not configurable in user step so they - # don't get lost on user step - if import_data.get(CONF_APPS): - self._apps = copy.deepcopy(import_data[CONF_APPS]) - return await self.async_step_user(user_input=import_data) - async def async_step_zeroconf( self, discovery_info: zeroconf.ZeroconfServiceInfo ) -> ConfigFlowResult: @@ -433,11 +346,6 @@ class VizioConfigFlow(ConfigFlow, domain=DOMAIN): if pair_data: self._data[CONF_ACCESS_TOKEN] = pair_data.auth_token self._must_show_form = True - - if self.source == SOURCE_IMPORT: - # If user is pairing via config import, show different message - return await self.async_step_pairing_complete_import() - return await self.async_step_pairing_complete() # If no data was retrieved, it's assumed that the pairing attempt was not diff --git a/homeassistant/components/vizio/const.py b/homeassistant/components/vizio/const.py index 4eb96256d2e..8451ae747de 100644 --- a/homeassistant/components/vizio/const.py +++ b/homeassistant/components/vizio/const.py @@ -10,14 +10,6 @@ from homeassistant.components.media_player import ( MediaPlayerDeviceClass, MediaPlayerEntityFeature, ) -from homeassistant.const import ( - CONF_ACCESS_TOKEN, - CONF_DEVICE_CLASS, - CONF_EXCLUDE, - CONF_HOST, - CONF_INCLUDE, - CONF_NAME, -) import homeassistant.helpers.config_validation as cv from homeassistant.helpers.typing import VolDictType @@ -84,43 +76,3 @@ VIZIO_DEVICE_CLASSES = { MediaPlayerDeviceClass.SPEAKER: VIZIO_DEVICE_CLASS_SPEAKER, MediaPlayerDeviceClass.TV: VIZIO_DEVICE_CLASS_TV, } - -VIZIO_SCHEMA = { - vol.Required(CONF_HOST): cv.string, - vol.Optional(CONF_ACCESS_TOKEN): cv.string, - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_DEVICE_CLASS, default=DEFAULT_DEVICE_CLASS): vol.All( - cv.string, - vol.Lower, - vol.In([MediaPlayerDeviceClass.TV, MediaPlayerDeviceClass.SPEAKER]), - ), - vol.Optional(CONF_VOLUME_STEP, default=DEFAULT_VOLUME_STEP): vol.All( - vol.Coerce(int), vol.Range(min=1, max=10) - ), - vol.Optional(CONF_APPS): vol.All( - { - vol.Exclusive(CONF_INCLUDE, "apps_filter"): vol.All( - cv.ensure_list, [cv.string] - ), - vol.Exclusive(CONF_EXCLUDE, "apps_filter"): vol.All( - cv.ensure_list, [cv.string] - ), - vol.Optional(CONF_ADDITIONAL_CONFIGS): vol.All( - cv.ensure_list, - [ - { - vol.Required(CONF_NAME): cv.string, - vol.Required(CONF_CONFIG): { - vol.Required(CONF_APP_ID): cv.string, - vol.Required(CONF_NAME_SPACE): vol.Coerce(int), - vol.Optional(CONF_MESSAGE, default=None): vol.Or( - cv.string, None - ), - }, - }, - ], - ), - }, - cv.has_at_least_one_key(CONF_INCLUDE, CONF_EXCLUDE, CONF_ADDITIONAL_CONFIGS), - ), -} diff --git a/tests/components/vizio/const.py b/tests/components/vizio/const.py index 3e7b0c83c70..51151ae8f42 100644 --- a/tests/components/vizio/const.py +++ b/tests/components/vizio/const.py @@ -112,14 +112,6 @@ MOCK_OPTIONS = { CONF_VOLUME_STEP: VOLUME_STEP, } -MOCK_IMPORT_VALID_TV_CONFIG = { - CONF_NAME: NAME, - CONF_HOST: HOST, - CONF_DEVICE_CLASS: MediaPlayerDeviceClass.TV, - CONF_ACCESS_TOKEN: ACCESS_TOKEN, - CONF_VOLUME_STEP: VOLUME_STEP, -} - MOCK_TV_WITH_INCLUDE_CONFIG = { CONF_NAME: NAME, CONF_HOST: HOST, @@ -147,23 +139,6 @@ MOCK_TV_WITH_ADDITIONAL_APPS_CONFIG = { CONF_APPS: {CONF_ADDITIONAL_CONFIGS: [ADDITIONAL_APP_CONFIG]}, } -MOCK_SPEAKER_APPS_FAILURE = { - CONF_NAME: NAME, - CONF_HOST: HOST, - CONF_DEVICE_CLASS: MediaPlayerDeviceClass.SPEAKER, - CONF_ACCESS_TOKEN: ACCESS_TOKEN, - CONF_VOLUME_STEP: VOLUME_STEP, - CONF_APPS: {CONF_ADDITIONAL_CONFIGS: [ADDITIONAL_APP_CONFIG]}, -} - -MOCK_TV_APPS_FAILURE = { - CONF_NAME: NAME, - CONF_HOST: HOST, - CONF_DEVICE_CLASS: MediaPlayerDeviceClass.TV, - CONF_ACCESS_TOKEN: ACCESS_TOKEN, - CONF_VOLUME_STEP: VOLUME_STEP, - CONF_APPS: None, -} MOCK_TV_APPS_WITH_VALID_APPS_CONFIG = { CONF_HOST: HOST, diff --git a/tests/components/vizio/test_config_flow.py b/tests/components/vizio/test_config_flow.py index 42d4394ca80..2ef7c18bd04 100644 --- a/tests/components/vizio/test_config_flow.py +++ b/tests/components/vizio/test_config_flow.py @@ -3,30 +3,20 @@ import dataclasses import pytest -import voluptuous as vol from homeassistant.components.media_player import MediaPlayerDeviceClass -from homeassistant.components.vizio.config_flow import _get_config_schema from homeassistant.components.vizio.const import ( CONF_APPS, CONF_APPS_TO_INCLUDE_OR_EXCLUDE, - CONF_INCLUDE, CONF_VOLUME_STEP, - DEFAULT_NAME, - DEFAULT_VOLUME_STEP, DOMAIN, - VIZIO_SCHEMA, -) -from homeassistant.config_entries import ( - SOURCE_IGNORE, - SOURCE_IMPORT, - SOURCE_USER, - SOURCE_ZEROCONF, ) +from homeassistant.config_entries import SOURCE_IGNORE, SOURCE_USER, SOURCE_ZEROCONF from homeassistant.const import ( CONF_ACCESS_TOKEN, CONF_DEVICE_CLASS, CONF_HOST, + CONF_INCLUDE, CONF_NAME, CONF_PIN, ) @@ -38,14 +28,11 @@ from .const import ( CURRENT_APP, HOST, HOST2, - MOCK_IMPORT_VALID_TV_CONFIG, MOCK_INCLUDE_APPS, MOCK_INCLUDE_NO_APPS, MOCK_PIN_CONFIG, MOCK_SPEAKER_CONFIG, MOCK_TV_CONFIG_NO_TOKEN, - MOCK_TV_WITH_ADDITIONAL_APPS_CONFIG, - MOCK_TV_WITH_EXCLUDE_CONFIG, MOCK_USER_VALID_TV_CONFIG, MOCK_ZEROCONF_SERVICE_INFO, NAME, @@ -370,297 +357,6 @@ async def test_user_ignore(hass: HomeAssistant) -> None: assert result["type"] is FlowResultType.CREATE_ENTRY -@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_setup") -async def test_import_flow_minimum_fields(hass: HomeAssistant) -> None: - """Test import config flow with minimum fields.""" - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data=vol.Schema(VIZIO_SCHEMA)( - {CONF_HOST: HOST, CONF_DEVICE_CLASS: MediaPlayerDeviceClass.SPEAKER} - ), - ) - - assert result["type"] is FlowResultType.CREATE_ENTRY - assert result["title"] == DEFAULT_NAME - assert result["data"][CONF_NAME] == DEFAULT_NAME - assert result["data"][CONF_HOST] == HOST - assert result["data"][CONF_DEVICE_CLASS] == MediaPlayerDeviceClass.SPEAKER - assert result["data"][CONF_VOLUME_STEP] == DEFAULT_VOLUME_STEP - - -@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_setup") -async def test_import_flow_all_fields(hass: HomeAssistant) -> None: - """Test import config flow with all fields.""" - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data=vol.Schema(VIZIO_SCHEMA)(MOCK_IMPORT_VALID_TV_CONFIG), - ) - - assert result["type"] is FlowResultType.CREATE_ENTRY - assert result["title"] == NAME - assert result["data"][CONF_NAME] == NAME - assert result["data"][CONF_HOST] == HOST - assert result["data"][CONF_DEVICE_CLASS] == MediaPlayerDeviceClass.TV - assert result["data"][CONF_ACCESS_TOKEN] == ACCESS_TOKEN - assert result["data"][CONF_VOLUME_STEP] == VOLUME_STEP - - -@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_setup") -async def test_import_entity_already_configured(hass: HomeAssistant) -> None: - """Test entity is already configured during import setup.""" - entry = MockConfigEntry( - domain=DOMAIN, - data=vol.Schema(VIZIO_SCHEMA)(MOCK_SPEAKER_CONFIG), - options={CONF_VOLUME_STEP: VOLUME_STEP}, - ) - entry.add_to_hass(hass) - fail_entry = vol.Schema(VIZIO_SCHEMA)(MOCK_SPEAKER_CONFIG.copy()) - - result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_IMPORT}, data=fail_entry - ) - - assert result["type"] is FlowResultType.ABORT - assert result["reason"] == "already_configured_device" - - -@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_update") -async def test_import_flow_update_options(hass: HomeAssistant) -> None: - """Test import config flow with updated options.""" - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data=vol.Schema(VIZIO_SCHEMA)(MOCK_SPEAKER_CONFIG), - ) - await hass.async_block_till_done() - - assert result["result"].options == {CONF_VOLUME_STEP: DEFAULT_VOLUME_STEP} - assert result["type"] is FlowResultType.CREATE_ENTRY - entry_id = result["result"].entry_id - - updated_config = MOCK_SPEAKER_CONFIG.copy() - updated_config[CONF_VOLUME_STEP] = VOLUME_STEP + 1 - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data=vol.Schema(VIZIO_SCHEMA)(updated_config), - ) - - assert result["type"] is FlowResultType.ABORT - assert result["reason"] == "updated_entry" - config_entry = hass.config_entries.async_get_entry(entry_id) - assert config_entry.options[CONF_VOLUME_STEP] == VOLUME_STEP + 1 - - -@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_update") -async def test_import_flow_update_name_and_apps(hass: HomeAssistant) -> None: - """Test import config flow with updated name and apps.""" - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data=vol.Schema(VIZIO_SCHEMA)(MOCK_IMPORT_VALID_TV_CONFIG), - ) - await hass.async_block_till_done() - - assert result["result"].data[CONF_NAME] == NAME - assert result["type"] is FlowResultType.CREATE_ENTRY - entry_id = result["result"].entry_id - - updated_config = MOCK_IMPORT_VALID_TV_CONFIG.copy() - updated_config[CONF_NAME] = NAME2 - updated_config[CONF_APPS] = {CONF_INCLUDE: [CURRENT_APP]} - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data=vol.Schema(VIZIO_SCHEMA)(updated_config), - ) - - assert result["type"] is FlowResultType.ABORT - assert result["reason"] == "updated_entry" - config_entry = hass.config_entries.async_get_entry(entry_id) - assert config_entry.data[CONF_NAME] == NAME2 - assert config_entry.data[CONF_APPS] == {CONF_INCLUDE: [CURRENT_APP]} - assert config_entry.options[CONF_APPS] == {CONF_INCLUDE: [CURRENT_APP]} - - -@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_update") -async def test_import_flow_update_remove_apps(hass: HomeAssistant) -> None: - """Test import config flow with removed apps.""" - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data=vol.Schema(VIZIO_SCHEMA)(MOCK_TV_WITH_EXCLUDE_CONFIG), - ) - await hass.async_block_till_done() - - assert result["result"].data[CONF_NAME] == NAME - assert result["type"] is FlowResultType.CREATE_ENTRY - config_entry = hass.config_entries.async_get_entry(result["result"].entry_id) - assert CONF_APPS in config_entry.data - assert CONF_APPS in config_entry.options - - updated_config = MOCK_TV_WITH_EXCLUDE_CONFIG.copy() - updated_config.pop(CONF_APPS) - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data=vol.Schema(VIZIO_SCHEMA)(updated_config), - ) - - assert result["type"] is FlowResultType.ABORT - assert result["reason"] == "updated_entry" - assert CONF_APPS not in config_entry.data - assert CONF_APPS not in config_entry.options - - -@pytest.mark.usefixtures( - "vizio_connect", "vizio_bypass_setup", "vizio_complete_pairing" -) -async def test_import_needs_pairing(hass: HomeAssistant) -> None: - """Test pairing config flow when access token not provided for tv during import.""" - result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_IMPORT}, data=MOCK_TV_CONFIG_NO_TOKEN - ) - - assert result["type"] is FlowResultType.FORM - assert result["step_id"] == "user" - - result = await hass.config_entries.flow.async_configure( - result["flow_id"], user_input=MOCK_TV_CONFIG_NO_TOKEN - ) - - assert result["type"] is FlowResultType.FORM - assert result["step_id"] == "pair_tv" - - result = await hass.config_entries.flow.async_configure( - result["flow_id"], user_input=MOCK_PIN_CONFIG - ) - - assert result["type"] is FlowResultType.FORM - assert result["step_id"] == "pairing_complete_import" - - result = await hass.config_entries.flow.async_configure(result["flow_id"]) - - assert result["type"] is FlowResultType.CREATE_ENTRY - assert result["title"] == NAME - assert result["data"][CONF_NAME] == NAME - assert result["data"][CONF_HOST] == HOST - assert result["data"][CONF_DEVICE_CLASS] == MediaPlayerDeviceClass.TV - - -@pytest.mark.usefixtures( - "vizio_connect", "vizio_bypass_setup", "vizio_complete_pairing" -) -async def test_import_with_apps_needs_pairing(hass: HomeAssistant) -> None: - """Test pairing config flow when access token not provided for tv but apps are included during import.""" - import_config = MOCK_TV_CONFIG_NO_TOKEN.copy() - import_config[CONF_APPS] = {CONF_INCLUDE: [CURRENT_APP]} - - result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_IMPORT}, data=import_config - ) - - assert result["type"] is FlowResultType.FORM - assert result["step_id"] == "user" - - # Mock inputting info without apps to make sure apps get stored - result = await hass.config_entries.flow.async_configure( - result["flow_id"], - user_input=_get_config_schema(MOCK_TV_CONFIG_NO_TOKEN)(MOCK_TV_CONFIG_NO_TOKEN), - ) - - assert result["type"] is FlowResultType.FORM - assert result["step_id"] == "pair_tv" - - result = await hass.config_entries.flow.async_configure( - result["flow_id"], user_input=MOCK_PIN_CONFIG - ) - - assert result["type"] is FlowResultType.FORM - assert result["step_id"] == "pairing_complete_import" - - result = await hass.config_entries.flow.async_configure(result["flow_id"]) - - assert result["type"] is FlowResultType.CREATE_ENTRY - assert result["title"] == NAME - assert result["data"][CONF_NAME] == NAME - assert result["data"][CONF_HOST] == HOST - assert result["data"][CONF_DEVICE_CLASS] == MediaPlayerDeviceClass.TV - assert result["data"][CONF_APPS][CONF_INCLUDE] == [CURRENT_APP] - - -@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_update") -async def test_import_flow_additional_configs(hass: HomeAssistant) -> None: - """Test import config flow with additional configs defined in CONF_APPS.""" - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data=vol.Schema(VIZIO_SCHEMA)(MOCK_TV_WITH_ADDITIONAL_APPS_CONFIG), - ) - await hass.async_block_till_done() - - assert result["result"].data[CONF_NAME] == NAME - assert result["type"] is FlowResultType.CREATE_ENTRY - config_entry = hass.config_entries.async_get_entry(result["result"].entry_id) - assert CONF_APPS in config_entry.data - assert CONF_APPS not in config_entry.options - - -@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_setup") -async def test_import_error( - hass: HomeAssistant, - caplog: pytest.LogCaptureFixture, -) -> None: - """Test that error is logged when import config has an error.""" - entry = MockConfigEntry( - domain=DOMAIN, - data=vol.Schema(VIZIO_SCHEMA)(MOCK_SPEAKER_CONFIG), - options={CONF_VOLUME_STEP: VOLUME_STEP}, - unique_id=UNIQUE_ID, - ) - entry.add_to_hass(hass) - fail_entry = MOCK_SPEAKER_CONFIG.copy() - fail_entry[CONF_HOST] = "0.0.0.0" - - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data=vol.Schema(VIZIO_SCHEMA)(fail_entry), - ) - - assert result["type"] is FlowResultType.FORM - - # Ensure error gets logged - vizio_log_list = [ - log - for log in caplog.records - if log.name == "homeassistant.components.vizio.config_flow" - ] - assert len(vizio_log_list) == 1 - - -@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_setup") -async def test_import_ignore(hass: HomeAssistant) -> None: - """Test import config flow doesn't throw an error when there's an existing ignored source.""" - entry = MockConfigEntry( - domain=DOMAIN, - data=MOCK_SPEAKER_CONFIG, - options={CONF_VOLUME_STEP: VOLUME_STEP}, - source=SOURCE_IGNORE, - ) - entry.add_to_hass(hass) - - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data=vol.Schema(VIZIO_SCHEMA)(MOCK_SPEAKER_CONFIG), - ) - - assert result["type"] is FlowResultType.CREATE_ENTRY - - @pytest.mark.usefixtures( "vizio_connect", "vizio_bypass_setup", "vizio_guess_device_type" ) @@ -854,26 +550,3 @@ async def test_zeroconf_flow_already_configured_hostname(hass: HomeAssistant) -> # Flow should abort because device is already setup assert result["type"] is FlowResultType.ABORT assert result["reason"] == "already_configured" - - -@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_setup", "vizio_hostname_check") -async def test_import_flow_already_configured_hostname(hass: HomeAssistant) -> None: - """Test entity is already configured during import setup when existing entry uses hostname.""" - config = MOCK_SPEAKER_CONFIG.copy() - config[CONF_HOST] = "hostname" - entry = MockConfigEntry( - domain=DOMAIN, data=config, options={CONF_VOLUME_STEP: VOLUME_STEP} - ) - entry.add_to_hass(hass) - - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data=vol.Schema(VIZIO_SCHEMA)(MOCK_SPEAKER_CONFIG), - ) - - # Flow should abort because device was updated - assert result["type"] is FlowResultType.ABORT - assert result["reason"] == "updated_entry" - - assert entry.data[CONF_HOST] == HOST diff --git a/tests/components/vizio/test_init.py b/tests/components/vizio/test_init.py index c2b19377809..e004255ec6d 100644 --- a/tests/components/vizio/test_init.py +++ b/tests/components/vizio/test_init.py @@ -7,7 +7,6 @@ import pytest from homeassistant.components.vizio.const import DOMAIN from homeassistant.const import STATE_UNAVAILABLE, Platform from homeassistant.core import HomeAssistant -from homeassistant.setup import async_setup_component import homeassistant.util.dt as dt_util from .const import MOCK_SPEAKER_CONFIG, MOCK_USER_VALID_TV_CONFIG, UNIQUE_ID @@ -15,16 +14,6 @@ from .const import MOCK_SPEAKER_CONFIG, MOCK_USER_VALID_TV_CONFIG, UNIQUE_ID from tests.common import MockConfigEntry, async_fire_time_changed -@pytest.mark.usefixtures("vizio_connect", "vizio_update") -async def test_setup_component(hass: HomeAssistant) -> None: - """Test component setup.""" - assert await async_setup_component( - hass, DOMAIN, {DOMAIN: MOCK_USER_VALID_TV_CONFIG} - ) - await hass.async_block_till_done() - assert len(hass.states.async_entity_ids(Platform.MEDIA_PLAYER)) == 1 - - @pytest.mark.usefixtures("vizio_connect", "vizio_update") async def test_tv_load_and_unload(hass: HomeAssistant) -> None: """Test loading and unloading TV entry.""" diff --git a/tests/components/vizio/test_media_player.py b/tests/components/vizio/test_media_player.py index 12e19077c8e..a76dfa3fa2d 100644 --- a/tests/components/vizio/test_media_player.py +++ b/tests/components/vizio/test_media_player.py @@ -19,7 +19,6 @@ from pyvizio.const import ( MAX_VOLUME, UNKNOWN_APP, ) -import voluptuous as vol from homeassistant.components.media_player import ( ATTR_INPUT_SOURCE, @@ -42,7 +41,6 @@ from homeassistant.components.media_player import ( SERVICE_VOLUME_UP, MediaPlayerDeviceClass, ) -from homeassistant.components.vizio import validate_apps from homeassistant.components.vizio.const import ( CONF_ADDITIONAL_CONFIGS, CONF_APPS, @@ -50,7 +48,6 @@ from homeassistant.components.vizio.const import ( DEFAULT_VOLUME_STEP, DOMAIN, SERVICE_UPDATE_SETTING, - VIZIO_SCHEMA, ) from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON, STATE_UNAVAILABLE from homeassistant.core import HomeAssistant @@ -69,9 +66,7 @@ from .const import ( EQ_LIST, INPUT_LIST, INPUT_LIST_WITH_APPS, - MOCK_SPEAKER_APPS_FAILURE, MOCK_SPEAKER_CONFIG, - MOCK_TV_APPS_FAILURE, MOCK_TV_WITH_ADDITIONAL_APPS_CONFIG, MOCK_TV_WITH_EXCLUDE_CONFIG, MOCK_TV_WITH_INCLUDE_CONFIG, @@ -155,7 +150,7 @@ async def _test_setup_tv(hass: HomeAssistant, vizio_power_state: bool | None) -> config_entry = MockConfigEntry( domain=DOMAIN, - data=vol.Schema(VIZIO_SCHEMA)(MOCK_USER_VALID_TV_CONFIG), + data=MOCK_USER_VALID_TV_CONFIG, unique_id=UNIQUE_ID, ) @@ -181,7 +176,7 @@ async def _test_setup_speaker( config_entry = MockConfigEntry( domain=DOMAIN, - data=vol.Schema(VIZIO_SCHEMA)(MOCK_SPEAKER_CONFIG), + data=MOCK_SPEAKER_CONFIG, unique_id=UNIQUE_ID, ) @@ -215,7 +210,7 @@ async def _cm_for_test_setup_tv_with_apps( ) -> AsyncIterator[None]: """Context manager to setup test for Vizio TV with support for apps.""" config_entry = MockConfigEntry( - domain=DOMAIN, data=vol.Schema(VIZIO_SCHEMA)(device_config), unique_id=UNIQUE_ID + domain=DOMAIN, data=device_config, unique_id=UNIQUE_ID ) async with _cm_for_test_setup_without_apps( @@ -641,15 +636,6 @@ async def test_setup_with_apps_additional_apps_config( assert not service_call2.called -def test_invalid_apps_config(hass: HomeAssistant) -> None: - """Test that schema validation fails on certain conditions.""" - with pytest.raises(vol.Invalid): - vol.Schema(vol.All(VIZIO_SCHEMA, validate_apps))(MOCK_TV_APPS_FAILURE) - - with pytest.raises(vol.Invalid): - vol.Schema(vol.All(VIZIO_SCHEMA, validate_apps))(MOCK_SPEAKER_APPS_FAILURE) - - @pytest.mark.usefixtures("vizio_connect", "vizio_update_with_apps") async def test_setup_with_unknown_app_config( hass: HomeAssistant, @@ -687,7 +673,7 @@ async def test_setup_tv_without_mute(hass: HomeAssistant) -> None: """Test Vizio TV entity setup when mute property isn't returned by Vizio API.""" config_entry = MockConfigEntry( domain=DOMAIN, - data=vol.Schema(VIZIO_SCHEMA)(MOCK_USER_VALID_TV_CONFIG), + data=MOCK_USER_VALID_TV_CONFIG, unique_id=UNIQUE_ID, ) @@ -742,7 +728,7 @@ async def test_vizio_update_with_apps_on_input(hass: HomeAssistant) -> None: """Test a vizio TV with apps that is on a TV input.""" config_entry = MockConfigEntry( domain=DOMAIN, - data=vol.Schema(VIZIO_SCHEMA)(MOCK_USER_VALID_TV_CONFIG), + data=MOCK_USER_VALID_TV_CONFIG, unique_id=UNIQUE_ID, ) await _add_config_entry_to_hass(hass, config_entry)