diff --git a/homeassistant/components/august/__init__.py b/homeassistant/components/august/__init__.py index 23419f4df2d..73f1cc6a1b5 100644 --- a/homeassistant/components/august/__init__.py +++ b/homeassistant/components/august/__init__.py @@ -4,169 +4,25 @@ import itertools import logging from aiohttp import ClientError, ClientResponseError -from august.authenticator import ValidationResult from august.exceptions import AugustApiAIOHTTPError -import voluptuous as vol -from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry -from homeassistant.const import ( - CONF_PASSWORD, - CONF_TIMEOUT, - CONF_USERNAME, - HTTP_UNAUTHORIZED, -) +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_PASSWORD, HTTP_UNAUTHORIZED from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError -import homeassistant.helpers.config_validation as cv from .activity import ActivityStream -from .const import ( - CONF_ACCESS_TOKEN_CACHE_FILE, - CONF_INSTALL_ID, - CONF_LOGIN_METHOD, - DATA_AUGUST, - DEFAULT_AUGUST_CONFIG_FILE, - DEFAULT_NAME, - DEFAULT_TIMEOUT, - DOMAIN, - LOGIN_METHODS, - MIN_TIME_BETWEEN_DETAIL_UPDATES, - PLATFORMS, - VERIFICATION_CODE_KEY, -) +from .const import DATA_AUGUST, DOMAIN, MIN_TIME_BETWEEN_DETAIL_UPDATES, PLATFORMS from .exceptions import CannotConnect, InvalidAuth, RequireValidation from .gateway import AugustGateway from .subscriber import AugustSubscriberMixin _LOGGER = logging.getLogger(__name__) -TWO_FA_REVALIDATE = "verify_configurator" - -CONFIG_SCHEMA = vol.Schema( - vol.All( - cv.deprecated(DOMAIN), - { - DOMAIN: vol.Schema( - { - vol.Required(CONF_LOGIN_METHOD): vol.In(LOGIN_METHODS), - vol.Required(CONF_USERNAME): cv.string, - vol.Required(CONF_PASSWORD): cv.string, - vol.Optional(CONF_INSTALL_ID): cv.string, - vol.Optional( - CONF_TIMEOUT, default=DEFAULT_TIMEOUT - ): cv.positive_int, - } - ) - }, - ), - extra=vol.ALLOW_EXTRA, -) - - -async def async_request_validation(hass, config_entry, august_gateway): - """Request a new verification code from the user.""" - - # - # In the future this should start a new config flow - # instead of using the legacy configurator - # - _LOGGER.error("Access token is no longer valid") - configurator = hass.components.configurator - entry_id = config_entry.entry_id - - async def async_august_configuration_validation_callback(data): - code = data.get(VERIFICATION_CODE_KEY) - result = await august_gateway.authenticator.async_validate_verification_code( - code - ) - - if result == ValidationResult.INVALID_VERIFICATION_CODE: - configurator.async_notify_errors( - hass.data[DOMAIN][entry_id][TWO_FA_REVALIDATE], - "Invalid verification code, please make sure you are using the latest code and try again.", - ) - elif result == ValidationResult.VALIDATED: - return await async_setup_august(hass, config_entry, august_gateway) - - return False - - if TWO_FA_REVALIDATE not in hass.data[DOMAIN][entry_id]: - await august_gateway.authenticator.async_send_verification_code() - - entry_data = config_entry.data - login_method = entry_data.get(CONF_LOGIN_METHOD) - username = entry_data.get(CONF_USERNAME) - - hass.data[DOMAIN][entry_id][TWO_FA_REVALIDATE] = configurator.async_request_config( - f"{DEFAULT_NAME} ({username})", - async_august_configuration_validation_callback, - description=( - "August must be re-verified. " - f"Please check your {login_method} ({username}) " - "and enter the verification code below" - ), - submit_caption="Verify", - fields=[ - {"id": VERIFICATION_CODE_KEY, "name": "Verification code", "type": "string"} - ], - ) - return - - -async def async_setup_august(hass, config_entry, august_gateway): - """Set up the August component.""" - - entry_id = config_entry.entry_id - hass.data[DOMAIN].setdefault(entry_id, {}) - - try: - await august_gateway.async_authenticate() - except RequireValidation: - await async_request_validation(hass, config_entry, august_gateway) - raise - - # We still use the configurator to get a new 2fa code - # when needed since config_flow doesn't have a way - # to re-request if it expires - if TWO_FA_REVALIDATE in hass.data[DOMAIN][entry_id]: - hass.components.configurator.async_request_done( - hass.data[DOMAIN][entry_id].pop(TWO_FA_REVALIDATE) - ) - - hass.data[DOMAIN][entry_id][DATA_AUGUST] = AugustData(hass, august_gateway) - - await hass.data[DOMAIN][entry_id][DATA_AUGUST].async_setup() - - for platform in PLATFORMS: - hass.async_create_task( - hass.config_entries.async_forward_entry_setup(config_entry, platform) - ) - - return True - async def async_setup(hass: HomeAssistant, config: dict): """Set up the August component from YAML.""" - - conf = config.get(DOMAIN) hass.data.setdefault(DOMAIN, {}) - - if not conf: - return True - - hass.async_create_task( - hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data={ - CONF_LOGIN_METHOD: conf.get(CONF_LOGIN_METHOD), - CONF_USERNAME: conf.get(CONF_USERNAME), - CONF_PASSWORD: conf.get(CONF_PASSWORD), - CONF_INSTALL_ID: conf.get(CONF_INSTALL_ID), - CONF_ACCESS_TOKEN_CACHE_FILE: DEFAULT_AUGUST_CONFIG_FILE, - }, - ) - ) return True @@ -184,11 +40,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): return False raise ConfigEntryNotReady from err - except InvalidAuth: + except (RequireValidation, InvalidAuth): _async_start_reauth(hass, entry) return False - except RequireValidation: - return False except (CannotConnect, asyncio.TimeoutError) as err: raise ConfigEntryNotReady from err @@ -221,6 +75,31 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): return unload_ok +async def async_setup_august(hass, config_entry, august_gateway): + """Set up the August component.""" + + if CONF_PASSWORD in config_entry.data: + # We no longer need to store passwords since we do not + # support YAML anymore + config_data = config_entry.data.copy() + del config_data[CONF_PASSWORD] + hass.config_entries.async_update_entry(config_entry, data=config_data) + + await august_gateway.async_authenticate() + + data = hass.data[DOMAIN][config_entry.entry_id] = { + DATA_AUGUST: AugustData(hass, august_gateway) + } + await data[DATA_AUGUST].async_setup() + + for platform in PLATFORMS: + hass.async_create_task( + hass.config_entries.async_forward_entry_setup(config_entry, platform) + ) + + return True + + class AugustData(AugustSubscriberMixin): """August data object.""" diff --git a/homeassistant/components/august/config_flow.py b/homeassistant/components/august/config_flow.py index f595479c0cf..29bb41947a0 100644 --- a/homeassistant/components/august/config_flow.py +++ b/homeassistant/components/august/config_flow.py @@ -5,14 +5,9 @@ from august.authenticator import ValidationResult import voluptuous as vol from homeassistant import config_entries -from homeassistant.const import CONF_PASSWORD, CONF_TIMEOUT, CONF_USERNAME +from homeassistant.const import CONF_PASSWORD, CONF_USERNAME -from .const import ( - CONF_LOGIN_METHOD, - DEFAULT_TIMEOUT, - LOGIN_METHODS, - VERIFICATION_CODE_KEY, -) +from .const import CONF_LOGIN_METHOD, LOGIN_METHODS, VERIFICATION_CODE_KEY from .const import DOMAIN # pylint:disable=unused-import from .exceptions import CannotConnect, InvalidAuth, RequireValidation from .gateway import AugustGateway @@ -68,61 +63,48 @@ class AugustConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): def __init__(self): """Store an AugustGateway().""" self._august_gateway = None - self.user_auth_details = {} + self._user_auth_details = {} self._needs_reset = False + self._mode = None super().__init__() async def async_step_user(self, user_input=None): """Handle the initial step.""" - if self._august_gateway is None: - self._august_gateway = AugustGateway(self.hass) + self._august_gateway = AugustGateway(self.hass) + return await self.async_step_user_validate() + + async def async_step_user_validate(self, user_input=None): + """Handle authentication.""" errors = {} if user_input is not None: - combined_inputs = {**self.user_auth_details, **user_input} - await self._august_gateway.async_setup(combined_inputs) - if self._needs_reset: - self._needs_reset = False - await self._august_gateway.async_reset_authentication() - - try: - info = await async_validate_input( - combined_inputs, - self._august_gateway, - ) - except CannotConnect: - errors["base"] = "cannot_connect" - except InvalidAuth: - errors["base"] = "invalid_auth" - except RequireValidation: - self.user_auth_details.update(user_input) - - return await self.async_step_validation() - except Exception: # pylint: disable=broad-except - _LOGGER.exception("Unexpected exception") - errors["base"] = "unknown" - - if not errors: - self.user_auth_details.update(user_input) - - existing_entry = await self.async_set_unique_id( - combined_inputs[CONF_USERNAME] - ) - if existing_entry: - self.hass.config_entries.async_update_entry( - existing_entry, data=info["data"] - ) - await self.hass.config_entries.async_reload(existing_entry.entry_id) - return self.async_abort(reason="reauth_successful") - return self.async_create_entry(title=info["title"], data=info["data"]) + result = await self._async_auth_or_validate(user_input, errors) + if result is not None: + return result return self.async_show_form( - step_id="user", data_schema=self._async_build_schema(), errors=errors + step_id="user_validate", + data_schema=vol.Schema( + { + vol.Required( + CONF_LOGIN_METHOD, + default=self._user_auth_details.get(CONF_LOGIN_METHOD, "phone"), + ): vol.In(LOGIN_METHODS), + vol.Required( + CONF_USERNAME, + default=self._user_auth_details.get(CONF_USERNAME), + ): str, + vol.Required(CONF_PASSWORD): str, + } + ), + errors=errors, ) async def async_step_validation(self, user_input=None): """Handle validation (2fa) step.""" if user_input: - return await self.async_step_user({**self.user_auth_details, **user_input}) + if self._mode == "reauth": + return await self.async_step_reauth_validate(user_input) + return await self.async_step_user_validate(user_input) return self.async_show_form( step_id="validation", @@ -130,34 +112,70 @@ class AugustConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): {vol.Required(VERIFICATION_CODE_KEY): vol.All(str, vol.Strip)} ), description_placeholders={ - CONF_USERNAME: self.user_auth_details.get(CONF_USERNAME), - CONF_LOGIN_METHOD: self.user_auth_details.get(CONF_LOGIN_METHOD), + CONF_USERNAME: self._user_auth_details[CONF_USERNAME], + CONF_LOGIN_METHOD: self._user_auth_details[CONF_LOGIN_METHOD], }, ) - async def async_step_import(self, user_input): - """Handle import.""" - await self.async_set_unique_id(user_input[CONF_USERNAME]) - self._abort_if_unique_id_configured() - - return await self.async_step_user(user_input) - async def async_step_reauth(self, data): """Handle configuration by re-auth.""" - self.user_auth_details = dict(data) + self._user_auth_details = dict(data) + self._mode = "reauth" self._needs_reset = True - return await self.async_step_user() + self._august_gateway = AugustGateway(self.hass) + return await self.async_step_reauth_validate() - def _async_build_schema(self): - """Generate the config flow schema.""" - base_schema = { - vol.Required(CONF_LOGIN_METHOD, default="phone"): vol.In(LOGIN_METHODS), - vol.Required(CONF_USERNAME): str, - vol.Required(CONF_PASSWORD): str, - vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): vol.Coerce(int), - } - for key in self.user_auth_details: - if key == CONF_PASSWORD or key not in base_schema: - continue - del base_schema[key] - return vol.Schema(base_schema) + async def async_step_reauth_validate(self, user_input=None): + """Handle reauth and validation.""" + errors = {} + if user_input is not None: + result = await self._async_auth_or_validate(user_input, errors) + if result is not None: + return result + + return self.async_show_form( + step_id="reauth_validate", + data_schema=vol.Schema( + { + vol.Required(CONF_PASSWORD): str, + } + ), + errors=errors, + description_placeholders={ + CONF_USERNAME: self._user_auth_details[CONF_USERNAME], + }, + ) + + async def _async_auth_or_validate(self, user_input, errors): + self._user_auth_details.update(user_input) + await self._august_gateway.async_setup(self._user_auth_details) + if self._needs_reset: + self._needs_reset = False + await self._august_gateway.async_reset_authentication() + try: + info = await async_validate_input( + self._user_auth_details, + self._august_gateway, + ) + except CannotConnect: + errors["base"] = "cannot_connect" + except InvalidAuth: + errors["base"] = "invalid_auth" + except RequireValidation: + return await self.async_step_validation() + except Exception: # pylint: disable=broad-except + _LOGGER.exception("Unexpected exception") + errors["base"] = "unknown" + + if errors: + return None + + existing_entry = await self.async_set_unique_id( + self._user_auth_details[CONF_USERNAME] + ) + if not existing_entry: + return self.async_create_entry(title=info["title"], data=info["data"]) + + self.hass.config_entries.async_update_entry(existing_entry, data=info["data"]) + await self.hass.config_entries.async_reload(existing_entry.entry_id) + return self.async_abort(reason="reauth_successful") diff --git a/homeassistant/components/august/gateway.py b/homeassistant/components/august/gateway.py index b72bb52e710..f71541e82fc 100644 --- a/homeassistant/components/august/gateway.py +++ b/homeassistant/components/august/gateway.py @@ -21,6 +21,7 @@ from .const import ( CONF_INSTALL_ID, CONF_LOGIN_METHOD, DEFAULT_AUGUST_CONFIG_FILE, + DEFAULT_TIMEOUT, VERIFICATION_CODE_KEY, ) from .exceptions import CannotConnect, InvalidAuth, RequireValidation @@ -52,9 +53,7 @@ class AugustGateway: return { CONF_LOGIN_METHOD: self._config[CONF_LOGIN_METHOD], CONF_USERNAME: self._config[CONF_USERNAME], - CONF_PASSWORD: self._config[CONF_PASSWORD], CONF_INSTALL_ID: self._config.get(CONF_INSTALL_ID), - CONF_TIMEOUT: self._config.get(CONF_TIMEOUT), CONF_ACCESS_TOKEN_CACHE_FILE: self._access_token_cache_file, } @@ -70,14 +69,15 @@ class AugustGateway: self._config = conf self.api = ApiAsync( - self._aiohttp_session, timeout=self._config.get(CONF_TIMEOUT) + self._aiohttp_session, + timeout=self._config.get(CONF_TIMEOUT, DEFAULT_TIMEOUT), ) self.authenticator = AuthenticatorAsync( self.api, self._config[CONF_LOGIN_METHOD], self._config[CONF_USERNAME], - self._config[CONF_PASSWORD], + self._config.get(CONF_PASSWORD, ""), install_id=self._config.get(CONF_INSTALL_ID), access_token_cache_file=self._hass.config.path( self._access_token_cache_file @@ -128,14 +128,15 @@ class AugustGateway: async def async_refresh_access_token_if_needed(self): """Refresh the august access token if needed.""" - if self.authenticator.should_refresh(): - async with self._token_refresh_lock: - refreshed_authentication = ( - await self.authenticator.async_refresh_access_token(force=False) - ) - _LOGGER.info( - "Refreshed august access token. The old token expired at %s, and the new token expires at %s", - self.authentication.access_token_expires, - refreshed_authentication.access_token_expires, - ) - self.authentication = refreshed_authentication + if not self.authenticator.should_refresh(): + return + async with self._token_refresh_lock: + refreshed_authentication = ( + await self.authenticator.async_refresh_access_token(force=False) + ) + _LOGGER.info( + "Refreshed august access token. The old token expired at %s, and the new token expires at %s", + self.authentication.access_token_expires, + refreshed_authentication.access_token_expires, + ) + self.authentication = refreshed_authentication diff --git a/homeassistant/components/august/manifest.json b/homeassistant/components/august/manifest.json index dcdfb0a0497..91733b6822e 100644 --- a/homeassistant/components/august/manifest.json +++ b/homeassistant/components/august/manifest.json @@ -3,7 +3,6 @@ "name": "August", "documentation": "https://www.home-assistant.io/integrations/august", "requirements": ["py-august==0.25.2"], - "dependencies": ["configurator"], "codeowners": ["@bdraco"], "dhcp": [ {"hostname":"connect","macaddress":"D86162*"}, diff --git a/homeassistant/components/august/strings.json b/homeassistant/components/august/strings.json index 998d870e629..7939fb1d25f 100644 --- a/homeassistant/components/august/strings.json +++ b/homeassistant/components/august/strings.json @@ -17,15 +17,21 @@ }, "description": "Please check your {login_method} ({username}) and enter the verification code below" }, - "user": { + "user_validate": { "description": "If the Login Method is 'email', Username is the email address. If the Login Method is 'phone', Username is the phone number in the format '+NNNNNNNNN'.", "data": { - "timeout": "Timeout (seconds)", "password": "[%key:common::config_flow::data::password%]", "username": "[%key:common::config_flow::data::username%]", "login_method": "Login Method" }, "title": "Setup an August account" + }, + "reauth_validate": { + "description": "Enter the password for {username}.", + "data": { + "password": "[%key:common::config_flow::data::password%]" + }, + "title": "Reauthenticate an August account" } } } diff --git a/homeassistant/components/august/translations/en.json b/homeassistant/components/august/translations/en.json index c6c19321d8a..f2ceef78d48 100644 --- a/homeassistant/components/august/translations/en.json +++ b/homeassistant/components/august/translations/en.json @@ -10,11 +10,17 @@ "unknown": "Unexpected error" }, "step": { - "user": { + "reauth_validate": { + "data": { + "password": "Password" + }, + "description": "Enter the password for {username}.", + "title": "Reauthenticate an August account" + }, + "user_validate": { "data": { "login_method": "Login Method", "password": "Password", - "timeout": "Timeout (seconds)", "username": "Username" }, "description": "If the Login Method is 'email', Username is the email address. If the Login Method is 'phone', Username is the phone number in the format '+NNNNNNNNN'.", diff --git a/tests/components/august/mocks.py b/tests/components/august/mocks.py index e02e1ec59dd..928b753af52 100644 --- a/tests/components/august/mocks.py +++ b/tests/components/august/mocks.py @@ -22,15 +22,10 @@ from august.authenticator import AuthenticationState from august.doorbell import Doorbell, DoorbellDetail from august.lock import Lock, LockDetail -from homeassistant.components.august import ( - CONF_LOGIN_METHOD, - CONF_PASSWORD, - CONF_USERNAME, - DOMAIN, -) -from homeassistant.setup import async_setup_component +from homeassistant.components.august.const import CONF_LOGIN_METHOD, DOMAIN +from homeassistant.const import CONF_PASSWORD, CONF_USERNAME -from tests.common import load_fixture +from tests.common import MockConfigEntry, load_fixture def _mock_get_config(): @@ -61,7 +56,13 @@ async def _mock_setup_august(hass, api_instance, authenticate_mock, api_mock): ) ) api_mock.return_value = api_instance - assert await async_setup_component(hass, DOMAIN, _mock_get_config()) + entry = MockConfigEntry( + domain=DOMAIN, + data=_mock_get_config()[DOMAIN], + options={}, + ) + entry.add_to_hass(hass) + assert await hass.config_entries.async_setup(entry.entry_id) await hass.async_block_till_done() return True diff --git a/tests/components/august/test_config_flow.py b/tests/components/august/test_config_flow.py index c1e7c9bb3c5..205c5c70689 100644 --- a/tests/components/august/test_config_flow.py +++ b/tests/components/august/test_config_flow.py @@ -54,9 +54,7 @@ async def test_form(hass): assert result2["data"] == { CONF_LOGIN_METHOD: "email", CONF_USERNAME: "my@email.tld", - CONF_PASSWORD: "test-password", CONF_INSTALL_ID: None, - CONF_TIMEOUT: 10, CONF_ACCESS_TOKEN_CACHE_FILE: ".my@email.tld.august.conf", } assert len(mock_setup.mock_calls) == 1 @@ -215,9 +213,7 @@ async def test_form_needs_validate(hass): assert result4["data"] == { CONF_LOGIN_METHOD: "email", CONF_USERNAME: "my@email.tld", - CONF_PASSWORD: "test-password", CONF_INSTALL_ID: None, - CONF_TIMEOUT: 10, CONF_ACCESS_TOKEN_CACHE_FILE: ".my@email.tld.august.conf", } assert len(mock_setup.mock_calls) == 1 @@ -268,3 +264,75 @@ async def test_form_reauth(hass): assert result2["reason"] == "reauth_successful" assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_form_reauth_with_2fa(hass): + """Test reauthenticate with 2fa.""" + + entry = MockConfigEntry( + domain=DOMAIN, + data={ + CONF_LOGIN_METHOD: "email", + CONF_USERNAME: "my@email.tld", + CONF_PASSWORD: "test-password", + CONF_INSTALL_ID: None, + CONF_TIMEOUT: 10, + CONF_ACCESS_TOKEN_CACHE_FILE: ".my@email.tld.august.conf", + }, + unique_id="my@email.tld", + ) + entry.add_to_hass(hass) + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": "reauth"}, data=entry.data + ) + assert result["type"] == "form" + assert result["errors"] == {} + + with patch( + "homeassistant.components.august.config_flow.AugustGateway.async_authenticate", + side_effect=RequireValidation, + ), patch( + "homeassistant.components.august.gateway.AuthenticatorAsync.async_send_verification_code", + return_value=True, + ) as mock_send_verification_code: + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + CONF_PASSWORD: "new-test-password", + }, + ) + await hass.async_block_till_done() + + assert len(mock_send_verification_code.mock_calls) == 1 + assert result2["type"] == "form" + assert result2["errors"] is None + assert result2["step_id"] == "validation" + + # Try with the CORRECT verification code and we setup + with patch( + "homeassistant.components.august.config_flow.AugustGateway.async_authenticate", + return_value=True, + ), patch( + "homeassistant.components.august.gateway.AuthenticatorAsync.async_validate_verification_code", + return_value=ValidationResult.VALIDATED, + ) as mock_validate_verification_code, patch( + "homeassistant.components.august.gateway.AuthenticatorAsync.async_send_verification_code", + return_value=True, + ) as mock_send_verification_code, patch( + "homeassistant.components.august.async_setup", return_value=True + ) as mock_setup, patch( + "homeassistant.components.august.async_setup_entry", return_value=True + ) as mock_setup_entry: + result3 = await hass.config_entries.flow.async_configure( + result2["flow_id"], + {VERIFICATION_CODE_KEY: "correct"}, + ) + await hass.async_block_till_done() + + assert len(mock_validate_verification_code.mock_calls) == 1 + assert len(mock_send_verification_code.mock_calls) == 0 + assert result3["type"] == "abort" + assert result3["reason"] == "reauth_successful" + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/august/test_init.py b/tests/components/august/test_init.py index e881ac09c97..d0116d2c586 100644 --- a/tests/components/august/test_init.py +++ b/tests/components/august/test_init.py @@ -7,13 +7,7 @@ from august.authenticator_common import AuthenticationState from august.exceptions import AugustApiAIOHTTPError from homeassistant import setup -from homeassistant.components.august.const import ( - CONF_ACCESS_TOKEN_CACHE_FILE, - CONF_INSTALL_ID, - CONF_LOGIN_METHOD, - DEFAULT_AUGUST_CONFIG_FILE, - DOMAIN, -) +from homeassistant.components.august.const import DOMAIN from homeassistant.components.lock import DOMAIN as LOCK_DOMAIN from homeassistant.config_entries import ( ENTRY_STATE_SETUP_ERROR, @@ -21,16 +15,12 @@ from homeassistant.config_entries import ( ) from homeassistant.const import ( ATTR_ENTITY_ID, - CONF_PASSWORD, - CONF_TIMEOUT, - CONF_USERNAME, SERVICE_LOCK, SERVICE_UNLOCK, STATE_LOCKED, STATE_ON, ) from homeassistant.exceptions import HomeAssistantError -from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry from tests.components.august.mocks import ( @@ -149,35 +139,6 @@ async def test_lock_has_doorsense(hass): assert binary_sensor_missing_doorsense_id_name_open is None -async def test_set_up_from_yaml(hass): - """Test to make sure config is imported from yaml.""" - - await setup.async_setup_component(hass, "persistent_notification", {}) - with patch( - "homeassistant.components.august.async_setup_august", - return_value=True, - ) as mock_setup_august, patch( - "homeassistant.components.august.config_flow.AugustGateway.async_authenticate", - return_value=True, - ): - assert await async_setup_component(hass, DOMAIN, _mock_get_config()) - await hass.async_block_till_done() - assert len(mock_setup_august.mock_calls) == 1 - call = mock_setup_august.call_args - args, _ = call - imported_config_entry = args[1] - # The import must use DEFAULT_AUGUST_CONFIG_FILE so they - # do not loose their token when config is migrated - assert imported_config_entry.data == { - CONF_ACCESS_TOKEN_CACHE_FILE: DEFAULT_AUGUST_CONFIG_FILE, - CONF_INSTALL_ID: None, - CONF_LOGIN_METHOD: "email", - CONF_PASSWORD: "mocked_password", - CONF_TIMEOUT: None, - CONF_USERNAME: "mocked_username", - } - - async def test_auth_fails(hass): """Config entry state is ENTRY_STATE_SETUP_ERROR when auth fails.""" @@ -201,7 +162,7 @@ async def test_auth_fails(hass): flows = hass.config_entries.flow.async_progress() - assert flows[0]["step_id"] == "user" + assert flows[0]["step_id"] == "reauth_validate" async def test_bad_password(hass): @@ -229,7 +190,7 @@ async def test_bad_password(hass): flows = hass.config_entries.flow.async_progress() - assert flows[0]["step_id"] == "user" + assert flows[0]["step_id"] == "reauth_validate" async def test_http_failure(hass): @@ -279,7 +240,7 @@ async def test_unknown_auth_state(hass): flows = hass.config_entries.flow.async_progress() - assert flows[0]["step_id"] == "user" + assert flows[0]["step_id"] == "reauth_validate" async def test_requires_validation_state(hass): @@ -305,4 +266,5 @@ async def test_requires_validation_state(hass): assert config_entry.state == ENTRY_STATE_SETUP_ERROR - assert hass.config_entries.flow.async_progress() == [] + assert len(hass.config_entries.flow.async_progress()) == 1 + assert hass.config_entries.flow.async_progress()[0]["context"]["source"] == "reauth"