Use dispatch instead of eventbus for supervisor events (#46986)

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
Joakim Sørensen 2021-02-25 19:52:11 +01:00 committed by GitHub
parent f4db74fe73
commit 7d90cdea1e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 164 additions and 115 deletions

View file

@ -33,7 +33,8 @@ X_HASS_IS_ADMIN = "X-Hass-Is-Admin"
WS_TYPE = "type"
WS_ID = "id"
WS_TYPE_EVENT = "supervisor/event"
WS_TYPE_API = "supervisor/api"
WS_TYPE_EVENT = "supervisor/event"
WS_TYPE_SUBSCRIBE = "supervisor/subscribe"
EVENT_SUPERVISOR_EVENT = "supervisor_event"

View file

@ -7,6 +7,10 @@ from homeassistant.components import websocket_api
from homeassistant.components.websocket_api.connection import ActiveConnection
from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import (
async_dispatcher_connect,
async_dispatcher_send,
)
from .const import (
ATTR_DATA,
@ -20,6 +24,7 @@ from .const import (
WS_TYPE,
WS_TYPE_API,
WS_TYPE_EVENT,
WS_TYPE_SUBSCRIBE,
)
from .handler import HassIO
@ -36,6 +41,26 @@ def async_load_websocket_api(hass: HomeAssistant):
"""Set up the websocket API."""
websocket_api.async_register_command(hass, websocket_supervisor_event)
websocket_api.async_register_command(hass, websocket_supervisor_api)
websocket_api.async_register_command(hass, websocket_subscribe)
@websocket_api.require_admin
@websocket_api.async_response
@websocket_api.websocket_command({vol.Required(WS_TYPE): WS_TYPE_SUBSCRIBE})
async def websocket_subscribe(
hass: HomeAssistant, connection: ActiveConnection, msg: dict
):
"""Subscribe to supervisor events."""
@callback
def forward_messages(data):
"""Forward events to websocket."""
connection.send_message(websocket_api.event_message(msg[WS_ID], data))
connection.subscriptions[msg[WS_ID]] = async_dispatcher_connect(
hass, EVENT_SUPERVISOR_EVENT, forward_messages
)
connection.send_message(websocket_api.result_message(msg[WS_ID]))
@websocket_api.async_response
@ -49,7 +74,7 @@ async def websocket_supervisor_event(
hass: HomeAssistant, connection: ActiveConnection, msg: dict
):
"""Publish events from the Supervisor."""
hass.bus.async_fire(EVENT_SUPERVISOR_EVENT, msg[ATTR_DATA])
async_dispatcher_send(hass, EVENT_SUPERVISOR_EVENT, msg[ATTR_DATA])
connection.send_result(msg[WS_ID])

View file

@ -1,3 +1,48 @@
"""Tests for Hass.io component."""
import pytest
HASSIO_TOKEN = "123456"
@pytest.fixture(autouse=True)
def mock_all(aioclient_mock):
"""Mock all setup requests."""
aioclient_mock.post("http://127.0.0.1/homeassistant/options", json={"result": "ok"})
aioclient_mock.get("http://127.0.0.1/supervisor/ping", json={"result": "ok"})
aioclient_mock.post("http://127.0.0.1/supervisor/options", json={"result": "ok"})
aioclient_mock.get(
"http://127.0.0.1/info",
json={
"result": "ok",
"data": {"supervisor": "222", "homeassistant": "0.110.0", "hassos": None},
},
)
aioclient_mock.get(
"http://127.0.0.1/host/info",
json={
"result": "ok",
"data": {
"result": "ok",
"data": {
"chassis": "vm",
"operating_system": "Debian GNU/Linux 10 (buster)",
"kernel": "4.19.0-6-amd64",
},
},
},
)
aioclient_mock.get(
"http://127.0.0.1/core/info",
json={"result": "ok", "data": {"version_latest": "1.0.0"}},
)
aioclient_mock.get(
"http://127.0.0.1/os/info",
json={"result": "ok", "data": {"version_latest": "1.0.0"}},
)
aioclient_mock.get(
"http://127.0.0.1/supervisor/info",
json={"result": "ok", "data": {"version_latest": "1.0.0"}},
)
aioclient_mock.get(
"http://127.0.0.1/ingress/panels", json={"result": "ok", "data": {"panels": {}}}
)

View file

@ -2,73 +2,16 @@
import os
from unittest.mock import patch
import pytest
from homeassistant.auth.const import GROUP_ID_ADMIN
from homeassistant.components import frontend
from homeassistant.components.hassio import STORAGE_KEY
from homeassistant.components.hassio.const import (
ATTR_DATA,
ATTR_ENDPOINT,
ATTR_METHOD,
EVENT_SUPERVISOR_EVENT,
WS_ID,
WS_TYPE,
WS_TYPE_API,
WS_TYPE_EVENT,
)
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from tests.common import async_capture_events
from . import mock_all # noqa
MOCK_ENVIRON = {"HASSIO": "127.0.0.1", "HASSIO_TOKEN": "abcdefgh"}
@pytest.fixture(autouse=True)
def mock_all(aioclient_mock):
"""Mock all setup requests."""
aioclient_mock.post("http://127.0.0.1/homeassistant/options", json={"result": "ok"})
aioclient_mock.get("http://127.0.0.1/supervisor/ping", json={"result": "ok"})
aioclient_mock.post("http://127.0.0.1/supervisor/options", json={"result": "ok"})
aioclient_mock.get(
"http://127.0.0.1/info",
json={
"result": "ok",
"data": {"supervisor": "222", "homeassistant": "0.110.0", "hassos": None},
},
)
aioclient_mock.get(
"http://127.0.0.1/host/info",
json={
"result": "ok",
"data": {
"result": "ok",
"data": {
"chassis": "vm",
"operating_system": "Debian GNU/Linux 10 (buster)",
"kernel": "4.19.0-6-amd64",
},
},
},
)
aioclient_mock.get(
"http://127.0.0.1/core/info",
json={"result": "ok", "data": {"version_latest": "1.0.0"}},
)
aioclient_mock.get(
"http://127.0.0.1/os/info",
json={"result": "ok", "data": {"version_latest": "1.0.0"}},
)
aioclient_mock.get(
"http://127.0.0.1/supervisor/info",
json={"result": "ok", "data": {"version_latest": "1.0.0"}},
)
aioclient_mock.get(
"http://127.0.0.1/ingress/panels", json={"result": "ok", "data": {"panels": {}}}
)
async def test_setup_api_ping(hass, aioclient_mock):
"""Test setup with API ping."""
with patch.dict(os.environ, MOCK_ENVIRON):
@ -359,58 +302,3 @@ async def test_service_calls_core(hassio_env, hass, aioclient_mock):
assert mock_check_config.called
assert aioclient_mock.call_count == 5
async def test_websocket_supervisor_event(
hassio_env, hass: HomeAssistant, hass_ws_client
):
"""Test Supervisor websocket event."""
assert await async_setup_component(hass, "hassio", {})
websocket_client = await hass_ws_client(hass)
test_event = async_capture_events(hass, EVENT_SUPERVISOR_EVENT)
await websocket_client.send_json(
{WS_ID: 1, WS_TYPE: WS_TYPE_EVENT, ATTR_DATA: {"event": "test"}}
)
assert await websocket_client.receive_json()
await hass.async_block_till_done()
assert test_event[0].data == {"event": "test"}
async def test_websocket_supervisor_api(
hassio_env, hass: HomeAssistant, hass_ws_client, aioclient_mock
):
"""Test Supervisor websocket api."""
assert await async_setup_component(hass, "hassio", {})
websocket_client = await hass_ws_client(hass)
aioclient_mock.post(
"http://127.0.0.1/snapshots/new/partial",
json={"result": "ok", "data": {"slug": "sn_slug"}},
)
await websocket_client.send_json(
{
WS_ID: 1,
WS_TYPE: WS_TYPE_API,
ATTR_ENDPOINT: "/snapshots/new/partial",
ATTR_METHOD: "post",
}
)
msg = await websocket_client.receive_json()
assert msg["result"]["slug"] == "sn_slug"
await websocket_client.send_json(
{
WS_ID: 2,
WS_TYPE: WS_TYPE_API,
ATTR_ENDPOINT: "/supervisor/info",
ATTR_METHOD: "get",
}
)
msg = await websocket_client.receive_json()
assert msg["result"]["version_latest"] == "1.0.0"

View file

@ -0,0 +1,90 @@
"""Test websocket API."""
from homeassistant.components.hassio.const import (
ATTR_DATA,
ATTR_ENDPOINT,
ATTR_METHOD,
ATTR_WS_EVENT,
EVENT_SUPERVISOR_EVENT,
WS_ID,
WS_TYPE,
WS_TYPE_API,
WS_TYPE_SUBSCRIBE,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.setup import async_setup_component
from . import mock_all # noqa
from tests.common import async_mock_signal
async def test_ws_subscription(hassio_env, hass: HomeAssistant, hass_ws_client):
"""Test websocket subscription."""
assert await async_setup_component(hass, "hassio", {})
client = await hass_ws_client(hass)
await client.send_json({WS_ID: 5, WS_TYPE: WS_TYPE_SUBSCRIBE})
response = await client.receive_json()
assert response["success"]
calls = async_mock_signal(hass, EVENT_SUPERVISOR_EVENT)
async_dispatcher_send(hass, EVENT_SUPERVISOR_EVENT, {"lorem": "ipsum"})
response = await client.receive_json()
assert response["event"]["lorem"] == "ipsum"
assert len(calls) == 1
await client.send_json(
{
WS_ID: 6,
WS_TYPE: "supervisor/event",
ATTR_DATA: {ATTR_WS_EVENT: "test", "lorem": "ipsum"},
}
)
response = await client.receive_json()
assert response["success"]
assert len(calls) == 2
response = await client.receive_json()
assert response["event"]["lorem"] == "ipsum"
# Unsubscribe
await client.send_json({WS_ID: 7, WS_TYPE: "unsubscribe_events", "subscription": 5})
response = await client.receive_json()
assert response["success"]
async def test_websocket_supervisor_api(
hassio_env, hass: HomeAssistant, hass_ws_client, aioclient_mock
):
"""Test Supervisor websocket api."""
assert await async_setup_component(hass, "hassio", {})
websocket_client = await hass_ws_client(hass)
aioclient_mock.post(
"http://127.0.0.1/snapshots/new/partial",
json={"result": "ok", "data": {"slug": "sn_slug"}},
)
await websocket_client.send_json(
{
WS_ID: 1,
WS_TYPE: WS_TYPE_API,
ATTR_ENDPOINT: "/snapshots/new/partial",
ATTR_METHOD: "post",
}
)
msg = await websocket_client.receive_json()
assert msg["result"]["slug"] == "sn_slug"
await websocket_client.send_json(
{
WS_ID: 2,
WS_TYPE: WS_TYPE_API,
ATTR_ENDPOINT: "/supervisor/info",
ATTR_METHOD: "get",
}
)
msg = await websocket_client.receive_json()
assert msg["result"]["version_latest"] == "1.0.0"