diff --git a/homeassistant/components/google/__init__.py b/homeassistant/components/google/__init__.py index f35f79a5f92..0769422366e 100644 --- a/homeassistant/components/google/__init__.py +++ b/homeassistant/components/google/__init__.py @@ -5,7 +5,6 @@ from collections.abc import Mapping from datetime import datetime, timedelta, timezone from enum import Enum import logging -import os from typing import Any from googleapiclient import discovery as google_discovery @@ -163,7 +162,10 @@ ADD_EVENT_SERVICE_SCHEMA = vol.Schema( def do_authentication( - hass: HomeAssistant, hass_config: ConfigType, config: ConfigType + hass: HomeAssistant, + hass_config: ConfigType, + config: ConfigType, + storage: Storage, ) -> bool: """Notify user of actions and authenticate. @@ -226,7 +228,6 @@ def do_authentication( # not ready yet, call again return - storage = Storage(hass.config.path(TOKEN_FILE)) storage.put(credentials) do_setup(hass, hass_config, config) assert listener @@ -256,16 +257,16 @@ def setup(hass: HomeAssistant, config: ConfigType) -> bool: # component is set up by tts platform return True - token_file = hass.config.path(TOKEN_FILE) - if not os.path.isfile(token_file): - _LOGGER.debug("Token file does not exist, authenticating for first time") - do_authentication(hass, config, conf) + storage = Storage(hass.config.path(TOKEN_FILE)) + creds = storage.get() + if ( + not creds + or not creds.scopes + or conf[CONF_CALENDAR_ACCESS].scope not in creds.scopes + ): + do_authentication(hass, config, conf, storage) else: - if not check_correct_scopes(hass, token_file, conf): - _LOGGER.debug("Existing scopes are not sufficient, re-authenticating") - do_authentication(hass, config, conf) - else: - do_setup(hass, config, conf) + do_setup(hass, config, conf) return True diff --git a/tests/components/google/conftest.py b/tests/components/google/conftest.py index 59de9b2cddf..3c354b36226 100644 --- a/tests/components/google/conftest.py +++ b/tests/components/google/conftest.py @@ -1,11 +1,17 @@ """Test configuration and mocks for the google integration.""" +from __future__ import annotations + from collections.abc import Callable +import datetime from typing import Any, Generator, TypeVar from unittest.mock import Mock, patch +from oauth2client.client import Credentials, OAuth2Credentials import pytest from homeassistant.components.google import GoogleCalendarService +from homeassistant.core import HomeAssistant +from homeassistant.util.dt import utcnow ApiResult = Callable[[dict[str, Any]], None] T = TypeVar("T") @@ -36,6 +42,62 @@ def test_calendar(): return TEST_CALENDAR +class FakeStorage: + """A fake storage object for persiting creds.""" + + def __init__(self) -> None: + """Initialize FakeStorage.""" + self._creds: Credentials | None = None + + def get(self) -> Credentials | None: + """Get credentials from storage.""" + return self._creds + + def put(self, creds: Credentials) -> None: + """Put credentials in storage.""" + self._creds = creds + + +@pytest.fixture +async def token_scopes() -> list[str]: + """Fixture for scopes used during test.""" + return ["https://www.googleapis.com/auth/calendar"] + + +@pytest.fixture +async def creds(token_scopes: list[str]) -> OAuth2Credentials: + """Fixture that defines creds used in the test.""" + token_expiry = utcnow() + datetime.timedelta(days=7) + return OAuth2Credentials( + access_token="ACCESS_TOKEN", + client_id="client-id", + client_secret="client-secret", + refresh_token="REFRESH_TOKEN", + token_expiry=token_expiry, + token_uri="http://example.com", + user_agent="n/a", + scopes=token_scopes, + ) + + +@pytest.fixture(autouse=True) +async def storage() -> YieldFixture[FakeStorage]: + """Fixture to populate an existing token file for read on startup.""" + storage = FakeStorage() + with patch("homeassistant.components.google.Storage", return_value=storage): + yield storage + + +@pytest.fixture +async def mock_token_read( + hass: HomeAssistant, + creds: OAuth2Credentials, + storage: FakeStorage, +) -> None: + """Fixture to populate an existing token file for read on startup.""" + storage.put(creds) + + @pytest.fixture def mock_next_event(): """Mock the google calendar data.""" diff --git a/tests/components/google/test_calendar.py b/tests/components/google/test_calendar.py index 0ee257788dd..6f91fed7b24 100644 --- a/tests/components/google/test_calendar.py +++ b/tests/components/google/test_calendar.py @@ -21,7 +21,6 @@ from homeassistant.components.google import ( CONF_TRACK, DEVICE_SCHEMA, SERVICE_SCAN_CALENDARS, - do_setup, ) from homeassistant.const import STATE_OFF, STATE_ON from homeassistant.helpers.template import DATE_STR_FORMAT @@ -86,21 +85,18 @@ def get_calendar_info(calendar): @pytest.fixture(autouse=True) -def mock_google_setup(hass, test_calendar): +def mock_google_setup(hass, test_calendar, mock_token_read): """Mock the google set up functions.""" hass.loop.run_until_complete(async_setup_component(hass, "group", {"group": {}})) calendar = get_calendar_info(test_calendar) calendars = {calendar[CONF_CAL_ID]: calendar} - patch_google_auth = patch( - "homeassistant.components.google.do_authentication", side_effect=do_setup - ) patch_google_load = patch( "homeassistant.components.google.load_config", return_value=calendars ) patch_google_services = patch("homeassistant.components.google.setup_services") async_mock_service(hass, "google", SERVICE_SCAN_CALENDARS) - with patch_google_auth, patch_google_load, patch_google_services: + with patch_google_load, patch_google_services: yield diff --git a/tests/components/google/test_init.py b/tests/components/google/test_init.py index c3754511b04..8fbcb97bfe2 100644 --- a/tests/components/google/test_init.py +++ b/tests/components/google/test_init.py @@ -53,28 +53,6 @@ async def mock_code_flow( yield mock_flow -@pytest.fixture -async def token_scopes() -> list[str]: - """Fixture for scopes used during test.""" - return ["https://www.googleapis.com/auth/calendar"] - - -@pytest.fixture -async def creds(token_scopes: list[str]) -> OAuth2Credentials: - """Fixture that defines creds used in the test.""" - token_expiry = utcnow() + datetime.timedelta(days=7) - return OAuth2Credentials( - access_token="ACCESS_TOKEN", - client_id="client-id", - client_secret="client-secret", - refresh_token="REFRESH_TOKEN", - token_expiry=token_expiry, - token_uri="http://example.com", - user_agent="n/a", - scopes=token_scopes, - ) - - @pytest.fixture async def mock_exchange(creds: OAuth2Credentials) -> YieldFixture[Mock]: """Fixture for mocking out the exchange for credentials.""" @@ -84,25 +62,6 @@ async def mock_exchange(creds: OAuth2Credentials) -> YieldFixture[Mock]: yield mock -@pytest.fixture(autouse=True) -async def mock_token_write(hass: HomeAssistant) -> None: - """Fixture to avoid writing token files to disk.""" - with patch( - "homeassistant.components.google.os.path.isfile", return_value=True - ), patch("homeassistant.components.google.Storage.put"): - yield - - -@pytest.fixture -async def mock_token_read( - hass: HomeAssistant, - creds: OAuth2Credentials, -) -> None: - """Fixture to populate an existing token file.""" - with patch("homeassistant.components.google.Storage.get", return_value=creds): - yield - - @pytest.fixture async def calendars_config() -> list[dict[str, Any]]: """Fixture for tests to override default calendar configuration."""