Fix options update during import config flow step for vizio component (Bugfix for #30653) (#30977)

* fix options update logic during import

* add missing tests

* fix abort reasons and strings, add missing test

* combine steps when testing esn already exists

* readd removed test

* no mock_coro_func needed

* add block_until_done and assert entry options
pull/30995/head
Raman Gupta 2020-01-19 23:13:15 -05:00 committed by Paulus Schoutsen
parent 0c3ffbe282
commit e535133016
3 changed files with 107 additions and 28 deletions

View File

@ -111,7 +111,9 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
if await self.async_set_unique_id(
unique_id=unique_id, raise_on_progress=True
):
return self.async_abort(reason="already_setup")
return self.async_abort(
reason="already_setup_with_diff_host_and_name"
)
return self.async_create_entry(
title=user_input[CONF_NAME], data=user_input
@ -128,16 +130,19 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
if entry.data[CONF_HOST] == import_config[CONF_HOST] and entry.data[
CONF_NAME
] == import_config.get(CONF_NAME):
new_options = {}
updated_options = {}
if entry.data[CONF_VOLUME_STEP] != import_config[CONF_VOLUME_STEP]:
new_options[CONF_VOLUME_STEP] = import_config[CONF_VOLUME_STEP]
updated_options[CONF_VOLUME_STEP] = import_config[CONF_VOLUME_STEP]
if updated_options:
new_data = entry.data.copy()
new_data.update(updated_options)
new_options = entry.options.copy()
new_options.update(updated_options)
if new_options:
self.hass.config_entries.async_update_entry(
entry=entry,
data=entry.data.copy().update(new_options),
options=entry.options.copy().update(new_options),
entry=entry, data=new_data, options=new_options,
)
return self.async_abort(reason="updated_options")

View File

@ -13,16 +13,14 @@
}
},
"error": {
"host_exists": "Host already configured.",
"name_exists": "Name already configured.",
"host_exists": "Vizio device with specified host already configured.",
"name_exists": "Vizio device with specified name already configured.",
"cant_connect": "Could not connect to the device. [Review the docs](https://www.home-assistant.io/integrations/vizio/) and re-verify that:\n- The device is powered on\n- The device is connected to the network\n- The values you filled in are accurate\nbefore attempting to resubmit.",
"tv_needs_token": "When Device Type is `tv` then a valid Access Token is needed."
},
"abort": {
"already_in_progress": "Config flow for vizio component already in progress.",
"already_setup": "This entry has already been setup.",
"host_exists": "Vizio component with host already configured.",
"name_exists": "Vizio component with name already configured.",
"already_setup_with_diff_host_and_name": "This entry appears to have already been setup with a different host and name based on its serial number. Please remove any old entries from your configuration.yaml and from the Integrations menu before reattempting to add this device.",
"updated_options": "This entry has already been setup but the options defined in the config do not match the previously imported options values so the config entry has been updated accordingly."
}
},

View File

@ -14,6 +14,7 @@ from homeassistant.components.vizio.const import (
DOMAIN,
VIZIO_SCHEMA,
)
from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER
from homeassistant.const import (
CONF_ACCESS_TOKEN,
CONF_DEVICE_CLASS,
@ -27,7 +28,9 @@ 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"
@ -69,12 +72,27 @@ def vizio_connect_fixture():
), 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_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."""
@ -85,11 +103,13 @@ def vizio_cant_connect_fixture():
yield
async def test_user_flow_minimum_fields(hass: HomeAssistantType, vizio_connect) -> None:
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": "user"}
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "user"
@ -110,11 +130,13 @@ async def test_user_flow_minimum_fields(hass: HomeAssistantType, vizio_connect)
assert result["data"][CONF_DEVICE_CLASS] == DEVICE_CLASS_SPEAKER
async def test_user_flow_all_fields(hass: HomeAssistantType, vizio_connect) -> None:
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": "user"}
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
@ -162,7 +184,7 @@ async def test_options_flow(hass: HomeAssistantType) -> None:
async def test_user_host_already_configured(
hass: HomeAssistantType, vizio_connect
hass: HomeAssistantType, vizio_connect, vizio_bypass_setup
) -> None:
"""Test host is already configured during user setup."""
entry = MockConfigEntry(
@ -175,7 +197,7 @@ async def test_user_host_already_configured(
fail_entry[CONF_NAME] = "newtestname"
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "user"}
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
@ -190,7 +212,7 @@ async def test_user_host_already_configured(
async def test_user_name_already_configured(
hass: HomeAssistantType, vizio_connect
hass: HomeAssistantType, vizio_connect, vizio_bypass_setup
) -> None:
"""Test name is already configured during user setup."""
entry = MockConfigEntry(
@ -204,7 +226,7 @@ async def test_user_name_already_configured(
fail_entry[CONF_HOST] = "0.0.0.0"
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "user"}
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "user"
@ -217,12 +239,34 @@ async def test_user_name_already_configured(
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": "user"}
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
@ -236,11 +280,11 @@ async def test_user_error_on_could_not_connect(
async def test_user_error_on_tv_needs_token(
hass: HomeAssistantType, vizio_connect
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": "user"}
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
@ -255,7 +299,7 @@ async def test_user_error_on_tv_needs_token(
async def test_import_flow_minimum_fields(
hass: HomeAssistantType, vizio_connect
hass: HomeAssistantType, vizio_connect, vizio_bypass_setup
) -> None:
"""Test import config flow with minimum fields."""
result = await hass.config_entries.flow.async_init(
@ -274,7 +318,9 @@ async def test_import_flow_minimum_fields(
assert result["data"][CONF_VOLUME_STEP] == DEFAULT_VOLUME_STEP
async def test_import_flow_all_fields(hass: HomeAssistantType, vizio_connect) -> None:
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,
@ -292,7 +338,7 @@ async def test_import_flow_all_fields(hass: HomeAssistantType, vizio_connect) ->
async def test_import_entity_already_configured(
hass: HomeAssistantType, vizio_connect
hass: HomeAssistantType, vizio_connect, vizio_bypass_setup
) -> None:
"""Test entity is already configured during import setup."""
entry = MockConfigEntry(
@ -309,3 +355,33 @@ async def test_import_entity_already_configured(
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
)