From 8c1cdc0cf7a2012c0e68001650054a1fc8f874eb Mon Sep 17 00:00:00 2001 From: Alexei Chetroi Date: Mon, 9 Dec 2019 15:15:24 -0500 Subject: [PATCH] Add input_text reload service. (#29644) * Add input_text reload service. * Add test. --- .../components/input_text/__init__.py | 43 +++++++++--- .../components/input_text/services.yaml | 2 + tests/components/input_text/test_init.py | 67 ++++++++++++++++++- 3 files changed, 102 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/input_text/__init__.py b/homeassistant/components/input_text/__init__.py index 2d5a23e2a76..77f007c5ba8 100644 --- a/homeassistant/components/input_text/__init__.py +++ b/homeassistant/components/input_text/__init__.py @@ -9,10 +9,12 @@ from homeassistant.const import ( CONF_ICON, CONF_MODE, CONF_NAME, + SERVICE_RELOAD, ) import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.restore_state import RestoreEntity +import homeassistant.helpers.service _LOGGER = logging.getLogger(__name__) @@ -76,12 +78,43 @@ CONFIG_SCHEMA = vol.Schema( required=True, extra=vol.ALLOW_EXTRA, ) +RELOAD_SERVICE_SCHEMA = vol.Schema({}) async def async_setup(hass, config): """Set up an input text box.""" component = EntityComponent(_LOGGER, DOMAIN, hass) + entities = await _async_process_config(config) + + async def reload_service_handler(service_call): + """Remove all entities and load new ones from config.""" + conf = await component.async_prepare_reload() + if conf is None: + return + new_entities = await _async_process_config(conf) + if new_entities: + await component.async_add_entities(new_entities) + + homeassistant.helpers.service.async_register_admin_service( + hass, + DOMAIN, + SERVICE_RELOAD, + reload_service_handler, + schema=RELOAD_SERVICE_SCHEMA, + ) + + component.async_register_entity_service( + SERVICE_SET_VALUE, {vol.Required(ATTR_VALUE): cv.string}, "async_set_value" + ) + + if entities: + await component.async_add_entities(entities) + return True + + +async def _async_process_config(config): + """Process config and create list of entities.""" entities = [] for object_id, cfg in config[DOMAIN].items(): @@ -102,15 +135,7 @@ async def async_setup(hass, config): ) ) - if not entities: - return False - - component.async_register_entity_service( - SERVICE_SET_VALUE, {vol.Required(ATTR_VALUE): cv.string}, "async_set_value" - ) - - await component.async_add_entities(entities) - return True + return entities class InputText(RestoreEntity): diff --git a/homeassistant/components/input_text/services.yaml b/homeassistant/components/input_text/services.yaml index 219eecf2fd6..e9b709b0c03 100644 --- a/homeassistant/components/input_text/services.yaml +++ b/homeassistant/components/input_text/services.yaml @@ -4,3 +4,5 @@ set_value: entity_id: {description: Entity id of the input text to set the new value., example: input_text.text1} value: {description: The target value the entity should be set to., example: This is an example text} +reload: + description: Reload the input_text configuration. diff --git a/tests/components/input_text/test_init.py b/tests/components/input_text/test_init.py index b758b245092..1bcf612c39b 100644 --- a/tests/components/input_text/test_init.py +++ b/tests/components/input_text/test_init.py @@ -1,10 +1,14 @@ """The tests for the Input text component.""" # pylint: disable=protected-access import asyncio +from unittest.mock import patch + +import pytest from homeassistant.components.input_text import ATTR_VALUE, DOMAIN, SERVICE_SET_VALUE -from homeassistant.const import ATTR_ENTITY_ID +from homeassistant.const import ATTR_ENTITY_ID, SERVICE_RELOAD from homeassistant.core import Context, CoreState, State +from homeassistant.exceptions import Unauthorized from homeassistant.loader import bind_hass from homeassistant.setup import async_setup_component @@ -195,3 +199,64 @@ async def test_config_none(hass): state = hass.states.get("input_text.b1") assert state assert str(state.state) == "unknown" + + +async def test_reload(hass, hass_admin_user, hass_read_only_user): + """Test reload service.""" + count_start = len(hass.states.async_entity_ids()) + + assert await async_setup_component( + hass, + DOMAIN, + {DOMAIN: {"test_1": {"initial": "test 1"}, "test_2": {"initial": "test 2"}}}, + ) + + assert count_start + 2 == len(hass.states.async_entity_ids()) + + state_1 = hass.states.get("input_text.test_1") + state_2 = hass.states.get("input_text.test_2") + state_3 = hass.states.get("input_text.test_3") + + assert state_1 is not None + assert state_2 is not None + assert state_3 is None + assert "test 1" == state_1.state + assert "test 2" == state_2.state + + with patch( + "homeassistant.config.load_yaml_config_file", + autospec=True, + return_value={ + DOMAIN: { + "test_2": {"initial": "test reloaded"}, + "test_3": {"initial": "test 3"}, + } + }, + ): + with patch("homeassistant.config.find_config_file", return_value=""): + with pytest.raises(Unauthorized): + await hass.services.async_call( + DOMAIN, + SERVICE_RELOAD, + blocking=True, + context=Context(user_id=hass_read_only_user.id), + ) + await hass.services.async_call( + DOMAIN, + SERVICE_RELOAD, + blocking=True, + context=Context(user_id=hass_admin_user.id), + ) + await hass.async_block_till_done() + + assert count_start + 2 == len(hass.states.async_entity_ids()) + + state_1 = hass.states.get("input_text.test_1") + state_2 = hass.states.get("input_text.test_2") + state_3 = hass.states.get("input_text.test_3") + + assert state_1 is None + assert state_2 is not None + assert state_3 is not None + assert "test reloaded" == state_2.state + assert "test 3" == state_3.state