From d345b58ce6b9f0486bc901b850dfd72b5238c6fe Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Tue, 8 Oct 2019 23:44:33 +0200 Subject: [PATCH] Improve UniFi config flow tests and add options flow test (#27340) --- homeassistant/components/unifi/config_flow.py | 6 - tests/components/deconz/test_config_flow.py | 2 +- tests/components/unifi/test_config_flow.py | 265 ++++++++++++++++++ tests/components/unifi/test_init.py | 172 +----------- 4 files changed, 268 insertions(+), 177 deletions(-) create mode 100644 tests/components/unifi/test_config_flow.py diff --git a/homeassistant/components/unifi/config_flow.py b/homeassistant/components/unifi/config_flow.py index 92281837f48..01b97a78366 100644 --- a/homeassistant/components/unifi/config_flow.py +++ b/homeassistant/components/unifi/config_flow.py @@ -150,12 +150,6 @@ class UnifiFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): self.desc = next(iter(self.sites.values()))["desc"] return await self.async_step_site(user_input={}) - if self.desc is not None: - for site in self.sites.values(): - if self.desc == site["name"]: - self.desc = site["desc"] - return await self.async_step_site(user_input={}) - sites = [] for site in self.sites.values(): sites.append(site["desc"]) diff --git a/tests/components/deconz/test_config_flow.py b/tests/components/deconz/test_config_flow.py index d0423c394a6..4045201bd18 100644 --- a/tests/components/deconz/test_config_flow.py +++ b/tests/components/deconz/test_config_flow.py @@ -387,7 +387,7 @@ async def test_hassio_confirm(hass): async def test_option_flow(hass): - """Test config flow selection of one of two bridges.""" + """Test config flow options.""" entry = MockConfigEntry(domain=config_flow.DOMAIN, data={}, options=None) hass.config_entries._entries.append(entry) diff --git a/tests/components/unifi/test_config_flow.py b/tests/components/unifi/test_config_flow.py new file mode 100644 index 00000000000..aea4d565f3d --- /dev/null +++ b/tests/components/unifi/test_config_flow.py @@ -0,0 +1,265 @@ +"""Test UniFi config flow.""" +from asynctest import patch + +from homeassistant.components import unifi +from homeassistant.components.unifi import config_flow +from homeassistant.components.unifi.const import CONF_CONTROLLER, CONF_SITE_ID + +from homeassistant.const import ( + CONF_HOST, + CONF_PASSWORD, + CONF_PORT, + CONF_USERNAME, + CONF_VERIFY_SSL, +) + +from tests.common import MockConfigEntry + +import aiounifi + + +async def test_flow_works(hass, aioclient_mock): + """Test config flow.""" + result = await hass.config_entries.flow.async_init( + config_flow.DOMAIN, context={"source": "user"} + ) + + assert result["type"] == "form" + assert result["step_id"] == "user" + + aioclient_mock.post( + "https://1.2.3.4:1234/api/login", + json={"data": "login successful", "meta": {"rc": "ok"}}, + headers={"content-type": "application/json"}, + ) + + aioclient_mock.get( + "https://1.2.3.4:1234/api/self/sites", + json={ + "data": [{"desc": "Site name", "name": "site_id", "role": "admin"}], + "meta": {"rc": "ok"}, + }, + headers={"content-type": "application/json"}, + ) + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={ + CONF_HOST: "1.2.3.4", + CONF_USERNAME: "username", + CONF_PASSWORD: "password", + CONF_PORT: 1234, + CONF_VERIFY_SSL: True, + }, + ) + + assert result["type"] == "create_entry" + assert result["title"] == "Site name" + assert result["data"] == { + CONF_CONTROLLER: { + CONF_HOST: "1.2.3.4", + CONF_USERNAME: "username", + CONF_PASSWORD: "password", + CONF_PORT: 1234, + CONF_SITE_ID: "site_id", + CONF_VERIFY_SSL: True, + } + } + + +async def test_flow_works_multiple_sites(hass, aioclient_mock): + """Test config flow works when finding multiple sites.""" + result = await hass.config_entries.flow.async_init( + config_flow.DOMAIN, context={"source": "user"} + ) + + assert result["type"] == "form" + assert result["step_id"] == "user" + + aioclient_mock.post( + "https://1.2.3.4:1234/api/login", + json={"data": "login successful", "meta": {"rc": "ok"}}, + headers={"content-type": "application/json"}, + ) + + aioclient_mock.get( + "https://1.2.3.4:1234/api/self/sites", + json={ + "data": [ + {"name": "default", "role": "admin", "desc": "site name"}, + {"name": "site2", "role": "admin", "desc": "site2 name"}, + ], + "meta": {"rc": "ok"}, + }, + headers={"content-type": "application/json"}, + ) + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={ + CONF_HOST: "1.2.3.4", + CONF_USERNAME: "username", + CONF_PASSWORD: "password", + CONF_PORT: 1234, + CONF_VERIFY_SSL: True, + }, + ) + + assert result["type"] == "form" + assert result["step_id"] == "site" + assert result["data_schema"]({"site": "site name"}) + assert result["data_schema"]({"site": "site2 name"}) + + +async def test_flow_fails_site_already_configured(hass, aioclient_mock): + """Test config flow.""" + entry = MockConfigEntry( + domain=unifi.DOMAIN, data={"controller": {"host": "1.2.3.4", "site": "site_id"}} + ) + entry.add_to_hass(hass) + + result = await hass.config_entries.flow.async_init( + config_flow.DOMAIN, context={"source": "user"} + ) + + assert result["type"] == "form" + assert result["step_id"] == "user" + + aioclient_mock.post( + "https://1.2.3.4:1234/api/login", + json={"data": "login successful", "meta": {"rc": "ok"}}, + headers={"content-type": "application/json"}, + ) + + aioclient_mock.get( + "https://1.2.3.4:1234/api/self/sites", + json={ + "data": [{"desc": "Site name", "name": "site_id", "role": "admin"}], + "meta": {"rc": "ok"}, + }, + headers={"content-type": "application/json"}, + ) + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={ + CONF_HOST: "1.2.3.4", + CONF_USERNAME: "username", + CONF_PASSWORD: "password", + CONF_PORT: 1234, + CONF_VERIFY_SSL: True, + }, + ) + + assert result["type"] == "abort" + + +async def test_flow_fails_user_credentials_faulty(hass, aioclient_mock): + """Test config flow.""" + result = await hass.config_entries.flow.async_init( + config_flow.DOMAIN, context={"source": "user"} + ) + + assert result["type"] == "form" + assert result["step_id"] == "user" + + with patch("aiounifi.Controller.login", side_effect=aiounifi.errors.Unauthorized): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={ + CONF_HOST: "1.2.3.4", + CONF_USERNAME: "username", + CONF_PASSWORD: "password", + CONF_PORT: 1234, + CONF_VERIFY_SSL: True, + }, + ) + + assert result["type"] == "form" + assert result["errors"] == {"base": "faulty_credentials"} + + +async def test_flow_fails_controller_unavailable(hass, aioclient_mock): + """Test config flow.""" + result = await hass.config_entries.flow.async_init( + config_flow.DOMAIN, context={"source": "user"} + ) + + assert result["type"] == "form" + assert result["step_id"] == "user" + + with patch("aiounifi.Controller.login", side_effect=aiounifi.errors.RequestError): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={ + CONF_HOST: "1.2.3.4", + CONF_USERNAME: "username", + CONF_PASSWORD: "password", + CONF_PORT: 1234, + CONF_VERIFY_SSL: True, + }, + ) + + assert result["type"] == "form" + assert result["errors"] == {"base": "service_unavailable"} + + +async def test_flow_fails_unknown_problem(hass, aioclient_mock): + """Test config flow.""" + result = await hass.config_entries.flow.async_init( + config_flow.DOMAIN, context={"source": "user"} + ) + + assert result["type"] == "form" + assert result["step_id"] == "user" + + with patch("aiounifi.Controller.login", side_effect=Exception): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={ + CONF_HOST: "1.2.3.4", + CONF_USERNAME: "username", + CONF_PASSWORD: "password", + CONF_PORT: 1234, + CONF_VERIFY_SSL: True, + }, + ) + + assert result["type"] == "abort" + + +async def test_option_flow(hass): + """Test config flow options.""" + entry = MockConfigEntry(domain=config_flow.DOMAIN, data={}, options=None) + hass.config_entries._entries.append(entry) + + flow = await hass.config_entries.options._async_create_flow( + entry.entry_id, context={"source": "test"}, data=None + ) + + result = await flow.async_step_init() + assert result["type"] == "form" + assert result["step_id"] == "device_tracker" + + result = await flow.async_step_device_tracker( + user_input={ + config_flow.CONF_TRACK_CLIENTS: False, + config_flow.CONF_TRACK_WIRED_CLIENTS: False, + config_flow.CONF_TRACK_DEVICES: False, + config_flow.CONF_DETECTION_TIME: 100, + } + ) + assert result["type"] == "form" + assert result["step_id"] == "statistics_sensors" + + result = await flow.async_step_statistics_sensors( + user_input={config_flow.CONF_ALLOW_BANDWIDTH_SENSORS: True} + ) + assert result["type"] == "create_entry" + assert result["data"] == { + config_flow.CONF_TRACK_CLIENTS: False, + config_flow.CONF_TRACK_WIRED_CLIENTS: False, + config_flow.CONF_TRACK_DEVICES: False, + config_flow.CONF_DETECTION_TIME: 100, + config_flow.CONF_ALLOW_BANDWIDTH_SENSORS: True, + } diff --git a/tests/components/unifi/test_init.py b/tests/components/unifi/test_init.py index 845954d8134..6b17b803390 100644 --- a/tests/components/unifi/test_init.py +++ b/tests/components/unifi/test_init.py @@ -2,16 +2,9 @@ from unittest.mock import Mock, patch from homeassistant.components import unifi -from homeassistant.components.unifi import config_flow + from homeassistant.setup import async_setup_component -from homeassistant.components.unifi.const import CONF_CONTROLLER, CONF_SITE_ID -from homeassistant.const import ( - CONF_HOST, - CONF_PASSWORD, - CONF_PORT, - CONF_USERNAME, - CONF_VERIFY_SSL, -) + from tests.common import mock_coro, MockConfigEntry @@ -179,164 +172,3 @@ async def test_unload_entry(hass): assert await unifi.async_unload_entry(hass, entry) assert len(mock_controller.return_value.async_reset.mock_calls) == 1 assert hass.data[unifi.DOMAIN] == {} - - -async def test_flow_works(hass, aioclient_mock): - """Test config flow.""" - flow = config_flow.UnifiFlowHandler() - flow.hass = hass - - with patch("aiounifi.Controller") as mock_controller: - - def mock_constructor( - host, username, password, port, site, websession, sslcontext - ): - """Fake the controller constructor.""" - mock_controller.host = host - mock_controller.username = username - mock_controller.password = password - mock_controller.port = port - mock_controller.site = site - return mock_controller - - mock_controller.side_effect = mock_constructor - mock_controller.login.return_value = mock_coro() - mock_controller.sites.return_value = mock_coro( - {"site1": {"name": "default", "role": "admin", "desc": "site name"}} - ) - - await flow.async_step_user( - user_input={ - CONF_HOST: "1.2.3.4", - CONF_USERNAME: "username", - CONF_PASSWORD: "password", - CONF_PORT: 1234, - CONF_VERIFY_SSL: True, - } - ) - - result = await flow.async_step_site(user_input={}) - - assert mock_controller.host == "1.2.3.4" - assert len(mock_controller.login.mock_calls) == 1 - assert len(mock_controller.sites.mock_calls) == 1 - - assert result["type"] == "create_entry" - assert result["title"] == "site name" - assert result["data"] == { - CONF_CONTROLLER: { - CONF_HOST: "1.2.3.4", - CONF_USERNAME: "username", - CONF_PASSWORD: "password", - CONF_PORT: 1234, - CONF_SITE_ID: "default", - CONF_VERIFY_SSL: True, - } - } - - -async def test_controller_multiple_sites(hass): - """Test config flow.""" - flow = config_flow.UnifiFlowHandler() - flow.hass = hass - - flow.config = { - CONF_HOST: "1.2.3.4", - CONF_USERNAME: "username", - CONF_PASSWORD: "password", - } - flow.sites = { - "site1": {"name": "default", "role": "admin", "desc": "site name"}, - "site2": {"name": "site2", "role": "admin", "desc": "site2 name"}, - } - - result = await flow.async_step_site() - - assert result["type"] == "form" - assert result["step_id"] == "site" - - assert result["data_schema"]({"site": "site name"}) - assert result["data_schema"]({"site": "site2 name"}) - - -async def test_controller_site_already_configured(hass): - """Test config flow.""" - flow = config_flow.UnifiFlowHandler() - flow.hass = hass - - entry = MockConfigEntry( - domain=unifi.DOMAIN, data={"controller": {"host": "1.2.3.4", "site": "default"}} - ) - entry.add_to_hass(hass) - - flow.config = { - CONF_HOST: "1.2.3.4", - CONF_USERNAME: "username", - CONF_PASSWORD: "password", - } - flow.desc = "site name" - flow.sites = {"site1": {"name": "default", "role": "admin", "desc": "site name"}} - - result = await flow.async_step_site() - - assert result["type"] == "abort" - - -async def test_user_credentials_faulty(hass, aioclient_mock): - """Test config flow.""" - flow = config_flow.UnifiFlowHandler() - flow.hass = hass - - with patch.object( - config_flow, "get_controller", side_effect=unifi.errors.AuthenticationRequired - ): - result = await flow.async_step_user( - { - CONF_HOST: "1.2.3.4", - CONF_USERNAME: "username", - CONF_PASSWORD: "password", - CONF_SITE_ID: "default", - } - ) - - assert result["type"] == "form" - assert result["errors"] == {"base": "faulty_credentials"} - - -async def test_controller_is_unavailable(hass, aioclient_mock): - """Test config flow.""" - flow = config_flow.UnifiFlowHandler() - flow.hass = hass - - with patch.object( - config_flow, "get_controller", side_effect=unifi.errors.CannotConnect - ): - result = await flow.async_step_user( - { - CONF_HOST: "1.2.3.4", - CONF_USERNAME: "username", - CONF_PASSWORD: "password", - CONF_SITE_ID: "default", - } - ) - - assert result["type"] == "form" - assert result["errors"] == {"base": "service_unavailable"} - - -async def test_controller_unkown_problem(hass, aioclient_mock): - """Test config flow.""" - flow = config_flow.UnifiFlowHandler() - flow.hass = hass - - with patch.object(config_flow, "get_controller", side_effect=Exception): - result = await flow.async_step_user( - { - CONF_HOST: "1.2.3.4", - CONF_USERNAME: "username", - CONF_PASSWORD: "password", - CONF_SITE_ID: "default", - } - ) - - assert result["type"] == "abort"