From dcd2d428940ef1f46cac738ae2b085dff9c64486 Mon Sep 17 00:00:00 2001 From: Joost Lekkerkerker <joostlek@outlook.com> Date: Mon, 3 Mar 2025 20:07:07 +0100 Subject: [PATCH] Abort SmartThings flow if default_config is not enabled (#139700) * Abort SmartThings flow if default_config is not enabled * Abort SmartThings flow if default_config is not enabled * Abort SmartThings flow if default_config is not enabled --- .../components/smartthings/config_flow.py | 11 +++ .../components/smartthings/strings.json | 3 +- .../smartthings/test_config_flow.py | 82 +++++++++++++++++-- 3 files changed, 89 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/smartthings/config_flow.py b/homeassistant/components/smartthings/config_flow.py index 02b11b190c9..d2654348527 100644 --- a/homeassistant/components/smartthings/config_flow.py +++ b/homeassistant/components/smartthings/config_flow.py @@ -32,6 +32,17 @@ class SmartThingsConfigFlow(AbstractOAuth2FlowHandler, domain=DOMAIN): """Extra data that needs to be appended to the authorize url.""" return {"scope": " ".join(REQUESTED_SCOPES)} + async def async_step_user( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Check we have the cloud integration set up.""" + if "cloud" not in self.hass.config.components: + return self.async_abort( + reason="cloud_not_enabled", + description_placeholders={"default_config": "default_config"}, + ) + return await super().async_step_user(user_input) + async def async_oauth_create_entry(self, data: dict[str, Any]) -> ConfigFlowResult: """Create an entry for SmartThings.""" if not set(data[CONF_TOKEN]["scope"].split()) >= set(SCOPES): diff --git a/homeassistant/components/smartthings/strings.json b/homeassistant/components/smartthings/strings.json index 9fd417284af..844ebd12004 100644 --- a/homeassistant/components/smartthings/strings.json +++ b/homeassistant/components/smartthings/strings.json @@ -24,7 +24,8 @@ "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]", "reauth_account_mismatch": "Authenticated account does not match the account to be reauthenticated. Please log in with the correct account and pick the right location.", "reauth_location_mismatch": "Authenticated location does not match the location to be reauthenticated. Please log in with the correct account and pick the right location.", - "missing_scopes": "Authentication failed. Please make sure you have granted all required permissions." + "missing_scopes": "Authentication failed. Please make sure you have granted all required permissions.", + "cloud_not_enabled": "Please make sure you run Home Assistant with `{default_config}` enabled in your configuration.yaml." } }, "entity": { diff --git a/tests/components/smartthings/test_config_flow.py b/tests/components/smartthings/test_config_flow.py index a16747c1190..7472d7d6b71 100644 --- a/tests/components/smartthings/test_config_flow.py +++ b/tests/components/smartthings/test_config_flow.py @@ -28,7 +28,13 @@ from tests.test_util.aiohttp import AiohttpClientMocker from tests.typing import ClientSessionGenerator -@pytest.mark.usefixtures("current_request_with_host") +@pytest.fixture +def use_cloud(hass: HomeAssistant) -> None: + """Set up the cloud component.""" + hass.config.components.add("cloud") + + +@pytest.mark.usefixtures("current_request_with_host", "use_cloud") async def test_full_flow( hass: HomeAssistant, hass_client_no_auth: ClientSessionGenerator, @@ -100,7 +106,7 @@ async def test_full_flow( assert result["result"].unique_id == "397678e5-9995-4a39-9d9f-ae6ba310236c" -@pytest.mark.usefixtures("current_request_with_host") +@pytest.mark.usefixtures("current_request_with_host", "use_cloud") async def test_not_enough_scopes( hass: HomeAssistant, hass_client_no_auth: ClientSessionGenerator, @@ -161,7 +167,7 @@ async def test_not_enough_scopes( assert result["reason"] == "missing_scopes" -@pytest.mark.usefixtures("current_request_with_host") +@pytest.mark.usefixtures("current_request_with_host", "use_cloud") async def test_duplicate_entry( hass: HomeAssistant, hass_client_no_auth: ClientSessionGenerator, @@ -224,6 +230,23 @@ async def test_duplicate_entry( @pytest.mark.usefixtures("current_request_with_host") +async def test_no_cloud( + hass: HomeAssistant, + hass_client_no_auth: ClientSessionGenerator, + aioclient_mock: AiohttpClientMocker, + mock_smartthings: AsyncMock, + mock_setup_entry: AsyncMock, +) -> None: + """Check we abort when cloud is not enabled.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "cloud_not_enabled" + + +@pytest.mark.usefixtures("current_request_with_host", "use_cloud") async def test_reauthentication( hass: HomeAssistant, hass_client_no_auth: ClientSessionGenerator, @@ -285,7 +308,7 @@ async def test_reauthentication( } -@pytest.mark.usefixtures("current_request_with_host") +@pytest.mark.usefixtures("current_request_with_host", "use_cloud") async def test_reauthentication_wrong_scopes( hass: HomeAssistant, hass_client_no_auth: ClientSessionGenerator, @@ -336,7 +359,7 @@ async def test_reauthentication_wrong_scopes( assert result["reason"] == "missing_scopes" -@pytest.mark.usefixtures("current_request_with_host") +@pytest.mark.usefixtures("current_request_with_host", "use_cloud") async def test_reauth_account_mismatch( hass: HomeAssistant, hass_client_no_auth: ClientSessionGenerator, @@ -388,6 +411,29 @@ async def test_reauth_account_mismatch( @pytest.mark.usefixtures("current_request_with_host") +async def test_reauthentication_no_cloud( + hass: HomeAssistant, + hass_client_no_auth: ClientSessionGenerator, + aioclient_mock: AiohttpClientMocker, + mock_smartthings: AsyncMock, + mock_setup_entry: AsyncMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test SmartThings reauthentication without cloud.""" + mock_config_entry.add_to_hass(hass) + + result = await mock_config_entry.start_reauth_flow(hass) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "reauth_confirm" + + result = await hass.config_entries.flow.async_configure(result["flow_id"], {}) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "cloud_not_enabled" + + +@pytest.mark.usefixtures("current_request_with_host", "use_cloud") async def test_migration( hass: HomeAssistant, hass_client_no_auth: ClientSessionGenerator, @@ -468,7 +514,7 @@ async def test_migration( assert mock_old_config_entry.minor_version == 1 -@pytest.mark.usefixtures("current_request_with_host") +@pytest.mark.usefixtures("current_request_with_host", "use_cloud") async def test_migration_wrong_location( hass: HomeAssistant, hass_client_no_auth: ClientSessionGenerator, @@ -539,3 +585,27 @@ async def test_migration_wrong_location( ) assert mock_old_config_entry.version == 3 assert mock_old_config_entry.minor_version == 1 + + +@pytest.mark.usefixtures("current_request_with_host") +async def test_migration_no_cloud( + hass: HomeAssistant, + hass_client_no_auth: ClientSessionGenerator, + aioclient_mock: AiohttpClientMocker, + mock_smartthings: AsyncMock, + mock_old_config_entry: MockConfigEntry, +) -> None: + """Test SmartThings reauthentication with different account.""" + mock_old_config_entry.add_to_hass(hass) + + await hass.config_entries.async_setup(mock_old_config_entry.entry_id) + await hass.async_block_till_done() + + assert mock_old_config_entry.state is ConfigEntryState.SETUP_ERROR + + result = hass.config_entries.flow.async_progress()[0] + + result = await hass.config_entries.flow.async_configure(result["flow_id"], {}) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "cloud_not_enabled" -- GitLab