Improved Homekit tests (#12800)
* Added test for temperature fahrenheit * Restructured tests to use more mocks * Rearanged homekit constants * Improved 'test_homekit_class' * Added import statements * Fix Pylint Test errors
This commit is contained in:
parent
d3386907a4
commit
168e1f0e2d
11 changed files with 420 additions and 94 deletions
165
tests/components/homekit/test_accessories.py
Normal file
165
tests/components/homekit/test_accessories.py
Normal file
|
@ -0,0 +1,165 @@
|
|||
"""Test all functions related to the basic accessory implementation.
|
||||
|
||||
This includes tests for all mock object types.
|
||||
"""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
# pylint: disable=unused-import
|
||||
from pyhap.loader import get_serv_loader, get_char_loader # noqa F401
|
||||
|
||||
from homeassistant.components.homekit.accessories import (
|
||||
set_accessory_info, add_preload_service, override_properties,
|
||||
HomeAccessory, HomeBridge)
|
||||
from homeassistant.components.homekit.const import (
|
||||
SERV_ACCESSORY_INFO, SERV_BRIDGING_STATE,
|
||||
CHAR_MODEL, CHAR_MANUFACTURER, CHAR_SERIAL_NUMBER)
|
||||
|
||||
from tests.mock.homekit import (
|
||||
get_patch_paths, mock_preload_service,
|
||||
MockTypeLoader, MockAccessory, MockService, MockChar)
|
||||
|
||||
PATH_SERV = 'pyhap.loader.get_serv_loader'
|
||||
PATH_CHAR = 'pyhap.loader.get_char_loader'
|
||||
PATH_ACC, _ = get_patch_paths()
|
||||
|
||||
|
||||
@patch(PATH_CHAR, return_value=MockTypeLoader('char'))
|
||||
@patch(PATH_SERV, return_value=MockTypeLoader('service'))
|
||||
def test_add_preload_service(mock_serv, mock_char):
|
||||
"""Test method add_preload_service.
|
||||
|
||||
The methods 'get_serv_loader' and 'get_char_loader' are mocked.
|
||||
"""
|
||||
acc = MockAccessory('Accessory')
|
||||
serv = add_preload_service(acc, 'TestService',
|
||||
['TestChar', 'TestChar2'],
|
||||
['TestOptChar', 'TestOptChar2'])
|
||||
|
||||
assert serv.display_name == 'TestService'
|
||||
assert len(serv.characteristics) == 2
|
||||
assert len(serv.opt_characteristics) == 2
|
||||
|
||||
acc.services = []
|
||||
serv = add_preload_service(acc, 'TestService')
|
||||
|
||||
assert not serv.characteristics
|
||||
assert not serv.opt_characteristics
|
||||
|
||||
acc.services = []
|
||||
serv = add_preload_service(acc, 'TestService',
|
||||
'TestChar', 'TestOptChar')
|
||||
|
||||
assert len(serv.characteristics) == 1
|
||||
assert len(serv.opt_characteristics) == 1
|
||||
|
||||
assert serv.characteristics[0].display_name == 'TestChar'
|
||||
assert serv.opt_characteristics[0].display_name == 'TestOptChar'
|
||||
|
||||
|
||||
def test_override_properties():
|
||||
"""Test override of characteristic properties with MockChar."""
|
||||
char = MockChar('TestChar')
|
||||
new_prop = {1: 'Test', 2: 'Demo'}
|
||||
override_properties(char, new_prop)
|
||||
|
||||
assert char.properties == new_prop
|
||||
|
||||
|
||||
def test_set_accessory_info():
|
||||
"""Test setting of basic accessory information with MockAccessory."""
|
||||
acc = MockAccessory('Accessory')
|
||||
set_accessory_info(acc, 'model', 'manufacturer', '0000')
|
||||
|
||||
assert len(acc.services) == 1
|
||||
serv = acc.services[0]
|
||||
|
||||
assert serv.display_name == SERV_ACCESSORY_INFO
|
||||
assert len(serv.characteristics) == 3
|
||||
chars = serv.characteristics
|
||||
|
||||
assert chars[0].display_name == CHAR_MODEL
|
||||
assert chars[0].value == 'model'
|
||||
assert chars[1].display_name == CHAR_MANUFACTURER
|
||||
assert chars[1].value == 'manufacturer'
|
||||
assert chars[2].display_name == CHAR_SERIAL_NUMBER
|
||||
assert chars[2].value == '0000'
|
||||
|
||||
|
||||
@patch(PATH_ACC, side_effect=mock_preload_service)
|
||||
def test_home_accessory(mock_pre_serv):
|
||||
"""Test initializing a HomeAccessory object."""
|
||||
acc = HomeAccessory('TestAccessory', 'test.accessory', 'WINDOW')
|
||||
|
||||
assert acc.display_name == 'TestAccessory'
|
||||
assert acc.category == 13 # Category.WINDOW
|
||||
assert len(acc.services) == 1
|
||||
|
||||
serv = acc.services[0]
|
||||
assert serv.display_name == SERV_ACCESSORY_INFO
|
||||
char_model = serv.get_characteristic(CHAR_MODEL)
|
||||
assert char_model.get_value() == 'test.accessory'
|
||||
|
||||
|
||||
@patch(PATH_ACC, side_effect=mock_preload_service)
|
||||
def test_home_bridge(mock_pre_serv):
|
||||
"""Test initializing a HomeBridge object."""
|
||||
bridge = HomeBridge('TestBridge', 'test.bridge', b'123-45-678')
|
||||
|
||||
assert bridge.display_name == 'TestBridge'
|
||||
assert bridge.pincode == b'123-45-678'
|
||||
assert len(bridge.services) == 2
|
||||
|
||||
assert bridge.services[0].display_name == SERV_ACCESSORY_INFO
|
||||
assert bridge.services[1].display_name == SERV_BRIDGING_STATE
|
||||
|
||||
char_model = bridge.services[0].get_characteristic(CHAR_MODEL)
|
||||
assert char_model.get_value() == 'test.bridge'
|
||||
|
||||
|
||||
def test_mock_accessory():
|
||||
"""Test attributes and functions of a MockAccessory."""
|
||||
acc = MockAccessory('TestAcc')
|
||||
serv = MockService('TestServ')
|
||||
acc.add_service(serv)
|
||||
|
||||
assert acc.display_name == 'TestAcc'
|
||||
assert len(acc.services) == 1
|
||||
|
||||
assert acc.get_service('TestServ') == serv
|
||||
assert acc.get_service('NewServ').display_name == 'NewServ'
|
||||
assert len(acc.services) == 2
|
||||
|
||||
|
||||
def test_mock_service():
|
||||
"""Test attributes and functions of a MockService."""
|
||||
serv = MockService('TestServ')
|
||||
char = MockChar('TestChar')
|
||||
opt_char = MockChar('TestOptChar')
|
||||
serv.add_characteristic(char)
|
||||
serv.add_opt_characteristic(opt_char)
|
||||
|
||||
assert serv.display_name == 'TestServ'
|
||||
assert len(serv.characteristics) == 1
|
||||
assert len(serv.opt_characteristics) == 1
|
||||
|
||||
assert serv.get_characteristic('TestChar') == char
|
||||
assert serv.get_characteristic('TestOptChar') == opt_char
|
||||
assert serv.get_characteristic('NewChar').display_name == 'NewChar'
|
||||
assert len(serv.characteristics) == 2
|
||||
|
||||
|
||||
def test_mock_char():
|
||||
"""Test attributes and functions of a MockChar."""
|
||||
def callback_method(value):
|
||||
"""Provide a callback options for 'set_value' method."""
|
||||
assert value == 'With callback'
|
||||
|
||||
char = MockChar('TestChar')
|
||||
char.set_value('Value')
|
||||
|
||||
assert char.display_name == 'TestChar'
|
||||
assert char.get_value() == 'Value'
|
||||
|
||||
char.setter_callback = callback_method
|
||||
char.set_value('With callback')
|
|
@ -1,5 +1,6 @@
|
|||
"""Test different accessory types: Covers."""
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.components.cover import (
|
||||
|
@ -10,6 +11,9 @@ from homeassistant.const import (
|
|||
ATTR_SERVICE, ATTR_SERVICE_DATA, EVENT_CALL_SERVICE)
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
from tests.mock.homekit import get_patch_paths, mock_preload_service
|
||||
|
||||
PATH_ACC, PATH_FILE = get_patch_paths('covers')
|
||||
|
||||
|
||||
class TestHomekitSensors(unittest.TestCase):
|
||||
|
@ -35,13 +39,14 @@ class TestHomekitSensors(unittest.TestCase):
|
|||
"""Test if accessory and HA are updated accordingly."""
|
||||
window_cover = 'cover.window'
|
||||
|
||||
acc = Window(self.hass, window_cover, 'Cover')
|
||||
acc.run()
|
||||
with patch(PATH_ACC, side_effect=mock_preload_service):
|
||||
with patch(PATH_FILE, side_effect=mock_preload_service):
|
||||
acc = Window(self.hass, window_cover, 'Cover')
|
||||
acc.run()
|
||||
|
||||
self.assertEqual(acc.char_current_position.value, 0)
|
||||
self.assertEqual(acc.char_target_position.value, 0)
|
||||
# Temporarily disabled due to bug in HAP-python==1.15 with py3.5
|
||||
# self.assertEqual(acc.char_position_state.value, 0)
|
||||
self.assertEqual(acc.char_position_state.value, 0)
|
||||
|
||||
self.hass.states.set(window_cover, STATE_UNKNOWN,
|
||||
{ATTR_CURRENT_POSITION: None})
|
||||
|
@ -49,8 +54,7 @@ class TestHomekitSensors(unittest.TestCase):
|
|||
|
||||
self.assertEqual(acc.char_current_position.value, 0)
|
||||
self.assertEqual(acc.char_target_position.value, 0)
|
||||
# Temporarily disabled due to bug in HAP-python==1.15 with py3.5
|
||||
# self.assertEqual(acc.char_position_state.value, 0)
|
||||
self.assertEqual(acc.char_position_state.value, 0)
|
||||
|
||||
self.hass.states.set(window_cover, STATE_OPEN,
|
||||
{ATTR_CURRENT_POSITION: 50})
|
||||
|
|
|
@ -6,7 +6,7 @@ from homeassistant.components.homekit import (
|
|||
TYPES, get_accessory, import_types)
|
||||
from homeassistant.const import (
|
||||
ATTR_UNIT_OF_MEASUREMENT, ATTR_SUPPORTED_FEATURES,
|
||||
TEMP_CELSIUS, STATE_UNKNOWN)
|
||||
TEMP_CELSIUS, TEMP_FAHRENHEIT, STATE_UNKNOWN)
|
||||
|
||||
|
||||
def test_import_types():
|
||||
|
@ -26,21 +26,32 @@ def test_component_not_supported():
|
|||
assert True if get_accessory(None, state) is None else False
|
||||
|
||||
|
||||
def test_sensor_temperatur_celsius():
|
||||
"""Test temperature sensor with celsius as unit."""
|
||||
def test_sensor_temperature_celsius():
|
||||
"""Test temperature sensor with Celsius as unit."""
|
||||
mock_type = MagicMock()
|
||||
with patch.dict(TYPES, {'TemperatureSensor': mock_type}):
|
||||
state = State('sensor.temperatur', '23',
|
||||
state = State('sensor.temperature', '23',
|
||||
{ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS})
|
||||
get_accessory(None, state)
|
||||
assert len(mock_type.mock_calls) == 1
|
||||
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
def test_sensor_temperature_fahrenheit():
|
||||
"""Test temperature sensor with Fahrenheit as unit."""
|
||||
mock_type = MagicMock()
|
||||
with patch.dict(TYPES, {'TemperatureSensor': mock_type}):
|
||||
state = State('sensor.temperature', '74',
|
||||
{ATTR_UNIT_OF_MEASUREMENT: TEMP_FAHRENHEIT})
|
||||
get_accessory(None, state)
|
||||
assert len(mock_type.mock_calls) == 1
|
||||
|
||||
|
||||
def test_cover_set_position():
|
||||
"""Test cover with support for set_cover_position."""
|
||||
mock_type = MagicMock()
|
||||
with patch.dict(TYPES, {'Window': mock_type}):
|
||||
state = State('cover.setposition', 'open',
|
||||
state = State('cover.set_position', 'open',
|
||||
{ATTR_SUPPORTED_FEATURES: 4})
|
||||
get_accessory(None, state)
|
||||
assert len(mock_type.mock_calls) == 1
|
||||
|
|
|
@ -1,20 +1,25 @@
|
|||
"""Tests for the HomeKit component."""
|
||||
|
||||
import unittest
|
||||
from unittest.mock import call, patch
|
||||
from unittest.mock import call, patch, ANY
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
# pylint: disable=unused-import
|
||||
from pyhap.accessory_driver import AccessoryDriver # noqa F401
|
||||
|
||||
from homeassistant import setup
|
||||
from homeassistant.core import Event
|
||||
from homeassistant.components.homekit import (
|
||||
CONF_PIN_CODE, BRIDGE_NAME, HOMEKIT_FILE, HomeKit, valid_pin)
|
||||
CONF_PIN_CODE, HOMEKIT_FILE, HomeKit, valid_pin)
|
||||
from homeassistant.const import (
|
||||
CONF_PORT, EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP)
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
from tests.mock.homekit import get_patch_paths, PATH_HOMEKIT
|
||||
|
||||
HOMEKIT_PATH = 'homeassistant.components.homekit'
|
||||
PATH_ACC, _ = get_patch_paths()
|
||||
IP_ADDRESS = '127.0.0.1'
|
||||
|
||||
CONFIG_MIN = {'homekit': {}}
|
||||
CONFIG = {
|
||||
|
@ -36,39 +41,6 @@ class TestHomeKit(unittest.TestCase):
|
|||
"""Stop down everything that was started."""
|
||||
self.hass.stop()
|
||||
|
||||
@patch(HOMEKIT_PATH + '.HomeKit.start_driver')
|
||||
@patch(HOMEKIT_PATH + '.HomeKit.setup_bridge')
|
||||
@patch(HOMEKIT_PATH + '.HomeKit.__init__')
|
||||
def test_setup_min(self, mock_homekit, mock_setup_bridge,
|
||||
mock_start_driver):
|
||||
"""Test async_setup with minimal config option."""
|
||||
mock_homekit.return_value = None
|
||||
|
||||
self.assertTrue(setup.setup_component(
|
||||
self.hass, 'homekit', CONFIG_MIN))
|
||||
|
||||
mock_homekit.assert_called_once_with(self.hass, 51826)
|
||||
mock_setup_bridge.assert_called_with(b'123-45-678')
|
||||
mock_start_driver.assert_not_called()
|
||||
|
||||
self.hass.start()
|
||||
self.hass.block_till_done()
|
||||
self.assertEqual(mock_start_driver.call_count, 1)
|
||||
|
||||
@patch(HOMEKIT_PATH + '.HomeKit.start_driver')
|
||||
@patch(HOMEKIT_PATH + '.HomeKit.setup_bridge')
|
||||
@patch(HOMEKIT_PATH + '.HomeKit.__init__')
|
||||
def test_setup_parameters(self, mock_homekit, mock_setup_bridge,
|
||||
mock_start_driver):
|
||||
"""Test async_setup with full config option."""
|
||||
mock_homekit.return_value = None
|
||||
|
||||
self.assertTrue(setup.setup_component(
|
||||
self.hass, 'homekit', CONFIG))
|
||||
|
||||
mock_homekit.assert_called_once_with(self.hass, 11111)
|
||||
mock_setup_bridge.assert_called_with(b'987-65-432')
|
||||
|
||||
def test_validate_pincode(self):
|
||||
"""Test async_setup with invalid config option."""
|
||||
schema = vol.Schema(valid_pin)
|
||||
|
@ -80,45 +52,64 @@ class TestHomeKit(unittest.TestCase):
|
|||
for value in ('123-45-678', '234-56-789'):
|
||||
self.assertTrue(schema(value))
|
||||
|
||||
@patch(PATH_HOMEKIT + '.HomeKit')
|
||||
def test_setup_min(self, mock_homekit):
|
||||
"""Test async_setup with minimal config option."""
|
||||
self.assertTrue(setup.setup_component(
|
||||
self.hass, 'homekit', CONFIG_MIN))
|
||||
|
||||
self.assertEqual(mock_homekit.mock_calls,
|
||||
[call(self.hass, 51826),
|
||||
call().setup_bridge(b'123-45-678')])
|
||||
mock_homekit.reset_mock()
|
||||
|
||||
self.hass.bus.fire(EVENT_HOMEASSISTANT_START)
|
||||
self.hass.block_till_done()
|
||||
|
||||
self.assertEqual(mock_homekit.mock_calls,
|
||||
[call().start_driver(ANY)])
|
||||
|
||||
@patch(PATH_HOMEKIT + '.HomeKit')
|
||||
def test_setup_parameters(self, mock_homekit):
|
||||
"""Test async_setup with full config option."""
|
||||
self.assertTrue(setup.setup_component(
|
||||
self.hass, 'homekit', CONFIG))
|
||||
|
||||
self.assertEqual(mock_homekit.mock_calls,
|
||||
[call(self.hass, 11111),
|
||||
call().setup_bridge(b'987-65-432')])
|
||||
|
||||
@patch('pyhap.accessory_driver.AccessoryDriver')
|
||||
@patch('pyhap.accessory.Bridge.add_accessory')
|
||||
@patch(HOMEKIT_PATH + '.import_types')
|
||||
@patch(HOMEKIT_PATH + '.get_accessory')
|
||||
def test_homekit_pyhap_interaction(
|
||||
self, mock_get_accessory, mock_import_types,
|
||||
mock_add_accessory, mock_acc_driver):
|
||||
def test_homekit_class(self, mock_acc_driver):
|
||||
"""Test interaction between the HomeKit class and pyhap."""
|
||||
mock_get_accessory.side_effect = ['TemperatureSensor', 'Window']
|
||||
|
||||
homekit = HomeKit(self.hass, 51826)
|
||||
homekit.setup_bridge(b'123-45-678')
|
||||
|
||||
self.assertEqual(homekit.bridge.display_name, BRIDGE_NAME)
|
||||
with patch(PATH_HOMEKIT + '.accessories.HomeBridge') as mock_bridge:
|
||||
homekit = HomeKit(self.hass, 51826)
|
||||
homekit.setup_bridge(b'123-45-678')
|
||||
|
||||
mock_bridge.reset_mock()
|
||||
self.hass.states.set('demo.demo1', 'on')
|
||||
self.hass.states.set('demo.demo2', 'off')
|
||||
|
||||
self.hass.start()
|
||||
self.hass.block_till_done()
|
||||
|
||||
with patch('homeassistant.util.get_local_ip',
|
||||
return_value='127.0.0.1'):
|
||||
with patch(PATH_HOMEKIT + '.get_accessory') as mock_get_acc, \
|
||||
patch(PATH_HOMEKIT + '.import_types') as mock_import_types, \
|
||||
patch('homeassistant.util.get_local_ip') as mock_ip:
|
||||
mock_get_acc.side_effect = ['TempSensor', 'Window']
|
||||
mock_ip.return_value = IP_ADDRESS
|
||||
homekit.start_driver(Event(EVENT_HOMEASSISTANT_START))
|
||||
|
||||
ip_address = '127.0.0.1'
|
||||
path = self.hass.config.path(HOMEKIT_FILE)
|
||||
|
||||
self.assertEqual(mock_get_accessory.call_count, 2)
|
||||
self.assertEqual(mock_import_types.call_count, 1)
|
||||
self.assertEqual(mock_get_acc.call_count, 2)
|
||||
self.assertEqual(mock_bridge.mock_calls,
|
||||
[call().add_accessory('TempSensor'),
|
||||
call().add_accessory('Window')])
|
||||
self.assertEqual(mock_acc_driver.mock_calls,
|
||||
[call(homekit.bridge, 51826, ip_address, path),
|
||||
[call(homekit.bridge, 51826, IP_ADDRESS, path),
|
||||
call().start()])
|
||||
|
||||
self.assertEqual(mock_add_accessory.mock_calls,
|
||||
[call('TemperatureSensor'), call('Window')])
|
||||
mock_acc_driver.reset_mock()
|
||||
|
||||
self.hass.bus.fire(EVENT_HOMEASSISTANT_STOP)
|
||||
self.hass.block_till_done()
|
||||
|
||||
self.assertEqual(mock_acc_driver.mock_calls[2], call().stop())
|
||||
self.assertEqual(len(mock_acc_driver.mock_calls), 3)
|
||||
self.assertEqual(mock_acc_driver.mock_calls, [call().stop()])
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
"""Test different accessory types: Sensors."""
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.homekit.const import PROP_CELSIUS
|
||||
from homeassistant.components.homekit.sensors import (
|
||||
TemperatureSensor, calc_temperature)
|
||||
from homeassistant.const import (
|
||||
ATTR_UNIT_OF_MEASUREMENT, TEMP_CELSIUS, TEMP_FAHRENHEIT, STATE_UNKNOWN)
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
from tests.mock.homekit import get_patch_paths, mock_preload_service
|
||||
|
||||
PATH_ACC, PATH_FILE = get_patch_paths('sensors')
|
||||
|
||||
|
||||
def test_calc_temperature():
|
||||
|
@ -27,19 +32,24 @@ class TestHomekitSensors(unittest.TestCase):
|
|||
def setUp(self):
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
get_patch_paths('sensors')
|
||||
|
||||
def tearDown(self):
|
||||
"""Stop down everything that was started."""
|
||||
self.hass.stop()
|
||||
|
||||
def test_temperature_celsius(self):
|
||||
def test_temperature(self):
|
||||
"""Test if accessory is updated after state change."""
|
||||
temperature_sensor = 'sensor.temperature'
|
||||
|
||||
acc = TemperatureSensor(self.hass, temperature_sensor, 'Temperature')
|
||||
acc.run()
|
||||
with patch(PATH_ACC, side_effect=mock_preload_service):
|
||||
with patch(PATH_FILE, side_effect=mock_preload_service):
|
||||
acc = TemperatureSensor(self.hass, temperature_sensor,
|
||||
'Temperature')
|
||||
acc.run()
|
||||
|
||||
self.assertEqual(acc.char_temp.value, 0.0)
|
||||
self.assertEqual(acc.char_temp.properties, PROP_CELSIUS)
|
||||
|
||||
self.hass.states.set(temperature_sensor, STATE_UNKNOWN,
|
||||
{ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue