Disable Aladdin Connect (#120558)

Co-authored-by: Robert Resch <robert@resch.dev>
This commit is contained in:
Joost Lekkerkerker 2024-06-26 15:41:20 +02:00 committed by GitHub
parent d0f82d6f02
commit 66a803e56c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 249 additions and 245 deletions

View File

@ -1,9 +1,9 @@
"""The Aladdin Connect Genie integration.""" """The Aladdin Connect Genie integration."""
# mypy: ignore-errors
from __future__ import annotations from __future__ import annotations
from genie_partner_sdk.client import AladdinConnectClient # from genie_partner_sdk.client import AladdinConnectClient
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform from homeassistant.const import Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant

View File

@ -1,10 +1,11 @@
"""API for Aladdin Connect Genie bound to Home Assistant OAuth.""" """API for Aladdin Connect Genie bound to Home Assistant OAuth."""
# mypy: ignore-errors
from typing import cast from typing import cast
from aiohttp import ClientSession from aiohttp import ClientSession
from genie_partner_sdk.auth import Auth
# from genie_partner_sdk.auth import Auth
from homeassistant.helpers.config_entry_oauth2_flow import OAuth2Session from homeassistant.helpers.config_entry_oauth2_flow import OAuth2Session
API_URL = "https://twdvzuefzh.execute-api.us-east-2.amazonaws.com/v1" API_URL = "https://twdvzuefzh.execute-api.us-east-2.amazonaws.com/v1"

View File

@ -1,11 +1,11 @@
"""Define an object to coordinate fetching Aladdin Connect data.""" """Define an object to coordinate fetching Aladdin Connect data."""
# mypy: ignore-errors
from datetime import timedelta from datetime import timedelta
import logging import logging
from genie_partner_sdk.client import AladdinConnectClient # from genie_partner_sdk.client import AladdinConnectClient
from genie_partner_sdk.model import GarageDoor # from genie_partner_sdk.model import GarageDoor
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from homeassistant.helpers.update_coordinator import DataUpdateCoordinator

View File

@ -1,9 +1,9 @@
"""Cover Entity for Genie Garage Door.""" """Cover Entity for Genie Garage Door."""
# mypy: ignore-errors
from typing import Any from typing import Any
from genie_partner_sdk.model import GarageDoor # from genie_partner_sdk.model import GarageDoor
from homeassistant.components.cover import ( from homeassistant.components.cover import (
CoverDeviceClass, CoverDeviceClass,
CoverEntity, CoverEntity,

View File

@ -1,6 +1,6 @@
"""Defines a base Aladdin Connect entity.""" """Defines a base Aladdin Connect entity."""
# mypy: ignore-errors
from genie_partner_sdk.model import GarageDoor # from genie_partner_sdk.model import GarageDoor
from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity from homeassistant.helpers.update_coordinator import CoordinatorEntity

View File

@ -4,6 +4,7 @@
"codeowners": ["@swcloudgenie"], "codeowners": ["@swcloudgenie"],
"config_flow": true, "config_flow": true,
"dependencies": ["application_credentials"], "dependencies": ["application_credentials"],
"disabled": "This integration is disabled because it uses non-open source code to operate.",
"documentation": "https://www.home-assistant.io/integrations/aladdin_connect", "documentation": "https://www.home-assistant.io/integrations/aladdin_connect",
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"requirements": ["genie-partner-sdk==1.0.2"] "requirements": ["genie-partner-sdk==1.0.2"]

View File

@ -0,0 +1,5 @@
extend = "../../../pyproject.toml"
lint.extend-ignore = [
"F821"
]

View File

@ -1,13 +1,13 @@
"""Support for Aladdin Connect Garage Door sensors.""" """Support for Aladdin Connect Garage Door sensors."""
# mypy: ignore-errors
from __future__ import annotations from __future__ import annotations
from collections.abc import Callable from collections.abc import Callable
from dataclasses import dataclass from dataclasses import dataclass
from genie_partner_sdk.client import AladdinConnectClient # from genie_partner_sdk.client import AladdinConnectClient
from genie_partner_sdk.model import GarageDoor # from genie_partner_sdk.model import GarageDoor
from homeassistant.components.sensor import ( from homeassistant.components.sensor import (
SensorDeviceClass, SensorDeviceClass,
SensorEntity, SensorEntity,

View File

@ -926,9 +926,6 @@ gassist-text==0.0.11
# homeassistant.components.google # homeassistant.components.google
gcal-sync==6.0.4 gcal-sync==6.0.4
# homeassistant.components.aladdin_connect
genie-partner-sdk==1.0.2
# homeassistant.components.geniushub # homeassistant.components.geniushub
geniushub-client==0.7.1 geniushub-client==0.7.1

View File

@ -764,9 +764,6 @@ gassist-text==0.0.11
# homeassistant.components.google # homeassistant.components.google
gcal-sync==6.0.4 gcal-sync==6.0.4
# homeassistant.components.aladdin_connect
genie-partner-sdk==1.0.2
# homeassistant.components.geocaching # homeassistant.components.geocaching
geocachingapi==0.2.1 geocachingapi==0.2.1

View File

@ -5,8 +5,6 @@ from unittest.mock import AsyncMock, patch
import pytest import pytest
from typing_extensions import Generator from typing_extensions import Generator
from homeassistant.components.aladdin_connect import DOMAIN
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
@ -23,7 +21,7 @@ def mock_setup_entry() -> Generator[AsyncMock]:
def mock_config_entry() -> MockConfigEntry: def mock_config_entry() -> MockConfigEntry:
"""Return an Aladdin Connect config entry.""" """Return an Aladdin Connect config entry."""
return MockConfigEntry( return MockConfigEntry(
domain=DOMAIN, domain="aladdin_connect",
data={}, data={},
title="test@test.com", title="test@test.com",
unique_id="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", unique_id="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",

View File

@ -1,225 +1,230 @@
"""Test the Aladdin Connect Garage Door config flow.""" """Test the Aladdin Connect Garage Door config flow."""
from unittest.mock import AsyncMock # from unittest.mock import AsyncMock
#
import pytest # import pytest
#
from homeassistant.components.aladdin_connect.const import ( # from homeassistant.components.aladdin_connect.const import (
DOMAIN, # DOMAIN,
OAUTH2_AUTHORIZE, # OAUTH2_AUTHORIZE,
OAUTH2_TOKEN, # OAUTH2_TOKEN,
) # )
from homeassistant.components.application_credentials import ( # from homeassistant.components.application_credentials import (
ClientCredential, # ClientCredential,
async_import_client_credential, # async_import_client_credential,
) # )
from homeassistant.config_entries import SOURCE_REAUTH, SOURCE_USER, ConfigFlowResult # from homeassistant.config_entries import SOURCE_REAUTH, SOURCE_USER, ConfigFlowResult
from homeassistant.core import HomeAssistant # from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType # from homeassistant.data_entry_flow import FlowResultType
from homeassistant.helpers import config_entry_oauth2_flow # from homeassistant.helpers import config_entry_oauth2_flow
from homeassistant.setup import async_setup_component # from homeassistant.setup import async_setup_component
#
from tests.common import MockConfigEntry # from tests.common import MockConfigEntry
from tests.test_util.aiohttp import AiohttpClientMocker # from tests.test_util.aiohttp import AiohttpClientMocker
from tests.typing import ClientSessionGenerator # from tests.typing import ClientSessionGenerator
#
CLIENT_ID = "1234" # CLIENT_ID = "1234"
CLIENT_SECRET = "5678" # CLIENT_SECRET = "5678"
#
EXAMPLE_TOKEN = ( # EXAMPLE_TOKEN = (
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhYWFhYWFhYS1iYmJiLWNjY2MtZGRk" # "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhYWFhYWFhYS1iYmJiLWNjY2MtZGRk"
"ZC1lZWVlZWVlZWVlZWUiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjIsInVzZXJuYW" # "ZC1lZWVlZWVlZWVlZWUiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjIsInVzZXJuYW"
"1lIjoidGVzdEB0ZXN0LmNvbSJ9.CTU1YItIrUl8nSM3koJxlFJr5CjLghgc9gS6h45D8dE" # "1lIjoidGVzdEB0ZXN0LmNvbSJ9.CTU1YItIrUl8nSM3koJxlFJr5CjLghgc9gS6h45D8dE"
) # )
#
#
@pytest.fixture # @pytest.fixture
async def setup_credentials(hass: HomeAssistant) -> None: # async def setup_credentials(hass: HomeAssistant) -> None:
"""Fixture to setup credentials.""" # """Fixture to setup credentials."""
assert await async_setup_component(hass, "application_credentials", {}) # assert await async_setup_component(hass, "application_credentials", {})
await async_import_client_credential( # await async_import_client_credential(
hass, # hass,
DOMAIN, # DOMAIN,
ClientCredential(CLIENT_ID, CLIENT_SECRET), # ClientCredential(CLIENT_ID, CLIENT_SECRET),
) # )
#
#
async def _oauth_actions( # async def _oauth_actions(
hass: HomeAssistant, # hass: HomeAssistant,
result: ConfigFlowResult, # result: ConfigFlowResult,
hass_client_no_auth: ClientSessionGenerator, # hass_client_no_auth: ClientSessionGenerator,
aioclient_mock: AiohttpClientMocker, # aioclient_mock: AiohttpClientMocker,
) -> None: # ) -> None:
state = config_entry_oauth2_flow._encode_jwt( # state = config_entry_oauth2_flow._encode_jwt(
hass, # hass,
{ # {
"flow_id": result["flow_id"], # "flow_id": result["flow_id"],
"redirect_uri": "https://example.com/auth/external/callback", # "redirect_uri": "https://example.com/auth/external/callback",
}, # },
) # )
#
assert result["url"] == ( # assert result["url"] == (
f"{OAUTH2_AUTHORIZE}?response_type=code&client_id={CLIENT_ID}" # f"{OAUTH2_AUTHORIZE}?response_type=code&client_id={CLIENT_ID}"
"&redirect_uri=https://example.com/auth/external/callback" # "&redirect_uri=https://example.com/auth/external/callback"
f"&state={state}" # f"&state={state}"
) # )
#
client = await hass_client_no_auth() # client = await hass_client_no_auth()
resp = await client.get(f"/auth/external/callback?code=abcd&state={state}") # resp = await client.get(f"/auth/external/callback?code=abcd&state={state}")
assert resp.status == 200 # assert resp.status == 200
assert resp.headers["content-type"] == "text/html; charset=utf-8" # assert resp.headers["content-type"] == "text/html; charset=utf-8"
#
aioclient_mock.post( # aioclient_mock.post(
OAUTH2_TOKEN, # OAUTH2_TOKEN,
json={ # json={
"refresh_token": "mock-refresh-token", # "refresh_token": "mock-refresh-token",
"access_token": EXAMPLE_TOKEN, # "access_token": EXAMPLE_TOKEN,
"type": "Bearer", # "type": "Bearer",
"expires_in": 60, # "expires_in": 60,
}, # },
) # )
#
#
@pytest.mark.usefixtures("current_request_with_host") # @pytest.mark.skip(reason="Integration disabled")
async def test_full_flow( # @pytest.mark.usefixtures("current_request_with_host")
hass: HomeAssistant, # async def test_full_flow(
hass_client_no_auth: ClientSessionGenerator, # hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker, # hass_client_no_auth: ClientSessionGenerator,
setup_credentials: None, # aioclient_mock: AiohttpClientMocker,
mock_setup_entry: AsyncMock, # setup_credentials: None,
) -> None: # mock_setup_entry: AsyncMock,
"""Check full flow.""" # ) -> None:
result = await hass.config_entries.flow.async_init( # """Check full flow."""
DOMAIN, context={"source": SOURCE_USER} # result = await hass.config_entries.flow.async_init(
) # DOMAIN, context={"source": SOURCE_USER}
await _oauth_actions(hass, result, hass_client_no_auth, aioclient_mock) # )
# await _oauth_actions(hass, result, hass_client_no_auth, aioclient_mock)
result = await hass.config_entries.flow.async_configure(result["flow_id"]) #
assert result["type"] is FlowResultType.CREATE_ENTRY # result = await hass.config_entries.flow.async_configure(result["flow_id"])
assert result["title"] == "test@test.com" # assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["data"]["token"]["access_token"] == EXAMPLE_TOKEN # assert result["title"] == "test@test.com"
assert result["data"]["token"]["refresh_token"] == "mock-refresh-token" # assert result["data"]["token"]["access_token"] == EXAMPLE_TOKEN
assert result["result"].unique_id == "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" # assert result["data"]["token"]["refresh_token"] == "mock-refresh-token"
# assert result["result"].unique_id == "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
assert len(hass.config_entries.async_entries(DOMAIN)) == 1 #
assert len(mock_setup_entry.mock_calls) == 1 # assert len(hass.config_entries.async_entries(DOMAIN)) == 1
# assert len(mock_setup_entry.mock_calls) == 1
#
@pytest.mark.usefixtures("current_request_with_host") #
async def test_duplicate_entry( # @pytest.mark.skip(reason="Integration disabled")
hass: HomeAssistant, # @pytest.mark.usefixtures("current_request_with_host")
hass_client_no_auth: ClientSessionGenerator, # async def test_duplicate_entry(
aioclient_mock: AiohttpClientMocker, # hass: HomeAssistant,
setup_credentials: None, # hass_client_no_auth: ClientSessionGenerator,
mock_config_entry: MockConfigEntry, # aioclient_mock: AiohttpClientMocker,
) -> None: # setup_credentials: None,
"""Test we abort with duplicate entry.""" # mock_config_entry: MockConfigEntry,
mock_config_entry.add_to_hass(hass) # ) -> None:
result = await hass.config_entries.flow.async_init( # """Test we abort with duplicate entry."""
DOMAIN, context={"source": SOURCE_USER} # mock_config_entry.add_to_hass(hass)
) # result = await hass.config_entries.flow.async_init(
await _oauth_actions(hass, result, hass_client_no_auth, aioclient_mock) # DOMAIN, context={"source": SOURCE_USER}
# )
result = await hass.config_entries.flow.async_configure(result["flow_id"]) # await _oauth_actions(hass, result, hass_client_no_auth, aioclient_mock)
assert result["type"] is FlowResultType.ABORT #
assert result["reason"] == "already_configured" # result = await hass.config_entries.flow.async_configure(result["flow_id"])
# assert result["type"] is FlowResultType.ABORT
# assert result["reason"] == "already_configured"
@pytest.mark.usefixtures("current_request_with_host") #
async def test_reauth( #
hass: HomeAssistant, # @pytest.mark.skip(reason="Integration disabled")
hass_client_no_auth: ClientSessionGenerator, # @pytest.mark.usefixtures("current_request_with_host")
aioclient_mock: AiohttpClientMocker, # async def test_reauth(
setup_credentials: None, # hass: HomeAssistant,
mock_config_entry: MockConfigEntry, # hass_client_no_auth: ClientSessionGenerator,
mock_setup_entry: AsyncMock, # aioclient_mock: AiohttpClientMocker,
) -> None: # setup_credentials: None,
"""Test reauthentication.""" # mock_config_entry: MockConfigEntry,
mock_config_entry.add_to_hass(hass) # mock_setup_entry: AsyncMock,
result = await hass.config_entries.flow.async_init( # ) -> None:
DOMAIN, # """Test reauthentication."""
context={ # mock_config_entry.add_to_hass(hass)
"source": SOURCE_REAUTH, # result = await hass.config_entries.flow.async_init(
"entry_id": mock_config_entry.entry_id, # DOMAIN,
}, # context={
data=mock_config_entry.data, # "source": SOURCE_REAUTH,
) # "entry_id": mock_config_entry.entry_id,
assert result["type"] is FlowResultType.FORM # },
assert result["step_id"] == "reauth_confirm" # data=mock_config_entry.data,
result = await hass.config_entries.flow.async_configure(result["flow_id"], {}) # )
await _oauth_actions(hass, result, hass_client_no_auth, aioclient_mock) # assert result["type"] is FlowResultType.FORM
# assert result["step_id"] == "reauth_confirm"
result = await hass.config_entries.flow.async_configure(result["flow_id"]) # result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
assert result["type"] is FlowResultType.ABORT # await _oauth_actions(hass, result, hass_client_no_auth, aioclient_mock)
assert result["reason"] == "reauth_successful" #
# result = await hass.config_entries.flow.async_configure(result["flow_id"])
# assert result["type"] is FlowResultType.ABORT
@pytest.mark.usefixtures("current_request_with_host") # assert result["reason"] == "reauth_successful"
async def test_reauth_wrong_account( #
hass: HomeAssistant, #
hass_client_no_auth: ClientSessionGenerator, # @pytest.mark.skip(reason="Integration disabled")
aioclient_mock: AiohttpClientMocker, # @pytest.mark.usefixtures("current_request_with_host")
setup_credentials: None, # async def test_reauth_wrong_account(
mock_setup_entry: AsyncMock, # hass: HomeAssistant,
) -> None: # hass_client_no_auth: ClientSessionGenerator,
"""Test reauthentication with wrong account.""" # aioclient_mock: AiohttpClientMocker,
config_entry = MockConfigEntry( # setup_credentials: None,
domain=DOMAIN, # mock_setup_entry: AsyncMock,
data={}, # ) -> None:
title="test@test.com", # """Test reauthentication with wrong account."""
unique_id="aaaaaaaa-bbbb-ffff-dddd-eeeeeeeeeeee", # config_entry = MockConfigEntry(
version=2, # domain=DOMAIN,
) # data={},
config_entry.add_to_hass(hass) # title="test@test.com",
result = await hass.config_entries.flow.async_init( # unique_id="aaaaaaaa-bbbb-ffff-dddd-eeeeeeeeeeee",
DOMAIN, # version=2,
context={ # )
"source": SOURCE_REAUTH, # config_entry.add_to_hass(hass)
"entry_id": config_entry.entry_id, # result = await hass.config_entries.flow.async_init(
}, # DOMAIN,
data=config_entry.data, # context={
) # "source": SOURCE_REAUTH,
assert result["type"] is FlowResultType.FORM # "entry_id": config_entry.entry_id,
assert result["step_id"] == "reauth_confirm" # },
result = await hass.config_entries.flow.async_configure(result["flow_id"], {}) # data=config_entry.data,
await _oauth_actions(hass, result, hass_client_no_auth, aioclient_mock) # )
# assert result["type"] is FlowResultType.FORM
result = await hass.config_entries.flow.async_configure(result["flow_id"]) # assert result["step_id"] == "reauth_confirm"
assert result["type"] is FlowResultType.ABORT # result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
assert result["reason"] == "wrong_account" # await _oauth_actions(hass, result, hass_client_no_auth, aioclient_mock)
#
# result = await hass.config_entries.flow.async_configure(result["flow_id"])
@pytest.mark.usefixtures("current_request_with_host") # assert result["type"] is FlowResultType.ABORT
async def test_reauth_old_account( # assert result["reason"] == "wrong_account"
hass: HomeAssistant, #
hass_client_no_auth: ClientSessionGenerator, #
aioclient_mock: AiohttpClientMocker, # @pytest.mark.skip(reason="Integration disabled")
setup_credentials: None, # @pytest.mark.usefixtures("current_request_with_host")
mock_setup_entry: AsyncMock, # async def test_reauth_old_account(
) -> None: # hass: HomeAssistant,
"""Test reauthentication with old account.""" # hass_client_no_auth: ClientSessionGenerator,
config_entry = MockConfigEntry( # aioclient_mock: AiohttpClientMocker,
domain=DOMAIN, # setup_credentials: None,
data={}, # mock_setup_entry: AsyncMock,
title="test@test.com", # ) -> None:
unique_id="test@test.com", # """Test reauthentication with old account."""
version=2, # config_entry = MockConfigEntry(
) # domain=DOMAIN,
config_entry.add_to_hass(hass) # data={},
result = await hass.config_entries.flow.async_init( # title="test@test.com",
DOMAIN, # unique_id="test@test.com",
context={ # version=2,
"source": SOURCE_REAUTH, # )
"entry_id": config_entry.entry_id, # config_entry.add_to_hass(hass)
}, # result = await hass.config_entries.flow.async_init(
data=config_entry.data, # DOMAIN,
) # context={
assert result["type"] is FlowResultType.FORM # "source": SOURCE_REAUTH,
assert result["step_id"] == "reauth_confirm" # "entry_id": config_entry.entry_id,
result = await hass.config_entries.flow.async_configure(result["flow_id"], {}) # },
await _oauth_actions(hass, result, hass_client_no_auth, aioclient_mock) # data=config_entry.data,
# )
result = await hass.config_entries.flow.async_configure(result["flow_id"]) # assert result["type"] is FlowResultType.FORM
assert result["type"] is FlowResultType.ABORT # assert result["step_id"] == "reauth_confirm"
assert result["reason"] == "reauth_successful" # result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
assert config_entry.unique_id == "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" # await _oauth_actions(hass, result, hass_client_no_auth, aioclient_mock)
#
# result = await hass.config_entries.flow.async_configure(result["flow_id"])
# assert result["type"] is FlowResultType.ABORT
# assert result["reason"] == "reauth_successful"
# assert config_entry.unique_id == "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"