mirror of
https://github.com/home-assistant/core.git
synced 2025-12-24 12:59:34 +00:00
Allow multiple google calendar config entries (#73715)
* Support multiple config entries at once * Add test coverage for multiple config entries * Add support for multiple config entries to google config flow * Clear hass.data when unloading config entry * Make google config flow defensive against reuse of the same account * Assign existing google config entries a unique id * Migrate entities to new unique id format * Support muliple accounts per oauth client id * Fix mypy typing errors * Hard fail to keep state consistent, removing graceful degredation * Remove invalid entity regsitry entries
This commit is contained in:
@@ -26,6 +26,7 @@ from homeassistant.util.dt import utcnow
|
||||
|
||||
from .conftest import (
|
||||
CALENDAR_ID,
|
||||
EMAIL_ADDRESS,
|
||||
TEST_API_ENTITY,
|
||||
TEST_API_ENTITY_NAME,
|
||||
TEST_YAML_ENTITY,
|
||||
@@ -62,6 +63,7 @@ def setup_config_entry(
|
||||
) -> MockConfigEntry:
|
||||
"""Fixture to initialize the config entry."""
|
||||
config_entry.add_to_hass(hass)
|
||||
return config_entry
|
||||
|
||||
|
||||
@pytest.fixture(
|
||||
@@ -219,11 +221,9 @@ async def test_calendar_yaml_error(
|
||||
assert hass.states.get(TEST_API_ENTITY)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("calendars_config", [[]])
|
||||
async def test_found_calendar_from_api(
|
||||
async def test_init_calendar(
|
||||
hass: HomeAssistant,
|
||||
component_setup: ComponentSetup,
|
||||
mock_calendars_yaml: None,
|
||||
mock_calendars_list: ApiResult,
|
||||
test_api_calendar: dict[str, Any],
|
||||
mock_events_list: ApiResult,
|
||||
@@ -275,6 +275,59 @@ async def test_load_application_credentials(
|
||||
assert not hass.states.get(TEST_YAML_ENTITY)
|
||||
|
||||
|
||||
async def test_multiple_config_entries(
|
||||
hass: HomeAssistant,
|
||||
component_setup: ComponentSetup,
|
||||
mock_calendars_list: ApiResult,
|
||||
test_api_calendar: dict[str, Any],
|
||||
mock_events_list: ApiResult,
|
||||
config_entry: MockConfigEntry,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
) -> None:
|
||||
"""Test finding a calendar from the API."""
|
||||
|
||||
assert await component_setup()
|
||||
|
||||
config_entry1 = MockConfigEntry(
|
||||
domain=DOMAIN, data=config_entry.data, unique_id=EMAIL_ADDRESS
|
||||
)
|
||||
calendar1 = {
|
||||
**test_api_calendar,
|
||||
"id": "calendar-id1",
|
||||
"summary": "Example Calendar 1",
|
||||
}
|
||||
|
||||
mock_calendars_list({"items": [calendar1]})
|
||||
mock_events_list({}, calendar_id="calendar-id1")
|
||||
config_entry1.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(config_entry1.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("calendar.example_calendar_1")
|
||||
assert state
|
||||
assert state.name == "Example Calendar 1"
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
config_entry2 = MockConfigEntry(
|
||||
domain=DOMAIN, data=config_entry.data, unique_id="other-address@example.com"
|
||||
)
|
||||
calendar2 = {
|
||||
**test_api_calendar,
|
||||
"id": "calendar-id2",
|
||||
"summary": "Example Calendar 2",
|
||||
}
|
||||
aioclient_mock.clear_requests()
|
||||
mock_calendars_list({"items": [calendar2]})
|
||||
mock_events_list({}, calendar_id="calendar-id2")
|
||||
config_entry2.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(config_entry2.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("calendar.example_calendar_2")
|
||||
assert state
|
||||
assert state.name == "Example Calendar 2"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"calendars_config_track,expected_state,google_config_track_new",
|
||||
[
|
||||
@@ -795,3 +848,72 @@ async def test_update_will_reload(
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
mock_reload.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("config_entry_unique_id", [None])
|
||||
async def test_assign_unique_id(
|
||||
hass: HomeAssistant,
|
||||
component_setup: ComponentSetup,
|
||||
mock_calendars_list: ApiResult,
|
||||
test_api_calendar: dict[str, Any],
|
||||
mock_events_list: ApiResult,
|
||||
mock_calendar_get: Callable[[...], None],
|
||||
setup_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test an existing config is updated to have unique id if it does not exist."""
|
||||
|
||||
assert setup_config_entry.state is ConfigEntryState.NOT_LOADED
|
||||
assert setup_config_entry.unique_id is None
|
||||
|
||||
mock_calendar_get(
|
||||
"primary",
|
||||
{"id": EMAIL_ADDRESS, "summary": "Personal"},
|
||||
)
|
||||
|
||||
mock_calendars_list({"items": [test_api_calendar]})
|
||||
mock_events_list({})
|
||||
assert await component_setup()
|
||||
|
||||
assert setup_config_entry.state is ConfigEntryState.LOADED
|
||||
assert setup_config_entry.unique_id == EMAIL_ADDRESS
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"config_entry_unique_id,request_status,config_entry_status",
|
||||
[
|
||||
(None, http.HTTPStatus.BAD_REQUEST, ConfigEntryState.SETUP_RETRY),
|
||||
(
|
||||
None,
|
||||
http.HTTPStatus.UNAUTHORIZED,
|
||||
ConfigEntryState.SETUP_ERROR,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_assign_unique_id_failure(
|
||||
hass: HomeAssistant,
|
||||
component_setup: ComponentSetup,
|
||||
mock_calendars_list: ApiResult,
|
||||
test_api_calendar: dict[str, Any],
|
||||
mock_events_list: ApiResult,
|
||||
mock_calendar_get: Callable[[...], None],
|
||||
setup_config_entry: MockConfigEntry,
|
||||
request_status: http.HTTPStatus,
|
||||
config_entry_status: ConfigEntryState,
|
||||
) -> None:
|
||||
"""Test lookup failures during unique id assignment are handled gracefully."""
|
||||
|
||||
assert setup_config_entry.state is ConfigEntryState.NOT_LOADED
|
||||
assert setup_config_entry.unique_id is None
|
||||
|
||||
mock_calendar_get(
|
||||
"primary",
|
||||
{},
|
||||
status=request_status,
|
||||
)
|
||||
|
||||
mock_calendars_list({"items": [test_api_calendar]})
|
||||
mock_events_list({})
|
||||
assert await component_setup()
|
||||
|
||||
assert setup_config_entry.state is config_entry_status
|
||||
assert setup_config_entry.unique_id is None
|
||||
|
||||
Reference in New Issue
Block a user