hass-core/tests/components/template/test_fan.py
Penny Wood f195ecca4b Consolidate all platforms that have tests (#22109)
* Moved climate components with tests into platform dirs.

* Updated tests from climate component.

* Moved binary_sensor components with tests into platform dirs.

* Updated tests from binary_sensor component.

* Moved calendar components with tests into platform dirs.

* Updated tests from calendar component.

* Moved camera components with tests into platform dirs.

* Updated tests from camera component.

* Moved cover components with tests into platform dirs.

* Updated tests from cover component.

* Moved device_tracker components with tests into platform dirs.

* Updated tests from device_tracker component.

* Moved fan components with tests into platform dirs.

* Updated tests from fan component.

* Moved geo_location components with tests into platform dirs.

* Updated tests from geo_location component.

* Moved image_processing components with tests into platform dirs.

* Updated tests from image_processing component.

* Moved light components with tests into platform dirs.

* Updated tests from light component.

* Moved lock components with tests into platform dirs.

* Moved media_player components with tests into platform dirs.

* Updated tests from media_player component.

* Moved scene components with tests into platform dirs.

* Moved sensor components with tests into platform dirs.

* Updated tests from sensor component.

* Moved switch components with tests into platform dirs.

* Updated tests from sensor component.

* Moved vacuum components with tests into platform dirs.

* Updated tests from vacuum component.

* Moved weather components with tests into platform dirs.

* Fixed __init__.py files

* Fixes for stuff moved as part of this branch.

* Fix stuff needed to merge with balloob's branch.

* Formatting issues.

* Missing __init__.py files.

* Fix-ups

* Fixup

* Regenerated requirements.

* Linting errors fixed.

* Fixed more broken tests.

* Missing init files.

* Fix broken tests.

* More broken tests

* There seems to be a thread race condition.
I suspect the logger stuff is running in another thread, which means waiting until the aio loop is done is missing the log messages.
Used sleep instead because that allows the logger thread to run. I think the api_streams sensor might not be thread safe.

* Disabled tests, will remove sensor in #22147

* Updated coverage and codeowners.
2019-03-18 23:07:39 -07:00

648 lines
20 KiB
Python

"""The tests for the Template fan platform."""
import logging
import pytest
from homeassistant import setup
from homeassistant.const import STATE_ON, STATE_OFF
from homeassistant.components.fan import (
ATTR_SPEED, ATTR_OSCILLATING, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH,
ATTR_DIRECTION, DIRECTION_FORWARD, DIRECTION_REVERSE)
from tests.common import (
async_mock_service, assert_setup_component)
from tests.components.fan import common
_LOGGER = logging.getLogger(__name__)
_TEST_FAN = 'fan.test_fan'
# Represent for fan's state
_STATE_INPUT_BOOLEAN = 'input_boolean.state'
# Represent for fan's speed
_SPEED_INPUT_SELECT = 'input_select.speed'
# Represent for fan's oscillating
_OSC_INPUT = 'input_select.osc'
# Represent for fan's direction
_DIRECTION_INPUT_SELECT = 'input_select.direction'
@pytest.fixture
def calls(hass):
"""Track calls to a mock serivce."""
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, 'fan'):
assert await setup.async_setup_component(hass, 'fan', {
'fan': {
'platform': 'template',
'fans': {
'test_fan': {
'value_template': "{{ 'on' }}",
'turn_on': {
'service': 'script.fan_on'
},
'turn_off': {
'service': 'script.fan_off'
}
}
}
}
})
await hass.async_start()
await hass.async_block_till_done()
_verify(hass, STATE_ON, None, None, None)
async def test_missing_value_template_config(hass, calls):
"""Test: missing 'value_template' will fail."""
with assert_setup_component(0, 'fan'):
assert await setup.async_setup_component(hass, 'fan', {
'fan': {
'platform': 'template',
'fans': {
'test_fan': {
'turn_on': {
'service': 'script.fan_on'
},
'turn_off': {
'service': 'script.fan_off'
}
}
}
}
})
await hass.async_start()
await hass.async_block_till_done()
assert hass.states.async_all() == []
async def test_missing_turn_on_config(hass, calls):
"""Test: missing 'turn_on' will fail."""
with assert_setup_component(0, 'fan'):
assert await setup.async_setup_component(hass, 'fan', {
'fan': {
'platform': 'template',
'fans': {
'test_fan': {
'value_template': "{{ 'on' }}",
'turn_off': {
'service': 'script.fan_off'
}
}
}
}
})
await hass.async_start()
await hass.async_block_till_done()
assert hass.states.async_all() == []
async def test_missing_turn_off_config(hass, calls):
"""Test: missing 'turn_off' will fail."""
with assert_setup_component(0, 'fan'):
assert await setup.async_setup_component(hass, 'fan', {
'fan': {
'platform': 'template',
'fans': {
'test_fan': {
'value_template': "{{ 'on' }}",
'turn_on': {
'service': 'script.fan_on'
}
}
}
}
})
await hass.async_start()
await hass.async_block_till_done()
assert hass.states.async_all() == []
async def test_invalid_config(hass, calls):
"""Test: missing 'turn_off' will fail."""
with assert_setup_component(0, 'fan'):
assert await setup.async_setup_component(hass, 'fan', {
'platform': 'template',
'fans': {
'test_fan': {
'value_template': "{{ 'on' }}",
'turn_on': {
'service': 'script.fan_on'
}
}
}
})
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 tempalates with values from other entities."""
value_template = """
{% if is_state('input_boolean.state', 'True') %}
{{ 'on' }}
{% else %}
{{ 'off' }}
{% endif %}
"""
with assert_setup_component(1, 'fan'):
assert await setup.async_setup_component(hass, 'fan', {
'fan': {
'platform': 'template',
'fans': {
'test_fan': {
'value_template': value_template,
'speed_template':
"{{ states('input_select.speed') }}",
'oscillating_template':
"{{ states('input_select.osc') }}",
'direction_template':
"{{ states('input_select.direction') }}",
'turn_on': {
'service': 'script.fan_on'
},
'turn_off': {
'service': 'script.fan_off'
}
}
}
}
})
await hass.async_start()
await hass.async_block_till_done()
_verify(hass, STATE_OFF, None, None, None)
hass.states.async_set(_STATE_INPUT_BOOLEAN, True)
hass.states.async_set(_SPEED_INPUT_SELECT, SPEED_MEDIUM)
hass.states.async_set(_OSC_INPUT, 'True')
hass.states.async_set(_DIRECTION_INPUT_SELECT, DIRECTION_FORWARD)
await hass.async_block_till_done()
_verify(hass, STATE_ON, SPEED_MEDIUM, True, DIRECTION_FORWARD)
async def test_templates_with_valid_values(hass, calls):
"""Test templates with valid values."""
with assert_setup_component(1, 'fan'):
assert await setup.async_setup_component(hass, 'fan', {
'fan': {
'platform': 'template',
'fans': {
'test_fan': {
'value_template':
"{{ 'on' }}",
'speed_template':
"{{ 'medium' }}",
'oscillating_template':
"{{ 1 == 1 }}",
'direction_template':
"{{ 'forward' }}",
'turn_on': {
'service': 'script.fan_on'
},
'turn_off': {
'service': 'script.fan_off'
}
}
}
}
})
await hass.async_start()
await hass.async_block_till_done()
_verify(hass, STATE_ON, SPEED_MEDIUM, True, DIRECTION_FORWARD)
async def test_templates_invalid_values(hass, calls):
"""Test templates with invalid values."""
with assert_setup_component(1, 'fan'):
assert await setup.async_setup_component(hass, 'fan', {
'fan': {
'platform': 'template',
'fans': {
'test_fan': {
'value_template':
"{{ 'abc' }}",
'speed_template':
"{{ '0' }}",
'oscillating_template':
"{{ 'xyz' }}",
'direction_template':
"{{ 'right' }}",
'turn_on': {
'service': 'script.fan_on'
},
'turn_off': {
'service': 'script.fan_off'
}
}
}
}
})
await hass.async_start()
await hass.async_block_till_done()
_verify(hass, STATE_OFF, None, None, None)
# End of template tests #
# Function tests #
async def test_on_off(hass, calls):
"""Test turn on and turn off."""
await _register_components(hass)
# Turn on fan
common.async_turn_on(hass, _TEST_FAN)
await hass.async_block_till_done()
# verify
assert hass.states.get(_STATE_INPUT_BOOLEAN).state == STATE_ON
_verify(hass, STATE_ON, None, None, None)
# Turn off fan
common.async_turn_off(hass, _TEST_FAN)
await hass.async_block_till_done()
# verify
assert hass.states.get(_STATE_INPUT_BOOLEAN).state == STATE_OFF
_verify(hass, STATE_OFF, None, None, None)
async def test_on_with_speed(hass, calls):
"""Test turn on with speed."""
await _register_components(hass)
# Turn on fan with high speed
common.async_turn_on(hass, _TEST_FAN, SPEED_HIGH)
await hass.async_block_till_done()
# verify
assert hass.states.get(_STATE_INPUT_BOOLEAN).state == STATE_ON
assert hass.states.get(_SPEED_INPUT_SELECT).state == SPEED_HIGH
_verify(hass, STATE_ON, SPEED_HIGH, None, None)
async def test_set_speed(hass, calls):
"""Test set valid speed."""
await _register_components(hass)
# Turn on fan
common.async_turn_on(hass, _TEST_FAN)
await hass.async_block_till_done()
# Set fan's speed to high
common.async_set_speed(hass, _TEST_FAN, SPEED_HIGH)
await hass.async_block_till_done()
# verify
assert hass.states.get(_SPEED_INPUT_SELECT).state == SPEED_HIGH
_verify(hass, STATE_ON, SPEED_HIGH, None, None)
# Set fan's speed to medium
common.async_set_speed(hass, _TEST_FAN, SPEED_MEDIUM)
await hass.async_block_till_done()
# verify
assert hass.states.get(_SPEED_INPUT_SELECT).state == SPEED_MEDIUM
_verify(hass, STATE_ON, SPEED_MEDIUM, None, None)
async def test_set_invalid_speed_from_initial_stage(hass, calls):
"""Test set invalid speed when fan is in initial state."""
await _register_components(hass)
# Turn on fan
common.async_turn_on(hass, _TEST_FAN)
await hass.async_block_till_done()
# Set fan's speed to 'invalid'
common.async_set_speed(hass, _TEST_FAN, 'invalid')
await hass.async_block_till_done()
# verify speed is unchanged
assert hass.states.get(_SPEED_INPUT_SELECT).state == ''
_verify(hass, STATE_ON, None, None, None)
async def test_set_invalid_speed(hass, calls):
"""Test set invalid speed when fan has valid speed."""
await _register_components(hass)
# Turn on fan
common.async_turn_on(hass, _TEST_FAN)
await hass.async_block_till_done()
# Set fan's speed to high
common.async_set_speed(hass, _TEST_FAN, SPEED_HIGH)
await hass.async_block_till_done()
# verify
assert hass.states.get(_SPEED_INPUT_SELECT).state == SPEED_HIGH
_verify(hass, STATE_ON, SPEED_HIGH, None, None)
# Set fan's speed to 'invalid'
common.async_set_speed(hass, _TEST_FAN, 'invalid')
await hass.async_block_till_done()
# verify speed is unchanged
assert hass.states.get(_SPEED_INPUT_SELECT).state == SPEED_HIGH
_verify(hass, STATE_ON, SPEED_HIGH, None, None)
async def test_custom_speed_list(hass, calls):
"""Test set custom speed list."""
await _register_components(hass, ['1', '2', '3'])
# Turn on fan
common.async_turn_on(hass, _TEST_FAN)
await hass.async_block_till_done()
# Set fan's speed to '1'
common.async_set_speed(hass, _TEST_FAN, '1')
await hass.async_block_till_done()
# verify
assert hass.states.get(_SPEED_INPUT_SELECT).state == '1'
_verify(hass, STATE_ON, '1', None, None)
# Set fan's speed to 'medium' which is invalid
common.async_set_speed(hass, _TEST_FAN, SPEED_MEDIUM)
await hass.async_block_till_done()
# verify that speed is unchanged
assert hass.states.get(_SPEED_INPUT_SELECT).state == '1'
_verify(hass, STATE_ON, '1', None, None)
async def test_set_osc(hass, calls):
"""Test set oscillating."""
await _register_components(hass)
# Turn on fan
common.async_turn_on(hass, _TEST_FAN)
await hass.async_block_till_done()
# Set fan's osc to True
common.async_oscillate(hass, _TEST_FAN, True)
await hass.async_block_till_done()
# verify
assert hass.states.get(_OSC_INPUT).state == 'True'
_verify(hass, STATE_ON, None, True, None)
# Set fan's osc to False
common.async_oscillate(hass, _TEST_FAN, False)
await hass.async_block_till_done()
# verify
assert hass.states.get(_OSC_INPUT).state == 'False'
_verify(hass, STATE_ON, None, False, None)
async def test_set_invalid_osc_from_initial_state(hass, calls):
"""Test set invalid oscillating when fan is in initial state."""
await _register_components(hass)
# Turn on fan
common.async_turn_on(hass, _TEST_FAN)
await hass.async_block_till_done()
# Set fan's osc to 'invalid'
common.async_oscillate(hass, _TEST_FAN, 'invalid')
await hass.async_block_till_done()
# verify
assert hass.states.get(_OSC_INPUT).state == ''
_verify(hass, STATE_ON, None, None, None)
async def test_set_invalid_osc(hass, calls):
"""Test set invalid oscillating when fan has valid osc."""
await _register_components(hass)
# Turn on fan
common.async_turn_on(hass, _TEST_FAN)
await hass.async_block_till_done()
# Set fan's osc to True
common.async_oscillate(hass, _TEST_FAN, True)
await hass.async_block_till_done()
# verify
assert hass.states.get(_OSC_INPUT).state == 'True'
_verify(hass, STATE_ON, None, True, None)
# Set fan's osc to False
common.async_oscillate(hass, _TEST_FAN, None)
await hass.async_block_till_done()
# verify osc is unchanged
assert hass.states.get(_OSC_INPUT).state == 'True'
_verify(hass, STATE_ON, None, True, None)
async def test_set_direction(hass, calls):
"""Test set valid direction."""
await _register_components(hass)
# Turn on fan
common.async_turn_on(hass, _TEST_FAN)
await hass.async_block_till_done()
# Set fan's direction to forward
common.async_set_direction(hass, _TEST_FAN, DIRECTION_FORWARD)
await hass.async_block_till_done()
# verify
assert hass.states.get(_DIRECTION_INPUT_SELECT).state \
== DIRECTION_FORWARD
_verify(hass, STATE_ON, None, None, DIRECTION_FORWARD)
# Set fan's direction to reverse
common.async_set_direction(hass, _TEST_FAN, DIRECTION_REVERSE)
await hass.async_block_till_done()
# verify
assert hass.states.get(_DIRECTION_INPUT_SELECT).state \
== DIRECTION_REVERSE
_verify(hass, STATE_ON, None, None, DIRECTION_REVERSE)
async def test_set_invalid_direction_from_initial_stage(hass, calls):
"""Test set invalid direction when fan is in initial state."""
await _register_components(hass)
# Turn on fan
common.async_turn_on(hass, _TEST_FAN)
await hass.async_block_till_done()
# Set fan's direction to 'invalid'
common.async_set_direction(hass, _TEST_FAN, 'invalid')
await hass.async_block_till_done()
# verify direction is unchanged
assert hass.states.get(_DIRECTION_INPUT_SELECT).state == ''
_verify(hass, STATE_ON, None, None, None)
async def test_set_invalid_direction(hass, calls):
"""Test set invalid direction when fan has valid direction."""
await _register_components(hass)
# Turn on fan
common.async_turn_on(hass, _TEST_FAN)
await hass.async_block_till_done()
# Set fan's direction to forward
common.async_set_direction(hass, _TEST_FAN, DIRECTION_FORWARD)
await hass.async_block_till_done()
# verify
assert hass.states.get(_DIRECTION_INPUT_SELECT).state == \
DIRECTION_FORWARD
_verify(hass, STATE_ON, None, None, DIRECTION_FORWARD)
# Set fan's direction to 'invalid'
common.async_set_direction(hass, _TEST_FAN, 'invalid')
await hass.async_block_till_done()
# verify direction is unchanged
assert hass.states.get(_DIRECTION_INPUT_SELECT).state == \
DIRECTION_FORWARD
_verify(hass, STATE_ON, None, None, DIRECTION_FORWARD)
def _verify(hass, expected_state, expected_speed, expected_oscillating,
expected_direction):
"""Verify fan's state, speed and osc."""
state = hass.states.get(_TEST_FAN)
attributes = state.attributes
assert state.state == expected_state
assert attributes.get(ATTR_SPEED, None) == expected_speed
assert attributes.get(ATTR_OSCILLATING, None) == expected_oscillating
assert attributes.get(ATTR_DIRECTION, None) == expected_direction
async def _register_components(hass, speed_list=None):
"""Register basic components for testing."""
with assert_setup_component(1, 'input_boolean'):
assert await setup.async_setup_component(
hass,
'input_boolean',
{'input_boolean': {'state': None}}
)
with assert_setup_component(3, 'input_select'):
assert await setup.async_setup_component(hass, 'input_select', {
'input_select': {
'speed': {
'name': 'Speed',
'options': ['', SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH,
'1', '2', '3']
},
'osc': {
'name': 'oscillating',
'options': ['', 'True', 'False']
},
'direction': {
'name': 'Direction',
'options': ['', DIRECTION_FORWARD, DIRECTION_REVERSE]
},
}
})
with assert_setup_component(1, 'fan'):
value_template = """
{% if is_state('input_boolean.state', 'on') %}
{{ 'on' }}
{% else %}
{{ 'off' }}
{% endif %}
"""
test_fan_config = {
'value_template': value_template,
'speed_template':
"{{ states('input_select.speed') }}",
'oscillating_template':
"{{ states('input_select.osc') }}",
'direction_template':
"{{ states('input_select.direction') }}",
'turn_on': {
'service': 'input_boolean.turn_on',
'entity_id': _STATE_INPUT_BOOLEAN
},
'turn_off': {
'service': 'input_boolean.turn_off',
'entity_id': _STATE_INPUT_BOOLEAN
},
'set_speed': {
'service': 'input_select.select_option',
'data_template': {
'entity_id': _SPEED_INPUT_SELECT,
'option': '{{ speed }}'
}
},
'set_oscillating': {
'service': 'input_select.select_option',
'data_template': {
'entity_id': _OSC_INPUT,
'option': '{{ oscillating }}'
}
},
'set_direction': {
'service': 'input_select.select_option',
'data_template': {
'entity_id': _DIRECTION_INPUT_SELECT,
'option': '{{ direction }}'
}
}
}
if speed_list:
test_fan_config['speeds'] = speed_list
assert await setup.async_setup_component(hass, 'fan', {
'fan': {
'platform': 'template',
'fans': {
'test_fan': test_fan_config
}
}
})
await hass.async_start()
await hass.async_block_till_done()