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_ROOM_NAME, CONF_SYNC_MODE, CONF_USERNAME, DEFAULT_REFRESH_INTERVAL, DOMAIN, SYNC_MODE_API, SYNC_MODE_CALDAV, SYNC_MODE_MANUAL, ) # --------------------------------------------------------------------------- # 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"] == "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"] == "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"] == "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"