Don't allow creating or updating input_select with duplicates (#66718)
* Don't allow creating or updating input_select with duplicates * Simplify error message * Improve error message
This commit is contained in:
parent
a9aefb66b5
commit
4236764fd5
2 changed files with 22 additions and 20 deletions
|
@ -45,15 +45,27 @@ STORAGE_KEY = DOMAIN
|
||||||
STORAGE_VERSION = 1
|
STORAGE_VERSION = 1
|
||||||
STORAGE_VERSION_MINOR = 2
|
STORAGE_VERSION_MINOR = 2
|
||||||
|
|
||||||
|
|
||||||
|
def _unique(options: Any) -> Any:
|
||||||
|
try:
|
||||||
|
return vol.Unique()(options)
|
||||||
|
except vol.Invalid as exc:
|
||||||
|
raise HomeAssistantError("Duplicate options are not allowed") from exc
|
||||||
|
|
||||||
|
|
||||||
CREATE_FIELDS = {
|
CREATE_FIELDS = {
|
||||||
vol.Required(CONF_NAME): vol.All(str, vol.Length(min=1)),
|
vol.Required(CONF_NAME): vol.All(str, vol.Length(min=1)),
|
||||||
vol.Required(CONF_OPTIONS): vol.All(cv.ensure_list, vol.Length(min=1), [cv.string]),
|
vol.Required(CONF_OPTIONS): vol.All(
|
||||||
|
cv.ensure_list, vol.Length(min=1), _unique, [cv.string]
|
||||||
|
),
|
||||||
vol.Optional(CONF_INITIAL): cv.string,
|
vol.Optional(CONF_INITIAL): cv.string,
|
||||||
vol.Optional(CONF_ICON): cv.icon,
|
vol.Optional(CONF_ICON): cv.icon,
|
||||||
}
|
}
|
||||||
UPDATE_FIELDS = {
|
UPDATE_FIELDS = {
|
||||||
vol.Optional(CONF_NAME): cv.string,
|
vol.Optional(CONF_NAME): cv.string,
|
||||||
vol.Optional(CONF_OPTIONS): vol.All(cv.ensure_list, vol.Length(min=1), [cv.string]),
|
vol.Optional(CONF_OPTIONS): vol.All(
|
||||||
|
cv.ensure_list, vol.Length(min=1), _unique, [cv.string]
|
||||||
|
),
|
||||||
vol.Optional(CONF_INITIAL): cv.string,
|
vol.Optional(CONF_INITIAL): cv.string,
|
||||||
vol.Optional(CONF_ICON): cv.icon,
|
vol.Optional(CONF_ICON): cv.icon,
|
||||||
}
|
}
|
||||||
|
|
|
@ -707,16 +707,12 @@ async def test_update_duplicates(hass, hass_ws_client, storage_setup, caplog):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
resp = await client.receive_json()
|
resp = await client.receive_json()
|
||||||
assert resp["success"]
|
assert not resp["success"]
|
||||||
|
assert resp["error"]["code"] == "unknown_error"
|
||||||
assert (
|
assert resp["error"]["message"] == "Duplicate options are not allowed"
|
||||||
"Input select 'from storage' with options "
|
|
||||||
"['new option', 'newer option', 'newer option'] "
|
|
||||||
"had duplicated options, the duplicates have been removed"
|
|
||||||
) in caplog.text
|
|
||||||
|
|
||||||
state = hass.states.get(input_entity_id)
|
state = hass.states.get(input_entity_id)
|
||||||
assert state.attributes[ATTR_OPTIONS] == ["new option", "newer option"]
|
assert state.attributes[ATTR_OPTIONS] == ["yaml update 1", "yaml update 2"]
|
||||||
|
|
||||||
|
|
||||||
async def test_ws_create(hass, hass_ws_client, storage_setup):
|
async def test_ws_create(hass, hass_ws_client, storage_setup):
|
||||||
|
@ -774,17 +770,11 @@ async def test_ws_create_duplicates(hass, hass_ws_client, storage_setup, caplog)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
resp = await client.receive_json()
|
resp = await client.receive_json()
|
||||||
assert resp["success"]
|
assert not resp["success"]
|
||||||
|
assert resp["error"]["code"] == "unknown_error"
|
||||||
|
assert resp["error"]["message"] == "Duplicate options are not allowed"
|
||||||
|
|
||||||
assert (
|
assert not hass.states.get(input_entity_id)
|
||||||
"Input select 'New Input' with options "
|
|
||||||
"['new option', 'even newer option', 'even newer option'] "
|
|
||||||
"had duplicated options, the duplicates have been removed"
|
|
||||||
) in caplog.text
|
|
||||||
|
|
||||||
state = hass.states.get(input_entity_id)
|
|
||||||
assert state.state == "even newer option"
|
|
||||||
assert state.attributes[ATTR_OPTIONS] == ["new option", "even newer option"]
|
|
||||||
|
|
||||||
|
|
||||||
async def test_setup_no_config(hass, hass_admin_user):
|
async def test_setup_no_config(hass, hass_admin_user):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue