Skip to content

Commit 48091e5

Browse files
emontnemeryCopilot
andauthored
Improve test of WS command get_services (home-assistant#150901)
Co-authored-by: Copilot <[email protected]>
1 parent 26582ce commit 48091e5

File tree

2 files changed

+207
-6
lines changed

2 files changed

+207
-6
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# serializer version: 1
2+
# name: test_get_services
3+
dict({
4+
'reload': dict({
5+
'description': 'Reloads group configuration, entities, and notify services from YAML-configuration.',
6+
'fields': dict({
7+
}),
8+
'name': 'Reload',
9+
}),
10+
'remove': dict({
11+
'description': 'Removes a group.',
12+
'fields': dict({
13+
'object_id': dict({
14+
'description': 'Object ID of this group. This object ID is used as part of the entity ID. Entity ID format: [domain].[object_id].',
15+
'example': 'test_group',
16+
'name': 'Object ID',
17+
'required': True,
18+
'selector': dict({
19+
'object': dict({
20+
}),
21+
}),
22+
}),
23+
}),
24+
'name': 'Remove',
25+
}),
26+
'set': dict({
27+
'description': 'Creates/Updates a group.',
28+
'fields': dict({
29+
'add_entities': dict({
30+
'description': 'List of members to be added to the group. Cannot be used in combination with `Entities` or `Remove entities`.',
31+
'example': 'domain.entity_id1, domain.entity_id2',
32+
'name': 'Add entities',
33+
'selector': dict({
34+
'entity': dict({
35+
'multiple': True,
36+
'reorder': False,
37+
}),
38+
}),
39+
}),
40+
'all': dict({
41+
'description': 'Enable this option if the group should only be used when all entities are in state `on`.',
42+
'name': 'All',
43+
'selector': dict({
44+
'boolean': dict({
45+
}),
46+
}),
47+
}),
48+
'entities': dict({
49+
'description': 'List of all members in the group. Cannot be used in combination with `Add entities` or `Remove entities`.',
50+
'example': 'domain.entity_id1, domain.entity_id2',
51+
'name': 'Entities',
52+
'selector': dict({
53+
'entity': dict({
54+
'multiple': True,
55+
'reorder': False,
56+
}),
57+
}),
58+
}),
59+
'icon': dict({
60+
'description': 'Name of the icon for the group.',
61+
'example': 'mdi:camera',
62+
'name': 'Icon',
63+
'selector': dict({
64+
'icon': dict({
65+
}),
66+
}),
67+
}),
68+
'name': dict({
69+
'description': 'Name of the group.',
70+
'example': 'My test group',
71+
'name': 'Name',
72+
'selector': dict({
73+
'text': dict({
74+
}),
75+
}),
76+
}),
77+
'object_id': dict({
78+
'description': 'Object ID of this group. This object ID is used as part of the entity ID. Entity ID format: [domain].[object_id].',
79+
'example': 'test_group',
80+
'name': 'Object ID',
81+
'required': True,
82+
'selector': dict({
83+
'text': dict({
84+
}),
85+
}),
86+
}),
87+
'remove_entities': dict({
88+
'description': 'List of members to be removed from a group. Cannot be used in combination with `Entities` or `Add entities`.',
89+
'example': 'domain.entity_id1, domain.entity_id2',
90+
'name': 'Remove entities',
91+
'selector': dict({
92+
'entity': dict({
93+
'multiple': True,
94+
'reorder': False,
95+
}),
96+
}),
97+
}),
98+
}),
99+
'name': 'Set',
100+
}),
101+
})
102+
# ---
103+
# name: test_get_services.1
104+
dict({
105+
'set_default_level': dict({
106+
'description': 'Translated description',
107+
'fields': dict({
108+
'level': dict({
109+
'description': 'Field description',
110+
'example': 'Field example',
111+
'name': 'Field name',
112+
'selector': dict({
113+
'select': dict({
114+
'options': list([
115+
'debug',
116+
'info',
117+
'warning',
118+
'error',
119+
'fatal',
120+
'critical',
121+
]),
122+
'translation_key': 'level',
123+
}),
124+
}),
125+
}),
126+
}),
127+
'name': 'Translated name',
128+
}),
129+
'set_level': dict({
130+
'description': '',
131+
'fields': dict({
132+
}),
133+
'name': '',
134+
}),
135+
})
136+
# ---

tests/components/websocket_api/test_commands.py

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@
88
from unittest.mock import ANY, AsyncMock, Mock, patch
99

1010
import pytest
11+
from syrupy.assertion import SnapshotAssertion
1112
import voluptuous as vol
1213

1314
from homeassistant import loader
1415
from homeassistant.components.device_automation import toggle_entity
16+
from homeassistant.components.group import DOMAIN as DOMAIN_GROUP
17+
from homeassistant.components.logger import DOMAIN as DOMAIN_LOGGER
1518
from homeassistant.components.websocket_api import const
1619
from homeassistant.components.websocket_api.auth import (
1720
TYPE_AUTH,
@@ -34,7 +37,7 @@
3437
from homeassistant.loader import Integration, async_get_integration
3538
from homeassistant.setup import async_set_domains_to_be_loaded, async_setup_component
3639
from homeassistant.util.json import json_loads
37-
from homeassistant.util.yaml.loader import parse_yaml
40+
from homeassistant.util.yaml.loader import JSON_TYPE, parse_yaml
3841

3942
from tests.common import (
4043
MockConfigEntry,
@@ -671,7 +674,9 @@ async def test_get_states(
671674

672675

673676
async def test_get_services(
674-
hass: HomeAssistant, websocket_client: MockHAClientWebSocket
677+
hass: HomeAssistant,
678+
websocket_client: MockHAClientWebSocket,
679+
snapshot: SnapshotAssertion,
675680
) -> None:
676681
"""Test get_services command."""
677682
assert ALL_SERVICE_DESCRIPTIONS_JSON_CACHE not in hass.data
@@ -686,16 +691,18 @@ async def test_get_services(
686691
assert msg == {"id": 2, "result": {}, "success": True, "type": "result"}
687692
assert hass.data[ALL_SERVICE_DESCRIPTIONS_JSON_CACHE] is old_cache
688693

689-
# Load a service and check cache is updated
690-
assert await async_setup_component(hass, "logger", {})
694+
# Set up an integration that has services and check cache is updated
695+
assert await async_setup_component(hass, DOMAIN_GROUP, {DOMAIN_GROUP: {}})
691696
await websocket_client.send_json_auto_id({"type": "get_services"})
692697
msg = await websocket_client.receive_json()
693698
assert msg == {
694699
"id": 3,
695-
"result": {"logger": {"set_default_level": ANY, "set_level": ANY}},
700+
"result": {DOMAIN_GROUP: ANY},
696701
"success": True,
697702
"type": "result",
698703
}
704+
group_services = msg["result"][DOMAIN_GROUP]
705+
assert group_services == snapshot
699706
assert hass.data[ALL_SERVICE_DESCRIPTIONS_JSON_CACHE] is not old_cache
700707

701708
# Check cache is reused
@@ -704,12 +711,70 @@ async def test_get_services(
704711
msg = await websocket_client.receive_json()
705712
assert msg == {
706713
"id": 4,
707-
"result": {"logger": {"set_default_level": ANY, "set_level": ANY}},
714+
"result": {DOMAIN_GROUP: group_services},
708715
"success": True,
709716
"type": "result",
710717
}
711718
assert hass.data[ALL_SERVICE_DESCRIPTIONS_JSON_CACHE] is old_cache
712719

720+
# Set up an integration with legacy translations in services.yaml
721+
def _load_services_file(hass: HomeAssistant, integration: Integration) -> JSON_TYPE:
722+
return {
723+
"set_default_level": {
724+
"description": "Translated description",
725+
"fields": {
726+
"level": {
727+
"description": "Field description",
728+
"example": "Field example",
729+
"name": "Field name",
730+
"selector": {
731+
"select": {
732+
"options": [
733+
"debug",
734+
"info",
735+
"warning",
736+
"error",
737+
"fatal",
738+
"critical",
739+
],
740+
"translation_key": "level",
741+
}
742+
},
743+
}
744+
},
745+
"name": "Translated name",
746+
},
747+
"set_level": None,
748+
}
749+
750+
await async_setup_component(hass, DOMAIN_LOGGER, {DOMAIN_LOGGER: {}})
751+
await hass.async_block_till_done()
752+
753+
with (
754+
patch(
755+
"homeassistant.helpers.service._load_services_file",
756+
side_effect=_load_services_file,
757+
),
758+
patch(
759+
"homeassistant.helpers.service.translation.async_get_translations",
760+
return_value={},
761+
),
762+
):
763+
await websocket_client.send_json_auto_id({"type": "get_services"})
764+
msg = await websocket_client.receive_json()
765+
766+
assert msg == {
767+
"id": 5,
768+
"result": {
769+
DOMAIN_LOGGER: ANY,
770+
DOMAIN_GROUP: group_services,
771+
},
772+
"success": True,
773+
"type": "result",
774+
}
775+
logger_services = msg["result"][DOMAIN_LOGGER]
776+
assert logger_services == snapshot
777+
713778

714779
@patch("annotatedyaml.loader.load_yaml")
715780
@patch.object(Integration, "has_conditions", return_value=True)

0 commit comments

Comments
 (0)