mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 04:37:06 +00:00
Decouple Withings sensor tests from yaml (#99691)
* Decouple Withings sensor tests from yaml * Fix feedback * Add pytest fixture * Update tests/components/withings/test_sensor.py Co-authored-by: G Johansson <goran.johansson@shiftit.se> * Update snapshots * Update snapshots --------- Co-authored-by: G Johansson <goran.johansson@shiftit.se>
This commit is contained in:
parent
868fdd81da
commit
a62ffeaa99
@ -1 +1,85 @@
|
|||||||
"""Tests for the withings component."""
|
"""Tests for the withings component."""
|
||||||
|
from collections.abc import Iterable
|
||||||
|
from typing import Any, Optional
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
import arrow
|
||||||
|
from withings_api import DateType
|
||||||
|
from withings_api.common import (
|
||||||
|
GetSleepSummaryField,
|
||||||
|
MeasureGetMeasGroupCategory,
|
||||||
|
MeasureGetMeasResponse,
|
||||||
|
MeasureType,
|
||||||
|
SleepGetSummaryResponse,
|
||||||
|
UserGetDeviceResponse,
|
||||||
|
)
|
||||||
|
|
||||||
|
from homeassistant.components.webhook import async_generate_url
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
from .common import ProfileConfig, WebhookResponse
|
||||||
|
|
||||||
|
|
||||||
|
async def call_webhook(
|
||||||
|
hass: HomeAssistant, webhook_id: str, data: dict[str, Any], client
|
||||||
|
) -> WebhookResponse:
|
||||||
|
"""Call the webhook."""
|
||||||
|
webhook_url = async_generate_url(hass, webhook_id)
|
||||||
|
|
||||||
|
resp = await client.post(
|
||||||
|
urlparse(webhook_url).path,
|
||||||
|
data=data,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Wait for remaining tasks to complete.
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
data: dict[str, Any] = await resp.json()
|
||||||
|
resp.close()
|
||||||
|
|
||||||
|
return WebhookResponse(message=data["message"], message_code=data["code"])
|
||||||
|
|
||||||
|
|
||||||
|
class MockWithings:
|
||||||
|
"""Mock object for Withings."""
|
||||||
|
|
||||||
|
def __init__(self, user_profile: ProfileConfig):
|
||||||
|
"""Initialize mock."""
|
||||||
|
self.api_response_user_get_device = user_profile.api_response_user_get_device
|
||||||
|
self.api_response_measure_get_meas = user_profile.api_response_measure_get_meas
|
||||||
|
self.api_response_sleep_get_summary = (
|
||||||
|
user_profile.api_response_sleep_get_summary
|
||||||
|
)
|
||||||
|
|
||||||
|
def user_get_device(self) -> UserGetDeviceResponse:
|
||||||
|
"""Get devices."""
|
||||||
|
if isinstance(self.api_response_user_get_device, Exception):
|
||||||
|
raise self.api_response_user_get_device
|
||||||
|
return self.api_response_user_get_device
|
||||||
|
|
||||||
|
def measure_get_meas(
|
||||||
|
self,
|
||||||
|
meastype: MeasureType | None = None,
|
||||||
|
category: MeasureGetMeasGroupCategory | None = None,
|
||||||
|
startdate: DateType | None = None,
|
||||||
|
enddate: DateType | None = None,
|
||||||
|
offset: int | None = None,
|
||||||
|
lastupdate: DateType | None = None,
|
||||||
|
) -> MeasureGetMeasResponse:
|
||||||
|
"""Get measurements."""
|
||||||
|
if isinstance(self.api_response_measure_get_meas, Exception):
|
||||||
|
raise self.api_response_measure_get_meas
|
||||||
|
return self.api_response_measure_get_meas
|
||||||
|
|
||||||
|
def sleep_get_summary(
|
||||||
|
self,
|
||||||
|
data_fields: Iterable[GetSleepSummaryField],
|
||||||
|
startdateymd: Optional[DateType] = arrow.utcnow(),
|
||||||
|
enddateymd: Optional[DateType] = arrow.utcnow(),
|
||||||
|
offset: Optional[int] = None,
|
||||||
|
lastupdate: Optional[DateType] = arrow.utcnow(),
|
||||||
|
) -> SleepGetSummaryResponse:
|
||||||
|
"""Get sleep."""
|
||||||
|
if isinstance(self.api_response_sleep_get_summary, Exception):
|
||||||
|
raise self.api_response_sleep_get_summary
|
||||||
|
return self.api_response_sleep_get_summary
|
||||||
|
@ -1,15 +1,276 @@
|
|||||||
"""Fixtures for tests."""
|
"""Fixtures for tests."""
|
||||||
|
from collections.abc import Awaitable, Callable, Coroutine
|
||||||
|
import time
|
||||||
|
from typing import Any
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import arrow
|
||||||
import pytest
|
import pytest
|
||||||
|
from withings_api.common import (
|
||||||
|
GetSleepSummaryData,
|
||||||
|
GetSleepSummarySerie,
|
||||||
|
MeasureGetMeasGroup,
|
||||||
|
MeasureGetMeasGroupAttrib,
|
||||||
|
MeasureGetMeasGroupCategory,
|
||||||
|
MeasureGetMeasMeasure,
|
||||||
|
MeasureGetMeasResponse,
|
||||||
|
MeasureType,
|
||||||
|
SleepGetSummaryResponse,
|
||||||
|
SleepModel,
|
||||||
|
)
|
||||||
|
|
||||||
|
from homeassistant.components.application_credentials import (
|
||||||
|
ClientCredential,
|
||||||
|
async_import_client_credential,
|
||||||
|
)
|
||||||
|
from homeassistant.components.withings.const import DOMAIN
|
||||||
|
from homeassistant.config import async_process_ha_core_config
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
from .common import ComponentFactory
|
from . import MockWithings
|
||||||
|
from .common import ComponentFactory, new_profile_config
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||||
|
|
||||||
|
ComponentSetup = Callable[[], Awaitable[MockWithings]]
|
||||||
|
|
||||||
|
CLIENT_ID = "1234"
|
||||||
|
CLIENT_SECRET = "5678"
|
||||||
|
SCOPES = [
|
||||||
|
"user.info",
|
||||||
|
"user.metrics",
|
||||||
|
"user.activity",
|
||||||
|
"user.sleepevents",
|
||||||
|
]
|
||||||
|
TITLE = "henk"
|
||||||
|
WEBHOOK_ID = "55a7335ea8dee830eed4ef8f84cda8f6d80b83af0847dc74032e86120bffed5e"
|
||||||
|
|
||||||
|
PERSON0 = new_profile_config(
|
||||||
|
profile="12345",
|
||||||
|
user_id=12345,
|
||||||
|
api_response_measure_get_meas=MeasureGetMeasResponse(
|
||||||
|
measuregrps=(
|
||||||
|
MeasureGetMeasGroup(
|
||||||
|
attrib=MeasureGetMeasGroupAttrib.DEVICE_ENTRY_FOR_USER,
|
||||||
|
category=MeasureGetMeasGroupCategory.REAL,
|
||||||
|
created=arrow.utcnow().shift(hours=-1),
|
||||||
|
date=arrow.utcnow().shift(hours=-1),
|
||||||
|
deviceid="DEV_ID",
|
||||||
|
grpid=1,
|
||||||
|
measures=(
|
||||||
|
MeasureGetMeasMeasure(type=MeasureType.WEIGHT, unit=0, value=70),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.FAT_MASS_WEIGHT, unit=0, value=5
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.FAT_FREE_MASS, unit=0, value=60
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.MUSCLE_MASS, unit=0, value=50
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(type=MeasureType.BONE_MASS, unit=0, value=10),
|
||||||
|
MeasureGetMeasMeasure(type=MeasureType.HEIGHT, unit=0, value=2),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.TEMPERATURE, unit=0, value=40
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.BODY_TEMPERATURE, unit=0, value=40
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.SKIN_TEMPERATURE, unit=0, value=20
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.FAT_RATIO, unit=-3, value=70
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.DIASTOLIC_BLOOD_PRESSURE, unit=0, value=70
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.SYSTOLIC_BLOOD_PRESSURE, unit=0, value=100
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.HEART_RATE, unit=0, value=60
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(type=MeasureType.SP02, unit=-2, value=95),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.HYDRATION, unit=-2, value=95
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.PULSE_WAVE_VELOCITY, unit=0, value=100
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
MeasureGetMeasGroup(
|
||||||
|
attrib=MeasureGetMeasGroupAttrib.DEVICE_ENTRY_FOR_USER,
|
||||||
|
category=MeasureGetMeasGroupCategory.REAL,
|
||||||
|
created=arrow.utcnow().shift(hours=-2),
|
||||||
|
date=arrow.utcnow().shift(hours=-2),
|
||||||
|
deviceid="DEV_ID",
|
||||||
|
grpid=1,
|
||||||
|
measures=(
|
||||||
|
MeasureGetMeasMeasure(type=MeasureType.WEIGHT, unit=0, value=71),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.FAT_MASS_WEIGHT, unit=0, value=51
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.FAT_FREE_MASS, unit=0, value=61
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.MUSCLE_MASS, unit=0, value=51
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(type=MeasureType.BONE_MASS, unit=0, value=11),
|
||||||
|
MeasureGetMeasMeasure(type=MeasureType.HEIGHT, unit=0, value=21),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.TEMPERATURE, unit=0, value=41
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.BODY_TEMPERATURE, unit=0, value=41
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.SKIN_TEMPERATURE, unit=0, value=21
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.FAT_RATIO, unit=-3, value=71
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.DIASTOLIC_BLOOD_PRESSURE, unit=0, value=71
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.SYSTOLIC_BLOOD_PRESSURE, unit=0, value=101
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.HEART_RATE, unit=0, value=61
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(type=MeasureType.SP02, unit=-2, value=96),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.HYDRATION, unit=-2, value=96
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.PULSE_WAVE_VELOCITY, unit=0, value=101
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
MeasureGetMeasGroup(
|
||||||
|
attrib=MeasureGetMeasGroupAttrib.DEVICE_ENTRY_FOR_USER_AMBIGUOUS,
|
||||||
|
category=MeasureGetMeasGroupCategory.REAL,
|
||||||
|
created=arrow.utcnow(),
|
||||||
|
date=arrow.utcnow(),
|
||||||
|
deviceid="DEV_ID",
|
||||||
|
grpid=1,
|
||||||
|
measures=(
|
||||||
|
MeasureGetMeasMeasure(type=MeasureType.WEIGHT, unit=0, value=71),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.FAT_MASS_WEIGHT, unit=0, value=4
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.FAT_FREE_MASS, unit=0, value=40
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.MUSCLE_MASS, unit=0, value=51
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(type=MeasureType.BONE_MASS, unit=0, value=11),
|
||||||
|
MeasureGetMeasMeasure(type=MeasureType.HEIGHT, unit=0, value=201),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.TEMPERATURE, unit=0, value=41
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.BODY_TEMPERATURE, unit=0, value=34
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.SKIN_TEMPERATURE, unit=0, value=21
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.FAT_RATIO, unit=-3, value=71
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.DIASTOLIC_BLOOD_PRESSURE, unit=0, value=71
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.SYSTOLIC_BLOOD_PRESSURE, unit=0, value=101
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.HEART_RATE, unit=0, value=61
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(type=MeasureType.SP02, unit=-2, value=98),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.HYDRATION, unit=-2, value=96
|
||||||
|
),
|
||||||
|
MeasureGetMeasMeasure(
|
||||||
|
type=MeasureType.PULSE_WAVE_VELOCITY, unit=0, value=102
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
more=False,
|
||||||
|
timezone=dt_util.UTC,
|
||||||
|
updatetime=arrow.get("2019-08-01"),
|
||||||
|
offset=0,
|
||||||
|
),
|
||||||
|
api_response_sleep_get_summary=SleepGetSummaryResponse(
|
||||||
|
more=False,
|
||||||
|
offset=0,
|
||||||
|
series=(
|
||||||
|
GetSleepSummarySerie(
|
||||||
|
timezone=dt_util.UTC,
|
||||||
|
model=SleepModel.SLEEP_MONITOR,
|
||||||
|
startdate=arrow.get("2019-02-01"),
|
||||||
|
enddate=arrow.get("2019-02-01"),
|
||||||
|
date=arrow.get("2019-02-01"),
|
||||||
|
modified=arrow.get(12345),
|
||||||
|
data=GetSleepSummaryData(
|
||||||
|
breathing_disturbances_intensity=110,
|
||||||
|
deepsleepduration=111,
|
||||||
|
durationtosleep=112,
|
||||||
|
durationtowakeup=113,
|
||||||
|
hr_average=114,
|
||||||
|
hr_max=115,
|
||||||
|
hr_min=116,
|
||||||
|
lightsleepduration=117,
|
||||||
|
remsleepduration=118,
|
||||||
|
rr_average=119,
|
||||||
|
rr_max=120,
|
||||||
|
rr_min=121,
|
||||||
|
sleep_score=122,
|
||||||
|
snoring=123,
|
||||||
|
snoringepisodecount=124,
|
||||||
|
wakeupcount=125,
|
||||||
|
wakeupduration=126,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GetSleepSummarySerie(
|
||||||
|
timezone=dt_util.UTC,
|
||||||
|
model=SleepModel.SLEEP_MONITOR,
|
||||||
|
startdate=arrow.get("2019-02-01"),
|
||||||
|
enddate=arrow.get("2019-02-01"),
|
||||||
|
date=arrow.get("2019-02-01"),
|
||||||
|
modified=arrow.get(12345),
|
||||||
|
data=GetSleepSummaryData(
|
||||||
|
breathing_disturbances_intensity=210,
|
||||||
|
deepsleepduration=211,
|
||||||
|
durationtosleep=212,
|
||||||
|
durationtowakeup=213,
|
||||||
|
hr_average=214,
|
||||||
|
hr_max=215,
|
||||||
|
hr_min=216,
|
||||||
|
lightsleepduration=217,
|
||||||
|
remsleepduration=218,
|
||||||
|
rr_average=219,
|
||||||
|
rr_max=220,
|
||||||
|
rr_min=221,
|
||||||
|
sleep_score=222,
|
||||||
|
snoring=223,
|
||||||
|
snoringepisodecount=224,
|
||||||
|
wakeupcount=225,
|
||||||
|
wakeupduration=226,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def component_factory(
|
def component_factory(
|
||||||
@ -25,3 +286,83 @@ def component_factory(
|
|||||||
yield ComponentFactory(
|
yield ComponentFactory(
|
||||||
hass, api_class_mock, hass_client_no_auth, aioclient_mock
|
hass, api_class_mock, hass_client_no_auth, aioclient_mock
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="scopes")
|
||||||
|
def mock_scopes() -> list[str]:
|
||||||
|
"""Fixture to set the scopes present in the OAuth token."""
|
||||||
|
return SCOPES
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
async def setup_credentials(hass: HomeAssistant) -> None:
|
||||||
|
"""Fixture to setup credentials."""
|
||||||
|
assert await async_setup_component(hass, "application_credentials", {})
|
||||||
|
await async_import_client_credential(
|
||||||
|
hass,
|
||||||
|
DOMAIN,
|
||||||
|
ClientCredential(CLIENT_ID, CLIENT_SECRET),
|
||||||
|
DOMAIN,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="expires_at")
|
||||||
|
def mock_expires_at() -> int:
|
||||||
|
"""Fixture to set the oauth token expiration time."""
|
||||||
|
return time.time() + 3600
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="config_entry")
|
||||||
|
def mock_config_entry(expires_at: int, scopes: list[str]) -> MockConfigEntry:
|
||||||
|
"""Create Withings entry in Home Assistant."""
|
||||||
|
return MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
title=TITLE,
|
||||||
|
unique_id="12345",
|
||||||
|
data={
|
||||||
|
"auth_implementation": DOMAIN,
|
||||||
|
"token": {
|
||||||
|
"status": 0,
|
||||||
|
"userid": "12345",
|
||||||
|
"access_token": "mock-access-token",
|
||||||
|
"refresh_token": "mock-refresh-token",
|
||||||
|
"expires_at": expires_at,
|
||||||
|
"scope": ",".join(scopes),
|
||||||
|
},
|
||||||
|
"profile": TITLE,
|
||||||
|
"use_webhook": True,
|
||||||
|
"webhook_id": WEBHOOK_ID,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="setup_integration")
|
||||||
|
async def mock_setup_integration(
|
||||||
|
hass: HomeAssistant, config_entry: MockConfigEntry
|
||||||
|
) -> Callable[[], Coroutine[Any, Any, MockWithings]]:
|
||||||
|
"""Fixture for setting up the component."""
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
assert await async_setup_component(hass, "application_credentials", {})
|
||||||
|
await async_import_client_credential(
|
||||||
|
hass,
|
||||||
|
DOMAIN,
|
||||||
|
ClientCredential(CLIENT_ID, CLIENT_SECRET),
|
||||||
|
DOMAIN,
|
||||||
|
)
|
||||||
|
await async_process_ha_core_config(
|
||||||
|
hass,
|
||||||
|
{"internal_url": "http://example.local:8123"},
|
||||||
|
)
|
||||||
|
|
||||||
|
async def func() -> MockWithings:
|
||||||
|
mock = MockWithings(PERSON0)
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.withings.common.ConfigEntryWithingsApi",
|
||||||
|
return_value=mock,
|
||||||
|
):
|
||||||
|
assert await async_setup_component(hass, DOMAIN, {})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
return mock
|
||||||
|
|
||||||
|
return func
|
||||||
|
1254
tests/components/withings/snapshots/test_sensor.ambr
Normal file
1254
tests/components/withings/snapshots/test_sensor.ambr
Normal file
File diff suppressed because it is too large
Load Diff
@ -2,20 +2,9 @@
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import arrow
|
import pytest
|
||||||
from withings_api.common import (
|
from syrupy import SnapshotAssertion
|
||||||
GetSleepSummaryData,
|
from withings_api.common import NotifyAppli
|
||||||
GetSleepSummarySerie,
|
|
||||||
MeasureGetMeasGroup,
|
|
||||||
MeasureGetMeasGroupAttrib,
|
|
||||||
MeasureGetMeasGroupCategory,
|
|
||||||
MeasureGetMeasMeasure,
|
|
||||||
MeasureGetMeasResponse,
|
|
||||||
MeasureType,
|
|
||||||
NotifyAppli,
|
|
||||||
SleepGetSummaryResponse,
|
|
||||||
SleepModel,
|
|
||||||
)
|
|
||||||
|
|
||||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||||
from homeassistant.components.withings.common import WithingsEntityDescription
|
from homeassistant.components.withings.common import WithingsEntityDescription
|
||||||
@ -24,236 +13,17 @@ from homeassistant.components.withings.sensor import SENSORS
|
|||||||
from homeassistant.core import HomeAssistant, State
|
from homeassistant.core import HomeAssistant, State
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
from homeassistant.helpers.entity_registry import EntityRegistry
|
from homeassistant.helpers.entity_registry import EntityRegistry
|
||||||
from homeassistant.util import dt as dt_util
|
|
||||||
|
|
||||||
from .common import ComponentFactory, async_get_entity_id, new_profile_config
|
from . import MockWithings, call_webhook
|
||||||
|
from .common import async_get_entity_id
|
||||||
|
from .conftest import PERSON0, WEBHOOK_ID, ComponentSetup
|
||||||
|
|
||||||
|
from tests.typing import ClientSessionGenerator
|
||||||
|
|
||||||
WITHINGS_MEASUREMENTS_MAP: dict[Measurement, WithingsEntityDescription] = {
|
WITHINGS_MEASUREMENTS_MAP: dict[Measurement, WithingsEntityDescription] = {
|
||||||
attr.measurement: attr for attr in SENSORS
|
attr.measurement: attr for attr in SENSORS
|
||||||
}
|
}
|
||||||
|
|
||||||
PERSON0 = new_profile_config(
|
|
||||||
"person0",
|
|
||||||
0,
|
|
||||||
api_response_measure_get_meas=MeasureGetMeasResponse(
|
|
||||||
measuregrps=(
|
|
||||||
MeasureGetMeasGroup(
|
|
||||||
attrib=MeasureGetMeasGroupAttrib.DEVICE_ENTRY_FOR_USER,
|
|
||||||
category=MeasureGetMeasGroupCategory.REAL,
|
|
||||||
created=arrow.utcnow().shift(hours=-1),
|
|
||||||
date=arrow.utcnow().shift(hours=-1),
|
|
||||||
deviceid="DEV_ID",
|
|
||||||
grpid=1,
|
|
||||||
measures=(
|
|
||||||
MeasureGetMeasMeasure(type=MeasureType.WEIGHT, unit=0, value=70),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.FAT_MASS_WEIGHT, unit=0, value=5
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.FAT_FREE_MASS, unit=0, value=60
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.MUSCLE_MASS, unit=0, value=50
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(type=MeasureType.BONE_MASS, unit=0, value=10),
|
|
||||||
MeasureGetMeasMeasure(type=MeasureType.HEIGHT, unit=0, value=2),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.TEMPERATURE, unit=0, value=40
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.BODY_TEMPERATURE, unit=0, value=40
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.SKIN_TEMPERATURE, unit=0, value=20
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.FAT_RATIO, unit=-3, value=70
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.DIASTOLIC_BLOOD_PRESSURE, unit=0, value=70
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.SYSTOLIC_BLOOD_PRESSURE, unit=0, value=100
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.HEART_RATE, unit=0, value=60
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(type=MeasureType.SP02, unit=-2, value=95),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.HYDRATION, unit=-2, value=95
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.PULSE_WAVE_VELOCITY, unit=0, value=100
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
MeasureGetMeasGroup(
|
|
||||||
attrib=MeasureGetMeasGroupAttrib.DEVICE_ENTRY_FOR_USER,
|
|
||||||
category=MeasureGetMeasGroupCategory.REAL,
|
|
||||||
created=arrow.utcnow().shift(hours=-2),
|
|
||||||
date=arrow.utcnow().shift(hours=-2),
|
|
||||||
deviceid="DEV_ID",
|
|
||||||
grpid=1,
|
|
||||||
measures=(
|
|
||||||
MeasureGetMeasMeasure(type=MeasureType.WEIGHT, unit=0, value=71),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.FAT_MASS_WEIGHT, unit=0, value=51
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.FAT_FREE_MASS, unit=0, value=61
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.MUSCLE_MASS, unit=0, value=51
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(type=MeasureType.BONE_MASS, unit=0, value=11),
|
|
||||||
MeasureGetMeasMeasure(type=MeasureType.HEIGHT, unit=0, value=21),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.TEMPERATURE, unit=0, value=41
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.BODY_TEMPERATURE, unit=0, value=41
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.SKIN_TEMPERATURE, unit=0, value=21
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.FAT_RATIO, unit=-3, value=71
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.DIASTOLIC_BLOOD_PRESSURE, unit=0, value=71
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.SYSTOLIC_BLOOD_PRESSURE, unit=0, value=101
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.HEART_RATE, unit=0, value=61
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(type=MeasureType.SP02, unit=-2, value=96),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.HYDRATION, unit=-2, value=96
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.PULSE_WAVE_VELOCITY, unit=0, value=101
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
MeasureGetMeasGroup(
|
|
||||||
attrib=MeasureGetMeasGroupAttrib.DEVICE_ENTRY_FOR_USER_AMBIGUOUS,
|
|
||||||
category=MeasureGetMeasGroupCategory.REAL,
|
|
||||||
created=arrow.utcnow(),
|
|
||||||
date=arrow.utcnow(),
|
|
||||||
deviceid="DEV_ID",
|
|
||||||
grpid=1,
|
|
||||||
measures=(
|
|
||||||
MeasureGetMeasMeasure(type=MeasureType.WEIGHT, unit=0, value=71),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.FAT_MASS_WEIGHT, unit=0, value=4
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.FAT_FREE_MASS, unit=0, value=40
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.MUSCLE_MASS, unit=0, value=51
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(type=MeasureType.BONE_MASS, unit=0, value=11),
|
|
||||||
MeasureGetMeasMeasure(type=MeasureType.HEIGHT, unit=0, value=201),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.TEMPERATURE, unit=0, value=41
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.BODY_TEMPERATURE, unit=0, value=34
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.SKIN_TEMPERATURE, unit=0, value=21
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.FAT_RATIO, unit=-3, value=71
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.DIASTOLIC_BLOOD_PRESSURE, unit=0, value=71
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.SYSTOLIC_BLOOD_PRESSURE, unit=0, value=101
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.HEART_RATE, unit=0, value=61
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(type=MeasureType.SP02, unit=-2, value=98),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.HYDRATION, unit=-2, value=96
|
|
||||||
),
|
|
||||||
MeasureGetMeasMeasure(
|
|
||||||
type=MeasureType.PULSE_WAVE_VELOCITY, unit=0, value=102
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
more=False,
|
|
||||||
timezone=dt_util.UTC,
|
|
||||||
updatetime=arrow.get("2019-08-01"),
|
|
||||||
offset=0,
|
|
||||||
),
|
|
||||||
api_response_sleep_get_summary=SleepGetSummaryResponse(
|
|
||||||
more=False,
|
|
||||||
offset=0,
|
|
||||||
series=(
|
|
||||||
GetSleepSummarySerie(
|
|
||||||
timezone=dt_util.UTC,
|
|
||||||
model=SleepModel.SLEEP_MONITOR,
|
|
||||||
startdate=arrow.get("2019-02-01"),
|
|
||||||
enddate=arrow.get("2019-02-01"),
|
|
||||||
date=arrow.get("2019-02-01"),
|
|
||||||
modified=arrow.get(12345),
|
|
||||||
data=GetSleepSummaryData(
|
|
||||||
breathing_disturbances_intensity=110,
|
|
||||||
deepsleepduration=111,
|
|
||||||
durationtosleep=112,
|
|
||||||
durationtowakeup=113,
|
|
||||||
hr_average=114,
|
|
||||||
hr_max=115,
|
|
||||||
hr_min=116,
|
|
||||||
lightsleepduration=117,
|
|
||||||
remsleepduration=118,
|
|
||||||
rr_average=119,
|
|
||||||
rr_max=120,
|
|
||||||
rr_min=121,
|
|
||||||
sleep_score=122,
|
|
||||||
snoring=123,
|
|
||||||
snoringepisodecount=124,
|
|
||||||
wakeupcount=125,
|
|
||||||
wakeupduration=126,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
GetSleepSummarySerie(
|
|
||||||
timezone=dt_util.UTC,
|
|
||||||
model=SleepModel.SLEEP_MONITOR,
|
|
||||||
startdate=arrow.get("2019-02-01"),
|
|
||||||
enddate=arrow.get("2019-02-01"),
|
|
||||||
date=arrow.get("2019-02-01"),
|
|
||||||
modified=arrow.get(12345),
|
|
||||||
data=GetSleepSummaryData(
|
|
||||||
breathing_disturbances_intensity=210,
|
|
||||||
deepsleepduration=211,
|
|
||||||
durationtosleep=212,
|
|
||||||
durationtowakeup=213,
|
|
||||||
hr_average=214,
|
|
||||||
hr_max=215,
|
|
||||||
hr_min=216,
|
|
||||||
lightsleepduration=217,
|
|
||||||
remsleepduration=218,
|
|
||||||
rr_average=219,
|
|
||||||
rr_max=220,
|
|
||||||
rr_min=221,
|
|
||||||
sleep_score=222,
|
|
||||||
snoring=223,
|
|
||||||
snoringepisodecount=224,
|
|
||||||
wakeupcount=225,
|
|
||||||
wakeupduration=226,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
EXPECTED_DATA = (
|
EXPECTED_DATA = (
|
||||||
(PERSON0, Measurement.WEIGHT_KG, 70.0),
|
(PERSON0, Measurement.WEIGHT_KG, 70.0),
|
||||||
@ -304,25 +74,22 @@ def async_assert_state_equals(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||||
async def test_sensor_default_enabled_entities(
|
async def test_sensor_default_enabled_entities(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
component_factory: ComponentFactory,
|
setup_integration: ComponentSetup,
|
||||||
current_request_with_host: None,
|
hass_client_no_auth: ClientSessionGenerator,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test entities enabled by default."""
|
"""Test entities enabled by default."""
|
||||||
|
await setup_integration()
|
||||||
entity_registry: EntityRegistry = er.async_get(hass)
|
entity_registry: EntityRegistry = er.async_get(hass)
|
||||||
|
|
||||||
await component_factory.configure_component(profile_configs=(PERSON0,))
|
mock = MockWithings(PERSON0)
|
||||||
|
with patch(
|
||||||
# Assert entities should not exist yet.
|
"homeassistant.components.withings.common.ConfigEntryWithingsApi",
|
||||||
for attribute in SENSORS:
|
return_value=mock,
|
||||||
assert not await async_get_entity_id(
|
):
|
||||||
hass, attribute, PERSON0.user_id, SENSOR_DOMAIN
|
client = await hass_client_no_auth()
|
||||||
)
|
|
||||||
|
|
||||||
# person 0
|
|
||||||
await component_factory.setup_profile(PERSON0.user_id)
|
|
||||||
|
|
||||||
# Assert entities should exist.
|
# Assert entities should exist.
|
||||||
for attribute in SENSORS:
|
for attribute in SENSORS:
|
||||||
entity_id = await async_get_entity_id(
|
entity_id = await async_get_entity_id(
|
||||||
@ -330,11 +97,21 @@ async def test_sensor_default_enabled_entities(
|
|||||||
)
|
)
|
||||||
assert entity_id
|
assert entity_id
|
||||||
assert entity_registry.async_is_registered(entity_id)
|
assert entity_registry.async_is_registered(entity_id)
|
||||||
|
resp = await call_webhook(
|
||||||
resp = await component_factory.call_webhook(PERSON0.user_id, NotifyAppli.SLEEP)
|
hass,
|
||||||
|
WEBHOOK_ID,
|
||||||
|
{"userid": PERSON0.user_id, "appli": NotifyAppli.SLEEP},
|
||||||
|
client,
|
||||||
|
)
|
||||||
|
assert resp.message_code == 0
|
||||||
|
resp = await call_webhook(
|
||||||
|
hass,
|
||||||
|
WEBHOOK_ID,
|
||||||
|
{"userid": PERSON0.user_id, "appli": NotifyAppli.WEIGHT},
|
||||||
|
client,
|
||||||
|
)
|
||||||
assert resp.message_code == 0
|
assert resp.message_code == 0
|
||||||
|
|
||||||
resp = await component_factory.call_webhook(PERSON0.user_id, NotifyAppli.WEIGHT)
|
|
||||||
assert resp.message_code == 0
|
assert resp.message_code == 0
|
||||||
|
|
||||||
for person, measurement, expected in EXPECTED_DATA:
|
for person, measurement, expected in EXPECTED_DATA:
|
||||||
@ -344,61 +121,21 @@ async def test_sensor_default_enabled_entities(
|
|||||||
)
|
)
|
||||||
state_obj = hass.states.get(entity_id)
|
state_obj = hass.states.get(entity_id)
|
||||||
|
|
||||||
if attribute.entity_registry_enabled_default:
|
|
||||||
async_assert_state_equals(entity_id, state_obj, expected, attribute)
|
async_assert_state_equals(entity_id, state_obj, expected, attribute)
|
||||||
else:
|
|
||||||
assert state_obj is None
|
|
||||||
|
|
||||||
# Unload
|
|
||||||
await component_factory.unload(PERSON0)
|
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||||
async def test_all_entities(
|
async def test_all_entities(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant, setup_integration: ComponentSetup, snapshot: SnapshotAssertion
|
||||||
component_factory: ComponentFactory,
|
|
||||||
current_request_with_host: None,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test all entities."""
|
"""Test all entities."""
|
||||||
entity_registry: EntityRegistry = er.async_get(hass)
|
await setup_integration()
|
||||||
|
|
||||||
|
mock = MockWithings(PERSON0)
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.withings.sensor.BaseWithingsSensor.entity_registry_enabled_default"
|
"homeassistant.components.withings.common.ConfigEntryWithingsApi",
|
||||||
) as enabled_by_default_mock:
|
return_value=mock,
|
||||||
enabled_by_default_mock.return_value = True
|
):
|
||||||
|
for sensor in SENSORS:
|
||||||
await component_factory.configure_component(profile_configs=(PERSON0,))
|
entity_id = await async_get_entity_id(hass, sensor, 12345, SENSOR_DOMAIN)
|
||||||
|
assert hass.states.get(entity_id) == snapshot
|
||||||
# Assert entities should not exist yet.
|
|
||||||
for attribute in SENSORS:
|
|
||||||
assert not await async_get_entity_id(
|
|
||||||
hass, attribute, PERSON0.user_id, SENSOR_DOMAIN
|
|
||||||
)
|
|
||||||
|
|
||||||
# person 0
|
|
||||||
await component_factory.setup_profile(PERSON0.user_id)
|
|
||||||
|
|
||||||
# Assert entities should exist.
|
|
||||||
for attribute in SENSORS:
|
|
||||||
entity_id = await async_get_entity_id(
|
|
||||||
hass, attribute, PERSON0.user_id, SENSOR_DOMAIN
|
|
||||||
)
|
|
||||||
assert entity_id
|
|
||||||
assert entity_registry.async_is_registered(entity_id)
|
|
||||||
|
|
||||||
resp = await component_factory.call_webhook(PERSON0.user_id, NotifyAppli.SLEEP)
|
|
||||||
assert resp.message_code == 0
|
|
||||||
|
|
||||||
resp = await component_factory.call_webhook(PERSON0.user_id, NotifyAppli.WEIGHT)
|
|
||||||
assert resp.message_code == 0
|
|
||||||
|
|
||||||
for person, measurement, expected in EXPECTED_DATA:
|
|
||||||
attribute = WITHINGS_MEASUREMENTS_MAP[measurement]
|
|
||||||
entity_id = await async_get_entity_id(
|
|
||||||
hass, attribute, person.user_id, SENSOR_DOMAIN
|
|
||||||
)
|
|
||||||
state_obj = hass.states.get(entity_id)
|
|
||||||
|
|
||||||
async_assert_state_equals(entity_id, state_obj, expected, attribute)
|
|
||||||
|
|
||||||
# Unload
|
|
||||||
await component_factory.unload(PERSON0)
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user