1
mirror of https://github.com/home-assistant/core synced 2024-07-09 04:58:30 +02:00

Add slots to the service registry (#95857)

This commit is contained in:
J. Nick Koston 2023-07-05 08:59:36 -05:00 committed by GitHub
parent bd7057f7b1
commit ea57f78392
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 77 additions and 156 deletions

View File

@ -1726,6 +1726,8 @@ class ServiceCall:
class ServiceRegistry:
"""Offer the services over the eventbus."""
__slots__ = ("_services", "_hass")
def __init__(self, hass: HomeAssistant) -> None:
"""Initialize a service registry."""
self._services: dict[str, dict[str, Service]] = {}

View File

@ -1,7 +1,7 @@
"""Test Google Smart Home."""
import asyncio
from types import SimpleNamespace
from unittest.mock import ANY, call, patch
from unittest.mock import ANY, patch
import pytest
from pytest_unordered import unordered
@ -488,76 +488,41 @@ async def test_execute(
events = async_capture_events(hass, EVENT_COMMAND_RECEIVED)
service_events = async_capture_events(hass, EVENT_CALL_SERVICE)
with patch.object(
hass.services, "async_call", wraps=hass.services.async_call
) as call_service_mock:
result = await sh.async_handle_message(
hass,
MockConfig(should_report_state=report_state),
None,
{
"requestId": REQ_ID,
"inputs": [
{
"intent": "action.devices.EXECUTE",
"payload": {
"commands": [
{
"devices": [
{"id": "light.non_existing"},
{"id": "light.ceiling_lights"},
{"id": "light.kitchen_lights"},
],
"execution": [
{
"command": "action.devices.commands.OnOff",
"params": {"on": True},
},
{
"command": "action.devices.commands.BrightnessAbsolute",
"params": {"brightness": 20},
},
],
}
]
},
}
],
},
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)
result = await sh.async_handle_message(
hass,
MockConfig(should_report_state=report_state),
None,
{
"requestId": REQ_ID,
"inputs": [
{
"intent": "action.devices.EXECUTE",
"payload": {
"commands": [
{
"devices": [
{"id": "light.non_existing"},
{"id": "light.ceiling_lights"},
{"id": "light.kitchen_lights"},
],
"execution": [
{
"command": "action.devices.commands.OnOff",
"params": {"on": True},
},
{
"command": "action.devices.commands.BrightnessAbsolute",
"params": {"brightness": 20},
},
],
}
]
},
}
],
},
const.SOURCE_CLOUD,
)
await hass.async_block_till_done()
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
await turn_on_wait.wait()
with patch.object(
hass.services, "async_call", wraps=hass.services.async_call
) as call_service_mock, patch.object(
DemoLight, "async_turn_on", wraps=slow_turn_on
):
with patch.object(DemoLight, "async_turn_on", wraps=slow_turn_on):
result = await sh.async_handle_message(
hass,
MockConfig(should_report_state=report_state),
@ -722,51 +683,10 @@ async def test_execute_times_out(
},
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()
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 == {
"requestId": REQ_ID,

View File

@ -1,5 +1,4 @@
"""The tests for the Group Light platform."""
import unittest.mock
from unittest.mock import MagicMock, patch
import async_timeout
@ -16,7 +15,6 @@ from homeassistant.components.light import (
ATTR_COLOR_TEMP_KELVIN,
ATTR_EFFECT,
ATTR_EFFECT_LIST,
ATTR_FLASH,
ATTR_HS_COLOR,
ATTR_MAX_COLOR_TEMP_KELVIN,
ATTR_MIN_COLOR_TEMP_KELVIN,
@ -26,7 +24,6 @@ from homeassistant.components.light import (
ATTR_SUPPORTED_COLOR_MODES,
ATTR_TRANSITION,
ATTR_WHITE,
ATTR_XY_COLOR,
DOMAIN as LIGHT_DOMAIN,
SERVICE_TOGGLE,
SERVICE_TURN_OFF,
@ -39,16 +36,17 @@ from homeassistant.components.light import (
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_SUPPORTED_FEATURES,
EVENT_CALL_SERVICE,
STATE_OFF,
STATE_ON,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
)
from homeassistant.core import HomeAssistant
from homeassistant.core import Event, HomeAssistant
from homeassistant.helpers import entity_registry as er
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:
@ -1443,6 +1441,7 @@ async def test_invalid_service_calls(hass: HomeAssistant) -> None:
await group.async_setup_platform(
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_start()
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.hass = hass
with unittest.mock.patch.object(hass.services, "async_call") as mock_call:
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()
service_call_events = async_capture_events(hass, EVENT_CALL_SERVICE)
await grouped_light.async_turn_off(transition=4, four_oh_four="404")
data = {ATTR_ENTITY_ID: ["light.test1", "light.test2"], ATTR_TRANSITION: 4}
mock_call.assert_called_once_with(
LIGHT_DOMAIN, SERVICE_TURN_OFF, data, blocking=True, context=None
)
mock_call.reset_mock()
await grouped_light.async_turn_on(brightness=150, four_oh_four="404")
data = {ATTR_ENTITY_ID: ["light.test1", "light.test2"], ATTR_BRIGHTNESS: 150}
assert len(service_call_events) == 1
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()
data = {
ATTR_BRIGHTNESS: 150,
ATTR_XY_COLOR: (0.5, 0.42),
ATTR_RGB_COLOR: (80, 120, 50),
ATTR_COLOR_TEMP_KELVIN: 1234,
ATTR_EFFECT: "Sunshine",
ATTR_TRANSITION: 4,
ATTR_FLASH: "long",
}
await grouped_light.async_turn_on(**data)
data[ATTR_ENTITY_ID] = ["light.test1", "light.test2"]
mock_call.assert_called_once_with(
LIGHT_DOMAIN, SERVICE_TURN_ON, data, blocking=True, context=None
)
await grouped_light.async_turn_off(transition=4, four_oh_four="404")
data = {ATTR_ENTITY_ID: ["light.test1", "light.test2"], ATTR_TRANSITION: 4}
assert len(service_call_events) == 1
service_event_call: Event = service_call_events[0]
assert service_event_call.data["domain"] == LIGHT_DOMAIN
assert service_event_call.data["service"] == SERVICE_TURN_OFF
assert service_event_call.data["service_data"] == data
service_call_events.clear()
data = {
ATTR_BRIGHTNESS: 150,
ATTR_COLOR_TEMP_KELVIN: 1234,
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:

View File

@ -33,15 +33,12 @@ async def test_async_setup_entry__not_login(
hass.config_entries, "async_forward_entry_setup"
) as setup_mock, patch(
"homeassistant.components.vesync.async_process_devices"
) as process_mock, patch.object(
hass.services, "async_register"
) as register_mock:
) as process_mock:
assert not await async_setup_entry(hass, config_entry)
await hass.async_block_till_done()
assert setups_mock.call_count == 0
assert setup_mock.call_count == 0
assert process_mock.call_count == 0
assert register_mock.call_count == 0
assert manager.login.call_count == 1
assert DOMAIN not in hass.data

View File

@ -332,8 +332,8 @@ def zha_device_mock(
@pytest.fixture
def hass_disable_services(hass):
"""Mock service register."""
with patch.object(hass.services, "async_register"), patch.object(
hass.services, "has_service", return_value=True
"""Mock services."""
with patch.object(
hass, "services", MagicMock(has_service=MagicMock(return_value=True))
):
yield hass