Fix service registration supported features check (#35718)
parent
b0578018cb
commit
d21cfd869e
|
@ -431,7 +431,8 @@ async def entity_service_call(hass, platforms, func, call, required_features=Non
|
||||||
|
|
||||||
# Skip entities that don't have the required feature.
|
# Skip entities that don't have the required feature.
|
||||||
if required_features is not None and not any(
|
if required_features is not None and not any(
|
||||||
entity.supported_features & feature_set for feature_set in required_features
|
entity.supported_features & feature_set == feature_set
|
||||||
|
for feature_set in required_features
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,10 @@ from tests.common import (
|
||||||
mock_service,
|
mock_service,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SUPPORT_A = 1
|
||||||
|
SUPPORT_B = 2
|
||||||
|
SUPPORT_C = 4
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_handle_entity_call():
|
def mock_handle_entity_call():
|
||||||
|
@ -52,17 +56,31 @@ def mock_entities(hass):
|
||||||
entity_id="light.kitchen",
|
entity_id="light.kitchen",
|
||||||
available=True,
|
available=True,
|
||||||
should_poll=False,
|
should_poll=False,
|
||||||
supported_features=1,
|
supported_features=SUPPORT_A,
|
||||||
)
|
)
|
||||||
living_room = MockEntity(
|
living_room = MockEntity(
|
||||||
entity_id="light.living_room",
|
entity_id="light.living_room",
|
||||||
available=True,
|
available=True,
|
||||||
should_poll=False,
|
should_poll=False,
|
||||||
supported_features=0,
|
supported_features=SUPPORT_B,
|
||||||
|
)
|
||||||
|
bedroom = MockEntity(
|
||||||
|
entity_id="light.bedroom",
|
||||||
|
available=True,
|
||||||
|
should_poll=False,
|
||||||
|
supported_features=(SUPPORT_A | SUPPORT_B),
|
||||||
|
)
|
||||||
|
bathroom = MockEntity(
|
||||||
|
entity_id="light.bathroom",
|
||||||
|
available=True,
|
||||||
|
should_poll=False,
|
||||||
|
supported_features=(SUPPORT_B | SUPPORT_C),
|
||||||
)
|
)
|
||||||
entities = OrderedDict()
|
entities = OrderedDict()
|
||||||
entities[kitchen.entity_id] = kitchen
|
entities[kitchen.entity_id] = kitchen
|
||||||
entities[living_room.entity_id] = living_room
|
entities[living_room.entity_id] = living_room
|
||||||
|
entities[bedroom.entity_id] = bedroom
|
||||||
|
entities[bathroom.entity_id] = bathroom
|
||||||
return entities
|
return entities
|
||||||
|
|
||||||
|
|
||||||
|
@ -307,18 +325,61 @@ async def test_async_get_all_descriptions(hass):
|
||||||
|
|
||||||
|
|
||||||
async def test_call_with_required_features(hass, mock_entities):
|
async def test_call_with_required_features(hass, mock_entities):
|
||||||
"""Test service calls invoked only if entity has required feautres."""
|
"""Test service calls invoked only if entity has required features."""
|
||||||
test_service_mock = AsyncMock(return_value=None)
|
test_service_mock = AsyncMock(return_value=None)
|
||||||
await service.entity_service_call(
|
await service.entity_service_call(
|
||||||
hass,
|
hass,
|
||||||
[Mock(entities=mock_entities)],
|
[Mock(entities=mock_entities)],
|
||||||
test_service_mock,
|
test_service_mock,
|
||||||
ha.ServiceCall("test_domain", "test_service", {"entity_id": "all"}),
|
ha.ServiceCall("test_domain", "test_service", {"entity_id": "all"}),
|
||||||
required_features=[1],
|
required_features=[SUPPORT_A],
|
||||||
)
|
)
|
||||||
assert len(mock_entities) == 2
|
|
||||||
# Called once because only one of the entities had the required features
|
assert test_service_mock.call_count == 2
|
||||||
|
expected = [
|
||||||
|
mock_entities["light.kitchen"],
|
||||||
|
mock_entities["light.bedroom"],
|
||||||
|
]
|
||||||
|
actual = [call[0][0] for call in test_service_mock.call_args_list]
|
||||||
|
assert all(entity in actual for entity in expected)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_call_with_both_required_features(hass, mock_entities):
|
||||||
|
"""Test service calls invoked only if entity has both features."""
|
||||||
|
test_service_mock = AsyncMock(return_value=None)
|
||||||
|
await service.entity_service_call(
|
||||||
|
hass,
|
||||||
|
[Mock(entities=mock_entities)],
|
||||||
|
test_service_mock,
|
||||||
|
ha.ServiceCall("test_domain", "test_service", {"entity_id": "all"}),
|
||||||
|
required_features=[SUPPORT_A | SUPPORT_B],
|
||||||
|
)
|
||||||
|
|
||||||
assert test_service_mock.call_count == 1
|
assert test_service_mock.call_count == 1
|
||||||
|
assert [call[0][0] for call in test_service_mock.call_args_list] == [
|
||||||
|
mock_entities["light.bedroom"]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_call_with_one_of_required_features(hass, mock_entities):
|
||||||
|
"""Test service calls invoked with one entity having the required features."""
|
||||||
|
test_service_mock = AsyncMock(return_value=None)
|
||||||
|
await service.entity_service_call(
|
||||||
|
hass,
|
||||||
|
[Mock(entities=mock_entities)],
|
||||||
|
test_service_mock,
|
||||||
|
ha.ServiceCall("test_domain", "test_service", {"entity_id": "all"}),
|
||||||
|
required_features=[SUPPORT_A, SUPPORT_C],
|
||||||
|
)
|
||||||
|
|
||||||
|
assert test_service_mock.call_count == 3
|
||||||
|
expected = [
|
||||||
|
mock_entities["light.kitchen"],
|
||||||
|
mock_entities["light.bedroom"],
|
||||||
|
mock_entities["light.bathroom"],
|
||||||
|
]
|
||||||
|
actual = [call[0][0] for call in test_service_mock.call_args_list]
|
||||||
|
assert all(entity in actual for entity in expected)
|
||||||
|
|
||||||
|
|
||||||
async def test_call_with_sync_func(hass, mock_entities):
|
async def test_call_with_sync_func(hass, mock_entities):
|
||||||
|
@ -458,7 +519,7 @@ async def test_call_no_context_target_all(hass, mock_handle_entity_call, mock_en
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert len(mock_handle_entity_call.mock_calls) == 2
|
assert len(mock_handle_entity_call.mock_calls) == 4
|
||||||
assert [call[1][1] for call in mock_handle_entity_call.mock_calls] == list(
|
assert [call[1][1] for call in mock_handle_entity_call.mock_calls] == list(
|
||||||
mock_entities.values()
|
mock_entities.values()
|
||||||
)
|
)
|
||||||
|
@ -494,7 +555,7 @@ async def test_call_with_match_all(
|
||||||
ha.ServiceCall("test_domain", "test_service", {"entity_id": "all"}),
|
ha.ServiceCall("test_domain", "test_service", {"entity_id": "all"}),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert len(mock_handle_entity_call.mock_calls) == 2
|
assert len(mock_handle_entity_call.mock_calls) == 4
|
||||||
assert [call[1][1] for call in mock_handle_entity_call.mock_calls] == list(
|
assert [call[1][1] for call in mock_handle_entity_call.mock_calls] == list(
|
||||||
mock_entities.values()
|
mock_entities.values()
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue