mirror of
https://github.com/home-assistant/core.git
synced 2025-12-24 12:59:34 +00:00
Add foundation for integration services (#30813)
* Add foundation for integration services * Fix tests * Remove async_get_platform * Migrate Sonos partially to EntityPlatform.async_register_entity_service * Tweaks * Move other Sonos services to media player domain * Move other Sonos services to media player domain * Address comments * Remove lock * Fix typos * Use make_entity_service_schema * Add area extraction to async_extract_entities Co-authored-by: Anders Melchiorsen <amelchio@nogoto.net>
This commit is contained in:
@@ -23,6 +23,7 @@ import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.common import (
|
||||
MockEntity,
|
||||
get_test_home_assistant,
|
||||
mock_coro,
|
||||
mock_device_registry,
|
||||
@@ -64,6 +65,54 @@ def mock_entities():
|
||||
return entities
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def area_mock(hass):
|
||||
"""Mock including area info."""
|
||||
hass.states.async_set("light.Bowl", STATE_ON)
|
||||
hass.states.async_set("light.Ceiling", STATE_OFF)
|
||||
hass.states.async_set("light.Kitchen", STATE_OFF)
|
||||
|
||||
device_in_area = dev_reg.DeviceEntry(area_id="test-area")
|
||||
device_no_area = dev_reg.DeviceEntry()
|
||||
device_diff_area = dev_reg.DeviceEntry(area_id="diff-area")
|
||||
|
||||
mock_device_registry(
|
||||
hass,
|
||||
{
|
||||
device_in_area.id: device_in_area,
|
||||
device_no_area.id: device_no_area,
|
||||
device_diff_area.id: device_diff_area,
|
||||
},
|
||||
)
|
||||
|
||||
entity_in_area = ent_reg.RegistryEntry(
|
||||
entity_id="light.in_area",
|
||||
unique_id="in-area-id",
|
||||
platform="test",
|
||||
device_id=device_in_area.id,
|
||||
)
|
||||
entity_no_area = ent_reg.RegistryEntry(
|
||||
entity_id="light.no_area",
|
||||
unique_id="no-area-id",
|
||||
platform="test",
|
||||
device_id=device_no_area.id,
|
||||
)
|
||||
entity_diff_area = ent_reg.RegistryEntry(
|
||||
entity_id="light.diff_area",
|
||||
unique_id="diff-area-id",
|
||||
platform="test",
|
||||
device_id=device_diff_area.id,
|
||||
)
|
||||
mock_registry(
|
||||
hass,
|
||||
{
|
||||
entity_in_area.entity_id: entity_in_area,
|
||||
entity_no_area.entity_id: entity_no_area,
|
||||
entity_diff_area.entity_id: entity_diff_area,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class TestServiceHelpers(unittest.TestCase):
|
||||
"""Test the Home Assistant service helpers."""
|
||||
|
||||
@@ -204,52 +253,8 @@ async def test_extract_entity_ids(hass):
|
||||
)
|
||||
|
||||
|
||||
async def test_extract_entity_ids_from_area(hass):
|
||||
async def test_extract_entity_ids_from_area(hass, area_mock):
|
||||
"""Test extract_entity_ids method with areas."""
|
||||
hass.states.async_set("light.Bowl", STATE_ON)
|
||||
hass.states.async_set("light.Ceiling", STATE_OFF)
|
||||
hass.states.async_set("light.Kitchen", STATE_OFF)
|
||||
|
||||
device_in_area = dev_reg.DeviceEntry(area_id="test-area")
|
||||
device_no_area = dev_reg.DeviceEntry()
|
||||
device_diff_area = dev_reg.DeviceEntry(area_id="diff-area")
|
||||
|
||||
mock_device_registry(
|
||||
hass,
|
||||
{
|
||||
device_in_area.id: device_in_area,
|
||||
device_no_area.id: device_no_area,
|
||||
device_diff_area.id: device_diff_area,
|
||||
},
|
||||
)
|
||||
|
||||
entity_in_area = ent_reg.RegistryEntry(
|
||||
entity_id="light.in_area",
|
||||
unique_id="in-area-id",
|
||||
platform="test",
|
||||
device_id=device_in_area.id,
|
||||
)
|
||||
entity_no_area = ent_reg.RegistryEntry(
|
||||
entity_id="light.no_area",
|
||||
unique_id="no-area-id",
|
||||
platform="test",
|
||||
device_id=device_no_area.id,
|
||||
)
|
||||
entity_diff_area = ent_reg.RegistryEntry(
|
||||
entity_id="light.diff_area",
|
||||
unique_id="diff-area-id",
|
||||
platform="test",
|
||||
device_id=device_diff_area.id,
|
||||
)
|
||||
mock_registry(
|
||||
hass,
|
||||
{
|
||||
entity_in_area.entity_id: entity_in_area,
|
||||
entity_no_area.entity_id: entity_no_area,
|
||||
entity_diff_area.entity_id: entity_diff_area,
|
||||
},
|
||||
)
|
||||
|
||||
call = ha.ServiceCall("light", "turn_on", {"area_id": "test-area"})
|
||||
|
||||
assert {"light.in_area"} == await service.async_extract_entity_ids(hass, call)
|
||||
@@ -678,3 +683,86 @@ async def test_domain_control_no_user(hass, mock_entities):
|
||||
)
|
||||
|
||||
assert len(calls) == 1
|
||||
|
||||
|
||||
async def test_extract_from_service_available_device(hass):
|
||||
"""Test the extraction of entity from service and device is available."""
|
||||
entities = [
|
||||
MockEntity(name="test_1", entity_id="test_domain.test_1"),
|
||||
MockEntity(name="test_2", entity_id="test_domain.test_2", available=False),
|
||||
MockEntity(name="test_3", entity_id="test_domain.test_3"),
|
||||
MockEntity(name="test_4", entity_id="test_domain.test_4", available=False),
|
||||
]
|
||||
|
||||
call_1 = ha.ServiceCall("test", "service", data={"entity_id": ENTITY_MATCH_ALL})
|
||||
|
||||
assert ["test_domain.test_1", "test_domain.test_3"] == [
|
||||
ent.entity_id
|
||||
for ent in (await service.async_extract_entities(hass, entities, call_1))
|
||||
]
|
||||
|
||||
call_2 = ha.ServiceCall(
|
||||
"test",
|
||||
"service",
|
||||
data={"entity_id": ["test_domain.test_3", "test_domain.test_4"]},
|
||||
)
|
||||
|
||||
assert ["test_domain.test_3"] == [
|
||||
ent.entity_id
|
||||
for ent in (await service.async_extract_entities(hass, entities, call_2))
|
||||
]
|
||||
|
||||
|
||||
async def test_extract_from_service_empty_if_no_entity_id(hass):
|
||||
"""Test the extraction from service without specifying entity."""
|
||||
entities = [
|
||||
MockEntity(name="test_1", entity_id="test_domain.test_1"),
|
||||
MockEntity(name="test_2", entity_id="test_domain.test_2"),
|
||||
]
|
||||
call = ha.ServiceCall("test", "service")
|
||||
|
||||
assert [] == [
|
||||
ent.entity_id
|
||||
for ent in (await service.async_extract_entities(hass, entities, call))
|
||||
]
|
||||
|
||||
|
||||
async def test_extract_from_service_filter_out_non_existing_entities(hass):
|
||||
"""Test the extraction of non existing entities from service."""
|
||||
entities = [
|
||||
MockEntity(name="test_1", entity_id="test_domain.test_1"),
|
||||
MockEntity(name="test_2", entity_id="test_domain.test_2"),
|
||||
]
|
||||
|
||||
call = ha.ServiceCall(
|
||||
"test",
|
||||
"service",
|
||||
{"entity_id": ["test_domain.test_2", "test_domain.non_exist"]},
|
||||
)
|
||||
|
||||
assert ["test_domain.test_2"] == [
|
||||
ent.entity_id
|
||||
for ent in (await service.async_extract_entities(hass, entities, call))
|
||||
]
|
||||
|
||||
|
||||
async def test_extract_from_service_area_id(hass, area_mock):
|
||||
"""Test the extraction using area ID as reference."""
|
||||
entities = [
|
||||
MockEntity(name="in_area", entity_id="light.in_area"),
|
||||
MockEntity(name="no_area", entity_id="light.no_area"),
|
||||
MockEntity(name="diff_area", entity_id="light.diff_area"),
|
||||
]
|
||||
|
||||
call = ha.ServiceCall("light", "turn_on", {"area_id": "test-area"})
|
||||
extracted = await service.async_extract_entities(hass, entities, call)
|
||||
assert len(extracted) == 1
|
||||
assert extracted[0].entity_id == "light.in_area"
|
||||
|
||||
call = ha.ServiceCall("light", "turn_on", {"area_id": ["test-area", "diff-area"]})
|
||||
extracted = await service.async_extract_entities(hass, entities, call)
|
||||
assert len(extracted) == 2
|
||||
assert sorted(ent.entity_id for ent in extracted) == [
|
||||
"light.diff_area",
|
||||
"light.in_area",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user