core/tests/components/vizio/test_config_flow.py

290 lines
8.8 KiB
Python
Raw Normal View History

Add Config Flow support, Device Registry support, available property to vizio component (#30653) * add config flow support, device registry support, available property * raise PlatformNotReady if HA cant connect to device * remove test logging statement and fix integration title * store import and last user input values so user can see errors next to value that caused error * add PARALLEL_UPDATES * add missing type hints * add missing type hints to tests * fix options config flow title * changes based on review * better key name for message when cant connect * fix missed update to key name * fix comments * remove logger from test which was used to debug and update test function names and docstrings to be more accurate * add __init__.py to vizio tests module * readded options flow and updated main component to handle options updates, set unique ID to serial, fixes based on review * pop hass.data in media_player unload instead of in __init__ since it is set in media_player * update requirements_all and requirements_test_all * make unique_id key name a constant * remove additional line breaks after docstrings * unload entries during test_user_flow and test_import_flow tests to hopefully reduce teardown time * try to speed up tests * remove unnecessary code, use event bus to track options updates, move patches to pytest fixtures and fix patch scoping * fix comment * remove translations from commit * suppress API error logging when checking for device availability as it can spam logs * update requirements_all and requirements_test_all * dont pass hass to entity since it is passed to entity anyway, remove entity unload from tests, other misc changes from review * fix clearing listeners * use config_entry unique ID for unique ID and use config_entry entry ID as update signal * update config flow based on suggested changes * update volume step on config import if it doesn't match config_entry volume step * update config_entry data and options with new volume step value * copy entry.data and entry.options before updating when updating config_entry * fix test_import_entity_already_configured
2020-01-15 10:43:55 +00:00
"""Tests for Vizio config flow."""
import logging
from asynctest import patch
import pytest
import voluptuous as vol
from homeassistant import data_entry_flow
from homeassistant.components.vizio import VIZIO_SCHEMA
from homeassistant.components.vizio.const import (
CONF_VOLUME_STEP,
DEFAULT_NAME,
DEFAULT_VOLUME_STEP,
DOMAIN,
)
from homeassistant.const import (
CONF_ACCESS_TOKEN,
CONF_DEVICE_CLASS,
CONF_HOST,
CONF_NAME,
)
from homeassistant.helpers.typing import HomeAssistantType
from tests.common import MockConfigEntry
_LOGGER = logging.getLogger(__name__)
NAME = "Vizio"
HOST = "192.168.1.1:9000"
DEVICE_CLASS_TV = "tv"
DEVICE_CLASS_SOUNDBAR = "soundbar"
ACCESS_TOKEN = "deadbeef"
VOLUME_STEP = 2
UNIQUE_ID = "testid"
MOCK_USER_VALID_TV_ENTRY = {
CONF_NAME: NAME,
CONF_HOST: HOST,
CONF_DEVICE_CLASS: DEVICE_CLASS_TV,
CONF_ACCESS_TOKEN: ACCESS_TOKEN,
}
MOCK_IMPORT_VALID_TV_ENTRY = {
CONF_NAME: NAME,
CONF_HOST: HOST,
CONF_DEVICE_CLASS: DEVICE_CLASS_TV,
CONF_ACCESS_TOKEN: ACCESS_TOKEN,
CONF_VOLUME_STEP: VOLUME_STEP,
}
MOCK_INVALID_TV_ENTRY = {
CONF_NAME: NAME,
CONF_HOST: HOST,
CONF_DEVICE_CLASS: DEVICE_CLASS_TV,
}
MOCK_SOUNDBAR_ENTRY = {
CONF_NAME: NAME,
CONF_HOST: HOST,
CONF_DEVICE_CLASS: DEVICE_CLASS_SOUNDBAR,
}
@pytest.fixture(name="vizio_connect")
def vizio_connect_fixture():
"""Mock valid vizio device and entry setup."""
with patch(
"homeassistant.components.vizio.config_flow.VizioAsync.validate_ha_config",
return_value=True,
), patch(
"homeassistant.components.vizio.config_flow.VizioAsync.get_unique_id",
return_value=UNIQUE_ID,
), patch(
"homeassistant.components.vizio.async_setup_entry", return_value=True
):
yield
@pytest.fixture(name="vizio_cant_connect")
def vizio_cant_connect_fixture():
"""Mock vizio device cant connect."""
with patch(
"homeassistant.components.vizio.config_flow.VizioAsync.validate_ha_config",
return_value=False,
):
yield
async def test_user_flow_minimum_fields(hass: HomeAssistantType, vizio_connect) -> None:
"""Test user config flow with minimum fields."""
# test form shows
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "user"}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "user"
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_NAME: NAME,
CONF_HOST: HOST,
CONF_DEVICE_CLASS: DEVICE_CLASS_SOUNDBAR,
},
)
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == NAME
assert result["data"][CONF_NAME] == NAME
assert result["data"][CONF_HOST] == HOST
assert result["data"][CONF_DEVICE_CLASS] == DEVICE_CLASS_SOUNDBAR
async def test_user_flow_all_fields(hass: HomeAssistantType, vizio_connect) -> None:
"""Test user config flow with all fields."""
# test form shows
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "user"}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "user"
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_NAME: NAME,
CONF_HOST: HOST,
CONF_DEVICE_CLASS: DEVICE_CLASS_TV,
CONF_ACCESS_TOKEN: ACCESS_TOKEN,
},
)
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == NAME
assert result["data"][CONF_NAME] == NAME
assert result["data"][CONF_HOST] == HOST
assert result["data"][CONF_DEVICE_CLASS] == DEVICE_CLASS_TV
assert result["data"][CONF_ACCESS_TOKEN] == ACCESS_TOKEN
async def test_user_host_already_configured(
hass: HomeAssistantType, vizio_connect
) -> None:
"""Test host is already configured during user setup."""
entry = MockConfigEntry(
domain=DOMAIN,
data=MOCK_SOUNDBAR_ENTRY,
options={CONF_VOLUME_STEP: VOLUME_STEP},
)
entry.add_to_hass(hass)
fail_entry = MOCK_SOUNDBAR_ENTRY.copy()
fail_entry[CONF_NAME] = "newtestname"
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "user"}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "user"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=fail_entry,
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {CONF_HOST: "host_exists"}
async def test_user_name_already_configured(
hass: HomeAssistantType, vizio_connect
) -> None:
"""Test name is already configured during user setup."""
entry = MockConfigEntry(
domain=DOMAIN,
data=MOCK_SOUNDBAR_ENTRY,
options={CONF_VOLUME_STEP: VOLUME_STEP},
)
entry.add_to_hass(hass)
fail_entry = MOCK_SOUNDBAR_ENTRY.copy()
fail_entry[CONF_HOST] = "0.0.0.0"
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "user"}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "user"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], fail_entry
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {CONF_NAME: "name_exists"}
async def test_user_error_on_could_not_connect(
hass: HomeAssistantType, vizio_cant_connect
) -> None:
"""Test with could_not_connect during user_setup."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "user"}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "user"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], MOCK_USER_VALID_TV_ENTRY
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {"base": "cant_connect"}
async def test_user_error_on_tv_needs_token(
hass: HomeAssistantType, vizio_connect
) -> None:
"""Test when config fails custom validation for non null access token when device_class = tv during user setup."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "user"}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "user"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], MOCK_INVALID_TV_ENTRY
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {"base": "tv_needs_token"}
async def test_import_flow_minimum_fields(
hass: HomeAssistantType, vizio_connect
) -> None:
"""Test import config flow with minimum fields."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": "import"},
data=vol.Schema(VIZIO_SCHEMA)(
{CONF_HOST: HOST, CONF_DEVICE_CLASS: DEVICE_CLASS_SOUNDBAR}
),
)
assert result["type"] == data_entry_flow.RESULT_TYPE_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] == DEVICE_CLASS_SOUNDBAR
assert result["data"][CONF_VOLUME_STEP] == DEFAULT_VOLUME_STEP
async def test_import_flow_all_fields(hass: HomeAssistantType, vizio_connect) -> None:
"""Test import config flow with all fields."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": "import"},
data=vol.Schema(VIZIO_SCHEMA)(MOCK_IMPORT_VALID_TV_ENTRY),
)
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == NAME
assert result["data"][CONF_NAME] == NAME
assert result["data"][CONF_HOST] == HOST
assert result["data"][CONF_DEVICE_CLASS] == DEVICE_CLASS_TV
assert result["data"][CONF_ACCESS_TOKEN] == ACCESS_TOKEN
assert result["data"][CONF_VOLUME_STEP] == VOLUME_STEP
async def test_import_entity_already_configured(
hass: HomeAssistantType, vizio_connect
) -> None:
"""Test entity is already configured during import setup."""
entry = MockConfigEntry(
domain=DOMAIN,
data=vol.Schema(VIZIO_SCHEMA)(MOCK_SOUNDBAR_ENTRY),
options={CONF_VOLUME_STEP: VOLUME_STEP},
)
entry.add_to_hass(hass)
fail_entry = vol.Schema(VIZIO_SCHEMA)(MOCK_SOUNDBAR_ENTRY.copy())
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "import"}, data=fail_entry
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "already_setup"