async def async_step_authorize(self, user_input=None): """Wait for the user to authorize the app installation.""" user_input = {} if user_input is None else user_input self.installed_app_id = user_input.get(CONF_INSTALLED_APP_ID) self.refresh_token = user_input.get(CONF_REFRESH_TOKEN) if self.installed_app_id is None: # Launch the external setup URL url = format_install_url(self.app_id, self.location_id) return self.async_external_step(step_id="authorize", url=url) return self.async_external_step_done(next_step_id="install")
async def test_step_select_location_advances(hass): """Test select location aborts if no available locations.""" location_id = str(uuid4()) app_id = str(uuid4()) flow = SmartThingsFlowHandler() flow.hass = hass flow.app_id = app_id result = await flow.async_step_select_location( {CONF_LOCATION_ID: location_id}) assert flow.location_id == location_id assert result["type"] == data_entry_flow.RESULT_TYPE_EXTERNAL_STEP assert result["step_id"] == "authorize" assert result["url"] == format_install_url(app_id, location_id)
async def test_entry_created(hass, app, app_oauth_client, location, smartthings_mock): """Test local webhook, new app, install event creates entry.""" token = str(uuid4()) installed_app_id = str(uuid4()) refresh_token = str(uuid4()) smartthings_mock.apps.return_value = [] smartthings_mock.create_app.return_value = (app, app_oauth_client) smartthings_mock.locations.return_value = [location] request = Mock() request.installed_app_id = installed_app_id request.auth_token = token request.location_id = location.location_id request.refresh_token = refresh_token # Webhook confirmation shown result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": "user"}) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["step_id"] == "user" assert result["description_placeholders"][ "webhook_url"] == smartapp.get_webhook_url(hass) # Advance to PAT screen result = await hass.config_entries.flow.async_configure( result["flow_id"], {}) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["step_id"] == "pat" assert "token_url" in result["description_placeholders"] assert "component_url" in result["description_placeholders"] # Enter token and advance to location screen result = await hass.config_entries.flow.async_configure( result["flow_id"], {CONF_ACCESS_TOKEN: token}) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["step_id"] == "select_location" # Select location and advance to external auth result = await hass.config_entries.flow.async_configure( result["flow_id"], {CONF_LOCATION_ID: location.location_id}) assert result["type"] == data_entry_flow.RESULT_TYPE_EXTERNAL_STEP assert result["step_id"] == "authorize" assert result["url"] == format_install_url(app.app_id, location.location_id) # Complete external auth and advance to install await smartapp.smartapp_install(hass, request, None, app) # Finish result = await hass.config_entries.flow.async_configure(result["flow_id"]) assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["data"]["app_id"] == app.app_id assert result["data"]["installed_app_id"] == installed_app_id assert result["data"]["location_id"] == location.location_id assert result["data"]["access_token"] == token assert result["data"]["refresh_token"] == request.refresh_token assert result["data"][CONF_CLIENT_SECRET] == app_oauth_client.client_secret assert result["data"][CONF_CLIENT_ID] == app_oauth_client.client_id assert result["title"] == location.name entry = next( (entry for entry in hass.config_entries.async_entries(DOMAIN)), None, ) assert entry.unique_id == smartapp.format_unique_id( app.app_id, location.location_id)
async def test_entry_created_with_cloudhook(hass, app, app_oauth_client, location, smartthings_mock): """Test cloud, new app, install event creates entry.""" hass.config.components.add("cloud") # Unload the endpoint so we can reload it under the cloud. await smartapp.unload_smartapp_endpoint(hass) token = str(uuid4()) installed_app_id = str(uuid4()) refresh_token = str(uuid4()) smartthings_mock.apps.return_value = [] smartthings_mock.create_app = AsyncMock(return_value=(app, app_oauth_client)) smartthings_mock.locations = AsyncMock(return_value=[location]) request = Mock() request.installed_app_id = installed_app_id request.auth_token = token request.location_id = location.location_id request.refresh_token = refresh_token with patch.object(hass.components.cloud, "async_active_subscription", Mock(return_value=True)), patch.object( hass.components.cloud, "async_create_cloudhook", AsyncMock(return_value="http://cloud.test"), ) as mock_create_cloudhook: await smartapp.setup_smartapp_endpoint(hass) # Webhook confirmation shown result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": "user"}) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["step_id"] == "user" assert result["description_placeholders"][ "webhook_url"] == smartapp.get_webhook_url(hass) assert mock_create_cloudhook.call_count == 1 # Advance to PAT screen result = await hass.config_entries.flow.async_configure( result["flow_id"], {}) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["step_id"] == "pat" assert "token_url" in result["description_placeholders"] assert "component_url" in result["description_placeholders"] # Enter token and advance to location screen result = await hass.config_entries.flow.async_configure( result["flow_id"], {CONF_ACCESS_TOKEN: token}) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["step_id"] == "select_location" # Select location and advance to external auth result = await hass.config_entries.flow.async_configure( result["flow_id"], {CONF_LOCATION_ID: location.location_id}) assert result["type"] == data_entry_flow.RESULT_TYPE_EXTERNAL_STEP assert result["step_id"] == "authorize" assert result["url"] == format_install_url(app.app_id, location.location_id) # Complete external auth and advance to install await smartapp.smartapp_install(hass, request, None, app) # Finish result = await hass.config_entries.flow.async_configure( result["flow_id"]) assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["data"]["app_id"] == app.app_id assert result["data"]["installed_app_id"] == installed_app_id assert result["data"]["location_id"] == location.location_id assert result["data"]["access_token"] == token assert result["data"]["refresh_token"] == request.refresh_token assert result["data"][ CONF_CLIENT_SECRET] == app_oauth_client.client_secret assert result["data"][CONF_CLIENT_ID] == app_oauth_client.client_id assert result["title"] == location.name entry = next( (entry for entry in hass.config_entries.async_entries(DOMAIN)), None, ) assert entry.unique_id == smartapp.format_unique_id( app.app_id, location.location_id)
async def test_entry_created_existing_app_copies_oauth_client( hass, app, location, smartthings_mock): """Test entry is created with an existing app and copies the oauth client from another entry.""" token = str(uuid4()) installed_app_id = str(uuid4()) refresh_token = str(uuid4()) oauth_client_id = str(uuid4()) oauth_client_secret = str(uuid4()) smartthings_mock.apps.return_value = [app] smartthings_mock.locations.return_value = [location] request = Mock() request.installed_app_id = installed_app_id request.auth_token = token request.location_id = location.location_id request.refresh_token = refresh_token entry = MockConfigEntry( domain=DOMAIN, data={ CONF_APP_ID: app.app_id, CONF_CLIENT_ID: oauth_client_id, CONF_CLIENT_SECRET: oauth_client_secret, CONF_LOCATION_ID: str(uuid4()), CONF_INSTALLED_APP_ID: str(uuid4()), CONF_ACCESS_TOKEN: token, }, ) entry.add_to_hass(hass) # Webhook confirmation shown result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": "user"}) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["step_id"] == "user" assert result["description_placeholders"][ "webhook_url"] == smartapp.get_webhook_url(hass) # Advance to PAT screen result = await hass.config_entries.flow.async_configure( result["flow_id"], {}) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["step_id"] == "pat" assert "token_url" in result["description_placeholders"] assert "component_url" in result["description_placeholders"] # Assert access token is defaulted to an existing entry for convenience. assert result["data_schema"]({}) == {CONF_ACCESS_TOKEN: token} # Enter token and advance to location screen result = await hass.config_entries.flow.async_configure( result["flow_id"], {CONF_ACCESS_TOKEN: token}) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["step_id"] == "select_location" # Select location and advance to external auth result = await hass.config_entries.flow.async_configure( result["flow_id"], {CONF_LOCATION_ID: location.location_id}) assert result["type"] == data_entry_flow.RESULT_TYPE_EXTERNAL_STEP assert result["step_id"] == "authorize" assert result["url"] == format_install_url(app.app_id, location.location_id) # Complete external auth and advance to install await smartapp.smartapp_install(hass, request, None, app) # Finish result = await hass.config_entries.flow.async_configure(result["flow_id"]) assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["data"]["app_id"] == app.app_id assert result["data"]["installed_app_id"] == installed_app_id assert result["data"]["location_id"] == location.location_id assert result["data"]["access_token"] == token assert result["data"]["refresh_token"] == request.refresh_token assert result["data"][CONF_CLIENT_SECRET] == oauth_client_secret assert result["data"][CONF_CLIENT_ID] == oauth_client_id assert result["title"] == location.name entry = next( (entry for entry in hass.config_entries.async_entries(DOMAIN) if entry.data[CONF_INSTALLED_APP_ID] == installed_app_id), None, ) assert entry.unique_id == smartapp.format_unique_id( app.app_id, location.location_id)