mirror of
https://github.com/home-assistant/core.git
synced 2026-09-16 21:48:38 +01:00
281 lines
9.4 KiB
Python
281 lines
9.4 KiB
Python
"""Sensor tests for the YouTube integration."""
|
|
|
|
import asyncio
|
|
from datetime import timedelta
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
from syrupy.assertion import SnapshotAssertion
|
|
from youtubeaio.types import UnauthorizedError, YouTubeBackendError
|
|
|
|
from homeassistant import config_entries
|
|
from homeassistant.components.youtube.const import DOMAIN
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.util import dt as dt_util
|
|
|
|
from . import MockYouTube
|
|
from .conftest import ComponentSetup
|
|
|
|
from tests.common import async_fire_time_changed
|
|
|
|
|
|
async def test_sensor(
|
|
hass: HomeAssistant, snapshot: SnapshotAssertion, setup_integration: ComponentSetup
|
|
) -> None:
|
|
"""Test sensor."""
|
|
await setup_integration()
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_upload")
|
|
assert state == snapshot
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_short")
|
|
assert state == snapshot
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_video")
|
|
assert state == snapshot
|
|
|
|
state = hass.states.get("sensor.google_for_developers_subscribers")
|
|
assert state == snapshot
|
|
|
|
state = hass.states.get("sensor.google_for_developers_videos")
|
|
assert state == snapshot
|
|
|
|
state = hass.states.get("sensor.google_for_developers_views")
|
|
assert state == snapshot
|
|
|
|
|
|
async def test_sensor_without_uploaded_video(
|
|
hass: HomeAssistant, snapshot: SnapshotAssertion, setup_integration: ComponentSetup
|
|
) -> None:
|
|
"""Test sensor when there is no video on the channel."""
|
|
await setup_integration()
|
|
|
|
with patch(
|
|
"homeassistant.components.youtube.api.AsyncConfigEntryAuth.get_resource",
|
|
return_value=MockYouTube(
|
|
hass, playlist_items_fixture="get_no_playlist_items.json"
|
|
),
|
|
):
|
|
future = dt_util.utcnow() + timedelta(minutes=15)
|
|
async_fire_time_changed(hass, future)
|
|
await hass.async_block_till_done()
|
|
await asyncio.sleep(0.1)
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_upload")
|
|
assert state == snapshot
|
|
|
|
state = hass.states.get("sensor.google_for_developers_subscribers")
|
|
assert state == snapshot
|
|
|
|
state = hass.states.get("sensor.google_for_developers_videos")
|
|
assert state == snapshot
|
|
|
|
state = hass.states.get("sensor.google_for_developers_views")
|
|
assert state == snapshot
|
|
|
|
|
|
async def test_sensor_with_short(
|
|
hass: HomeAssistant, snapshot: SnapshotAssertion, setup_integration: ComponentSetup
|
|
) -> None:
|
|
"""Test sensors when the channel has a Short upload."""
|
|
with patch(
|
|
"homeassistant.components.youtube.api.AsyncConfigEntryAuth.get_resource",
|
|
return_value=MockYouTube(hass, short_video_ids={"wysukDrMdqU"}),
|
|
):
|
|
await setup_integration()
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_short")
|
|
assert state == snapshot
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_video")
|
|
assert state == snapshot
|
|
|
|
|
|
async def test_sensor_updating(
|
|
hass: HomeAssistant, setup_integration: ComponentSetup
|
|
) -> None:
|
|
"""Test updating sensor."""
|
|
await setup_integration()
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_upload")
|
|
assert state
|
|
assert state.attributes["video_id"] == "wysukDrMdqU"
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_video")
|
|
assert state
|
|
assert state.attributes["video_id"] == "wysukDrMdqU"
|
|
|
|
with patch(
|
|
"homeassistant.components.youtube.api.AsyncConfigEntryAuth.get_resource",
|
|
return_value=MockYouTube(
|
|
hass, playlist_items_fixture="get_playlist_items_2.json"
|
|
),
|
|
):
|
|
future = dt_util.utcnow() + timedelta(minutes=15)
|
|
async_fire_time_changed(hass, future)
|
|
await hass.async_block_till_done()
|
|
await asyncio.sleep(0.1)
|
|
state = hass.states.get("sensor.google_for_developers_latest_upload")
|
|
assert state
|
|
assert state.name == "Google for Developers Latest upload"
|
|
assert state.state == "Google I/O 2023 Developer Keynote in 5 minutes"
|
|
assert (
|
|
state.attributes["entity_picture"]
|
|
== "https://i.ytimg.com/vi/hleLlcHwQLM/maxresdefault.jpg"
|
|
)
|
|
assert state.attributes["video_id"] == "hleLlcHwQLM"
|
|
|
|
|
|
async def test_sensor_reauth_trigger(
|
|
hass: HomeAssistant, setup_integration: ComponentSetup
|
|
) -> None:
|
|
"""Test reauth is triggered after a refresh error."""
|
|
mock = await setup_integration()
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_upload")
|
|
assert state.state == "What's new in Google Home in less than 1 minute"
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_video")
|
|
assert state.state == "What's new in Google Home in less than 1 minute"
|
|
|
|
state = hass.states.get("sensor.google_for_developers_subscribers")
|
|
assert state.state == "2290000"
|
|
|
|
state = hass.states.get("sensor.google_for_developers_views")
|
|
assert state.state == "214141263"
|
|
|
|
mock.set_thrown_exception(UnauthorizedError())
|
|
future = dt_util.utcnow() + timedelta(minutes=15)
|
|
async_fire_time_changed(hass, future)
|
|
await hass.async_block_till_done()
|
|
|
|
flows = hass.config_entries.flow.async_progress()
|
|
|
|
assert len(flows) == 1
|
|
flow = flows[0]
|
|
assert flow["step_id"] == "reauth_confirm"
|
|
assert flow["handler"] == DOMAIN
|
|
assert flow["context"]["source"] == config_entries.SOURCE_REAUTH
|
|
|
|
|
|
async def test_sensor_unavailable(
|
|
hass: HomeAssistant, setup_integration: ComponentSetup
|
|
) -> None:
|
|
"""Test update failed."""
|
|
mock = await setup_integration()
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_upload")
|
|
assert state.state == "What's new in Google Home in less than 1 minute"
|
|
|
|
state = hass.states.get("sensor.google_for_developers_subscribers")
|
|
assert state.state == "2290000"
|
|
|
|
state = hass.states.get("sensor.google_for_developers_views")
|
|
assert state.state == "214141263"
|
|
|
|
mock.set_thrown_exception(YouTubeBackendError())
|
|
future = dt_util.utcnow() + timedelta(minutes=15)
|
|
async_fire_time_changed(hass, future)
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_upload")
|
|
assert state.state == "unavailable"
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_short")
|
|
assert state.state == "unavailable"
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_video")
|
|
assert state.state == "unavailable"
|
|
|
|
state = hass.states.get("sensor.google_for_developers_subscribers")
|
|
assert state.state == "unavailable"
|
|
|
|
state = hass.states.get("sensor.google_for_developers_videos")
|
|
assert state.state == "unavailable"
|
|
|
|
state = hass.states.get("sensor.google_for_developers_views")
|
|
assert state.state == "unavailable"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("short_video_ids", "expected_yielded", "expected_latest_video_state"),
|
|
[
|
|
pytest.param(
|
|
{"wysukDrMdqU"},
|
|
2,
|
|
"Google I/O 2023 Developer Keynote in 5 minutes",
|
|
id="stops_after_short_and_non_short_found",
|
|
),
|
|
pytest.param(
|
|
{"wysukDrMdqU", "hleLlcHwQLM", "lMKjtSFujcw", "c0mqBuXPrpA", "_n9xwuTORas"},
|
|
10,
|
|
"unavailable",
|
|
id="caps_at_page_size_when_only_shorts",
|
|
),
|
|
],
|
|
)
|
|
async def test_sensor_playlist_iteration(
|
|
hass: HomeAssistant,
|
|
setup_integration: ComponentSetup,
|
|
short_video_ids: set[str],
|
|
expected_yielded: int,
|
|
expected_latest_video_state: str,
|
|
) -> None:
|
|
"""Test playlist iteration stops as early as possible and never paginates."""
|
|
mock = MockYouTube(hass, short_video_ids=short_video_ids)
|
|
with patch(
|
|
"homeassistant.components.youtube.api.AsyncConfigEntryAuth.get_resource",
|
|
return_value=mock,
|
|
):
|
|
await setup_integration()
|
|
|
|
assert mock.playlist_item_requests == 1
|
|
assert mock.playlist_items_yielded == expected_yielded
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_short")
|
|
assert state.state == "What's new in Google Home in less than 1 minute"
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_video")
|
|
assert state.state == expected_latest_video_state
|
|
|
|
|
|
async def test_sensor_shorts_detection_timeout(
|
|
hass: HomeAssistant,
|
|
caplog: pytest.LogCaptureFixture,
|
|
setup_integration: ComponentSetup,
|
|
) -> None:
|
|
"""Test the per-channel pass is bounded when is_short hangs.
|
|
|
|
Channel-level sensors stay available while the video sensors report
|
|
unavailable from the partial results.
|
|
"""
|
|
mock = MockYouTube(hass, short_check_delay=1)
|
|
with (
|
|
patch(
|
|
"homeassistant.components.youtube.api.AsyncConfigEntryAuth.get_resource",
|
|
return_value=mock,
|
|
),
|
|
patch(
|
|
"homeassistant.components.youtube.coordinator._SHORTS_DETECTION_TIMEOUT",
|
|
0.1,
|
|
),
|
|
):
|
|
await setup_integration()
|
|
|
|
assert "Timed out processing recent uploads" in caplog.text
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_upload")
|
|
assert state.state == "unavailable"
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_short")
|
|
assert state.state == "unavailable"
|
|
|
|
state = hass.states.get("sensor.google_for_developers_latest_video")
|
|
assert state.state == "unavailable"
|
|
|
|
state = hass.states.get("sensor.google_for_developers_subscribers")
|
|
assert state.state == "2290000"
|
|
|
|
state = hass.states.get("sensor.google_for_developers_views")
|
|
assert state.state == "214141263"
|