From de7352dbde08d73862addf0db7d69fae5d7270ad Mon Sep 17 00:00:00 2001 From: jan iversen Date: Tue, 24 Aug 2021 14:11:40 +0200 Subject: [PATCH] Convert template/vacuum to pytest with fixtures (#54841) --- tests/components/template/conftest.py | 27 +- tests/components/template/test_vacuum.py | 537 ++++++++++------------- 2 files changed, 262 insertions(+), 302 deletions(-) diff --git a/tests/components/template/conftest.py b/tests/components/template/conftest.py index 0848200b35d..e2168d0925e 100644 --- a/tests/components/template/conftest.py +++ b/tests/components/template/conftest.py @@ -1,2 +1,27 @@ """template conftest.""" -from tests.components.light.conftest import mock_light_profiles # noqa: F401 +import pytest + +from homeassistant.setup import async_setup_component + +from tests.common import assert_setup_component, async_mock_service + + +@pytest.fixture +def calls(hass): + """Track calls to a mock service.""" + return async_mock_service(hass, "test", "automation") + + +@pytest.fixture +async def start_ha(hass, count, domain, config, caplog): + """Do setup of integration.""" + with assert_setup_component(count, domain): + assert await async_setup_component( + hass, + domain, + config, + ) + + await hass.async_block_till_done() + await hass.async_start() + await hass.async_block_till_done() diff --git a/tests/components/template/test_vacuum.py b/tests/components/template/test_vacuum.py index e18f8ecc059..6e0252845d1 100644 --- a/tests/components/template/test_vacuum.py +++ b/tests/components/template/test_vacuum.py @@ -12,7 +12,7 @@ from homeassistant.components.vacuum import ( ) from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE, STATE_UNKNOWN -from tests.common import assert_setup_component, async_mock_service +from tests.common import assert_setup_component from tests.components.vacuum import common _TEST_VACUUM = "vacuum.test_vacuum" @@ -23,19 +23,13 @@ _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", +@pytest.mark.parametrize("count,domain", [(1, "vacuum")]) +@pytest.mark.parametrize( + "parm1,parm2,config", + [ + ( + STATE_UNKNOWN, + None, { "vacuum": { "platform": "template", @@ -44,66 +38,90 @@ async def test_missing_optional_config(hass, calls): }, } }, - ) - - await hass.async_block_till_done() - 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", + ), + ( + STATE_CLEANING, + 100, { "vacuum": { "platform": "template", - "vacuums": {"test_vacuum": {"value_template": "{{ 'on' }}"}}, + "vacuums": { + "test_vacuum": { + "value_template": "{{ 'cleaning' }}", + "battery_level_template": "{{ 100 }}", + "start": {"service": "script.vacuum_start"}, + } + }, } }, - ) - - await hass.async_block_till_done() - 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", + ), + ( + STATE_UNKNOWN, + None, { - "platform": "template", - "vacuums": { - "test_vacuum": {"start": {"service": "script.vacuum_start"}} - }, + "vacuum": { + "platform": "template", + "vacuums": { + "test_vacuum": { + "value_template": "{{ 'abc' }}", + "battery_level_template": "{{ 101 }}", + "start": {"service": "script.vacuum_start"}, + } + }, + } }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - - assert hass.states.async_all() == [] + ), + ( + STATE_UNKNOWN, + None, + { + "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"}, + } + }, + } + }, + ), + ], +) +async def test_valid_configs(hass, count, parm1, parm2, start_ha): + """Test: configs.""" + assert len(hass.states.async_all()) == count + _verify(hass, parm1, parm2) -# End of configuration tests # +@pytest.mark.parametrize("count,domain", [(0, "vacuum")]) +@pytest.mark.parametrize( + "config", + [ + { + "vacuum": { + "platform": "template", + "vacuums": {"test_vacuum": {"value_template": "{{ 'on' }}"}}, + } + }, + { + "platform": "template", + "vacuums": {"test_vacuum": {"start": {"service": "script.vacuum_start"}}}, + }, + ], +) +async def test_invalid_configs(hass, count, start_ha): + """Test: configs.""" + assert len(hass.states.async_all()) == count -# 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, +@pytest.mark.parametrize( + "count,domain,config", + [ + ( + 1, "vacuum", { "vacuum": { @@ -118,125 +136,41 @@ async def test_templates_with_entities(hass, calls): } }, ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - + ], +) +async def test_templates_with_entities(hass, start_ha): + """Test templates with values from other entities.""" _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, +@pytest.mark.parametrize( + "count,domain,config", + [ + ( + 1, "vacuum", { "vacuum": { "platform": "template", "vacuums": { - "test_vacuum": { - "value_template": "{{ 'cleaning' }}", - "battery_level_template": "{{ 100 }}", + "test_template_vacuum": { + "availability_template": "{{ is_state('availability_state.state', 'on') }}", "start": {"service": "script.vacuum_start"}, } }, } }, ) - - await hass.async_block_till_done() - 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_block_till_done() - 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_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - - _verify(hass, STATE_UNKNOWN, None) - - -async def test_available_template_with_entities(hass, calls): + ], +) +async def test_available_template_with_entities(hass, start_ha): """Test availability templates with values from other entities.""" - assert await setup.async_setup_component( - hass, - "vacuum", - { - "vacuum": { - "platform": "template", - "vacuums": { - "test_template_vacuum": { - "availability_template": "{{ is_state('availability_state.state', 'on') }}", - "start": {"service": "script.vacuum_start"}, - } - }, - } - }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - # When template returns true.. hass.states.async_set("availability_state.state", STATE_ON) await hass.async_block_till_done() @@ -252,57 +186,60 @@ async def test_available_template_with_entities(hass, calls): assert hass.states.get("vacuum.test_template_vacuum").state == STATE_UNAVAILABLE -async def test_invalid_availability_template_keeps_component_available(hass, caplog): +@pytest.mark.parametrize( + "count,domain,config", + [ + ( + 1, + "vacuum", + { + "vacuum": { + "platform": "template", + "vacuums": { + "test_template_vacuum": { + "availability_template": "{{ x - 12 }}", + "start": {"service": "script.vacuum_start"}, + } + }, + } + }, + ) + ], +) +async def test_invalid_availability_template_keeps_component_available( + hass, caplog, start_ha +): """Test that an invalid availability keeps the device available.""" - assert await setup.async_setup_component( - hass, - "vacuum", - { - "vacuum": { - "platform": "template", - "vacuums": { - "test_template_vacuum": { - "availability_template": "{{ x - 12 }}", - "start": {"service": "script.vacuum_start"}, - } - }, - } - }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - assert hass.states.get("vacuum.test_template_vacuum") != STATE_UNAVAILABLE - assert ("UndefinedError: 'x' is undefined") in caplog.text + text = str([x.getMessage() for x in caplog.get_records("setup")]) + assert ("UndefinedError: \\'x\\' is undefined") in text -async def test_attribute_templates(hass, calls): +@pytest.mark.parametrize( + "count,domain,config", + [ + ( + 1, + "vacuum", + { + "vacuum": { + "platform": "template", + "vacuums": { + "test_template_vacuum": { + "value_template": "{{ 'cleaning' }}", + "start": {"service": "script.vacuum_start"}, + "attribute_templates": { + "test_attribute": "It {{ states.sensor.test_state.state }}." + }, + } + }, + } + }, + ) + ], +) +async def test_attribute_templates(hass, start_ha): """Test attribute_templates template.""" - assert await setup.async_setup_component( - hass, - "vacuum", - { - "vacuum": { - "platform": "template", - "vacuums": { - "test_template_vacuum": { - "value_template": "{{ 'cleaning' }}", - "start": {"service": "script.vacuum_start"}, - "attribute_templates": { - "test_attribute": "It {{ states.sensor.test_state.state }}." - }, - } - }, - } - }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - state = hass.states.get("vacuum.test_template_vacuum") assert state.attributes["test_attribute"] == "It ." @@ -315,41 +252,101 @@ async def test_attribute_templates(hass, calls): assert state.attributes["test_attribute"] == "It Works." -async def test_invalid_attribute_template(hass, caplog): +@pytest.mark.parametrize( + "count,domain,config", + [ + ( + 1, + "vacuum", + { + "vacuum": { + "platform": "template", + "vacuums": { + "invalid_template": { + "value_template": "{{ states('input_select.state') }}", + "start": {"service": "script.vacuum_start"}, + "attribute_templates": { + "test_attribute": "{{ this_function_does_not_exist() }}" + }, + } + }, + } + }, + ) + ], +) +async def test_invalid_attribute_template(hass, caplog, start_ha): """Test that errors are logged if rendering template fails.""" - assert await setup.async_setup_component( - hass, - "vacuum", - { - "vacuum": { - "platform": "template", - "vacuums": { - "invalid_template": { - "value_template": "{{ states('input_select.state') }}", - "start": {"service": "script.vacuum_start"}, - "attribute_templates": { - "test_attribute": "{{ this_function_does_not_exist() }}" - }, - } - }, - } - }, - ) - await hass.async_block_till_done() assert len(hass.states.async_all()) == 1 - await hass.async_start() + text = str([x.getMessage() for x in caplog.get_records("setup")]) + assert "test_attribute" in text + assert "TemplateError" in text + + +@pytest.mark.parametrize( + "count,domain,config", + [ + ( + 1, + "vacuum", + { + "vacuum": { + "platform": "template", + "vacuums": { + "test_template_vacuum_01": { + "unique_id": "not-so-unique-anymore", + "value_template": "{{ true }}", + "start": {"service": "script.vacuum_start"}, + }, + "test_template_vacuum_02": { + "unique_id": "not-so-unique-anymore", + "value_template": "{{ false }}", + "start": {"service": "script.vacuum_start"}, + }, + }, + } + }, + ), + ], +) +async def test_unique_id(hass, start_ha): + """Test unique_id option only creates one vacuum per id.""" + assert len(hass.states.async_all()) == 1 + + +async def test_unused_services(hass): + """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() - assert "test_attribute" in caplog.text - assert "TemplateError" in caplog.text + # 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) -# End of template tests # - - -# Function tests # -async def test_state_services(hass, calls): +async def test_state_services(hass): """Test state services.""" await _register_components(hass) @@ -386,38 +383,7 @@ async def test_state_services(hass, calls): _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): +async def test_clean_spot_service(hass): """Test clean spot service.""" await _register_components(hass) @@ -429,7 +395,7 @@ async def test_clean_spot_service(hass, calls): assert hass.states.get(_SPOT_CLEANING_INPUT_BOOLEAN).state == STATE_ON -async def test_locate_service(hass, calls): +async def test_locate_service(hass): """Test locate service.""" await _register_components(hass) @@ -441,7 +407,7 @@ async def test_locate_service(hass, calls): assert hass.states.get(_LOCATING_INPUT_BOOLEAN).state == STATE_ON -async def test_set_fan_speed(hass, calls): +async def test_set_fan_speed(hass): """Test set valid fan speed.""" await _register_components(hass) @@ -460,7 +426,7 @@ async def test_set_fan_speed(hass, calls): assert hass.states.get(_FAN_SPEED_INPUT_SELECT).state == "medium" -async def test_set_invalid_fan_speed(hass, calls): +async def test_set_invalid_fan_speed(hass): """Test set invalid fan speed when fan has valid speed.""" await _register_components(hass) @@ -611,34 +577,3 @@ async def _register_components(hass): await hass.async_block_till_done() await hass.async_start() await hass.async_block_till_done() - - -async def test_unique_id(hass): - """Test unique_id option only creates one vacuum per id.""" - await setup.async_setup_component( - hass, - "vacuum", - { - "vacuum": { - "platform": "template", - "vacuums": { - "test_template_vacuum_01": { - "unique_id": "not-so-unique-anymore", - "value_template": "{{ true }}", - "start": {"service": "script.vacuum_start"}, - }, - "test_template_vacuum_02": { - "unique_id": "not-so-unique-anymore", - "value_template": "{{ false }}", - "start": {"service": "script.vacuum_start"}, - }, - }, - } - }, - ) - - await hass.async_block_till_done() - await hass.async_start() - await hass.async_block_till_done() - - assert len(hass.states.async_all()) == 1