mirror of
https://github.com/home-assistant/supervisor.git
synced 2026-04-02 08:12:47 +01:00
* Unify Core user listing with HomeAssistantUser model Replace the ingress-specific IngressSessionDataUser with a general HomeAssistantUser dataclass that models the Core config/auth/list WS response. This deduplicates the WS call (previously in both auth.py and module.py) into a single HomeAssistant.list_users() method. - Add HomeAssistantUser dataclass with fields matching Core's user API - Remove get_users() and its unnecessary 5-minute Job throttle - Auth and ingress consumers both use HomeAssistant.list_users() - Auth API endpoint uses typed attribute access instead of dict keys - Migrate session serialization from legacy "displayname" to "name" - Accept both keys in schema/deserialization for backwards compat - Add test for loading persisted sessions with legacy displayname key Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Tighten list_users() to trust Core's auth/list contract Core's config/auth/list WS command always returns a list, never None. Replace the silent `if not raw: return []` (which also swallowed empty lists) with an assert, remove the dead AuthListUsersNoneResponseError exception class, and document the HomeAssistantWSError contract in the docstring. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove | None from async_send_command return type The WebSocket result is always set from data["result"] in _receive_json, never explicitly to None. Remove the misleading | None from the return type of both WSClient and HomeAssistantWebSocket async_send_command, and drop the now-unnecessary assert in list_users. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Use HomeAssistantWSConnectionError in _ensure_connected _ensure_connected and connect_with_auth raise on connection-level failures, so use the more specific HomeAssistantWSConnectionError instead of the broad HomeAssistantWSError. This allows callers to distinguish connection errors from Core API errors (e.g. unsuccessful WebSocket command responses). Also document that _ensure_connected can propagate HomeAssistantAuthError from ensure_access_token. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Remove user list cache from _find_user_by_id Drop the _list_of_users cache to avoid stale auth data in ingress session creation. The method now fetches users fresh each time and returns None on any API error instead of serving potentially outdated cached results. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
109 lines
3.7 KiB
Python
109 lines
3.7 KiB
Python
"""Test websocket."""
|
|
|
|
# pylint: disable=import-error
|
|
import asyncio
|
|
from unittest.mock import AsyncMock, patch
|
|
|
|
import pytest
|
|
|
|
from supervisor.const import CoreState
|
|
from supervisor.coresys import CoreSys
|
|
from supervisor.exceptions import HomeAssistantWSConnectionError
|
|
from supervisor.homeassistant.const import WSEvent, WSType
|
|
|
|
|
|
async def test_send_command(coresys: CoreSys, ha_ws_client: AsyncMock):
|
|
"""Test sending a command returns a response."""
|
|
await coresys.homeassistant.websocket.async_send_command({"type": "test"})
|
|
ha_ws_client.async_send_command.assert_called_with({"type": "test"})
|
|
|
|
await coresys.homeassistant.websocket.async_supervisor_update_event(
|
|
"test", {"lorem": "ipsum"}
|
|
)
|
|
ha_ws_client.async_send_command.assert_called_with(
|
|
{
|
|
"type": WSType.SUPERVISOR_EVENT,
|
|
"data": {
|
|
"event": WSEvent.SUPERVISOR_UPDATE,
|
|
"update_key": "test",
|
|
"data": {"lorem": "ipsum"},
|
|
},
|
|
}
|
|
)
|
|
|
|
|
|
async def test_fire_and_forget_during_startup(
|
|
coresys: CoreSys, ha_ws_client: AsyncMock
|
|
):
|
|
"""Test fire-and-forget commands queue during startup and replay when running."""
|
|
await coresys.homeassistant.websocket.load()
|
|
await coresys.core.set_state(CoreState.SETUP)
|
|
|
|
await coresys.homeassistant.websocket.async_supervisor_update_event(
|
|
"test", {"lorem": "ipsum"}
|
|
)
|
|
ha_ws_client.async_send_command.assert_not_called()
|
|
|
|
await coresys.core.set_state(CoreState.RUNNING)
|
|
await asyncio.sleep(0)
|
|
|
|
assert ha_ws_client.async_send_command.call_count == 2
|
|
assert ha_ws_client.async_send_command.call_args_list[0][0][0] == {
|
|
"type": WSType.SUPERVISOR_EVENT,
|
|
"data": {
|
|
"event": WSEvent.SUPERVISOR_UPDATE,
|
|
"update_key": "test",
|
|
"data": {"lorem": "ipsum"},
|
|
},
|
|
}
|
|
assert ha_ws_client.async_send_command.call_args_list[1][0][0] == {
|
|
"type": WSType.SUPERVISOR_EVENT,
|
|
"data": {
|
|
"event": WSEvent.SUPERVISOR_UPDATE,
|
|
"update_key": "info",
|
|
"data": {"state": "running"},
|
|
},
|
|
}
|
|
|
|
ha_ws_client.reset_mock()
|
|
await coresys.core.set_state(CoreState.SHUTDOWN)
|
|
|
|
await coresys.homeassistant.websocket.async_supervisor_update_event(
|
|
"test", {"lorem": "ipsum"}
|
|
)
|
|
ha_ws_client.async_send_command.assert_not_called()
|
|
|
|
|
|
async def test_send_command_core_not_reachable(
|
|
coresys: CoreSys, ha_ws_client: AsyncMock
|
|
):
|
|
"""Test async_send_command raises when Core API is not reachable."""
|
|
ha_ws_client.connected = False
|
|
with (
|
|
patch.object(coresys.homeassistant.api, "check_api_state", return_value=False),
|
|
pytest.raises(HomeAssistantWSConnectionError, match="not reachable"),
|
|
):
|
|
await coresys.homeassistant.websocket.async_send_command({"type": "test"})
|
|
|
|
ha_ws_client.async_send_command.assert_not_called()
|
|
|
|
|
|
async def test_fire_and_forget_core_not_reachable(
|
|
coresys: CoreSys, ha_ws_client: AsyncMock
|
|
):
|
|
"""Test fire-and-forget command silently skips when Core API is not reachable."""
|
|
ha_ws_client.connected = False
|
|
with patch.object(coresys.homeassistant.api, "check_api_state", return_value=False):
|
|
await coresys.homeassistant.websocket._async_send_command({"type": "test"})
|
|
|
|
ha_ws_client.async_send_command.assert_not_called()
|
|
|
|
|
|
async def test_send_command_during_shutdown(coresys: CoreSys, ha_ws_client: AsyncMock):
|
|
"""Test async_send_command raises during shutdown."""
|
|
await coresys.core.set_state(CoreState.SHUTDOWN)
|
|
with pytest.raises(HomeAssistantWSConnectionError, match="shutting down"):
|
|
await coresys.homeassistant.websocket.async_send_command({"type": "test"})
|
|
|
|
ha_ws_client.async_send_command.assert_not_called()
|