Add storage for cacheable homekit entity maps. (#23191)
This commit is contained in:
parent
f57191e8dd
commit
4ac9a2e9de
9 changed files with 373 additions and 29 deletions
|
@ -249,6 +249,7 @@ async def device_config_changed(hass, accessories):
|
|||
|
||||
# Wait for services to reconfigure
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
async def setup_test_component(hass, services, capitalize=False, suffix=None):
|
||||
|
|
|
@ -4,12 +4,16 @@ Regression tests for Ecobee 3.
|
|||
https://github.com/home-assistant/home-assistant/issues/15336
|
||||
"""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from homekit import AccessoryDisconnectedError
|
||||
|
||||
from homeassistant.components.climate.const import (
|
||||
SUPPORT_TARGET_TEMPERATURE, SUPPORT_TARGET_HUMIDITY,
|
||||
SUPPORT_OPERATION_MODE)
|
||||
from tests.components.homekit_controller.common import (
|
||||
device_config_changed, setup_accessories_from_file, setup_test_accessories,
|
||||
Helper
|
||||
FakePairing, device_config_changed, setup_accessories_from_file,
|
||||
setup_test_accessories, Helper
|
||||
)
|
||||
|
||||
|
||||
|
@ -46,6 +50,74 @@ async def test_ecobee3_setup(hass):
|
|||
assert occ3.unique_id == 'homekit-AB3C-56'
|
||||
|
||||
|
||||
async def test_ecobee3_setup_from_cache(hass, hass_storage):
|
||||
"""Test that Ecbobee can be correctly setup from its cached entity map."""
|
||||
accessories = await setup_accessories_from_file(hass, 'ecobee3.json')
|
||||
|
||||
hass_storage['homekit_controller-entity-map'] = {
|
||||
'version': 1,
|
||||
'data': {
|
||||
'pairings': {
|
||||
'00:00:00:00:00:00': {
|
||||
'config_num': 1,
|
||||
'accessories': [
|
||||
a.to_accessory_and_service_list() for a in accessories
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await setup_test_accessories(hass, accessories)
|
||||
|
||||
entity_registry = await hass.helpers.entity_registry.async_get_registry()
|
||||
|
||||
climate = entity_registry.async_get('climate.homew')
|
||||
assert climate.unique_id == 'homekit-123456789012-16'
|
||||
|
||||
occ1 = entity_registry.async_get('binary_sensor.kitchen')
|
||||
assert occ1.unique_id == 'homekit-AB1C-56'
|
||||
|
||||
occ2 = entity_registry.async_get('binary_sensor.porch')
|
||||
assert occ2.unique_id == 'homekit-AB2C-56'
|
||||
|
||||
occ3 = entity_registry.async_get('binary_sensor.basement')
|
||||
assert occ3.unique_id == 'homekit-AB3C-56'
|
||||
|
||||
|
||||
async def test_ecobee3_setup_connection_failure(hass):
|
||||
"""Test that Ecbobee can be correctly setup from its cached entity map."""
|
||||
accessories = await setup_accessories_from_file(hass, 'ecobee3.json')
|
||||
|
||||
entity_registry = await hass.helpers.entity_registry.async_get_registry()
|
||||
|
||||
# Test that the connection fails during initial setup.
|
||||
# No entities should be created.
|
||||
list_accessories = 'list_accessories_and_characteristics'
|
||||
with mock.patch.object(FakePairing, list_accessories) as laac:
|
||||
laac.side_effect = AccessoryDisconnectedError('Connection failed')
|
||||
await setup_test_accessories(hass, accessories)
|
||||
|
||||
climate = entity_registry.async_get('climate.homew')
|
||||
assert climate is None
|
||||
|
||||
# When a regular discovery event happens it should trigger another scan
|
||||
# which should cause our entities to be added.
|
||||
await device_config_changed(hass, accessories)
|
||||
|
||||
climate = entity_registry.async_get('climate.homew')
|
||||
assert climate.unique_id == 'homekit-123456789012-16'
|
||||
|
||||
occ1 = entity_registry.async_get('binary_sensor.kitchen')
|
||||
assert occ1.unique_id == 'homekit-AB1C-56'
|
||||
|
||||
occ2 = entity_registry.async_get('binary_sensor.porch')
|
||||
assert occ2.unique_id == 'homekit-AB2C-56'
|
||||
|
||||
occ3 = entity_registry.async_get('binary_sensor.basement')
|
||||
assert occ3.unique_id == 'homekit-AB3C-56'
|
||||
|
||||
|
||||
async def test_ecobee3_add_sensors_at_runtime(hass):
|
||||
"""Test that new sensors are automatically added."""
|
||||
entity_registry = await hass.helpers.entity_registry.async_get_registry()
|
||||
|
|
|
@ -295,7 +295,7 @@ async def test_discovery_already_configured_config_change(hass):
|
|||
assert result['type'] == 'abort'
|
||||
assert result['reason'] == 'already_configured'
|
||||
|
||||
assert conn.async_config_num_changed.call_args == mock.call(2)
|
||||
assert conn.async_refresh_entity_map.call_args == mock.call(2)
|
||||
|
||||
|
||||
async def test_pair_unable_to_pair(hass):
|
||||
|
|
112
tests/components/homekit_controller/test_storage.py
Normal file
112
tests/components/homekit_controller/test_storage.py
Normal file
|
@ -0,0 +1,112 @@
|
|||
"""Basic checks for entity map storage."""
|
||||
from tests.common import flush_store
|
||||
from tests.components.homekit_controller.common import (
|
||||
FakeService, setup_test_component, setup_platform)
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.homekit_controller import async_remove_entry
|
||||
from homeassistant.components.homekit_controller.const import ENTITY_MAP
|
||||
|
||||
|
||||
async def test_load_from_storage(hass, hass_storage):
|
||||
"""Test that entity map can be correctly loaded from cache."""
|
||||
hkid = '00:00:00:00:00:00'
|
||||
|
||||
hass_storage['homekit_controller-entity-map'] = {
|
||||
'version': 1,
|
||||
'data': {
|
||||
'pairings': {
|
||||
hkid: {
|
||||
'c#': 1,
|
||||
'accessories': [],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await setup_platform(hass)
|
||||
assert hkid in hass.data[ENTITY_MAP].storage_data
|
||||
|
||||
|
||||
async def test_storage_is_removed(hass, hass_storage):
|
||||
"""Test entity map storage removal is idempotent."""
|
||||
await setup_platform(hass)
|
||||
|
||||
entity_map = hass.data[ENTITY_MAP]
|
||||
hkid = '00:00:00:00:00:01'
|
||||
|
||||
entity_map.async_create_or_update_map(
|
||||
hkid,
|
||||
1,
|
||||
[],
|
||||
)
|
||||
assert hkid in entity_map.storage_data
|
||||
await flush_store(entity_map.store)
|
||||
assert hkid in hass_storage[ENTITY_MAP]['data']['pairings']
|
||||
|
||||
entity_map.async_delete_map(hkid)
|
||||
assert hkid not in hass.data[ENTITY_MAP].storage_data
|
||||
await flush_store(entity_map.store)
|
||||
|
||||
assert hass_storage[ENTITY_MAP]['data']['pairings'] == {}
|
||||
|
||||
|
||||
async def test_storage_is_removed_idempotent(hass):
|
||||
"""Test entity map storage removal is idempotent."""
|
||||
await setup_platform(hass)
|
||||
|
||||
entity_map = hass.data[ENTITY_MAP]
|
||||
hkid = '00:00:00:00:00:01'
|
||||
|
||||
assert hkid not in entity_map.storage_data
|
||||
|
||||
entity_map.async_delete_map(hkid)
|
||||
|
||||
assert hkid not in entity_map.storage_data
|
||||
|
||||
|
||||
def create_lightbulb_service():
|
||||
"""Define lightbulb characteristics."""
|
||||
service = FakeService('public.hap.service.lightbulb')
|
||||
on_char = service.add_characteristic('on')
|
||||
on_char.value = 0
|
||||
return service
|
||||
|
||||
|
||||
async def test_storage_is_updated_on_add(hass, hass_storage, utcnow):
|
||||
"""Test entity map storage is cleaned up on adding an accessory."""
|
||||
bulb = create_lightbulb_service()
|
||||
await setup_test_component(hass, [bulb])
|
||||
|
||||
entity_map = hass.data[ENTITY_MAP]
|
||||
hkid = '00:00:00:00:00:00'
|
||||
|
||||
# Is in memory store updated?
|
||||
assert hkid in entity_map.storage_data
|
||||
|
||||
# Is saved out to store?
|
||||
await flush_store(entity_map.store)
|
||||
assert hkid in hass_storage[ENTITY_MAP]['data']['pairings']
|
||||
|
||||
|
||||
async def test_storage_is_removed_on_config_entry_removal(hass, utcnow):
|
||||
"""Test entity map storage is cleaned up on config entry removal."""
|
||||
bulb = create_lightbulb_service()
|
||||
await setup_test_component(hass, [bulb])
|
||||
|
||||
hkid = '00:00:00:00:00:00'
|
||||
|
||||
pairing_data = {
|
||||
'AccessoryPairingID': hkid,
|
||||
}
|
||||
|
||||
entry = config_entries.ConfigEntry(
|
||||
1, 'homekit_controller', 'TestData', pairing_data,
|
||||
'test', config_entries.CONN_CLASS_LOCAL_PUSH
|
||||
)
|
||||
|
||||
assert hkid in hass.data[ENTITY_MAP].storage_data
|
||||
|
||||
await async_remove_entry(hass, entry)
|
||||
|
||||
assert hkid not in hass.data[ENTITY_MAP].storage_data
|
Loading…
Add table
Add a link
Reference in a new issue