mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
Simplify google calendar API interactions (#67319)
* Simplify google calendar APIs and tests * Simplify authentication logic at startup * Improve readability of diffs * Reduce diffs * Simplify api datetime logic * Remove duplicate test fixtures added in prior commit * Remove duplicate event filter calls * Fix event list argument names * More improvements found from additional testing * Remove unnecessary variables in create event call
This commit is contained in:
parent
479aa13211
commit
deda9e38e4
@ -7,8 +7,6 @@ from enum import Enum
|
|||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from googleapiclient import discovery as google_discovery
|
|
||||||
import httplib2
|
|
||||||
from oauth2client.client import (
|
from oauth2client.client import (
|
||||||
FlowExchangeError,
|
FlowExchangeError,
|
||||||
OAuth2DeviceCodeError,
|
OAuth2DeviceCodeError,
|
||||||
@ -37,6 +35,8 @@ from homeassistant.helpers.event import track_utc_time_change
|
|||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
from homeassistant.util import convert
|
from homeassistant.util import convert
|
||||||
|
|
||||||
|
from .api import GoogleCalendarService
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
DOMAIN = "google"
|
DOMAIN = "google"
|
||||||
@ -77,6 +77,7 @@ SERVICE_FOUND_CALENDARS = "found_calendar"
|
|||||||
SERVICE_ADD_EVENT = "add_event"
|
SERVICE_ADD_EVENT = "add_event"
|
||||||
|
|
||||||
DATA_CALENDARS = "calendars"
|
DATA_CALENDARS = "calendars"
|
||||||
|
DATA_SERVICE = "service"
|
||||||
|
|
||||||
YAML_DEVICES = f"{DOMAIN}_calendars.yaml"
|
YAML_DEVICES = f"{DOMAIN}_calendars.yaml"
|
||||||
|
|
||||||
@ -251,13 +252,16 @@ def do_authentication(
|
|||||||
|
|
||||||
def setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
def setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
"""Set up the Google platform."""
|
"""Set up the Google platform."""
|
||||||
hass.data[DOMAIN] = {DATA_CALENDARS: {}}
|
|
||||||
|
|
||||||
if not (conf := config.get(DOMAIN, {})):
|
if not (conf := config.get(DOMAIN, {})):
|
||||||
# component is set up by tts platform
|
# component is set up by tts platform
|
||||||
return True
|
return True
|
||||||
|
|
||||||
storage = Storage(hass.config.path(TOKEN_FILE))
|
storage = Storage(hass.config.path(TOKEN_FILE))
|
||||||
|
hass.data[DOMAIN] = {
|
||||||
|
DATA_CALENDARS: {},
|
||||||
|
DATA_SERVICE: GoogleCalendarService(hass, storage),
|
||||||
|
}
|
||||||
creds = storage.get()
|
creds = storage.get()
|
||||||
if (
|
if (
|
||||||
not creds
|
not creds
|
||||||
@ -271,34 +275,6 @@ def setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def check_correct_scopes(
|
|
||||||
hass: HomeAssistant, token_file: str, config: ConfigType
|
|
||||||
) -> bool:
|
|
||||||
"""Check for the correct scopes in file."""
|
|
||||||
creds = Storage(token_file).get()
|
|
||||||
if not creds or not creds.scopes:
|
|
||||||
return False
|
|
||||||
target_scope = config[CONF_CALENDAR_ACCESS].scope
|
|
||||||
return target_scope in creds.scopes
|
|
||||||
|
|
||||||
|
|
||||||
class GoogleCalendarService:
|
|
||||||
"""Calendar service interface to Google."""
|
|
||||||
|
|
||||||
def __init__(self, token_file: str) -> None:
|
|
||||||
"""Init the Google Calendar service."""
|
|
||||||
self.token_file = token_file
|
|
||||||
|
|
||||||
def get(self) -> google_discovery.Resource:
|
|
||||||
"""Get the calendar service from the storage file token."""
|
|
||||||
credentials = Storage(self.token_file).get()
|
|
||||||
http = credentials.authorize(httplib2.Http())
|
|
||||||
service = google_discovery.build(
|
|
||||||
"calendar", "v3", http=http, cache_discovery=False
|
|
||||||
)
|
|
||||||
return service
|
|
||||||
|
|
||||||
|
|
||||||
def setup_services(
|
def setup_services(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
hass_config: ConfigType,
|
hass_config: ConfigType,
|
||||||
@ -328,9 +304,7 @@ def setup_services(
|
|||||||
|
|
||||||
def _scan_for_calendars(call: ServiceCall) -> None:
|
def _scan_for_calendars(call: ServiceCall) -> None:
|
||||||
"""Scan for new calendars."""
|
"""Scan for new calendars."""
|
||||||
service = calendar_service.get()
|
calendars = calendar_service.list_calendars()
|
||||||
cal_list = service.calendarList()
|
|
||||||
calendars = cal_list.list().execute()["items"]
|
|
||||||
for calendar in calendars:
|
for calendar in calendars:
|
||||||
calendar["track"] = track_new_found_calendars
|
calendar["track"] = track_new_found_calendars
|
||||||
hass.services.call(DOMAIN, SERVICE_FOUND_CALENDARS, calendar)
|
hass.services.call(DOMAIN, SERVICE_FOUND_CALENDARS, calendar)
|
||||||
@ -339,7 +313,6 @@ def setup_services(
|
|||||||
|
|
||||||
def _add_event(call: ServiceCall) -> None:
|
def _add_event(call: ServiceCall) -> None:
|
||||||
"""Add a new event to calendar."""
|
"""Add a new event to calendar."""
|
||||||
service = calendar_service.get()
|
|
||||||
start = {}
|
start = {}
|
||||||
end = {}
|
end = {}
|
||||||
|
|
||||||
@ -374,14 +347,15 @@ def setup_services(
|
|||||||
start = {"dateTime": start_dt, "timeZone": str(hass.config.time_zone)}
|
start = {"dateTime": start_dt, "timeZone": str(hass.config.time_zone)}
|
||||||
end = {"dateTime": end_dt, "timeZone": str(hass.config.time_zone)}
|
end = {"dateTime": end_dt, "timeZone": str(hass.config.time_zone)}
|
||||||
|
|
||||||
event = {
|
calendar_service.create_event(
|
||||||
"summary": call.data[EVENT_SUMMARY],
|
call.data[EVENT_CALENDAR_ID],
|
||||||
"description": call.data[EVENT_DESCRIPTION],
|
{
|
||||||
"start": start,
|
"summary": call.data[EVENT_SUMMARY],
|
||||||
"end": end,
|
"description": call.data[EVENT_DESCRIPTION],
|
||||||
}
|
"start": start,
|
||||||
service_data = {"calendarId": call.data[EVENT_CALENDAR_ID], "body": event}
|
"end": end,
|
||||||
event = service.events().insert(**service_data).execute()
|
},
|
||||||
|
)
|
||||||
|
|
||||||
# Only expose the add event service if we have the correct permissions
|
# Only expose the add event service if we have the correct permissions
|
||||||
if config.get(CONF_CALENDAR_ACCESS) is FeatureAccess.read_write:
|
if config.get(CONF_CALENDAR_ACCESS) is FeatureAccess.read_write:
|
||||||
@ -392,12 +366,11 @@ def setup_services(
|
|||||||
|
|
||||||
def do_setup(hass: HomeAssistant, hass_config: ConfigType, config: ConfigType) -> None:
|
def do_setup(hass: HomeAssistant, hass_config: ConfigType, config: ConfigType) -> None:
|
||||||
"""Run the setup after we have everything configured."""
|
"""Run the setup after we have everything configured."""
|
||||||
_LOGGER.debug("Setting up integration")
|
|
||||||
# Load calendars the user has configured
|
# Load calendars the user has configured
|
||||||
calendars = load_config(hass.config.path(YAML_DEVICES))
|
calendars = load_config(hass.config.path(YAML_DEVICES))
|
||||||
hass.data[DOMAIN][DATA_CALENDARS] = calendars
|
hass.data[DOMAIN][DATA_CALENDARS] = calendars
|
||||||
|
|
||||||
calendar_service = GoogleCalendarService(hass.config.path(TOKEN_FILE))
|
calendar_service = hass.data[DOMAIN][DATA_SERVICE]
|
||||||
track_new_found_calendars = convert(
|
track_new_found_calendars = convert(
|
||||||
config.get(CONF_TRACK_NEW), bool, DEFAULT_CONF_TRACK_NEW
|
config.get(CONF_TRACK_NEW), bool, DEFAULT_CONF_TRACK_NEW
|
||||||
)
|
)
|
||||||
|
86
homeassistant/components/google/api.py
Normal file
86
homeassistant/components/google/api.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
"""Client library for talking to Google APIs."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from googleapiclient import discovery as google_discovery
|
||||||
|
from oauth2client.file import Storage
|
||||||
|
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.util import dt
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
EVENT_PAGE_SIZE = 100
|
||||||
|
|
||||||
|
|
||||||
|
def _api_time_format(time: datetime.datetime | None) -> str | None:
|
||||||
|
"""Convert a datetime to the api string format."""
|
||||||
|
return time.isoformat("T") if time else None
|
||||||
|
|
||||||
|
|
||||||
|
class GoogleCalendarService:
|
||||||
|
"""Calendar service interface to Google."""
|
||||||
|
|
||||||
|
def __init__(self, hass: HomeAssistant, storage: Storage) -> None:
|
||||||
|
"""Init the Google Calendar service."""
|
||||||
|
self._hass = hass
|
||||||
|
self._storage = storage
|
||||||
|
|
||||||
|
def _get_service(self) -> google_discovery.Resource:
|
||||||
|
"""Get the calendar service from the storage file token."""
|
||||||
|
return google_discovery.build(
|
||||||
|
"calendar", "v3", credentials=self._storage.get(), cache_discovery=False
|
||||||
|
)
|
||||||
|
|
||||||
|
def list_calendars(self) -> list[dict[str, Any]]:
|
||||||
|
"""Return the list of calendars the user has added to their list."""
|
||||||
|
cal_list = self._get_service().calendarList() # pylint: disable=no-member
|
||||||
|
return cal_list.list().execute()["items"]
|
||||||
|
|
||||||
|
def create_event(self, calendar_id: str, event: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
"""Create an event."""
|
||||||
|
events = self._get_service().events() # pylint: disable=no-member
|
||||||
|
return events.insert(calendarId=calendar_id, body=event).execute()
|
||||||
|
|
||||||
|
async def async_list_events(
|
||||||
|
self,
|
||||||
|
calendar_id: str,
|
||||||
|
start_time: datetime.datetime | None = None,
|
||||||
|
end_time: datetime.datetime | None = None,
|
||||||
|
search: str | None = None,
|
||||||
|
page_token: str | None = None,
|
||||||
|
) -> tuple[list[dict[str, Any]], str | None]:
|
||||||
|
"""Return the list of events."""
|
||||||
|
return await self._hass.async_add_executor_job(
|
||||||
|
self.list_events,
|
||||||
|
calendar_id,
|
||||||
|
start_time,
|
||||||
|
end_time,
|
||||||
|
search,
|
||||||
|
page_token,
|
||||||
|
)
|
||||||
|
|
||||||
|
def list_events(
|
||||||
|
self,
|
||||||
|
calendar_id: str,
|
||||||
|
start_time: datetime.datetime | None = None,
|
||||||
|
end_time: datetime.datetime | None = None,
|
||||||
|
search: str | None = None,
|
||||||
|
page_token: str | None = None,
|
||||||
|
) -> tuple[list[dict[str, Any]], str | None]:
|
||||||
|
"""Return the list of events."""
|
||||||
|
events = self._get_service().events() # pylint: disable=no-member
|
||||||
|
result = events.list(
|
||||||
|
calendarId=calendar_id,
|
||||||
|
timeMin=_api_time_format(start_time if start_time else dt.now()),
|
||||||
|
timeMax=_api_time_format(end_time),
|
||||||
|
q=search,
|
||||||
|
maxResults=EVENT_PAGE_SIZE,
|
||||||
|
pageToken=page_token,
|
||||||
|
).execute()
|
||||||
|
return (result["items"], result.get("nextPageToken"))
|
@ -6,7 +6,6 @@ from datetime import datetime, timedelta
|
|||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from googleapiclient import discovery as google_discovery
|
|
||||||
from httplib2 import ServerNotFoundError
|
from httplib2 import ServerNotFoundError
|
||||||
|
|
||||||
from homeassistant.components.calendar import (
|
from homeassistant.components.calendar import (
|
||||||
@ -20,17 +19,18 @@ from homeassistant.core import HomeAssistant
|
|||||||
from homeassistant.helpers.entity import generate_entity_id
|
from homeassistant.helpers.entity import generate_entity_id
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
from homeassistant.util import Throttle, dt
|
from homeassistant.util import Throttle
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
CONF_CAL_ID,
|
CONF_CAL_ID,
|
||||||
CONF_IGNORE_AVAILABILITY,
|
CONF_IGNORE_AVAILABILITY,
|
||||||
CONF_SEARCH,
|
CONF_SEARCH,
|
||||||
CONF_TRACK,
|
CONF_TRACK,
|
||||||
|
DATA_SERVICE,
|
||||||
DEFAULT_CONF_OFFSET,
|
DEFAULT_CONF_OFFSET,
|
||||||
TOKEN_FILE,
|
DOMAIN,
|
||||||
GoogleCalendarService,
|
|
||||||
)
|
)
|
||||||
|
from .api import GoogleCalendarService
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ def setup_platform(
|
|||||||
if not any(data[CONF_TRACK] for data in disc_info[CONF_ENTITIES]):
|
if not any(data[CONF_TRACK] for data in disc_info[CONF_ENTITIES]):
|
||||||
return
|
return
|
||||||
|
|
||||||
calendar_service = GoogleCalendarService(hass.config.path(TOKEN_FILE))
|
calendar_service = hass.data[DOMAIN][DATA_SERVICE]
|
||||||
entities = []
|
entities = []
|
||||||
for data in disc_info[CONF_ENTITIES]:
|
for data in disc_info[CONF_ENTITIES]:
|
||||||
if not data[CONF_TRACK]:
|
if not data[CONF_TRACK]:
|
||||||
@ -150,23 +150,6 @@ class GoogleCalendarData:
|
|||||||
self.ignore_availability = ignore_availability
|
self.ignore_availability = ignore_availability
|
||||||
self.event: dict[str, Any] | None = None
|
self.event: dict[str, Any] | None = None
|
||||||
|
|
||||||
def _prepare_query(
|
|
||||||
self,
|
|
||||||
) -> tuple[google_discovery.Resource | None, dict[str, Any] | None]:
|
|
||||||
try:
|
|
||||||
service = self.calendar_service.get()
|
|
||||||
except ServerNotFoundError as err:
|
|
||||||
_LOGGER.error("Unable to connect to Google: %s", err)
|
|
||||||
return None, None
|
|
||||||
params = dict(DEFAULT_GOOGLE_SEARCH_PARAMS)
|
|
||||||
params["calendarId"] = self.calendar_id
|
|
||||||
params["maxResults"] = 100 # Page size
|
|
||||||
|
|
||||||
if self.search:
|
|
||||||
params["q"] = self.search
|
|
||||||
|
|
||||||
return service, params
|
|
||||||
|
|
||||||
def _event_filter(self, event: dict[str, Any]) -> bool:
|
def _event_filter(self, event: dict[str, Any]) -> bool:
|
||||||
"""Return True if the event is visible."""
|
"""Return True if the event is visible."""
|
||||||
if self.ignore_availability:
|
if self.ignore_availability:
|
||||||
@ -177,51 +160,36 @@ class GoogleCalendarData:
|
|||||||
self, hass: HomeAssistant, start_date: datetime, end_date: datetime
|
self, hass: HomeAssistant, start_date: datetime, end_date: datetime
|
||||||
) -> list[dict[str, Any]]:
|
) -> list[dict[str, Any]]:
|
||||||
"""Get all events in a specific time frame."""
|
"""Get all events in a specific time frame."""
|
||||||
service, params = await hass.async_add_executor_job(self._prepare_query)
|
|
||||||
if service is None or params is None:
|
|
||||||
return []
|
|
||||||
params["timeMin"] = start_date.isoformat("T")
|
|
||||||
params["timeMax"] = end_date.isoformat("T")
|
|
||||||
|
|
||||||
event_list: list[dict[str, Any]] = []
|
event_list: list[dict[str, Any]] = []
|
||||||
events = await hass.async_add_executor_job(service.events)
|
|
||||||
page_token: str | None = None
|
page_token: str | None = None
|
||||||
while True:
|
while True:
|
||||||
page_token = await self.async_get_events_page(
|
try:
|
||||||
hass, events, params, page_token, event_list
|
items, page_token = await self.calendar_service.async_list_events(
|
||||||
)
|
self.calendar_id,
|
||||||
|
start_time=start_date,
|
||||||
|
end_time=end_date,
|
||||||
|
search=self.search,
|
||||||
|
page_token=page_token,
|
||||||
|
)
|
||||||
|
except ServerNotFoundError as err:
|
||||||
|
_LOGGER.error("Unable to connect to Google: %s", err)
|
||||||
|
return []
|
||||||
|
|
||||||
|
event_list.extend(filter(self._event_filter, items))
|
||||||
if not page_token:
|
if not page_token:
|
||||||
break
|
break
|
||||||
return event_list
|
return event_list
|
||||||
|
|
||||||
async def async_get_events_page(
|
|
||||||
self,
|
|
||||||
hass: HomeAssistant,
|
|
||||||
events: google_discovery.Resource,
|
|
||||||
params: dict[str, Any],
|
|
||||||
page_token: str | None,
|
|
||||||
event_list: list[dict[str, Any]],
|
|
||||||
) -> str | None:
|
|
||||||
"""Get a page of events in a specific time frame."""
|
|
||||||
params["pageToken"] = page_token
|
|
||||||
result = await hass.async_add_executor_job(events.list(**params).execute)
|
|
||||||
|
|
||||||
items = result.get("items", [])
|
|
||||||
visible_items = filter(self._event_filter, items)
|
|
||||||
event_list.extend(visible_items)
|
|
||||||
return result.get("nextPageToken")
|
|
||||||
|
|
||||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||||
def update(self) -> None:
|
def update(self) -> None:
|
||||||
"""Get the latest data."""
|
"""Get the latest data."""
|
||||||
service, params = self._prepare_query()
|
try:
|
||||||
if service is None or params is None:
|
items, _ = self.calendar_service.list_events(
|
||||||
|
self.calendar_id, search=self.search
|
||||||
|
)
|
||||||
|
except ServerNotFoundError as err:
|
||||||
|
_LOGGER.error("Unable to connect to Google: %s", err)
|
||||||
return
|
return
|
||||||
params["timeMin"] = dt.now().isoformat("T")
|
|
||||||
|
|
||||||
events = service.events()
|
|
||||||
result = events.list(**params).execute()
|
|
||||||
|
|
||||||
items = result.get("items", [])
|
|
||||||
valid_events = filter(self._event_filter, items)
|
valid_events = filter(self._event_filter, items)
|
||||||
self.event = next(valid_events, None)
|
self.event = next(valid_events, None)
|
||||||
|
@ -6,10 +6,10 @@ import datetime
|
|||||||
from typing import Any, Generator, TypeVar
|
from typing import Any, Generator, TypeVar
|
||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
|
from googleapiclient import discovery as google_discovery
|
||||||
from oauth2client.client import Credentials, OAuth2Credentials
|
from oauth2client.client import Credentials, OAuth2Credentials
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.google import GoogleCalendarService
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.util.dt import utcnow
|
from homeassistant.util.dt import utcnow
|
||||||
|
|
||||||
@ -108,14 +108,21 @@ def mock_next_event():
|
|||||||
yield google_cal_data
|
yield google_cal_data
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def calendar_resource() -> YieldFixture[google_discovery.Resource]:
|
||||||
|
"""Fixture to mock out the Google discovery API."""
|
||||||
|
with patch("homeassistant.components.google.api.google_discovery.build") as mock:
|
||||||
|
yield mock
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_events_list(
|
def mock_events_list(
|
||||||
google_service: GoogleCalendarService,
|
calendar_resource: google_discovery.Resource,
|
||||||
) -> Callable[[dict[str, Any]], None]:
|
) -> Callable[[dict[str, Any]], None]:
|
||||||
"""Fixture to construct a fake event list API response."""
|
"""Fixture to construct a fake event list API response."""
|
||||||
|
|
||||||
def _put_result(response: dict[str, Any]) -> None:
|
def _put_result(response: dict[str, Any]) -> None:
|
||||||
google_service.return_value.get.return_value.events.return_value.list.return_value.execute.return_value = (
|
calendar_resource.return_value.events.return_value.list.return_value.execute.return_value = (
|
||||||
response
|
response
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
@ -125,12 +132,12 @@ def mock_events_list(
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_calendars_list(
|
def mock_calendars_list(
|
||||||
google_service: GoogleCalendarService,
|
calendar_resource: google_discovery.Resource,
|
||||||
) -> ApiResult:
|
) -> ApiResult:
|
||||||
"""Fixture to construct a fake calendar list API response."""
|
"""Fixture to construct a fake calendar list API response."""
|
||||||
|
|
||||||
def _put_result(response: dict[str, Any]) -> None:
|
def _put_result(response: dict[str, Any]) -> None:
|
||||||
google_service.return_value.get.return_value.calendarList.return_value.list.return_value.execute.return_value = (
|
calendar_resource.return_value.calendarList.return_value.list.return_value.execute.return_value = (
|
||||||
response
|
response
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
@ -140,11 +147,9 @@ def mock_calendars_list(
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_insert_event(
|
def mock_insert_event(
|
||||||
google_service: GoogleCalendarService,
|
calendar_resource: google_discovery.Resource,
|
||||||
) -> Mock:
|
) -> Mock:
|
||||||
"""Fixture to create a mock to capture new events added to the API."""
|
"""Fixture to create a mock to capture new events added to the API."""
|
||||||
insert_mock = Mock()
|
insert_mock = Mock()
|
||||||
google_service.return_value.get.return_value.events.return_value.insert = (
|
calendar_resource.return_value.events.return_value.insert = insert_mock
|
||||||
insert_mock
|
|
||||||
)
|
|
||||||
return insert_mock
|
return insert_mock
|
||||||
|
@ -110,17 +110,7 @@ def set_time_zone():
|
|||||||
dt_util.set_default_time_zone(dt_util.get_time_zone("UTC"))
|
dt_util.set_default_time_zone(dt_util.get_time_zone("UTC"))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="google_service")
|
async def test_all_day_event(hass, mock_next_event, mock_token_read):
|
||||||
def mock_google_service():
|
|
||||||
"""Mock google service."""
|
|
||||||
patch_google_service = patch(
|
|
||||||
"homeassistant.components.google.calendar.GoogleCalendarService"
|
|
||||||
)
|
|
||||||
with patch_google_service as mock_service:
|
|
||||||
yield mock_service
|
|
||||||
|
|
||||||
|
|
||||||
async def test_all_day_event(hass, mock_next_event):
|
|
||||||
"""Test that we can create an event trigger on device."""
|
"""Test that we can create an event trigger on device."""
|
||||||
week_from_today = dt_util.dt.date.today() + dt_util.dt.timedelta(days=7)
|
week_from_today = dt_util.dt.date.today() + dt_util.dt.timedelta(days=7)
|
||||||
end_event = week_from_today + dt_util.dt.timedelta(days=1)
|
end_event = week_from_today + dt_util.dt.timedelta(days=1)
|
||||||
@ -302,9 +292,9 @@ async def test_all_day_offset_event(hass, mock_next_event):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def test_update_error(hass, google_service):
|
async def test_update_error(hass, calendar_resource):
|
||||||
"""Test that the calendar handles a server error."""
|
"""Test that the calendar handles a server error."""
|
||||||
google_service.return_value.get = Mock(
|
calendar_resource.return_value.get = Mock(
|
||||||
side_effect=httplib2.ServerNotFoundError("unit test")
|
side_effect=httplib2.ServerNotFoundError("unit test")
|
||||||
)
|
)
|
||||||
assert await async_setup_component(hass, "google", {"google": GOOGLE_CONFIG})
|
assert await async_setup_component(hass, "google", {"google": GOOGLE_CONFIG})
|
||||||
@ -315,7 +305,7 @@ async def test_update_error(hass, google_service):
|
|||||||
assert state.state == "off"
|
assert state.state == "off"
|
||||||
|
|
||||||
|
|
||||||
async def test_calendars_api(hass, hass_client, google_service):
|
async def test_calendars_api(hass, hass_client):
|
||||||
"""Test the Rest API returns the calendar."""
|
"""Test the Rest API returns the calendar."""
|
||||||
assert await async_setup_component(hass, "google", {"google": GOOGLE_CONFIG})
|
assert await async_setup_component(hass, "google", {"google": GOOGLE_CONFIG})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -332,11 +322,9 @@ async def test_calendars_api(hass, hass_client, google_service):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
async def test_http_event_api_failure(hass, hass_client, google_service):
|
async def test_http_event_api_failure(hass, hass_client, calendar_resource):
|
||||||
"""Test the Rest API response during a calendar failure."""
|
"""Test the Rest API response during a calendar failure."""
|
||||||
google_service.return_value.get = Mock(
|
calendar_resource.side_effect = httplib2.ServerNotFoundError("unit test")
|
||||||
side_effect=httplib2.ServerNotFoundError("unit test")
|
|
||||||
)
|
|
||||||
|
|
||||||
assert await async_setup_component(hass, "google", {"google": GOOGLE_CONFIG})
|
assert await async_setup_component(hass, "google", {"google": GOOGLE_CONFIG})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -352,7 +340,7 @@ async def test_http_event_api_failure(hass, hass_client, google_service):
|
|||||||
assert events == []
|
assert events == []
|
||||||
|
|
||||||
|
|
||||||
async def test_http_api_event(hass, hass_client, google_service, mock_events_list):
|
async def test_http_api_event(hass, hass_client, mock_events_list):
|
||||||
"""Test querying the API and fetching events from the server."""
|
"""Test querying the API and fetching events from the server."""
|
||||||
now = dt_util.now()
|
now = dt_util.now()
|
||||||
|
|
||||||
@ -392,7 +380,7 @@ def create_ignore_avail_calendar() -> dict[str, Any]:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("test_calendar", [create_ignore_avail_calendar()])
|
@pytest.mark.parametrize("test_calendar", [create_ignore_avail_calendar()])
|
||||||
async def test_opaque_event(hass, hass_client, google_service, mock_events_list):
|
async def test_opaque_event(hass, hass_client, mock_events_list):
|
||||||
"""Test querying the API and fetching events from the server."""
|
"""Test querying the API and fetching events from the server."""
|
||||||
now = dt_util.now()
|
now = dt_util.now()
|
||||||
|
|
||||||
@ -426,7 +414,7 @@ async def test_opaque_event(hass, hass_client, google_service, mock_events_list)
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("test_calendar", [create_ignore_avail_calendar()])
|
@pytest.mark.parametrize("test_calendar", [create_ignore_avail_calendar()])
|
||||||
async def test_transparent_event(hass, hass_client, google_service, mock_events_list):
|
async def test_transparent_event(hass, hass_client, mock_events_list):
|
||||||
"""Test querying the API and fetching events from the server."""
|
"""Test querying the API and fetching events from the server."""
|
||||||
now = dt_util.now()
|
now = dt_util.now()
|
||||||
|
|
||||||
|
@ -12,11 +12,7 @@ from oauth2client.client import (
|
|||||||
import pytest
|
import pytest
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from homeassistant.components.google import (
|
from homeassistant.components.google import DOMAIN, SERVICE_ADD_EVENT
|
||||||
DOMAIN,
|
|
||||||
SERVICE_ADD_EVENT,
|
|
||||||
GoogleCalendarService,
|
|
||||||
)
|
|
||||||
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET, STATE_OFF
|
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET, STATE_OFF
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
@ -118,15 +114,6 @@ async def component_setup(
|
|||||||
return _setup_func
|
return _setup_func
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
async def google_service() -> YieldFixture[GoogleCalendarService]:
|
|
||||||
"""Fixture to capture service calls."""
|
|
||||||
with patch("homeassistant.components.google.GoogleCalendarService") as mock, patch(
|
|
||||||
"homeassistant.components.google.calendar.GoogleCalendarService", mock
|
|
||||||
):
|
|
||||||
yield mock
|
|
||||||
|
|
||||||
|
|
||||||
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):
|
||||||
@ -150,7 +137,6 @@ async def test_setup_config_empty(
|
|||||||
|
|
||||||
async def test_init_success(
|
async def test_init_success(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
google_service: GoogleCalendarService,
|
|
||||||
mock_code_flow: Mock,
|
mock_code_flow: Mock,
|
||||||
mock_exchange: Mock,
|
mock_exchange: Mock,
|
||||||
mock_notification: Mock,
|
mock_notification: Mock,
|
||||||
@ -243,7 +229,6 @@ async def test_existing_token(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_token_read: None,
|
mock_token_read: None,
|
||||||
component_setup: ComponentSetup,
|
component_setup: ComponentSetup,
|
||||||
google_service: GoogleCalendarService,
|
|
||||||
mock_calendars_yaml: None,
|
mock_calendars_yaml: None,
|
||||||
mock_notification: Mock,
|
mock_notification: Mock,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -266,7 +251,6 @@ async def test_existing_token_missing_scope(
|
|||||||
token_scopes: list[str],
|
token_scopes: list[str],
|
||||||
mock_token_read: None,
|
mock_token_read: None,
|
||||||
component_setup: ComponentSetup,
|
component_setup: ComponentSetup,
|
||||||
google_service: GoogleCalendarService,
|
|
||||||
mock_calendars_yaml: None,
|
mock_calendars_yaml: None,
|
||||||
mock_notification: Mock,
|
mock_notification: Mock,
|
||||||
mock_code_flow: Mock,
|
mock_code_flow: Mock,
|
||||||
@ -295,7 +279,6 @@ async def test_calendar_yaml_missing_required_fields(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_token_read: None,
|
mock_token_read: None,
|
||||||
component_setup: ComponentSetup,
|
component_setup: ComponentSetup,
|
||||||
google_service: GoogleCalendarService,
|
|
||||||
calendars_config: list[dict[str, Any]],
|
calendars_config: list[dict[str, Any]],
|
||||||
mock_calendars_yaml: None,
|
mock_calendars_yaml: None,
|
||||||
mock_notification: Mock,
|
mock_notification: Mock,
|
||||||
@ -313,7 +296,6 @@ async def test_invalid_calendar_yaml(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_token_read: None,
|
mock_token_read: None,
|
||||||
component_setup: ComponentSetup,
|
component_setup: ComponentSetup,
|
||||||
google_service: GoogleCalendarService,
|
|
||||||
calendars_config: list[dict[str, Any]],
|
calendars_config: list[dict[str, Any]],
|
||||||
mock_calendars_yaml: None,
|
mock_calendars_yaml: None,
|
||||||
mock_notification: Mock,
|
mock_notification: Mock,
|
||||||
@ -332,7 +314,6 @@ async def test_found_calendar_from_api(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_token_read: None,
|
mock_token_read: None,
|
||||||
component_setup: ComponentSetup,
|
component_setup: ComponentSetup,
|
||||||
google_service: GoogleCalendarService,
|
|
||||||
mock_calendars_list: ApiResult,
|
mock_calendars_list: ApiResult,
|
||||||
test_calendar: dict[str, Any],
|
test_calendar: dict[str, Any],
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -354,7 +335,6 @@ async def test_add_event(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_token_read: None,
|
mock_token_read: None,
|
||||||
component_setup: ComponentSetup,
|
component_setup: ComponentSetup,
|
||||||
google_service: GoogleCalendarService,
|
|
||||||
mock_calendars_list: ApiResult,
|
mock_calendars_list: ApiResult,
|
||||||
test_calendar: dict[str, Any],
|
test_calendar: dict[str, Any],
|
||||||
mock_insert_event: Mock,
|
mock_insert_event: Mock,
|
||||||
@ -416,7 +396,6 @@ async def test_add_event_date_ranges(
|
|||||||
mock_token_read: None,
|
mock_token_read: None,
|
||||||
calendars_config: list[dict[str, Any]],
|
calendars_config: list[dict[str, Any]],
|
||||||
component_setup: ComponentSetup,
|
component_setup: ComponentSetup,
|
||||||
google_service: GoogleCalendarService,
|
|
||||||
mock_calendars_list: ApiResult,
|
mock_calendars_list: ApiResult,
|
||||||
test_calendar: dict[str, Any],
|
test_calendar: dict[str, Any],
|
||||||
mock_insert_event: Mock,
|
mock_insert_event: Mock,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user