"""Tests for the MB-Secure config flow.""" from unittest.mock import patch from homeassistant.config_entries import SOURCE_HASSIO, SOURCE_USER from homeassistant.const import CONF_HOST, CONF_PORT from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType from homeassistant.helpers.service_info.hassio import HassioServiceInfo from custom_components.mb_secure.api import BridgeAuthenticationError from custom_components.mb_secure.const import CONF_TOKEN, DOMAIN from custom_components.mb_secure.models import BridgeInfo USER_INPUT = { CONF_HOST: "bridge.local", CONF_PORT: 8099, CONF_TOKEN: "x" * 32, } async def test_user_flow_creates_entry_with_stable_bridge_id( hass: HomeAssistant, ) -> None: """Successful validation uses the installation ID as config entry ID.""" result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER} ) assert result["type"] is FlowResultType.FORM info = BridgeInfo( bridge_id="bridge-installation-1", bridge_version="0.1.0", api_version=1, connected=False, capabilities=frozenset({"snapshot", "events"}), ) with patch( "custom_components.mb_secure.api.BridgeClient.async_get_info", return_value=info, ): result = await hass.config_entries.flow.async_configure( result["flow_id"], USER_INPUT ) assert result["type"] is FlowResultType.CREATE_ENTRY assert result["data"] == USER_INPUT assert result["result"].unique_id == "bridge-installation-1" async def test_user_flow_reports_invalid_token(hass: HomeAssistant) -> None: """A rejected local bridge token remains inside the form flow.""" result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER} ) with patch( "custom_components.mb_secure.api.BridgeClient.async_get_info", side_effect=BridgeAuthenticationError, ): result = await hass.config_entries.flow.async_configure( result["flow_id"], USER_INPUT ) assert result["type"] is FlowResultType.FORM assert result["errors"] == {"base": "invalid_auth"} async def test_user_flow_rejects_bridge_without_stable_id( hass: HomeAssistant, ) -> None: """A bridge without an installation ID cannot create stable entities.""" result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER} ) info = BridgeInfo( bridge_id=None, bridge_version="0.1.0", api_version=1, connected=False, capabilities=frozenset(), ) with patch( "custom_components.mb_secure.api.BridgeClient.async_get_info", return_value=info, ): result = await hass.config_entries.flow.async_configure( result["flow_id"], USER_INPUT ) assert result["type"] is FlowResultType.FORM assert result["errors"] == {"base": "missing_bridge_id"} async def test_hassio_discovery_requires_confirmation_and_uses_bridge_id( hass: HomeAssistant, ) -> None: """Supervisor discovery remains user-confirmed and adopts the bridge ID.""" discovery = HassioServiceInfo( config=USER_INPUT, name="MB-Secure Bridge", slug="mb_secure_bridge", uuid="discovery-installation-1", ) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_HASSIO}, data=discovery, ) assert result["type"] is FlowResultType.FORM assert result["step_id"] == "hassio_confirm" info = BridgeInfo( bridge_id="bridge-installation-1", bridge_version="0.1.0", api_version=1, connected=True, capabilities=frozenset({"snapshot", "events"}), ) with patch( "custom_components.mb_secure.api.BridgeClient.async_get_info", return_value=info, ): result = await hass.config_entries.flow.async_configure(result["flow_id"], {}) assert result["type"] is FlowResultType.CREATE_ENTRY assert result["result"].unique_id == "bridge-installation-1" assert result["data"] == USER_INPUT async def test_hassio_discovery_rejects_incomplete_data( hass: HomeAssistant, ) -> None: """Supervisor discovery never guesses missing connection credentials.""" discovery = HassioServiceInfo( config={"host": "bridge.local"}, name="MB-Secure Bridge", slug="mb_secure_bridge", uuid="discovery-installation-1", ) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_HASSIO}, data=discovery, ) assert result["type"] is FlowResultType.ABORT assert result["reason"] == "invalid_discovery"