mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Fix regression in nest event media player with multiple devices (#61064)
This commit is contained in:
parent
4144699814
commit
5bd1139867
@ -4,7 +4,7 @@
|
|||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"dependencies": ["ffmpeg", "http", "media_source"],
|
"dependencies": ["ffmpeg", "http", "media_source"],
|
||||||
"documentation": "https://www.home-assistant.io/integrations/nest",
|
"documentation": "https://www.home-assistant.io/integrations/nest",
|
||||||
"requirements": ["python-nest==4.1.0", "google-nest-sdm==0.4.2"],
|
"requirements": ["python-nest==4.1.0", "google-nest-sdm==0.4.3"],
|
||||||
"codeowners": ["@allenporter"],
|
"codeowners": ["@allenporter"],
|
||||||
"quality_scale": "platinum",
|
"quality_scale": "platinum",
|
||||||
"dhcp": [
|
"dhcp": [
|
||||||
|
@ -738,7 +738,7 @@ google-cloud-pubsub==2.1.0
|
|||||||
google-cloud-texttospeech==0.4.0
|
google-cloud-texttospeech==0.4.0
|
||||||
|
|
||||||
# homeassistant.components.nest
|
# homeassistant.components.nest
|
||||||
google-nest-sdm==0.4.2
|
google-nest-sdm==0.4.3
|
||||||
|
|
||||||
# homeassistant.components.google_travel_time
|
# homeassistant.components.google_travel_time
|
||||||
googlemaps==2.5.1
|
googlemaps==2.5.1
|
||||||
|
@ -461,7 +461,7 @@ google-api-python-client==1.6.4
|
|||||||
google-cloud-pubsub==2.1.0
|
google-cloud-pubsub==2.1.0
|
||||||
|
|
||||||
# homeassistant.components.nest
|
# homeassistant.components.nest
|
||||||
google-nest-sdm==0.4.2
|
google-nest-sdm==0.4.3
|
||||||
|
|
||||||
# homeassistant.components.google_travel_time
|
# homeassistant.components.google_travel_time
|
||||||
googlemaps==2.5.1
|
googlemaps==2.5.1
|
||||||
|
@ -53,31 +53,12 @@ def create_config_entry(hass, token_expiration_time=None) -> MockConfigEntry:
|
|||||||
return config_entry
|
return config_entry
|
||||||
|
|
||||||
|
|
||||||
class FakeDeviceManager(DeviceManager):
|
|
||||||
"""Fake DeviceManager that can supply a list of devices and structures."""
|
|
||||||
|
|
||||||
def __init__(self, devices: dict, structures: dict):
|
|
||||||
"""Initialize FakeDeviceManager."""
|
|
||||||
super().__init__()
|
|
||||||
self._devices = devices
|
|
||||||
|
|
||||||
@property
|
|
||||||
def structures(self) -> dict:
|
|
||||||
"""Override structures with fake result."""
|
|
||||||
return self._structures
|
|
||||||
|
|
||||||
@property
|
|
||||||
def devices(self) -> dict:
|
|
||||||
"""Override devices with fake result."""
|
|
||||||
return self._devices
|
|
||||||
|
|
||||||
|
|
||||||
class FakeSubscriber(GoogleNestSubscriber):
|
class FakeSubscriber(GoogleNestSubscriber):
|
||||||
"""Fake subscriber that supplies a FakeDeviceManager."""
|
"""Fake subscriber that supplies a FakeDeviceManager."""
|
||||||
|
|
||||||
def __init__(self, device_manager: FakeDeviceManager):
|
def __init__(self):
|
||||||
"""Initialize Fake Subscriber."""
|
"""Initialize Fake Subscriber."""
|
||||||
self._device_manager = device_manager
|
self._device_manager = DeviceManager()
|
||||||
|
|
||||||
def set_update_callback(self, callback: Callable[[EventMessage], Awaitable[None]]):
|
def set_update_callback(self, callback: Callable[[EventMessage], Awaitable[None]]):
|
||||||
"""Capture the callback set by Home Assistant."""
|
"""Capture the callback set by Home Assistant."""
|
||||||
@ -121,8 +102,14 @@ async def async_setup_sdm_platform(
|
|||||||
"""Set up the platform and prerequisites."""
|
"""Set up the platform and prerequisites."""
|
||||||
if with_config:
|
if with_config:
|
||||||
create_config_entry(hass)
|
create_config_entry(hass)
|
||||||
device_manager = FakeDeviceManager(devices=devices, structures=structures)
|
subscriber = FakeSubscriber()
|
||||||
subscriber = FakeSubscriber(device_manager)
|
device_manager = await subscriber.async_get_device_manager()
|
||||||
|
if devices:
|
||||||
|
for device in devices.values():
|
||||||
|
device_manager.add_device(device)
|
||||||
|
if structures:
|
||||||
|
for structure in structures.values():
|
||||||
|
device_manager.add_structure(structure)
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.helpers.config_entry_oauth2_flow.async_get_config_entry_implementation"
|
"homeassistant.helpers.config_entry_oauth2_flow.async_get_config_entry_implementation"
|
||||||
), patch("homeassistant.components.nest.PLATFORMS", [platform]), patch(
|
), patch("homeassistant.components.nest.PLATFORMS", [platform]), patch(
|
||||||
@ -131,4 +118,7 @@ async def async_setup_sdm_platform(
|
|||||||
):
|
):
|
||||||
assert await async_setup_component(hass, DOMAIN, CONFIG)
|
assert await async_setup_component(hass, DOMAIN, CONFIG)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
# Disabled to reduce setup burden, and enabled manually by tests that
|
||||||
|
# need to exercise this
|
||||||
|
subscriber.cache_policy.fetch = False
|
||||||
return subscriber
|
return subscriber
|
||||||
|
@ -17,7 +17,7 @@ from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import config_entry_oauth2_flow
|
from homeassistant.helpers import config_entry_oauth2_flow
|
||||||
|
|
||||||
from .common import FakeDeviceManager, FakeSubscriber, MockConfigEntry
|
from .common import FakeSubscriber, MockConfigEntry
|
||||||
|
|
||||||
CLIENT_ID = "1234"
|
CLIENT_ID = "1234"
|
||||||
CLIENT_SECRET = "5678"
|
CLIENT_SECRET = "5678"
|
||||||
@ -43,15 +43,9 @@ APP_REDIRECT_URL = "urn:ietf:wg:oauth:2.0:oob"
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def device_manager() -> FakeDeviceManager:
|
def subscriber() -> FakeSubscriber:
|
||||||
"""Create FakeDeviceManager."""
|
|
||||||
return FakeDeviceManager(devices={}, structures={})
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def subscriber(device_manager: FakeDeviceManager) -> FakeSubscriber:
|
|
||||||
"""Create FakeSubscriber."""
|
"""Create FakeSubscriber."""
|
||||||
return FakeSubscriber(device_manager)
|
return FakeSubscriber()
|
||||||
|
|
||||||
|
|
||||||
def get_config_entry(hass):
|
def get_config_entry(hass):
|
||||||
|
@ -81,7 +81,7 @@ async def async_setup_devices(hass, auth, device_type, traits={}, events=[]):
|
|||||||
return subscriber
|
return subscriber
|
||||||
|
|
||||||
|
|
||||||
def create_event(event_id, event_type, timestamp=None):
|
def create_event(event_id, event_type, timestamp=None, device_id=None):
|
||||||
"""Create an EventMessage for a single event type."""
|
"""Create an EventMessage for a single event type."""
|
||||||
if not timestamp:
|
if not timestamp:
|
||||||
timestamp = dt_util.now()
|
timestamp = dt_util.now()
|
||||||
@ -91,17 +91,19 @@ def create_event(event_id, event_type, timestamp=None):
|
|||||||
"eventId": event_id,
|
"eventId": event_id,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return create_event_message(event_id, event_data, timestamp)
|
return create_event_message(event_id, event_data, timestamp, device_id=device_id)
|
||||||
|
|
||||||
|
|
||||||
def create_event_message(event_id, event_data, timestamp):
|
def create_event_message(event_id, event_data, timestamp, device_id=None):
|
||||||
"""Create an EventMessage for a single event type."""
|
"""Create an EventMessage for a single event type."""
|
||||||
|
if device_id is None:
|
||||||
|
device_id = DEVICE_ID
|
||||||
return EventMessage(
|
return EventMessage(
|
||||||
{
|
{
|
||||||
"eventId": f"{event_id}-{timestamp}",
|
"eventId": f"{event_id}-{timestamp}",
|
||||||
"timestamp": timestamp.isoformat(timespec="seconds"),
|
"timestamp": timestamp.isoformat(timespec="seconds"),
|
||||||
"resourceUpdate": {
|
"resourceUpdate": {
|
||||||
"name": DEVICE_ID,
|
"name": device_id,
|
||||||
"events": event_data,
|
"events": event_data,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -568,3 +570,75 @@ async def test_media_permission_unauthorized(hass, auth, hass_client, hass_admin
|
|||||||
assert response.status == HTTPStatus.UNAUTHORIZED, (
|
assert response.status == HTTPStatus.UNAUTHORIZED, (
|
||||||
"Response not matched: %s" % response
|
"Response not matched: %s" % response
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_multiple_devices(hass, auth, hass_client):
|
||||||
|
"""Test events received for multiple devices."""
|
||||||
|
device_id1 = f"{DEVICE_ID}-1"
|
||||||
|
device_id2 = f"{DEVICE_ID}-2"
|
||||||
|
|
||||||
|
devices = {
|
||||||
|
device_id1: Device.MakeDevice(
|
||||||
|
{
|
||||||
|
"name": device_id1,
|
||||||
|
"type": CAMERA_DEVICE_TYPE,
|
||||||
|
"traits": CAMERA_TRAITS,
|
||||||
|
},
|
||||||
|
auth=auth,
|
||||||
|
),
|
||||||
|
device_id2: Device.MakeDevice(
|
||||||
|
{
|
||||||
|
"name": device_id2,
|
||||||
|
"type": CAMERA_DEVICE_TYPE,
|
||||||
|
"traits": CAMERA_TRAITS,
|
||||||
|
},
|
||||||
|
auth=auth,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
subscriber = await async_setup_sdm_platform(hass, PLATFORM, devices=devices)
|
||||||
|
|
||||||
|
device_registry = dr.async_get(hass)
|
||||||
|
device1 = device_registry.async_get_device({(DOMAIN, device_id1)})
|
||||||
|
assert device1
|
||||||
|
device2 = device_registry.async_get_device({(DOMAIN, device_id2)})
|
||||||
|
assert device2
|
||||||
|
|
||||||
|
# Very no events have been received yet
|
||||||
|
browse = await media_source.async_browse_media(
|
||||||
|
hass, f"{const.URI_SCHEME}{DOMAIN}/{device1.id}"
|
||||||
|
)
|
||||||
|
assert len(browse.children) == 0
|
||||||
|
browse = await media_source.async_browse_media(
|
||||||
|
hass, f"{const.URI_SCHEME}{DOMAIN}/{device2.id}"
|
||||||
|
)
|
||||||
|
assert len(browse.children) == 0
|
||||||
|
|
||||||
|
# Send events for device #1
|
||||||
|
for i in range(0, 5):
|
||||||
|
await subscriber.async_receive_event(
|
||||||
|
create_event(f"event-id-{i}", PERSON_EVENT, device_id=device_id1)
|
||||||
|
)
|
||||||
|
|
||||||
|
browse = await media_source.async_browse_media(
|
||||||
|
hass, f"{const.URI_SCHEME}{DOMAIN}/{device1.id}"
|
||||||
|
)
|
||||||
|
assert len(browse.children) == 5
|
||||||
|
browse = await media_source.async_browse_media(
|
||||||
|
hass, f"{const.URI_SCHEME}{DOMAIN}/{device2.id}"
|
||||||
|
)
|
||||||
|
assert len(browse.children) == 0
|
||||||
|
|
||||||
|
# Send events for device #2
|
||||||
|
for i in range(0, 3):
|
||||||
|
await subscriber.async_receive_event(
|
||||||
|
create_event(f"other-id-{i}", PERSON_EVENT, device_id=device_id2)
|
||||||
|
)
|
||||||
|
|
||||||
|
browse = await media_source.async_browse_media(
|
||||||
|
hass, f"{const.URI_SCHEME}{DOMAIN}/{device1.id}"
|
||||||
|
)
|
||||||
|
assert len(browse.children) == 5
|
||||||
|
browse = await media_source.async_browse_media(
|
||||||
|
hass, f"{const.URI_SCHEME}{DOMAIN}/{device2.id}"
|
||||||
|
)
|
||||||
|
assert len(browse.children) == 3
|
||||||
|
Loading…
x
Reference in New Issue
Block a user