diff --git a/homeassistant/components/google/calendar.py b/homeassistant/components/google/calendar.py index 4eb57cff49c114..eff26c2fbc4dc7 100644 --- a/homeassistant/components/google/calendar.py +++ b/homeassistant/components/google/calendar.py @@ -10,7 +10,7 @@ from gcal_sync.api import GoogleCalendarService, ListEventsRequest, SyncEventsRequest from gcal_sync.exceptions import ApiException -from gcal_sync.model import DateOrDatetime, Event +from gcal_sync.model import AccessRole, DateOrDatetime, Event from gcal_sync.store import ScopedCalendarStore from gcal_sync.sync import CalendarEventSyncManager from gcal_sync.timeline import Timeline @@ -198,7 +198,13 @@ async def async_setup_entry( entity_entry.entity_id, ) coordinator: CalendarSyncUpdateCoordinator | CalendarQueryUpdateCoordinator - if search := data.get(CONF_SEARCH): + # Prefer calendar sync down of resources when possible. However, sync does not work + # for search. Also free-busy calendars denormalize recurring events as individual + # events which is not efficient for sync + if ( + search := data.get(CONF_SEARCH) + or calendar_item.access_role == AccessRole.FREE_BUSY_READER + ): coordinator = CalendarQueryUpdateCoordinator( hass, calendar_service, diff --git a/tests/components/google/conftest.py b/tests/components/google/conftest.py index 2f5efd829bf983..ad27e971eceb01 100644 --- a/tests/components/google/conftest.py +++ b/tests/components/google/conftest.py @@ -47,7 +47,6 @@ "id": CALENDAR_ID, "etag": '"3584134138943410"', "timeZone": "UTC", - "accessRole": "reader", "foregroundColor": "#000000", "selected": True, "kind": "calendar#calendarListEntry", @@ -62,10 +61,19 @@ CLIENT_SECRET = "client-secret" +@pytest.fixture(name="calendar_access_role") +def test_calendar_access_role() -> str: + """Default access role to use for test_api_calendar in tests.""" + return "reader" + + @pytest.fixture -def test_api_calendar(): +def test_api_calendar(calendar_access_role: str): """Return a test calendar object used in API responses.""" - return TEST_API_CALENDAR + return { + **TEST_API_CALENDAR, + "accessRole": calendar_access_role, + } @pytest.fixture diff --git a/tests/components/google/test_calendar.py b/tests/components/google/test_calendar.py index 90ec8f44850ac6..cba93d9a6a66f3 100644 --- a/tests/components/google/test_calendar.py +++ b/tests/components/google/test_calendar.py @@ -60,6 +60,14 @@ } +@pytest.fixture( + autouse=True, scope="module", params=["reader", "owner", "freeBusyReader"] +) +def calendar_access_role(request) -> str: + """Fixture to exercise access roles in tests.""" + return request.param + + @pytest.fixture(autouse=True) def mock_test_setup( test_api_calendar, @@ -720,12 +728,15 @@ async def test_invalid_unique_id_cleanup( @pytest.mark.parametrize( - "time_zone,event_order", + "time_zone,event_order,calendar_access_role", + # This only tests the reader role to force testing against the local + # database filtering based on start/end time. (free busy reader would + # just use the API response which this test is not exercising) [ - ("America/Los_Angeles", ["One", "Two", "All Day Event"]), - ("America/Regina", ["One", "Two", "All Day Event"]), - ("UTC", ["One", "All Day Event", "Two"]), - ("Asia/Tokyo", ["All Day Event", "One", "Two"]), + ("America/Los_Angeles", ["One", "Two", "All Day Event"], "reader"), + ("America/Regina", ["One", "Two", "All Day Event"], "reader"), + ("UTC", ["One", "All Day Event", "Two"], "reader"), + ("Asia/Tokyo", ["All Day Event", "One", "Two"], "reader"), ], ) async def test_all_day_iter_order(