| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- from unittest.mock import AsyncMock, patch
- import pytest
- import caldav.lib.error as caldav_error
- from homeassistant.config_entries import SOURCE_USER
- from homeassistant.core import HomeAssistant
- from custom_components.room_cal_ha.const import (
- CONF_API_BASE_URL,
- CONF_API_TOKEN,
- CONF_CALDAV_URL,
- CONF_CALENDAR_NAME,
- CONF_PASSWORD,
- CONF_REFRESH_INTERVAL,
- CONF_RESERVATION_DEFAULTS,
- CONF_ROOM_NAME,
- CONF_SYNC_MODE,
- CONF_USERNAME,
- DEFAULT_REFRESH_INTERVAL,
- DOMAIN,
- SYNC_MODE_API,
- SYNC_MODE_CALDAV,
- SYNC_MODE_MANUAL,
- )
- _EMPTY_DEFAULTS = {
- "guest_name": "",
- "check_in_time": "",
- "check_out_time": "",
- "wifi_ssid": "",
- "wifi_key": "",
- "door_code": "",
- }
- # ---------------------------------------------------------------------------
- # Config flow — user step
- # ---------------------------------------------------------------------------
- async def test_user_step_shows_form(hass: HomeAssistant):
- result = await hass.config_entries.flow.async_init(
- DOMAIN, context={"source": SOURCE_USER}
- )
- assert result["type"] == "form"
- assert result["step_id"] == "user"
- async def test_user_step_creates_entry_with_room_name(hass: HomeAssistant):
- result = await hass.config_entries.flow.async_init(
- DOMAIN, context={"source": SOURCE_USER}
- )
- result = await hass.config_entries.flow.async_configure(
- result["flow_id"],
- user_input={CONF_ROOM_NAME: "Beach House"},
- )
- assert result["type"] == "create_entry"
- assert result["title"] == "Beach House"
- assert result["data"][CONF_ROOM_NAME] == "Beach House"
- # ---------------------------------------------------------------------------
- # Options flow — sync_mode step
- # ---------------------------------------------------------------------------
- async def test_options_sync_mode_manual(hass: HomeAssistant, mock_entry):
- mock_entry.add_to_hass(hass)
- result = await hass.config_entries.options.async_init(mock_entry.entry_id)
- assert result["type"] == "form"
- assert result["step_id"] == "sync_mode"
- result = await hass.config_entries.options.async_configure(
- result["flow_id"],
- user_input={CONF_SYNC_MODE: SYNC_MODE_MANUAL},
- )
- assert result["type"] == "form"
- assert result["step_id"] == "defaults"
- result = await hass.config_entries.options.async_configure(
- result["flow_id"],
- user_input=_EMPTY_DEFAULTS,
- )
- assert result["type"] == "create_entry"
- assert result["data"][CONF_SYNC_MODE] == SYNC_MODE_MANUAL
- async def test_options_sync_mode_caldav_proceeds_to_caldav_step(hass: HomeAssistant, mock_entry):
- mock_entry.add_to_hass(hass)
- result = await hass.config_entries.options.async_init(mock_entry.entry_id)
- result = await hass.config_entries.options.async_configure(
- result["flow_id"],
- user_input={CONF_SYNC_MODE: SYNC_MODE_CALDAV},
- )
- assert result["type"] == "form"
- assert result["step_id"] == "caldav"
- async def test_options_sync_mode_api_proceeds_to_api_step(hass: HomeAssistant, mock_entry):
- mock_entry.add_to_hass(hass)
- result = await hass.config_entries.options.async_init(mock_entry.entry_id)
- result = await hass.config_entries.options.async_configure(
- result["flow_id"],
- user_input={CONF_SYNC_MODE: SYNC_MODE_API},
- )
- assert result["type"] == "form"
- assert result["step_id"] == "api"
- # ---------------------------------------------------------------------------
- # Options flow — CalDAV step
- # ---------------------------------------------------------------------------
- async def test_options_caldav_saves_on_success(hass: HomeAssistant, mock_entry):
- mock_entry.add_to_hass(hass)
- result = await hass.config_entries.options.async_init(mock_entry.entry_id)
- await hass.config_entries.options.async_configure(
- result["flow_id"], user_input={CONF_SYNC_MODE: SYNC_MODE_CALDAV}
- )
- with patch("custom_components.room_cal_ha.config_flow._test_caldav_auth", return_value=None):
- result = await hass.config_entries.options.async_configure(
- result["flow_id"],
- user_input={
- CONF_CALDAV_URL: "https://cal.example.com",
- CONF_CALENDAR_NAME: "Room",
- CONF_USERNAME: "user",
- CONF_PASSWORD: "pass",
- CONF_REFRESH_INTERVAL: 30,
- },
- )
- assert result["type"] == "form"
- assert result["step_id"] == "defaults"
- result = await hass.config_entries.options.async_configure(
- result["flow_id"],
- user_input=_EMPTY_DEFAULTS,
- )
- assert result["type"] == "create_entry"
- assert result["data"][CONF_SYNC_MODE] == SYNC_MODE_CALDAV
- assert result["data"][CONF_CALDAV_URL] == "https://cal.example.com"
- assert result["data"][CONF_REFRESH_INTERVAL] == 30
- async def test_options_caldav_bad_credentials_shows_error(hass: HomeAssistant, mock_entry):
- mock_entry.add_to_hass(hass)
- result = await hass.config_entries.options.async_init(mock_entry.entry_id)
- await hass.config_entries.options.async_configure(
- result["flow_id"], user_input={CONF_SYNC_MODE: SYNC_MODE_CALDAV}
- )
- with patch(
- "custom_components.room_cal_ha.config_flow._test_caldav_auth",
- side_effect=caldav_error.AuthorizationError,
- ):
- result = await hass.config_entries.options.async_configure(
- result["flow_id"],
- user_input={
- CONF_CALDAV_URL: "https://cal.example.com",
- CONF_CALENDAR_NAME: "Room",
- CONF_USERNAME: "user",
- CONF_PASSWORD: "bad",
- CONF_REFRESH_INTERVAL: 15,
- },
- )
- assert result["type"] == "form"
- assert result["errors"]["base"] == "invalid_auth"
- async def test_options_caldav_connect_error_shows_error(hass: HomeAssistant, mock_entry):
- mock_entry.add_to_hass(hass)
- result = await hass.config_entries.options.async_init(mock_entry.entry_id)
- await hass.config_entries.options.async_configure(
- result["flow_id"], user_input={CONF_SYNC_MODE: SYNC_MODE_CALDAV}
- )
- with patch(
- "custom_components.room_cal_ha.config_flow._test_caldav_auth",
- side_effect=Exception("timeout"),
- ):
- result = await hass.config_entries.options.async_configure(
- result["flow_id"],
- user_input={
- CONF_CALDAV_URL: "https://cal.example.com",
- CONF_CALENDAR_NAME: "Room",
- CONF_USERNAME: "user",
- CONF_PASSWORD: "pass",
- CONF_REFRESH_INTERVAL: 15,
- },
- )
- assert result["type"] == "form"
- assert result["errors"]["base"] == "cannot_connect"
- # ---------------------------------------------------------------------------
- # Options flow — API step
- # ---------------------------------------------------------------------------
- async def test_options_api_saves_on_success(hass: HomeAssistant, mock_entry):
- mock_entry.add_to_hass(hass)
- result = await hass.config_entries.options.async_init(mock_entry.entry_id)
- await hass.config_entries.options.async_configure(
- result["flow_id"], user_input={CONF_SYNC_MODE: SYNC_MODE_API}
- )
- with patch(
- "custom_components.room_cal_ha.config_flow._test_api_connection",
- new=AsyncMock(return_value=None),
- ):
- result = await hass.config_entries.options.async_configure(
- result["flow_id"],
- user_input={
- CONF_API_BASE_URL: "https://api.example.com",
- CONF_API_TOKEN: "tok-secret",
- CONF_REFRESH_INTERVAL: 10,
- },
- )
- assert result["type"] == "form"
- assert result["step_id"] == "defaults"
- result = await hass.config_entries.options.async_configure(
- result["flow_id"],
- user_input=_EMPTY_DEFAULTS,
- )
- assert result["type"] == "create_entry"
- assert result["data"][CONF_SYNC_MODE] == SYNC_MODE_API
- assert result["data"][CONF_API_BASE_URL] == "https://api.example.com"
- assert result["data"][CONF_REFRESH_INTERVAL] == 10
- async def test_options_api_bad_token_shows_error(hass: HomeAssistant, mock_entry):
- from custom_components.room_cal_ha.config_flow import _ApiAuthError
- mock_entry.add_to_hass(hass)
- result = await hass.config_entries.options.async_init(mock_entry.entry_id)
- await hass.config_entries.options.async_configure(
- result["flow_id"], user_input={CONF_SYNC_MODE: SYNC_MODE_API}
- )
- with patch(
- "custom_components.room_cal_ha.config_flow._test_api_connection",
- new=AsyncMock(side_effect=_ApiAuthError),
- ):
- result = await hass.config_entries.options.async_configure(
- result["flow_id"],
- user_input={
- CONF_API_BASE_URL: "https://api.example.com",
- CONF_API_TOKEN: "bad-token",
- CONF_REFRESH_INTERVAL: 15,
- },
- )
- assert result["type"] == "form"
- assert result["errors"]["base"] == "invalid_auth"
- async def test_options_api_connect_error_shows_error(hass: HomeAssistant, mock_entry):
- mock_entry.add_to_hass(hass)
- result = await hass.config_entries.options.async_init(mock_entry.entry_id)
- await hass.config_entries.options.async_configure(
- result["flow_id"], user_input={CONF_SYNC_MODE: SYNC_MODE_API}
- )
- with patch(
- "custom_components.room_cal_ha.config_flow._test_api_connection",
- new=AsyncMock(side_effect=Exception("timeout")),
- ):
- result = await hass.config_entries.options.async_configure(
- result["flow_id"],
- user_input={
- CONF_API_BASE_URL: "https://api.example.com",
- CONF_API_TOKEN: "tok",
- CONF_REFRESH_INTERVAL: 15,
- },
- )
- assert result["type"] == "form"
- assert result["errors"]["base"] == "cannot_connect"
- # ---------------------------------------------------------------------------
- # Options flow — defaults step
- # ---------------------------------------------------------------------------
- async def _reach_defaults_step(hass: HomeAssistant, mock_entry):
- """Navigate to the defaults step via manual sync mode."""
- mock_entry.add_to_hass(hass)
- result = await hass.config_entries.options.async_init(mock_entry.entry_id)
- result = await hass.config_entries.options.async_configure(
- result["flow_id"], user_input={CONF_SYNC_MODE: SYNC_MODE_MANUAL}
- )
- assert result["step_id"] == "defaults"
- return result
- async def test_options_defaults_saves_values(hass: HomeAssistant, mock_entry):
- result = await _reach_defaults_step(hass, mock_entry)
- result = await hass.config_entries.options.async_configure(
- result["flow_id"],
- user_input={
- "guest_name": "Default Guest",
- "check_in_time": "15:00",
- "check_out_time": "11:00",
- "wifi_ssid": "HomeNet",
- "wifi_key": "secret",
- "door_code": "1234",
- },
- )
- assert result["type"] == "create_entry"
- defaults = result["data"][CONF_RESERVATION_DEFAULTS]
- assert defaults["guest_name"] == "Default Guest"
- assert defaults["check_in_time"] == "15:00"
- assert defaults["check_out_time"] == "11:00"
- assert defaults["wifi_ssid"] == "HomeNet"
- assert defaults["wifi_key"] == "secret"
- assert defaults["door_code"] == "1234"
- async def test_options_defaults_empty_strings_become_none(hass: HomeAssistant, mock_entry):
- result = await _reach_defaults_step(hass, mock_entry)
- result = await hass.config_entries.options.async_configure(
- result["flow_id"],
- user_input=_EMPTY_DEFAULTS,
- )
- assert result["type"] == "create_entry"
- defaults = result["data"][CONF_RESERVATION_DEFAULTS]
- assert defaults["guest_name"] is None
- assert defaults["check_in_time"] is None
- assert defaults["wifi_ssid"] is None
- async def test_options_defaults_invalid_time_shows_error(hass: HomeAssistant, mock_entry):
- result = await _reach_defaults_step(hass, mock_entry)
- result = await hass.config_entries.options.async_configure(
- result["flow_id"],
- user_input={**_EMPTY_DEFAULTS, "check_in_time": "not-a-time"},
- )
- assert result["type"] == "form"
- assert "check_in_time" in result["errors"]
|