Make Withings recoverable after internet outage (#115124)

This commit is contained in:
Joost Lekkerkerker 2024-04-19 18:18:32 +02:00 committed by GitHub
parent c108c7df38
commit cc2e0fd921
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 111 additions and 1 deletions

View File

@ -12,6 +12,7 @@ from dataclasses import dataclass, field
from datetime import timedelta
from typing import TYPE_CHECKING, Any, cast
from aiohttp import ClientError
from aiohttp.hdrs import METH_POST
from aiohttp.web import Request, Response
from aiowithings import NotificationCategory, WithingsClient
@ -274,7 +275,11 @@ class WithingsWebhookManager:
async def async_unsubscribe_webhooks(client: WithingsClient) -> None:
"""Unsubscribe to all Withings webhooks."""
try:
current_webhooks = await client.list_notification_configurations()
except ClientError:
LOGGER.exception("Error when unsubscribing webhooks")
return
for webhook_configuration in current_webhooks:
LOGGER.debug(

View File

@ -5,6 +5,7 @@ from typing import Any
from unittest.mock import AsyncMock, patch
from urllib.parse import urlparse
from aiohttp import ClientConnectionError
from aiohttp.hdrs import METH_HEAD
from aiowithings import (
NotificationCategory,
@ -425,6 +426,110 @@ async def test_cloud_disconnect(
assert withings.subscribe_notification.call_count == 12
async def test_internet_disconnect(
hass: HomeAssistant,
withings: AsyncMock,
webhook_config_entry: MockConfigEntry,
hass_client_no_auth: ClientSessionGenerator,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test we can recover from internet disconnects."""
await mock_cloud(hass)
await hass.async_block_till_done()
with (
patch("homeassistant.components.cloud.async_is_logged_in", return_value=True),
patch.object(cloud, "async_is_connected", return_value=True),
patch.object(cloud, "async_active_subscription", return_value=True),
patch(
"homeassistant.components.cloud.async_create_cloudhook",
return_value="https://hooks.nabu.casa/ABCD",
),
patch(
"homeassistant.components.withings.async_get_config_entry_implementation",
),
patch(
"homeassistant.components.cloud.async_delete_cloudhook",
),
patch(
"homeassistant.components.withings.webhook_generate_url",
),
):
await setup_integration(hass, webhook_config_entry)
await prepare_webhook_setup(hass, freezer)
assert cloud.async_active_subscription(hass) is True
assert cloud.async_is_connected(hass) is True
assert withings.revoke_notification_configurations.call_count == 3
assert withings.subscribe_notification.call_count == 6
await hass.async_block_till_done()
withings.list_notification_configurations.side_effect = ClientConnectionError
async_mock_cloud_connection_status(hass, False)
await hass.async_block_till_done()
assert withings.revoke_notification_configurations.call_count == 3
async_mock_cloud_connection_status(hass, True)
await hass.async_block_till_done()
assert withings.subscribe_notification.call_count == 12
async def test_cloud_disconnect_retry(
hass: HomeAssistant,
withings: AsyncMock,
webhook_config_entry: MockConfigEntry,
hass_client_no_auth: ClientSessionGenerator,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test we retry to create webhook connection again after cloud disconnects."""
await mock_cloud(hass)
await hass.async_block_till_done()
with (
patch("homeassistant.components.cloud.async_is_logged_in", return_value=True),
patch.object(cloud, "async_is_connected", return_value=True),
patch.object(
cloud, "async_active_subscription", return_value=True
) as mock_async_active_subscription,
patch(
"homeassistant.components.cloud.async_create_cloudhook",
return_value="https://hooks.nabu.casa/ABCD",
),
patch(
"homeassistant.components.withings.async_get_config_entry_implementation",
),
patch(
"homeassistant.components.cloud.async_delete_cloudhook",
),
patch(
"homeassistant.components.withings.webhook_generate_url",
),
):
await setup_integration(hass, webhook_config_entry)
await prepare_webhook_setup(hass, freezer)
assert cloud.async_active_subscription(hass) is True
assert cloud.async_is_connected(hass) is True
assert mock_async_active_subscription.call_count == 3
await hass.async_block_till_done()
async_mock_cloud_connection_status(hass, False)
await hass.async_block_till_done()
assert mock_async_active_subscription.call_count == 3
freezer.tick(timedelta(seconds=30))
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert mock_async_active_subscription.call_count == 4
@pytest.mark.parametrize(
("body", "expected_code"),
[