core/tests/components/wiz/test_config_flow.py

424 lines
13 KiB
Python
Raw Normal View History

"""Test the WiZ Platform config flow."""
from contextlib import contextmanager
from copy import deepcopy
from unittest.mock import patch
import pytest
from pywizlight.discovery import DiscoveredBulb
from pywizlight.exceptions import WizLightConnectionError, WizLightTimeOutError
from homeassistant import config_entries
from homeassistant.components import dhcp
from homeassistant.components.wiz.config_flow import CONF_DEVICE
from homeassistant.components.wiz.const import DOMAIN
from homeassistant.const import CONF_HOST
from homeassistant.data_entry_flow import RESULT_TYPE_ABORT, RESULT_TYPE_FORM
from tests.common import MockConfigEntry
FAKE_IP = "1.1.1.1"
FAKE_MAC = "ABCABCABCABC"
FAKE_BULB_CONFIG = {
"method": "getSystemConfig",
"env": "pro",
"result": {
"mac": FAKE_MAC,
"homeId": 653906,
"roomId": 989983,
"moduleName": "ESP_0711_STR",
"fwVersion": "1.21.0",
"groupId": 0,
"drvConf": [20, 2],
"ewf": [255, 0, 255, 255, 0, 0, 0],
"ewfHex": "ff00ffff000000",
"ping": 0,
},
}
FAKE_SOCKET_CONFIG = deepcopy(FAKE_BULB_CONFIG)
FAKE_SOCKET_CONFIG["result"]["moduleName"] = "ESP10_SOCKET_06"
FAKE_EXTENDED_WHITE_RANGE = [2200, 2700, 6500, 6500]
TEST_SYSTEM_INFO = {"id": FAKE_MAC, "name": "Test Bulb"}
TEST_CONNECTION = {CONF_HOST: "1.1.1.1"}
TEST_NO_IP = {CONF_HOST: "this is no IP input"}
DHCP_DISCOVERY = dhcp.DhcpServiceInfo(
hostname="wiz_abcabc",
ip=FAKE_IP,
macaddress=FAKE_MAC,
)
INTEGRATION_DISCOVERY = {
"ip_address": FAKE_IP,
"mac_address": FAKE_MAC,
}
def _patch_wizlight(device=None, extended_white_range=None):
@contextmanager
def _patcher():
with patch(
"homeassistant.components.wiz.wizlight.getBulbConfig",
return_value=device or FAKE_BULB_CONFIG,
), patch(
"homeassistant.components.wiz.wizlight.getExtendedWhiteRange",
return_value=extended_white_range or FAKE_EXTENDED_WHITE_RANGE,
), patch(
"homeassistant.components.wiz.wizlight.getMac",
return_value=FAKE_MAC,
):
yield
return _patcher()
def _patch_discovery():
@contextmanager
def _patcher():
with patch(
"homeassistant.components.wiz.discovery.find_wizlights",
return_value=[DiscoveredBulb(FAKE_IP, FAKE_MAC)],
):
yield
return _patcher()
async def test_form(hass):
"""Test we get the form."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == "form"
assert result["errors"] == {}
# Patch functions
with _patch_wizlight(), patch(
"homeassistant.components.wiz.async_setup_entry",
return_value=True,
) as mock_setup_entry, patch(
"homeassistant.components.wiz.async_setup", return_value=True
) as mock_setup:
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
TEST_CONNECTION,
)
await hass.async_block_till_done()
assert result2["type"] == "create_entry"
assert result2["title"] == "WiZ Dimmable White ABCABC"
assert result2["data"] == {
CONF_HOST: "1.1.1.1",
}
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
async def test_user_flow_enters_dns_name(hass):
"""Test we reject dns names and want ips."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == "form"
assert result["errors"] == {}
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_HOST: "ip.only"},
)
await hass.async_block_till_done()
assert result2["type"] == RESULT_TYPE_FORM
assert result2["errors"] == {"base": "no_ip"}
with _patch_wizlight(), patch(
"homeassistant.components.wiz.async_setup_entry",
return_value=True,
) as mock_setup_entry, patch(
"homeassistant.components.wiz.async_setup", return_value=True
) as mock_setup:
result3 = await hass.config_entries.flow.async_configure(
result2["flow_id"],
TEST_CONNECTION,
)
await hass.async_block_till_done()
assert result3["type"] == "create_entry"
assert result3["title"] == "WiZ Dimmable White ABCABC"
assert result3["data"] == {
CONF_HOST: "1.1.1.1",
}
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
@pytest.mark.parametrize(
"side_effect, error_base",
[
(WizLightTimeOutError, "bulb_time_out"),
(WizLightConnectionError, "no_wiz_light"),
(Exception, "unknown"),
(ConnectionRefusedError, "cannot_connect"),
],
)
async def test_user_form_exceptions(hass, side_effect, error_base):
"""Test all user exceptions in the flow."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch(
"homeassistant.components.wiz.wizlight.getBulbConfig",
side_effect=side_effect,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
TEST_CONNECTION,
)
assert result2["type"] == "form"
assert result2["errors"] == {"base": error_base}
async def test_form_updates_unique_id(hass):
"""Test a duplicate id aborts and updates existing entry."""
entry = MockConfigEntry(
domain=DOMAIN,
unique_id=TEST_SYSTEM_INFO["id"],
data={CONF_HOST: "dummy"},
)
entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with _patch_wizlight():
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
TEST_CONNECTION,
)
await hass.async_block_till_done()
assert result2["type"] == "abort"
assert result2["reason"] == "already_configured"
assert entry.data[CONF_HOST] == FAKE_IP
@pytest.mark.parametrize(
"source, data",
[
(config_entries.SOURCE_DHCP, DHCP_DISCOVERY),
(config_entries.SOURCE_INTEGRATION_DISCOVERY, INTEGRATION_DISCOVERY),
],
)
async def test_discovered_by_dhcp_connection_fails(hass, source, data):
"""Test we abort on connection failure."""
with patch(
"homeassistant.components.wiz.wizlight.getBulbConfig",
side_effect=WizLightTimeOutError,
):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": source}, data=data
)
await hass.async_block_till_done()
assert result["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "cannot_connect"
@pytest.mark.parametrize(
"source, data, device, extended_white_range, name",
[
(
config_entries.SOURCE_DHCP,
DHCP_DISCOVERY,
FAKE_BULB_CONFIG,
FAKE_EXTENDED_WHITE_RANGE,
"WiZ Dimmable White ABCABC",
),
(
config_entries.SOURCE_INTEGRATION_DISCOVERY,
INTEGRATION_DISCOVERY,
FAKE_BULB_CONFIG,
FAKE_EXTENDED_WHITE_RANGE,
"WiZ Dimmable White ABCABC",
),
(
config_entries.SOURCE_DHCP,
DHCP_DISCOVERY,
FAKE_SOCKET_CONFIG,
None,
"WiZ Socket ABCABC",
),
(
config_entries.SOURCE_INTEGRATION_DISCOVERY,
INTEGRATION_DISCOVERY,
FAKE_SOCKET_CONFIG,
None,
"WiZ Socket ABCABC",
),
],
)
async def test_discovered_by_dhcp_or_integration_discovery(
hass, source, data, device, extended_white_range, name
):
"""Test we can configure when discovered from dhcp or discovery."""
with _patch_wizlight(device=device, extended_white_range=extended_white_range):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": source}, data=data
)
await hass.async_block_till_done()
assert result["type"] == RESULT_TYPE_FORM
assert result["step_id"] == "discovery_confirm"
with patch(
"homeassistant.components.wiz.async_setup_entry",
return_value=True,
) as mock_setup_entry, patch(
"homeassistant.components.wiz.async_setup", return_value=True
) as mock_setup:
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{},
)
await hass.async_block_till_done()
assert result2["type"] == "create_entry"
assert result2["title"] == name
assert result2["data"] == {
CONF_HOST: "1.1.1.1",
}
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
@pytest.mark.parametrize(
"source, data",
[
(config_entries.SOURCE_DHCP, DHCP_DISCOVERY),
(config_entries.SOURCE_INTEGRATION_DISCOVERY, INTEGRATION_DISCOVERY),
],
)
async def test_discovered_by_dhcp_or_integration_discovery_updates_host(
hass, source, data
):
"""Test dhcp or discovery updates existing host."""
entry = MockConfigEntry(
domain=DOMAIN,
unique_id=TEST_SYSTEM_INFO["id"],
data={CONF_HOST: "dummy"},
)
entry.add_to_hass(hass)
with _patch_wizlight():
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": source}, data=data
)
await hass.async_block_till_done()
assert result["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "already_configured"
assert entry.data[CONF_HOST] == FAKE_IP
async def test_setup_via_discovery(hass):
"""Test setting up via discovery."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
await hass.async_block_till_done()
assert result["type"] == "form"
assert result["step_id"] == "user"
assert not result["errors"]
with _patch_discovery():
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
await hass.async_block_till_done()
assert result2["type"] == "form"
assert result2["step_id"] == "pick_device"
assert not result2["errors"]
# test we can try again
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == "form"
assert result["step_id"] == "user"
assert not result["errors"]
with _patch_discovery():
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
await hass.async_block_till_done()
assert result2["type"] == "form"
assert result2["step_id"] == "pick_device"
assert not result2["errors"]
with _patch_wizlight(), patch(
"homeassistant.components.wiz.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.wiz.async_setup_entry", return_value=True
) as mock_setup_entry:
result3 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_DEVICE: FAKE_MAC},
)
await hass.async_block_till_done()
assert result3["type"] == "create_entry"
assert result3["title"] == "WiZ Dimmable White ABCABC"
assert result3["data"] == {
CONF_HOST: "1.1.1.1",
}
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
# ignore configured devices
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == "form"
assert result["step_id"] == "user"
assert not result["errors"]
with _patch_discovery():
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
await hass.async_block_till_done()
assert result2["type"] == "abort"
assert result2["reason"] == "no_devices_found"
async def test_setup_via_discovery_cannot_connect(hass):
"""Test setting up via discovery and we fail to connect to the discovered device."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
await hass.async_block_till_done()
assert result["type"] == "form"
assert result["step_id"] == "user"
assert not result["errors"]
with _patch_discovery():
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
await hass.async_block_till_done()
assert result2["type"] == "form"
assert result2["step_id"] == "pick_device"
assert not result2["errors"]
with patch(
"homeassistant.components.wiz.wizlight.getBulbConfig",
side_effect=WizLightTimeOutError,
), _patch_discovery():
result3 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_DEVICE: FAKE_MAC},
)
await hass.async_block_till_done()
assert result3["type"] == "abort"
assert result3["reason"] == "cannot_connect"