Stop updating google_calendars.yaml if it does not already exist (#72340)
* Stop updating google_calendars.yaml if it does not already exist * Add additional test coverage to make CI pass * Add test for no updates to google_calendar.yaml * Add parameter to test for expecting write calls * Missing call argument * Remove conditional and replace with inline assertpull/72485/head
parent
9591d5366e
commit
71bc650ac7
|
@ -300,6 +300,7 @@ async def async_setup_services(
|
||||||
calendars = await hass.async_add_executor_job(
|
calendars = await hass.async_add_executor_job(
|
||||||
load_config, hass.config.path(YAML_DEVICES)
|
load_config, hass.config.path(YAML_DEVICES)
|
||||||
)
|
)
|
||||||
|
calendars_file_lock = asyncio.Lock()
|
||||||
|
|
||||||
async def _found_calendar(calendar_item: Calendar) -> None:
|
async def _found_calendar(calendar_item: Calendar) -> None:
|
||||||
calendar = get_calendar_info(
|
calendar = get_calendar_info(
|
||||||
|
@ -307,15 +308,19 @@ async def async_setup_services(
|
||||||
calendar_item.dict(exclude_unset=True),
|
calendar_item.dict(exclude_unset=True),
|
||||||
)
|
)
|
||||||
calendar_id = calendar_item.id
|
calendar_id = calendar_item.id
|
||||||
# Populate the yaml file with all discovered calendars
|
# If the google_calendars.yaml file already exists, populate it for
|
||||||
if calendar_id not in calendars:
|
# backwards compatibility, but otherwise do not create it if it does
|
||||||
calendars[calendar_id] = calendar
|
# not exist.
|
||||||
await hass.async_add_executor_job(
|
if calendars:
|
||||||
update_config, hass.config.path(YAML_DEVICES), calendar
|
if calendar_id not in calendars:
|
||||||
)
|
calendars[calendar_id] = calendar
|
||||||
else:
|
async with calendars_file_lock:
|
||||||
# Prefer entity/name information from yaml, overriding api
|
await hass.async_add_executor_job(
|
||||||
calendar = calendars[calendar_id]
|
update_config, hass.config.path(YAML_DEVICES), calendar
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Prefer entity/name information from yaml, overriding api
|
||||||
|
calendar = calendars[calendar_id]
|
||||||
async_dispatcher_send(hass, DISCOVER_CALENDAR, calendar)
|
async_dispatcher_send(hass, DISCOVER_CALENDAR, calendar)
|
||||||
|
|
||||||
created_calendars = set()
|
created_calendars = set()
|
||||||
|
|
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
||||||
from collections.abc import Awaitable, Callable
|
from collections.abc import Awaitable, Callable
|
||||||
import datetime
|
import datetime
|
||||||
from typing import Any, Generator, TypeVar
|
from typing import Any, Generator, TypeVar
|
||||||
from unittest.mock import mock_open, patch
|
from unittest.mock import Mock, mock_open, patch
|
||||||
|
|
||||||
from aiohttp.client_exceptions import ClientError
|
from aiohttp.client_exceptions import ClientError
|
||||||
from gcal_sync.auth import API_BASE_URL
|
from gcal_sync.auth import API_BASE_URL
|
||||||
|
@ -104,11 +104,11 @@ def calendars_config(calendars_config_entity: dict[str, Any]) -> list[dict[str,
|
||||||
def mock_calendars_yaml(
|
def mock_calendars_yaml(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
calendars_config: list[dict[str, Any]],
|
calendars_config: list[dict[str, Any]],
|
||||||
) -> None:
|
) -> Generator[Mock, None, None]:
|
||||||
"""Fixture that prepares the google_calendars.yaml mocks."""
|
"""Fixture that prepares the google_calendars.yaml mocks."""
|
||||||
mocked_open_function = mock_open(read_data=yaml.dump(calendars_config))
|
mocked_open_function = mock_open(read_data=yaml.dump(calendars_config))
|
||||||
with patch("homeassistant.components.google.open", mocked_open_function):
|
with patch("homeassistant.components.google.open", mocked_open_function):
|
||||||
yield
|
yield mocked_open_function
|
||||||
|
|
||||||
|
|
||||||
class FakeStorage:
|
class FakeStorage:
|
||||||
|
@ -170,10 +170,17 @@ def config_entry_token_expiry(token_expiry: datetime.datetime) -> float:
|
||||||
return token_expiry.timestamp()
|
return token_expiry.timestamp()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def config_entry_options() -> dict[str, Any] | None:
|
||||||
|
"""Fixture to set initial config entry options."""
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def config_entry(
|
def config_entry(
|
||||||
token_scopes: list[str],
|
token_scopes: list[str],
|
||||||
config_entry_token_expiry: float,
|
config_entry_token_expiry: float,
|
||||||
|
config_entry_options: dict[str, Any] | None,
|
||||||
) -> MockConfigEntry:
|
) -> MockConfigEntry:
|
||||||
"""Fixture to create a config entry for the integration."""
|
"""Fixture to create a config entry for the integration."""
|
||||||
return MockConfigEntry(
|
return MockConfigEntry(
|
||||||
|
@ -188,6 +195,7 @@ def config_entry(
|
||||||
"expires_at": config_entry_token_expiry,
|
"expires_at": config_entry_token_expiry,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
options=config_entry_options,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -572,14 +572,16 @@ async def test_opaque_event(
|
||||||
assert (len(events) > 0) == expect_visible_event
|
assert (len(events) > 0) == expect_visible_event
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("mock_test_setup", [None])
|
||||||
async def test_scan_calendar_error(
|
async def test_scan_calendar_error(
|
||||||
hass,
|
hass,
|
||||||
component_setup,
|
component_setup,
|
||||||
test_api_calendar,
|
test_api_calendar,
|
||||||
mock_calendars_list,
|
mock_calendars_list,
|
||||||
|
config_entry,
|
||||||
):
|
):
|
||||||
"""Test that the calendar update handles a server error."""
|
"""Test that the calendar update handles a server error."""
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
mock_calendars_list({}, exc=ClientError())
|
mock_calendars_list({}, exc=ClientError())
|
||||||
assert await component_setup()
|
assert await component_setup()
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import datetime
|
||||||
import http
|
import http
|
||||||
import time
|
import time
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from unittest.mock import patch
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ from homeassistant.components.google import (
|
||||||
SERVICE_ADD_EVENT,
|
SERVICE_ADD_EVENT,
|
||||||
SERVICE_SCAN_CALENDARS,
|
SERVICE_SCAN_CALENDARS,
|
||||||
)
|
)
|
||||||
|
from homeassistant.components.google.const import CONF_CALENDAR_ACCESS
|
||||||
from homeassistant.config_entries import ConfigEntryState
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
from homeassistant.const import STATE_OFF
|
from homeassistant.const import STATE_OFF
|
||||||
from homeassistant.core import HomeAssistant, State
|
from homeassistant.core import HomeAssistant, State
|
||||||
|
@ -229,7 +230,10 @@ async def test_found_calendar_from_api(
|
||||||
assert not hass.states.get(TEST_YAML_ENTITY)
|
assert not hass.states.get(TEST_YAML_ENTITY)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("calendars_config,google_config", [([], {})])
|
@pytest.mark.parametrize(
|
||||||
|
"calendars_config,google_config,config_entry_options",
|
||||||
|
[([], {}, {CONF_CALENDAR_ACCESS: "read_write"})],
|
||||||
|
)
|
||||||
async def test_load_application_credentials(
|
async def test_load_application_credentials(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
component_setup: ComponentSetup,
|
component_setup: ComponentSetup,
|
||||||
|
@ -604,3 +608,48 @@ async def test_expired_token_requires_reauth(
|
||||||
flows = hass.config_entries.flow.async_progress()
|
flows = hass.config_entries.flow.async_progress()
|
||||||
assert len(flows) == 1
|
assert len(flows) == 1
|
||||||
assert flows[0]["step_id"] == "reauth_confirm"
|
assert flows[0]["step_id"] == "reauth_confirm"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"calendars_config,expect_write_calls",
|
||||||
|
[
|
||||||
|
(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"cal_id": "ignored",
|
||||||
|
"entities": {"device_id": "existing", "name": "existing"},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
([], False),
|
||||||
|
],
|
||||||
|
ids=["has_yaml", "no_yaml"],
|
||||||
|
)
|
||||||
|
async def test_calendar_yaml_update(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
component_setup: ComponentSetup,
|
||||||
|
mock_calendars_yaml: Mock,
|
||||||
|
mock_calendars_list: ApiResult,
|
||||||
|
test_api_calendar: dict[str, Any],
|
||||||
|
mock_events_list: ApiResult,
|
||||||
|
setup_config_entry: MockConfigEntry,
|
||||||
|
calendars_config: dict[str, Any],
|
||||||
|
expect_write_calls: bool,
|
||||||
|
) -> None:
|
||||||
|
"""Test updating the yaml file with a new calendar."""
|
||||||
|
|
||||||
|
mock_calendars_list({"items": [test_api_calendar]})
|
||||||
|
mock_events_list({})
|
||||||
|
assert await component_setup()
|
||||||
|
|
||||||
|
mock_calendars_yaml().read.assert_called()
|
||||||
|
mock_calendars_yaml().write.called is expect_write_calls
|
||||||
|
|
||||||
|
state = hass.states.get(TEST_API_ENTITY)
|
||||||
|
assert state
|
||||||
|
assert state.name == TEST_API_ENTITY_NAME
|
||||||
|
assert state.state == STATE_OFF
|
||||||
|
|
||||||
|
# No yaml config loaded that overwrites the entity name
|
||||||
|
assert not hass.states.get(TEST_YAML_ENTITY)
|
||||||
|
|
Loading…
Reference in New Issue