Simplify access to hass in service calls (#133062)

This commit is contained in:
epenet 2024-12-13 09:31:21 +01:00 committed by GitHub
parent f9f37b9932
commit 899fb091fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 204 additions and 94 deletions

View File

@ -2432,10 +2432,11 @@ class Service:
class ServiceCall:
"""Representation of a call to a service."""
__slots__ = ("domain", "service", "data", "context", "return_response")
__slots__ = ("hass", "domain", "service", "data", "context", "return_response")
def __init__(
self,
hass: HomeAssistant,
domain: str,
service: str,
data: dict[str, Any] | None = None,
@ -2443,6 +2444,7 @@ class ServiceCall:
return_response: bool = False,
) -> None:
"""Initialize a service call."""
self.hass = hass
self.domain = domain
self.service = service
self.data = ReadOnlyDict(data or {})
@ -2768,7 +2770,7 @@ class ServiceRegistry:
processed_data = service_data
service_call = ServiceCall(
domain, service, processed_data, context, return_response
self._hass, domain, service, processed_data, context, return_response
)
self._hass.bus.async_fire_internal(

View File

@ -184,6 +184,7 @@ async def test_turn_on_skips_domains_without_service(
# because by mocking out the call service method, we mock out all
# So we mimic how the service registry calls services
service_call = ha.ServiceCall(
hass,
"homeassistant",
"turn_on",
{"entity_id": ["light.test", "sensor.bla", "binary_sensor.blub", "light.bla"]},

View File

@ -64,21 +64,22 @@ async def test_text_set_value(hass: HomeAssistant) -> None:
with pytest.raises(ValueError):
await _async_set_value(
text, ServiceCall(DOMAIN, SERVICE_SET_VALUE, {ATTR_VALUE: ""})
text, ServiceCall(hass, DOMAIN, SERVICE_SET_VALUE, {ATTR_VALUE: ""})
)
with pytest.raises(ValueError):
await _async_set_value(
text, ServiceCall(DOMAIN, SERVICE_SET_VALUE, {ATTR_VALUE: "hello world!"})
text,
ServiceCall(hass, DOMAIN, SERVICE_SET_VALUE, {ATTR_VALUE: "hello world!"}),
)
with pytest.raises(ValueError):
await _async_set_value(
text, ServiceCall(DOMAIN, SERVICE_SET_VALUE, {ATTR_VALUE: "HELLO"})
text, ServiceCall(hass, DOMAIN, SERVICE_SET_VALUE, {ATTR_VALUE: "HELLO"})
)
await _async_set_value(
text, ServiceCall(DOMAIN, SERVICE_SET_VALUE, {ATTR_VALUE: "test2"})
text, ServiceCall(hass, DOMAIN, SERVICE_SET_VALUE, {ATTR_VALUE: "test2"})
)
assert text.state == "test2"

View File

@ -1899,7 +1899,7 @@ def service_calls(hass: HomeAssistant) -> Generator[list[ServiceCall]]:
return_response: bool = False,
) -> ServiceResponse:
calls.append(
ServiceCall(domain, service, service_data, context, return_response)
ServiceCall(hass, domain, service, service_data, context, return_response)
)
try:
return await _original_async_call(

View File

@ -189,13 +189,14 @@ async def test_extract_from_service_available_device(hass: HomeAssistant) -> Non
]
)
call_1 = ServiceCall("test", "service", data={"entity_id": ENTITY_MATCH_ALL})
call_1 = ServiceCall(hass, "test", "service", data={"entity_id": ENTITY_MATCH_ALL})
assert sorted(
ent.entity_id for ent in (await component.async_extract_from_service(call_1))
) == ["test_domain.test_1", "test_domain.test_3"]
call_2 = ServiceCall(
hass,
"test",
"service",
data={"entity_id": ["test_domain.test_3", "test_domain.test_4"]},
@ -256,17 +257,18 @@ async def test_extract_from_service_fails_if_no_entity_id(hass: HomeAssistant) -
)
assert (
await component.async_extract_from_service(ServiceCall("test", "service")) == []
await component.async_extract_from_service(ServiceCall(hass, "test", "service"))
== []
)
assert (
await component.async_extract_from_service(
ServiceCall("test", "service", {"entity_id": ENTITY_MATCH_NONE})
ServiceCall(hass, "test", "service", {"entity_id": ENTITY_MATCH_NONE})
)
== []
)
assert (
await component.async_extract_from_service(
ServiceCall("test", "service", {"area_id": ENTITY_MATCH_NONE})
ServiceCall(hass, "test", "service", {"area_id": ENTITY_MATCH_NONE})
)
== []
)
@ -283,6 +285,7 @@ async def test_extract_from_service_filter_out_non_existing_entities(
)
call = ServiceCall(
hass,
"test",
"service",
{"entity_id": ["test_domain.test_2", "test_domain.non_exist"]},
@ -299,7 +302,7 @@ async def test_extract_from_service_no_group_expand(hass: HomeAssistant) -> None
await component.async_setup({})
await component.async_add_entities([MockEntity(entity_id="group.test_group")])
call = ServiceCall("test", "service", {"entity_id": ["group.test_group"]})
call = ServiceCall(hass, "test", "service", {"entity_id": ["group.test_group"]})
extracted = await component.async_extract_from_service(call, expand_group=False)
assert len(extracted) == 1
@ -465,7 +468,7 @@ async def test_extract_all_omit_entity_id(
[MockEntity(name="test_1"), MockEntity(name="test_2")]
)
call = ServiceCall("test", "service")
call = ServiceCall(hass, "test", "service")
assert (
sorted(
@ -485,7 +488,7 @@ async def test_extract_all_use_match_all(
[MockEntity(name="test_1"), MockEntity(name="test_2")]
)
call = ServiceCall("test", "service", {"entity_id": "all"})
call = ServiceCall(hass, "test", "service", {"entity_id": "all"})
assert sorted(
ent.entity_id for ent in await component.async_extract_from_service(call)

View File

@ -642,11 +642,11 @@ async def test_extract_entity_ids(hass: HomeAssistant) -> None:
order=None,
)
call = ServiceCall("light", "turn_on", {ATTR_ENTITY_ID: "light.Bowl"})
call = ServiceCall(hass, "light", "turn_on", {ATTR_ENTITY_ID: "light.Bowl"})
assert {"light.bowl"} == await service.async_extract_entity_ids(hass, call)
call = ServiceCall("light", "turn_on", {ATTR_ENTITY_ID: "group.test"})
call = ServiceCall(hass, "light", "turn_on", {ATTR_ENTITY_ID: "group.test"})
assert {"light.ceiling", "light.kitchen"} == await service.async_extract_entity_ids(
hass, call
@ -659,7 +659,7 @@ async def test_extract_entity_ids(hass: HomeAssistant) -> None:
assert (
await service.async_extract_entity_ids(
hass,
ServiceCall("light", "turn_on", {ATTR_ENTITY_ID: ENTITY_MATCH_NONE}),
ServiceCall(hass, "light", "turn_on", {ATTR_ENTITY_ID: ENTITY_MATCH_NONE}),
)
== set()
)
@ -669,20 +669,22 @@ async def test_extract_entity_ids_from_area(
hass: HomeAssistant, floor_area_mock
) -> None:
"""Test extract_entity_ids method with areas."""
call = ServiceCall("light", "turn_on", {"area_id": "own-area"})
call = ServiceCall(hass, "light", "turn_on", {"area_id": "own-area"})
assert {
"light.in_own_area",
} == await service.async_extract_entity_ids(hass, call)
call = ServiceCall("light", "turn_on", {"area_id": "test-area"})
call = ServiceCall(hass, "light", "turn_on", {"area_id": "test-area"})
assert {
"light.in_area",
"light.assigned_to_area",
} == await service.async_extract_entity_ids(hass, call)
call = ServiceCall("light", "turn_on", {"area_id": ["test-area", "diff-area"]})
call = ServiceCall(
hass, "light", "turn_on", {"area_id": ["test-area", "diff-area"]}
)
assert {
"light.in_area",
@ -692,7 +694,7 @@ async def test_extract_entity_ids_from_area(
assert (
await service.async_extract_entity_ids(
hass, ServiceCall("light", "turn_on", {"area_id": ENTITY_MATCH_NONE})
hass, ServiceCall(hass, "light", "turn_on", {"area_id": ENTITY_MATCH_NONE})
)
== set()
)
@ -703,13 +705,13 @@ async def test_extract_entity_ids_from_devices(
) -> None:
"""Test extract_entity_ids method with devices."""
assert await service.async_extract_entity_ids(
hass, ServiceCall("light", "turn_on", {"device_id": "device-no-area-id"})
hass, ServiceCall(hass, "light", "turn_on", {"device_id": "device-no-area-id"})
) == {
"light.no_area",
}
assert await service.async_extract_entity_ids(
hass, ServiceCall("light", "turn_on", {"device_id": "device-area-a-id"})
hass, ServiceCall(hass, "light", "turn_on", {"device_id": "device-area-a-id"})
) == {
"light.in_area_a",
"light.in_area_b",
@ -717,7 +719,8 @@ async def test_extract_entity_ids_from_devices(
assert (
await service.async_extract_entity_ids(
hass, ServiceCall("light", "turn_on", {"device_id": "non-existing-id"})
hass,
ServiceCall(hass, "light", "turn_on", {"device_id": "non-existing-id"}),
)
== set()
)
@ -726,14 +729,16 @@ async def test_extract_entity_ids_from_devices(
@pytest.mark.usefixtures("floor_area_mock")
async def test_extract_entity_ids_from_floor(hass: HomeAssistant) -> None:
"""Test extract_entity_ids method with floors."""
call = ServiceCall("light", "turn_on", {"floor_id": "test-floor"})
call = ServiceCall(hass, "light", "turn_on", {"floor_id": "test-floor"})
assert {
"light.in_area",
"light.assigned_to_area",
} == await service.async_extract_entity_ids(hass, call)
call = ServiceCall("light", "turn_on", {"floor_id": ["test-floor", "floor-a"]})
call = ServiceCall(
hass, "light", "turn_on", {"floor_id": ["test-floor", "floor-a"]}
)
assert {
"light.in_area",
@ -743,7 +748,7 @@ async def test_extract_entity_ids_from_floor(hass: HomeAssistant) -> None:
assert (
await service.async_extract_entity_ids(
hass, ServiceCall("light", "turn_on", {"floor_id": ENTITY_MATCH_NONE})
hass, ServiceCall(hass, "light", "turn_on", {"floor_id": ENTITY_MATCH_NONE})
)
== set()
)
@ -752,13 +757,13 @@ async def test_extract_entity_ids_from_floor(hass: HomeAssistant) -> None:
@pytest.mark.usefixtures("label_mock")
async def test_extract_entity_ids_from_labels(hass: HomeAssistant) -> None:
"""Test extract_entity_ids method with labels."""
call = ServiceCall("light", "turn_on", {"label_id": "my-label"})
call = ServiceCall(hass, "light", "turn_on", {"label_id": "my-label"})
assert {
"light.with_my_label",
} == await service.async_extract_entity_ids(hass, call)
call = ServiceCall("light", "turn_on", {"label_id": "label1"})
call = ServiceCall(hass, "light", "turn_on", {"label_id": "label1"})
assert {
"light.with_label1_from_device",
@ -767,14 +772,14 @@ async def test_extract_entity_ids_from_labels(hass: HomeAssistant) -> None:
"light.with_label1_and_label2_from_device",
} == await service.async_extract_entity_ids(hass, call)
call = ServiceCall("light", "turn_on", {"label_id": ["label2"]})
call = ServiceCall(hass, "light", "turn_on", {"label_id": ["label2"]})
assert {
"light.with_labels_from_device",
"light.with_label1_and_label2_from_device",
} == await service.async_extract_entity_ids(hass, call)
call = ServiceCall("light", "turn_on", {"label_id": ["label_area"]})
call = ServiceCall(hass, "light", "turn_on", {"label_id": ["label_area"]})
assert {
"light.with_labels_from_device",
@ -782,7 +787,7 @@ async def test_extract_entity_ids_from_labels(hass: HomeAssistant) -> None:
assert (
await service.async_extract_entity_ids(
hass, ServiceCall("light", "turn_on", {"label_id": ENTITY_MATCH_NONE})
hass, ServiceCall(hass, "light", "turn_on", {"label_id": ENTITY_MATCH_NONE})
)
== set()
)
@ -1281,7 +1286,7 @@ async def test_call_with_required_features(hass: HomeAssistant, mock_entities) -
hass,
mock_entities,
HassJob(test_service_mock),
ServiceCall("test_domain", "test_service", {"entity_id": "all"}),
ServiceCall(hass, "test_domain", "test_service", {"entity_id": "all"}),
required_features=[SUPPORT_A],
)
@ -1305,7 +1310,7 @@ async def test_call_with_required_features(hass: HomeAssistant, mock_entities) -
mock_entities,
HassJob(test_service_mock),
ServiceCall(
"test_domain", "test_service", {"entity_id": "light.living_room"}
hass, "test_domain", "test_service", {"entity_id": "light.living_room"}
),
required_features=[SUPPORT_A],
)
@ -1321,7 +1326,7 @@ async def test_call_with_both_required_features(
hass,
mock_entities,
HassJob(test_service_mock),
ServiceCall("test_domain", "test_service", {"entity_id": "all"}),
ServiceCall(hass, "test_domain", "test_service", {"entity_id": "all"}),
required_features=[SUPPORT_A | SUPPORT_B],
)
@ -1340,7 +1345,7 @@ async def test_call_with_one_of_required_features(
hass,
mock_entities,
HassJob(test_service_mock),
ServiceCall("test_domain", "test_service", {"entity_id": "all"}),
ServiceCall(hass, "test_domain", "test_service", {"entity_id": "all"}),
required_features=[SUPPORT_A, SUPPORT_C],
)
@ -1361,7 +1366,9 @@ async def test_call_with_sync_func(hass: HomeAssistant, mock_entities) -> None:
hass,
mock_entities,
HassJob(test_service_mock),
ServiceCall("test_domain", "test_service", {"entity_id": "light.kitchen"}),
ServiceCall(
hass, "test_domain", "test_service", {"entity_id": "light.kitchen"}
),
)
assert test_service_mock.call_count == 1
@ -1374,6 +1381,7 @@ async def test_call_with_sync_attr(hass: HomeAssistant, mock_entities) -> None:
mock_entities,
"sync_method",
ServiceCall(
hass,
"test_domain",
"test_service",
{"entity_id": "light.kitchen", "area_id": "abcd"},
@ -1392,6 +1400,7 @@ async def test_call_context_user_not_exist(hass: HomeAssistant) -> None:
{},
Mock(),
ServiceCall(
hass,
"test_domain",
"test_service",
context=Context(user_id="non-existing"),
@ -1419,6 +1428,7 @@ async def test_call_context_target_all(
mock_entities,
Mock(),
ServiceCall(
hass,
"test_domain",
"test_service",
data={"entity_id": ENTITY_MATCH_ALL},
@ -1447,6 +1457,7 @@ async def test_call_context_target_specific(
mock_entities,
Mock(),
ServiceCall(
hass,
"test_domain",
"test_service",
{"entity_id": "light.kitchen"},
@ -1474,6 +1485,7 @@ async def test_call_context_target_specific_no_auth(
mock_entities,
Mock(),
ServiceCall(
hass,
"test_domain",
"test_service",
{"entity_id": "light.kitchen"},
@ -1494,7 +1506,7 @@ async def test_call_no_context_target_all(
mock_entities,
Mock(),
ServiceCall(
"test_domain", "test_service", data={"entity_id": ENTITY_MATCH_ALL}
hass, "test_domain", "test_service", data={"entity_id": ENTITY_MATCH_ALL}
),
)
@ -1513,6 +1525,7 @@ async def test_call_no_context_target_specific(
mock_entities,
Mock(),
ServiceCall(
hass,
"test_domain",
"test_service",
{"entity_id": ["light.kitchen", "light.non-existing"]},
@ -1534,7 +1547,7 @@ async def test_call_with_match_all(
hass,
mock_entities,
Mock(),
ServiceCall("test_domain", "test_service", {"entity_id": "all"}),
ServiceCall(hass, "test_domain", "test_service", {"entity_id": "all"}),
)
assert len(mock_handle_entity_call.mock_calls) == 4
@ -1551,7 +1564,7 @@ async def test_call_with_omit_entity_id(
hass,
mock_entities,
Mock(),
ServiceCall("test_domain", "test_service"),
ServiceCall(hass, "test_domain", "test_service"),
)
assert len(mock_handle_entity_call.mock_calls) == 0
@ -1797,7 +1810,7 @@ async def test_extract_from_service_available_device(hass: HomeAssistant) -> Non
MockEntity(name="test_4", entity_id="test_domain.test_4", available=False),
]
call_1 = ServiceCall("test", "service", data={"entity_id": ENTITY_MATCH_ALL})
call_1 = ServiceCall(hass, "test", "service", data={"entity_id": ENTITY_MATCH_ALL})
assert [
ent.entity_id
@ -1805,6 +1818,7 @@ async def test_extract_from_service_available_device(hass: HomeAssistant) -> Non
] == ["test_domain.test_1", "test_domain.test_3"]
call_2 = ServiceCall(
hass,
"test",
"service",
data={"entity_id": ["test_domain.test_3", "test_domain.test_4"]},
@ -1820,6 +1834,7 @@ async def test_extract_from_service_available_device(hass: HomeAssistant) -> Non
hass,
entities,
ServiceCall(
hass,
"test",
"service",
data={"entity_id": ENTITY_MATCH_NONE},
@ -1835,7 +1850,7 @@ async def test_extract_from_service_empty_if_no_entity_id(hass: HomeAssistant) -
MockEntity(name="test_1", entity_id="test_domain.test_1"),
MockEntity(name="test_2", entity_id="test_domain.test_2"),
]
call = ServiceCall("test", "service")
call = ServiceCall(hass, "test", "service")
assert [
ent.entity_id
@ -1853,6 +1868,7 @@ async def test_extract_from_service_filter_out_non_existing_entities(
]
call = ServiceCall(
hass,
"test",
"service",
{"entity_id": ["test_domain.test_2", "test_domain.non_exist"]},
@ -1874,12 +1890,14 @@ async def test_extract_from_service_area_id(
MockEntity(name="diff_area", entity_id="light.diff_area"),
]
call = ServiceCall("light", "turn_on", {"area_id": "test-area"})
call = ServiceCall(hass, "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 = ServiceCall("light", "turn_on", {"area_id": ["test-area", "diff-area"]})
call = ServiceCall(
hass, "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) == [
@ -1888,6 +1906,7 @@ async def test_extract_from_service_area_id(
]
call = ServiceCall(
hass,
"light",
"turn_on",
{"area_id": ["test-area", "diff-area"], "device_id": "device-no-area-id"},
@ -1912,17 +1931,17 @@ async def test_extract_from_service_label_id(hass: HomeAssistant) -> None:
),
]
call = ServiceCall("light", "turn_on", {"label_id": "label_area"})
call = ServiceCall(hass, "light", "turn_on", {"label_id": "label_area"})
extracted = await service.async_extract_entities(hass, entities, call)
assert len(extracted) == 1
assert extracted[0].entity_id == "light.with_labels_from_device"
call = ServiceCall("light", "turn_on", {"label_id": "my-label"})
call = ServiceCall(hass, "light", "turn_on", {"label_id": "my-label"})
extracted = await service.async_extract_entities(hass, entities, call)
assert len(extracted) == 1
assert extracted[0].entity_id == "light.with_my_label"
call = ServiceCall("light", "turn_on", {"label_id": ["my-label", "label1"]})
call = ServiceCall(hass, "light", "turn_on", {"label_id": ["my-label", "label1"]})
extracted = await service.async_extract_entities(hass, entities, call)
assert len(extracted) == 2
assert sorted(ent.entity_id for ent in extracted) == [
@ -1931,6 +1950,7 @@ async def test_extract_from_service_label_id(hass: HomeAssistant) -> None:
]
call = ServiceCall(
hass,
"light",
"turn_on",
{"label_id": ["my-label", "label1"], "device_id": "device-no-labels"},
@ -1949,6 +1969,7 @@ async def test_entity_service_call_warn_referenced(
) -> None:
"""Test we only warn for referenced entities in entity_service_call."""
call = ServiceCall(
hass,
"light",
"turn_on",
{
@ -1972,6 +1993,7 @@ async def test_async_extract_entities_warn_referenced(
) -> None:
"""Test we only warn for referenced entities in async_extract_entities."""
call = ServiceCall(
hass,
"light",
"turn_on",
{
@ -1997,6 +2019,7 @@ async def test_async_extract_config_entry_ids(hass: HomeAssistant) -> None:
device_no_entities = dr.DeviceEntry(id="device-no-entities", config_entries={"abc"})
call = ServiceCall(
hass,
"homeassistant",
"reload_config_entry",
{
@ -2042,17 +2065,33 @@ async def test_reload_service_helper(hass: HomeAssistant) -> None:
reloader = service.ReloadServiceHelper(reload_service_handler, reload_targets)
tasks = [
# This reload task will start executing first, (target1)
reloader.execute_service(ServiceCall("test", "test", {"target": "target1"})),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target1"})
),
# These reload tasks will be deduplicated to (target2, target3, target4, target1)
# while the first task is reloaded, note that target1 can't be deduplicated
# because it's already being reloaded.
reloader.execute_service(ServiceCall("test", "test", {"target": "target2"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target3"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target4"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target1"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target2"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target3"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target4"})),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target2"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target3"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target4"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target1"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target2"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target3"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target4"})
),
]
await asyncio.gather(*tasks)
assert reloaded == unordered(
@ -2063,13 +2102,21 @@ async def test_reload_service_helper(hass: HomeAssistant) -> None:
reloaded.clear()
tasks = [
# This reload task will start executing first, (target1)
reloader.execute_service(ServiceCall("test", "test", {"target": "target1"})),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target1"})
),
# These reload tasks will be deduplicated to (target2, target3, target4, all)
# while the first task is reloaded.
reloader.execute_service(ServiceCall("test", "test", {"target": "target2"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target3"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target4"})),
reloader.execute_service(ServiceCall("test", "test")),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target2"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target3"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target4"})
),
reloader.execute_service(ServiceCall(hass, "test", "test")),
]
await asyncio.gather(*tasks)
assert reloaded == unordered(["target1", "target2", "target3", "target4", "all"])
@ -2078,13 +2125,21 @@ async def test_reload_service_helper(hass: HomeAssistant) -> None:
reloaded.clear()
tasks = [
# This reload task will start executing first, (all)
reloader.execute_service(ServiceCall("test", "test")),
reloader.execute_service(ServiceCall(hass, "test", "test")),
# These reload tasks will be deduplicated to (target1, target2, target3, target4)
# while the first task is reloaded.
reloader.execute_service(ServiceCall("test", "test", {"target": "target1"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target2"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target3"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target4"})),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target1"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target2"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target3"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target4"})
),
]
await asyncio.gather(*tasks)
assert reloaded == unordered(["all", "target1", "target2", "target3", "target4"])
@ -2093,21 +2148,45 @@ async def test_reload_service_helper(hass: HomeAssistant) -> None:
reloaded.clear()
tasks = [
# This reload task will start executing first, (target1)
reloader.execute_service(ServiceCall("test", "test", {"target": "target1"})),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target1"})
),
# These reload tasks will be deduplicated to (target2, target3, target4, target1)
# while the first task is reloaded, note that target1 can't be deduplicated
# because it's already being reloaded.
reloader.execute_service(ServiceCall("test", "test", {"target": "target2"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target3"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target4"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target1"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target2"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target3"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target4"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target1"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target2"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target3"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target4"})),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target2"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target3"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target4"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target1"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target2"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target3"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target4"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target1"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target2"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target3"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target4"})
),
]
await asyncio.gather(*tasks)
assert reloaded == unordered(
@ -2118,14 +2197,22 @@ async def test_reload_service_helper(hass: HomeAssistant) -> None:
reloaded.clear()
tasks = [
# This reload task will start executing first, (target1)
reloader.execute_service(ServiceCall("test", "test", {"target": "target1"})),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target1"})
),
# These reload tasks will be deduplicated to (target2, target3, target4, all)
# while the first task is reloaded.
reloader.execute_service(ServiceCall("test", "test", {"target": "target2"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target3"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target4"})),
reloader.execute_service(ServiceCall("test", "test")),
reloader.execute_service(ServiceCall("test", "test")),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target2"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target3"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target4"})
),
reloader.execute_service(ServiceCall(hass, "test", "test")),
reloader.execute_service(ServiceCall(hass, "test", "test")),
]
await asyncio.gather(*tasks)
assert reloaded == unordered(["target1", "target2", "target3", "target4", "all"])
@ -2134,17 +2221,33 @@ async def test_reload_service_helper(hass: HomeAssistant) -> None:
reloaded.clear()
tasks = [
# This reload task will start executing first, (all)
reloader.execute_service(ServiceCall("test", "test")),
reloader.execute_service(ServiceCall(hass, "test", "test")),
# These reload tasks will be deduplicated to (target1, target2, target3, target4)
# while the first task is reloaded.
reloader.execute_service(ServiceCall("test", "test", {"target": "target1"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target2"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target3"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target4"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target1"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target2"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target3"})),
reloader.execute_service(ServiceCall("test", "test", {"target": "target4"})),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target1"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target2"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target3"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target4"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target1"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target2"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target3"})
),
reloader.execute_service(
ServiceCall(hass, "test", "test", {"target": "target4"})
),
]
await asyncio.gather(*tasks)
assert reloaded == unordered(["all", "target1", "target2", "target3", "target4"])

View File

@ -1562,10 +1562,10 @@ async def test_statemachine_avoids_updating_attributes(hass: HomeAssistant) -> N
def test_service_call_repr() -> None:
"""Test ServiceCall repr."""
call = ha.ServiceCall("homeassistant", "start")
call = ha.ServiceCall(None, "homeassistant", "start")
assert str(call) == f"<ServiceCall homeassistant.start (c:{call.context.id})>"
call2 = ha.ServiceCall("homeassistant", "start", {"fast": "yes"})
call2 = ha.ServiceCall(None, "homeassistant", "start", {"fast": "yes"})
assert (
str(call2)
== f"<ServiceCall homeassistant.start (c:{call2.context.id}): fast=yes>"