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
|
@ -64,12 +64,10 @@ def async_setup(hass, config):
|
|||
|
||||
|
||||
def import_types():
|
||||
"""Import all types from files in the HomeKit dir."""
|
||||
"""Import all types from files in the HomeKit directory."""
|
||||
_LOGGER.debug("Import type files.")
|
||||
# pylint: disable=unused-variable
|
||||
from .covers import Window # noqa F401
|
||||
# pylint: disable=unused-variable
|
||||
from .sensors import TemperatureSensor # noqa F401
|
||||
from . import covers, sensors # noqa F401
|
||||
|
||||
|
||||
def get_accessory(hass, state):
|
||||
|
|
|
@ -4,7 +4,7 @@ import logging
|
|||
from pyhap.accessory import Accessory, Bridge, Category
|
||||
|
||||
from .const import (
|
||||
SERV_ACCESSORY_INFO, MANUFACTURER,
|
||||
SERV_ACCESSORY_INFO, SERV_BRIDGING_STATE, MANUFACTURER,
|
||||
CHAR_MODEL, CHAR_MANUFACTURER, CHAR_SERIAL_NUMBER)
|
||||
|
||||
|
||||
|
@ -46,17 +46,24 @@ def override_properties(char, new_properties):
|
|||
class HomeAccessory(Accessory):
|
||||
"""Class to extend the Accessory class."""
|
||||
|
||||
def __init__(self, display_name, model, category='OTHER'):
|
||||
def __init__(self, display_name, model, category='OTHER', **kwargs):
|
||||
"""Initialize a Accessory object."""
|
||||
super().__init__(display_name)
|
||||
super().__init__(display_name, **kwargs)
|
||||
set_accessory_info(self, model)
|
||||
self.category = getattr(Category, category, Category.OTHER)
|
||||
|
||||
def _set_services(self):
|
||||
add_preload_service(self, SERV_ACCESSORY_INFO)
|
||||
|
||||
|
||||
class HomeBridge(Bridge):
|
||||
"""Class to extend the Bridge class."""
|
||||
|
||||
def __init__(self, display_name, model, pincode):
|
||||
def __init__(self, display_name, model, pincode, **kwargs):
|
||||
"""Initialize a Bridge object."""
|
||||
super().__init__(display_name, pincode=pincode)
|
||||
super().__init__(display_name, pincode=pincode, **kwargs)
|
||||
set_accessory_info(self, model)
|
||||
|
||||
def _set_services(self):
|
||||
add_preload_service(self, SERV_ACCESSORY_INFO)
|
||||
add_preload_service(self, SERV_BRIDGING_STATE)
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
"""Constants used be the HomeKit component."""
|
||||
MANUFACTURER = 'HomeAssistant'
|
||||
|
||||
# Service: AccessoryInfomation
|
||||
# Services
|
||||
SERV_ACCESSORY_INFO = 'AccessoryInformation'
|
||||
CHAR_MODEL = 'Model'
|
||||
CHAR_MANUFACTURER = 'Manufacturer'
|
||||
CHAR_SERIAL_NUMBER = 'SerialNumber'
|
||||
|
||||
# Service: TemperatureSensor
|
||||
SERV_BRIDGING_STATE = 'BridgingState'
|
||||
SERV_TEMPERATURE_SENSOR = 'TemperatureSensor'
|
||||
CHAR_CURRENT_TEMPERATURE = 'CurrentTemperature'
|
||||
|
||||
# Service: WindowCovering
|
||||
SERV_WINDOW_COVERING = 'WindowCovering'
|
||||
|
||||
# Characteristics
|
||||
CHAR_ACC_IDENTIFIER = 'AccessoryIdentifier'
|
||||
CHAR_CATEGORY = 'Category'
|
||||
CHAR_CURRENT_POSITION = 'CurrentPosition'
|
||||
CHAR_TARGET_POSITION = 'TargetPosition'
|
||||
CHAR_CURRENT_TEMPERATURE = 'CurrentTemperature'
|
||||
CHAR_LINK_QUALITY = 'LinkQuality'
|
||||
CHAR_MANUFACTURER = 'Manufacturer'
|
||||
CHAR_MODEL = 'Model'
|
||||
CHAR_POSITION_STATE = 'PositionState'
|
||||
CHAR_REACHABLE = 'Reachable'
|
||||
CHAR_SERIAL_NUMBER = 'SerialNumber'
|
||||
CHAR_TARGET_POSITION = 'TargetPosition'
|
||||
|
||||
# Properties
|
||||
PROP_CELSIUS = {'minValue': -273, 'maxValue': 999}
|
||||
|
|
|
@ -38,6 +38,9 @@ class Window(HomeAccessory):
|
|||
get_characteristic(CHAR_TARGET_POSITION)
|
||||
self.char_position_state = self.serv_cover. \
|
||||
get_characteristic(CHAR_POSITION_STATE)
|
||||
self.char_current_position.value = 0
|
||||
self.char_target_position.value = 0
|
||||
self.char_position_state.value = 0
|
||||
|
||||
self.char_target_position.setter_callback = self.move_cover
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ class TemperatureSensor(HomeAccessory):
|
|||
self.char_temp = self.serv_temp. \
|
||||
get_characteristic(CHAR_CURRENT_TEMPERATURE)
|
||||
override_properties(self.char_temp, PROP_CELSIUS)
|
||||
self.char_temp.value = 0
|
||||
self.unit = None
|
||||
|
||||
def run(self):
|
||||
|
|
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})
|
||||
|
|
133
tests/mock/homekit.py
Normal file
133
tests/mock/homekit.py
Normal file
|
@ -0,0 +1,133 @@
|
|||
"""Basic mock functions and objects related to the HomeKit component."""
|
||||
PATH_HOMEKIT = 'homeassistant.components.homekit'
|
||||
|
||||
|
||||
def get_patch_paths(name=None):
|
||||
"""Return paths to mock 'add_preload_service'."""
|
||||
path_acc = PATH_HOMEKIT + '.accessories.add_preload_service'
|
||||
path_file = PATH_HOMEKIT + '.' + str(name) + '.add_preload_service'
|
||||
return (path_acc, path_file)
|
||||
|
||||
|
||||
def mock_preload_service(acc, service, chars=None, opt_chars=None):
|
||||
"""Mock alternative for function 'add_preload_service'."""
|
||||
service = MockService(service)
|
||||
if chars:
|
||||
chars = chars if isinstance(chars, list) else [chars]
|
||||
for char_name in chars:
|
||||
service.add_characteristic(char_name)
|
||||
if opt_chars:
|
||||
opt_chars = opt_chars if isinstance(opt_chars, list) else [opt_chars]
|
||||
for opt_char_name in opt_chars:
|
||||
service.add_characteristic(opt_char_name)
|
||||
acc.add_service(service)
|
||||
return service
|
||||
|
||||
|
||||
class MockAccessory():
|
||||
"""Define all attributes and methods for a MockAccessory."""
|
||||
|
||||
def __init__(self, name):
|
||||
"""Initialize a MockAccessory object."""
|
||||
self.display_name = name
|
||||
self.services = []
|
||||
|
||||
def __repr__(self):
|
||||
"""Return a representation of a MockAccessory. Use for debugging."""
|
||||
serv_list = [serv.display_name for serv in self.services]
|
||||
return "<accessory \"{}\", services={}>".format(
|
||||
self.display_name, serv_list)
|
||||
|
||||
def add_service(self, service):
|
||||
"""Add service to list of services."""
|
||||
self.services.append(service)
|
||||
|
||||
def get_service(self, name):
|
||||
"""Retrieve service from service list or return new MockService."""
|
||||
for serv in self.services:
|
||||
if serv.display_name == name:
|
||||
return serv
|
||||
serv = MockService(name)
|
||||
self.add_service(serv)
|
||||
return serv
|
||||
|
||||
|
||||
class MockService():
|
||||
"""Define all attributes and methods for a MockService."""
|
||||
|
||||
def __init__(self, name):
|
||||
"""Initialize a MockService object."""
|
||||
self.characteristics = []
|
||||
self.opt_characteristics = []
|
||||
self.display_name = name
|
||||
|
||||
def __repr__(self):
|
||||
"""Return a representation of a MockService. Use for debugging."""
|
||||
char_list = [char.display_name for char in self.characteristics]
|
||||
opt_char_list = [
|
||||
char.display_name for char in self.opt_characteristics]
|
||||
return "<service \"{}\", chars={}, opt_chars={}>".format(
|
||||
self.display_name, char_list, opt_char_list)
|
||||
|
||||
def add_characteristic(self, char):
|
||||
"""Add characteristic to char list."""
|
||||
self.characteristics.append(char)
|
||||
|
||||
def add_opt_characteristic(self, char):
|
||||
"""Add characteristic to opt_char list."""
|
||||
self.opt_characteristics.append(char)
|
||||
|
||||
def get_characteristic(self, name):
|
||||
"""Get char for char lists or return new MockChar."""
|
||||
for char in self.characteristics:
|
||||
if char.display_name == name:
|
||||
return char
|
||||
for char in self.opt_characteristics:
|
||||
if char.display_name == name:
|
||||
return char
|
||||
char = MockChar(name)
|
||||
self.add_characteristic(char)
|
||||
return char
|
||||
|
||||
|
||||
class MockChar():
|
||||
"""Define all attributes and methods for a MockChar."""
|
||||
|
||||
def __init__(self, name):
|
||||
"""Initialize a MockChar object."""
|
||||
self.display_name = name
|
||||
self.properties = {}
|
||||
self.value = None
|
||||
self.type_id = None
|
||||
self.setter_callback = None
|
||||
|
||||
def __repr__(self):
|
||||
"""Return a representation of a MockChar. Use for debugging."""
|
||||
return "<char \"{}\", value={}>".format(
|
||||
self.display_name, self.value)
|
||||
|
||||
def set_value(self, value, should_notify=True, should_callback=True):
|
||||
"""Set value of char."""
|
||||
self.value = value
|
||||
if self.setter_callback is not None and should_callback:
|
||||
# pylint: disable=not-callable
|
||||
self.setter_callback(value)
|
||||
|
||||
def get_value(self):
|
||||
"""Get char value."""
|
||||
return self.value
|
||||
|
||||
|
||||
class MockTypeLoader():
|
||||
"""Define all attributes and methods for a MockTypeLoader."""
|
||||
|
||||
def __init__(self, class_type):
|
||||
"""Initialize a MockTypeLoader object."""
|
||||
self.class_type = class_type
|
||||
|
||||
def get(self, name):
|
||||
"""Return a MockService or MockChar object."""
|
||||
if self.class_type == 'service':
|
||||
return MockService(name)
|
||||
elif self.class_type == 'char':
|
||||
return MockChar(name)
|
Loading…
Add table
Reference in a new issue