From fbb67820813b1bd674162339ad71ea253c18f261 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Sat, 12 Aug 2017 18:39:05 +0200 Subject: [PATCH] Fix SET_TEMPERATURE_SCHEMA in climate component (#8879) * Require either temperature or high/low target temperatures. * Add tests. --- homeassistant/components/climate/__init__.py | 18 +++++---- tests/common.py | 5 ++- tests/components/climate/test_init.py | 40 ++++++++++++++++++++ 3 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 tests/components/climate/test_init.py diff --git a/homeassistant/components/climate/__init__.py b/homeassistant/components/climate/__init__.py index 6dd66817d43..1f919301254 100644 --- a/homeassistant/components/climate/__init__.py +++ b/homeassistant/components/climate/__init__.py @@ -86,13 +86,17 @@ SET_AUX_HEAT_SCHEMA = vol.Schema({ vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, vol.Required(ATTR_AUX_HEAT): cv.boolean, }) -SET_TEMPERATURE_SCHEMA = vol.Schema({ - vol.Exclusive(ATTR_TEMPERATURE, 'temperature'): vol.Coerce(float), - vol.Inclusive(ATTR_TARGET_TEMP_HIGH, 'temperature'): vol.Coerce(float), - vol.Inclusive(ATTR_TARGET_TEMP_LOW, 'temperature'): vol.Coerce(float), - vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, - vol.Optional(ATTR_OPERATION_MODE): cv.string, -}) +SET_TEMPERATURE_SCHEMA = vol.Schema(vol.All( + cv.has_at_least_one_key( + ATTR_TEMPERATURE, ATTR_TARGET_TEMP_HIGH, ATTR_TARGET_TEMP_LOW), + { + vol.Exclusive(ATTR_TEMPERATURE, 'temperature'): vol.Coerce(float), + vol.Inclusive(ATTR_TARGET_TEMP_HIGH, 'temperature'): vol.Coerce(float), + vol.Inclusive(ATTR_TARGET_TEMP_LOW, 'temperature'): vol.Coerce(float), + vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, + vol.Optional(ATTR_OPERATION_MODE): cv.string, + } +)) SET_FAN_MODE_SCHEMA = vol.Schema({ vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, vol.Required(ATTR_FAN_MODE): cv.string, diff --git a/tests/common.py b/tests/common.py index 5e328959a7a..5fdec2fc411 100644 --- a/tests/common.py +++ b/tests/common.py @@ -174,7 +174,7 @@ def get_test_instance_port(): @ha.callback -def async_mock_service(hass, domain, service): +def async_mock_service(hass, domain, service, schema=None): """Set up a fake service & return a calls log list to this service.""" calls = [] @@ -183,7 +183,8 @@ def async_mock_service(hass, domain, service): """Mock service call.""" calls.append(call) - hass.services.async_register(domain, service, mock_service_log) + hass.services.async_register( + domain, service, mock_service_log, schema=schema) return calls diff --git a/tests/components/climate/test_init.py b/tests/components/climate/test_init.py new file mode 100644 index 00000000000..2e942c5988c --- /dev/null +++ b/tests/components/climate/test_init.py @@ -0,0 +1,40 @@ +"""The tests for the climate component.""" +import asyncio + +from homeassistant.components.climate import SET_TEMPERATURE_SCHEMA +from tests.common import async_mock_service + + +@asyncio.coroutine +def test_set_temp_schema_no_req(hass, caplog): + """Test the set temperature schema with missing required data.""" + domain = 'climate' + service = 'test_set_temperature' + schema = SET_TEMPERATURE_SCHEMA + calls = async_mock_service(hass, domain, service, schema) + + data = {'operation_mode': 'test', 'entity_id': ['climate.test_id']} + yield from hass.services.async_call(domain, service, data) + yield from hass.async_block_till_done() + + assert len(calls) == 0 + assert 'ERROR' in caplog.text + assert 'Invalid service data' in caplog.text + + +@asyncio.coroutine +def test_set_temp_schema(hass, caplog): + """Test the set temperature schema with ok required data.""" + domain = 'climate' + service = 'test_set_temperature' + schema = SET_TEMPERATURE_SCHEMA + calls = async_mock_service(hass, domain, service, schema) + + data = { + 'temperature': 20.0, 'operation_mode': 'test', + 'entity_id': ['climate.test_id']} + yield from hass.services.async_call(domain, service, data) + yield from hass.async_block_till_done() + + assert len(calls) == 1 + assert calls[-1].data == data