2018-10-01 09:21:00 +00:00
|
|
|
"""Tests for WebSocket API commands."""
|
2021-04-05 08:11:44 +00:00
|
|
|
import datetime
|
2021-03-22 05:12:56 +00:00
|
|
|
from unittest.mock import ANY, patch
|
|
|
|
|
2018-10-01 09:21:00 +00:00
|
|
|
from async_timeout import timeout
|
2021-03-22 05:12:56 +00:00
|
|
|
import pytest
|
2021-01-27 14:20:22 +00:00
|
|
|
import voluptuous as vol
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2021-04-05 08:11:44 +00:00
|
|
|
from homeassistant.bootstrap import SIGNAL_BOOTSTRAP_INTEGRATONS
|
2019-12-09 11:30:23 +00:00
|
|
|
from homeassistant.components.websocket_api import const
|
2018-10-01 14:09:31 +00:00
|
|
|
from homeassistant.components.websocket_api.auth import (
|
2019-07-31 19:25:30 +00:00
|
|
|
TYPE_AUTH,
|
|
|
|
TYPE_AUTH_OK,
|
|
|
|
TYPE_AUTH_REQUIRED,
|
2018-10-01 14:09:31 +00:00
|
|
|
)
|
2019-12-09 11:30:23 +00:00
|
|
|
from homeassistant.components.websocket_api.const import URL
|
2021-04-22 15:04:28 +00:00
|
|
|
from homeassistant.core import Context, HomeAssistant, callback
|
2019-03-02 07:09:31 +00:00
|
|
|
from homeassistant.exceptions import HomeAssistantError
|
2020-08-19 12:57:38 +00:00
|
|
|
from homeassistant.helpers import entity
|
2021-04-05 08:11:44 +00:00
|
|
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
2020-04-15 20:36:16 +00:00
|
|
|
from homeassistant.loader import async_get_integration
|
2021-04-05 08:11:44 +00:00
|
|
|
from homeassistant.setup import DATA_SETUP_TIME, async_setup_component
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2020-08-19 12:57:38 +00:00
|
|
|
from tests.common import MockEntity, MockEntityPlatform, async_mock_service
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_call_service(hass, websocket_client):
|
|
|
|
"""Test call service command."""
|
2021-03-05 23:34:18 +00:00
|
|
|
calls = async_mock_service(hass, "domain_test", "test_service")
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 5,
|
|
|
|
"type": "call_service",
|
|
|
|
"domain": "domain_test",
|
|
|
|
"service": "test_service",
|
|
|
|
"service_data": {"hello": "world"},
|
2018-10-01 09:21:00 +00:00
|
|
|
}
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
assert len(calls) == 1
|
|
|
|
call = calls[0]
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
assert call.domain == "domain_test"
|
|
|
|
assert call.service == "test_service"
|
|
|
|
assert call.data == {"hello": "world"}
|
2021-03-16 07:51:00 +00:00
|
|
|
assert call.context.as_dict() == msg["result"]["context"]
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
|
2021-03-22 05:12:56 +00:00
|
|
|
@pytest.mark.parametrize("command", ("call_service", "call_service_action"))
|
|
|
|
async def test_call_service_blocking(hass, websocket_client, command):
|
|
|
|
"""Test call service commands block, except for homeassistant restart / stop."""
|
|
|
|
with patch(
|
|
|
|
"homeassistant.core.ServiceRegistry.async_call", autospec=True
|
|
|
|
) as mock_call:
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 5,
|
|
|
|
"type": "call_service",
|
|
|
|
"domain": "domain_test",
|
|
|
|
"service": "test_service",
|
|
|
|
"service_data": {"hello": "world"},
|
|
|
|
},
|
|
|
|
)
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
mock_call.assert_called_once_with(
|
|
|
|
ANY,
|
|
|
|
"domain_test",
|
|
|
|
"test_service",
|
|
|
|
{"hello": "world"},
|
|
|
|
blocking=True,
|
|
|
|
context=ANY,
|
|
|
|
target=ANY,
|
|
|
|
)
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
"homeassistant.core.ServiceRegistry.async_call", autospec=True
|
|
|
|
) as mock_call:
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 6,
|
|
|
|
"type": "call_service",
|
|
|
|
"domain": "homeassistant",
|
|
|
|
"service": "test_service",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
|
|
|
|
assert msg["id"] == 6
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
mock_call.assert_called_once_with(
|
|
|
|
ANY,
|
|
|
|
"homeassistant",
|
|
|
|
"test_service",
|
|
|
|
ANY,
|
|
|
|
blocking=True,
|
|
|
|
context=ANY,
|
|
|
|
target=ANY,
|
|
|
|
)
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
"homeassistant.core.ServiceRegistry.async_call", autospec=True
|
|
|
|
) as mock_call:
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 7,
|
|
|
|
"type": "call_service",
|
|
|
|
"domain": "homeassistant",
|
|
|
|
"service": "restart",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
|
|
|
|
assert msg["id"] == 7
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
mock_call.assert_called_once_with(
|
2021-04-13 00:18:38 +00:00
|
|
|
ANY, "homeassistant", "restart", ANY, blocking=True, context=ANY, target=ANY
|
2021-03-22 05:12:56 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2021-02-10 11:42:28 +00:00
|
|
|
async def test_call_service_target(hass, websocket_client):
|
|
|
|
"""Test call service command with target."""
|
2021-03-05 23:34:18 +00:00
|
|
|
calls = async_mock_service(hass, "domain_test", "test_service")
|
2021-02-10 11:42:28 +00:00
|
|
|
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 5,
|
|
|
|
"type": "call_service",
|
|
|
|
"domain": "domain_test",
|
|
|
|
"service": "test_service",
|
|
|
|
"service_data": {"hello": "world"},
|
|
|
|
"target": {
|
|
|
|
"entity_id": ["entity.one", "entity.two"],
|
|
|
|
"device_id": "deviceid",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
|
|
|
|
assert len(calls) == 1
|
|
|
|
call = calls[0]
|
|
|
|
|
|
|
|
assert call.domain == "domain_test"
|
|
|
|
assert call.service == "test_service"
|
|
|
|
assert call.data == {
|
|
|
|
"hello": "world",
|
|
|
|
"entity_id": ["entity.one", "entity.two"],
|
|
|
|
"device_id": ["deviceid"],
|
|
|
|
}
|
2021-03-16 07:51:00 +00:00
|
|
|
assert call.context.as_dict() == msg["result"]["context"]
|
2021-02-10 11:42:28 +00:00
|
|
|
|
|
|
|
|
2021-03-05 23:34:18 +00:00
|
|
|
async def test_call_service_target_template(hass, websocket_client):
|
|
|
|
"""Test call service command with target does not allow template."""
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 5,
|
|
|
|
"type": "call_service",
|
|
|
|
"domain": "domain_test",
|
|
|
|
"service": "test_service",
|
|
|
|
"service_data": {"hello": "world"},
|
|
|
|
"target": {
|
|
|
|
"entity_id": "{{ 1 }}",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert not msg["success"]
|
|
|
|
assert msg["error"]["code"] == const.ERR_INVALID_FORMAT
|
|
|
|
|
|
|
|
|
2018-11-30 20:28:35 +00:00
|
|
|
async def test_call_service_not_found(hass, websocket_client):
|
|
|
|
"""Test call service command."""
|
2019-07-31 19:25:30 +00:00
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 5,
|
|
|
|
"type": "call_service",
|
|
|
|
"domain": "domain_test",
|
|
|
|
"service": "test_service",
|
|
|
|
"service_data": {"hello": "world"},
|
2018-11-30 20:28:35 +00:00
|
|
|
}
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
2018-11-30 20:28:35 +00:00
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert not msg["success"]
|
|
|
|
assert msg["error"]["code"] == const.ERR_NOT_FOUND
|
2018-11-30 20:28:35 +00:00
|
|
|
|
|
|
|
|
2019-05-14 05:09:11 +00:00
|
|
|
async def test_call_service_child_not_found(hass, websocket_client):
|
|
|
|
"""Test not reporting not found errors if it's not the called service."""
|
2019-07-31 19:25:30 +00:00
|
|
|
|
2019-05-14 05:09:11 +00:00
|
|
|
async def serv_handler(call):
|
2019-07-31 19:25:30 +00:00
|
|
|
await hass.services.async_call("non", "existing")
|
2019-05-14 05:09:11 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
hass.services.async_register("domain_test", "test_service", serv_handler)
|
2019-05-14 05:09:11 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 5,
|
|
|
|
"type": "call_service",
|
|
|
|
"domain": "domain_test",
|
|
|
|
"service": "test_service",
|
|
|
|
"service_data": {"hello": "world"},
|
2019-05-14 05:09:11 +00:00
|
|
|
}
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
2019-05-14 05:09:11 +00:00
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert not msg["success"]
|
|
|
|
assert msg["error"]["code"] == const.ERR_HOME_ASSISTANT_ERROR
|
2019-05-14 05:09:11 +00:00
|
|
|
|
|
|
|
|
2021-01-27 14:20:22 +00:00
|
|
|
async def test_call_service_schema_validation_error(
|
2021-04-22 15:04:28 +00:00
|
|
|
hass: HomeAssistant, websocket_client
|
2021-01-27 14:20:22 +00:00
|
|
|
):
|
|
|
|
"""Test call service command with invalid service data."""
|
|
|
|
|
|
|
|
calls = []
|
|
|
|
service_schema = vol.Schema(
|
|
|
|
{
|
|
|
|
vol.Required("message"): str,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
@callback
|
|
|
|
def service_call(call):
|
|
|
|
calls.append(call)
|
|
|
|
|
|
|
|
hass.services.async_register(
|
|
|
|
"domain_test",
|
|
|
|
"test_service",
|
|
|
|
service_call,
|
|
|
|
schema=service_schema,
|
|
|
|
)
|
|
|
|
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 5,
|
|
|
|
"type": "call_service",
|
|
|
|
"domain": "domain_test",
|
|
|
|
"service": "test_service",
|
|
|
|
"service_data": {},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert not msg["success"]
|
|
|
|
assert msg["error"]["code"] == const.ERR_INVALID_FORMAT
|
|
|
|
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 6,
|
|
|
|
"type": "call_service",
|
|
|
|
"domain": "domain_test",
|
|
|
|
"service": "test_service",
|
|
|
|
"service_data": {"extra_key": "not allowed"},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 6
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert not msg["success"]
|
|
|
|
assert msg["error"]["code"] == const.ERR_INVALID_FORMAT
|
|
|
|
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 7,
|
|
|
|
"type": "call_service",
|
|
|
|
"domain": "domain_test",
|
|
|
|
"service": "test_service",
|
|
|
|
"service_data": {"message": []},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 7
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert not msg["success"]
|
|
|
|
assert msg["error"]["code"] == const.ERR_INVALID_FORMAT
|
|
|
|
|
|
|
|
assert len(calls) == 0
|
|
|
|
|
|
|
|
|
2019-03-02 07:09:31 +00:00
|
|
|
async def test_call_service_error(hass, websocket_client):
|
|
|
|
"""Test call service command with error."""
|
2019-07-31 19:25:30 +00:00
|
|
|
|
2019-03-02 07:09:31 +00:00
|
|
|
@callback
|
|
|
|
def ha_error_call(_):
|
2019-07-31 19:25:30 +00:00
|
|
|
raise HomeAssistantError("error_message")
|
2019-03-02 07:09:31 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
hass.services.async_register("domain_test", "ha_error", ha_error_call)
|
2019-03-02 07:09:31 +00:00
|
|
|
|
|
|
|
async def unknown_error_call(_):
|
2019-07-31 19:25:30 +00:00
|
|
|
raise ValueError("value_error")
|
2019-03-02 07:09:31 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
hass.services.async_register("domain_test", "unknown_error", unknown_error_call)
|
2019-03-02 07:09:31 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 5,
|
|
|
|
"type": "call_service",
|
|
|
|
"domain": "domain_test",
|
|
|
|
"service": "ha_error",
|
|
|
|
}
|
|
|
|
)
|
2019-03-02 07:09:31 +00:00
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"] is False
|
|
|
|
assert msg["error"]["code"] == "home_assistant_error"
|
|
|
|
assert msg["error"]["message"] == "error_message"
|
|
|
|
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 6,
|
|
|
|
"type": "call_service",
|
|
|
|
"domain": "domain_test",
|
|
|
|
"service": "unknown_error",
|
|
|
|
}
|
|
|
|
)
|
2019-03-02 07:09:31 +00:00
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["id"] == 6
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"] is False
|
|
|
|
assert msg["error"]["code"] == "unknown_error"
|
|
|
|
assert msg["error"]["message"] == "value_error"
|
2019-03-02 07:09:31 +00:00
|
|
|
|
|
|
|
|
2018-10-01 09:21:00 +00:00
|
|
|
async def test_subscribe_unsubscribe_events(hass, websocket_client):
|
|
|
|
"""Test subscribe/unsubscribe events command."""
|
|
|
|
init_count = sum(hass.bus.async_listeners().values())
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
await websocket_client.send_json(
|
|
|
|
{"id": 5, "type": "subscribe_events", "event_type": "test_event"}
|
|
|
|
)
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
# Verify we have a new listener
|
|
|
|
assert sum(hass.bus.async_listeners().values()) == init_count + 1
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
hass.bus.async_fire("ignore_event")
|
|
|
|
hass.bus.async_fire("test_event", {"hello": "world"})
|
|
|
|
hass.bus.async_fire("ignore_event")
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2021-11-04 15:07:50 +00:00
|
|
|
async with timeout(3):
|
2018-10-01 09:21:00 +00:00
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == "event"
|
|
|
|
event = msg["event"]
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
assert event["event_type"] == "test_event"
|
|
|
|
assert event["data"] == {"hello": "world"}
|
|
|
|
assert event["origin"] == "LOCAL"
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
await websocket_client.send_json(
|
|
|
|
{"id": 6, "type": "unsubscribe_events", "subscription": 5}
|
|
|
|
)
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["id"] == 6
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
# Check our listener got unsubscribed
|
|
|
|
assert sum(hass.bus.async_listeners().values()) == init_count
|
|
|
|
|
|
|
|
|
|
|
|
async def test_get_states(hass, websocket_client):
|
|
|
|
"""Test get_states command."""
|
2019-07-31 19:25:30 +00:00
|
|
|
hass.states.async_set("greeting.hello", "world")
|
|
|
|
hass.states.async_set("greeting.bye", "universe")
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
await websocket_client.send_json({"id": 5, "type": "get_states"})
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
states = []
|
|
|
|
for state in hass.states.async_all():
|
2020-10-05 14:18:57 +00:00
|
|
|
states.append(state.as_dict())
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["result"] == states
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_get_services(hass, websocket_client):
|
|
|
|
"""Test get_services command."""
|
2019-07-31 19:25:30 +00:00
|
|
|
await websocket_client.send_json({"id": 5, "type": "get_services"})
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
assert msg["result"] == hass.services.async_services()
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_get_config(hass, websocket_client):
|
|
|
|
"""Test get_config command."""
|
2019-07-31 19:25:30 +00:00
|
|
|
await websocket_client.send_json({"id": 5, "type": "get_config"})
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
if "components" in msg["result"]:
|
|
|
|
msg["result"]["components"] = set(msg["result"]["components"])
|
|
|
|
if "whitelist_external_dirs" in msg["result"]:
|
|
|
|
msg["result"]["whitelist_external_dirs"] = set(
|
|
|
|
msg["result"]["whitelist_external_dirs"]
|
|
|
|
)
|
2020-07-13 15:43:11 +00:00
|
|
|
if "allowlist_external_dirs" in msg["result"]:
|
|
|
|
msg["result"]["allowlist_external_dirs"] = set(
|
|
|
|
msg["result"]["allowlist_external_dirs"]
|
|
|
|
)
|
2020-06-25 00:37:01 +00:00
|
|
|
if "allowlist_external_urls" in msg["result"]:
|
|
|
|
msg["result"]["allowlist_external_urls"] = set(
|
|
|
|
msg["result"]["allowlist_external_urls"]
|
|
|
|
)
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["result"] == hass.config.as_dict()
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_ping(websocket_client):
|
|
|
|
"""Test get_panels command."""
|
2019-07-31 19:25:30 +00:00
|
|
|
await websocket_client.send_json({"id": 5, "type": "ping"})
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == "pong"
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
|
2021-09-02 12:50:10 +00:00
|
|
|
async def test_call_service_context_with_user(
|
|
|
|
hass, hass_client_no_auth, hass_access_token
|
|
|
|
):
|
2018-10-01 09:21:00 +00:00
|
|
|
"""Test that the user is set in the service call context."""
|
2019-10-14 21:56:45 +00:00
|
|
|
assert await async_setup_component(hass, "websocket_api", {})
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
calls = async_mock_service(hass, "domain_test", "test_service")
|
2021-09-02 12:50:10 +00:00
|
|
|
client = await hass_client_no_auth()
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2018-10-01 14:09:31 +00:00
|
|
|
async with client.ws_connect(URL) as ws:
|
2018-10-01 09:21:00 +00:00
|
|
|
auth_msg = await ws.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert auth_msg["type"] == TYPE_AUTH_REQUIRED
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
await ws.send_json({"type": TYPE_AUTH, "access_token": hass_access_token})
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
auth_msg = await ws.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert auth_msg["type"] == TYPE_AUTH_OK
|
|
|
|
|
|
|
|
await ws.send_json(
|
|
|
|
{
|
|
|
|
"id": 5,
|
|
|
|
"type": "call_service",
|
|
|
|
"domain": "domain_test",
|
|
|
|
"service": "test_service",
|
|
|
|
"service_data": {"hello": "world"},
|
2018-10-01 09:21:00 +00:00
|
|
|
}
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
2018-10-01 09:21:00 +00:00
|
|
|
|
|
|
|
msg = await ws.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["success"]
|
2018-10-01 09:21:00 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
refresh_token = await hass.auth.async_validate_access_token(hass_access_token)
|
2018-12-02 15:32:53 +00:00
|
|
|
|
2018-10-01 09:21:00 +00:00
|
|
|
assert len(calls) == 1
|
|
|
|
call = calls[0]
|
2019-07-31 19:25:30 +00:00
|
|
|
assert call.domain == "domain_test"
|
|
|
|
assert call.service == "test_service"
|
|
|
|
assert call.data == {"hello": "world"}
|
2018-12-02 15:32:53 +00:00
|
|
|
assert call.context.user_id == refresh_token.user.id
|
2018-11-27 09:12:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_subscribe_requires_admin(websocket_client, hass_admin_user):
|
|
|
|
"""Test subscribing events without being admin."""
|
|
|
|
hass_admin_user.groups = []
|
2019-07-31 19:25:30 +00:00
|
|
|
await websocket_client.send_json(
|
|
|
|
{"id": 5, "type": "subscribe_events", "event_type": "test_event"}
|
|
|
|
)
|
2018-11-27 09:12:31 +00:00
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert not msg["success"]
|
|
|
|
assert msg["error"]["code"] == const.ERR_UNAUTHORIZED
|
2018-11-27 09:12:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_states_filters_visible(hass, hass_admin_user, websocket_client):
|
|
|
|
"""Test we only get entities that we're allowed to see."""
|
2019-07-31 19:25:30 +00:00
|
|
|
hass_admin_user.mock_policy({"entities": {"entity_ids": {"test.entity": True}}})
|
|
|
|
hass.states.async_set("test.entity", "hello")
|
|
|
|
hass.states.async_set("test.not_visible_entity", "invisible")
|
|
|
|
await websocket_client.send_json({"id": 5, "type": "get_states"})
|
2018-11-27 09:12:31 +00:00
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
2018-11-27 09:12:31 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
assert len(msg["result"]) == 1
|
|
|
|
assert msg["result"][0]["entity_id"] == "test.entity"
|
2018-11-28 12:25:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_get_states_not_allows_nan(hass, websocket_client):
|
|
|
|
"""Test get_states command not allows NaN floats."""
|
2019-07-31 19:25:30 +00:00
|
|
|
hass.states.async_set("greeting.hello", "world", {"hello": float("NaN")})
|
2018-11-28 12:25:23 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
await websocket_client.send_json({"id": 5, "type": "get_states"})
|
2018-11-28 12:25:23 +00:00
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert not msg["success"]
|
|
|
|
assert msg["error"]["code"] == const.ERR_UNKNOWN_ERROR
|
2019-03-18 02:13:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_subscribe_unsubscribe_events_whitelist(
|
2019-07-31 19:25:30 +00:00
|
|
|
hass, websocket_client, hass_admin_user
|
|
|
|
):
|
2019-03-18 02:13:06 +00:00
|
|
|
"""Test subscribe/unsubscribe events on whitelist."""
|
|
|
|
hass_admin_user.groups = []
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
await websocket_client.send_json(
|
|
|
|
{"id": 5, "type": "subscribe_events", "event_type": "not-in-whitelist"}
|
|
|
|
)
|
2019-03-18 02:13:06 +00:00
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert not msg["success"]
|
|
|
|
assert msg["error"]["code"] == "unauthorized"
|
2019-03-18 02:13:06 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
await websocket_client.send_json(
|
|
|
|
{"id": 6, "type": "subscribe_events", "event_type": "themes_updated"}
|
|
|
|
)
|
2019-03-18 02:13:06 +00:00
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["id"] == 6
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
2019-03-18 02:13:06 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
hass.bus.async_fire("themes_updated")
|
2019-03-18 02:13:06 +00:00
|
|
|
|
2021-11-04 15:07:50 +00:00
|
|
|
async with timeout(3):
|
2019-03-18 02:13:06 +00:00
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["id"] == 6
|
|
|
|
assert msg["type"] == "event"
|
|
|
|
event = msg["event"]
|
|
|
|
assert event["event_type"] == "themes_updated"
|
|
|
|
assert event["origin"] == "LOCAL"
|
2019-03-18 02:13:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_subscribe_unsubscribe_events_state_changed(
|
2019-07-31 19:25:30 +00:00
|
|
|
hass, websocket_client, hass_admin_user
|
|
|
|
):
|
2019-03-18 02:13:06 +00:00
|
|
|
"""Test subscribe/unsubscribe state_changed events."""
|
|
|
|
hass_admin_user.groups = []
|
2019-07-31 19:25:30 +00:00
|
|
|
hass_admin_user.mock_policy({"entities": {"entity_ids": {"light.permitted": True}}})
|
2019-03-18 02:13:06 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
await websocket_client.send_json(
|
|
|
|
{"id": 7, "type": "subscribe_events", "event_type": "state_changed"}
|
|
|
|
)
|
2019-03-18 02:13:06 +00:00
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["id"] == 7
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
2019-03-18 02:13:06 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
hass.states.async_set("light.not_permitted", "on")
|
|
|
|
hass.states.async_set("light.permitted", "on")
|
2019-03-18 02:13:06 +00:00
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2019-07-31 19:25:30 +00:00
|
|
|
assert msg["id"] == 7
|
|
|
|
assert msg["type"] == "event"
|
|
|
|
assert msg["event"]["event_type"] == "state_changed"
|
|
|
|
assert msg["event"]["data"]["entity_id"] == "light.permitted"
|
2019-08-10 19:46:49 +00:00
|
|
|
|
|
|
|
|
2020-09-28 12:43:22 +00:00
|
|
|
async def test_render_template_renders_template(hass, websocket_client):
|
2019-08-10 19:46:49 +00:00
|
|
|
"""Test simple template is rendered and updated."""
|
|
|
|
hass.states.async_set("light.test", "on")
|
|
|
|
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 5,
|
|
|
|
"type": "render_template",
|
|
|
|
"template": "State is: {{ states('light.test') }}",
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == "event"
|
|
|
|
event = msg["event"]
|
2020-09-11 18:18:40 +00:00
|
|
|
assert event == {
|
|
|
|
"result": "State is: on",
|
2020-10-19 09:02:43 +00:00
|
|
|
"listeners": {
|
|
|
|
"all": False,
|
|
|
|
"domains": [],
|
|
|
|
"entities": ["light.test"],
|
|
|
|
"time": False,
|
|
|
|
},
|
2020-09-11 18:18:40 +00:00
|
|
|
}
|
2019-08-10 19:46:49 +00:00
|
|
|
|
|
|
|
hass.states.async_set("light.test", "off")
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == "event"
|
|
|
|
event = msg["event"]
|
2020-09-11 18:18:40 +00:00
|
|
|
assert event == {
|
|
|
|
"result": "State is: off",
|
2020-10-19 09:02:43 +00:00
|
|
|
"listeners": {
|
|
|
|
"all": False,
|
|
|
|
"domains": [],
|
|
|
|
"entities": ["light.test"],
|
|
|
|
"time": False,
|
|
|
|
},
|
2020-09-11 18:18:40 +00:00
|
|
|
}
|
2019-08-10 19:46:49 +00:00
|
|
|
|
|
|
|
|
2020-08-21 12:04:29 +00:00
|
|
|
async def test_render_template_manual_entity_ids_no_longer_needed(
|
2020-09-28 12:43:22 +00:00
|
|
|
hass, websocket_client
|
2019-08-10 19:46:49 +00:00
|
|
|
):
|
|
|
|
"""Test that updates to specified entity ids cause a template rerender."""
|
|
|
|
hass.states.async_set("light.test", "on")
|
|
|
|
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 5,
|
|
|
|
"type": "render_template",
|
|
|
|
"template": "State is: {{ states('light.test') }}",
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == "event"
|
|
|
|
event = msg["event"]
|
2020-09-11 18:18:40 +00:00
|
|
|
assert event == {
|
|
|
|
"result": "State is: on",
|
2020-10-19 09:02:43 +00:00
|
|
|
"listeners": {
|
|
|
|
"all": False,
|
|
|
|
"domains": [],
|
|
|
|
"entities": ["light.test"],
|
|
|
|
"time": False,
|
|
|
|
},
|
2020-09-11 18:18:40 +00:00
|
|
|
}
|
2019-08-10 19:46:49 +00:00
|
|
|
|
2020-08-21 12:04:29 +00:00
|
|
|
hass.states.async_set("light.test", "off")
|
2019-08-10 19:46:49 +00:00
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == "event"
|
|
|
|
event = msg["event"]
|
2020-09-11 18:18:40 +00:00
|
|
|
assert event == {
|
|
|
|
"result": "State is: off",
|
2020-10-19 09:02:43 +00:00
|
|
|
"listeners": {
|
|
|
|
"all": False,
|
|
|
|
"domains": [],
|
|
|
|
"entities": ["light.test"],
|
|
|
|
"time": False,
|
|
|
|
},
|
2020-09-11 18:18:40 +00:00
|
|
|
}
|
2020-08-21 12:04:29 +00:00
|
|
|
|
|
|
|
|
2021-04-09 19:10:02 +00:00
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"template",
|
|
|
|
[
|
|
|
|
"{{ my_unknown_func() + 1 }}",
|
|
|
|
"{{ my_unknown_var }}",
|
|
|
|
"{{ my_unknown_var + 1 }}",
|
|
|
|
"{{ now() | unknown_filter }}",
|
|
|
|
],
|
|
|
|
)
|
|
|
|
async def test_render_template_with_error(hass, websocket_client, caplog, template):
|
2020-08-21 12:04:29 +00:00
|
|
|
"""Test a template with an error."""
|
|
|
|
await websocket_client.send_json(
|
2021-04-09 19:10:02 +00:00
|
|
|
{"id": 5, "type": "render_template", "template": template, "strict": True}
|
2020-08-21 12:04:29 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
2020-09-26 22:03:32 +00:00
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert not msg["success"]
|
|
|
|
assert msg["error"]["code"] == const.ERR_TEMPLATE_ERROR
|
|
|
|
|
2021-04-09 19:10:02 +00:00
|
|
|
assert "Template variable error" not in caplog.text
|
2020-09-26 22:03:32 +00:00
|
|
|
assert "TemplateError" not in caplog.text
|
|
|
|
|
|
|
|
|
2021-04-09 19:10:02 +00:00
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"template",
|
|
|
|
[
|
|
|
|
"{{ my_unknown_func() + 1 }}",
|
|
|
|
"{{ my_unknown_var }}",
|
|
|
|
"{{ my_unknown_var + 1 }}",
|
|
|
|
"{{ now() | unknown_filter }}",
|
|
|
|
],
|
|
|
|
)
|
|
|
|
async def test_render_template_with_timeout_and_error(
|
|
|
|
hass, websocket_client, caplog, template
|
|
|
|
):
|
2020-10-12 14:38:24 +00:00
|
|
|
"""Test a template with an error with a timeout."""
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 5,
|
|
|
|
"type": "render_template",
|
2021-04-09 19:10:02 +00:00
|
|
|
"template": template,
|
2020-10-12 14:38:24 +00:00
|
|
|
"timeout": 5,
|
2021-04-09 19:10:02 +00:00
|
|
|
"strict": True,
|
2020-10-12 14:38:24 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert not msg["success"]
|
|
|
|
assert msg["error"]["code"] == const.ERR_TEMPLATE_ERROR
|
|
|
|
|
2021-04-09 19:10:02 +00:00
|
|
|
assert "Template variable error" not in caplog.text
|
2020-10-12 14:38:24 +00:00
|
|
|
assert "TemplateError" not in caplog.text
|
|
|
|
|
|
|
|
|
|
|
|
async def test_render_template_error_in_template_code(hass, websocket_client, caplog):
|
|
|
|
"""Test a template that will throw in template.py."""
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{"id": 5, "type": "render_template", "template": "{{ now() | random }}"}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert not msg["success"]
|
|
|
|
assert msg["error"]["code"] == const.ERR_TEMPLATE_ERROR
|
|
|
|
|
|
|
|
assert "TemplateError" not in caplog.text
|
|
|
|
|
|
|
|
|
2020-09-28 12:43:22 +00:00
|
|
|
async def test_render_template_with_delayed_error(hass, websocket_client, caplog):
|
2020-09-26 22:03:32 +00:00
|
|
|
"""Test a template with an error that only happens after a state change."""
|
|
|
|
hass.states.async_set("sensor.test", "on")
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
template_str = """
|
|
|
|
{% if states.sensor.test.state %}
|
|
|
|
on
|
|
|
|
{% else %}
|
|
|
|
{{ explode + 1 }}
|
|
|
|
{% endif %}
|
|
|
|
"""
|
|
|
|
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{"id": 5, "type": "render_template", "template": template_str}
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
|
2020-08-21 12:04:29 +00:00
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
|
2020-09-26 22:03:32 +00:00
|
|
|
hass.states.async_remove("sensor.test")
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
2020-08-21 12:04:29 +00:00
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == "event"
|
|
|
|
event = msg["event"]
|
2020-09-11 18:18:40 +00:00
|
|
|
assert event == {
|
2020-09-26 22:03:32 +00:00
|
|
|
"result": "on",
|
2020-10-19 09:02:43 +00:00
|
|
|
"listeners": {
|
|
|
|
"all": False,
|
|
|
|
"domains": [],
|
|
|
|
"entities": ["sensor.test"],
|
|
|
|
"time": False,
|
|
|
|
},
|
2020-09-11 18:18:40 +00:00
|
|
|
}
|
2020-08-21 12:04:29 +00:00
|
|
|
|
2020-09-26 22:03:32 +00:00
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert not msg["success"]
|
|
|
|
assert msg["error"]["code"] == const.ERR_TEMPLATE_ERROR
|
|
|
|
|
|
|
|
assert "TemplateError" not in caplog.text
|
2019-08-10 19:46:49 +00:00
|
|
|
|
|
|
|
|
2020-09-28 12:43:22 +00:00
|
|
|
async def test_render_template_with_timeout(hass, websocket_client, caplog):
|
|
|
|
"""Test a template that will timeout."""
|
|
|
|
|
|
|
|
slow_template_str = """
|
|
|
|
{% for var in range(1000) -%}
|
|
|
|
{% for var in range(1000) -%}
|
|
|
|
{{ var }}
|
|
|
|
{%- endfor %}
|
|
|
|
{%- endfor %}
|
|
|
|
"""
|
|
|
|
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 5,
|
|
|
|
"type": "render_template",
|
|
|
|
"timeout": 0.000001,
|
|
|
|
"template": slow_template_str,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert not msg["success"]
|
|
|
|
assert msg["error"]["code"] == const.ERR_TEMPLATE_ERROR
|
|
|
|
|
|
|
|
assert "TemplateError" not in caplog.text
|
|
|
|
|
|
|
|
|
|
|
|
async def test_render_template_returns_with_match_all(hass, websocket_client):
|
2019-08-10 19:46:49 +00:00
|
|
|
"""Test that a template that would match with all entities still return success."""
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{"id": 5, "type": "render_template", "template": "State is: {{ 42 }}"}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
2020-04-15 20:36:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_manifest_list(hass, websocket_client):
|
|
|
|
"""Test loading manifests."""
|
|
|
|
http = await async_get_integration(hass, "http")
|
|
|
|
websocket_api = await async_get_integration(hass, "websocket_api")
|
|
|
|
|
|
|
|
await websocket_client.send_json({"id": 5, "type": "manifest/list"})
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
assert sorted(msg["result"], key=lambda manifest: manifest["domain"]) == [
|
|
|
|
http.manifest,
|
|
|
|
websocket_api.manifest,
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
async def test_manifest_get(hass, websocket_client):
|
|
|
|
"""Test getting a manifest."""
|
|
|
|
hue = await async_get_integration(hass, "hue")
|
|
|
|
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{"id": 6, "type": "manifest/get", "integration": "hue"}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 6
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
assert msg["result"] == hue.manifest
|
|
|
|
|
|
|
|
# Non existing
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{"id": 7, "type": "manifest/get", "integration": "non_existing"}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 7
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert not msg["success"]
|
|
|
|
assert msg["error"]["code"] == "not_found"
|
2020-08-19 12:57:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_entity_source_admin(hass, websocket_client, hass_admin_user):
|
|
|
|
"""Check that we fetch sources correctly."""
|
|
|
|
platform = MockEntityPlatform(hass)
|
|
|
|
|
|
|
|
await platform.async_add_entities(
|
|
|
|
[MockEntity(name="Entity 1"), MockEntity(name="Entity 2")]
|
|
|
|
)
|
|
|
|
|
|
|
|
# Fetch all
|
|
|
|
await websocket_client.send_json({"id": 6, "type": "entity/source"})
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 6
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
assert msg["result"] == {
|
|
|
|
"test_domain.entity_1": {
|
2021-09-30 14:49:16 +00:00
|
|
|
"custom_component": False,
|
2020-08-19 12:57:38 +00:00
|
|
|
"domain": "test_platform",
|
2021-09-30 14:49:16 +00:00
|
|
|
"source": entity.SOURCE_PLATFORM_CONFIG,
|
2020-08-19 12:57:38 +00:00
|
|
|
},
|
|
|
|
"test_domain.entity_2": {
|
2021-09-30 14:49:16 +00:00
|
|
|
"custom_component": False,
|
2020-08-19 12:57:38 +00:00
|
|
|
"domain": "test_platform",
|
2021-09-30 14:49:16 +00:00
|
|
|
"source": entity.SOURCE_PLATFORM_CONFIG,
|
2020-08-19 12:57:38 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
# Fetch one
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{"id": 7, "type": "entity/source", "entity_id": ["test_domain.entity_2"]}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 7
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
assert msg["result"] == {
|
|
|
|
"test_domain.entity_2": {
|
2021-09-30 14:49:16 +00:00
|
|
|
"custom_component": False,
|
2020-08-19 12:57:38 +00:00
|
|
|
"domain": "test_platform",
|
2021-09-30 14:49:16 +00:00
|
|
|
"source": entity.SOURCE_PLATFORM_CONFIG,
|
2020-08-19 12:57:38 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
# Fetch two
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 8,
|
|
|
|
"type": "entity/source",
|
|
|
|
"entity_id": ["test_domain.entity_2", "test_domain.entity_1"],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 8
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
assert msg["result"] == {
|
|
|
|
"test_domain.entity_1": {
|
2021-09-30 14:49:16 +00:00
|
|
|
"custom_component": False,
|
2020-08-19 12:57:38 +00:00
|
|
|
"domain": "test_platform",
|
2021-09-30 14:49:16 +00:00
|
|
|
"source": entity.SOURCE_PLATFORM_CONFIG,
|
2020-08-19 12:57:38 +00:00
|
|
|
},
|
|
|
|
"test_domain.entity_2": {
|
2021-09-30 14:49:16 +00:00
|
|
|
"custom_component": False,
|
2020-08-19 12:57:38 +00:00
|
|
|
"domain": "test_platform",
|
2021-09-30 14:49:16 +00:00
|
|
|
"source": entity.SOURCE_PLATFORM_CONFIG,
|
2020-08-19 12:57:38 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
# Fetch non existing
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 9,
|
|
|
|
"type": "entity/source",
|
|
|
|
"entity_id": ["test_domain.entity_2", "test_domain.non_existing"],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 9
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert not msg["success"]
|
|
|
|
assert msg["error"]["code"] == const.ERR_NOT_FOUND
|
|
|
|
|
|
|
|
# Mock policy
|
|
|
|
hass_admin_user.groups = []
|
|
|
|
hass_admin_user.mock_policy(
|
|
|
|
{"entities": {"entity_ids": {"test_domain.entity_2": True}}}
|
|
|
|
)
|
|
|
|
|
|
|
|
# Fetch all
|
|
|
|
await websocket_client.send_json({"id": 10, "type": "entity/source"})
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 10
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
assert msg["result"] == {
|
|
|
|
"test_domain.entity_2": {
|
2021-09-30 14:49:16 +00:00
|
|
|
"custom_component": False,
|
2020-08-19 12:57:38 +00:00
|
|
|
"domain": "test_platform",
|
2021-09-30 14:49:16 +00:00
|
|
|
"source": entity.SOURCE_PLATFORM_CONFIG,
|
2020-08-19 12:57:38 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
# Fetch unauthorized
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{"id": 11, "type": "entity/source", "entity_id": ["test_domain.entity_1"]}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 11
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert not msg["success"]
|
|
|
|
assert msg["error"]["code"] == const.ERR_UNAUTHORIZED
|
2020-08-24 21:01:57 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_subscribe_trigger(hass, websocket_client):
|
|
|
|
"""Test subscribing to a trigger."""
|
|
|
|
init_count = sum(hass.bus.async_listeners().values())
|
|
|
|
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 5,
|
|
|
|
"type": "subscribe_trigger",
|
|
|
|
"trigger": {"platform": "event", "event_type": "test_event"},
|
|
|
|
"variables": {"hello": "world"},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
|
|
|
|
# Verify we have a new listener
|
|
|
|
assert sum(hass.bus.async_listeners().values()) == init_count + 1
|
|
|
|
|
|
|
|
context = Context()
|
|
|
|
|
|
|
|
hass.bus.async_fire("ignore_event")
|
|
|
|
hass.bus.async_fire("test_event", {"hello": "world"}, context=context)
|
|
|
|
hass.bus.async_fire("ignore_event")
|
|
|
|
|
2021-11-04 15:07:50 +00:00
|
|
|
async with timeout(3):
|
2020-08-24 21:01:57 +00:00
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == "event"
|
|
|
|
assert msg["event"]["context"]["id"] == context.id
|
|
|
|
assert msg["event"]["variables"]["trigger"]["platform"] == "event"
|
|
|
|
|
|
|
|
event = msg["event"]["variables"]["trigger"]["event"]
|
|
|
|
|
|
|
|
assert event["event_type"] == "test_event"
|
|
|
|
assert event["data"] == {"hello": "world"}
|
|
|
|
assert event["origin"] == "LOCAL"
|
|
|
|
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{"id": 6, "type": "unsubscribe_events", "subscription": 5}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 6
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
|
|
|
|
# Check our listener got unsubscribed
|
|
|
|
assert sum(hass.bus.async_listeners().values()) == init_count
|
|
|
|
|
|
|
|
|
|
|
|
async def test_test_condition(hass, websocket_client):
|
|
|
|
"""Test testing a condition."""
|
|
|
|
hass.states.async_set("hello.world", "paulus")
|
|
|
|
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 5,
|
|
|
|
"type": "test_condition",
|
|
|
|
"condition": {
|
|
|
|
"condition": "state",
|
|
|
|
"entity_id": "hello.world",
|
|
|
|
"state": "paulus",
|
|
|
|
},
|
|
|
|
"variables": {"hello": "world"},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 5
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
assert msg["result"]["result"] is True
|
2021-03-16 07:51:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_execute_script(hass, websocket_client):
|
|
|
|
"""Test testing a condition."""
|
|
|
|
calls = async_mock_service(hass, "domain_test", "test_service")
|
|
|
|
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 5,
|
|
|
|
"type": "execute_script",
|
|
|
|
"sequence": [
|
|
|
|
{
|
|
|
|
"service": "domain_test.test_service",
|
|
|
|
"data": {"hello": "world"},
|
|
|
|
}
|
|
|
|
],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2021-04-02 13:27:41 +00:00
|
|
|
msg_no_var = await websocket_client.receive_json()
|
|
|
|
assert msg_no_var["id"] == 5
|
|
|
|
assert msg_no_var["type"] == const.TYPE_RESULT
|
|
|
|
assert msg_no_var["success"]
|
2021-03-16 07:51:00 +00:00
|
|
|
|
2021-04-02 13:27:41 +00:00
|
|
|
await websocket_client.send_json(
|
|
|
|
{
|
|
|
|
"id": 6,
|
|
|
|
"type": "execute_script",
|
|
|
|
"sequence": {
|
|
|
|
"service": "domain_test.test_service",
|
|
|
|
"data": {"hello": "{{ name }}"},
|
|
|
|
},
|
|
|
|
"variables": {"name": "From variable"},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg_var = await websocket_client.receive_json()
|
|
|
|
assert msg_var["id"] == 6
|
|
|
|
assert msg_var["type"] == const.TYPE_RESULT
|
|
|
|
assert msg_var["success"]
|
2021-03-16 07:51:00 +00:00
|
|
|
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
2021-04-02 13:27:41 +00:00
|
|
|
assert len(calls) == 2
|
2021-03-16 07:51:00 +00:00
|
|
|
|
2021-04-02 13:27:41 +00:00
|
|
|
call = calls[0]
|
2021-03-16 07:51:00 +00:00
|
|
|
assert call.domain == "domain_test"
|
|
|
|
assert call.service == "test_service"
|
|
|
|
assert call.data == {"hello": "world"}
|
2021-04-02 13:27:41 +00:00
|
|
|
assert call.context.as_dict() == msg_no_var["result"]["context"]
|
|
|
|
|
|
|
|
call = calls[1]
|
|
|
|
assert call.domain == "domain_test"
|
|
|
|
assert call.service == "test_service"
|
|
|
|
assert call.data == {"hello": "From variable"}
|
|
|
|
assert call.context.as_dict() == msg_var["result"]["context"]
|
2021-04-05 08:11:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_subscribe_unsubscribe_bootstrap_integrations(
|
|
|
|
hass, websocket_client, hass_admin_user
|
|
|
|
):
|
|
|
|
"""Test subscribe/unsubscribe bootstrap_integrations."""
|
|
|
|
await websocket_client.send_json(
|
|
|
|
{"id": 7, "type": "subscribe_bootstrap_integrations"}
|
|
|
|
)
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 7
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
|
|
|
|
message = {"august": 12.5, "isy994": 12.8}
|
|
|
|
|
|
|
|
async_dispatcher_send(hass, SIGNAL_BOOTSTRAP_INTEGRATONS, message)
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 7
|
2021-04-08 17:30:33 +00:00
|
|
|
assert msg["type"] == "event"
|
|
|
|
assert msg["event"] == message
|
2021-04-05 08:11:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_integration_setup_info(hass, websocket_client, hass_admin_user):
|
|
|
|
"""Test subscribe/unsubscribe bootstrap_integrations."""
|
|
|
|
hass.data[DATA_SETUP_TIME] = {
|
|
|
|
"august": datetime.timedelta(seconds=12.5),
|
|
|
|
"isy994": datetime.timedelta(seconds=12.8),
|
|
|
|
}
|
|
|
|
await websocket_client.send_json({"id": 7, "type": "integration/setup_info"})
|
|
|
|
|
|
|
|
msg = await websocket_client.receive_json()
|
|
|
|
assert msg["id"] == 7
|
|
|
|
assert msg["type"] == const.TYPE_RESULT
|
|
|
|
assert msg["success"]
|
|
|
|
assert msg["result"] == [
|
|
|
|
{"domain": "august", "seconds": 12.5},
|
|
|
|
{"domain": "isy994", "seconds": 12.8},
|
|
|
|
]
|