Close onvif device cleanly (#49659)

* onvif: close device cleanly

Signed-off-by: Xuefer <xuefer@gmail.com>

* onvif: Too many nested blocks

Signed-off-by: Xuefer <xuefer@gmail.com>

* update tests to cover onvif config_flow

Signed-off-by: Xuefer <xuefer@gmail.com>
This commit is contained in:
Xuefer 2021-05-25 03:27:40 +08:00 committed by GitHub
parent a7eedeeaba
commit 2a47805b4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 59 additions and 10 deletions

View File

@ -206,9 +206,12 @@ class OnvifFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
if not self.device_id:
try:
network_interfaces = await device_mgmt.GetNetworkInterfaces()
for interface in network_interfaces:
if interface.Enabled:
self.device_id = interface.Info.HwAddress
interface = next(
filter(lambda interface: interface.Enabled, network_interfaces),
None,
)
if interface:
self.device_id = interface.Info.HwAddress
except Fault as fault:
if "not implemented" not in fault.message:
raise fault
@ -248,8 +251,6 @@ class OnvifFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
if not h264:
return self.async_abort(reason="no_h264")
await device.close()
title = f"{self.onvif_config[CONF_NAME]} - {self.device_id}"
return self.async_create_entry(title=title, data=self.onvif_config)
@ -259,13 +260,14 @@ class OnvifFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
self.onvif_config[CONF_NAME],
err,
)
await device.close()
return self.async_abort(reason="onvif_error")
except Fault:
errors["base"] = "cannot_connect"
await device.close()
finally:
await device.close()
return self.async_show_form(step_id="auth", errors=errors)
async def async_step_import(self, user_input):

View File

@ -41,6 +41,7 @@ def setup_mock_onvif_camera(
with_h264=True,
two_profiles=False,
with_interfaces=True,
with_interfaces_not_implemented=False,
with_serial=True,
):
"""Prepare mock onvif.ONVIFCamera."""
@ -54,9 +55,14 @@ def setup_mock_onvif_camera(
interface.Enabled = True
interface.Info.HwAddress = MAC
devicemgmt.GetNetworkInterfaces = AsyncMock(
return_value=[interface] if with_interfaces else []
)
if with_interfaces_not_implemented:
devicemgmt.GetNetworkInterfaces = AsyncMock(
side_effect=Fault("not implemented")
)
else:
devicemgmt.GetNetworkInterfaces = AsyncMock(
return_value=[interface] if with_interfaces else []
)
media_service = MagicMock()
@ -413,6 +419,47 @@ async def test_flow_manual_entry(hass):
}
async def test_flow_import_not_implemented(hass):
"""Test that config flow uses Serial Number when no MAC available."""
with patch(
"homeassistant.components.onvif.config_flow.get_device"
) as mock_onvif_camera, patch(
"homeassistant.components.onvif.ONVIFDevice"
) as mock_device, patch(
"homeassistant.components.onvif.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.onvif.async_setup_entry", return_value=True
) as mock_setup_entry:
setup_mock_onvif_camera(mock_onvif_camera, with_interfaces_not_implemented=True)
setup_mock_device(mock_device)
result = await hass.config_entries.flow.async_init(
config_flow.DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data={
config_flow.CONF_NAME: NAME,
config_flow.CONF_HOST: HOST,
config_flow.CONF_PORT: PORT,
config_flow.CONF_USERNAME: USERNAME,
config_flow.CONF_PASSWORD: PASSWORD,
},
)
await hass.async_block_till_done()
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == f"{NAME} - {SERIAL_NUMBER}"
assert result["data"] == {
config_flow.CONF_NAME: NAME,
config_flow.CONF_HOST: HOST,
config_flow.CONF_PORT: PORT,
config_flow.CONF_USERNAME: USERNAME,
config_flow.CONF_PASSWORD: PASSWORD,
}
async def test_flow_import_no_mac(hass):
"""Test that config flow uses Serial Number when no MAC available."""
with patch(