388 lines
12 KiB
Python
388 lines
12 KiB
Python
"""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.media_player import DEVICE_CLASS_SPEAKER, DEVICE_CLASS_TV
|
|
from homeassistant.components.vizio.const import (
|
|
CONF_VOLUME_STEP,
|
|
DEFAULT_NAME,
|
|
DEFAULT_VOLUME_STEP,
|
|
DOMAIN,
|
|
VIZIO_SCHEMA,
|
|
)
|
|
from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER
|
|
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"
|
|
NAME2 = "Vizio2"
|
|
HOST = "192.168.1.1:9000"
|
|
HOST2 = "192.168.1.2:9000"
|
|
ACCESS_TOKEN = "deadbeef"
|
|
VOLUME_STEP = 2
|
|
UNIQUE_ID = "testid"
|
|
|
|
MOCK_USER_VALID_TV_CONFIG = {
|
|
CONF_NAME: NAME,
|
|
CONF_HOST: HOST,
|
|
CONF_DEVICE_CLASS: DEVICE_CLASS_TV,
|
|
CONF_ACCESS_TOKEN: ACCESS_TOKEN,
|
|
}
|
|
|
|
MOCK_IMPORT_VALID_TV_CONFIG = {
|
|
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_CONFIG = {
|
|
CONF_NAME: NAME,
|
|
CONF_HOST: HOST,
|
|
CONF_DEVICE_CLASS: DEVICE_CLASS_TV,
|
|
}
|
|
|
|
MOCK_SPEAKER_CONFIG = {
|
|
CONF_NAME: NAME,
|
|
CONF_HOST: HOST,
|
|
CONF_DEVICE_CLASS: DEVICE_CLASS_SPEAKER,
|
|
}
|
|
|
|
|
|
@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,
|
|
):
|
|
yield
|
|
|
|
|
|
@pytest.fixture(name="vizio_bypass_setup")
|
|
def vizio_bypass_setup_fixture():
|
|
"""Mock component setup."""
|
|
with patch("homeassistant.components.vizio.async_setup_entry", return_value=True):
|
|
yield
|
|
|
|
|
|
@pytest.fixture(name="vizio_bypass_update")
|
|
def vizio_bypass_update_fixture():
|
|
"""Mock component update."""
|
|
with patch(
|
|
"homeassistant.components.vizio.media_player.VizioAsync.can_connect",
|
|
return_value=True,
|
|
), patch("homeassistant.components.vizio.media_player.VizioDevice.async_update"):
|
|
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, vizio_bypass_setup
|
|
) -> None:
|
|
"""Test user config flow with minimum fields."""
|
|
# test form shows
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": 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_SPEAKER,
|
|
},
|
|
)
|
|
|
|
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_SPEAKER
|
|
|
|
|
|
async def test_user_flow_all_fields(
|
|
hass: HomeAssistantType, vizio_connect, vizio_bypass_setup
|
|
) -> None:
|
|
"""Test user config flow with all fields."""
|
|
# test form shows
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": 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_options_flow(hass: HomeAssistantType) -> None:
|
|
"""Test options config flow."""
|
|
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_SPEAKER_CONFIG)
|
|
entry.add_to_hass(hass)
|
|
|
|
assert not entry.options
|
|
|
|
result = await hass.config_entries.options.async_init(
|
|
entry.entry_id, context={"source": "test"}, data=None
|
|
)
|
|
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
assert result["step_id"] == "init"
|
|
|
|
result = await hass.config_entries.options.async_configure(
|
|
result["flow_id"], user_input={CONF_VOLUME_STEP: VOLUME_STEP},
|
|
)
|
|
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
|
assert result["title"] == ""
|
|
assert result["data"][CONF_VOLUME_STEP] == VOLUME_STEP
|
|
|
|
|
|
async def test_user_host_already_configured(
|
|
hass: HomeAssistantType, vizio_connect, vizio_bypass_setup
|
|
) -> None:
|
|
"""Test host is already configured during user setup."""
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data=MOCK_SPEAKER_CONFIG,
|
|
options={CONF_VOLUME_STEP: VOLUME_STEP},
|
|
)
|
|
entry.add_to_hass(hass)
|
|
fail_entry = MOCK_SPEAKER_CONFIG.copy()
|
|
fail_entry[CONF_NAME] = "newtestname"
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": 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, vizio_bypass_setup
|
|
) -> None:
|
|
"""Test name is already configured during user setup."""
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data=MOCK_SPEAKER_CONFIG,
|
|
options={CONF_VOLUME_STEP: VOLUME_STEP},
|
|
)
|
|
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_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_esn_already_exists(
|
|
hass: HomeAssistantType, vizio_connect, vizio_bypass_setup
|
|
) -> None:
|
|
"""Test ESN is already configured with different host and name during user setup."""
|
|
# Set up new entry
|
|
MockConfigEntry(
|
|
domain=DOMAIN, data=MOCK_SPEAKER_CONFIG, unique_id=UNIQUE_ID
|
|
).add_to_hass(hass)
|
|
|
|
# Set up new entry with same unique_id but different host and name
|
|
fail_entry = MOCK_SPEAKER_CONFIG.copy()
|
|
fail_entry[CONF_HOST] = HOST2
|
|
fail_entry[CONF_NAME] = NAME2
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": SOURCE_USER}, data=fail_entry
|
|
)
|
|
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
|
assert result["reason"] == "already_setup_with_diff_host_and_name"
|
|
|
|
|
|
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": 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_CONFIG
|
|
)
|
|
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, vizio_bypass_setup
|
|
) -> 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": 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_CONFIG
|
|
)
|
|
|
|
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, vizio_bypass_setup
|
|
) -> 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_SPEAKER}
|
|
),
|
|
)
|
|
|
|
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_SPEAKER
|
|
assert result["data"][CONF_VOLUME_STEP] == DEFAULT_VOLUME_STEP
|
|
|
|
|
|
async def test_import_flow_all_fields(
|
|
hass: HomeAssistantType, vizio_connect, vizio_bypass_setup
|
|
) -> 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_CONFIG),
|
|
)
|
|
|
|
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, vizio_bypass_setup
|
|
) -> 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": "import"}, data=fail_entry
|
|
)
|
|
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
|
assert result["reason"] == "already_setup"
|
|
|
|
|
|
async def test_import_flow_update_options(
|
|
hass: HomeAssistantType, vizio_connect, vizio_bypass_update
|
|
) -> 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_IMPORT_VALID_TV_CONFIG),
|
|
)
|
|
await hass.async_block_till_done()
|
|
assert result["result"].options == {CONF_VOLUME_STEP: VOLUME_STEP}
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
|
entry_id = result["result"].entry_id
|
|
|
|
updated_config = MOCK_IMPORT_VALID_TV_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"] == data_entry_flow.RESULT_TYPE_ABORT
|
|
assert result["reason"] == "updated_options"
|
|
assert (
|
|
hass.config_entries.async_get_entry(entry_id).options[CONF_VOLUME_STEP]
|
|
== VOLUME_STEP + 1
|
|
)
|