Improve sonos test synchronization (#114468)

pull/114764/head
J. Nick Koston 2024-03-30 06:34:47 -10:00 committed by Paulus Schoutsen
parent f2edc15687
commit bdf51553ef
2 changed files with 38 additions and 9 deletions

View File

@ -1,16 +1,20 @@
"""Configuration for Sonos tests."""
import asyncio
from collections.abc import Callable
from copy import copy
from ipaddress import ip_address
from unittest.mock import AsyncMock, MagicMock, Mock, patch
import pytest
from soco import SoCo
from soco.events_base import Event as SonosEvent
from homeassistant.components import ssdp, zeroconf
from homeassistant.components.media_player import DOMAIN as MP_DOMAIN
from homeassistant.components.sonos import DOMAIN
from homeassistant.const import CONF_HOSTS
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry, load_fixture
@ -30,6 +34,31 @@ class SonosMockSubscribe:
"""Initialize the mock subscriber."""
self.event_listener = SonosMockEventListener(ip_address)
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:
"""Unsubscribe mock."""
@ -456,14 +485,14 @@ def zgs_discovery_fixture():
@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."""
variables = {"ZoneGroupState": zgs_discovery}
async def _wrapper():
event = SonosMockEvent(soco, soco.zoneGroupTopology, variables)
subscription = soco.zoneGroupTopology.subscribe.return_value
sub_callback = subscription.callback
subscription: SonosMockSubscribe = soco.zoneGroupTopology.subscribe.return_value
sub_callback = await subscription.wait_for_callback_to_be_set()
sub_callback(event)
await hass.async_block_till_done()

View File

@ -2,6 +2,8 @@
from unittest.mock import Mock
from soco import SoCo
from homeassistant.components.sonos.const import (
DOMAIN,
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.util import dt as dt_util
from .conftest import SonosMockEvent
from .conftest import SonosMockEvent, SonosMockSubscribe
from tests.common import MockConfigEntry, async_fire_time_changed
async def test_subscription_repair_issues(
hass: HomeAssistant, config_entry: MockConfigEntry, soco, zgs_discovery
hass: HomeAssistant, config_entry: MockConfigEntry, soco: SoCo, zgs_discovery
) -> None:
"""Test repair issues handling for failed subscriptions."""
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))
config_entry.add_to_hass(hass)
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
sub_callback = subscription.callback
sub_callback = await subscription.wait_for_callback_to_be_set()
async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL)
await hass.async_block_till_done(wait_background_tasks=True)
assert issue_registry.async_get_issue(DOMAIN, SUB_FAIL_ISSUE_ID)