Update nest camera tests to use common test fixture (#66192)

pull/66788/head
Allen Porter 2022-02-17 23:08:29 -08:00 committed by GitHub
parent 736a1ca0a3
commit 58551ec66d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 160 additions and 119 deletions

View File

@ -10,7 +10,6 @@ from http import HTTPStatus
from unittest.mock import AsyncMock, Mock, patch from unittest.mock import AsyncMock, Mock, patch
import aiohttp import aiohttp
from google_nest_sdm.device import Device
from google_nest_sdm.event import EventMessage from google_nest_sdm.event import EventMessage
import pytest import pytest
@ -21,18 +20,20 @@ from homeassistant.components.camera import (
STREAM_TYPE_HLS, STREAM_TYPE_HLS,
STREAM_TYPE_WEB_RTC, STREAM_TYPE_WEB_RTC,
) )
from homeassistant.components.nest.const import DOMAIN
from homeassistant.components.websocket_api.const import TYPE_RESULT from homeassistant.components.websocket_api.const import TYPE_RESULT
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from homeassistant.util.dt import utcnow from homeassistant.util.dt import utcnow
from .common import async_setup_sdm_platform from .common import DEVICE_ID, CreateDevice, FakeSubscriber, PlatformSetup
from .conftest import FakeAuth
from tests.common import async_fire_time_changed from tests.common import async_fire_time_changed
PLATFORM = "camera" PLATFORM = "camera"
CAMERA_DEVICE_TYPE = "sdm.devices.types.CAMERA" CAMERA_DEVICE_TYPE = "sdm.devices.types.CAMERA"
DEVICE_ID = "some-device-id"
DEVICE_TRAITS = { DEVICE_TRAITS = {
"sdm.devices.traits.Info": { "sdm.devices.traits.Info": {
"customName": "My Camera", "customName": "My Camera",
@ -49,7 +50,6 @@ DEVICE_TRAITS = {
"sdm.devices.traits.CameraMotion": {}, "sdm.devices.traits.CameraMotion": {},
} }
DATETIME_FORMAT = "YY-MM-DDTHH:MM:SS" DATETIME_FORMAT = "YY-MM-DDTHH:MM:SS"
DOMAIN = "nest"
MOTION_EVENT_ID = "FWWVQVUdGNUlTU2V4MGV2aTNXV..." MOTION_EVENT_ID = "FWWVQVUdGNUlTU2V4MGV2aTNXV..."
EVENT_SESSION_ID = "CjY5Y3VKaTZwR3o4Y19YbTVfMF..." EVENT_SESSION_ID = "CjY5Y3VKaTZwR3o4Y19YbTVfMF..."
@ -65,6 +65,45 @@ GENERATE_IMAGE_URL_RESPONSE = {
IMAGE_AUTHORIZATION_HEADERS = {"Authorization": "Basic g.0.eventToken"} IMAGE_AUTHORIZATION_HEADERS = {"Authorization": "Basic g.0.eventToken"}
@pytest.fixture
def platforms() -> list[str]:
"""Fixture to set platforms used in the test."""
return ["camera"]
@pytest.fixture
async def device_type() -> str:
"""Fixture to set default device type used when creating devices."""
return "sdm.devices.types.CAMERA"
@pytest.fixture
def camera_device(create_device: CreateDevice) -> None:
"""Fixture to create a basic camera device."""
create_device.create(DEVICE_TRAITS)
@pytest.fixture
def webrtc_camera_device(create_device: CreateDevice) -> None:
"""Fixture to create a WebRTC camera device."""
create_device.create(
{
"sdm.devices.traits.Info": {
"customName": "My Camera",
},
"sdm.devices.traits.CameraLiveStream": {
"maxVideoResolution": {
"width": 640,
"height": 480,
},
"videoCodecs": ["H264"],
"audioCodecs": ["AAC"],
"supportedProtocols": ["WEB_RTC"],
},
}
)
def make_motion_event( def make_motion_event(
event_id: str = MOTION_EVENT_ID, event_id: str = MOTION_EVENT_ID,
event_session_id: str = EVENT_SESSION_ID, event_session_id: str = EVENT_SESSION_ID,
@ -136,21 +175,6 @@ async def async_get_image(hass, width=None, height=None):
return image.content return image.content
async def async_setup_camera(hass, traits={}, auth=None):
"""Set up the platform and prerequisites."""
devices = {}
if traits:
devices[DEVICE_ID] = Device.MakeDevice(
{
"name": DEVICE_ID,
"type": CAMERA_DEVICE_TYPE,
"traits": traits,
},
auth=auth,
)
return await async_setup_sdm_platform(hass, PLATFORM, devices)
async def fire_alarm(hass, point_in_time): async def fire_alarm(hass, point_in_time):
"""Fire an alarm and wait for callbacks to run.""" """Fire an alarm and wait for callbacks to run."""
with patch("homeassistant.util.dt.utcnow", return_value=point_in_time): with patch("homeassistant.util.dt.utcnow", return_value=point_in_time):
@ -158,28 +182,33 @@ async def fire_alarm(hass, point_in_time):
await hass.async_block_till_done() await hass.async_block_till_done()
async def test_no_devices(hass): async def test_no_devices(hass: HomeAssistant, setup_platform: PlatformSetup):
"""Test configuration that returns no devices.""" """Test configuration that returns no devices."""
await async_setup_camera(hass) await setup_platform()
assert len(hass.states.async_all()) == 0 assert len(hass.states.async_all()) == 0
async def test_ineligible_device(hass): async def test_ineligible_device(
hass: HomeAssistant, setup_platform: PlatformSetup, create_device: CreateDevice
):
"""Test configuration with devices that do not support cameras.""" """Test configuration with devices that do not support cameras."""
await async_setup_camera( create_device.create(
hass,
{ {
"sdm.devices.traits.Info": { "sdm.devices.traits.Info": {
"customName": "My Camera", "customName": "My Camera",
}, },
}, }
) )
await setup_platform()
assert len(hass.states.async_all()) == 0 assert len(hass.states.async_all()) == 0
async def test_camera_device(hass): async def test_camera_device(
hass: HomeAssistant, setup_platform: PlatformSetup, camera_device: None
):
"""Test a basic camera with a live stream.""" """Test a basic camera with a live stream."""
await async_setup_camera(hass, DEVICE_TRAITS) await setup_platform()
assert len(hass.states.async_all()) == 1 assert len(hass.states.async_all()) == 1
camera = hass.states.get("camera.my_camera") camera = hass.states.get("camera.my_camera")
@ -188,7 +217,7 @@ async def test_camera_device(hass):
registry = er.async_get(hass) registry = er.async_get(hass)
entry = registry.async_get("camera.my_camera") entry = registry.async_get("camera.my_camera")
assert entry.unique_id == "some-device-id-camera" assert entry.unique_id == f"{DEVICE_ID}-camera"
assert entry.original_name == "My Camera" assert entry.original_name == "My Camera"
assert entry.domain == "camera" assert entry.domain == "camera"
@ -199,10 +228,16 @@ async def test_camera_device(hass):
assert device.identifiers == {("nest", DEVICE_ID)} assert device.identifiers == {("nest", DEVICE_ID)}
async def test_camera_stream(hass, auth, mock_create_stream): async def test_camera_stream(
hass: HomeAssistant,
setup_platform: PlatformSetup,
camera_device: None,
auth: FakeAuth,
mock_create_stream: Mock,
):
"""Test a basic camera and fetch its live stream.""" """Test a basic camera and fetch its live stream."""
auth.responses = [make_stream_url_response()] auth.responses = [make_stream_url_response()]
await async_setup_camera(hass, DEVICE_TRAITS, auth=auth) await setup_platform()
assert len(hass.states.async_all()) == 1 assert len(hass.states.async_all()) == 1
cam = hass.states.get("camera.my_camera") cam = hass.states.get("camera.my_camera")
@ -216,10 +251,17 @@ async def test_camera_stream(hass, auth, mock_create_stream):
assert await async_get_image(hass) == IMAGE_BYTES_FROM_STREAM assert await async_get_image(hass) == IMAGE_BYTES_FROM_STREAM
async def test_camera_ws_stream(hass, auth, hass_ws_client, mock_create_stream): async def test_camera_ws_stream(
hass,
setup_platform,
camera_device,
hass_ws_client,
auth,
mock_create_stream,
):
"""Test a basic camera that supports web rtc.""" """Test a basic camera that supports web rtc."""
auth.responses = [make_stream_url_response()] auth.responses = [make_stream_url_response()]
await async_setup_camera(hass, DEVICE_TRAITS, auth=auth) await setup_platform()
assert len(hass.states.async_all()) == 1 assert len(hass.states.async_all()) == 1
cam = hass.states.get("camera.my_camera") cam = hass.states.get("camera.my_camera")
@ -245,10 +287,12 @@ async def test_camera_ws_stream(hass, auth, hass_ws_client, mock_create_stream):
assert await async_get_image(hass) == IMAGE_BYTES_FROM_STREAM assert await async_get_image(hass) == IMAGE_BYTES_FROM_STREAM
async def test_camera_ws_stream_failure(hass, auth, hass_ws_client): async def test_camera_ws_stream_failure(
hass, setup_platform, camera_device, hass_ws_client, auth
):
"""Test a basic camera that supports web rtc.""" """Test a basic camera that supports web rtc."""
auth.responses = [aiohttp.web.Response(status=HTTPStatus.BAD_REQUEST)] auth.responses = [aiohttp.web.Response(status=HTTPStatus.BAD_REQUEST)]
await async_setup_camera(hass, DEVICE_TRAITS, auth=auth) await setup_platform()
assert len(hass.states.async_all()) == 1 assert len(hass.states.async_all()) == 1
cam = hass.states.get("camera.my_camera") cam = hass.states.get("camera.my_camera")
@ -272,21 +316,22 @@ async def test_camera_ws_stream_failure(hass, auth, hass_ws_client):
assert msg["error"]["message"].startswith("Nest API error") assert msg["error"]["message"].startswith("Nest API error")
async def test_camera_stream_missing_trait(hass, auth): async def test_camera_stream_missing_trait(hass, setup_platform, create_device):
"""Test fetching a video stream when not supported by the API.""" """Test fetching a video stream when not supported by the API."""
traits = { create_device.create(
"sdm.devices.traits.Info": { {
"customName": "My Camera", "sdm.devices.traits.Info": {
}, "customName": "My Camera",
"sdm.devices.traits.CameraImage": { },
"maxImageResolution": { "sdm.devices.traits.CameraImage": {
"width": 800, "maxImageResolution": {
"height": 600, "width": 800,
} "height": 600,
}, }
} },
}
await async_setup_camera(hass, traits, auth=auth) )
await setup_platform()
assert len(hass.states.async_all()) == 1 assert len(hass.states.async_all()) == 1
cam = hass.states.get("camera.my_camera") cam = hass.states.get("camera.my_camera")
@ -300,7 +345,12 @@ async def test_camera_stream_missing_trait(hass, auth):
await async_get_image(hass) await async_get_image(hass)
async def test_refresh_expired_stream_token(hass, auth): async def test_refresh_expired_stream_token(
hass: HomeAssistant,
setup_platform: PlatformSetup,
auth: FakeAuth,
camera_device: None,
):
"""Test a camera stream expiration and refresh.""" """Test a camera stream expiration and refresh."""
now = utcnow() now = utcnow()
stream_1_expiration = now + datetime.timedelta(seconds=90) stream_1_expiration = now + datetime.timedelta(seconds=90)
@ -314,11 +364,7 @@ async def test_refresh_expired_stream_token(hass, auth):
# Stream URL #3 # Stream URL #3
make_stream_url_response(stream_3_expiration, token_num=3), make_stream_url_response(stream_3_expiration, token_num=3),
] ]
await async_setup_camera( await setup_platform()
hass,
DEVICE_TRAITS,
auth=auth,
)
assert await async_setup_component(hass, "stream", {}) assert await async_setup_component(hass, "stream", {})
assert len(hass.states.async_all()) == 1 assert len(hass.states.async_all()) == 1
@ -375,7 +421,12 @@ async def test_refresh_expired_stream_token(hass, auth):
assert hls_url == hls_url2 assert hls_url == hls_url2
async def test_stream_response_already_expired(hass, auth): async def test_stream_response_already_expired(
hass: HomeAssistant,
auth: FakeAuth,
setup_platform: PlatformSetup,
camera_device: None,
):
"""Test a API response returning an expired stream url.""" """Test a API response returning an expired stream url."""
now = utcnow() now = utcnow()
stream_1_expiration = now + datetime.timedelta(seconds=-90) stream_1_expiration = now + datetime.timedelta(seconds=-90)
@ -384,7 +435,7 @@ async def test_stream_response_already_expired(hass, auth):
make_stream_url_response(stream_1_expiration, token_num=1), make_stream_url_response(stream_1_expiration, token_num=1),
make_stream_url_response(stream_2_expiration, token_num=2), make_stream_url_response(stream_2_expiration, token_num=2),
] ]
await async_setup_camera(hass, DEVICE_TRAITS, auth=auth) await setup_platform()
assert len(hass.states.async_all()) == 1 assert len(hass.states.async_all()) == 1
cam = hass.states.get("camera.my_camera") cam = hass.states.get("camera.my_camera")
@ -402,13 +453,15 @@ async def test_stream_response_already_expired(hass, auth):
assert stream_source == "rtsp://some/url?auth=g.2.streamingToken" assert stream_source == "rtsp://some/url?auth=g.2.streamingToken"
async def test_camera_removed(hass, auth): async def test_camera_removed(
hass: HomeAssistant,
auth: FakeAuth,
camera_device: None,
subscriber: FakeSubscriber,
setup_platform: PlatformSetup,
):
"""Test case where entities are removed and stream tokens revoked.""" """Test case where entities are removed and stream tokens revoked."""
subscriber = await async_setup_camera( await setup_platform()
hass,
DEVICE_TRAITS,
auth=auth,
)
# Simplify test setup # Simplify test setup
subscriber.cache_policy.fetch = False subscriber.cache_policy.fetch = False
@ -431,13 +484,14 @@ async def test_camera_removed(hass, auth):
assert len(hass.states.async_all()) == 0 assert len(hass.states.async_all()) == 0
async def test_camera_remove_failure(hass, auth): async def test_camera_remove_failure(
hass: HomeAssistant,
auth: FakeAuth,
camera_device: None,
setup_platform: PlatformSetup,
):
"""Test case where revoking the stream token fails on unload.""" """Test case where revoking the stream token fails on unload."""
await async_setup_camera( await setup_platform()
hass,
DEVICE_TRAITS,
auth=auth,
)
assert len(hass.states.async_all()) == 1 assert len(hass.states.async_all()) == 1
cam = hass.states.get("camera.my_camera") cam = hass.states.get("camera.my_camera")
@ -460,7 +514,12 @@ async def test_camera_remove_failure(hass, auth):
assert len(hass.states.async_all()) == 0 assert len(hass.states.async_all()) == 0
async def test_refresh_expired_stream_failure(hass, auth): async def test_refresh_expired_stream_failure(
hass: HomeAssistant,
auth: FakeAuth,
setup_platform: PlatformSetup,
camera_device: None,
):
"""Tests a failure when refreshing the stream.""" """Tests a failure when refreshing the stream."""
now = utcnow() now = utcnow()
stream_1_expiration = now + datetime.timedelta(seconds=90) stream_1_expiration = now + datetime.timedelta(seconds=90)
@ -472,7 +531,7 @@ async def test_refresh_expired_stream_failure(hass, auth):
# Next attempt to get a stream fetches a new url # Next attempt to get a stream fetches a new url
make_stream_url_response(expiration=stream_2_expiration, token_num=2), make_stream_url_response(expiration=stream_2_expiration, token_num=2),
] ]
await async_setup_camera(hass, DEVICE_TRAITS, auth=auth) await setup_platform()
assert await async_setup_component(hass, "stream", {}) assert await async_setup_component(hass, "stream", {})
assert len(hass.states.async_all()) == 1 assert len(hass.states.async_all()) == 1
@ -510,7 +569,9 @@ async def test_refresh_expired_stream_failure(hass, auth):
assert create_stream.called assert create_stream.called
async def test_camera_web_rtc(hass, auth, hass_ws_client): async def test_camera_web_rtc(
hass, auth, hass_ws_client, webrtc_camera_device, setup_platform
):
"""Test a basic camera that supports web rtc.""" """Test a basic camera that supports web rtc."""
expiration = utcnow() + datetime.timedelta(seconds=100) expiration = utcnow() + datetime.timedelta(seconds=100)
auth.responses = [ auth.responses = [
@ -524,21 +585,7 @@ async def test_camera_web_rtc(hass, auth, hass_ws_client):
} }
) )
] ]
device_traits = { await setup_platform()
"sdm.devices.traits.Info": {
"customName": "My Camera",
},
"sdm.devices.traits.CameraLiveStream": {
"maxVideoResolution": {
"width": 640,
"height": 480,
},
"videoCodecs": ["H264"],
"audioCodecs": ["AAC"],
"supportedProtocols": ["WEB_RTC"],
},
}
await async_setup_camera(hass, device_traits, auth=auth)
assert len(hass.states.async_all()) == 1 assert len(hass.states.async_all()) == 1
cam = hass.states.get("camera.my_camera") cam = hass.states.get("camera.my_camera")
@ -567,9 +614,11 @@ async def test_camera_web_rtc(hass, auth, hass_ws_client):
await async_get_image(hass, width=1024, height=768) await async_get_image(hass, width=1024, height=768)
async def test_camera_web_rtc_unsupported(hass, auth, hass_ws_client): async def test_camera_web_rtc_unsupported(
hass, auth, hass_ws_client, camera_device, setup_platform
):
"""Test a basic camera that supports web rtc.""" """Test a basic camera that supports web rtc."""
await async_setup_camera(hass, DEVICE_TRAITS, auth=auth) await setup_platform()
assert len(hass.states.async_all()) == 1 assert len(hass.states.async_all()) == 1
cam = hass.states.get("camera.my_camera") cam = hass.states.get("camera.my_camera")
@ -595,26 +644,14 @@ async def test_camera_web_rtc_unsupported(hass, auth, hass_ws_client):
assert msg["error"]["message"].startswith("Camera does not support WebRTC") assert msg["error"]["message"].startswith("Camera does not support WebRTC")
async def test_camera_web_rtc_offer_failure(hass, auth, hass_ws_client): async def test_camera_web_rtc_offer_failure(
hass, auth, hass_ws_client, webrtc_camera_device, setup_platform
):
"""Test a basic camera that supports web rtc.""" """Test a basic camera that supports web rtc."""
auth.responses = [ auth.responses = [
aiohttp.web.Response(status=HTTPStatus.BAD_REQUEST), aiohttp.web.Response(status=HTTPStatus.BAD_REQUEST),
] ]
device_traits = { await setup_platform()
"sdm.devices.traits.Info": {
"customName": "My Camera",
},
"sdm.devices.traits.CameraLiveStream": {
"maxVideoResolution": {
"width": 640,
"height": 480,
},
"videoCodecs": ["H264"],
"audioCodecs": ["AAC"],
"supportedProtocols": ["WEB_RTC"],
},
}
await async_setup_camera(hass, device_traits, auth=auth)
assert len(hass.states.async_all()) == 1 assert len(hass.states.async_all()) == 1
cam = hass.states.get("camera.my_camera") cam = hass.states.get("camera.my_camera")
@ -639,7 +676,9 @@ async def test_camera_web_rtc_offer_failure(hass, auth, hass_ws_client):
assert msg["error"]["message"].startswith("Nest API error") assert msg["error"]["message"].startswith("Nest API error")
async def test_camera_multiple_streams(hass, auth, hass_ws_client, mock_create_stream): async def test_camera_multiple_streams(
hass, auth, hass_ws_client, create_device, setup_platform, mock_create_stream
):
"""Test a camera supporting multiple stream types.""" """Test a camera supporting multiple stream types."""
expiration = utcnow() + datetime.timedelta(seconds=100) expiration = utcnow() + datetime.timedelta(seconds=100)
auth.responses = [ auth.responses = [
@ -656,21 +695,23 @@ async def test_camera_multiple_streams(hass, auth, hass_ws_client, mock_create_s
} }
), ),
] ]
device_traits = { create_device.create(
"sdm.devices.traits.Info": { {
"customName": "My Camera", "sdm.devices.traits.Info": {
}, "customName": "My Camera",
"sdm.devices.traits.CameraLiveStream": {
"maxVideoResolution": {
"width": 640,
"height": 480,
}, },
"videoCodecs": ["H264"], "sdm.devices.traits.CameraLiveStream": {
"audioCodecs": ["AAC"], "maxVideoResolution": {
"supportedProtocols": ["WEB_RTC", "RTSP"], "width": 640,
}, "height": 480,
} },
await async_setup_camera(hass, device_traits, auth=auth) "videoCodecs": ["H264"],
"audioCodecs": ["AAC"],
"supportedProtocols": ["WEB_RTC", "RTSP"],
},
}
)
await setup_platform()
assert len(hass.states.async_all()) == 1 assert len(hass.states.async_all()) == 1
cam = hass.states.get("camera.my_camera") cam = hass.states.get("camera.my_camera")