Skip to content

Commit

Permalink
Fix config_flow error from dlna_dmr for UPnP discovery info containin…
Browse files Browse the repository at this point in the history
…g a single service (home-assistant#69977)
  • Loading branch information
chishm authored and Djelibeybi committed Apr 14, 2022
1 parent fdae942 commit 5036df3
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 5 deletions.
14 changes: 10 additions & 4 deletions homeassistant/components/dlna_dmr/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,16 @@ async def async_step_ssdp(self, discovery_info: ssdp.SsdpServiceInfo) -> FlowRes
discovery_service_list = discovery_info.upnp.get(ssdp.ATTR_UPNP_SERVICE_LIST)
if not discovery_service_list:
return self.async_abort(reason="not_dmr")
discovery_service_ids = {
service.get("serviceId")
for service in discovery_service_list.get("service") or []
}

services = discovery_service_list.get("service")
if not services:
discovery_service_ids: set[str] = set()
elif isinstance(services, list):
discovery_service_ids = {service.get("serviceId") for service in services}
else:
# Only one service defined (etree_to_dict failed to make a list)
discovery_service_ids = {services.get("serviceId")}

if not DmrDevice.SERVICE_IDS.issubset(discovery_service_ids):
return self.async_abort(reason="not_dmr")

Expand Down
36 changes: 35 additions & 1 deletion tests/components/dlna_dmr/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ async def test_ssdp_flow_upnp_udn(

async def test_ssdp_missing_services(hass: HomeAssistant) -> None:
"""Test SSDP ignores devices that are missing required services."""
# No services defined at all
# No service list at all
discovery = dataclasses.replace(MOCK_DISCOVERY)
discovery.upnp = discovery.upnp.copy()
del discovery.upnp[ssdp.ATTR_UPNP_SERVICE_LIST]
Expand All @@ -400,6 +400,18 @@ async def test_ssdp_missing_services(hass: HomeAssistant) -> None:
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "not_dmr"

# Service list does not contain services
discovery = dataclasses.replace(MOCK_DISCOVERY)
discovery.upnp = discovery.upnp.copy()
discovery.upnp[ssdp.ATTR_UPNP_SERVICE_LIST] = {"bad_key": "bad_value"}
result = await hass.config_entries.flow.async_init(
DLNA_DOMAIN,
context={"source": config_entries.SOURCE_SSDP},
data=discovery,
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "not_dmr"

# AVTransport service is missing
discovery = dataclasses.replace(MOCK_DISCOVERY)
discovery.upnp = discovery.upnp.copy()
Expand All @@ -417,6 +429,28 @@ async def test_ssdp_missing_services(hass: HomeAssistant) -> None:
assert result["reason"] == "not_dmr"


async def test_ssdp_single_service(hass: HomeAssistant) -> None:
"""Test SSDP discovery info with only one service defined.
THe etree_to_dict function turns multiple services into a list of dicts, but
a single service into only a dict.
"""
discovery = dataclasses.replace(MOCK_DISCOVERY)
discovery.upnp = discovery.upnp.copy()
service_list = discovery.upnp[ssdp.ATTR_UPNP_SERVICE_LIST].copy()
# Turn mock's list of service dicts into a single dict
service_list["service"] = service_list["service"][0]
discovery.upnp[ssdp.ATTR_UPNP_SERVICE_LIST] = service_list

result = await hass.config_entries.flow.async_init(
DLNA_DOMAIN,
context={"source": config_entries.SOURCE_SSDP},
data=discovery,
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "not_dmr"


async def test_ssdp_ignore_device(hass: HomeAssistant) -> None:
"""Test SSDP discovery ignores certain devices."""
discovery = dataclasses.replace(MOCK_DISCOVERY)
Expand Down

0 comments on commit 5036df3

Please # to comment.