mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 14:17:45 +00:00
User defined profile name for Withings (#36864)
This commit is contained in:
parent
e19c97af7c
commit
5446641f09
@ -39,18 +39,23 @@ DOMAIN = const.DOMAIN
|
|||||||
|
|
||||||
CONFIG_SCHEMA = vol.Schema(
|
CONFIG_SCHEMA = vol.Schema(
|
||||||
{
|
{
|
||||||
DOMAIN: vol.Schema(
|
DOMAIN: vol.All(
|
||||||
{
|
cv.deprecated(const.CONF_PROFILES, invalidation_version="0.114"),
|
||||||
vol.Required(CONF_CLIENT_ID): vol.All(cv.string, vol.Length(min=1)),
|
vol.Schema(
|
||||||
vol.Required(CONF_CLIENT_SECRET): vol.All(cv.string, vol.Length(min=1)),
|
{
|
||||||
vol.Optional(const.CONF_USE_WEBHOOK, default=False): cv.boolean,
|
vol.Required(CONF_CLIENT_ID): vol.All(cv.string, vol.Length(min=1)),
|
||||||
vol.Required(const.CONF_PROFILES): vol.All(
|
vol.Required(CONF_CLIENT_SECRET): vol.All(
|
||||||
cv.ensure_list,
|
cv.string, vol.Length(min=1)
|
||||||
vol.Unique(),
|
),
|
||||||
vol.Length(min=1),
|
vol.Optional(const.CONF_USE_WEBHOOK, default=False): cv.boolean,
|
||||||
[vol.All(cv.string, vol.Length(min=1))],
|
vol.Optional(const.CONF_PROFILES): vol.All(
|
||||||
),
|
cv.ensure_list,
|
||||||
}
|
vol.Unique(),
|
||||||
|
vol.Length(min=1),
|
||||||
|
[vol.All(cv.string, vol.Length(min=1))],
|
||||||
|
),
|
||||||
|
}
|
||||||
|
),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
extra=vol.ALLOW_EXTRA,
|
extra=vol.ALLOW_EXTRA,
|
||||||
@ -87,8 +92,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
config_updates = {}
|
config_updates = {}
|
||||||
|
|
||||||
# Add a unique id if it's an older config entry.
|
# Add a unique id if it's an older config entry.
|
||||||
if entry.unique_id != entry.data["token"]["userid"]:
|
if entry.unique_id != entry.data["token"]["userid"] or not isinstance(
|
||||||
config_updates["unique_id"] = entry.data["token"]["userid"]
|
entry.unique_id, str
|
||||||
|
):
|
||||||
|
config_updates["unique_id"] = str(entry.data["token"]["userid"])
|
||||||
|
|
||||||
# Add the webhook configuration.
|
# Add the webhook configuration.
|
||||||
if CONF_WEBHOOK_ID not in entry.data:
|
if CONF_WEBHOOK_ID not in entry.data:
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
"""Config flow for Withings."""
|
"""Config flow for Withings."""
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Dict, Union
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
from withings_api.common import AuthScope
|
from withings_api.common import AuthScope
|
||||||
@ -7,6 +8,7 @@ from withings_api.common import AuthScope
|
|||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components.withings import const
|
from homeassistant.components.withings import const
|
||||||
from homeassistant.helpers import config_entry_oauth2_flow
|
from homeassistant.helpers import config_entry_oauth2_flow
|
||||||
|
from homeassistant.util import slugify
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -18,7 +20,8 @@ class WithingsFlowHandler(
|
|||||||
|
|
||||||
DOMAIN = const.DOMAIN
|
DOMAIN = const.DOMAIN
|
||||||
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL
|
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL
|
||||||
_current_data = None
|
# Temporarily holds authorization data during the profile step.
|
||||||
|
_current_data: Dict[str, Union[None, str, int]] = {}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def logger(self) -> logging.Logger:
|
def logger(self) -> logging.Logger:
|
||||||
@ -46,33 +49,58 @@ class WithingsFlowHandler(
|
|||||||
|
|
||||||
async def async_step_profile(self, data: dict) -> dict:
|
async def async_step_profile(self, data: dict) -> dict:
|
||||||
"""Prompt the user to select a user profile."""
|
"""Prompt the user to select a user profile."""
|
||||||
profile = data.get(const.PROFILE)
|
errors = {}
|
||||||
|
# pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167
|
||||||
|
reauth_profile = (
|
||||||
|
self.context.get(const.PROFILE)
|
||||||
|
if self.context.get("source") == "reauth"
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
profile = data.get(const.PROFILE) or reauth_profile
|
||||||
|
|
||||||
if profile:
|
if profile:
|
||||||
new_data = {**self._current_data, **{const.PROFILE: profile}}
|
existing_entries = [
|
||||||
self._current_data = None
|
config_entry
|
||||||
return await self.async_step_finish(new_data)
|
for config_entry in self.hass.config_entries.async_entries(const.DOMAIN)
|
||||||
|
if slugify(config_entry.data.get(const.PROFILE)) == slugify(profile)
|
||||||
|
]
|
||||||
|
|
||||||
|
if reauth_profile or not existing_entries:
|
||||||
|
new_data = {**self._current_data, **data, const.PROFILE: profile}
|
||||||
|
self._current_data = {}
|
||||||
|
return await self.async_step_finish(new_data)
|
||||||
|
|
||||||
|
errors["base"] = "profile_exists"
|
||||||
|
|
||||||
profiles = self.hass.data[const.DOMAIN][const.CONFIG][const.CONF_PROFILES]
|
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="profile",
|
step_id="profile",
|
||||||
data_schema=vol.Schema({vol.Required(const.PROFILE): vol.In(profiles)}),
|
data_schema=vol.Schema({vol.Required(const.PROFILE): str}),
|
||||||
|
errors=errors,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_step_reauth(self, data: dict) -> dict:
|
async def async_step_reauth(self, data: dict = None) -> dict:
|
||||||
"""Prompt user to re-authenticate."""
|
"""Prompt user to re-authenticate."""
|
||||||
if data is not None:
|
if data is not None:
|
||||||
return await self.async_step_user()
|
return await self.async_step_user()
|
||||||
|
|
||||||
|
# pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167
|
||||||
|
placeholders = {const.PROFILE: self.context["profile"]}
|
||||||
|
|
||||||
|
self.context.update({"title_placeholders": placeholders})
|
||||||
|
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="reauth",
|
step_id="reauth",
|
||||||
# pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167
|
# pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167
|
||||||
description_placeholders={"profile": self.context["profile"]},
|
description_placeholders=placeholders,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_step_finish(self, data: dict) -> dict:
|
async def async_step_finish(self, data: dict) -> dict:
|
||||||
"""Finish the flow."""
|
"""Finish the flow."""
|
||||||
self._current_data = None
|
self._current_data = {}
|
||||||
|
|
||||||
|
await self.async_set_unique_id(
|
||||||
|
str(data["token"]["userid"]), raise_on_progress=False
|
||||||
|
)
|
||||||
|
self._abort_if_unique_id_configured(data)
|
||||||
|
|
||||||
await self.async_set_unique_id(data["token"]["userid"], raise_on_progress=False)
|
|
||||||
return self.async_create_entry(title=data[const.PROFILE], data=data)
|
return self.async_create_entry(title=data[const.PROFILE], data=data)
|
||||||
|
@ -4,18 +4,22 @@
|
|||||||
"step": {
|
"step": {
|
||||||
"profile": {
|
"profile": {
|
||||||
"title": "User Profile.",
|
"title": "User Profile.",
|
||||||
"description": "Which profile did you select on the Withings website? It's important the profiles match, otherwise data will be mis-labeled.",
|
"description": "Provide a unique profile name for this data. Typically this is the name of the profile you selected in the previous step.",
|
||||||
"data": { "profile": "Profile" }
|
"data": { "profile": "Profile Name" }
|
||||||
},
|
},
|
||||||
"pick_implementation": { "title": "Pick Authentication Method" },
|
"pick_implementation": { "title": "Pick Authentication Method" },
|
||||||
"reauth": {
|
"reauth": {
|
||||||
"title": "Re-authenticate {profile}",
|
"title": "Re-authenticate Profile",
|
||||||
"description": "The \"{profile}\" profile needs to be re-authenticated in order to continue receiving Withings data."
|
"description": "The \"{profile}\" profile needs to be re-authenticated in order to continue receiving Withings data."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"error": {
|
||||||
|
"profile_exists": "User profile is already configured. Please provide a unique profile name."
|
||||||
|
},
|
||||||
"abort": {
|
"abort": {
|
||||||
"authorize_url_timeout": "Timeout generating authorize url.",
|
"authorize_url_timeout": "Timeout generating authorize url.",
|
||||||
"missing_configuration": "The Withings integration is not configured. Please follow the documentation."
|
"missing_configuration": "The Withings integration is not configured. Please follow the documentation.",
|
||||||
|
"already_configured": "Configuration updated for profile."
|
||||||
},
|
},
|
||||||
"create_entry": { "default": "Successfully authenticated with Withings." }
|
"create_entry": { "default": "Successfully authenticated with Withings." }
|
||||||
}
|
}
|
||||||
|
@ -141,9 +141,6 @@ class ComponentFactory:
|
|||||||
CONF_CLIENT_ID: self._client_id,
|
CONF_CLIENT_ID: self._client_id,
|
||||||
CONF_CLIENT_SECRET: self._client_secret,
|
CONF_CLIENT_SECRET: self._client_secret,
|
||||||
const.CONF_USE_WEBHOOK: True,
|
const.CONF_USE_WEBHOOK: True,
|
||||||
const.CONF_PROFILES: [
|
|
||||||
profile_config.profile for profile_config in self._profile_configs
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,11 +230,9 @@ class ComponentFactory:
|
|||||||
result = await self._hass.config_entries.flow.async_configure(result["flow_id"])
|
result = await self._hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
assert result.get("type") == "form"
|
assert result.get("type") == "form"
|
||||||
assert result.get("step_id") == "profile"
|
assert result.get("step_id") == "profile"
|
||||||
assert result.get("data_schema").schema["profile"].container == [
|
assert "profile" in result.get("data_schema").schema
|
||||||
profile.profile for profile in self._profile_configs
|
|
||||||
]
|
|
||||||
|
|
||||||
# Select the user profile.
|
# Provide the user profile.
|
||||||
result = await self._hass.config_entries.flow.async_configure(
|
result = await self._hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"], {const.PROFILE: profile_config.profile}
|
result["flow_id"], {const.PROFILE: profile_config.profile}
|
||||||
)
|
)
|
||||||
|
97
tests/components/withings/test_config_flow.py
Normal file
97
tests/components/withings/test_config_flow.py
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
"""Tests for config flow."""
|
||||||
|
from aiohttp.test_utils import TestClient
|
||||||
|
|
||||||
|
from homeassistant.components.withings import const
|
||||||
|
from homeassistant.config import async_process_ha_core_config
|
||||||
|
from homeassistant.const import (
|
||||||
|
CONF_CLIENT_ID,
|
||||||
|
CONF_CLIENT_SECRET,
|
||||||
|
CONF_EXTERNAL_URL,
|
||||||
|
CONF_UNIT_SYSTEM,
|
||||||
|
CONF_UNIT_SYSTEM_METRIC,
|
||||||
|
)
|
||||||
|
from homeassistant.core import DOMAIN as HA_DOMAIN, HomeAssistant
|
||||||
|
from homeassistant.helpers import config_entry_oauth2_flow
|
||||||
|
from homeassistant.helpers.config_entry_oauth2_flow import AUTH_CALLBACK_PATH
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
|
async def test_config_non_unique_profile(hass: HomeAssistant) -> None:
|
||||||
|
"""Test setup a non-unique profile."""
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
domain=const.DOMAIN, data={const.PROFILE: "person0"}, unique_id="0"
|
||||||
|
)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
const.DOMAIN, context={"source": "profile"}, data={const.PROFILE: "person0"}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result
|
||||||
|
assert result["errors"]["base"] == "profile_exists"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_config_reauth_profile(
|
||||||
|
hass: HomeAssistant, aiohttp_client, aioclient_mock
|
||||||
|
) -> None:
|
||||||
|
"""Test reauth an existing profile re-creates the config entry."""
|
||||||
|
hass_config = {
|
||||||
|
HA_DOMAIN: {
|
||||||
|
CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_METRIC,
|
||||||
|
CONF_EXTERNAL_URL: "http://127.0.0.1:8080/",
|
||||||
|
},
|
||||||
|
const.DOMAIN: {
|
||||||
|
CONF_CLIENT_ID: "my_client_id",
|
||||||
|
CONF_CLIENT_SECRET: "my_client_secret",
|
||||||
|
const.CONF_USE_WEBHOOK: False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
await async_process_ha_core_config(hass, hass_config.get(HA_DOMAIN))
|
||||||
|
assert await async_setup_component(hass, const.DOMAIN, hass_config)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
domain=const.DOMAIN, data={const.PROFILE: "person0"}, unique_id="0"
|
||||||
|
)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
const.DOMAIN, context={"source": "reauth", "profile": "person0"}
|
||||||
|
)
|
||||||
|
assert result
|
||||||
|
assert result["type"] == "form"
|
||||||
|
assert result["step_id"] == "reauth"
|
||||||
|
assert result["description_placeholders"] == {const.PROFILE: "person0"}
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"], {},)
|
||||||
|
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
state = config_entry_oauth2_flow._encode_jwt(hass, {"flow_id": result["flow_id"]})
|
||||||
|
|
||||||
|
client: TestClient = await aiohttp_client(hass.http.app)
|
||||||
|
resp = await client.get(f"{AUTH_CALLBACK_PATH}?code=abcd&state={state}")
|
||||||
|
assert resp.status == 200
|
||||||
|
assert resp.headers["content-type"] == "text/html; charset=utf-8"
|
||||||
|
|
||||||
|
aioclient_mock.clear_requests()
|
||||||
|
aioclient_mock.post(
|
||||||
|
"https://account.withings.com/oauth2/token",
|
||||||
|
json={
|
||||||
|
"refresh_token": "mock-refresh-token",
|
||||||
|
"access_token": "mock-access-token",
|
||||||
|
"type": "Bearer",
|
||||||
|
"expires_in": 60,
|
||||||
|
"userid": "0",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
|
assert result
|
||||||
|
assert result["type"] == "abort"
|
||||||
|
assert result["reason"] == "already_configured"
|
||||||
|
|
||||||
|
entries = hass.config_entries.async_entries(const.DOMAIN)
|
||||||
|
assert entries
|
||||||
|
assert entries[0].data["token"]["refresh_token"] == "mock-refresh-token"
|
@ -1,14 +1,22 @@
|
|||||||
"""Tests for the Withings component."""
|
"""Tests for the Withings component."""
|
||||||
from asynctest import MagicMock, patch
|
|
||||||
import pytest
|
import pytest
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
from withings_api.common import UnauthorizedException
|
from withings_api.common import UnauthorizedException
|
||||||
|
|
||||||
|
import homeassistant.components.webhook as webhook
|
||||||
from homeassistant.components.withings import CONFIG_SCHEMA, DOMAIN, async_setup, const
|
from homeassistant.components.withings import CONFIG_SCHEMA, DOMAIN, async_setup, const
|
||||||
from homeassistant.components.withings.common import DataManager
|
from homeassistant.components.withings.common import ConfigEntryWithingsApi, DataManager
|
||||||
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET
|
from homeassistant.config import async_process_ha_core_config
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.const import (
|
||||||
|
CONF_CLIENT_ID,
|
||||||
|
CONF_CLIENT_SECRET,
|
||||||
|
CONF_EXTERNAL_URL,
|
||||||
|
CONF_UNIT_SYSTEM,
|
||||||
|
CONF_UNIT_SYSTEM_METRIC,
|
||||||
|
)
|
||||||
|
from homeassistant.core import DOMAIN as HA_DOMAIN, HomeAssistant
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
from .common import (
|
from .common import (
|
||||||
ComponentFactory,
|
ComponentFactory,
|
||||||
@ -17,7 +25,7 @@ from .common import (
|
|||||||
new_profile_config,
|
new_profile_config,
|
||||||
)
|
)
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MagicMock, MockConfigEntry, patch
|
||||||
|
|
||||||
|
|
||||||
def config_schema_validate(withings_config) -> dict:
|
def config_schema_validate(withings_config) -> dict:
|
||||||
@ -43,71 +51,40 @@ def test_config_schema_basic_config() -> None:
|
|||||||
CONF_CLIENT_ID: "my_client_id",
|
CONF_CLIENT_ID: "my_client_id",
|
||||||
CONF_CLIENT_SECRET: "my_client_secret",
|
CONF_CLIENT_SECRET: "my_client_secret",
|
||||||
const.CONF_USE_WEBHOOK: True,
|
const.CONF_USE_WEBHOOK: True,
|
||||||
const.CONF_PROFILES: ["Person 1", "Person 2"],
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_config_schema_client_id() -> None:
|
def test_config_schema_client_id() -> None:
|
||||||
"""Test schema."""
|
"""Test schema."""
|
||||||
|
config_schema_assert_fail({CONF_CLIENT_SECRET: "my_client_secret"})
|
||||||
config_schema_assert_fail(
|
config_schema_assert_fail(
|
||||||
{
|
{CONF_CLIENT_SECRET: "my_client_secret", CONF_CLIENT_ID: ""}
|
||||||
CONF_CLIENT_SECRET: "my_client_secret",
|
|
||||||
const.CONF_PROFILES: ["Person 1", "Person 2"],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
config_schema_assert_fail(
|
|
||||||
{
|
|
||||||
CONF_CLIENT_SECRET: "my_client_secret",
|
|
||||||
CONF_CLIENT_ID: "",
|
|
||||||
const.CONF_PROFILES: ["Person 1"],
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
config_schema_validate(
|
config_schema_validate(
|
||||||
{
|
{CONF_CLIENT_SECRET: "my_client_secret", CONF_CLIENT_ID: "my_client_id"}
|
||||||
CONF_CLIENT_SECRET: "my_client_secret",
|
|
||||||
CONF_CLIENT_ID: "my_client_id",
|
|
||||||
const.CONF_PROFILES: ["Person 1"],
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_config_schema_client_secret() -> None:
|
def test_config_schema_client_secret() -> None:
|
||||||
"""Test schema."""
|
"""Test schema."""
|
||||||
config_schema_assert_fail(
|
config_schema_assert_fail({CONF_CLIENT_ID: "my_client_id"})
|
||||||
{CONF_CLIENT_ID: "my_client_id", const.CONF_PROFILES: ["Person 1"]}
|
config_schema_assert_fail({CONF_CLIENT_ID: "my_client_id", CONF_CLIENT_SECRET: ""})
|
||||||
)
|
|
||||||
config_schema_assert_fail(
|
|
||||||
{
|
|
||||||
CONF_CLIENT_ID: "my_client_id",
|
|
||||||
CONF_CLIENT_SECRET: "",
|
|
||||||
const.CONF_PROFILES: ["Person 1"],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
config_schema_validate(
|
config_schema_validate(
|
||||||
{
|
{CONF_CLIENT_ID: "my_client_id", CONF_CLIENT_SECRET: "my_client_secret"}
|
||||||
CONF_CLIENT_ID: "my_client_id",
|
|
||||||
CONF_CLIENT_SECRET: "my_client_secret",
|
|
||||||
const.CONF_PROFILES: ["Person 1"],
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_config_schema_use_webhook() -> None:
|
def test_config_schema_use_webhook() -> None:
|
||||||
"""Test schema."""
|
"""Test schema."""
|
||||||
config_schema_validate(
|
config_schema_validate(
|
||||||
{
|
{CONF_CLIENT_ID: "my_client_id", CONF_CLIENT_SECRET: "my_client_secret"}
|
||||||
CONF_CLIENT_ID: "my_client_id",
|
|
||||||
CONF_CLIENT_SECRET: "my_client_secret",
|
|
||||||
const.CONF_PROFILES: ["Person 1"],
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
config = config_schema_validate(
|
config = config_schema_validate(
|
||||||
{
|
{
|
||||||
CONF_CLIENT_ID: "my_client_id",
|
CONF_CLIENT_ID: "my_client_id",
|
||||||
CONF_CLIENT_SECRET: "my_client_secret",
|
CONF_CLIENT_SECRET: "my_client_secret",
|
||||||
const.CONF_USE_WEBHOOK: True,
|
const.CONF_USE_WEBHOOK: True,
|
||||||
const.CONF_PROFILES: ["Person 1"],
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
assert config[const.DOMAIN][const.CONF_USE_WEBHOOK] is True
|
assert config[const.DOMAIN][const.CONF_USE_WEBHOOK] is True
|
||||||
@ -116,7 +93,6 @@ def test_config_schema_use_webhook() -> None:
|
|||||||
CONF_CLIENT_ID: "my_client_id",
|
CONF_CLIENT_ID: "my_client_id",
|
||||||
CONF_CLIENT_SECRET: "my_client_secret",
|
CONF_CLIENT_SECRET: "my_client_secret",
|
||||||
const.CONF_USE_WEBHOOK: False,
|
const.CONF_USE_WEBHOOK: False,
|
||||||
const.CONF_PROFILES: ["Person 1"],
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
assert config[const.DOMAIN][const.CONF_USE_WEBHOOK] is False
|
assert config[const.DOMAIN][const.CONF_USE_WEBHOOK] is False
|
||||||
@ -125,49 +101,6 @@ def test_config_schema_use_webhook() -> None:
|
|||||||
CONF_CLIENT_ID: "my_client_id",
|
CONF_CLIENT_ID: "my_client_id",
|
||||||
CONF_CLIENT_SECRET: "my_client_secret",
|
CONF_CLIENT_SECRET: "my_client_secret",
|
||||||
const.CONF_USE_WEBHOOK: "A",
|
const.CONF_USE_WEBHOOK: "A",
|
||||||
const.CONF_PROFILES: ["Person 1"],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_config_schema_profiles() -> None:
|
|
||||||
"""Test schema."""
|
|
||||||
config_schema_assert_fail(
|
|
||||||
{CONF_CLIENT_ID: "my_client_id", CONF_CLIENT_SECRET: "my_client_secret"}
|
|
||||||
)
|
|
||||||
config_schema_assert_fail(
|
|
||||||
{
|
|
||||||
CONF_CLIENT_ID: "my_client_id",
|
|
||||||
CONF_CLIENT_SECRET: "my_client_secret",
|
|
||||||
const.CONF_PROFILES: "",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
config_schema_assert_fail(
|
|
||||||
{
|
|
||||||
CONF_CLIENT_ID: "my_client_id",
|
|
||||||
CONF_CLIENT_SECRET: "my_client_secret",
|
|
||||||
const.CONF_PROFILES: [],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
config_schema_assert_fail(
|
|
||||||
{
|
|
||||||
CONF_CLIENT_ID: "my_client_id",
|
|
||||||
CONF_CLIENT_SECRET: "my_client_secret",
|
|
||||||
const.CONF_PROFILES: ["Person 1", "Person 1"],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
config_schema_validate(
|
|
||||||
{
|
|
||||||
CONF_CLIENT_ID: "my_client_id",
|
|
||||||
CONF_CLIENT_SECRET: "my_client_secret",
|
|
||||||
const.CONF_PROFILES: ["Person 1"],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
config_schema_validate(
|
|
||||||
{
|
|
||||||
CONF_CLIENT_ID: "my_client_id",
|
|
||||||
CONF_CLIENT_SECRET: "my_client_secret",
|
|
||||||
const.CONF_PROFILES: ["Person 1", "Person 2"],
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -252,3 +185,40 @@ async def test_set_config_unique_id(
|
|||||||
|
|
||||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
assert config_entry.unique_id == "my_user_id"
|
assert config_entry.unique_id == "my_user_id"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_set_convert_unique_id_to_string(hass: HomeAssistant) -> None:
|
||||||
|
"""Test upgrading configs to use a unique id."""
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
data={
|
||||||
|
"token": {"userid": 1234},
|
||||||
|
"auth_implementation": "withings",
|
||||||
|
"profile": "person0",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
hass_config = {
|
||||||
|
HA_DOMAIN: {
|
||||||
|
CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_METRIC,
|
||||||
|
CONF_EXTERNAL_URL: "http://127.0.0.1:8080/",
|
||||||
|
},
|
||||||
|
const.DOMAIN: {
|
||||||
|
CONF_CLIENT_ID: "my_client_id",
|
||||||
|
CONF_CLIENT_SECRET: "my_client_secret",
|
||||||
|
const.CONF_USE_WEBHOOK: False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.withings.common.ConfigEntryWithingsApi",
|
||||||
|
spec=ConfigEntryWithingsApi,
|
||||||
|
):
|
||||||
|
await async_process_ha_core_config(hass, hass_config.get(HA_DOMAIN))
|
||||||
|
assert await async_setup_component(hass, HA_DOMAIN, {})
|
||||||
|
assert await async_setup_component(hass, webhook.DOMAIN, hass_config)
|
||||||
|
assert await async_setup_component(hass, const.DOMAIN, hass_config)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert config_entry.unique_id == "1234"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user