Use the async_migrate_paypal_agreement function to get the migration URL (#83469)
* Use the async_migrate_paypal_agreement function to get the migration URL * Update URL * Handle timeout error
This commit is contained in:
parent
dfb0887765
commit
f5cfd0329c
4 changed files with 100 additions and 5 deletions
|
@ -13,7 +13,7 @@ from homeassistant.data_entry_flow import FlowResult
|
||||||
from homeassistant.helpers import issue_registry as ir
|
from homeassistant.helpers import issue_registry as ir
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .subscription import async_subscription_info
|
from .subscription import async_migrate_paypal_agreement, async_subscription_info
|
||||||
|
|
||||||
BACKOFF_TIME = 5
|
BACKOFF_TIME = 5
|
||||||
MAX_RETRIES = 60 # This allows for 10 minutes of retries
|
MAX_RETRIES = 60 # This allows for 10 minutes of retries
|
||||||
|
@ -68,13 +68,13 @@ class LegacySubscriptionRepairFlow(RepairsFlow):
|
||||||
async def async_step_change_plan(self, _: None = None) -> FlowResult:
|
async def async_step_change_plan(self, _: None = None) -> FlowResult:
|
||||||
"""Wait for the user to authorize the app installation."""
|
"""Wait for the user to authorize the app installation."""
|
||||||
|
|
||||||
|
cloud: Cloud = self.hass.data[DOMAIN]
|
||||||
|
|
||||||
async def _async_wait_for_plan_change() -> None:
|
async def _async_wait_for_plan_change() -> None:
|
||||||
flow_manager = repairs_flow_manager(self.hass)
|
flow_manager = repairs_flow_manager(self.hass)
|
||||||
# We can not get here without a flow manager
|
# We can not get here without a flow manager
|
||||||
assert flow_manager is not None
|
assert flow_manager is not None
|
||||||
|
|
||||||
cloud: Cloud = self.hass.data[DOMAIN]
|
|
||||||
|
|
||||||
retries = 0
|
retries = 0
|
||||||
while retries < MAX_RETRIES:
|
while retries < MAX_RETRIES:
|
||||||
self._data = await async_subscription_info(cloud)
|
self._data = await async_subscription_info(cloud)
|
||||||
|
@ -90,9 +90,10 @@ class LegacySubscriptionRepairFlow(RepairsFlow):
|
||||||
|
|
||||||
if not self.wait_task:
|
if not self.wait_task:
|
||||||
self.wait_task = self.hass.async_create_task(_async_wait_for_plan_change())
|
self.wait_task = self.hass.async_create_task(_async_wait_for_plan_change())
|
||||||
|
migration = await async_migrate_paypal_agreement(cloud)
|
||||||
return self.async_external_step(
|
return self.async_external_step(
|
||||||
step_id="change_plan",
|
step_id="change_plan",
|
||||||
url="https://account.nabucasa.com/",
|
url=migration["url"] if migration else "https://account.nabucasa.com/",
|
||||||
)
|
)
|
||||||
|
|
||||||
await self.wait_task
|
await self.wait_task
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""Subscription information."""
|
"""Subscription information."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
@ -18,7 +19,28 @@ async def async_subscription_info(cloud: Cloud) -> dict[str, Any] | None:
|
||||||
try:
|
try:
|
||||||
async with async_timeout.timeout(REQUEST_TIMEOUT):
|
async with async_timeout.timeout(REQUEST_TIMEOUT):
|
||||||
return await cloud_api.async_subscription_info(cloud)
|
return await cloud_api.async_subscription_info(cloud)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
_LOGGER.error(
|
||||||
|
"A timeout of %s was reached while trying to fetch subscription information",
|
||||||
|
REQUEST_TIMEOUT,
|
||||||
|
)
|
||||||
except ClientError:
|
except ClientError:
|
||||||
_LOGGER.error("Failed to fetch subscription information")
|
_LOGGER.error("Failed to fetch subscription information")
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
async def async_migrate_paypal_agreement(cloud: Cloud) -> dict[str, Any] | None:
|
||||||
|
"""Migrate a paypal agreement from legacy."""
|
||||||
|
try:
|
||||||
|
async with async_timeout.timeout(REQUEST_TIMEOUT):
|
||||||
|
return await cloud_api.async_migrate_paypal_agreement(cloud)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
_LOGGER.error(
|
||||||
|
"A timeout of %s was reached while trying to start agreement migration",
|
||||||
|
REQUEST_TIMEOUT,
|
||||||
|
)
|
||||||
|
except ClientError as exception:
|
||||||
|
_LOGGER.error("Failed to start agreement migration - %s", exception)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
|
@ -88,6 +88,10 @@ async def test_legacy_subscription_repair_flow(
|
||||||
"https://accounts.nabucasa.com/payments/subscription_info",
|
"https://accounts.nabucasa.com/payments/subscription_info",
|
||||||
json={"provider": None},
|
json={"provider": None},
|
||||||
)
|
)
|
||||||
|
aioclient_mock.post(
|
||||||
|
"https://accounts.nabucasa.com/payments/migrate_paypal_agreement",
|
||||||
|
json={"url": "https://paypal.com"},
|
||||||
|
)
|
||||||
|
|
||||||
cloud_repairs.async_manage_legacy_subscription_issue(hass, {"provider": "legacy"})
|
cloud_repairs.async_manage_legacy_subscription_issue(hass, {"provider": "legacy"})
|
||||||
repair_issue = issue_registry.async_get_issue(
|
repair_issue = issue_registry.async_get_issue(
|
||||||
|
@ -133,7 +137,7 @@ async def test_legacy_subscription_repair_flow(
|
||||||
"flow_id": flow_id,
|
"flow_id": flow_id,
|
||||||
"handler": DOMAIN,
|
"handler": DOMAIN,
|
||||||
"step_id": "change_plan",
|
"step_id": "change_plan",
|
||||||
"url": "https://account.nabucasa.com/",
|
"url": "https://paypal.com",
|
||||||
"description_placeholders": None,
|
"description_placeholders": None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,8 +165,15 @@ async def test_legacy_subscription_repair_flow(
|
||||||
async def test_legacy_subscription_repair_flow_timeout(
|
async def test_legacy_subscription_repair_flow_timeout(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
hass_client: Callable[..., Awaitable[ClientSession]],
|
hass_client: Callable[..., Awaitable[ClientSession]],
|
||||||
|
mock_auth: Generator[None, AsyncMock, None],
|
||||||
|
aioclient_mock: AiohttpClientMocker,
|
||||||
):
|
):
|
||||||
"""Test timeout flow of the fix flow for legacy subscription."""
|
"""Test timeout flow of the fix flow for legacy subscription."""
|
||||||
|
aioclient_mock.post(
|
||||||
|
"https://accounts.nabucasa.com/payments/migrate_paypal_agreement",
|
||||||
|
status=403,
|
||||||
|
)
|
||||||
|
|
||||||
issue_registry: ir.IssueRegistry = ir.async_get(hass)
|
issue_registry: ir.IssueRegistry = ir.async_get(hass)
|
||||||
|
|
||||||
cloud_repairs.async_manage_legacy_subscription_issue(hass, {"provider": "legacy"})
|
cloud_repairs.async_manage_legacy_subscription_issue(hass, {"provider": "legacy"})
|
||||||
|
|
61
tests/components/cloud/test_subscription.py
Normal file
61
tests/components/cloud/test_subscription.py
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
"""Test cloud subscription functions."""
|
||||||
|
import asyncio
|
||||||
|
from unittest.mock import AsyncMock, Mock
|
||||||
|
|
||||||
|
from hass_nabucasa import Cloud
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.cloud.subscription import (
|
||||||
|
async_migrate_paypal_agreement,
|
||||||
|
async_subscription_info,
|
||||||
|
)
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
|
|
||||||
|
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="mocked_cloud")
|
||||||
|
def mocked_cloud_object(hass: HomeAssistant) -> Cloud:
|
||||||
|
"""Mock cloud object."""
|
||||||
|
return Mock(
|
||||||
|
accounts_server="accounts.nabucasa.com",
|
||||||
|
auth=Mock(async_check_token=AsyncMock()),
|
||||||
|
websession=async_get_clientsession(hass),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_fetching_subscription_with_timeout_error(
|
||||||
|
aioclient_mock: AiohttpClientMocker,
|
||||||
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
mocked_cloud: Cloud,
|
||||||
|
):
|
||||||
|
"""Test that we handle timeout error."""
|
||||||
|
aioclient_mock.get(
|
||||||
|
"https://accounts.nabucasa.com/payments/subscription_info",
|
||||||
|
exc=asyncio.TimeoutError(),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert await async_subscription_info(mocked_cloud) is None
|
||||||
|
assert (
|
||||||
|
"A timeout of 10 was reached while trying to fetch subscription information"
|
||||||
|
in caplog.text
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_migrate_paypal_agreement_with_timeout_error(
|
||||||
|
aioclient_mock: AiohttpClientMocker,
|
||||||
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
mocked_cloud: Cloud,
|
||||||
|
):
|
||||||
|
"""Test that we handle timeout error."""
|
||||||
|
aioclient_mock.post(
|
||||||
|
"https://accounts.nabucasa.com/payments/migrate_paypal_agreement",
|
||||||
|
exc=asyncio.TimeoutError(),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert await async_migrate_paypal_agreement(mocked_cloud) is None
|
||||||
|
assert (
|
||||||
|
"A timeout of 10 was reached while trying to start agreement migration"
|
||||||
|
in caplog.text
|
||||||
|
)
|
Loading…
Add table
Add a link
Reference in a new issue