mirror of
https://github.com/home-assistant/core
synced 2024-07-30 21:18:57 +02:00
Add slots to the service registry (#95857)
This commit is contained in:
parent
bd7057f7b1
commit
ea57f78392
@ -1726,6 +1726,8 @@ class ServiceCall:
|
|||||||
class ServiceRegistry:
|
class ServiceRegistry:
|
||||||
"""Offer the services over the eventbus."""
|
"""Offer the services over the eventbus."""
|
||||||
|
|
||||||
|
__slots__ = ("_services", "_hass")
|
||||||
|
|
||||||
def __init__(self, hass: HomeAssistant) -> None:
|
def __init__(self, hass: HomeAssistant) -> None:
|
||||||
"""Initialize a service registry."""
|
"""Initialize a service registry."""
|
||||||
self._services: dict[str, dict[str, Service]] = {}
|
self._services: dict[str, dict[str, Service]] = {}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""Test Google Smart Home."""
|
"""Test Google Smart Home."""
|
||||||
import asyncio
|
import asyncio
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
from unittest.mock import ANY, call, patch
|
from unittest.mock import ANY, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from pytest_unordered import unordered
|
from pytest_unordered import unordered
|
||||||
@ -488,76 +488,41 @@ async def test_execute(
|
|||||||
events = async_capture_events(hass, EVENT_COMMAND_RECEIVED)
|
events = async_capture_events(hass, EVENT_COMMAND_RECEIVED)
|
||||||
service_events = async_capture_events(hass, EVENT_CALL_SERVICE)
|
service_events = async_capture_events(hass, EVENT_CALL_SERVICE)
|
||||||
|
|
||||||
with patch.object(
|
result = await sh.async_handle_message(
|
||||||
hass.services, "async_call", wraps=hass.services.async_call
|
hass,
|
||||||
) as call_service_mock:
|
MockConfig(should_report_state=report_state),
|
||||||
result = await sh.async_handle_message(
|
None,
|
||||||
hass,
|
{
|
||||||
MockConfig(should_report_state=report_state),
|
"requestId": REQ_ID,
|
||||||
None,
|
"inputs": [
|
||||||
{
|
{
|
||||||
"requestId": REQ_ID,
|
"intent": "action.devices.EXECUTE",
|
||||||
"inputs": [
|
"payload": {
|
||||||
{
|
"commands": [
|
||||||
"intent": "action.devices.EXECUTE",
|
{
|
||||||
"payload": {
|
"devices": [
|
||||||
"commands": [
|
{"id": "light.non_existing"},
|
||||||
{
|
{"id": "light.ceiling_lights"},
|
||||||
"devices": [
|
{"id": "light.kitchen_lights"},
|
||||||
{"id": "light.non_existing"},
|
],
|
||||||
{"id": "light.ceiling_lights"},
|
"execution": [
|
||||||
{"id": "light.kitchen_lights"},
|
{
|
||||||
],
|
"command": "action.devices.commands.OnOff",
|
||||||
"execution": [
|
"params": {"on": True},
|
||||||
{
|
},
|
||||||
"command": "action.devices.commands.OnOff",
|
{
|
||||||
"params": {"on": True},
|
"command": "action.devices.commands.BrightnessAbsolute",
|
||||||
},
|
"params": {"brightness": 20},
|
||||||
{
|
},
|
||||||
"command": "action.devices.commands.BrightnessAbsolute",
|
],
|
||||||
"params": {"brightness": 20},
|
}
|
||||||
},
|
]
|
||||||
],
|
},
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
}
|
const.SOURCE_CLOUD,
|
||||||
],
|
)
|
||||||
},
|
|
||||||
const.SOURCE_CLOUD,
|
|
||||||
)
|
|
||||||
assert call_service_mock.call_count == 4
|
|
||||||
expected_calls = [
|
|
||||||
call(
|
|
||||||
"light",
|
|
||||||
"turn_on",
|
|
||||||
{"entity_id": "light.ceiling_lights"},
|
|
||||||
blocking=not report_state,
|
|
||||||
context=ANY,
|
|
||||||
),
|
|
||||||
call(
|
|
||||||
"light",
|
|
||||||
"turn_on",
|
|
||||||
{"entity_id": "light.kitchen_lights"},
|
|
||||||
blocking=not report_state,
|
|
||||||
context=ANY,
|
|
||||||
),
|
|
||||||
call(
|
|
||||||
"light",
|
|
||||||
"turn_on",
|
|
||||||
{"entity_id": "light.ceiling_lights", "brightness_pct": 20},
|
|
||||||
blocking=not report_state,
|
|
||||||
context=ANY,
|
|
||||||
),
|
|
||||||
call(
|
|
||||||
"light",
|
|
||||||
"turn_on",
|
|
||||||
{"entity_id": "light.kitchen_lights", "brightness_pct": 20},
|
|
||||||
blocking=not report_state,
|
|
||||||
context=ANY,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
call_service_mock.assert_has_awaits(expected_calls, any_order=True)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert result == {
|
assert result == {
|
||||||
@ -682,11 +647,7 @@ async def test_execute_times_out(
|
|||||||
# Make DemoLigt.async_turn_on hang waiting for the turn_on_wait event
|
# Make DemoLigt.async_turn_on hang waiting for the turn_on_wait event
|
||||||
await turn_on_wait.wait()
|
await turn_on_wait.wait()
|
||||||
|
|
||||||
with patch.object(
|
with patch.object(DemoLight, "async_turn_on", wraps=slow_turn_on):
|
||||||
hass.services, "async_call", wraps=hass.services.async_call
|
|
||||||
) as call_service_mock, patch.object(
|
|
||||||
DemoLight, "async_turn_on", wraps=slow_turn_on
|
|
||||||
):
|
|
||||||
result = await sh.async_handle_message(
|
result = await sh.async_handle_message(
|
||||||
hass,
|
hass,
|
||||||
MockConfig(should_report_state=report_state),
|
MockConfig(should_report_state=report_state),
|
||||||
@ -722,51 +683,10 @@ async def test_execute_times_out(
|
|||||||
},
|
},
|
||||||
const.SOURCE_CLOUD,
|
const.SOURCE_CLOUD,
|
||||||
)
|
)
|
||||||
# Only the two first calls are executed
|
|
||||||
assert call_service_mock.call_count == 2
|
|
||||||
expected_calls = [
|
|
||||||
call(
|
|
||||||
"light",
|
|
||||||
"turn_on",
|
|
||||||
{"entity_id": "light.ceiling_lights"},
|
|
||||||
blocking=not report_state,
|
|
||||||
context=ANY,
|
|
||||||
),
|
|
||||||
call(
|
|
||||||
"light",
|
|
||||||
"turn_on",
|
|
||||||
{"entity_id": "light.kitchen_lights"},
|
|
||||||
blocking=not report_state,
|
|
||||||
context=ANY,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
call_service_mock.assert_has_awaits(expected_calls, any_order=True)
|
|
||||||
|
|
||||||
turn_on_wait.set()
|
turn_on_wait.set()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
# The remaining two calls should now have executed
|
|
||||||
assert call_service_mock.call_count == 4
|
|
||||||
expected_calls.extend(
|
|
||||||
[
|
|
||||||
call(
|
|
||||||
"light",
|
|
||||||
"turn_on",
|
|
||||||
{"entity_id": "light.ceiling_lights", "brightness_pct": 20},
|
|
||||||
blocking=not report_state,
|
|
||||||
context=ANY,
|
|
||||||
),
|
|
||||||
call(
|
|
||||||
"light",
|
|
||||||
"turn_on",
|
|
||||||
{"entity_id": "light.kitchen_lights", "brightness_pct": 20},
|
|
||||||
blocking=not report_state,
|
|
||||||
context=ANY,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
call_service_mock.assert_has_awaits(expected_calls, any_order=True)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert result == {
|
assert result == {
|
||||||
"requestId": REQ_ID,
|
"requestId": REQ_ID,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
"""The tests for the Group Light platform."""
|
"""The tests for the Group Light platform."""
|
||||||
import unittest.mock
|
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
import async_timeout
|
import async_timeout
|
||||||
@ -16,7 +15,6 @@ from homeassistant.components.light import (
|
|||||||
ATTR_COLOR_TEMP_KELVIN,
|
ATTR_COLOR_TEMP_KELVIN,
|
||||||
ATTR_EFFECT,
|
ATTR_EFFECT,
|
||||||
ATTR_EFFECT_LIST,
|
ATTR_EFFECT_LIST,
|
||||||
ATTR_FLASH,
|
|
||||||
ATTR_HS_COLOR,
|
ATTR_HS_COLOR,
|
||||||
ATTR_MAX_COLOR_TEMP_KELVIN,
|
ATTR_MAX_COLOR_TEMP_KELVIN,
|
||||||
ATTR_MIN_COLOR_TEMP_KELVIN,
|
ATTR_MIN_COLOR_TEMP_KELVIN,
|
||||||
@ -26,7 +24,6 @@ from homeassistant.components.light import (
|
|||||||
ATTR_SUPPORTED_COLOR_MODES,
|
ATTR_SUPPORTED_COLOR_MODES,
|
||||||
ATTR_TRANSITION,
|
ATTR_TRANSITION,
|
||||||
ATTR_WHITE,
|
ATTR_WHITE,
|
||||||
ATTR_XY_COLOR,
|
|
||||||
DOMAIN as LIGHT_DOMAIN,
|
DOMAIN as LIGHT_DOMAIN,
|
||||||
SERVICE_TOGGLE,
|
SERVICE_TOGGLE,
|
||||||
SERVICE_TURN_OFF,
|
SERVICE_TURN_OFF,
|
||||||
@ -39,16 +36,17 @@ from homeassistant.components.light import (
|
|||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID,
|
ATTR_ENTITY_ID,
|
||||||
ATTR_SUPPORTED_FEATURES,
|
ATTR_SUPPORTED_FEATURES,
|
||||||
|
EVENT_CALL_SERVICE,
|
||||||
STATE_OFF,
|
STATE_OFF,
|
||||||
STATE_ON,
|
STATE_ON,
|
||||||
STATE_UNAVAILABLE,
|
STATE_UNAVAILABLE,
|
||||||
STATE_UNKNOWN,
|
STATE_UNKNOWN,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import Event, HomeAssistant
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
from tests.common import get_fixture_path
|
from tests.common import async_capture_events, get_fixture_path
|
||||||
|
|
||||||
|
|
||||||
async def test_default_state(hass: HomeAssistant) -> None:
|
async def test_default_state(hass: HomeAssistant) -> None:
|
||||||
@ -1443,6 +1441,7 @@ async def test_invalid_service_calls(hass: HomeAssistant) -> None:
|
|||||||
await group.async_setup_platform(
|
await group.async_setup_platform(
|
||||||
hass, {"name": "test", "entities": ["light.test1", "light.test2"]}, add_entities
|
hass, {"name": "test", "entities": ["light.test1", "light.test2"]}, add_entities
|
||||||
)
|
)
|
||||||
|
await async_setup_component(hass, "light", {})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
await hass.async_start()
|
await hass.async_start()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -1451,35 +1450,38 @@ async def test_invalid_service_calls(hass: HomeAssistant) -> None:
|
|||||||
grouped_light = add_entities.call_args[0][0][0]
|
grouped_light = add_entities.call_args[0][0][0]
|
||||||
grouped_light.hass = hass
|
grouped_light.hass = hass
|
||||||
|
|
||||||
with unittest.mock.patch.object(hass.services, "async_call") as mock_call:
|
service_call_events = async_capture_events(hass, EVENT_CALL_SERVICE)
|
||||||
await grouped_light.async_turn_on(brightness=150, four_oh_four="404")
|
|
||||||
data = {ATTR_ENTITY_ID: ["light.test1", "light.test2"], ATTR_BRIGHTNESS: 150}
|
|
||||||
mock_call.assert_called_once_with(
|
|
||||||
LIGHT_DOMAIN, SERVICE_TURN_ON, data, blocking=True, context=None
|
|
||||||
)
|
|
||||||
mock_call.reset_mock()
|
|
||||||
|
|
||||||
await grouped_light.async_turn_off(transition=4, four_oh_four="404")
|
await grouped_light.async_turn_on(brightness=150, four_oh_four="404")
|
||||||
data = {ATTR_ENTITY_ID: ["light.test1", "light.test2"], ATTR_TRANSITION: 4}
|
data = {ATTR_ENTITY_ID: ["light.test1", "light.test2"], ATTR_BRIGHTNESS: 150}
|
||||||
mock_call.assert_called_once_with(
|
assert len(service_call_events) == 1
|
||||||
LIGHT_DOMAIN, SERVICE_TURN_OFF, data, blocking=True, context=None
|
service_event_call: Event = service_call_events[0]
|
||||||
)
|
assert service_event_call.data["domain"] == LIGHT_DOMAIN
|
||||||
mock_call.reset_mock()
|
assert service_event_call.data["service"] == SERVICE_TURN_ON
|
||||||
|
assert service_event_call.data["service_data"] == data
|
||||||
|
service_call_events.clear()
|
||||||
|
|
||||||
data = {
|
await grouped_light.async_turn_off(transition=4, four_oh_four="404")
|
||||||
ATTR_BRIGHTNESS: 150,
|
data = {ATTR_ENTITY_ID: ["light.test1", "light.test2"], ATTR_TRANSITION: 4}
|
||||||
ATTR_XY_COLOR: (0.5, 0.42),
|
assert len(service_call_events) == 1
|
||||||
ATTR_RGB_COLOR: (80, 120, 50),
|
service_event_call: Event = service_call_events[0]
|
||||||
ATTR_COLOR_TEMP_KELVIN: 1234,
|
assert service_event_call.data["domain"] == LIGHT_DOMAIN
|
||||||
ATTR_EFFECT: "Sunshine",
|
assert service_event_call.data["service"] == SERVICE_TURN_OFF
|
||||||
ATTR_TRANSITION: 4,
|
assert service_event_call.data["service_data"] == data
|
||||||
ATTR_FLASH: "long",
|
service_call_events.clear()
|
||||||
}
|
|
||||||
await grouped_light.async_turn_on(**data)
|
data = {
|
||||||
data[ATTR_ENTITY_ID] = ["light.test1", "light.test2"]
|
ATTR_BRIGHTNESS: 150,
|
||||||
mock_call.assert_called_once_with(
|
ATTR_COLOR_TEMP_KELVIN: 1234,
|
||||||
LIGHT_DOMAIN, SERVICE_TURN_ON, data, blocking=True, context=None
|
ATTR_TRANSITION: 4,
|
||||||
)
|
}
|
||||||
|
await grouped_light.async_turn_on(**data)
|
||||||
|
data[ATTR_ENTITY_ID] = ["light.test1", "light.test2"]
|
||||||
|
service_event_call: Event = service_call_events[0]
|
||||||
|
assert service_event_call.data["domain"] == LIGHT_DOMAIN
|
||||||
|
assert service_event_call.data["service"] == SERVICE_TURN_ON
|
||||||
|
assert service_event_call.data["service_data"] == data
|
||||||
|
service_call_events.clear()
|
||||||
|
|
||||||
|
|
||||||
async def test_reload(hass: HomeAssistant) -> None:
|
async def test_reload(hass: HomeAssistant) -> None:
|
||||||
|
@ -33,15 +33,12 @@ async def test_async_setup_entry__not_login(
|
|||||||
hass.config_entries, "async_forward_entry_setup"
|
hass.config_entries, "async_forward_entry_setup"
|
||||||
) as setup_mock, patch(
|
) as setup_mock, patch(
|
||||||
"homeassistant.components.vesync.async_process_devices"
|
"homeassistant.components.vesync.async_process_devices"
|
||||||
) as process_mock, patch.object(
|
) as process_mock:
|
||||||
hass.services, "async_register"
|
|
||||||
) as register_mock:
|
|
||||||
assert not await async_setup_entry(hass, config_entry)
|
assert not await async_setup_entry(hass, config_entry)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert setups_mock.call_count == 0
|
assert setups_mock.call_count == 0
|
||||||
assert setup_mock.call_count == 0
|
assert setup_mock.call_count == 0
|
||||||
assert process_mock.call_count == 0
|
assert process_mock.call_count == 0
|
||||||
assert register_mock.call_count == 0
|
|
||||||
|
|
||||||
assert manager.login.call_count == 1
|
assert manager.login.call_count == 1
|
||||||
assert DOMAIN not in hass.data
|
assert DOMAIN not in hass.data
|
||||||
|
@ -332,8 +332,8 @@ def zha_device_mock(
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def hass_disable_services(hass):
|
def hass_disable_services(hass):
|
||||||
"""Mock service register."""
|
"""Mock services."""
|
||||||
with patch.object(hass.services, "async_register"), patch.object(
|
with patch.object(
|
||||||
hass.services, "has_service", return_value=True
|
hass, "services", MagicMock(has_service=MagicMock(return_value=True))
|
||||||
):
|
):
|
||||||
yield hass
|
yield hass
|
||||||
|
Loading…
Reference in New Issue
Block a user