"""The tests for the Template vacuum platform.""" import logging import pytest from homeassistant import setup from homeassistant.const import (STATE_ON, STATE_UNKNOWN) from homeassistant.components.vacuum import ( ATTR_BATTERY_LEVEL, STATE_CLEANING, STATE_DOCKED, STATE_IDLE, STATE_PAUSED, STATE_RETURNING) from tests.common import ( async_mock_service, assert_setup_component) from tests.components.vacuum import common _LOGGER = logging.getLogger(__name__) _TEST_VACUUM = 'vacuum.test_vacuum' _STATE_INPUT_SELECT = 'input_select.state' _SPOT_CLEANING_INPUT_BOOLEAN = 'input_boolean.spot_cleaning' _LOCATING_INPUT_BOOLEAN = 'input_boolean.locating' _FAN_SPEED_INPUT_SELECT = 'input_select.fan_speed' _BATTERY_LEVEL_INPUT_NUMBER = 'input_number.battery_level' @pytest.fixture def calls(hass): """Track calls to a mock service.""" return async_mock_service(hass, 'test', 'automation') # Configuration tests # async def test_missing_optional_config(hass, calls): """Test: missing optional template is ok.""" with assert_setup_component(1, 'vacuum'): assert await setup.async_setup_component(hass, 'vacuum', { 'vacuum': { 'platform': 'template', 'vacuums': { 'test_vacuum': { 'start': { 'service': 'script.vacuum_start' } } } } }) await hass.async_start() await hass.async_block_till_done() _verify(hass, STATE_UNKNOWN, None) async def test_missing_start_config(hass, calls): """Test: missing 'start' will fail.""" with assert_setup_component(0, 'vacuum'): assert await setup.async_setup_component(hass, 'vacuum', { 'vacuum': { 'platform': 'template', 'vacuums': { 'test_vacuum': { 'value_template': "{{ 'on' }}" } } } }) await hass.async_start() await hass.async_block_till_done() assert hass.states.async_all() == [] async def test_invalid_config(hass, calls): """Test: invalid config structure will fail.""" with assert_setup_component(0, 'vacuum'): assert await setup.async_setup_component(hass, 'vacuum', { 'platform': 'template', 'vacuums': { 'test_vacuum': { 'start': { 'service': 'script.vacuum_start' } } } }) await hass.async_start() await hass.async_block_till_done() assert hass.states.async_all() == [] # End of configuration tests # # Template tests # async def test_templates_with_entities(hass, calls): """Test templates with values from other entities.""" with assert_setup_component(1, 'vacuum'): assert await setup.async_setup_component(hass, 'vacuum', { 'vacuum': { 'platform': 'template', 'vacuums': { 'test_vacuum': { 'value_template': "{{ states('input_select.state') }}", 'battery_level_template': "{{ states('input_number.battery_level') }}", 'start': { 'service': 'script.vacuum_start' } } } } }) await hass.async_start() await hass.async_block_till_done() _verify(hass, STATE_UNKNOWN, None) hass.states.async_set(_STATE_INPUT_SELECT, STATE_CLEANING) hass.states.async_set(_BATTERY_LEVEL_INPUT_NUMBER, 100) await hass.async_block_till_done() _verify(hass, STATE_CLEANING, 100) async def test_templates_with_valid_values(hass, calls): """Test templates with valid values.""" with assert_setup_component(1, 'vacuum'): assert await setup.async_setup_component(hass, 'vacuum', { 'vacuum': { 'platform': 'template', 'vacuums': { 'test_vacuum': { 'value_template': "{{ 'cleaning' }}", 'battery_level_template': "{{ 100 }}", 'start': { 'service': 'script.vacuum_start' } } } } }) await hass.async_start() await hass.async_block_till_done() _verify(hass, STATE_CLEANING, 100) async def test_templates_invalid_values(hass, calls): """Test templates with invalid values.""" with assert_setup_component(1, 'vacuum'): assert await setup.async_setup_component(hass, 'vacuum', { 'vacuum': { 'platform': 'template', 'vacuums': { 'test_vacuum': { 'value_template': "{{ 'abc' }}", 'battery_level_template': "{{ 101 }}", 'start': { 'service': 'script.vacuum_start' } } } } }) await hass.async_start() await hass.async_block_till_done() _verify(hass, STATE_UNKNOWN, None) async def test_invalid_templates(hass, calls): """Test invalid templates.""" with assert_setup_component(1, 'vacuum'): assert await setup.async_setup_component(hass, 'vacuum', { 'vacuum': { 'platform': 'template', 'vacuums': { 'test_vacuum': { 'value_template': "{{ this_function_does_not_exist() }}", 'battery_level_template': "{{ this_function_does_not_exist() }}", 'fan_speed_template': "{{ this_function_does_not_exist() }}", 'start': { 'service': 'script.vacuum_start' } } } } }) await hass.async_start() await hass.async_block_till_done() _verify(hass, STATE_UNKNOWN, None) # End of template tests # # Function tests # async def test_state_services(hass, calls): """Test state services.""" await _register_components(hass) # Start vacuum await common.async_start(hass, _TEST_VACUUM) await hass.async_block_till_done() # verify assert hass.states.get(_STATE_INPUT_SELECT).state == STATE_CLEANING _verify(hass, STATE_CLEANING, None) # Pause vacuum await common.async_pause(hass, _TEST_VACUUM) await hass.async_block_till_done() # verify assert hass.states.get(_STATE_INPUT_SELECT).state == STATE_PAUSED _verify(hass, STATE_PAUSED, None) # Stop vacuum await common.async_stop(hass, _TEST_VACUUM) await hass.async_block_till_done() # verify assert hass.states.get(_STATE_INPUT_SELECT).state == STATE_IDLE _verify(hass, STATE_IDLE, None) # Return vacuum to base await common.async_return_to_base(hass, _TEST_VACUUM) await hass.async_block_till_done() # verify assert hass.states.get(_STATE_INPUT_SELECT).state == STATE_RETURNING _verify(hass, STATE_RETURNING, None) async def test_unused_services(hass, calls): """Test calling unused services should not crash.""" await _register_basic_vacuum(hass) # Pause vacuum await common.async_pause(hass, _TEST_VACUUM) await hass.async_block_till_done() # Stop vacuum await common.async_stop(hass, _TEST_VACUUM) await hass.async_block_till_done() # Return vacuum to base await common.async_return_to_base(hass, _TEST_VACUUM) await hass.async_block_till_done() # Spot cleaning await common.async_clean_spot(hass, _TEST_VACUUM) await hass.async_block_till_done() # Locate vacuum await common.async_locate(hass, _TEST_VACUUM) await hass.async_block_till_done() # Set fan's speed await common.async_set_fan_speed(hass, 'medium', _TEST_VACUUM) await hass.async_block_till_done() _verify(hass, STATE_UNKNOWN, None) async def test_clean_spot_service(hass, calls): """Test clean spot service.""" await _register_components(hass) # Clean spot await common.async_clean_spot(hass, _TEST_VACUUM) await hass.async_block_till_done() # verify assert hass.states.get(_SPOT_CLEANING_INPUT_BOOLEAN).state == STATE_ON async def test_locate_service(hass, calls): """Test locate service.""" await _register_components(hass) # Locate vacuum await common.async_locate(hass, _TEST_VACUUM) await hass.async_block_till_done() # verify assert hass.states.get(_LOCATING_INPUT_BOOLEAN).state == STATE_ON async def test_set_fan_speed(hass, calls): """Test set valid fan speed.""" await _register_components(hass) # Set vacuum's fan speed to high await common.async_set_fan_speed(hass, 'high', _TEST_VACUUM) await hass.async_block_till_done() # verify assert hass.states.get(_FAN_SPEED_INPUT_SELECT).state == 'high' # Set fan's speed to medium await common.async_set_fan_speed(hass, 'medium', _TEST_VACUUM) await hass.async_block_till_done() # verify assert hass.states.get(_FAN_SPEED_INPUT_SELECT).state == 'medium' async def test_set_invalid_fan_speed(hass, calls): """Test set invalid fan speed when fan has valid speed.""" await _register_components(hass) # Set vacuum's fan speed to high await common.async_set_fan_speed(hass, 'high', _TEST_VACUUM) await hass.async_block_till_done() # verify assert hass.states.get(_FAN_SPEED_INPUT_SELECT).state == 'high' # Set vacuum's fan speed to 'invalid' await common.async_set_fan_speed(hass, 'invalid', _TEST_VACUUM) await hass.async_block_till_done() # verify fan speed is unchanged assert hass.states.get(_FAN_SPEED_INPUT_SELECT).state == 'high' def _verify(hass, expected_state, expected_battery_level): """Verify vacuum's state and speed.""" state = hass.states.get(_TEST_VACUUM) attributes = state.attributes assert state.state == expected_state assert attributes.get(ATTR_BATTERY_LEVEL) == expected_battery_level async def _register_basic_vacuum(hass): """Register basic vacuum with only required options for testing.""" with assert_setup_component(1, 'input_select'): assert await setup.async_setup_component(hass, 'input_select', { 'input_select': { 'state': { 'name': 'State', 'options': [STATE_CLEANING] } } }) with assert_setup_component(1, 'vacuum'): assert await setup.async_setup_component(hass, 'vacuum', { 'vacuum': { 'platform': 'template', 'vacuums': { 'test_vacuum': { 'start': { 'service': 'input_select.select_option', 'data': { 'entity_id': _STATE_INPUT_SELECT, 'option': STATE_CLEANING } } } } } }) await hass.async_start() await hass.async_block_till_done() async def _register_components(hass): """Register basic components for testing.""" with assert_setup_component(2, 'input_boolean'): assert await setup.async_setup_component(hass, 'input_boolean', { 'input_boolean': { 'spot_cleaning': None, 'locating': None } }) with assert_setup_component(2, 'input_select'): assert await setup.async_setup_component(hass, 'input_select', { 'input_select': { 'state': { 'name': 'State', 'options': [STATE_CLEANING, STATE_DOCKED, STATE_IDLE, STATE_PAUSED, STATE_RETURNING] }, 'fan_speed': { 'name': 'Fan speed', 'options': ['', 'low', 'medium', 'high'] } } }) with assert_setup_component(1, 'vacuum'): test_vacuum_config = { 'value_template': "{{ states('input_select.state') }}", 'fan_speed_template': "{{ states('input_select.fan_speed') }}", 'start': { 'service': 'input_select.select_option', 'data': { 'entity_id': _STATE_INPUT_SELECT, 'option': STATE_CLEANING } }, 'pause': { 'service': 'input_select.select_option', 'data': { 'entity_id': _STATE_INPUT_SELECT, 'option': STATE_PAUSED } }, 'stop': { 'service': 'input_select.select_option', 'data': { 'entity_id': _STATE_INPUT_SELECT, 'option': STATE_IDLE } }, 'return_to_base': { 'service': 'input_select.select_option', 'data': { 'entity_id': _STATE_INPUT_SELECT, 'option': STATE_RETURNING } }, 'clean_spot': { 'service': 'input_boolean.turn_on', 'entity_id': _SPOT_CLEANING_INPUT_BOOLEAN }, 'locate': { 'service': 'input_boolean.turn_on', 'entity_id': _LOCATING_INPUT_BOOLEAN }, 'set_fan_speed': { 'service': 'input_select.select_option', 'data_template': { 'entity_id': _FAN_SPEED_INPUT_SELECT, 'option': '{{ fan_speed }}' } }, 'fan_speeds': ['low', 'medium', 'high'] } assert await setup.async_setup_component(hass, 'vacuum', { 'vacuum': { 'platform': 'template', 'vacuums': { 'test_vacuum': test_vacuum_config } } }) await hass.async_start() await hass.async_block_till_done()