Fix listener leak in HomeKit on reload (#56143)

* Fix listener leak in HomeKit on reload

* Fix mocking
This commit is contained in:
J. Nick Koston 2021-09-12 12:06:03 -10:00 committed by GitHub
parent 4e8db7173a
commit 0fc89780e9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 87 additions and 33 deletions

View file

@ -60,7 +60,7 @@ async def test_accessory_cancels_track_state_change_on_stop(hass, hk_driver):
):
await acc.run()
assert len(hass.data[TRACK_STATE_CHANGE_CALLBACKS][entity_id]) == 1
acc.async_stop()
await acc.stop()
assert entity_id not in hass.data[TRACK_STATE_CHANGE_CALLBACKS]

View file

@ -442,11 +442,12 @@ async def test_homekit_remove_accessory(hass, mock_zeroconf):
homekit.driver = "driver"
homekit.bridge = _mock_pyhap_bridge()
acc_mock = MagicMock()
acc_mock.stop = AsyncMock()
homekit.bridge.accessories = {6: acc_mock}
acc = homekit.remove_bridge_accessory(6)
acc = await homekit.async_remove_bridge_accessory(6)
assert acc is acc_mock
assert acc_mock.async_stop.called
assert acc_mock.stop.called
assert len(homekit.bridge.accessories) == 0
@ -695,9 +696,11 @@ async def test_homekit_reset_accessories(hass, mock_zeroconf):
acc_mock = MagicMock()
acc_mock.entity_id = entity_id
acc_mock.stop = AsyncMock()
aid = homekit.aid_storage.get_or_allocate_aid_for_entity_id(entity_id)
homekit.bridge.accessories = {aid: acc_mock}
homekit.status = STATUS_RUNNING
homekit.driver.aio_stop_event = MagicMock()
await hass.services.async_call(
DOMAIN,
@ -730,9 +733,12 @@ async def test_homekit_unpair(hass, device_reg, mock_zeroconf):
acc_mock = MagicMock()
acc_mock.entity_id = entity_id
acc_mock.stop = AsyncMock()
aid = homekit.aid_storage.get_or_allocate_aid_for_entity_id(entity_id)
homekit.bridge.accessories = {aid: acc_mock}
homekit.status = STATUS_RUNNING
homekit.driver.aio_stop_event = MagicMock()
state = homekit.driver.state
state.add_paired_client("client1", "any", b"1")
@ -769,9 +775,12 @@ async def test_homekit_unpair_missing_device_id(hass, device_reg, mock_zeroconf)
acc_mock = MagicMock()
acc_mock.entity_id = entity_id
acc_mock.stop = AsyncMock()
aid = homekit.aid_storage.get_or_allocate_aid_for_entity_id(entity_id)
homekit.bridge.accessories = {aid: acc_mock}
homekit.status = STATUS_RUNNING
homekit.driver.aio_stop_event = MagicMock()
state = homekit.driver.state
state.add_paired_client("client1", "any", b"1")
@ -807,6 +816,8 @@ async def test_homekit_unpair_not_homekit_device(hass, device_reg, mock_zeroconf
acc_mock = MagicMock()
acc_mock.entity_id = entity_id
acc_mock.stop = AsyncMock()
aid = homekit.aid_storage.get_or_allocate_aid_for_entity_id(entity_id)
homekit.bridge.accessories = {aid: acc_mock}
homekit.status = STATUS_RUNNING
@ -856,9 +867,12 @@ async def test_homekit_reset_accessories_not_supported(hass, mock_zeroconf):
acc_mock = MagicMock()
acc_mock.entity_id = entity_id
acc_mock.stop = AsyncMock()
aid = homekit.aid_storage.get_or_allocate_aid_for_entity_id(entity_id)
homekit.bridge.accessories = {aid: acc_mock}
homekit.status = STATUS_RUNNING
homekit.driver.aio_stop_event = MagicMock()
await hass.services.async_call(
DOMAIN,
@ -896,9 +910,12 @@ async def test_homekit_reset_accessories_state_missing(hass, mock_zeroconf):
acc_mock = MagicMock()
acc_mock.entity_id = entity_id
acc_mock.stop = AsyncMock()
aid = homekit.aid_storage.get_or_allocate_aid_for_entity_id(entity_id)
homekit.bridge.accessories = {aid: acc_mock}
homekit.status = STATUS_RUNNING
homekit.driver.aio_stop_event = MagicMock()
await hass.services.async_call(
DOMAIN,
@ -935,9 +952,12 @@ async def test_homekit_reset_accessories_not_bridged(hass, mock_zeroconf):
acc_mock = MagicMock()
acc_mock.entity_id = entity_id
acc_mock.stop = AsyncMock()
aid = homekit.aid_storage.get_or_allocate_aid_for_entity_id(entity_id)
homekit.bridge.accessories = {aid: acc_mock}
homekit.status = STATUS_RUNNING
homekit.driver.aio_stop_event = MagicMock()
await hass.services.async_call(
DOMAIN,
@ -974,7 +994,10 @@ async def test_homekit_reset_single_accessory(hass, mock_zeroconf):
homekit.status = STATUS_RUNNING
acc_mock = MagicMock()
acc_mock.entity_id = entity_id
acc_mock.stop = AsyncMock()
homekit.driver.accessory = acc_mock
homekit.driver.aio_stop_event = MagicMock()
await hass.services.async_call(
DOMAIN,
@ -1008,7 +1031,10 @@ async def test_homekit_reset_single_accessory_unsupported(hass, mock_zeroconf):
homekit.status = STATUS_RUNNING
acc_mock = MagicMock()
acc_mock.entity_id = entity_id
acc_mock.stop = AsyncMock()
homekit.driver.accessory = acc_mock
homekit.driver.aio_stop_event = MagicMock()
await hass.services.async_call(
DOMAIN,
@ -1041,7 +1067,10 @@ async def test_homekit_reset_single_accessory_state_missing(hass, mock_zeroconf)
homekit.status = STATUS_RUNNING
acc_mock = MagicMock()
acc_mock.entity_id = entity_id
acc_mock.stop = AsyncMock()
homekit.driver.accessory = acc_mock
homekit.driver.aio_stop_event = MagicMock()
await hass.services.async_call(
DOMAIN,
@ -1074,7 +1103,10 @@ async def test_homekit_reset_single_accessory_no_match(hass, mock_zeroconf):
homekit.status = STATUS_RUNNING
acc_mock = MagicMock()
acc_mock.entity_id = entity_id
acc_mock.stop = AsyncMock()
homekit.driver.accessory = acc_mock
homekit.driver.aio_stop_event = MagicMock()
await hass.services.async_call(
DOMAIN,

View file

@ -1,5 +1,6 @@
"""Test different accessory types: Camera."""
import asyncio
from unittest.mock import AsyncMock, MagicMock, PropertyMock, patch
from uuid import UUID
@ -45,6 +46,7 @@ PID_THAT_WILL_NEVER_BE_ALIVE = 2147483647
async def _async_start_streaming(hass, acc):
"""Start streaming a camera."""
acc.set_selected_stream_configuration(MOCK_START_STREAM_TLV)
await hass.async_block_till_done()
await acc.run()
await hass.async_block_till_done()
@ -92,6 +94,18 @@ def run_driver(hass):
)
def _mock_reader():
"""Mock ffmpeg reader."""
async def _readline(*args, **kwargs):
await asyncio.sleep(0.1)
async def _get_reader(*args, **kwargs):
return AsyncMock(readline=_readline)
return _get_reader
def _get_exits_after_startup_mock_ffmpeg():
"""Return a ffmpeg that will have an invalid pid."""
ffmpeg = MagicMock()
@ -99,7 +113,7 @@ def _get_exits_after_startup_mock_ffmpeg():
ffmpeg.open = AsyncMock(return_value=True)
ffmpeg.close = AsyncMock(return_value=True)
ffmpeg.kill = AsyncMock(return_value=True)
ffmpeg.get_reader = AsyncMock()
ffmpeg.get_reader = _mock_reader()
return ffmpeg
@ -109,7 +123,7 @@ def _get_working_mock_ffmpeg():
ffmpeg.open = AsyncMock(return_value=True)
ffmpeg.close = AsyncMock(return_value=True)
ffmpeg.kill = AsyncMock(return_value=True)
ffmpeg.get_reader = AsyncMock()
ffmpeg.get_reader = _mock_reader()
return ffmpeg
@ -120,7 +134,7 @@ def _get_failing_mock_ffmpeg():
ffmpeg.open = AsyncMock(return_value=False)
ffmpeg.close = AsyncMock(side_effect=OSError)
ffmpeg.kill = AsyncMock(side_effect=OSError)
ffmpeg.get_reader = AsyncMock()
ffmpeg.get_reader = _mock_reader()
return ffmpeg