mirror of https://github.com/home-assistant/core
203 lines
6.5 KiB
Python
203 lines
6.5 KiB
Python
"""Test fixtures for Google Photos."""
|
|
|
|
from collections.abc import AsyncGenerator, Awaitable, Callable, Generator
|
|
import time
|
|
from typing import Any
|
|
from unittest.mock import AsyncMock, Mock, patch
|
|
|
|
from google_photos_library_api.api import GooglePhotosLibraryApi
|
|
from google_photos_library_api.model import (
|
|
Album,
|
|
ListAlbumResult,
|
|
ListMediaItemResult,
|
|
MediaItem,
|
|
UserInfoResult,
|
|
)
|
|
import pytest
|
|
|
|
from homeassistant.components.application_credentials import (
|
|
ClientCredential,
|
|
async_import_client_credential,
|
|
)
|
|
from homeassistant.components.google_photos.const import DOMAIN, OAUTH2_SCOPES
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.setup import async_setup_component
|
|
|
|
from tests.common import (
|
|
MockConfigEntry,
|
|
load_json_array_fixture,
|
|
load_json_object_fixture,
|
|
)
|
|
|
|
USER_IDENTIFIER = "user-identifier-1"
|
|
CONFIG_ENTRY_ID = "user-identifier-1"
|
|
CLIENT_ID = "1234"
|
|
CLIENT_SECRET = "5678"
|
|
FAKE_ACCESS_TOKEN = "some-access-token"
|
|
FAKE_REFRESH_TOKEN = "some-refresh-token"
|
|
EXPIRES_IN = 3600
|
|
USERINFO_URL = "https://www.googleapis.com/oauth2/v1/userinfo"
|
|
PHOTOS_BASE_URL = "https://photoslibrary.googleapis.com"
|
|
MEDIA_ITEMS_URL = f"{PHOTOS_BASE_URL}/v1/mediaItems"
|
|
ALBUMS_URL = f"{PHOTOS_BASE_URL}/v1/albums"
|
|
UPLOADS_URL = f"{PHOTOS_BASE_URL}/v1/uploads"
|
|
CREATE_MEDIA_ITEMS_URL = f"{PHOTOS_BASE_URL}/v1/mediaItems:batchCreate"
|
|
|
|
|
|
@pytest.fixture(name="expires_at")
|
|
def mock_expires_at() -> int:
|
|
"""Fixture to set the oauth token expiration time."""
|
|
return time.time() + EXPIRES_IN
|
|
|
|
|
|
@pytest.fixture(name="scopes")
|
|
def mock_scopes() -> list[str]:
|
|
"""Fixture to set scopes used during the config entry."""
|
|
return OAUTH2_SCOPES
|
|
|
|
|
|
@pytest.fixture(name="token_entry")
|
|
def mock_token_entry(expires_at: int, scopes: list[str]) -> dict[str, Any]:
|
|
"""Fixture for OAuth 'token' data for a ConfigEntry."""
|
|
return {
|
|
"access_token": FAKE_ACCESS_TOKEN,
|
|
"refresh_token": FAKE_REFRESH_TOKEN,
|
|
"scope": " ".join(scopes),
|
|
"type": "Bearer",
|
|
"expires_at": expires_at,
|
|
"expires_in": EXPIRES_IN,
|
|
}
|
|
|
|
|
|
@pytest.fixture(name="config_entry_id")
|
|
def mock_config_entry_id() -> str | None:
|
|
"""Provide a json fixture file to load for list media item api responses."""
|
|
return CONFIG_ENTRY_ID
|
|
|
|
|
|
@pytest.fixture(name="config_entry")
|
|
def mock_config_entry(
|
|
config_entry_id: str, token_entry: dict[str, Any]
|
|
) -> MockConfigEntry:
|
|
"""Fixture for a config entry."""
|
|
return MockConfigEntry(
|
|
domain=DOMAIN,
|
|
unique_id=config_entry_id,
|
|
data={
|
|
"auth_implementation": DOMAIN,
|
|
"token": token_entry,
|
|
},
|
|
title="Account Name",
|
|
)
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
async def setup_credentials(hass: HomeAssistant) -> None:
|
|
"""Fixture to setup credentials."""
|
|
assert await async_setup_component(hass, "application_credentials", {})
|
|
await async_import_client_credential(
|
|
hass,
|
|
DOMAIN,
|
|
ClientCredential(CLIENT_ID, CLIENT_SECRET),
|
|
)
|
|
|
|
|
|
@pytest.fixture(name="fixture_name")
|
|
def mock_fixture_name() -> str | None:
|
|
"""Provide a json fixture file to load for list media item api responses."""
|
|
return None
|
|
|
|
|
|
@pytest.fixture(name="user_identifier")
|
|
def mock_user_identifier() -> str | None:
|
|
"""Provide a json fixture file to load for list media item api responses."""
|
|
return USER_IDENTIFIER
|
|
|
|
|
|
@pytest.fixture(name="api_error")
|
|
def mock_api_error() -> Exception | None:
|
|
"""Provide a json fixture file to load for list media item api responses."""
|
|
return None
|
|
|
|
|
|
@pytest.fixture(name="mock_api")
|
|
def mock_client_api(
|
|
fixture_name: str,
|
|
user_identifier: str,
|
|
api_error: Exception,
|
|
) -> Generator[Mock]:
|
|
"""Set up fake Google Photos API responses from fixtures."""
|
|
mock_api = AsyncMock(GooglePhotosLibraryApi, autospec=True)
|
|
mock_api.get_user_info.return_value = UserInfoResult(
|
|
id=user_identifier,
|
|
name="Test Name",
|
|
)
|
|
|
|
responses = load_json_array_fixture(fixture_name, DOMAIN) if fixture_name else []
|
|
|
|
async def list_media_items(*args: Any) -> AsyncGenerator[ListMediaItemResult]:
|
|
for response in responses:
|
|
mock_list_media_items = Mock(ListMediaItemResult)
|
|
mock_list_media_items.media_items = [
|
|
MediaItem.from_dict(media_item) for media_item in response["mediaItems"]
|
|
]
|
|
yield mock_list_media_items
|
|
|
|
mock_api.list_media_items.return_value.__aiter__ = list_media_items
|
|
mock_api.list_media_items.return_value.__anext__ = list_media_items
|
|
mock_api.list_media_items.side_effect = api_error
|
|
|
|
# Mock a point lookup by reading contents of the fixture above
|
|
async def get_media_item(media_item_id: str, **kwargs: Any) -> Mock:
|
|
for response in responses:
|
|
for media_item in response["mediaItems"]:
|
|
if media_item["id"] == media_item_id:
|
|
return MediaItem.from_dict(media_item)
|
|
return None
|
|
|
|
mock_api.get_media_item = get_media_item
|
|
|
|
# Emulate an async iterator for returning pages of response objects. We just
|
|
# return a single page.
|
|
|
|
async def list_albums(*args: Any, **kwargs: Any) -> AsyncGenerator[ListAlbumResult]:
|
|
mock_list_album_result = Mock(ListAlbumResult)
|
|
mock_list_album_result.albums = [
|
|
Album.from_dict(album)
|
|
for album in load_json_object_fixture("list_albums.json", DOMAIN)["albums"]
|
|
]
|
|
yield mock_list_album_result
|
|
|
|
mock_api.list_albums.return_value.__aiter__ = list_albums
|
|
mock_api.list_albums.return_value.__anext__ = list_albums
|
|
mock_api.list_albums.side_effect = api_error
|
|
|
|
# Mock a point lookup by reading contents of the album fixture above
|
|
async def get_album(album_id: str, **kwargs: Any) -> Mock:
|
|
for album in load_json_object_fixture("list_albums.json", DOMAIN)["albums"]:
|
|
if album["id"] == album_id:
|
|
return Album.from_dict(album)
|
|
return None
|
|
|
|
mock_api.get_album = get_album
|
|
mock_api.get_album.side_effect = api_error
|
|
|
|
return mock_api
|
|
|
|
|
|
@pytest.fixture(name="setup_integration")
|
|
async def mock_setup_integration(
|
|
hass: HomeAssistant,
|
|
config_entry: MockConfigEntry,
|
|
mock_api: Mock,
|
|
) -> Callable[[], Awaitable[bool]]:
|
|
"""Fixture to set up the integration."""
|
|
config_entry.add_to_hass(hass)
|
|
|
|
with patch(
|
|
"homeassistant.components.google_photos.GooglePhotosLibraryApi",
|
|
return_value=mock_api,
|
|
):
|
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
|
await hass.async_block_till_done()
|