| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- """Tests for the reauth flows (CalDAV and API modes)."""
- from unittest.mock import AsyncMock, patch
- import caldav.lib.error as caldav_error
- import pytest
- from homeassistant.config_entries import SOURCE_REAUTH
- from homeassistant.core import HomeAssistant
- from pytest_homeassistant_custom_component.common import MockConfigEntry
- from custom_components.room_cal_ha.const import (
- CONF_API_BASE_URL,
- CONF_API_TOKEN,
- CONF_CALDAV_URL,
- CONF_PASSWORD,
- CONF_SYNC_MODE,
- CONF_USERNAME,
- DOMAIN,
- SYNC_MODE_API,
- SYNC_MODE_CALDAV,
- )
- # ---------------------------------------------------------------------------
- # Fixtures
- # ---------------------------------------------------------------------------
- @pytest.fixture
- def caldav_entry(hass: HomeAssistant):
- entry = MockConfigEntry(
- domain=DOMAIN,
- data={CONF_USERNAME: "user", CONF_PASSWORD: "pass"},
- options={CONF_SYNC_MODE: SYNC_MODE_CALDAV, CONF_CALDAV_URL: "https://cal.example.com"},
- )
- entry.add_to_hass(hass)
- return entry
- @pytest.fixture
- def api_entry(hass: HomeAssistant):
- entry = MockConfigEntry(
- domain=DOMAIN,
- data={CONF_API_TOKEN: "old-token"},
- options={CONF_SYNC_MODE: SYNC_MODE_API, CONF_API_BASE_URL: "https://api.example.com"},
- )
- entry.add_to_hass(hass)
- return entry
- def _start_reauth(hass, entry):
- return hass.config_entries.flow.async_init(
- DOMAIN,
- context={"source": SOURCE_REAUTH, "entry_id": entry.entry_id},
- data=entry.data,
- )
- # ---------------------------------------------------------------------------
- # CalDAV reauth
- # ---------------------------------------------------------------------------
- async def test_caldav_reauth_shows_confirm_form(hass: HomeAssistant, caldav_entry):
- result = await _start_reauth(hass, caldav_entry)
- assert result["type"] == "form"
- assert result["step_id"] == "reauth_confirm"
- async def test_caldav_reauth_bad_credentials_shows_invalid_auth(hass: HomeAssistant, caldav_entry):
- result = await _start_reauth(hass, caldav_entry)
- with patch(
- "custom_components.room_cal_ha.config_flow._test_caldav_auth",
- side_effect=caldav_error.AuthorizationError,
- ):
- result = await hass.config_entries.flow.async_configure(
- result["flow_id"],
- user_input={CONF_USERNAME: "user", CONF_PASSWORD: "wrong"},
- )
- assert result["type"] == "form"
- assert result["errors"]["base"] == "invalid_auth"
- async def test_caldav_reauth_connect_error_shows_cannot_connect(hass: HomeAssistant, caldav_entry):
- result = await _start_reauth(hass, caldav_entry)
- with patch(
- "custom_components.room_cal_ha.config_flow._test_caldav_auth",
- side_effect=Exception("timeout"),
- ):
- result = await hass.config_entries.flow.async_configure(
- result["flow_id"],
- user_input={CONF_USERNAME: "user", CONF_PASSWORD: "pass"},
- )
- assert result["type"] == "form"
- assert result["errors"]["base"] == "cannot_connect"
- async def test_caldav_reauth_success_updates_credentials(hass: HomeAssistant, caldav_entry):
- result = await _start_reauth(hass, caldav_entry)
- with (
- patch("custom_components.room_cal_ha.config_flow._test_caldav_auth", return_value=None),
- patch("custom_components.room_cal_ha.coordinator.CalDavBackend") as MockBackend,
- ):
- MockBackend.return_value.async_fetch = AsyncMock(return_value=(None, None))
- result = await hass.config_entries.flow.async_configure(
- result["flow_id"],
- user_input={CONF_USERNAME: "new_user", CONF_PASSWORD: "new_pass"},
- )
- # Drain the event loop so the triggered entry reload completes while patches are active.
- await hass.async_block_till_done()
- assert result["type"] == "abort"
- assert result["reason"] == "reauth_successful"
- assert caldav_entry.data[CONF_USERNAME] == "new_user"
- assert caldav_entry.data[CONF_PASSWORD] == "new_pass"
- # ---------------------------------------------------------------------------
- # API reauth
- # ---------------------------------------------------------------------------
- async def test_api_reauth_shows_api_form(hass: HomeAssistant, api_entry):
- result = await _start_reauth(hass, api_entry)
- assert result["type"] == "form"
- assert result["step_id"] == "reauth_api"
- async def test_api_reauth_bad_token_shows_invalid_auth(hass: HomeAssistant, api_entry):
- from custom_components.room_cal_ha.config_flow import _ApiAuthError
- result = await _start_reauth(hass, api_entry)
- with patch(
- "custom_components.room_cal_ha.config_flow._test_api_connection",
- new=AsyncMock(side_effect=_ApiAuthError),
- ):
- result = await hass.config_entries.flow.async_configure(
- result["flow_id"],
- user_input={CONF_API_TOKEN: "bad-token"},
- )
- assert result["type"] == "form"
- assert result["errors"]["base"] == "invalid_auth"
- async def test_api_reauth_connect_error_shows_cannot_connect(hass: HomeAssistant, api_entry):
- result = await _start_reauth(hass, api_entry)
- with patch(
- "custom_components.room_cal_ha.config_flow._test_api_connection",
- new=AsyncMock(side_effect=Exception("timeout")),
- ):
- result = await hass.config_entries.flow.async_configure(
- result["flow_id"],
- user_input={CONF_API_TOKEN: "tok"},
- )
- assert result["type"] == "form"
- assert result["errors"]["base"] == "cannot_connect"
- async def test_api_reauth_success_updates_token(hass: HomeAssistant, api_entry):
- from custom_components.room_cal_ha.models import ApiStatusData
- result = await _start_reauth(hass, api_entry)
- with (
- patch("custom_components.room_cal_ha.config_flow._test_api_connection", new=AsyncMock(return_value=None)),
- patch("custom_components.room_cal_ha.coordinator.RoomCalApiBackend") as MockBackend,
- ):
- instance = MockBackend.return_value
- instance.async_fetch = AsyncMock(return_value=(None, None))
- instance.async_fetch_status = AsyncMock(return_value=ApiStatusData(status="ok"))
- result = await hass.config_entries.flow.async_configure(
- result["flow_id"],
- user_input={CONF_API_TOKEN: "fresh-token"},
- )
- await hass.async_block_till_done()
- assert result["type"] == "abort"
- assert result["reason"] == "reauth_successful"
- assert api_entry.data[CONF_API_TOKEN] == "fresh-token"
|