core/tests/components/sensor/test_tcp.py

272 lines
11 KiB
Python
Raw Normal View History

2016-03-09 09:25:50 +00:00
"""The tests for the TCP sensor platform."""
2016-02-19 17:41:51 +00:00
import socket
2016-10-22 04:14:35 +00:00
import unittest
2016-02-19 17:41:51 +00:00
from copy import copy
from uuid import uuid4
from unittest.mock import patch, Mock
2016-02-19 17:41:51 +00:00
2016-10-22 04:14:35 +00:00
from tests.common import (get_test_home_assistant, assert_setup_component)
from homeassistant.bootstrap import setup_component
2016-02-19 17:41:51 +00:00
from homeassistant.components.sensor import tcp
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.template import Template
2016-02-19 17:41:51 +00:00
TEST_CONFIG = {
2016-10-22 04:14:35 +00:00
'sensor': {
'platform': 'tcp',
tcp.CONF_NAME: 'test_name',
tcp.CONF_HOST: 'test_host',
tcp.CONF_PORT: 12345,
tcp.CONF_TIMEOUT: tcp.DEFAULT_TIMEOUT + 1,
tcp.CONF_PAYLOAD: 'test_payload',
tcp.CONF_UNIT_OF_MEASUREMENT: 'test_unit',
tcp.CONF_VALUE_TEMPLATE: Template('test_template'),
2016-10-22 04:14:35 +00:00
tcp.CONF_VALUE_ON: 'test_on',
tcp.CONF_BUFFER_SIZE: tcp.DEFAULT_BUFFER_SIZE + 1
},
2016-02-19 17:41:51 +00:00
}
2016-10-22 04:14:35 +00:00
2016-02-19 17:41:51 +00:00
KEYS_AND_DEFAULTS = {
tcp.CONF_TIMEOUT: tcp.DEFAULT_TIMEOUT,
2016-10-22 04:14:35 +00:00
tcp.CONF_UNIT_OF_MEASUREMENT: None,
2016-02-19 17:41:51 +00:00
tcp.CONF_VALUE_TEMPLATE: None,
tcp.CONF_VALUE_ON: None,
tcp.CONF_BUFFER_SIZE: tcp.DEFAULT_BUFFER_SIZE
}
2016-10-22 04:14:35 +00:00
class TestTCPSensor(unittest.TestCase):
2016-03-09 09:25:50 +00:00
"""Test the TCP Sensor."""
2016-02-19 17:41:51 +00:00
2016-10-22 04:14:35 +00:00
def setup_method(self, method):
2016-03-09 09:25:50 +00:00
"""Setup things to be run when tests are started."""
2016-10-22 04:14:35 +00:00
self.hass = get_test_home_assistant()
2016-02-19 17:41:51 +00:00
2016-10-22 04:14:35 +00:00
def teardown_method(self, method):
2016-03-09 09:25:50 +00:00
"""Stop everything that was started."""
2016-10-22 04:14:35 +00:00
self.hass.stop()
@patch('homeassistant.components.sensor.tcp.TcpSensor.update')
def test_setup_platform_valid_config(self, mock_update):
"""Check a valid configuration and call add_devices with sensor."""
with assert_setup_component(0, 'sensor'):
assert setup_component(self.hass, 'sensor', TEST_CONFIG)
add_devices = Mock()
tcp.setup_platform(None, TEST_CONFIG['sensor'], add_devices)
assert add_devices.called
assert isinstance(add_devices.call_args[0][0][0], tcp.TcpSensor)
def test_setup_platform_invalid_config(self):
"""Check an invalid configuration."""
with assert_setup_component(0):
assert setup_component(self.hass, 'sensor', {
'sensor': {
'platform': 'tcp',
'porrt': 1234,
}
})
@patch('homeassistant.components.sensor.tcp.TcpSensor.update')
2016-03-05 17:27:22 +00:00
def test_name(self, mock_update):
2016-10-22 04:14:35 +00:00
"""Return the name if set in the configuration."""
sensor = tcp.TcpSensor(self.hass, TEST_CONFIG['sensor'])
assert sensor.name == TEST_CONFIG['sensor'][tcp.CONF_NAME]
2016-10-22 04:14:35 +00:00
@patch('homeassistant.components.sensor.tcp.TcpSensor.update')
2016-03-05 17:27:22 +00:00
def test_name_not_set(self, mock_update):
2016-10-22 04:14:35 +00:00
"""Return the superclass name property if not set in configuration."""
config = copy(TEST_CONFIG['sensor'])
del config[tcp.CONF_NAME]
entity = Entity()
2016-10-22 04:14:35 +00:00
sensor = tcp.TcpSensor(self.hass, config)
assert sensor.name == entity.name
2016-10-22 04:14:35 +00:00
@patch('homeassistant.components.sensor.tcp.TcpSensor.update')
2016-03-05 17:27:22 +00:00
def test_state(self, mock_update):
2016-10-22 04:14:35 +00:00
"""Return the contents of _state."""
sensor = tcp.TcpSensor(self.hass, TEST_CONFIG['sensor'])
uuid = str(uuid4())
sensor._state = uuid
assert sensor.state == uuid
2016-10-22 04:14:35 +00:00
@patch('homeassistant.components.sensor.tcp.TcpSensor.update')
2016-03-05 17:27:22 +00:00
def test_unit_of_measurement(self, mock_update):
2016-10-22 04:14:35 +00:00
"""Return the configured unit of measurement."""
sensor = tcp.TcpSensor(self.hass, TEST_CONFIG['sensor'])
assert sensor.unit_of_measurement == \
TEST_CONFIG['sensor'][tcp.CONF_UNIT_OF_MEASUREMENT]
2016-10-22 04:14:35 +00:00
@patch('homeassistant.components.sensor.tcp.TcpSensor.update')
2016-02-19 17:41:51 +00:00
def test_config_valid_keys(self, *args):
2016-10-22 04:14:35 +00:00
"""Store valid keys in _config."""
sensor = tcp.TcpSensor(self.hass, TEST_CONFIG['sensor'])
del TEST_CONFIG['sensor']['platform']
for key in TEST_CONFIG['sensor']:
2016-02-19 17:41:51 +00:00
assert key in sensor._config
def test_validate_config_valid_keys(self):
2016-10-22 04:14:35 +00:00
"""Return True when provided with the correct keys."""
with assert_setup_component(0, 'sensor'):
assert setup_component(self.hass, 'sensor', TEST_CONFIG)
2016-02-19 17:41:51 +00:00
2016-10-22 04:14:35 +00:00
@patch('homeassistant.components.sensor.tcp.TcpSensor.update')
2016-03-05 17:27:22 +00:00
def test_config_invalid_keys(self, mock_update):
2016-03-09 09:25:50 +00:00
"""Shouldn't store invalid keys in _config."""
2016-10-22 04:14:35 +00:00
config = copy(TEST_CONFIG['sensor'])
2016-02-19 17:41:51 +00:00
config.update({
2016-10-22 04:14:35 +00:00
'a': 'test_a',
'b': 'test_b',
'c': 'test_c'
2016-02-19 17:41:51 +00:00
})
2016-10-22 04:14:35 +00:00
sensor = tcp.TcpSensor(self.hass, config)
for invalid_key in 'abc':
2016-02-19 17:41:51 +00:00
assert invalid_key not in sensor._config
2016-03-05 17:27:22 +00:00
def test_validate_config_invalid_keys(self):
2016-03-09 09:25:50 +00:00
"""Test with invalid keys plus some extra."""
2016-10-22 04:14:35 +00:00
config = copy(TEST_CONFIG['sensor'])
2016-02-19 17:41:51 +00:00
config.update({
2016-10-22 04:14:35 +00:00
'a': 'test_a',
'b': 'test_b',
'c': 'test_c'
2016-02-19 17:41:51 +00:00
})
2016-10-22 04:14:35 +00:00
with assert_setup_component(0, 'sensor'):
assert setup_component(self.hass, 'sensor', {'tcp': config})
2016-02-19 17:41:51 +00:00
2016-10-22 04:14:35 +00:00
@patch('homeassistant.components.sensor.tcp.TcpSensor.update')
2016-03-05 17:27:22 +00:00
def test_config_uses_defaults(self, mock_update):
2016-10-22 04:14:35 +00:00
"""Check if defaults were set."""
config = copy(TEST_CONFIG['sensor'])
for key in KEYS_AND_DEFAULTS:
2016-02-19 17:41:51 +00:00
del config[key]
2016-10-22 04:14:35 +00:00
with assert_setup_component(1) as result_config:
assert setup_component(self.hass, 'sensor', {
'sensor': config,
})
sensor = tcp.TcpSensor(self.hass, result_config['sensor'][0])
2016-02-19 17:41:51 +00:00
for key, default in KEYS_AND_DEFAULTS.items():
assert sensor._config[key] == default
def test_validate_config_missing_defaults(self):
2016-10-22 04:14:35 +00:00
"""Return True when defaulted keys are not provided."""
config = copy(TEST_CONFIG['sensor'])
for key in KEYS_AND_DEFAULTS:
2016-02-19 17:41:51 +00:00
del config[key]
2016-10-22 04:14:35 +00:00
with assert_setup_component(0, 'sensor'):
assert setup_component(self.hass, 'sensor', {'tcp': config})
2016-02-19 17:41:51 +00:00
def test_validate_config_missing_required(self):
2016-10-22 04:14:35 +00:00
"""Return False when required config items are missing."""
for key in TEST_CONFIG['sensor']:
2016-02-19 17:41:51 +00:00
if key in KEYS_AND_DEFAULTS:
continue
2016-10-22 04:14:35 +00:00
config = copy(TEST_CONFIG['sensor'])
2016-02-19 17:41:51 +00:00
del config[key]
2016-10-22 04:14:35 +00:00
with assert_setup_component(0, 'sensor'):
assert setup_component(self.hass, 'sensor', {'tcp': config})
2016-02-19 17:41:51 +00:00
2016-10-22 04:14:35 +00:00
@patch('homeassistant.components.sensor.tcp.TcpSensor.update')
2016-02-19 17:41:51 +00:00
def test_init_calls_update(self, mock_update):
2016-10-22 04:14:35 +00:00
"""Call update() method during __init__()."""
tcp.TcpSensor(self.hass, TEST_CONFIG)
2016-02-19 17:41:51 +00:00
assert mock_update.called
2016-10-22 04:14:35 +00:00
@patch('socket.socket')
@patch('select.select', return_value=(True, False, False))
2016-02-19 17:41:51 +00:00
def test_update_connects_to_host_and_port(self, mock_select, mock_socket):
2016-10-22 04:14:35 +00:00
"""Connect to the configured host and port."""
tcp.TcpSensor(self.hass, TEST_CONFIG['sensor'])
2016-02-19 17:41:51 +00:00
mock_socket = mock_socket().__enter__()
2016-03-05 17:27:22 +00:00
assert mock_socket.connect.mock_calls[0][1] == ((
2016-10-22 04:14:35 +00:00
TEST_CONFIG['sensor'][tcp.CONF_HOST],
TEST_CONFIG['sensor'][tcp.CONF_PORT]),)
2016-02-19 17:41:51 +00:00
2016-10-22 04:14:35 +00:00
@patch('socket.socket.connect', side_effect=socket.error())
def test_update_returns_if_connecting_fails(self, *args):
2016-10-22 04:14:35 +00:00
"""Return if connecting to host fails."""
with patch('homeassistant.components.sensor.tcp.TcpSensor.update'):
sensor = tcp.TcpSensor(self.hass, TEST_CONFIG['sensor'])
2016-02-19 17:41:51 +00:00
assert sensor.update() is None
2016-10-22 04:14:35 +00:00
@patch('socket.socket.connect')
@patch('socket.socket.send', side_effect=socket.error())
def test_update_returns_if_sending_fails(self, *args):
2016-10-22 04:14:35 +00:00
"""Return if sending fails."""
with patch('homeassistant.components.sensor.tcp.TcpSensor.update'):
sensor = tcp.TcpSensor(self.hass, TEST_CONFIG['sensor'])
assert sensor.update() is None
2016-10-22 04:14:35 +00:00
@patch('socket.socket.connect')
@patch('socket.socket.send')
@patch('select.select', return_value=(False, False, False))
def test_update_returns_if_select_fails(self, *args):
2016-10-22 04:14:35 +00:00
"""Return if select fails to return a socket."""
with patch('homeassistant.components.sensor.tcp.TcpSensor.update'):
sensor = tcp.TcpSensor(self.hass, TEST_CONFIG['sensor'])
assert sensor.update() is None
2016-10-22 04:14:35 +00:00
@patch('socket.socket')
@patch('select.select', return_value=(True, False, False))
2016-02-19 17:41:51 +00:00
def test_update_sends_payload(self, mock_select, mock_socket):
2016-10-22 04:14:35 +00:00
"""Send the configured payload as bytes."""
tcp.TcpSensor(self.hass, TEST_CONFIG['sensor'])
2016-02-19 17:41:51 +00:00
mock_socket = mock_socket().__enter__()
mock_socket.send.assert_called_with(
2016-10-22 04:14:35 +00:00
TEST_CONFIG['sensor'][tcp.CONF_PAYLOAD].encode()
2016-02-19 17:41:51 +00:00
)
2016-10-22 04:14:35 +00:00
@patch('socket.socket')
@patch('select.select', return_value=(True, False, False))
2016-02-19 17:41:51 +00:00
def test_update_calls_select_with_timeout(self, mock_select, mock_socket):
2016-10-22 04:14:35 +00:00
"""Provide the timeout argument to select."""
tcp.TcpSensor(self.hass, TEST_CONFIG['sensor'])
2016-02-19 17:41:51 +00:00
mock_socket = mock_socket().__enter__()
mock_select.assert_called_with(
2016-10-22 04:14:35 +00:00
[mock_socket], [], [], TEST_CONFIG['sensor'][tcp.CONF_TIMEOUT])
2016-02-19 17:41:51 +00:00
2016-10-22 04:14:35 +00:00
@patch('socket.socket')
@patch('select.select', return_value=(True, False, False))
2016-02-19 17:41:51 +00:00
def test_update_receives_packet_and_sets_as_state(
self, mock_select, mock_socket):
2016-03-09 09:25:50 +00:00
"""Test the response from the socket and set it as the state."""
2016-10-22 04:14:35 +00:00
test_value = 'test_value'
2016-02-19 17:41:51 +00:00
mock_socket = mock_socket().__enter__()
mock_socket.recv.return_value = test_value.encode()
2016-10-22 04:14:35 +00:00
config = copy(TEST_CONFIG['sensor'])
2016-02-19 17:41:51 +00:00
del config[tcp.CONF_VALUE_TEMPLATE]
2016-10-22 04:14:35 +00:00
sensor = tcp.TcpSensor(self.hass, config)
2016-02-19 17:41:51 +00:00
assert sensor._state == test_value
2016-10-22 04:14:35 +00:00
@patch('socket.socket')
@patch('select.select', return_value=(True, False, False))
2016-02-19 17:41:51 +00:00
def test_update_renders_value_in_template(self, mock_select, mock_socket):
2016-10-22 04:14:35 +00:00
"""Render the value in the provided template."""
test_value = 'test_value'
2016-02-19 17:41:51 +00:00
mock_socket = mock_socket().__enter__()
mock_socket.recv.return_value = test_value.encode()
2016-10-22 04:14:35 +00:00
config = copy(TEST_CONFIG['sensor'])
config[tcp.CONF_VALUE_TEMPLATE] = Template('{{ value }} {{ 1+1 }}')
2016-10-22 04:14:35 +00:00
sensor = tcp.TcpSensor(self.hass, config)
assert sensor._state == '%s 2' % test_value
2016-10-22 04:14:35 +00:00
@patch('socket.socket')
@patch('select.select', return_value=(True, False, False))
def test_update_returns_if_template_render_fails(
self, mock_select, mock_socket):
2016-10-22 04:14:35 +00:00
"""Return None if rendering the template fails."""
test_value = 'test_value'
mock_socket = mock_socket().__enter__()
mock_socket.recv.return_value = test_value.encode()
2016-10-22 04:14:35 +00:00
config = copy(TEST_CONFIG['sensor'])
config[tcp.CONF_VALUE_TEMPLATE] = Template("{{ this won't work")
2016-10-22 04:14:35 +00:00
sensor = tcp.TcpSensor(self.hass, config)
assert sensor.update() is None