Update more nest tests to use common fixtures (#73303)

Update nest tests to use fixtures
This commit is contained in:
Allen Porter 2022-06-09 22:14:43 -07:00 committed by GitHub
parent 15621bee3f
commit 7a5fa8eb58
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 357 additions and 447 deletions

View file

@ -5,7 +5,6 @@ import copy
from dataclasses import dataclass
import time
from typing import Any, Generator, TypeVar
from unittest.mock import patch
from google_nest_sdm.auth import AbstractAuth
from google_nest_sdm.device import Device
@ -16,7 +15,6 @@ from google_nest_sdm.google_nest_subscriber import GoogleNestSubscriber
from homeassistant.components.nest import DOMAIN
from homeassistant.components.nest.const import SDM_SCOPES
from homeassistant.setup import async_setup_component
from tests.common import MockConfigEntry
@ -198,29 +196,3 @@ class CreateDevice:
data.update(raw_data if raw_data else {})
data["traits"].update(raw_traits if raw_traits else {})
self.device_manager.add_device(Device.MakeDevice(data, auth=self.auth))
async def async_setup_sdm_platform(
hass,
platform,
devices={},
):
"""Set up the platform and prerequisites."""
create_config_entry().add_to_hass(hass)
subscriber = FakeSubscriber()
device_manager = await subscriber.async_get_device_manager()
if devices:
for device in devices.values():
device_manager.add_device(device)
platforms = []
if platform:
platforms = [platform]
with patch(
"homeassistant.helpers.config_entry_oauth2_flow.async_get_config_entry_implementation"
), patch("homeassistant.components.nest.PLATFORMS", platforms), patch(
"homeassistant.components.nest.api.GoogleNestSubscriber",
return_value=subscriber,
):
assert await async_setup_component(hass, DOMAIN, CONFIG)
await hass.async_block_till_done()
return subscriber

View file

@ -1,5 +1,4 @@
"""The tests for Nest device triggers."""
from google_nest_sdm.device import Device
from google_nest_sdm.event import EventMessage
import pytest
@ -10,11 +9,12 @@ from homeassistant.components.device_automation.exceptions import (
)
from homeassistant.components.nest import DOMAIN
from homeassistant.components.nest.events import NEST_EVENT
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.setup import async_setup_component
from homeassistant.util.dt import utcnow
from .common import async_setup_sdm_platform
from .common import DEVICE_ID, CreateDevice, FakeSubscriber, PlatformSetup
from tests.common import (
assert_lists_same,
@ -22,11 +22,16 @@ from tests.common import (
async_mock_service,
)
DEVICE_ID = "some-device-id"
DEVICE_NAME = "My Camera"
DATA_MESSAGE = {"message": "service-called"}
@pytest.fixture
def platforms() -> list[str]:
"""Fixture to setup the platforms to test."""
return ["camera"]
def make_camera(device_id, name=DEVICE_NAME, traits={}):
"""Create a nest camera."""
traits = traits.copy()
@ -45,21 +50,11 @@ def make_camera(device_id, name=DEVICE_NAME, traits={}):
},
}
)
return Device.MakeDevice(
{
"name": device_id,
"type": "sdm.devices.types.CAMERA",
"traits": traits,
},
auth=None,
)
async def async_setup_camera(hass, devices=None):
"""Set up the platform and prerequisites for testing available triggers."""
if not devices:
devices = {DEVICE_ID: make_camera(device_id=DEVICE_ID)}
return await async_setup_sdm_platform(hass, "camera", devices)
return {
"name": device_id,
"type": "sdm.devices.types.CAMERA",
"traits": traits,
}
async def setup_automation(hass, device_id, trigger_type):
@ -92,16 +87,20 @@ def calls(hass):
return async_mock_service(hass, "test", "automation")
async def test_get_triggers(hass):
async def test_get_triggers(
hass: HomeAssistant, create_device: CreateDevice, setup_platform: PlatformSetup
) -> None:
"""Test we get the expected triggers from a nest."""
camera = make_camera(
device_id=DEVICE_ID,
traits={
"sdm.devices.traits.CameraMotion": {},
"sdm.devices.traits.CameraPerson": {},
},
create_device.create(
raw_data=make_camera(
device_id=DEVICE_ID,
traits={
"sdm.devices.traits.CameraMotion": {},
"sdm.devices.traits.CameraPerson": {},
},
)
)
await async_setup_camera(hass, {DEVICE_ID: camera})
await setup_platform()
device_registry = dr.async_get(hass)
device_entry = device_registry.async_get_device({("nest", DEVICE_ID)})
@ -128,23 +127,29 @@ async def test_get_triggers(hass):
assert_lists_same(triggers, expected_triggers)
async def test_multiple_devices(hass):
async def test_multiple_devices(
hass: HomeAssistant, create_device: CreateDevice, setup_platform: PlatformSetup
) -> None:
"""Test we get the expected triggers from a nest."""
camera1 = make_camera(
device_id="device-id-1",
name="Camera 1",
traits={
"sdm.devices.traits.CameraSound": {},
},
create_device.create(
raw_data=make_camera(
device_id="device-id-1",
name="Camera 1",
traits={
"sdm.devices.traits.CameraSound": {},
},
)
)
camera2 = make_camera(
device_id="device-id-2",
name="Camera 2",
traits={
"sdm.devices.traits.DoorbellChime": {},
},
create_device.create(
raw_data=make_camera(
device_id="device-id-2",
name="Camera 2",
traits={
"sdm.devices.traits.DoorbellChime": {},
},
)
)
await async_setup_camera(hass, {"device-id-1": camera1, "device-id-2": camera2})
await setup_platform()
registry = er.async_get(hass)
entry1 = registry.async_get("camera.camera_1")
@ -177,16 +182,20 @@ async def test_multiple_devices(hass):
}
async def test_triggers_for_invalid_device_id(hass):
async def test_triggers_for_invalid_device_id(
hass: HomeAssistant, create_device: CreateDevice, setup_platform: PlatformSetup
) -> None:
"""Get triggers for a device not found in the API."""
camera = make_camera(
device_id=DEVICE_ID,
traits={
"sdm.devices.traits.CameraMotion": {},
"sdm.devices.traits.CameraPerson": {},
},
create_device.create(
raw_data=make_camera(
device_id=DEVICE_ID,
traits={
"sdm.devices.traits.CameraMotion": {},
"sdm.devices.traits.CameraPerson": {},
},
)
)
await async_setup_camera(hass, {DEVICE_ID: camera})
await setup_platform()
device_registry = dr.async_get(hass)
device_entry = device_registry.async_get_device({("nest", DEVICE_ID)})
@ -207,14 +216,16 @@ async def test_triggers_for_invalid_device_id(hass):
)
async def test_no_triggers(hass):
async def test_no_triggers(
hass: HomeAssistant, create_device: CreateDevice, setup_platform: PlatformSetup
) -> None:
"""Test we get the expected triggers from a nest."""
camera = make_camera(device_id=DEVICE_ID, traits={})
await async_setup_camera(hass, {DEVICE_ID: camera})
create_device.create(raw_data=make_camera(device_id=DEVICE_ID, traits={}))
await setup_platform()
registry = er.async_get(hass)
entry = registry.async_get("camera.my_camera")
assert entry.unique_id == "some-device-id-camera"
assert entry.unique_id == f"{DEVICE_ID}-camera"
triggers = await async_get_device_automations(
hass, DeviceAutomationType.TRIGGER, entry.device_id
@ -294,15 +305,23 @@ async def test_trigger_for_wrong_event_type(hass, calls):
assert len(calls) == 0
async def test_subscriber_automation(hass, calls):
async def test_subscriber_automation(
hass: HomeAssistant,
calls: list,
create_device: CreateDevice,
setup_platform: PlatformSetup,
subscriber: FakeSubscriber,
) -> None:
"""Test end to end subscriber triggers automation."""
camera = make_camera(
device_id=DEVICE_ID,
traits={
"sdm.devices.traits.CameraMotion": {},
},
create_device.create(
raw_data=make_camera(
device_id=DEVICE_ID,
traits={
"sdm.devices.traits.CameraMotion": {},
},
)
)
subscriber = await async_setup_camera(hass, {DEVICE_ID: camera})
await setup_platform()
device_registry = dr.async_get(hass)
device_entry = device_registry.async_get_device({("nest", DEVICE_ID)})

View file

@ -13,11 +13,12 @@ from unittest.mock import patch
from google_nest_sdm.device import Device
from google_nest_sdm.event import EventMessage
import pytest
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.util.dt import utcnow
from .common import async_setup_sdm_platform
from .common import CreateDevice
from tests.common import async_capture_events
@ -31,26 +32,43 @@ EVENT_ID = "FWWVQVUdGNUlTU2V4MGV2aTNXV..."
EVENT_KEYS = {"device_id", "type", "timestamp", "zones"}
@pytest.fixture
def platforms() -> list[str]:
"""Fixture for platforms to setup."""
return [PLATFORM]
@pytest.fixture
def device_type() -> str:
"""Fixture for the type of device under test."""
return "sdm.devices.types.DOORBELL"
@pytest.fixture
def device_traits() -> list[str]:
"""Fixture for the present traits of the device under test."""
return ["sdm.devices.traits.DoorbellChime"]
@pytest.fixture(autouse=True)
def device(
device_type: str, device_traits: dict[str, Any], create_device: CreateDevice
) -> None:
"""Fixture to create a device under test."""
return create_device.create(
raw_data={
"name": DEVICE_ID,
"type": device_type,
"traits": create_device_traits(device_traits),
}
)
def event_view(d: Mapping[str, Any]) -> Mapping[str, Any]:
"""View of an event with relevant keys for testing."""
return {key: value for key, value in d.items() if key in EVENT_KEYS}
async def async_setup_devices(hass, device_type, traits={}, auth=None):
"""Set up the platform and prerequisites."""
devices = {
DEVICE_ID: Device.MakeDevice(
{
"name": DEVICE_ID,
"type": device_type,
"traits": traits,
},
auth=auth,
),
}
return await async_setup_sdm_platform(hass, PLATFORM, devices=devices)
def create_device_traits(event_traits=[]):
"""Create fake traits for a device."""
result = {
@ -98,15 +116,45 @@ def create_events(events, device_id=DEVICE_ID, timestamp=None):
)
async def test_doorbell_chime_event(hass, auth):
@pytest.mark.parametrize(
"device_type,device_traits,event_trait,expected_model,expected_type",
[
(
"sdm.devices.types.DOORBELL",
["sdm.devices.traits.DoorbellChime"],
"sdm.devices.events.DoorbellChime.Chime",
"Doorbell",
"doorbell_chime",
),
(
"sdm.devices.types.CAMERA",
["sdm.devices.traits.CameraMotion"],
"sdm.devices.events.CameraMotion.Motion",
"Camera",
"camera_motion",
),
(
"sdm.devices.types.CAMERA",
["sdm.devices.traits.CameraPerson"],
"sdm.devices.events.CameraPerson.Person",
"Camera",
"camera_person",
),
(
"sdm.devices.types.CAMERA",
["sdm.devices.traits.CameraSound"],
"sdm.devices.events.CameraSound.Sound",
"Camera",
"camera_sound",
),
],
)
async def test_event(
hass, auth, setup_platform, subscriber, event_trait, expected_model, expected_type
):
"""Test a pubsub message for a doorbell event."""
events = async_capture_events(hass, NEST_EVENT)
subscriber = await async_setup_devices(
hass,
"sdm.devices.types.DOORBELL",
create_device_traits(["sdm.devices.traits.DoorbellChime"]),
auth,
)
await setup_platform()
registry = er.async_get(hass)
entry = registry.async_get("camera.front")
@ -118,115 +166,32 @@ async def test_doorbell_chime_event(hass, auth):
device_registry = dr.async_get(hass)
device = device_registry.async_get(entry.device_id)
assert device.name == "Front"
assert device.model == "Doorbell"
assert device.model == expected_model
assert device.identifiers == {("nest", DEVICE_ID)}
timestamp = utcnow()
await subscriber.async_receive_event(
create_event("sdm.devices.events.DoorbellChime.Chime", timestamp=timestamp)
)
await subscriber.async_receive_event(create_event(event_trait, timestamp=timestamp))
await hass.async_block_till_done()
event_time = timestamp.replace(microsecond=0)
assert len(events) == 1
assert event_view(events[0].data) == {
"device_id": entry.device_id,
"type": "doorbell_chime",
"type": expected_type,
"timestamp": event_time,
}
async def test_camera_motion_event(hass):
"""Test a pubsub message for a camera motion event."""
events = async_capture_events(hass, NEST_EVENT)
subscriber = await async_setup_devices(
hass,
"sdm.devices.types.CAMERA",
create_device_traits(["sdm.devices.traits.CameraMotion"]),
)
registry = er.async_get(hass)
entry = registry.async_get("camera.front")
assert entry is not None
timestamp = utcnow()
await subscriber.async_receive_event(
create_event("sdm.devices.events.CameraMotion.Motion", timestamp=timestamp)
)
await hass.async_block_till_done()
event_time = timestamp.replace(microsecond=0)
assert len(events) == 1
assert event_view(events[0].data) == {
"device_id": entry.device_id,
"type": "camera_motion",
"timestamp": event_time,
}
async def test_camera_sound_event(hass):
"""Test a pubsub message for a camera sound event."""
events = async_capture_events(hass, NEST_EVENT)
subscriber = await async_setup_devices(
hass,
"sdm.devices.types.CAMERA",
create_device_traits(["sdm.devices.traits.CameraSound"]),
)
registry = er.async_get(hass)
entry = registry.async_get("camera.front")
assert entry is not None
timestamp = utcnow()
await subscriber.async_receive_event(
create_event("sdm.devices.events.CameraSound.Sound", timestamp=timestamp)
)
await hass.async_block_till_done()
event_time = timestamp.replace(microsecond=0)
assert len(events) == 1
assert event_view(events[0].data) == {
"device_id": entry.device_id,
"type": "camera_sound",
"timestamp": event_time,
}
async def test_camera_person_event(hass):
@pytest.mark.parametrize(
"device_traits",
[
["sdm.devices.traits.CameraMotion", "sdm.devices.traits.CameraPerson"],
],
)
async def test_camera_multiple_event(hass, subscriber, setup_platform):
"""Test a pubsub message for a camera person event."""
events = async_capture_events(hass, NEST_EVENT)
subscriber = await async_setup_devices(
hass,
"sdm.devices.types.DOORBELL",
create_device_traits(["sdm.devices.traits.CameraPerson"]),
)
registry = er.async_get(hass)
entry = registry.async_get("camera.front")
assert entry is not None
timestamp = utcnow()
await subscriber.async_receive_event(
create_event("sdm.devices.events.CameraPerson.Person", timestamp=timestamp)
)
await hass.async_block_till_done()
event_time = timestamp.replace(microsecond=0)
assert len(events) == 1
assert event_view(events[0].data) == {
"device_id": entry.device_id,
"type": "camera_person",
"timestamp": event_time,
}
async def test_camera_multiple_event(hass):
"""Test a pubsub message for a camera person event."""
events = async_capture_events(hass, NEST_EVENT)
subscriber = await async_setup_devices(
hass,
"sdm.devices.types.DOORBELL",
create_device_traits(
["sdm.devices.traits.CameraMotion", "sdm.devices.traits.CameraPerson"]
),
)
await setup_platform()
registry = er.async_get(hass)
entry = registry.async_get("camera.front")
assert entry is not None
@ -260,28 +225,20 @@ async def test_camera_multiple_event(hass):
}
async def test_unknown_event(hass):
async def test_unknown_event(hass, subscriber, setup_platform):
"""Test a pubsub message for an unknown event type."""
events = async_capture_events(hass, NEST_EVENT)
subscriber = await async_setup_devices(
hass,
"sdm.devices.types.DOORBELL",
create_device_traits(["sdm.devices.traits.DoorbellChime"]),
)
await setup_platform()
await subscriber.async_receive_event(create_event("some-event-id"))
await hass.async_block_till_done()
assert len(events) == 0
async def test_unknown_device_id(hass):
async def test_unknown_device_id(hass, subscriber, setup_platform):
"""Test a pubsub message for an unknown event type."""
events = async_capture_events(hass, NEST_EVENT)
subscriber = await async_setup_devices(
hass,
"sdm.devices.types.DOORBELL",
create_device_traits(["sdm.devices.traits.DoorbellChime"]),
)
await setup_platform()
await subscriber.async_receive_event(
create_event("sdm.devices.events.DoorbellChime.Chime", "invalid-device-id")
)
@ -290,14 +247,10 @@ async def test_unknown_device_id(hass):
assert len(events) == 0
async def test_event_message_without_device_event(hass):
async def test_event_message_without_device_event(hass, subscriber, setup_platform):
"""Test a pubsub message for an unknown event type."""
events = async_capture_events(hass, NEST_EVENT)
subscriber = await async_setup_devices(
hass,
"sdm.devices.types.DOORBELL",
create_device_traits(["sdm.devices.traits.DoorbellChime"]),
)
await setup_platform()
timestamp = utcnow()
event = EventMessage(
{
@ -312,20 +265,16 @@ async def test_event_message_without_device_event(hass):
assert len(events) == 0
async def test_doorbell_event_thread(hass, auth):
@pytest.mark.parametrize(
"device_traits",
[
["sdm.devices.traits.CameraClipPreview", "sdm.devices.traits.CameraPerson"],
],
)
async def test_doorbell_event_thread(hass, subscriber, setup_platform):
"""Test a series of pubsub messages in the same thread."""
events = async_capture_events(hass, NEST_EVENT)
subscriber = await async_setup_devices(
hass,
"sdm.devices.types.DOORBELL",
create_device_traits(
[
"sdm.devices.traits.CameraClipPreview",
"sdm.devices.traits.CameraPerson",
]
),
auth,
)
await setup_platform()
registry = er.async_get(hass)
entry = registry.async_get("camera.front")
assert entry is not None
@ -381,21 +330,20 @@ async def test_doorbell_event_thread(hass, auth):
}
async def test_doorbell_event_session_update(hass, auth):
@pytest.mark.parametrize(
"device_traits",
[
[
"sdm.devices.traits.CameraClipPreview",
"sdm.devices.traits.CameraPerson",
"sdm.devices.traits.CameraMotion",
],
],
)
async def test_doorbell_event_session_update(hass, subscriber, setup_platform):
"""Test a pubsub message with updates to an existing session."""
events = async_capture_events(hass, NEST_EVENT)
subscriber = await async_setup_devices(
hass,
"sdm.devices.types.DOORBELL",
create_device_traits(
[
"sdm.devices.traits.CameraClipPreview",
"sdm.devices.traits.CameraPerson",
"sdm.devices.traits.CameraMotion",
]
),
auth,
)
await setup_platform()
registry = er.async_get(hass)
entry = registry.async_get("camera.front")
assert entry is not None
@ -454,14 +402,10 @@ async def test_doorbell_event_session_update(hass, auth):
}
async def test_structure_update_event(hass):
async def test_structure_update_event(hass, subscriber, setup_platform):
"""Test a pubsub message for a new device being added."""
events = async_capture_events(hass, NEST_EVENT)
subscriber = await async_setup_devices(
hass,
"sdm.devices.types.DOORBELL",
create_device_traits(["sdm.devices.traits.DoorbellChime"]),
)
await setup_platform()
# Entity for first device is registered
registry = er.async_get(hass)
@ -516,14 +460,16 @@ async def test_structure_update_event(hass):
assert not registry.async_get("camera.back")
async def test_event_zones(hass):
@pytest.mark.parametrize(
"device_traits",
[
["sdm.devices.traits.CameraMotion"],
],
)
async def test_event_zones(hass, subscriber, setup_platform):
"""Test events published with zone information."""
events = async_capture_events(hass, NEST_EVENT)
subscriber = await async_setup_devices(
hass,
"sdm.devices.types.DOORBELL",
create_device_traits(["sdm.devices.traits.CameraMotion"]),
)
await setup_platform()
registry = er.async_get(hass)
entry = registry.async_get("camera.front")
assert entry is not None

View file

@ -8,11 +8,11 @@ from collections.abc import Generator
import datetime
from http import HTTPStatus
import io
from typing import Any
from unittest.mock import patch
import aiohttp
import av
from google_nest_sdm.device import Device
from google_nest_sdm.event import EventMessage
import numpy as np
import pytest
@ -27,17 +27,11 @@ from homeassistant.helpers.template import DATE_STR_FORMAT
from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util
from .common import (
CONFIG,
FakeSubscriber,
async_setup_sdm_platform,
create_config_entry,
)
from .common import DEVICE_ID, CreateDevice, FakeSubscriber
from tests.common import async_capture_events
DOMAIN = "nest"
DEVICE_ID = "example/api/device/id"
DEVICE_NAME = "Front"
PLATFORM = "camera"
NEST_EVENT = "nest_event"
@ -90,10 +84,42 @@ def frame_image_data(frame_i, total_frames):
return img
@pytest.fixture
def platforms() -> list[str]:
"""Fixture for platforms to setup."""
return [PLATFORM]
@pytest.fixture(autouse=True)
async def setup_media_source(hass) -> None:
"""Set up media source."""
assert await async_setup_component(hass, "media_source", {})
async def setup_components(hass) -> None:
"""Fixture to initialize the integration."""
await async_setup_component(hass, "media_source", {})
@pytest.fixture
def device_type() -> str:
"""Fixture for the type of device under test."""
return CAMERA_DEVICE_TYPE
@pytest.fixture
def device_traits() -> dict[str, Any]:
"""Fixture for the present traits of the device under test."""
return CAMERA_TRAITS
@pytest.fixture(autouse=True)
def device(
device_type: str, device_traits: dict[str, Any], create_device: CreateDevice
) -> None:
"""Fixture to create a device under test."""
return create_device.create(
raw_data={
"name": DEVICE_ID,
"type": device_type,
"traits": device_traits,
}
)
@pytest.fixture
@ -128,22 +154,23 @@ def mp4() -> io.BytesIO:
return output
async def async_setup_devices(hass, auth, device_type, traits={}, events=[]):
"""Set up the platform and prerequisites."""
devices = {
DEVICE_ID: Device.MakeDevice(
{
"name": DEVICE_ID,
"type": device_type,
"traits": traits,
},
auth=auth,
),
}
subscriber = await async_setup_sdm_platform(hass, PLATFORM, devices=devices)
# Enable feature for fetching media
@pytest.fixture(autouse=True)
def enable_prefetch(subscriber: FakeSubscriber) -> None:
"""Fixture to enable media fetching for tests to exercise."""
subscriber.cache_policy.fetch = True
return subscriber
@pytest.fixture
def cache_size() -> int:
"""Fixture for overrideing cache size."""
return 100
@pytest.fixture(autouse=True)
def apply_cache_size(cache_size):
"""Fixture for patching the cache size."""
with patch("homeassistant.components.nest.EVENT_MEDIA_CACHE_SIZE", new=cache_size):
yield
def create_event(
@ -194,17 +221,20 @@ def create_battery_event_data(
}
async def test_no_eligible_devices(hass, auth):
@pytest.mark.parametrize(
"device_type,device_traits",
[
(
"sdm.devices.types.THERMOSTAT",
{
"sdm.devices.traits.Temperature": {},
},
)
],
)
async def test_no_eligible_devices(hass, setup_platform):
"""Test a media source with no eligible camera devices."""
await async_setup_devices(
hass,
auth,
"sdm.devices.types.THERMOSTAT",
{
"sdm.devices.traits.Temperature": {},
},
)
await setup_platform()
browse = await media_source.async_browse_media(hass, f"{const.URI_SCHEME}{DOMAIN}")
assert browse.domain == DOMAIN
assert browse.identifier == ""
@ -212,10 +242,10 @@ async def test_no_eligible_devices(hass, auth):
assert not browse.children
@pytest.mark.parametrize("traits", [CAMERA_TRAITS, BATTERY_CAMERA_TRAITS])
async def test_supported_device(hass, auth, traits):
@pytest.mark.parametrize("device_traits", [CAMERA_TRAITS, BATTERY_CAMERA_TRAITS])
async def test_supported_device(hass, setup_platform):
"""Test a media source with a supported camera."""
await async_setup_devices(hass, auth, CAMERA_DEVICE_TYPE, traits)
await setup_platform()
assert len(hass.states.async_all()) == 1
camera = hass.states.get("camera.front")
@ -245,14 +275,9 @@ async def test_supported_device(hass, auth, traits):
assert len(browse.children) == 0
async def test_integration_unloaded(hass, auth):
async def test_integration_unloaded(hass, auth, setup_platform):
"""Test the media player loads, but has no devices, when config unloaded."""
await async_setup_devices(
hass,
auth,
CAMERA_DEVICE_TYPE,
CAMERA_TRAITS,
)
await setup_platform()
browse = await media_source.async_browse_media(hass, f"{const.URI_SCHEME}{DOMAIN}")
assert browse.domain == DOMAIN
@ -276,11 +301,9 @@ async def test_integration_unloaded(hass, auth):
assert len(browse.children) == 0
async def test_camera_event(hass, auth, hass_client):
async def test_camera_event(hass, hass_client, subscriber, auth, setup_platform):
"""Test a media source and image created for an event."""
subscriber = await async_setup_devices(
hass, auth, CAMERA_DEVICE_TYPE, CAMERA_TRAITS
)
await setup_platform()
assert len(hass.states.async_all()) == 1
camera = hass.states.get("camera.front")
@ -380,11 +403,9 @@ async def test_camera_event(hass, auth, hass_client):
assert media.mime_type == "image/jpeg"
async def test_event_order(hass, auth):
async def test_event_order(hass, auth, subscriber, setup_platform):
"""Test multiple events are in descending timestamp order."""
subscriber = await async_setup_devices(
hass, auth, CAMERA_DEVICE_TYPE, CAMERA_TRAITS
)
await setup_platform()
auth.responses = [
aiohttp.web.json_response(GENERATE_IMAGE_URL_RESPONSE),
@ -449,14 +470,15 @@ async def test_event_order(hass, auth):
assert not browse.children[1].can_play
async def test_multiple_image_events_in_session(hass, auth, hass_client):
async def test_multiple_image_events_in_session(
hass, auth, hass_client, subscriber, setup_platform
):
"""Test multiple events published within the same event session."""
await setup_platform()
event_session_id = "FWWVQVUdGNUlTU2V4MGV2aTNXV..."
event_timestamp1 = dt_util.now()
event_timestamp2 = event_timestamp1 + datetime.timedelta(seconds=5)
subscriber = await async_setup_devices(
hass, auth, CAMERA_DEVICE_TYPE, CAMERA_TRAITS
)
assert len(hass.states.async_all()) == 1
camera = hass.states.get("camera.front")
@ -560,13 +582,19 @@ async def test_multiple_image_events_in_session(hass, auth, hass_client):
assert contents == IMAGE_BYTES_FROM_EVENT + b"-1"
async def test_multiple_clip_preview_events_in_session(hass, auth, hass_client):
@pytest.mark.parametrize("device_traits", [BATTERY_CAMERA_TRAITS])
async def test_multiple_clip_preview_events_in_session(
hass,
auth,
hass_client,
subscriber,
setup_platform,
):
"""Test multiple events published within the same event session."""
await setup_platform()
event_timestamp1 = dt_util.now()
event_timestamp2 = event_timestamp1 + datetime.timedelta(seconds=5)
subscriber = await async_setup_devices(
hass, auth, CAMERA_DEVICE_TYPE, BATTERY_CAMERA_TRAITS
)
assert len(hass.states.async_all()) == 1
camera = hass.states.get("camera.front")
@ -656,9 +684,9 @@ async def test_multiple_clip_preview_events_in_session(hass, auth, hass_client):
assert contents == IMAGE_BYTES_FROM_EVENT
async def test_browse_invalid_device_id(hass, auth):
async def test_browse_invalid_device_id(hass, auth, setup_platform):
"""Test a media source request for an invalid device id."""
await async_setup_devices(hass, auth, CAMERA_DEVICE_TYPE, CAMERA_TRAITS)
await setup_platform()
device_registry = dr.async_get(hass)
device = device_registry.async_get_device({(DOMAIN, DEVICE_ID)})
@ -676,9 +704,9 @@ async def test_browse_invalid_device_id(hass, auth):
)
async def test_browse_invalid_event_id(hass, auth):
async def test_browse_invalid_event_id(hass, auth, setup_platform):
"""Test a media source browsing for an invalid event id."""
await async_setup_devices(hass, auth, CAMERA_DEVICE_TYPE, CAMERA_TRAITS)
await setup_platform()
device_registry = dr.async_get(hass)
device = device_registry.async_get_device({(DOMAIN, DEVICE_ID)})
@ -699,9 +727,9 @@ async def test_browse_invalid_event_id(hass, auth):
)
async def test_resolve_missing_event_id(hass, auth):
async def test_resolve_missing_event_id(hass, auth, setup_platform):
"""Test a media source request missing an event id."""
await async_setup_devices(hass, auth, CAMERA_DEVICE_TYPE, CAMERA_TRAITS)
await setup_platform()
device_registry = dr.async_get(hass)
device = device_registry.async_get_device({(DOMAIN, DEVICE_ID)})
@ -716,10 +744,9 @@ async def test_resolve_missing_event_id(hass, auth):
)
async def test_resolve_invalid_device_id(hass, auth):
async def test_resolve_invalid_device_id(hass, auth, setup_platform):
"""Test resolving media for an invalid event id."""
await async_setup_devices(hass, auth, CAMERA_DEVICE_TYPE, CAMERA_TRAITS)
await setup_platform()
with pytest.raises(Unresolvable):
await media_source.async_resolve_media(
hass,
@ -728,9 +755,9 @@ async def test_resolve_invalid_device_id(hass, auth):
)
async def test_resolve_invalid_event_id(hass, auth):
async def test_resolve_invalid_event_id(hass, auth, setup_platform):
"""Test resolving media for an invalid event id."""
await async_setup_devices(hass, auth, CAMERA_DEVICE_TYPE, CAMERA_TRAITS)
await setup_platform()
device_registry = dr.async_get(hass)
device = device_registry.async_get_device({(DOMAIN, DEVICE_ID)})
@ -750,14 +777,14 @@ async def test_resolve_invalid_event_id(hass, auth):
assert media.mime_type == "image/jpeg"
async def test_camera_event_clip_preview(hass, auth, hass_client, mp4):
@pytest.mark.parametrize("device_traits", [BATTERY_CAMERA_TRAITS])
async def test_camera_event_clip_preview(
hass, auth, hass_client, mp4, subscriber, setup_platform
):
"""Test an event for a battery camera video clip."""
subscriber = await async_setup_devices(
hass, auth, CAMERA_DEVICE_TYPE, BATTERY_CAMERA_TRAITS
)
# Capture any events published
received_events = async_capture_events(hass, NEST_EVENT)
await setup_platform()
auth.responses = [
aiohttp.web.Response(body=mp4.getvalue()),
@ -857,10 +884,11 @@ async def test_camera_event_clip_preview(hass, auth, hass_client, mp4):
await response.read() # Animated gif format not tested
async def test_event_media_render_invalid_device_id(hass, auth, hass_client):
async def test_event_media_render_invalid_device_id(
hass, auth, hass_client, setup_platform
):
"""Test event media API called with an invalid device id."""
await async_setup_devices(hass, auth, CAMERA_DEVICE_TYPE, CAMERA_TRAITS)
await setup_platform()
client = await hass_client()
response = await client.get("/api/nest/event_media/invalid-device-id")
assert response.status == HTTPStatus.NOT_FOUND, (
@ -868,10 +896,11 @@ async def test_event_media_render_invalid_device_id(hass, auth, hass_client):
)
async def test_event_media_render_invalid_event_id(hass, auth, hass_client):
async def test_event_media_render_invalid_event_id(
hass, auth, hass_client, setup_platform
):
"""Test event media API called with an invalid device id."""
await async_setup_devices(hass, auth, CAMERA_DEVICE_TYPE, CAMERA_TRAITS)
await setup_platform()
device_registry = dr.async_get(hass)
device = device_registry.async_get_device({(DOMAIN, DEVICE_ID)})
assert device
@ -884,13 +913,11 @@ async def test_event_media_render_invalid_event_id(hass, auth, hass_client):
)
async def test_event_media_failure(hass, auth, hass_client):
async def test_event_media_failure(hass, auth, hass_client, subscriber, setup_platform):
"""Test event media fetch sees a failure from the server."""
subscriber = await async_setup_devices(
hass, auth, CAMERA_DEVICE_TYPE, CAMERA_TRAITS
)
received_events = async_capture_events(hass, NEST_EVENT)
await setup_platform()
# Failure from server when fetching media
auth.responses = [
aiohttp.web.Response(status=HTTPStatus.INTERNAL_SERVER_ERROR),
@ -937,10 +964,11 @@ async def test_event_media_failure(hass, auth, hass_client):
)
async def test_media_permission_unauthorized(hass, auth, hass_client, hass_admin_user):
async def test_media_permission_unauthorized(
hass, auth, hass_client, hass_admin_user, setup_platform
):
"""Test case where user does not have permissions to view media."""
await async_setup_devices(hass, auth, CAMERA_DEVICE_TYPE, CAMERA_TRAITS)
await setup_platform()
assert len(hass.states.async_all()) == 1
camera = hass.states.get("camera.front")
assert camera is not None
@ -962,33 +990,22 @@ async def test_media_permission_unauthorized(hass, auth, hass_client, hass_admin
)
async def test_multiple_devices(hass, auth, hass_client):
async def test_multiple_devices(
hass, auth, hass_client, create_device, subscriber, setup_platform
):
"""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)
create_device.create(
raw_data={
"name": device_id2,
"type": CAMERA_DEVICE_TYPE,
"traits": CAMERA_TRAITS,
}
)
await setup_platform()
device_registry = dr.async_get(hass)
device1 = device_registry.async_get_device({(DOMAIN, device_id1)})
device1 = device_registry.async_get_device({(DOMAIN, DEVICE_ID)})
assert device1
device2 = device_registry.async_get_device({(DOMAIN, device_id2)})
assert device2
@ -1018,7 +1035,7 @@ async def test_multiple_devices(hass, auth, hass_client):
f"event-session-id-{i}",
f"event-id-{i}",
PERSON_EVENT,
device_id=device_id1,
device_id=DEVICE_ID,
)
)
await hass.async_block_till_done()
@ -1073,34 +1090,18 @@ def event_store() -> Generator[None, None, None]:
yield
async def test_media_store_persistence(hass, auth, hass_client, event_store):
@pytest.mark.parametrize("device_traits", [BATTERY_CAMERA_TRAITS])
async def test_media_store_persistence(
hass,
auth,
hass_client,
event_store,
subscriber,
setup_platform,
config_entry,
):
"""Test the disk backed media store persistence."""
nest_device = Device.MakeDevice(
{
"name": DEVICE_ID,
"type": CAMERA_DEVICE_TYPE,
"traits": BATTERY_CAMERA_TRAITS,
},
auth=auth,
)
subscriber = FakeSubscriber()
device_manager = await subscriber.async_get_device_manager()
device_manager.add_device(nest_device)
# Fetch media for events when published
subscriber.cache_policy.fetch = True
config_entry = create_config_entry()
config_entry.add_to_hass(hass)
with patch(
"homeassistant.helpers.config_entry_oauth2_flow.async_get_config_entry_implementation"
), patch("homeassistant.components.nest.PLATFORMS", [PLATFORM]), patch(
"homeassistant.components.nest.api.GoogleNestSubscriber",
return_value=subscriber,
):
assert await async_setup_component(hass, DOMAIN, CONFIG)
await hass.async_block_till_done()
await setup_platform()
device_registry = dr.async_get(hass)
device = device_registry.async_get_device({(DOMAIN, DEVICE_ID)})
@ -1154,18 +1155,8 @@ async def test_media_store_persistence(hass, auth, hass_client, event_store):
# Now rebuild the entire integration and verify that all persisted storage
# can be re-loaded from disk.
subscriber = FakeSubscriber()
device_manager = await subscriber.async_get_device_manager()
device_manager.add_device(nest_device)
with patch(
"homeassistant.helpers.config_entry_oauth2_flow.async_get_config_entry_implementation"
), patch("homeassistant.components.nest.PLATFORMS", [PLATFORM]), patch(
"homeassistant.components.nest.api.GoogleNestSubscriber",
return_value=subscriber,
):
await hass.config_entries.async_reload(config_entry.entry_id)
await hass.async_block_till_done()
await hass.config_entries.async_reload(config_entry.entry_id)
await hass.async_block_till_done()
device_registry = dr.async_get(hass)
device = device_registry.async_get_device({(DOMAIN, DEVICE_ID)})
@ -1197,11 +1188,12 @@ async def test_media_store_persistence(hass, auth, hass_client, event_store):
assert contents == IMAGE_BYTES_FROM_EVENT
async def test_media_store_save_filesystem_error(hass, auth, hass_client):
@pytest.mark.parametrize("device_traits", [BATTERY_CAMERA_TRAITS])
async def test_media_store_save_filesystem_error(
hass, auth, hass_client, subscriber, setup_platform
):
"""Test a filesystem error writing event media."""
subscriber = await async_setup_devices(
hass, auth, CAMERA_DEVICE_TYPE, BATTERY_CAMERA_TRAITS
)
await setup_platform()
auth.responses = [
aiohttp.web.Response(body=IMAGE_BYTES_FROM_EVENT),
@ -1250,11 +1242,11 @@ async def test_media_store_save_filesystem_error(hass, auth, hass_client):
)
async def test_media_store_load_filesystem_error(hass, auth, hass_client):
async def test_media_store_load_filesystem_error(
hass, auth, hass_client, subscriber, setup_platform
):
"""Test a filesystem error reading event media."""
subscriber = await async_setup_devices(
hass, auth, CAMERA_DEVICE_TYPE, BATTERY_CAMERA_TRAITS
)
await setup_platform()
assert len(hass.states.async_all()) == 1
camera = hass.states.get("camera.front")
@ -1299,17 +1291,12 @@ async def test_media_store_load_filesystem_error(hass, auth, hass_client):
)
async def test_camera_event_media_eviction(hass, auth, hass_client):
@pytest.mark.parametrize("device_traits,cache_size", [(BATTERY_CAMERA_TRAITS, 5)])
async def test_camera_event_media_eviction(
hass, auth, hass_client, subscriber, setup_platform
):
"""Test media files getting evicted from the cache."""
# Set small cache size for testing eviction
with patch("homeassistant.components.nest.EVENT_MEDIA_CACHE_SIZE", new=5):
subscriber = await async_setup_devices(
hass,
auth,
CAMERA_DEVICE_TYPE,
BATTERY_CAMERA_TRAITS,
)
await setup_platform()
device_registry = dr.async_get(hass)
device = device_registry.async_get_device({(DOMAIN, DEVICE_ID)})
@ -1384,23 +1371,9 @@ async def test_camera_event_media_eviction(hass, auth, hass_client):
await hass.async_block_till_done()
async def test_camera_image_resize(hass, auth, hass_client):
async def test_camera_image_resize(hass, auth, hass_client, subscriber, setup_platform):
"""Test scaling a thumbnail for an event image."""
event_timestamp = dt_util.now()
subscriber = await async_setup_devices(
hass,
auth,
CAMERA_DEVICE_TYPE,
CAMERA_TRAITS,
events=[
create_event(
EVENT_SESSION_ID,
EVENT_ID,
PERSON_EVENT,
timestamp=event_timestamp,
),
],
)
await setup_platform()
device_registry = dr.async_get(hass)
device = device_registry.async_get_device({(DOMAIN, DEVICE_ID)})