Improve sonos test synchronization ()

This commit is contained in:
J. Nick Koston 2024-03-30 06:34:47 -10:00 committed by GitHub
parent 3e99afdd54
commit d63adb6350
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 38 additions and 9 deletions
tests/components/sonos

View file

@ -1,16 +1,20 @@
"""Configuration for Sonos tests.""" """Configuration for Sonos tests."""
import asyncio
from collections.abc import Callable
from copy import copy from copy import copy
from ipaddress import ip_address from ipaddress import ip_address
from unittest.mock import AsyncMock, MagicMock, Mock, patch from unittest.mock import AsyncMock, MagicMock, Mock, patch
import pytest import pytest
from soco import SoCo from soco import SoCo
from soco.events_base import Event as SonosEvent
from homeassistant.components import ssdp, zeroconf from homeassistant.components import ssdp, zeroconf
from homeassistant.components.media_player import DOMAIN as MP_DOMAIN from homeassistant.components.media_player import DOMAIN as MP_DOMAIN
from homeassistant.components.sonos import DOMAIN from homeassistant.components.sonos import DOMAIN
from homeassistant.const import CONF_HOSTS from homeassistant.const import CONF_HOSTS
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry, load_fixture from tests.common import MockConfigEntry, load_fixture
@ -30,6 +34,31 @@ class SonosMockSubscribe:
"""Initialize the mock subscriber.""" """Initialize the mock subscriber."""
self.event_listener = SonosMockEventListener(ip_address) self.event_listener = SonosMockEventListener(ip_address)
self.service = Mock() self.service = Mock()
self.callback_future: asyncio.Future[Callable[[SonosEvent], None]] = None
self._callback: Callable[[SonosEvent], None] | None = None
@property
def callback(self) -> Callable[[SonosEvent], None] | None:
"""Return the callback."""
return self._callback
@callback.setter
def callback(self, callback: Callable[[SonosEvent], None]) -> None:
"""Set the callback."""
self._callback = callback
future = self._get_callback_future()
if not future.done():
future.set_result(callback)
def _get_callback_future(self) -> asyncio.Future[Callable[[SonosEvent], None]]:
"""Get the callback future."""
if not self.callback_future:
self.callback_future = asyncio.get_running_loop().create_future()
return self.callback_future
async def wait_for_callback_to_be_set(self) -> Callable[[SonosEvent], None]:
"""Wait for the callback to be set."""
return await self._get_callback_future()
async def unsubscribe(self) -> None: async def unsubscribe(self) -> None:
"""Unsubscribe mock.""" """Unsubscribe mock."""
@ -456,14 +485,14 @@ def zgs_discovery_fixture():
@pytest.fixture(name="fire_zgs_event") @pytest.fixture(name="fire_zgs_event")
def zgs_event_fixture(hass, soco, zgs_discovery): def zgs_event_fixture(hass: HomeAssistant, soco: SoCo, zgs_discovery: str):
"""Create alarm_event fixture.""" """Create alarm_event fixture."""
variables = {"ZoneGroupState": zgs_discovery} variables = {"ZoneGroupState": zgs_discovery}
async def _wrapper(): async def _wrapper():
event = SonosMockEvent(soco, soco.zoneGroupTopology, variables) event = SonosMockEvent(soco, soco.zoneGroupTopology, variables)
subscription = soco.zoneGroupTopology.subscribe.return_value subscription: SonosMockSubscribe = soco.zoneGroupTopology.subscribe.return_value
sub_callback = subscription.callback sub_callback = await subscription.wait_for_callback_to_be_set()
sub_callback(event) sub_callback(event)
await hass.async_block_till_done() await hass.async_block_till_done()

View file

@ -2,6 +2,8 @@
from unittest.mock import Mock from unittest.mock import Mock
from soco import SoCo
from homeassistant.components.sonos.const import ( from homeassistant.components.sonos.const import (
DOMAIN, DOMAIN,
SCAN_INTERVAL, SCAN_INTERVAL,
@ -11,27 +13,25 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.issue_registry import async_get as async_get_issue_registry from homeassistant.helpers.issue_registry import async_get as async_get_issue_registry
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from .conftest import SonosMockEvent from .conftest import SonosMockEvent, SonosMockSubscribe
from tests.common import MockConfigEntry, async_fire_time_changed from tests.common import MockConfigEntry, async_fire_time_changed
async def test_subscription_repair_issues( async def test_subscription_repair_issues(
hass: HomeAssistant, config_entry: MockConfigEntry, soco, zgs_discovery hass: HomeAssistant, config_entry: MockConfigEntry, soco: SoCo, zgs_discovery
) -> None: ) -> None:
"""Test repair issues handling for failed subscriptions.""" """Test repair issues handling for failed subscriptions."""
issue_registry = async_get_issue_registry(hass) issue_registry = async_get_issue_registry(hass)
subscription = soco.zoneGroupTopology.subscribe.return_value subscription: SonosMockSubscribe = soco.zoneGroupTopology.subscribe.return_value
subscription.event_listener = Mock(address=("192.168.4.2", 1400)) subscription.event_listener = Mock(address=("192.168.4.2", 1400))
config_entry.add_to_hass(hass) config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(config_entry.entry_id) assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
await hass.async_block_till_done()
# Ensure an issue is registered on subscription failure # Ensure an issue is registered on subscription failure
sub_callback = subscription.callback sub_callback = await subscription.wait_for_callback_to_be_set()
async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL) async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL)
await hass.async_block_till_done(wait_background_tasks=True) await hass.async_block_till_done(wait_background_tasks=True)
assert issue_registry.async_get_issue(DOMAIN, SUB_FAIL_ISSUE_ID) assert issue_registry.async_get_issue(DOMAIN, SUB_FAIL_ISSUE_ID)