Improve sonos test synchronization (#114468)
This commit is contained in:
parent
3e99afdd54
commit
d63adb6350
2 changed files with 38 additions and 9 deletions
tests/components/sonos
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Add table
Reference in a new issue