mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
Add async_register_backup_agents_listener to cloud/backup (#133584)
* Add async_register_backup_agents_listener to cloud/backup * Coverage * more coverage
This commit is contained in:
parent
ad34bc8910
commit
10191e7a23
@ -3,7 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
from collections.abc import AsyncIterator, Callable, Coroutine
|
||||
from collections.abc import AsyncIterator, Callable, Coroutine, Mapping
|
||||
import hashlib
|
||||
from typing import Any, Self
|
||||
|
||||
@ -18,9 +18,10 @@ from hass_nabucasa.cloud_api import (
|
||||
|
||||
from homeassistant.components.backup import AgentBackup, BackupAgent, BackupAgentError
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
|
||||
from .client import CloudClient
|
||||
from .const import DATA_CLOUD, DOMAIN
|
||||
from .const import DATA_CLOUD, DOMAIN, EVENT_CLOUD_EVENT
|
||||
|
||||
_STORAGE_BACKUP = "backup"
|
||||
|
||||
@ -45,6 +46,31 @@ async def async_get_backup_agents(
|
||||
return [CloudBackupAgent(hass=hass, cloud=cloud)]
|
||||
|
||||
|
||||
@callback
|
||||
def async_register_backup_agents_listener(
|
||||
hass: HomeAssistant,
|
||||
*,
|
||||
listener: Callable[[], None],
|
||||
**kwargs: Any,
|
||||
) -> Callable[[], None]:
|
||||
"""Register a listener to be called when agents are added or removed."""
|
||||
|
||||
@callback
|
||||
def unsub() -> None:
|
||||
"""Unsubscribe from events."""
|
||||
unsub_signal()
|
||||
|
||||
@callback
|
||||
def handle_event(data: Mapping[str, Any]) -> None:
|
||||
"""Handle event."""
|
||||
if data["type"] not in ("login", "logout"):
|
||||
return
|
||||
listener()
|
||||
|
||||
unsub_signal = async_dispatcher_connect(hass, EVENT_CLOUD_EVENT, handle_event)
|
||||
return unsub
|
||||
|
||||
|
||||
class ChunkAsyncStreamIterator:
|
||||
"""Async iterator for chunked streams.
|
||||
|
||||
|
@ -18,6 +18,8 @@ DATA_CLOUD: HassKey[Cloud[CloudClient]] = HassKey(DOMAIN)
|
||||
DATA_PLATFORMS_SETUP: HassKey[dict[str, asyncio.Event]] = HassKey(
|
||||
"cloud_platforms_setup"
|
||||
)
|
||||
EVENT_CLOUD_EVENT = "cloud_event"
|
||||
|
||||
REQUEST_TIMEOUT = 10
|
||||
|
||||
PREF_ENABLE_ALEXA = "alexa_enabled"
|
||||
|
@ -34,6 +34,7 @@ from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
from homeassistant.util.location import async_detect_location_info
|
||||
|
||||
from .alexa_config import entity_supported as entity_supported_by_alexa
|
||||
@ -41,6 +42,7 @@ from .assist_pipeline import async_create_cloud_pipeline
|
||||
from .client import CloudClient
|
||||
from .const import (
|
||||
DATA_CLOUD,
|
||||
EVENT_CLOUD_EVENT,
|
||||
LOGIN_MFA_TIMEOUT,
|
||||
PREF_ALEXA_REPORT_STATE,
|
||||
PREF_DISABLE_2FA,
|
||||
@ -278,6 +280,8 @@ class CloudLoginView(HomeAssistantView):
|
||||
new_cloud_pipeline_id = await async_create_cloud_pipeline(hass)
|
||||
else:
|
||||
new_cloud_pipeline_id = None
|
||||
|
||||
async_dispatcher_send(hass, EVENT_CLOUD_EVENT, {"type": "login"})
|
||||
return self.json({"success": True, "cloud_pipeline": new_cloud_pipeline_id})
|
||||
|
||||
|
||||
@ -297,6 +301,7 @@ class CloudLogoutView(HomeAssistantView):
|
||||
async with asyncio.timeout(REQUEST_TIMEOUT):
|
||||
await cloud.logout()
|
||||
|
||||
async_dispatcher_send(hass, EVENT_CLOUD_EVENT, {"type": "logout"})
|
||||
return self.json_message("ok")
|
||||
|
||||
|
||||
|
@ -17,7 +17,10 @@ from homeassistant.components.backup import (
|
||||
Folder,
|
||||
)
|
||||
from homeassistant.components.cloud import DOMAIN
|
||||
from homeassistant.components.cloud.backup import async_register_backup_agents_listener
|
||||
from homeassistant.components.cloud.const import EVENT_CLOUD_EVENT
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
@ -576,3 +579,49 @@ async def test_agents_delete_not_found(
|
||||
|
||||
assert response["success"]
|
||||
assert response["result"] == {"agent_errors": {}}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("event_type", ["login", "logout"])
|
||||
async def test_calling_listener_on_login_logout(
|
||||
hass: HomeAssistant,
|
||||
event_type: str,
|
||||
) -> None:
|
||||
"""Test calling listener for login and logout events."""
|
||||
listener = MagicMock()
|
||||
async_register_backup_agents_listener(hass, listener=listener)
|
||||
|
||||
assert listener.call_count == 0
|
||||
async_dispatcher_send(hass, EVENT_CLOUD_EVENT, {"type": event_type})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert listener.call_count == 1
|
||||
|
||||
|
||||
async def test_not_calling_listener_after_unsub(hass: HomeAssistant) -> None:
|
||||
"""Test only calling listener until unsub."""
|
||||
listener = MagicMock()
|
||||
unsub = async_register_backup_agents_listener(hass, listener=listener)
|
||||
|
||||
assert listener.call_count == 0
|
||||
async_dispatcher_send(hass, EVENT_CLOUD_EVENT, {"type": "login"})
|
||||
await hass.async_block_till_done()
|
||||
assert listener.call_count == 1
|
||||
|
||||
unsub()
|
||||
|
||||
async_dispatcher_send(hass, EVENT_CLOUD_EVENT, {"type": "login"})
|
||||
await hass.async_block_till_done()
|
||||
assert listener.call_count == 1
|
||||
|
||||
|
||||
async def test_not_calling_listener_with_unknown_event_type(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test not calling listener if we did not get the expected event type."""
|
||||
listener = MagicMock()
|
||||
async_register_backup_agents_listener(hass, listener=listener)
|
||||
|
||||
assert listener.call_count == 0
|
||||
async_dispatcher_send(hass, EVENT_CLOUD_EVENT, {"type": "unknown"})
|
||||
await hass.async_block_till_done()
|
||||
assert listener.call_count == 0
|
||||
|
@ -1819,3 +1819,45 @@ async def test_api_calls_require_admin(
|
||||
resp = await client.post(endpoint, json=data)
|
||||
|
||||
assert resp.status == HTTPStatus.UNAUTHORIZED
|
||||
|
||||
|
||||
async def test_login_view_dispatch_event(
|
||||
hass: HomeAssistant,
|
||||
cloud: MagicMock,
|
||||
hass_client: ClientSessionGenerator,
|
||||
) -> None:
|
||||
"""Test dispatching event while logging in."""
|
||||
assert await async_setup_component(hass, "homeassistant", {})
|
||||
assert await async_setup_component(hass, DOMAIN, {"cloud": {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
cloud_client = await hass_client()
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.cloud.http_api.async_dispatcher_send"
|
||||
) as async_dispatcher_send_mock:
|
||||
await cloud_client.post(
|
||||
"/api/cloud/login", json={"email": "my_username", "password": "my_password"}
|
||||
)
|
||||
|
||||
assert async_dispatcher_send_mock.call_count == 1
|
||||
assert async_dispatcher_send_mock.mock_calls[0][1][1] == "cloud_event"
|
||||
assert async_dispatcher_send_mock.mock_calls[0][1][2] == {"type": "login"}
|
||||
|
||||
|
||||
async def test_logout_view_dispatch_event(
|
||||
cloud: MagicMock,
|
||||
setup_cloud: None,
|
||||
hass_client: ClientSessionGenerator,
|
||||
) -> None:
|
||||
"""Test dispatching event while logging out."""
|
||||
cloud_client = await hass_client()
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.cloud.http_api.async_dispatcher_send"
|
||||
) as async_dispatcher_send_mock:
|
||||
await cloud_client.post("/api/cloud/logout")
|
||||
|
||||
assert async_dispatcher_send_mock.call_count == 1
|
||||
assert async_dispatcher_send_mock.mock_calls[0][1][1] == "cloud_event"
|
||||
assert async_dispatcher_send_mock.mock_calls[0][1][2] == {"type": "logout"}
|
||||
|
Loading…
x
Reference in New Issue
Block a user