core/tests/components/velbus/test_config_flow.py
Maikel Punie 4176776d70
Fix optional password in Velbus config flow (#140615)
* Fix velbusconfigflow

* add tests

* Paramtize the tests

* Removed duplicate test in favor of another case

* more comments
2025-03-18 14:49:27 +00:00

238 lines
7.3 KiB
Python

"""Tests for the Velbus config flow."""
from collections.abc import Generator
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
import serial.tools.list_ports
from velbusaio.exceptions import VelbusConnectionFailed
from homeassistant.components.velbus.const import CONF_TLS, DOMAIN
from homeassistant.config_entries import SOURCE_USB, SOURCE_USER
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_SOURCE
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from homeassistant.helpers.service_info.usb import UsbServiceInfo
from .const import PORT_SERIAL
from tests.common import MockConfigEntry
DISCOVERY_INFO = UsbServiceInfo(
device=PORT_SERIAL,
pid="10CF",
vid="0B1B",
serial_number="1234",
description="Velbus VMB1USB",
manufacturer="Velleman",
)
USB_DEV = "/dev/ttyACME100 - Some serial port, s/n: 1234 - Virtual serial port"
def com_port():
"""Mock of a serial port."""
port = serial.tools.list_ports_common.ListPortInfo(PORT_SERIAL)
port.serial_number = "1234"
port.manufacturer = "Virtual serial port"
port.device = PORT_SERIAL
port.description = "Some serial port"
return port
@pytest.fixture(autouse=True)
def override_async_setup_entry() -> Generator[AsyncMock]:
"""Override async_setup_entry."""
with (
patch(
"homeassistant.components.velbus.async_setup_entry", return_value=True
) as mock,
):
yield mock
@pytest.fixture(name="controller_connection_failed")
def mock_controller_connection_failed():
"""Mock the velbus controller with an assert."""
with patch("velbusaio.controller.Velbus", side_effect=VelbusConnectionFailed()):
yield
@pytest.mark.usefixtures("controller")
@pytest.mark.parametrize(
("inputParams", "expected"),
[
(
{
CONF_TLS: True,
CONF_PASSWORD: "password",
},
"tls://password@velbus:6000",
),
(
{
CONF_TLS: True,
CONF_PASSWORD: "",
},
"tls://velbus:6000",
),
({CONF_TLS: True}, "tls://velbus:6000"),
({CONF_TLS: False}, "velbus:6000"),
],
)
async def test_user_network_succes(
hass: HomeAssistant, inputParams: str, expected: str
) -> None:
"""Test user network config."""
# inttial menu show
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result
assert result.get("flow_id")
assert result.get("type") is FlowResultType.MENU
assert result.get("step_id") == "user"
assert result.get("menu_options") == ["network", "usbselect"]
# select the network option
result = await hass.config_entries.flow.async_configure(
result.get("flow_id"),
{"next_step_id": "network"},
)
assert result["type"] is FlowResultType.FORM
# fill in the network form
result = await hass.config_entries.flow.async_configure(
result.get("flow_id"),
{
CONF_HOST: "velbus",
CONF_PORT: 6000,
**inputParams,
},
)
assert result
assert result.get("type") is FlowResultType.CREATE_ENTRY
assert result.get("title") == "Velbus Network"
data = result.get("data")
assert data
assert data[CONF_PORT] == expected
@pytest.mark.usefixtures("controller")
@patch("serial.tools.list_ports.comports", MagicMock(return_value=[com_port()]))
async def test_user_usb_succes(hass: HomeAssistant) -> None:
"""Test user usb step."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
result = await hass.config_entries.flow.async_configure(
result.get("flow_id"),
{"next_step_id": "usbselect"},
)
assert result["type"] is FlowResultType.FORM
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_PORT: USB_DEV,
},
)
assert result
assert result.get("type") is FlowResultType.CREATE_ENTRY
assert result.get("title") == "Velbus USB"
data = result.get("data")
assert data
assert data[CONF_PORT] == PORT_SERIAL
@pytest.mark.usefixtures("controller")
async def test_network_abort_if_already_setup(hass: HomeAssistant) -> None:
"""Test we abort if Velbus is already setup."""
entry = MockConfigEntry(
domain=DOMAIN,
data={CONF_PORT: "127.0.0.1:3788"},
)
entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
result = await hass.config_entries.flow.async_configure(
result.get("flow_id"),
{"next_step_id": "network"},
)
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_TLS: False,
CONF_HOST: "127.0.0.1",
CONF_PORT: 3788,
CONF_PASSWORD: "",
},
)
assert result
assert result.get("type") is FlowResultType.ABORT
assert result.get("reason") == "already_configured"
@pytest.mark.usefixtures("controller")
@patch("serial.tools.list_ports.comports", MagicMock(return_value=[com_port()]))
async def test_flow_usb(hass: HomeAssistant) -> None:
"""Test usb discovery flow."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={CONF_SOURCE: SOURCE_USB},
data=DISCOVERY_INFO,
)
assert result
assert result.get("type") is FlowResultType.FORM
assert result.get("step_id") == "discovery_confirm"
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={},
)
assert result
assert result["result"].unique_id == "1234"
assert result.get("type") is FlowResultType.CREATE_ENTRY
@pytest.mark.usefixtures("controller")
@patch("serial.tools.list_ports.comports", MagicMock(return_value=[com_port()]))
async def test_flow_usb_if_already_setup(hass: HomeAssistant) -> None:
"""Test we abort if Velbus USB discovbery aborts in case it is already setup."""
entry = MockConfigEntry(
domain=DOMAIN,
data={CONF_PORT: PORT_SERIAL},
)
entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
result = await hass.config_entries.flow.async_configure(
result.get("flow_id"),
{"next_step_id": "usbselect"},
)
assert result
assert result["type"] is FlowResultType.FORM
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_PORT: USB_DEV,
},
)
assert result
assert result.get("type") is FlowResultType.ABORT
assert result.get("reason") == "already_configured"
@pytest.mark.usefixtures("controller_connection_failed")
@patch("serial.tools.list_ports.comports", MagicMock(return_value=[com_port()]))
async def test_flow_usb_failed(hass: HomeAssistant) -> None:
"""Test usb discovery flow with a failed velbus test."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={CONF_SOURCE: SOURCE_USB},
data=DISCOVERY_INFO,
)
assert result
assert result.get("type") is FlowResultType.ABORT
assert result.get("reason") == "cannot_connect"