mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 13:47:35 +00:00
deCONZ - Allow manual configuration to update existing configuration (#30469)
* Allow manual configuration to update existing configuration * Harmonize tests
This commit is contained in:
parent
639cdf5eef
commit
967fe89f6d
@ -147,8 +147,17 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
self.bridge_id = await async_get_bridge_id(
|
self.bridge_id = await async_get_bridge_id(
|
||||||
session, **self.deconz_config
|
session, **self.deconz_config
|
||||||
)
|
)
|
||||||
|
|
||||||
|
for entry in self.hass.config_entries.async_entries(DOMAIN):
|
||||||
|
if self.bridge_id == entry.unique_id:
|
||||||
|
return self._update_entry(
|
||||||
|
entry,
|
||||||
|
host=self.deconz_config[CONF_HOST],
|
||||||
|
port=self.deconz_config[CONF_PORT],
|
||||||
|
api_key=self.deconz_config[CONF_API_KEY],
|
||||||
|
)
|
||||||
|
|
||||||
await self.async_set_unique_id(self.bridge_id)
|
await self.async_set_unique_id(self.bridge_id)
|
||||||
self._abort_if_unique_id_configured()
|
|
||||||
|
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
return self.async_abort(reason="no_bridges")
|
return self.async_abort(reason="no_bridges")
|
||||||
|
@ -1,36 +1,23 @@
|
|||||||
"""Tests for deCONZ config flow."""
|
"""Tests for deCONZ config flow."""
|
||||||
import asyncio
|
import asyncio
|
||||||
from copy import deepcopy
|
|
||||||
|
|
||||||
from asynctest import Mock, patch
|
|
||||||
import pydeconz
|
import pydeconz
|
||||||
|
|
||||||
from homeassistant.components import ssdp
|
from homeassistant.components import ssdp
|
||||||
from homeassistant.components.deconz import config_flow
|
from homeassistant.components.deconz import config_flow
|
||||||
from homeassistant.components.deconz.const import CONF_BRIDGEID
|
|
||||||
|
|
||||||
from .test_gateway import (
|
from .test_gateway import API_KEY, BRIDGEID, setup_deconz_integration
|
||||||
BRIDGEID,
|
|
||||||
DECONZ_WEB_REQUEST,
|
|
||||||
ENTRY_CONFIG,
|
|
||||||
setup_deconz_integration,
|
|
||||||
)
|
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
async def test_flow_works(hass, aioclient_mock):
|
async def test_flow_1_discovered_bridge(hass, aioclient_mock):
|
||||||
"""Test that config flow works."""
|
"""Test that config flow for one discovered bridge works."""
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
pydeconz.utils.URL_DISCOVER,
|
pydeconz.utils.URL_DISCOVER,
|
||||||
json=[{"id": BRIDGEID, "internalipaddress": "1.2.3.4", "internalport": 80}],
|
json=[{"id": BRIDGEID, "internalipaddress": "1.2.3.4", "internalport": 80}],
|
||||||
headers={"content-type": "application/json"},
|
headers={"content-type": "application/json"},
|
||||||
)
|
)
|
||||||
aioclient_mock.post(
|
|
||||||
"http://1.2.3.4:80/api",
|
|
||||||
json=[{"success": {"username": "1234567890ABCDEF"}}],
|
|
||||||
headers={"content-type": "application/json"},
|
|
||||||
)
|
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
config_flow.DOMAIN, context={"source": "user"}
|
||||||
@ -39,6 +26,12 @@ async def test_flow_works(hass, aioclient_mock):
|
|||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "link"
|
assert result["step_id"] == "link"
|
||||||
|
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://1.2.3.4:80/api",
|
||||||
|
json=[{"success": {"username": API_KEY}}],
|
||||||
|
headers={"content-type": "application/json"},
|
||||||
|
)
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"], user_input={}
|
result["flow_id"], user_input={}
|
||||||
)
|
)
|
||||||
@ -48,65 +41,17 @@ async def test_flow_works(hass, aioclient_mock):
|
|||||||
assert result["data"] == {
|
assert result["data"] == {
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
config_flow.CONF_HOST: "1.2.3.4",
|
||||||
config_flow.CONF_PORT: 80,
|
config_flow.CONF_PORT: 80,
|
||||||
config_flow.CONF_API_KEY: "1234567890ABCDEF",
|
config_flow.CONF_API_KEY: API_KEY,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def test_user_step_bridge_discovery_fails(hass, aioclient_mock):
|
async def test_flow_2_discovered_bridges(hass, aioclient_mock):
|
||||||
"""Test config flow works when discovery fails."""
|
"""Test that config flow works for multiple discovered bridges."""
|
||||||
with patch(
|
|
||||||
"homeassistant.components.deconz.config_flow.async_discovery",
|
|
||||||
side_effect=asyncio.TimeoutError,
|
|
||||||
):
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result["type"] == "form"
|
|
||||||
assert result["step_id"] == "init"
|
|
||||||
|
|
||||||
|
|
||||||
async def test_user_step_no_discovered_bridges(hass, aioclient_mock):
|
|
||||||
"""Test config flow discovers no bridges."""
|
|
||||||
aioclient_mock.get(
|
|
||||||
pydeconz.utils.URL_DISCOVER,
|
|
||||||
json=[],
|
|
||||||
headers={"content-type": "application/json"},
|
|
||||||
)
|
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result["type"] == "form"
|
|
||||||
assert result["step_id"] == "init"
|
|
||||||
|
|
||||||
|
|
||||||
async def test_user_step_one_bridge_discovered(hass, aioclient_mock):
|
|
||||||
"""Test config flow discovers one bridge."""
|
|
||||||
aioclient_mock.get(
|
|
||||||
pydeconz.utils.URL_DISCOVER,
|
|
||||||
json=[{"id": "id", "internalipaddress": "1.2.3.4", "internalport": 80}],
|
|
||||||
headers={"content-type": "application/json"},
|
|
||||||
)
|
|
||||||
|
|
||||||
flow = config_flow.DeconzFlowHandler()
|
|
||||||
flow.hass = hass
|
|
||||||
|
|
||||||
result = await flow.async_step_user()
|
|
||||||
|
|
||||||
assert result["type"] == "form"
|
|
||||||
assert result["step_id"] == "link"
|
|
||||||
assert flow.deconz_config[config_flow.CONF_HOST] == "1.2.3.4"
|
|
||||||
|
|
||||||
|
|
||||||
async def test_user_step_two_bridges_discovered(hass, aioclient_mock):
|
|
||||||
"""Test config flow discovers two bridges."""
|
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
pydeconz.utils.URL_DISCOVER,
|
pydeconz.utils.URL_DISCOVER,
|
||||||
json=[
|
json=[
|
||||||
{"id": "id1", "internalipaddress": "1.2.3.4", "internalport": 80},
|
{"id": BRIDGEID, "internalipaddress": "1.2.3.4", "internalport": 80},
|
||||||
{"id": "id2", "internalipaddress": "5.6.7.8", "internalport": 80},
|
{"id": "1234E567890A", "internalipaddress": "5.6.7.8", "internalport": 80},
|
||||||
],
|
],
|
||||||
headers={"content-type": "application/json"},
|
headers={"content-type": "application/json"},
|
||||||
)
|
)
|
||||||
@ -115,37 +60,37 @@ async def test_user_step_two_bridges_discovered(hass, aioclient_mock):
|
|||||||
config_flow.DOMAIN, context={"source": "user"}
|
config_flow.DOMAIN, context={"source": "user"}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["data_schema"]({config_flow.CONF_HOST: "1.2.3.4"})
|
assert result["type"] == "form"
|
||||||
assert result["data_schema"]({config_flow.CONF_HOST: "5.6.7.8"})
|
assert result["step_id"] == "init"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], user_input={config_flow.CONF_HOST: "1.2.3.4"}
|
||||||
|
)
|
||||||
|
|
||||||
async def test_user_step_two_bridges_selection(hass, aioclient_mock):
|
|
||||||
"""Test config flow selection of one of two bridges."""
|
|
||||||
flow = config_flow.DeconzFlowHandler()
|
|
||||||
flow.hass = hass
|
|
||||||
flow.bridges = [
|
|
||||||
{
|
|
||||||
CONF_BRIDGEID: "id1",
|
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
|
||||||
config_flow.CONF_PORT: 80,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
CONF_BRIDGEID: "id2",
|
|
||||||
config_flow.CONF_HOST: "5.6.7.8",
|
|
||||||
config_flow.CONF_PORT: 80,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
result = await flow.async_step_user(user_input={config_flow.CONF_HOST: "1.2.3.4"})
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "link"
|
assert result["step_id"] == "link"
|
||||||
assert flow.deconz_config[config_flow.CONF_HOST] == "1.2.3.4"
|
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://1.2.3.4:80/api",
|
||||||
|
json=[{"success": {"username": API_KEY}}],
|
||||||
|
headers={"content-type": "application/json"},
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], user_input={}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == "create_entry"
|
||||||
|
assert result["title"] == BRIDGEID
|
||||||
|
assert result["data"] == {
|
||||||
|
config_flow.CONF_HOST: "1.2.3.4",
|
||||||
|
config_flow.CONF_PORT: 80,
|
||||||
|
config_flow.CONF_API_KEY: API_KEY,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def test_user_step_manual_configuration_no_bridges_discovered(
|
async def test_flow_manual_configuration(hass, aioclient_mock):
|
||||||
hass, aioclient_mock
|
"""Test that config flow works with manual configuration after no discovered bridges."""
|
||||||
):
|
|
||||||
"""Test config flow with manual input."""
|
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
pydeconz.utils.URL_DISCOVER,
|
pydeconz.utils.URL_DISCOVER,
|
||||||
json=[],
|
json=[],
|
||||||
@ -158,7 +103,6 @@ async def test_user_step_manual_configuration_no_bridges_discovered(
|
|||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "init"
|
assert result["step_id"] == "init"
|
||||||
assert not hass.config_entries.flow._progress[result["flow_id"]].bridges
|
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
@ -168,63 +112,223 @@ async def test_user_step_manual_configuration_no_bridges_discovered(
|
|||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "link"
|
assert result["step_id"] == "link"
|
||||||
|
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://1.2.3.4:80/api",
|
||||||
|
json=[{"success": {"username": API_KEY}}],
|
||||||
|
headers={"content-type": "application/json"},
|
||||||
|
)
|
||||||
|
|
||||||
async def test_user_step_manual_configuration_after_timeout(hass):
|
aioclient_mock.get(
|
||||||
"""Test config flow with manual input."""
|
f"http://1.2.3.4:80/api/{API_KEY}/config",
|
||||||
with patch(
|
json={"bridgeid": BRIDGEID},
|
||||||
"homeassistant.components.deconz.config_flow.async_discovery",
|
headers={"content-type": "application/json"},
|
||||||
side_effect=asyncio.TimeoutError,
|
)
|
||||||
):
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
result["flow_id"], user_input={}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
assert result["type"] == "create_entry"
|
||||||
|
assert result["title"] == BRIDGEID
|
||||||
|
assert result["data"] == {
|
||||||
|
config_flow.CONF_HOST: "1.2.3.4",
|
||||||
|
config_flow.CONF_PORT: 80,
|
||||||
|
config_flow.CONF_API_KEY: API_KEY,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_manual_configuration_after_discovery_timeout(hass, aioclient_mock):
|
||||||
|
"""Test failed discovery fallbacks to manual configuration."""
|
||||||
|
aioclient_mock.get(pydeconz.utils.URL_DISCOVER, exc=asyncio.TimeoutError)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
config_flow.DOMAIN, context={"source": "user"}
|
||||||
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "init"
|
assert result["step_id"] == "init"
|
||||||
assert not hass.config_entries.flow._progress[result["flow_id"]].bridges
|
assert not hass.config_entries.flow._progress[result["flow_id"]].bridges
|
||||||
|
|
||||||
|
|
||||||
async def test_user_step_manual_configuration_after_ResponseError(hass):
|
async def test_manual_configuration_after_discovery_ResponseError(hass, aioclient_mock):
|
||||||
"""Test config flow with manual input."""
|
"""Test failed discovery fallbacks to manual configuration."""
|
||||||
with patch(
|
aioclient_mock.get(pydeconz.utils.URL_DISCOVER, exc=config_flow.ResponseError)
|
||||||
"homeassistant.components.deconz.config_flow.async_discovery",
|
|
||||||
side_effect=config_flow.ResponseError,
|
result = await hass.config_entries.flow.async_init(
|
||||||
):
|
config_flow.DOMAIN, context={"source": "user"}
|
||||||
result = await hass.config_entries.flow.async_init(
|
)
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "init"
|
assert result["step_id"] == "init"
|
||||||
assert not hass.config_entries.flow._progress[result["flow_id"]].bridges
|
assert not hass.config_entries.flow._progress[result["flow_id"]].bridges
|
||||||
|
|
||||||
|
|
||||||
async def test_link_no_api_key(hass):
|
async def test_manual_configuration_update_configuration(hass, aioclient_mock):
|
||||||
|
"""Test that manual configuration can update existing config entry."""
|
||||||
|
gateway = await setup_deconz_integration(hass)
|
||||||
|
|
||||||
|
aioclient_mock.get(
|
||||||
|
pydeconz.utils.URL_DISCOVER,
|
||||||
|
json=[],
|
||||||
|
headers={"content-type": "application/json"},
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
config_flow.DOMAIN, context={"source": "user"}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == "form"
|
||||||
|
assert result["step_id"] == "init"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
user_input={config_flow.CONF_HOST: "2.3.4.5", config_flow.CONF_PORT: 80},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == "form"
|
||||||
|
assert result["step_id"] == "link"
|
||||||
|
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://2.3.4.5:80/api",
|
||||||
|
json=[{"success": {"username": API_KEY}}],
|
||||||
|
headers={"content-type": "application/json"},
|
||||||
|
)
|
||||||
|
|
||||||
|
aioclient_mock.get(
|
||||||
|
f"http://2.3.4.5:80/api/{API_KEY}/config",
|
||||||
|
json={"bridgeid": BRIDGEID},
|
||||||
|
headers={"content-type": "application/json"},
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], user_input={}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == "abort"
|
||||||
|
assert result["reason"] == "updated_instance"
|
||||||
|
assert gateway.config_entry.data[config_flow.CONF_HOST] == "2.3.4.5"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_manual_configuration_dont_update_configuration(hass, aioclient_mock):
|
||||||
|
"""Test that _create_entry work and that bridgeid can be requested."""
|
||||||
|
await setup_deconz_integration(hass)
|
||||||
|
|
||||||
|
aioclient_mock.get(
|
||||||
|
pydeconz.utils.URL_DISCOVER,
|
||||||
|
json=[],
|
||||||
|
headers={"content-type": "application/json"},
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
config_flow.DOMAIN, context={"source": "user"}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == "form"
|
||||||
|
assert result["step_id"] == "init"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
user_input={config_flow.CONF_HOST: "1.2.3.4", config_flow.CONF_PORT: 80},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == "form"
|
||||||
|
assert result["step_id"] == "link"
|
||||||
|
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://1.2.3.4:80/api",
|
||||||
|
json=[{"success": {"username": API_KEY}}],
|
||||||
|
headers={"content-type": "application/json"},
|
||||||
|
)
|
||||||
|
|
||||||
|
aioclient_mock.get(
|
||||||
|
f"http://1.2.3.4:80/api/{API_KEY}/config",
|
||||||
|
json={"bridgeid": BRIDGEID},
|
||||||
|
headers={"content-type": "application/json"},
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], user_input={}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == "abort"
|
||||||
|
assert result["reason"] == "already_configured"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_manual_configuration_timeout_get_bridge(hass, aioclient_mock):
|
||||||
|
"""Test that _create_entry handles a timeout."""
|
||||||
|
aioclient_mock.get(
|
||||||
|
pydeconz.utils.URL_DISCOVER,
|
||||||
|
json=[],
|
||||||
|
headers={"content-type": "application/json"},
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
config_flow.DOMAIN, context={"source": "user"}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == "form"
|
||||||
|
assert result["step_id"] == "init"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
user_input={config_flow.CONF_HOST: "1.2.3.4", config_flow.CONF_PORT: 80},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == "form"
|
||||||
|
assert result["step_id"] == "link"
|
||||||
|
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://1.2.3.4:80/api",
|
||||||
|
json=[{"success": {"username": API_KEY}}],
|
||||||
|
headers={"content-type": "application/json"},
|
||||||
|
)
|
||||||
|
|
||||||
|
aioclient_mock.get(
|
||||||
|
f"http://1.2.3.4:80/api/{API_KEY}/config", exc=asyncio.TimeoutError
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], user_input={}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == "abort"
|
||||||
|
assert result["reason"] == "no_bridges"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_link_get_api_key_ResponseError(hass, aioclient_mock):
|
||||||
"""Test config flow should abort if no API key was possible to retrieve."""
|
"""Test config flow should abort if no API key was possible to retrieve."""
|
||||||
flow = config_flow.DeconzFlowHandler()
|
aioclient_mock.get(
|
||||||
flow.hass = hass
|
pydeconz.utils.URL_DISCOVER,
|
||||||
flow.deconz_config = {config_flow.CONF_HOST: "1.2.3.4", config_flow.CONF_PORT: 80}
|
json=[{"id": BRIDGEID, "internalipaddress": "1.2.3.4", "internalport": 80}],
|
||||||
|
headers={"content-type": "application/json"},
|
||||||
|
)
|
||||||
|
|
||||||
with patch(
|
result = await hass.config_entries.flow.async_init(
|
||||||
"homeassistant.components.deconz.config_flow.async_get_api_key",
|
config_flow.DOMAIN, context={"source": "user"}
|
||||||
side_effect=pydeconz.errors.ResponseError,
|
)
|
||||||
):
|
|
||||||
result = await flow.async_step_link(user_input={})
|
assert result["type"] == "form"
|
||||||
|
assert result["step_id"] == "link"
|
||||||
|
|
||||||
|
aioclient_mock.post("http://1.2.3.4:80/api", exc=pydeconz.errors.ResponseError)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], user_input={}
|
||||||
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "link"
|
assert result["step_id"] == "link"
|
||||||
assert result["errors"] == {"base": "no_key"}
|
assert result["errors"] == {"base": "no_key"}
|
||||||
|
|
||||||
|
|
||||||
async def test_bridge_ssdp_discovery(hass):
|
async def test_flow_ssdp_discovery(hass, aioclient_mock):
|
||||||
"""Test a bridge being discovered over ssdp."""
|
"""Test that config flow for one discovered bridge works."""
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN,
|
config_flow.DOMAIN,
|
||||||
data={
|
data={
|
||||||
ssdp.ATTR_SSDP_LOCATION: "http://1.2.3.4:80/",
|
ssdp.ATTR_SSDP_LOCATION: "http://1.2.3.4:80/",
|
||||||
ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.DECONZ_MANUFACTURERURL,
|
ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.DECONZ_MANUFACTURERURL,
|
||||||
ssdp.ATTR_UPNP_SERIAL: "id",
|
ssdp.ATTR_UPNP_SERIAL: BRIDGEID,
|
||||||
ssdp.ATTR_UPNP_UDN: "uuid:1234",
|
|
||||||
},
|
},
|
||||||
context={"source": "ssdp"},
|
context={"source": "ssdp"},
|
||||||
)
|
)
|
||||||
@ -232,8 +336,26 @@ async def test_bridge_ssdp_discovery(hass):
|
|||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "link"
|
assert result["step_id"] == "link"
|
||||||
|
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://1.2.3.4:80/api",
|
||||||
|
json=[{"success": {"username": API_KEY}}],
|
||||||
|
headers={"content-type": "application/json"},
|
||||||
|
)
|
||||||
|
|
||||||
async def test_bridge_ssdp_discovery_not_deconz_bridge(hass):
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], user_input={}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == "create_entry"
|
||||||
|
assert result["title"] == BRIDGEID
|
||||||
|
assert result["data"] == {
|
||||||
|
config_flow.CONF_HOST: "1.2.3.4",
|
||||||
|
config_flow.CONF_PORT: 80,
|
||||||
|
config_flow.CONF_API_KEY: API_KEY,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_ssdp_discovery_not_deconz_bridge(hass):
|
||||||
"""Test a non deconz bridge being discovered over ssdp."""
|
"""Test a non deconz bridge being discovered over ssdp."""
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN,
|
config_flow.DOMAIN,
|
||||||
@ -245,24 +367,14 @@ async def test_bridge_ssdp_discovery_not_deconz_bridge(hass):
|
|||||||
assert result["reason"] == "not_deconz_bridge"
|
assert result["reason"] == "not_deconz_bridge"
|
||||||
|
|
||||||
|
|
||||||
async def test_bridge_discovery_update_existing_entry(hass):
|
async def test_ssdp_discovery_update_configuration(hass):
|
||||||
"""Test if a discovered bridge has already been configured."""
|
"""Test if a discovered bridge is configured but updates with new attributes."""
|
||||||
entry = MockConfigEntry(
|
gateway = await setup_deconz_integration(hass)
|
||||||
domain=config_flow.DOMAIN,
|
|
||||||
source="user",
|
|
||||||
data={config_flow.CONF_HOST: "1.2.3.4", config_flow.CONF_PORT: 80},
|
|
||||||
unique_id=BRIDGEID,
|
|
||||||
)
|
|
||||||
entry.add_to_hass(hass)
|
|
||||||
|
|
||||||
gateway = Mock()
|
|
||||||
gateway.config_entry = entry
|
|
||||||
hass.data[config_flow.DOMAIN] = {BRIDGEID: gateway}
|
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN,
|
config_flow.DOMAIN,
|
||||||
data={
|
data={
|
||||||
ssdp.ATTR_SSDP_LOCATION: "http://mock-deconz/",
|
ssdp.ATTR_SSDP_LOCATION: "http://2.3.4.5:80/",
|
||||||
ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.DECONZ_MANUFACTURERURL,
|
ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.DECONZ_MANUFACTURERURL,
|
||||||
ssdp.ATTR_UPNP_SERIAL: BRIDGEID,
|
ssdp.ATTR_UPNP_SERIAL: BRIDGEID,
|
||||||
},
|
},
|
||||||
@ -271,96 +383,79 @@ async def test_bridge_discovery_update_existing_entry(hass):
|
|||||||
|
|
||||||
assert result["type"] == "abort"
|
assert result["type"] == "abort"
|
||||||
assert result["reason"] == "updated_instance"
|
assert result["reason"] == "updated_instance"
|
||||||
assert entry.data[config_flow.CONF_HOST] == "mock-deconz"
|
assert gateway.config_entry.data[config_flow.CONF_HOST] == "2.3.4.5"
|
||||||
|
|
||||||
|
|
||||||
async def test_bridge_discovery_dont_update_existing_hassio_entry(hass):
|
async def test_ssdp_discovery_dont_update_configuration(hass):
|
||||||
"""Test to ensure the SSDP discovery does not update an Hass.io entry."""
|
"""Test if a discovered bridge has already been configured."""
|
||||||
entry = MockConfigEntry(
|
gateway = await setup_deconz_integration(hass)
|
||||||
domain=config_flow.DOMAIN,
|
|
||||||
source="hassio",
|
|
||||||
data={
|
|
||||||
config_flow.CONF_HOST: "core-deconz",
|
|
||||||
config_flow.CONF_BRIDGEID: "123ABC",
|
|
||||||
},
|
|
||||||
unique_id="123ABC",
|
|
||||||
)
|
|
||||||
entry.add_to_hass(hass)
|
|
||||||
|
|
||||||
gateway = Mock()
|
|
||||||
gateway.config_entry = entry
|
|
||||||
hass.data[config_flow.DOMAIN] = {"123ABC": gateway}
|
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN,
|
config_flow.DOMAIN,
|
||||||
data={
|
data={
|
||||||
ssdp.ATTR_SSDP_LOCATION: "http://mock-deconz/",
|
ssdp.ATTR_SSDP_LOCATION: "http://1.2.3.4:80/",
|
||||||
ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.DECONZ_MANUFACTURERURL,
|
ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.DECONZ_MANUFACTURERURL,
|
||||||
ssdp.ATTR_UPNP_SERIAL: "123ABC",
|
ssdp.ATTR_UPNP_SERIAL: BRIDGEID,
|
||||||
},
|
},
|
||||||
context={"source": "ssdp"},
|
context={"source": "ssdp"},
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "abort"
|
assert result["type"] == "abort"
|
||||||
assert result["reason"] == "already_configured"
|
assert result["reason"] == "already_configured"
|
||||||
assert entry.data[config_flow.CONF_HOST] == "core-deconz"
|
assert gateway.config_entry.data[config_flow.CONF_HOST] == "1.2.3.4"
|
||||||
|
|
||||||
|
|
||||||
async def test_create_entry(hass, aioclient_mock):
|
async def test_ssdp_discovery_dont_update_existing_hassio_configuration(hass):
|
||||||
"""Test that _create_entry work and that bridgeid can be requested."""
|
"""Test to ensure the SSDP discovery does not update an Hass.io entry."""
|
||||||
aioclient_mock.get(
|
gateway = await setup_deconz_integration(hass, source="hassio")
|
||||||
"http://1.2.3.4:80/api/1234567890ABCDEF/config",
|
|
||||||
json={"bridgeid": BRIDGEID, "uuid": "456DEF"},
|
result = await hass.config_entries.flow.async_init(
|
||||||
headers={"content-type": "application/json"},
|
config_flow.DOMAIN,
|
||||||
|
data={
|
||||||
|
ssdp.ATTR_SSDP_LOCATION: "http://1.2.3.4:80/",
|
||||||
|
ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.DECONZ_MANUFACTURERURL,
|
||||||
|
ssdp.ATTR_UPNP_SERIAL: BRIDGEID,
|
||||||
|
},
|
||||||
|
context={"source": "ssdp"},
|
||||||
)
|
)
|
||||||
|
|
||||||
flow = config_flow.DeconzFlowHandler()
|
|
||||||
flow.context = {}
|
|
||||||
flow.hass = hass
|
|
||||||
flow.deconz_config = {
|
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
|
||||||
config_flow.CONF_PORT: 80,
|
|
||||||
config_flow.CONF_API_KEY: "1234567890ABCDEF",
|
|
||||||
}
|
|
||||||
|
|
||||||
result = await flow._create_entry()
|
|
||||||
|
|
||||||
assert result["type"] == "create_entry"
|
|
||||||
assert result["title"] == BRIDGEID
|
|
||||||
assert result["data"] == {
|
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
|
||||||
config_flow.CONF_PORT: 80,
|
|
||||||
config_flow.CONF_API_KEY: "1234567890ABCDEF",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async def test_create_entry_timeout(hass, aioclient_mock):
|
|
||||||
"""Test that _create_entry handles a timeout."""
|
|
||||||
flow = config_flow.DeconzFlowHandler()
|
|
||||||
flow.hass = hass
|
|
||||||
flow.deconz_config = {
|
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
|
||||||
config_flow.CONF_PORT: 80,
|
|
||||||
config_flow.CONF_API_KEY: "1234567890ABCDEF",
|
|
||||||
}
|
|
||||||
|
|
||||||
with patch(
|
|
||||||
"homeassistant.components.deconz.config_flow.async_get_bridge_id",
|
|
||||||
side_effect=asyncio.TimeoutError,
|
|
||||||
):
|
|
||||||
result = await flow._create_entry()
|
|
||||||
|
|
||||||
assert result["type"] == "abort"
|
assert result["type"] == "abort"
|
||||||
assert result["reason"] == "no_bridges"
|
assert result["reason"] == "already_configured"
|
||||||
|
assert gateway.config_entry.data[config_flow.CONF_HOST] == "1.2.3.4"
|
||||||
|
|
||||||
|
|
||||||
async def test_hassio_update_instance(hass):
|
async def test_flow_hassio_discovery(hass):
|
||||||
"""Test we can update an existing config entry."""
|
"""Test hassio discovery flow works."""
|
||||||
data = deepcopy(DECONZ_WEB_REQUEST)
|
result = await hass.config_entries.flow.async_init(
|
||||||
entry_config = deepcopy(ENTRY_CONFIG)
|
config_flow.DOMAIN,
|
||||||
gateway = await setup_deconz_integration(
|
data={
|
||||||
hass, entry_config, options={}, get_state_response=data
|
"addon": "Mock Addon",
|
||||||
|
config_flow.CONF_HOST: "mock-deconz",
|
||||||
|
config_flow.CONF_PORT: 80,
|
||||||
|
config_flow.CONF_SERIAL: BRIDGEID,
|
||||||
|
config_flow.CONF_API_KEY: API_KEY,
|
||||||
|
},
|
||||||
|
context={"source": "hassio"},
|
||||||
)
|
)
|
||||||
|
assert result["type"] == "form"
|
||||||
|
assert result["step_id"] == "hassio_confirm"
|
||||||
|
assert result["description_placeholders"] == {"addon": "Mock Addon"}
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], user_input={}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == "create_entry"
|
||||||
|
assert result["result"].data == {
|
||||||
|
config_flow.CONF_HOST: "mock-deconz",
|
||||||
|
config_flow.CONF_PORT: 80,
|
||||||
|
config_flow.CONF_API_KEY: API_KEY,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_hassio_discovery_update_configuration(hass):
|
||||||
|
"""Test we can update an existing config entry."""
|
||||||
|
gateway = await setup_deconz_integration(hass)
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN,
|
config_flow.DOMAIN,
|
||||||
@ -380,19 +475,16 @@ async def test_hassio_update_instance(hass):
|
|||||||
assert gateway.config_entry.data[config_flow.CONF_API_KEY] == "updated"
|
assert gateway.config_entry.data[config_flow.CONF_API_KEY] == "updated"
|
||||||
|
|
||||||
|
|
||||||
async def test_hassio_dont_update_instance(hass):
|
async def test_hassio_discovery_dont_update_configuration(hass):
|
||||||
"""Test we can update an existing config entry."""
|
"""Test we can update an existing config entry."""
|
||||||
data = deepcopy(DECONZ_WEB_REQUEST)
|
await setup_deconz_integration(hass)
|
||||||
await setup_deconz_integration(
|
|
||||||
hass, ENTRY_CONFIG, options={}, get_state_response=data
|
|
||||||
)
|
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN,
|
config_flow.DOMAIN,
|
||||||
data={
|
data={
|
||||||
config_flow.CONF_HOST: "1.2.3.4",
|
config_flow.CONF_HOST: "1.2.3.4",
|
||||||
config_flow.CONF_PORT: 80,
|
config_flow.CONF_PORT: 80,
|
||||||
config_flow.CONF_API_KEY: "ABCDEF",
|
config_flow.CONF_API_KEY: API_KEY,
|
||||||
config_flow.CONF_SERIAL: BRIDGEID,
|
config_flow.CONF_SERIAL: BRIDGEID,
|
||||||
},
|
},
|
||||||
context={"source": "hassio"},
|
context={"source": "hassio"},
|
||||||
@ -402,35 +494,6 @@ async def test_hassio_dont_update_instance(hass):
|
|||||||
assert result["reason"] == "already_configured"
|
assert result["reason"] == "already_configured"
|
||||||
|
|
||||||
|
|
||||||
async def test_hassio_confirm(hass):
|
|
||||||
"""Test we can finish a config flow."""
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
config_flow.DOMAIN,
|
|
||||||
data={
|
|
||||||
"addon": "Mock Addon",
|
|
||||||
config_flow.CONF_HOST: "mock-deconz",
|
|
||||||
config_flow.CONF_PORT: 80,
|
|
||||||
config_flow.CONF_SERIAL: BRIDGEID,
|
|
||||||
config_flow.CONF_API_KEY: "1234567890ABCDEF",
|
|
||||||
},
|
|
||||||
context={"source": "hassio"},
|
|
||||||
)
|
|
||||||
assert result["type"] == "form"
|
|
||||||
assert result["step_id"] == "hassio_confirm"
|
|
||||||
assert result["description_placeholders"] == {"addon": "Mock Addon"}
|
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_configure(
|
|
||||||
result["flow_id"], user_input={}
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result["type"] == "create_entry"
|
|
||||||
assert result["result"].data == {
|
|
||||||
config_flow.CONF_HOST: "mock-deconz",
|
|
||||||
config_flow.CONF_PORT: 80,
|
|
||||||
config_flow.CONF_API_KEY: "1234567890ABCDEF",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async def test_option_flow(hass):
|
async def test_option_flow(hass):
|
||||||
"""Test config flow options."""
|
"""Test config flow options."""
|
||||||
entry = MockConfigEntry(domain=config_flow.DOMAIN, data={}, options=None)
|
entry = MockConfigEntry(domain=config_flow.DOMAIN, data={}, options=None)
|
||||||
|
@ -11,10 +11,11 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
|||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
API_KEY = "1234567890ABCDEF"
|
||||||
BRIDGEID = "01234E56789A"
|
BRIDGEID = "01234E56789A"
|
||||||
|
|
||||||
ENTRY_CONFIG = {
|
ENTRY_CONFIG = {
|
||||||
deconz.config_flow.CONF_API_KEY: "ABCDEF",
|
deconz.config_flow.CONF_API_KEY: API_KEY,
|
||||||
deconz.config_flow.CONF_HOST: "1.2.3.4",
|
deconz.config_flow.CONF_HOST: "1.2.3.4",
|
||||||
deconz.config_flow.CONF_PORT: 80,
|
deconz.config_flow.CONF_PORT: 80,
|
||||||
}
|
}
|
||||||
@ -46,10 +47,12 @@ async def setup_deconz_integration(
|
|||||||
options=ENTRY_OPTIONS,
|
options=ENTRY_OPTIONS,
|
||||||
get_state_response=DECONZ_WEB_REQUEST,
|
get_state_response=DECONZ_WEB_REQUEST,
|
||||||
entry_id="1",
|
entry_id="1",
|
||||||
|
source="user",
|
||||||
):
|
):
|
||||||
"""Create the deCONZ gateway."""
|
"""Create the deCONZ gateway."""
|
||||||
config_entry = MockConfigEntry(
|
config_entry = MockConfigEntry(
|
||||||
domain=deconz.DOMAIN,
|
domain=deconz.DOMAIN,
|
||||||
|
source=source,
|
||||||
data=deepcopy(config),
|
data=deepcopy(config),
|
||||||
connection_class=config_entries.CONN_CLASS_LOCAL_PUSH,
|
connection_class=config_entries.CONN_CLASS_LOCAL_PUSH,
|
||||||
options=deepcopy(options),
|
options=deepcopy(options),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user