"""Tests for the GogoGate2 component.""" from unittest.mock import MagicMock, patch from ismartgate import GogoGate2Api, ISmartGateApi from ismartgate.common import ApiError from ismartgate.const import GogoGate2ApiErrorCode from homeassistant import config_entries from homeassistant.components import dhcp, zeroconf from homeassistant.components.gogogate2.const import ( DEVICE_TYPE_GOGOGATE2, DEVICE_TYPE_ISMARTGATE, DOMAIN, ) from homeassistant.config_entries import SOURCE_USER from homeassistant.const import ( CONF_DEVICE, CONF_IP_ADDRESS, CONF_PASSWORD, CONF_USERNAME, ) from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import ( RESULT_TYPE_ABORT, RESULT_TYPE_CREATE_ENTRY, RESULT_TYPE_FORM, ) from . import _mocked_ismartgate_closed_door_response from tests.common import MockConfigEntry MOCK_MAC_ADDR = "AA:BB:CC:DD:EE:FF" @patch("homeassistant.components.gogogate2.async_setup_entry", return_value=True) @patch("homeassistant.components.gogogate2.common.GogoGate2Api") async def test_auth_fail( gogogate2api_mock, async_setup_entry_mock, hass: HomeAssistant ) -> None: """Test authorization failures.""" api: GogoGate2Api = MagicMock(spec=GogoGate2Api) gogogate2api_mock.return_value = api api.reset_mock() api.async_info.side_effect = ApiError( GogoGate2ApiErrorCode.CREDENTIALS_INCORRECT, "blah" ) result = await hass.config_entries.flow.async_init( "gogogate2", context={"source": SOURCE_USER} ) result = await hass.config_entries.flow.async_configure( result["flow_id"], user_input={ CONF_DEVICE: DEVICE_TYPE_GOGOGATE2, CONF_IP_ADDRESS: "127.0.0.2", CONF_USERNAME: "user0", CONF_PASSWORD: "password0", }, ) assert result assert result["type"] == RESULT_TYPE_FORM assert result["errors"] == { "base": "invalid_auth", } api.reset_mock() api.async_info.side_effect = Exception("Generic connection error.") result = await hass.config_entries.flow.async_init( "gogogate2", context={"source": SOURCE_USER} ) result = await hass.config_entries.flow.async_configure( result["flow_id"], user_input={ CONF_DEVICE: DEVICE_TYPE_GOGOGATE2, CONF_IP_ADDRESS: "127.0.0.2", CONF_USERNAME: "user0", CONF_PASSWORD: "password0", }, ) assert result assert result["type"] == RESULT_TYPE_FORM assert result["errors"] == {"base": "cannot_connect"} api.reset_mock() api.async_info.side_effect = ApiError(0, "blah") result = await hass.config_entries.flow.async_init( "gogogate2", context={"source": SOURCE_USER} ) result = await hass.config_entries.flow.async_configure( result["flow_id"], user_input={ CONF_DEVICE: DEVICE_TYPE_GOGOGATE2, CONF_IP_ADDRESS: "127.0.0.2", CONF_USERNAME: "user0", CONF_PASSWORD: "password0", }, ) assert result assert result["type"] == RESULT_TYPE_FORM assert result["errors"] == {"base": "cannot_connect"} async def test_form_homekit_unique_id_already_setup(hass): """Test that we abort from homekit if gogogate2 is already setup.""" result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_HOMEKIT}, data=zeroconf.ZeroconfServiceInfo( host="1.2.3.4", addresses=["1.2.3.4"], hostname="mock_hostname", name="mock_name", port=None, properties={zeroconf.ATTR_PROPERTIES_ID: MOCK_MAC_ADDR}, type="mock_type", ), ) assert result["type"] == RESULT_TYPE_FORM assert result["errors"] == {} flow = next( flow for flow in hass.config_entries.flow.async_progress() if flow["flow_id"] == result["flow_id"] ) assert flow["context"]["unique_id"] == MOCK_MAC_ADDR entry = MockConfigEntry( domain=DOMAIN, data={CONF_IP_ADDRESS: "1.2.3.4", CONF_USERNAME: "mock", CONF_PASSWORD: "mock"}, ) entry.add_to_hass(hass) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_HOMEKIT}, data=zeroconf.ZeroconfServiceInfo( host="1.2.3.4", addresses=["1.2.3.4"], hostname="mock_hostname", name="mock_name", port=None, properties={zeroconf.ATTR_PROPERTIES_ID: MOCK_MAC_ADDR}, type="mock_type", ), ) assert result["type"] == RESULT_TYPE_ABORT async def test_form_homekit_ip_address_already_setup(hass): """Test that we abort from homekit if gogogate2 is already setup.""" entry = MockConfigEntry( domain=DOMAIN, data={CONF_IP_ADDRESS: "1.2.3.4", CONF_USERNAME: "mock", CONF_PASSWORD: "mock"}, ) entry.add_to_hass(hass) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_HOMEKIT}, data=zeroconf.ZeroconfServiceInfo( host="1.2.3.4", addresses=["1.2.3.4"], hostname="mock_hostname", name="mock_name", port=None, properties={zeroconf.ATTR_PROPERTIES_ID: MOCK_MAC_ADDR}, type="mock_type", ), ) assert result["type"] == RESULT_TYPE_ABORT async def test_form_homekit_ip_address(hass): """Test homekit includes the defaults ip address.""" result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_HOMEKIT}, data=zeroconf.ZeroconfServiceInfo( host="1.2.3.4", addresses=["1.2.3.4"], hostname="mock_hostname", name="mock_name", port=None, properties={zeroconf.ATTR_PROPERTIES_ID: MOCK_MAC_ADDR}, type="mock_type", ), ) assert result["type"] == RESULT_TYPE_FORM assert result["errors"] == {} data_schema = result["data_schema"] assert data_schema({CONF_USERNAME: "username", CONF_PASSWORD: "password"}) == { CONF_DEVICE: DEVICE_TYPE_ISMARTGATE, CONF_IP_ADDRESS: "1.2.3.4", CONF_PASSWORD: "password", CONF_USERNAME: "username", } @patch("homeassistant.components.gogogate2.async_setup_entry", return_value=True) @patch("homeassistant.components.gogogate2.common.ISmartGateApi") async def test_discovered_dhcp( ismartgateapi_mock, async_setup_entry_mock, hass ) -> None: """Test we get the form with homekit and abort for dhcp source when we get both.""" api: ISmartGateApi = MagicMock(spec=ISmartGateApi) ismartgateapi_mock.return_value = api api.reset_mock() result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_DHCP}, data=dhcp.DhcpServiceInfo( ip="1.2.3.4", macaddress=MOCK_MAC_ADDR, hostname="mock_hostname" ), ) assert result["type"] == RESULT_TYPE_FORM assert result["errors"] == {} result2 = await hass.config_entries.flow.async_configure( result["flow_id"], user_input={ CONF_DEVICE: DEVICE_TYPE_ISMARTGATE, CONF_IP_ADDRESS: "1.2.3.4", CONF_USERNAME: "user0", CONF_PASSWORD: "password0", }, ) assert result2 assert result2["type"] == RESULT_TYPE_FORM assert result2["errors"] == {"base": "cannot_connect"} api.reset_mock() closed_door_response = _mocked_ismartgate_closed_door_response() api.async_info.return_value = closed_door_response result3 = await hass.config_entries.flow.async_configure( result2["flow_id"], user_input={ CONF_DEVICE: DEVICE_TYPE_ISMARTGATE, CONF_IP_ADDRESS: "1.2.3.4", CONF_USERNAME: "user0", CONF_PASSWORD: "password0", }, ) assert result3 assert result3["type"] == RESULT_TYPE_CREATE_ENTRY assert result3["data"] == { "device": "ismartgate", "ip_address": "1.2.3.4", "password": "password0", "username": "user0", } async def test_discovered_by_homekit_and_dhcp(hass): """Test we get the form with homekit and abort for dhcp source when we get both.""" result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_HOMEKIT}, data=zeroconf.ZeroconfServiceInfo( host="1.2.3.4", addresses=["1.2.3.4"], hostname="mock_hostname", name="mock_name", port=None, properties={zeroconf.ATTR_PROPERTIES_ID: MOCK_MAC_ADDR}, type="mock_type", ), ) assert result["type"] == RESULT_TYPE_FORM assert result["errors"] == {} result2 = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_DHCP}, data=dhcp.DhcpServiceInfo( ip="1.2.3.4", macaddress=MOCK_MAC_ADDR, hostname="mock_hostname" ), ) assert result2["type"] == RESULT_TYPE_ABORT assert result2["reason"] == "already_in_progress" result3 = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_DHCP}, data=dhcp.DhcpServiceInfo( ip="1.2.3.4", macaddress="00:00:00:00:00:00", hostname="mock_hostname" ), ) assert result3["type"] == RESULT_TYPE_ABORT assert result3["reason"] == "already_in_progress"