* add media player test and update media player logic to qualify vizio for platinum quality score * add SCAN_INTERVAL and log message once when device goes from available to unavailable and vice versa * move test constants into one file to avoid defining dupes in each test file * move constant to shrink diff * move pytest fixtures to conftest.py * remove commented out code * move unload test to test_init * updates to tests and logging based on review * bypass notification service * add fixture so component setup makes it through config flow * split failure tests into two * fix setup and entity check for test_init and setup failures in test_media_player * make domain references consistent across test files * remove logging steps that were introduced to help debug * move common patches out to new fixture and use config entry everywhere appropriate * fix docstring * add test for update options to increase code coverage * add one more assert * refactor test_media_player to move boiler plate logic out of each test into _test_init function * final refactor of test_media_player to move repeat logic into separate function * update docstrings * refactor setup failure tests to move shared logic into private function * fix last new functions code to use variable instead of static config variable * remove trailing comma * test that volume_step gets properly passed to Vizio volume function * fix comment language * assert with unittest.mock.call in _test_service and use config_entries.async_setup instead of config_entries.async_add * replace config_entries.async_add with config_entries.async_setup everywhere * simplify if statement for argument assertion * fix logging based on style guide * remove accidentally committed changes * update scan interval to something more reasonable and add tests for availability changes * change filter function to list comprehension, simplify log messages, remove default entity id from logs since it is user configurable, fix docstrings
353 lines
12 KiB
Python
353 lines
12 KiB
Python
"""Tests for Vizio config flow."""
|
|
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, SOURCE_ZEROCONF
|
|
from homeassistant.const import (
|
|
CONF_ACCESS_TOKEN,
|
|
CONF_DEVICE_CLASS,
|
|
CONF_HOST,
|
|
CONF_NAME,
|
|
)
|
|
from homeassistant.helpers.typing import HomeAssistantType
|
|
|
|
from .const import (
|
|
ACCESS_TOKEN,
|
|
HOST,
|
|
HOST2,
|
|
MOCK_IMPORT_VALID_TV_CONFIG,
|
|
MOCK_INVALID_TV_CONFIG,
|
|
MOCK_SPEAKER_CONFIG,
|
|
MOCK_USER_VALID_TV_CONFIG,
|
|
MOCK_ZEROCONF_SERVICE_INFO,
|
|
NAME,
|
|
NAME2,
|
|
UNIQUE_ID,
|
|
VOLUME_STEP,
|
|
)
|
|
|
|
from tests.common import MockConfigEntry
|
|
|
|
|
|
async def test_user_flow_minimum_fields(
|
|
hass: HomeAssistantType,
|
|
vizio_connect: pytest.fixture,
|
|
vizio_bypass_setup: pytest.fixture,
|
|
) -> 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=MOCK_SPEAKER_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_SPEAKER
|
|
|
|
|
|
async def test_user_flow_all_fields(
|
|
hass: HomeAssistantType,
|
|
vizio_connect: pytest.fixture,
|
|
vizio_bypass_setup: pytest.fixture,
|
|
) -> 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=MOCK_USER_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
|
|
|
|
|
|
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, 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: pytest.fixture,
|
|
vizio_bypass_setup: pytest.fixture,
|
|
) -> 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}, data=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: pytest.fixture,
|
|
vizio_bypass_setup: pytest.fixture,
|
|
) -> 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}, data=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: pytest.fixture,
|
|
vizio_bypass_setup: pytest.fixture,
|
|
) -> 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: pytest.fixture
|
|
) -> None:
|
|
"""Test with could_not_connect during user_setup."""
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": SOURCE_USER}, data=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: pytest.fixture,
|
|
vizio_bypass_setup: pytest.fixture,
|
|
) -> 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}, data=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: pytest.fixture,
|
|
vizio_bypass_setup: pytest.fixture,
|
|
) -> 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: 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: pytest.fixture,
|
|
vizio_bypass_setup: pytest.fixture,
|
|
) -> 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"] == 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: pytest.fixture,
|
|
vizio_bypass_setup: pytest.fixture,
|
|
) -> 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"] == data_entry_flow.RESULT_TYPE_ABORT
|
|
assert result["reason"] == "already_setup"
|
|
|
|
|
|
async def test_import_flow_update_options(
|
|
hass: HomeAssistantType,
|
|
vizio_connect: pytest.fixture,
|
|
vizio_bypass_update: pytest.fixture,
|
|
) -> 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
|
|
)
|
|
|
|
|
|
async def test_zeroconf_flow(
|
|
hass: HomeAssistantType,
|
|
vizio_connect: pytest.fixture,
|
|
vizio_bypass_setup: pytest.fixture,
|
|
vizio_guess_device_type: pytest.fixture,
|
|
) -> None:
|
|
"""Test zeroconf config flow."""
|
|
discovery_info = MOCK_ZEROCONF_SERVICE_INFO.copy()
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
|
)
|
|
|
|
# Form should always show even if all required properties are discovered
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
assert result["step_id"] == "user"
|
|
|
|
# Apply discovery updates to entry to mimick when user hits submit without changing
|
|
# defaults which were set from discovery parameters
|
|
user_input = result["data_schema"](discovery_info)
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"], user_input=user_input
|
|
)
|
|
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
|
assert result["title"] == NAME
|
|
assert result["data"][CONF_HOST] == HOST
|
|
assert result["data"][CONF_NAME] == NAME
|
|
assert result["data"][CONF_DEVICE_CLASS] == DEVICE_CLASS_SPEAKER
|
|
|
|
|
|
async def test_zeroconf_flow_already_configured(
|
|
hass: HomeAssistantType,
|
|
vizio_connect: pytest.fixture,
|
|
vizio_bypass_setup: pytest.fixture,
|
|
) -> None:
|
|
"""Test entity is already configured during zeroconf setup."""
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN, data=MOCK_SPEAKER_CONFIG, options={CONF_VOLUME_STEP: VOLUME_STEP}
|
|
)
|
|
entry.add_to_hass(hass)
|
|
|
|
# Try rediscovering same device
|
|
discovery_info = MOCK_ZEROCONF_SERVICE_INFO.copy()
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
|
|
)
|
|
|
|
# Flow should abort because device is already setup
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
|
assert result["reason"] == "already_setup"
|