1
0
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:
Allen Porter
2022-06-21 06:42:41 -07:00
committed by GitHub
parent 1b8dd3368a
commit d399815bea
8 changed files with 459 additions and 59 deletions

View File

@@ -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