Add Withings webhooks after a slight delay (#101542)

This commit is contained in:
Joost Lekkerkerker 2023-10-06 18:21:06 +02:00 committed by GitHub
parent 6359390a78
commit b2cad2370b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 38 additions and 44 deletions

View File

@ -38,7 +38,6 @@ from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
from homeassistant.helpers import config_entry_oauth2_flow, config_validation as cv from homeassistant.helpers import config_entry_oauth2_flow, config_validation as cv
from homeassistant.helpers.event import async_call_later from homeassistant.helpers.event import async_call_later
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
from homeassistant.helpers.start import async_at_started
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from .api import ConfigEntryWithingsApi from .api import ConfigEntryWithingsApi
@ -187,12 +186,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
if cloud.async_active_subscription(hass): if cloud.async_active_subscription(hass):
if cloud.async_is_connected(hass): if cloud.async_is_connected(hass):
await register_webhook(None) entry.async_on_unload(async_call_later(hass, 1, register_webhook))
entry.async_on_unload( entry.async_on_unload(
cloud.async_listen_connection_change(hass, manage_cloudhook) cloud.async_listen_connection_change(hass, manage_cloudhook)
) )
else: else:
entry.async_on_unload(async_at_started(hass, register_webhook)) entry.async_on_unload(async_call_later(hass, 1, register_webhook))
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
entry.async_on_unload(entry.add_update_listener(update_listener)) entry.async_on_unload(entry.add_update_listener(update_listener))

View File

@ -1,15 +1,17 @@
"""Tests for the withings component.""" """Tests for the withings component."""
from dataclasses import dataclass from dataclasses import dataclass
from datetime import timedelta
from typing import Any from typing import Any
from urllib.parse import urlparse from urllib.parse import urlparse
from aiohttp.test_utils import TestClient from aiohttp.test_utils import TestClient
from freezegun.api import FrozenDateTimeFactory
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.config import async_process_ha_core_config
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry from tests.common import MockConfigEntry, async_fire_time_changed
@dataclass @dataclass
@ -53,3 +55,12 @@ async def setup_integration(
) )
await hass.config_entries.async_setup(config_entry.entry_id) await hass.config_entries.async_setup(config_entry.entry_id)
async def prepare_webhook_setup(
hass: HomeAssistant, freezer: FrozenDateTimeFactory
) -> None:
"""Prepare webhooks are registered by waiting a second."""
freezer.tick(timedelta(seconds=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()

View File

@ -2,13 +2,14 @@
from unittest.mock import AsyncMock from unittest.mock import AsyncMock
from aiohttp.client_exceptions import ClientResponseError from aiohttp.client_exceptions import ClientResponseError
from freezegun.api import FrozenDateTimeFactory
import pytest import pytest
from withings_api.common import NotifyAppli from withings_api.common import NotifyAppli
from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNKNOWN from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNKNOWN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from . import call_webhook, setup_integration from . import call_webhook, prepare_webhook_setup, setup_integration
from .conftest import USER_ID, WEBHOOK_ID from .conftest import USER_ID, WEBHOOK_ID
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
@ -20,9 +21,11 @@ async def test_binary_sensor(
withings: AsyncMock, withings: AsyncMock,
webhook_config_entry: MockConfigEntry, webhook_config_entry: MockConfigEntry,
hass_client_no_auth: ClientSessionGenerator, hass_client_no_auth: ClientSessionGenerator,
freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test binary sensor.""" """Test binary sensor."""
await setup_integration(hass, webhook_config_entry) await setup_integration(hass, webhook_config_entry)
await prepare_webhook_setup(hass, freezer)
client = await hass_client_no_auth() client = await hass_client_no_auth()

View File

@ -15,16 +15,11 @@ from homeassistant.components.cloud import CloudNotAvailable
from homeassistant.components.webhook import async_generate_url from homeassistant.components.webhook import async_generate_url
from homeassistant.components.withings import CONFIG_SCHEMA, async_setup from homeassistant.components.withings import CONFIG_SCHEMA, async_setup
from homeassistant.components.withings.const import CONF_USE_WEBHOOK, DOMAIN from homeassistant.components.withings.const import CONF_USE_WEBHOOK, DOMAIN
from homeassistant.const import ( from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET, CONF_WEBHOOK_ID
CONF_CLIENT_ID, from homeassistant.core import HomeAssistant
CONF_CLIENT_SECRET,
CONF_WEBHOOK_ID,
EVENT_HOMEASSISTANT_STARTED,
)
from homeassistant.core import CoreState, HomeAssistant
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from . import call_webhook, setup_integration from . import call_webhook, prepare_webhook_setup, setup_integration
from .conftest import USER_ID, WEBHOOK_ID from .conftest import USER_ID, WEBHOOK_ID
from tests.common import ( from tests.common import (
@ -197,9 +192,12 @@ async def test_webhooks_request_data(
withings: AsyncMock, withings: AsyncMock,
webhook_config_entry: MockConfigEntry, webhook_config_entry: MockConfigEntry,
hass_client_no_auth: ClientSessionGenerator, hass_client_no_auth: ClientSessionGenerator,
freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test calling a webhook requests data.""" """Test calling a webhook requests data."""
await setup_integration(hass, webhook_config_entry) await setup_integration(hass, webhook_config_entry)
await prepare_webhook_setup(hass, freezer)
client = await hass_client_no_auth() client = await hass_client_no_auth()
assert withings.async_measure_get_meas.call_count == 1 assert withings.async_measure_get_meas.call_count == 1
@ -213,35 +211,6 @@ async def test_webhooks_request_data(
assert withings.async_measure_get_meas.call_count == 2 assert withings.async_measure_get_meas.call_count == 2
async def test_delayed_startup(
hass: HomeAssistant,
withings: AsyncMock,
webhook_config_entry: MockConfigEntry,
hass_client_no_auth: ClientSessionGenerator,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test delayed start up."""
hass.state = CoreState.not_running
await setup_integration(hass, webhook_config_entry)
withings.async_notify_subscribe.assert_not_called()
client = await hass_client_no_auth()
assert withings.async_measure_get_meas.call_count == 1
await hass.async_block_till_done()
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
await hass.async_block_till_done()
await call_webhook(
hass,
WEBHOOK_ID,
{"userid": USER_ID, "appli": NotifyAppli.WEIGHT},
client,
)
assert withings.async_measure_get_meas.call_count == 2
@pytest.mark.parametrize( @pytest.mark.parametrize(
"error", "error",
[ [
@ -395,7 +364,10 @@ async def test_removing_entry_with_cloud_unavailable(
async def test_setup_with_cloud( async def test_setup_with_cloud(
hass: HomeAssistant, webhook_config_entry: MockConfigEntry, withings: AsyncMock hass: HomeAssistant,
webhook_config_entry: MockConfigEntry,
withings: AsyncMock,
freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test if set up with active cloud subscription.""" """Test if set up with active cloud subscription."""
await mock_cloud(hass) await mock_cloud(hass)
@ -418,6 +390,8 @@ async def test_setup_with_cloud(
"homeassistant.components.withings.webhook_generate_url" "homeassistant.components.withings.webhook_generate_url"
): ):
await setup_integration(hass, webhook_config_entry) await setup_integration(hass, webhook_config_entry)
await prepare_webhook_setup(hass, freezer)
assert hass.components.cloud.async_active_subscription() is True assert hass.components.cloud.async_active_subscription() is True
assert hass.components.cloud.async_is_connected() is True assert hass.components.cloud.async_is_connected() is True
fake_create_cloudhook.assert_called_once() fake_create_cloudhook.assert_called_once()
@ -444,6 +418,7 @@ async def test_setup_without_https(
webhook_config_entry: MockConfigEntry, webhook_config_entry: MockConfigEntry,
withings: AsyncMock, withings: AsyncMock,
caplog: pytest.LogCaptureFixture, caplog: pytest.LogCaptureFixture,
freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test if set up with cloud link and without https.""" """Test if set up with cloud link and without https."""
hass.config.components.add("cloud") hass.config.components.add("cloud")
@ -457,6 +432,7 @@ async def test_setup_without_https(
) as mock_async_generate_url: ) as mock_async_generate_url:
mock_async_generate_url.return_value = "http://example.com" mock_async_generate_url.return_value = "http://example.com"
await setup_integration(hass, webhook_config_entry) await setup_integration(hass, webhook_config_entry)
await prepare_webhook_setup(hass, freezer)
await hass.async_block_till_done() await hass.async_block_till_done()
mock_async_generate_url.assert_called_once() mock_async_generate_url.assert_called_once()
@ -492,6 +468,7 @@ async def test_cloud_disconnect(
"homeassistant.components.withings.webhook_generate_url" "homeassistant.components.withings.webhook_generate_url"
): ):
await setup_integration(hass, webhook_config_entry) await setup_integration(hass, webhook_config_entry)
await prepare_webhook_setup(hass, freezer)
assert hass.components.cloud.async_active_subscription() is True assert hass.components.cloud.async_active_subscription() is True
assert hass.components.cloud.async_is_connected() is True assert hass.components.cloud.async_is_connected() is True
@ -537,9 +514,11 @@ async def test_webhook_post(
body: dict[str, Any], body: dict[str, Any],
expected_code: int, expected_code: int,
current_request_with_host: None, current_request_with_host: None,
freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test webhook callback.""" """Test webhook callback."""
await setup_integration(hass, webhook_config_entry) await setup_integration(hass, webhook_config_entry)
await prepare_webhook_setup(hass, freezer)
client = await hass_client_no_auth() client = await hass_client_no_auth()
webhook_url = async_generate_url(hass, WEBHOOK_ID) webhook_url = async_generate_url(hass, WEBHOOK_ID)

View File

@ -17,7 +17,7 @@ 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 call_webhook, setup_integration from . import call_webhook, prepare_webhook_setup, setup_integration
from .conftest import USER_ID, WEBHOOK_ID from .conftest import USER_ID, WEBHOOK_ID
from tests.common import MockConfigEntry, async_fire_time_changed from tests.common import MockConfigEntry, async_fire_time_changed
@ -96,9 +96,11 @@ async def test_sensor_default_enabled_entities(
withings: AsyncMock, withings: AsyncMock,
webhook_config_entry: MockConfigEntry, webhook_config_entry: MockConfigEntry,
hass_client_no_auth: ClientSessionGenerator, hass_client_no_auth: ClientSessionGenerator,
freezer: FrozenDateTimeFactory,
) -> None: ) -> None:
"""Test entities enabled by default.""" """Test entities enabled by default."""
await setup_integration(hass, webhook_config_entry) await setup_integration(hass, webhook_config_entry)
await prepare_webhook_setup(hass, freezer)
entity_registry: EntityRegistry = er.async_get(hass) entity_registry: EntityRegistry = er.async_get(hass)
client = await hass_client_no_auth() client = await hass_client_no_auth()