Decouple Withings webhook tests from YAML (#100143)

This commit is contained in:
Joost Lekkerkerker 2023-09-11 21:06:20 +02:00 committed by GitHub
parent ad5e9e9f5b
commit 5c206de906
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 242 additions and 358 deletions

View File

@ -53,6 +53,8 @@ NOT_AUTHENTICATED_ERROR = re.compile(
re.IGNORECASE, re.IGNORECASE,
) )
DATA_UPDATED_SIGNAL = "withings_entity_state_updated" DATA_UPDATED_SIGNAL = "withings_entity_state_updated"
SUBSCRIBE_DELAY = datetime.timedelta(seconds=5)
UNSUBSCRIBE_DELAY = datetime.timedelta(seconds=1)
class UpdateType(StrEnum): class UpdateType(StrEnum):
@ -229,8 +231,8 @@ class DataManager:
self._user_id = user_id self._user_id = user_id
self._profile = profile self._profile = profile
self._webhook_config = webhook_config self._webhook_config = webhook_config
self._notify_subscribe_delay = datetime.timedelta(seconds=5) self._notify_subscribe_delay = SUBSCRIBE_DELAY
self._notify_unsubscribe_delay = datetime.timedelta(seconds=1) self._notify_unsubscribe_delay = UNSUBSCRIBE_DELAY
self._is_available = True self._is_available = True
self._cancel_interval_update_interval: CALLBACK_TYPE | None = None self._cancel_interval_update_interval: CALLBACK_TYPE | None = None

View File

@ -1,27 +1,21 @@
"""Tests for the withings component.""" """Tests for the withings component."""
from collections.abc import Iterable from dataclasses import dataclass
from typing import Any from typing import Any
from urllib.parse import urlparse from urllib.parse import urlparse
import arrow
from withings_api import DateType
from withings_api.common import (
GetSleepSummaryField,
MeasureGetMeasGroupCategory,
MeasureGetMeasResponse,
MeasureType,
NotifyAppli,
NotifyListResponse,
SleepGetSummaryResponse,
UserGetDeviceResponse,
)
from homeassistant.components.webhook import async_generate_url from homeassistant.components.webhook import async_generate_url
from homeassistant.config import async_process_ha_core_config
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from .common import WebhookResponse from tests.common import MockConfigEntry
from tests.common import load_json_object_fixture
@dataclass
class WebhookResponse:
"""Response data from a webhook."""
message: str
message_code: int
async def call_webhook( async def call_webhook(
@ -44,56 +38,13 @@ async def call_webhook(
return WebhookResponse(message=data["message"], message_code=data["code"]) return WebhookResponse(message=data["message"], message_code=data["code"])
class MockWithings: async def setup_integration(hass: HomeAssistant, config_entry: MockConfigEntry) -> None:
"""Mock object for Withings.""" """Fixture for setting up the component."""
config_entry.add_to_hass(hass)
def __init__( await async_process_ha_core_config(
self, hass,
device_fixture: str = "person0_get_device.json", {"internal_url": "http://example.local:8123"},
measurement_fixture: str = "person0_get_meas.json", )
sleep_fixture: str = "person0_get_sleep.json",
notify_list_fixture: str = "person0_notify_list.json",
):
"""Initialize mock."""
self.device_fixture = device_fixture
self.measurement_fixture = measurement_fixture
self.sleep_fixture = sleep_fixture
self.notify_list_fixture = notify_list_fixture
def user_get_device(self) -> UserGetDeviceResponse: await hass.config_entries.async_setup(config_entry.entry_id)
"""Get devices."""
fixture = load_json_object_fixture(f"withings/{self.device_fixture}")
return UserGetDeviceResponse(**fixture)
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."""
fixture = load_json_object_fixture(f"withings/{self.measurement_fixture}")
return MeasureGetMeasResponse(**fixture)
def sleep_get_summary(
self,
data_fields: Iterable[GetSleepSummaryField],
startdateymd: DateType | None = arrow.utcnow(),
enddateymd: DateType | None = arrow.utcnow(),
offset: int | None = None,
lastupdate: DateType | None = arrow.utcnow(),
) -> SleepGetSummaryResponse:
"""Get sleep."""
fixture = load_json_object_fixture(f"withings/{self.sleep_fixture}")
return SleepGetSummaryResponse(**fixture)
def notify_list(
self,
appli: NotifyAppli | None = None,
) -> NotifyListResponse:
"""Get sleep."""
fixture = load_json_object_fixture(f"withings/{self.notify_list_fixture}")
return NotifyListResponse(**fixture)

View File

@ -44,6 +44,7 @@ from homeassistant.setup import async_setup_component
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
from tests.components.withings import WebhookResponse
from tests.test_util.aiohttp import AiohttpClientMocker from tests.test_util.aiohttp import AiohttpClientMocker
@ -91,14 +92,6 @@ def new_profile_config(
) )
@dataclass
class WebhookResponse:
"""Response data from a webhook."""
message: str
message_code: int
class ComponentFactory: class ComponentFactory:
"""Manages the setup and unloading of the withing component and profiles.""" """Manages the setup and unloading of the withing component and profiles."""

View File

@ -1,28 +1,30 @@
"""Fixtures for tests.""" """Fixtures for tests."""
from collections.abc import Awaitable, Callable, Coroutine from datetime import timedelta
import time import time
from typing import Any from unittest.mock import AsyncMock, patch
from unittest.mock import patch
import pytest import pytest
from withings_api import (
MeasureGetMeasResponse,
NotifyListResponse,
SleepGetSummaryResponse,
UserGetDeviceResponse,
)
from homeassistant.components.application_credentials import ( from homeassistant.components.application_credentials import (
ClientCredential, ClientCredential,
async_import_client_credential, async_import_client_credential,
) )
from homeassistant.components.withings.common import ConfigEntryWithingsApi
from homeassistant.components.withings.const import DOMAIN 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.setup import async_setup_component
from . import MockWithings
from .common import ComponentFactory from .common import ComponentFactory
from tests.common import MockConfigEntry from tests.common import MockConfigEntry, load_json_object_fixture
from tests.test_util.aiohttp import AiohttpClientMocker from tests.test_util.aiohttp import AiohttpClientMocker
ComponentSetup = Callable[[], Awaitable[MockWithings]]
CLIENT_ID = "1234" CLIENT_ID = "1234"
CLIENT_SECRET = "5678" CLIENT_SECRET = "5678"
SCOPES = [ SCOPES = [
@ -100,33 +102,40 @@ def mock_config_entry(expires_at: int, scopes: list[str]) -> MockConfigEntry:
) )
@pytest.fixture(name="setup_integration") @pytest.fixture(name="withings")
async def mock_setup_integration( def mock_withings():
hass: HomeAssistant, config_entry: MockConfigEntry """Mock withings."""
) -> 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", {}) mock = AsyncMock(spec=ConfigEntryWithingsApi)
await async_import_client_credential( mock.user_get_device.return_value = UserGetDeviceResponse(
hass, **load_json_object_fixture("withings/get_device.json")
DOMAIN,
ClientCredential(CLIENT_ID, CLIENT_SECRET),
DOMAIN,
) )
await async_process_ha_core_config( mock.measure_get_meas.return_value = MeasureGetMeasResponse(
hass, **load_json_object_fixture("withings/get_meas.json")
{"internal_url": "http://example.local:8123"}, )
mock.sleep_get_summary.return_value = SleepGetSummaryResponse(
**load_json_object_fixture("withings/get_sleep.json")
)
mock.notify_list.return_value = NotifyListResponse(
**load_json_object_fixture("withings/notify_list.json")
) )
async def func() -> MockWithings: with patch(
mock = MockWithings() "homeassistant.components.withings.common.ConfigEntryWithingsApi",
with patch( return_value=mock,
"homeassistant.components.withings.common.ConfigEntryWithingsApi", ):
return_value=mock, yield mock
):
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
return mock
return func
@pytest.fixture(name="disable_webhook_delay")
def disable_webhook_delay():
"""Disable webhook delay."""
mock = AsyncMock()
with patch(
"homeassistant.components.withings.common.SUBSCRIBE_DELAY", timedelta(seconds=0)
), patch(
"homeassistant.components.withings.common.UNSUBSCRIBE_DELAY",
timedelta(seconds=0),
):
yield mock

View File

@ -0,0 +1,15 @@
{
"devices": [
{
"type": "Scale",
"battery": "high",
"model": "Body+",
"model_id": 5,
"timezone": "Europe/Amsterdam",
"first_session_date": null,
"last_session_date": 1693867179,
"deviceid": "f998be4b9ccc9e136fd8cd8e8e344c31ec3b271d",
"hash_deviceid": "f998be4b9ccc9e136fd8cd8e8e344c31ec3b271d"
}
]
}

View File

@ -0,0 +1,22 @@
{
"profiles": [
{
"appli": 50,
"callbackurl": "https://not.my.callback/url",
"expires": 2147483647,
"comment": null
},
{
"appli": 50,
"callbackurl": "http://example.local:8123/api/webhook/55a7335ea8dee830eed4ef8f84cda8f6d80b83af0847dc74032e86120bffed5e",
"expires": 2147483647,
"comment": null
},
{
"appli": 51,
"callbackurl": "http://example.local:8123/api/webhook/55a7335ea8dee830eed4ef8f84cda8f6d80b83af0847dc74032e86120bffed5e",
"expires": 2147483647,
"comment": null
}
]
}

View File

@ -1,18 +0,0 @@
{
"status": 0,
"body": {
"devices": [
{
"type": "Scale",
"battery": "high",
"model": "Body+",
"model_id": 5,
"timezone": "Europe/Amsterdam",
"first_session_date": null,
"last_session_date": 1693867179,
"deviceid": "f998be4b9ccc9e136fd8cd8e8e344c31ec3b271d",
"hash_deviceid": "f998be4b9ccc9e136fd8cd8e8e344c31ec3b271d"
}
]
}
}

View File

@ -1,3 +0,0 @@
{
"profiles": []
}

View File

@ -1,51 +1,50 @@
"""Tests for the Withings component.""" """Tests for the Withings component."""
from unittest.mock import patch from unittest.mock import AsyncMock
from withings_api.common import NotifyAppli from withings_api.common import NotifyAppli
from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from . import MockWithings, call_webhook from . import call_webhook, setup_integration
from .conftest import USER_ID, WEBHOOK_ID, ComponentSetup from .conftest import USER_ID, WEBHOOK_ID
from tests.common import MockConfigEntry
from tests.typing import ClientSessionGenerator from tests.typing import ClientSessionGenerator
async def test_binary_sensor( async def test_binary_sensor(
hass: HomeAssistant, hass: HomeAssistant,
setup_integration: ComponentSetup, withings: AsyncMock,
disable_webhook_delay,
config_entry: MockConfigEntry,
hass_client_no_auth: ClientSessionGenerator, hass_client_no_auth: ClientSessionGenerator,
) -> None: ) -> None:
"""Test binary sensor.""" """Test binary sensor."""
await setup_integration() await setup_integration(hass, config_entry)
mock = MockWithings()
with patch(
"homeassistant.components.withings.common.ConfigEntryWithingsApi",
return_value=mock,
):
client = await hass_client_no_auth()
entity_id = "binary_sensor.henk_in_bed" client = await hass_client_no_auth()
assert hass.states.get(entity_id).state == STATE_UNAVAILABLE entity_id = "binary_sensor.henk_in_bed"
resp = await call_webhook( assert hass.states.get(entity_id).state == STATE_UNAVAILABLE
hass,
WEBHOOK_ID,
{"userid": USER_ID, "appli": NotifyAppli.BED_IN},
client,
)
assert resp.message_code == 0
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_ON
resp = await call_webhook( resp = await call_webhook(
hass, hass,
WEBHOOK_ID, WEBHOOK_ID,
{"userid": USER_ID, "appli": NotifyAppli.BED_OUT}, {"userid": USER_ID, "appli": NotifyAppli.BED_IN},
client, client,
) )
assert resp.message_code == 0 assert resp.message_code == 0
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_OFF assert hass.states.get(entity_id).state == STATE_ON
resp = await call_webhook(
hass,
WEBHOOK_ID,
{"userid": USER_ID, "appli": NotifyAppli.BED_OUT},
client,
)
assert resp.message_code == 0
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_OFF

View File

@ -1,5 +1,4 @@
"""Tests for the Withings component.""" """Tests for the Withings component."""
import datetime
from http import HTTPStatus from http import HTTPStatus
import re import re
from typing import Any from typing import Any
@ -9,20 +8,15 @@ from urllib.parse import urlparse
from aiohttp.test_utils import TestClient from aiohttp.test_utils import TestClient
import pytest import pytest
import requests_mock import requests_mock
from withings_api.common import NotifyAppli, NotifyListProfile, NotifyListResponse from withings_api.common import NotifyAppli
from homeassistant.components.withings.common import ( from homeassistant.components.withings.common import ConfigEntryWithingsApi
ConfigEntryWithingsApi,
DataManager,
WebhookConfig,
)
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.config_entry_oauth2_flow import AbstractOAuth2Implementation from homeassistant.helpers.config_entry_oauth2_flow import AbstractOAuth2Implementation
from .common import ComponentFactory, get_data_manager_by_user_id, new_profile_config from .common import ComponentFactory, get_data_manager_by_user_id, new_profile_config
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
from tests.test_util.aiohttp import AiohttpClientMocker
from tests.typing import ClientSessionGenerator from tests.typing import ClientSessionGenerator
@ -101,137 +95,3 @@ async def test_webhook_post(
resp.close() resp.close()
assert data["code"] == expected_code assert data["code"] == expected_code
async def test_webhook_head(
hass: HomeAssistant,
component_factory: ComponentFactory,
aiohttp_client: ClientSessionGenerator,
current_request_with_host: None,
) -> None:
"""Test head method on webhook view."""
person0 = new_profile_config("person0", 0)
await component_factory.configure_component(profile_configs=(person0,))
await component_factory.setup_profile(person0.user_id)
data_manager = get_data_manager_by_user_id(hass, person0.user_id)
client: TestClient = await aiohttp_client(hass.http.app)
resp = await client.head(urlparse(data_manager.webhook_config.url).path)
assert resp.status == HTTPStatus.OK
async def test_webhook_put(
hass: HomeAssistant,
component_factory: ComponentFactory,
aiohttp_client: ClientSessionGenerator,
current_request_with_host: None,
) -> None:
"""Test webhook callback."""
person0 = new_profile_config("person0", 0)
await component_factory.configure_component(profile_configs=(person0,))
await component_factory.setup_profile(person0.user_id)
data_manager = get_data_manager_by_user_id(hass, person0.user_id)
client: TestClient = await aiohttp_client(hass.http.app)
resp = await client.put(urlparse(data_manager.webhook_config.url).path)
# Wait for remaining tasks to complete.
await hass.async_block_till_done()
assert resp.status == HTTPStatus.OK
data = await resp.json()
assert data
assert data["code"] == 2
async def test_data_manager_webhook_subscription(
hass: HomeAssistant,
component_factory: ComponentFactory,
aioclient_mock: AiohttpClientMocker,
) -> None:
"""Test data manager webhook subscriptions."""
person0 = new_profile_config("person0", 0)
await component_factory.configure_component(profile_configs=(person0,))
api: ConfigEntryWithingsApi = MagicMock(spec=ConfigEntryWithingsApi)
data_manager = DataManager(
hass,
"person0",
api,
0,
WebhookConfig(id="1234", url="http://localhost/api/webhook/1234", enabled=True),
)
data_manager._notify_subscribe_delay = datetime.timedelta(seconds=0)
data_manager._notify_unsubscribe_delay = datetime.timedelta(seconds=0)
api.notify_list.return_value = NotifyListResponse(
profiles=(
NotifyListProfile(
appli=NotifyAppli.BED_IN,
callbackurl="https://not.my.callback/url",
expires=None,
comment=None,
),
NotifyListProfile(
appli=NotifyAppli.BED_IN,
callbackurl=data_manager.webhook_config.url,
expires=None,
comment=None,
),
NotifyListProfile(
appli=NotifyAppli.BED_OUT,
callbackurl=data_manager.webhook_config.url,
expires=None,
comment=None,
),
)
)
aioclient_mock.clear_requests()
aioclient_mock.request(
"HEAD",
data_manager.webhook_config.url,
status=HTTPStatus.OK,
)
# Test subscribing
await data_manager.async_subscribe_webhook()
api.notify_subscribe.assert_any_call(
data_manager.webhook_config.url, NotifyAppli.WEIGHT
)
api.notify_subscribe.assert_any_call(
data_manager.webhook_config.url, NotifyAppli.CIRCULATORY
)
api.notify_subscribe.assert_any_call(
data_manager.webhook_config.url, NotifyAppli.ACTIVITY
)
api.notify_subscribe.assert_any_call(
data_manager.webhook_config.url, NotifyAppli.SLEEP
)
with pytest.raises(AssertionError):
api.notify_subscribe.assert_any_call(
data_manager.webhook_config.url, NotifyAppli.USER
)
with pytest.raises(AssertionError):
api.notify_subscribe.assert_any_call(
data_manager.webhook_config.url, NotifyAppli.BED_IN
)
with pytest.raises(AssertionError):
api.notify_subscribe.assert_any_call(
data_manager.webhook_config.url, NotifyAppli.BED_OUT
)
# Test unsubscribing.
await data_manager.async_unsubscribe_webhook()
api.notify_revoke.assert_any_call(
data_manager.webhook_config.url, NotifyAppli.BED_IN
)
api.notify_revoke.assert_any_call(
data_manager.webhook_config.url, NotifyAppli.BED_OUT
)

View File

@ -86,6 +86,7 @@ async def test_config_non_unique_profile(
hass: HomeAssistant, hass: HomeAssistant,
hass_client_no_auth: ClientSessionGenerator, hass_client_no_auth: ClientSessionGenerator,
current_request_with_host: None, current_request_with_host: None,
disable_webhook_delay,
aioclient_mock: AiohttpClientMocker, aioclient_mock: AiohttpClientMocker,
) -> None: ) -> None:
"""Test setup a non-unique profile.""" """Test setup a non-unique profile."""
@ -154,6 +155,7 @@ async def test_config_reauth_profile(
hass_client_no_auth: ClientSessionGenerator, hass_client_no_auth: ClientSessionGenerator,
aioclient_mock: AiohttpClientMocker, aioclient_mock: AiohttpClientMocker,
config_entry: MockConfigEntry, config_entry: MockConfigEntry,
disable_webhook_delay,
current_request_with_host, current_request_with_host,
) -> None: ) -> None:
"""Test reauth an existing profile re-creates the config entry.""" """Test reauth an existing profile re-creates the config entry."""

View File

@ -1,11 +1,14 @@
"""Tests for the Withings component.""" """Tests for the Withings component."""
from unittest.mock import MagicMock, patch from datetime import timedelta
from unittest.mock import AsyncMock, MagicMock, patch
from urllib.parse import urlparse
import pytest import pytest
import voluptuous as vol import voluptuous as vol
from withings_api.common import UnauthorizedException from withings_api.common import NotifyAppli, UnauthorizedException
import homeassistant.components.webhook as webhook import homeassistant.components.webhook as webhook
from homeassistant.components.webhook import async_generate_url
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 ConfigEntryWithingsApi, DataManager from homeassistant.components.withings.common import ConfigEntryWithingsApi, DataManager
from homeassistant.config import async_process_ha_core_config from homeassistant.config import async_process_ha_core_config
@ -19,10 +22,14 @@ from homeassistant.const import (
from homeassistant.core import DOMAIN as HA_DOMAIN, HomeAssistant 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 homeassistant.setup import async_setup_component
from homeassistant.util import dt as dt_util
from . import setup_integration
from .common import ComponentFactory, get_data_manager_by_user_id, new_profile_config from .common import ComponentFactory, get_data_manager_by_user_id, new_profile_config
from .conftest import WEBHOOK_ID
from tests.common import MockConfigEntry from tests.common import MockConfigEntry, async_fire_time_changed
from tests.typing import ClientSessionGenerator
def config_schema_validate(withings_config) -> dict: def config_schema_validate(withings_config) -> dict:
@ -224,3 +231,57 @@ async def test_set_convert_unique_id_to_string(hass: HomeAssistant) -> None:
await hass.async_block_till_done() await hass.async_block_till_done()
assert config_entry.unique_id == "1234" assert config_entry.unique_id == "1234"
async def test_data_manager_webhook_subscription(
hass: HomeAssistant,
withings: AsyncMock,
disable_webhook_delay,
config_entry: MockConfigEntry,
hass_client_no_auth: ClientSessionGenerator,
) -> None:
"""Test data manager webhook subscriptions."""
await setup_integration(hass, config_entry)
await hass_client_no_auth()
await hass.async_block_till_done()
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=1))
await hass.async_block_till_done()
assert withings.notify_subscribe.call_count == 4
webhook_url = "http://example.local:8123/api/webhook/55a7335ea8dee830eed4ef8f84cda8f6d80b83af0847dc74032e86120bffed5e"
withings.notify_subscribe.assert_any_call(webhook_url, NotifyAppli.WEIGHT)
withings.notify_subscribe.assert_any_call(webhook_url, NotifyAppli.CIRCULATORY)
withings.notify_subscribe.assert_any_call(webhook_url, NotifyAppli.ACTIVITY)
withings.notify_subscribe.assert_any_call(webhook_url, NotifyAppli.SLEEP)
withings.notify_revoke.assert_any_call(webhook_url, NotifyAppli.BED_IN)
withings.notify_revoke.assert_any_call(webhook_url, NotifyAppli.BED_OUT)
@pytest.mark.parametrize(
"method",
[
"PUT",
"HEAD",
],
)
async def test_requests(
hass: HomeAssistant,
withings: AsyncMock,
config_entry: MockConfigEntry,
hass_client_no_auth: ClientSessionGenerator,
method: str,
disable_webhook_delay,
) -> None:
"""Test we handle request methods Withings sends."""
await setup_integration(hass, config_entry)
client = await hass_client_no_auth()
webhook_url = async_generate_url(hass, WEBHOOK_ID)
response = await client.request(
method=method,
path=urlparse(webhook_url).path,
)
assert response.status == 200

View File

@ -1,6 +1,6 @@
"""Tests for the Withings component.""" """Tests for the Withings component."""
from typing import Any from typing import Any
from unittest.mock import patch from unittest.mock import AsyncMock
import pytest import pytest
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
@ -14,10 +14,11 @@ 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 . import MockWithings, call_webhook from . import call_webhook, setup_integration
from .common import async_get_entity_id from .common import async_get_entity_id
from .conftest import USER_ID, WEBHOOK_ID, ComponentSetup from .conftest import USER_ID, WEBHOOK_ID
from tests.common import MockConfigEntry
from tests.typing import ClientSessionGenerator from tests.typing import ClientSessionGenerator
WITHINGS_MEASUREMENTS_MAP: dict[Measurement, WithingsEntityDescription] = { WITHINGS_MEASUREMENTS_MAP: dict[Measurement, WithingsEntityDescription] = {
@ -77,65 +78,55 @@ def async_assert_state_equals(
@pytest.mark.usefixtures("entity_registry_enabled_by_default") @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,
setup_integration: ComponentSetup, withings: AsyncMock,
config_entry: MockConfigEntry,
disable_webhook_delay,
hass_client_no_auth: ClientSessionGenerator, hass_client_no_auth: ClientSessionGenerator,
) -> None: ) -> None:
"""Test entities enabled by default.""" """Test entities enabled by default."""
await setup_integration() await setup_integration(hass, config_entry)
entity_registry: EntityRegistry = er.async_get(hass) entity_registry: EntityRegistry = er.async_get(hass)
mock = MockWithings() client = await hass_client_no_auth()
with patch( # Assert entities should exist.
"homeassistant.components.withings.common.ConfigEntryWithingsApi", for attribute in SENSORS:
return_value=mock, entity_id = await async_get_entity_id(hass, attribute, USER_ID, SENSOR_DOMAIN)
): assert entity_id
client = await hass_client_no_auth() assert entity_registry.async_is_registered(entity_id)
# Assert entities should exist. resp = await call_webhook(
for attribute in SENSORS: hass,
entity_id = await async_get_entity_id( WEBHOOK_ID,
hass, attribute, USER_ID, SENSOR_DOMAIN {"userid": USER_ID, "appli": NotifyAppli.SLEEP},
) client,
assert entity_id )
assert entity_registry.async_is_registered(entity_id) assert resp.message_code == 0
resp = await call_webhook( resp = await call_webhook(
hass, hass,
WEBHOOK_ID, WEBHOOK_ID,
{"userid": USER_ID, "appli": NotifyAppli.SLEEP}, {"userid": USER_ID, "appli": NotifyAppli.WEIGHT},
client, client,
) )
assert resp.message_code == 0 assert resp.message_code == 0
resp = await call_webhook(
hass,
WEBHOOK_ID,
{"userid": USER_ID, "appli": NotifyAppli.WEIGHT},
client,
)
assert resp.message_code == 0
assert resp.message_code == 0 for measurement, expected in EXPECTED_DATA:
attribute = WITHINGS_MEASUREMENTS_MAP[measurement]
entity_id = await async_get_entity_id(hass, attribute, USER_ID, SENSOR_DOMAIN)
state_obj = hass.states.get(entity_id)
for measurement, expected in EXPECTED_DATA: async_assert_state_equals(entity_id, state_obj, expected, attribute)
attribute = WITHINGS_MEASUREMENTS_MAP[measurement]
entity_id = await async_get_entity_id(
hass, attribute, USER_ID, SENSOR_DOMAIN
)
state_obj = hass.states.get(entity_id)
async_assert_state_equals(entity_id, state_obj, expected, attribute)
@pytest.mark.usefixtures("entity_registry_enabled_by_default") @pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_all_entities( async def test_all_entities(
hass: HomeAssistant, setup_integration: ComponentSetup, snapshot: SnapshotAssertion hass: HomeAssistant,
snapshot: SnapshotAssertion,
withings: AsyncMock,
disable_webhook_delay,
config_entry: MockConfigEntry,
) -> None: ) -> None:
"""Test all entities.""" """Test all entities."""
await setup_integration() await setup_integration(hass, config_entry)
mock = MockWithings() for sensor in SENSORS:
with patch( entity_id = await async_get_entity_id(hass, sensor, USER_ID, SENSOR_DOMAIN)
"homeassistant.components.withings.common.ConfigEntryWithingsApi", assert hass.states.get(entity_id) == snapshot
return_value=mock,
):
for sensor in SENSORS:
entity_id = await async_get_entity_id(hass, sensor, USER_ID, SENSOR_DOMAIN)
assert hass.states.get(entity_id) == snapshot