From 1031e416beec1403a88697d3ed0e99ac809960c9 Mon Sep 17 00:00:00 2001
From: Renat Sibgatulin <renat.sibgatulin@gmail.com>
Date: Wed, 27 Dec 2023 09:56:13 +0100
Subject: [PATCH] Remove IP / mDNS validation in airq integration setup
 (#106326)

Original design relied on aioairq.AirQ.__init__ checking if the input
was a valid IP address or an mDNS of a very specific structure,
and raising an InvalidInput otherwise.
Now, aioairq==0.3.2 removes said check completely following a user's
request to allow arbitrary host name and DNS entries.
In the config flow, "cannot_connect" covers the cases of misspelled
inputs now, which previously were covered by a dedicated "invalid_input"
---
 homeassistant/components/airq/config_flow.py | 52 ++++++++------------
 homeassistant/components/airq/manifest.json  |  2 +-
 requirements_all.txt                         |  2 +-
 requirements_test_all.txt                    |  2 +-
 tests/components/airq/test_config_flow.py    | 17 +------
 5 files changed, 24 insertions(+), 51 deletions(-)

diff --git a/homeassistant/components/airq/config_flow.py b/homeassistant/components/airq/config_flow.py
index 41eda912e98..33d76ec75bc 100644
--- a/homeassistant/components/airq/config_flow.py
+++ b/homeassistant/components/airq/config_flow.py
@@ -4,7 +4,7 @@ from __future__ import annotations
 import logging
 from typing import Any
 
-from aioairq import AirQ, InvalidAuth, InvalidInput
+from aioairq import AirQ, InvalidAuth
 from aiohttp.client_exceptions import ClientConnectionError
 import voluptuous as vol
 
@@ -42,44 +42,32 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
         errors: dict[str, str] = {}
 
         session = async_get_clientsession(self.hass)
+        airq = AirQ(user_input[CONF_IP_ADDRESS], user_input[CONF_PASSWORD], session)
         try:
-            airq = AirQ(user_input[CONF_IP_ADDRESS], user_input[CONF_PASSWORD], session)
-        except InvalidInput:
+            await airq.validate()
+        except ClientConnectionError:
             _LOGGER.debug(
-                "%s does not appear to be a valid IP address or mDNS name",
+                (
+                    "Failed to connect to device %s. Check the IP address / device"
+                    " ID as well as whether the device is connected to power and"
+                    " the WiFi"
+                ),
                 user_input[CONF_IP_ADDRESS],
             )
-            errors["base"] = "invalid_input"
+            errors["base"] = "cannot_connect"
+        except InvalidAuth:
+            _LOGGER.debug(
+                "Incorrect password for device %s", user_input[CONF_IP_ADDRESS]
+            )
+            errors["base"] = "invalid_auth"
         else:
-            try:
-                await airq.validate()
-            except ClientConnectionError:
-                _LOGGER.debug(
-                    (
-                        "Failed to connect to device %s. Check the IP address / device"
-                        " ID as well as whether the device is connected to power and"
-                        " the WiFi"
-                    ),
-                    user_input[CONF_IP_ADDRESS],
-                )
-                errors["base"] = "cannot_connect"
-            except InvalidAuth:
-                _LOGGER.debug(
-                    "Incorrect password for device %s", user_input[CONF_IP_ADDRESS]
-                )
-                errors["base"] = "invalid_auth"
-            else:
-                _LOGGER.debug(
-                    "Successfully connected to %s", user_input[CONF_IP_ADDRESS]
-                )
+            _LOGGER.debug("Successfully connected to %s", user_input[CONF_IP_ADDRESS])
 
-                device_info = await airq.fetch_device_info()
-                await self.async_set_unique_id(device_info["id"])
-                self._abort_if_unique_id_configured()
+            device_info = await airq.fetch_device_info()
+            await self.async_set_unique_id(device_info["id"])
+            self._abort_if_unique_id_configured()
 
-                return self.async_create_entry(
-                    title=device_info["name"], data=user_input
-                )
+            return self.async_create_entry(title=device_info["name"], data=user_input)
 
         return self.async_show_form(
             step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
diff --git a/homeassistant/components/airq/manifest.json b/homeassistant/components/airq/manifest.json
index 156f167913b..2b23928aba8 100644
--- a/homeassistant/components/airq/manifest.json
+++ b/homeassistant/components/airq/manifest.json
@@ -7,5 +7,5 @@
   "integration_type": "hub",
   "iot_class": "local_polling",
   "loggers": ["aioairq"],
-  "requirements": ["aioairq==0.3.1"]
+  "requirements": ["aioairq==0.3.2"]
 }
diff --git a/requirements_all.txt b/requirements_all.txt
index 47a37387974..68f9686f561 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -185,7 +185,7 @@ aio-geojson-usgs-earthquakes==0.2
 aio-georss-gdacs==0.8
 
 # homeassistant.components.airq
-aioairq==0.3.1
+aioairq==0.3.2
 
 # homeassistant.components.airzone_cloud
 aioairzone-cloud==0.3.6
diff --git a/requirements_test_all.txt b/requirements_test_all.txt
index 83df72a45c2..3fe7adabc2c 100644
--- a/requirements_test_all.txt
+++ b/requirements_test_all.txt
@@ -164,7 +164,7 @@ aio-geojson-usgs-earthquakes==0.2
 aio-georss-gdacs==0.8
 
 # homeassistant.components.airq
-aioairq==0.3.1
+aioairq==0.3.2
 
 # homeassistant.components.airzone_cloud
 aioairzone-cloud==0.3.6
diff --git a/tests/components/airq/test_config_flow.py b/tests/components/airq/test_config_flow.py
index 52fc8d2300b..1619440a6f7 100644
--- a/tests/components/airq/test_config_flow.py
+++ b/tests/components/airq/test_config_flow.py
@@ -1,7 +1,7 @@
 """Test the air-Q config flow."""
 from unittest.mock import patch
 
-from aioairq import DeviceInfo, InvalidAuth, InvalidInput
+from aioairq import DeviceInfo, InvalidAuth
 from aiohttp.client_exceptions import ClientConnectionError
 import pytest
 
@@ -80,21 +80,6 @@ async def test_form_cannot_connect(hass: HomeAssistant) -> None:
     assert result2["errors"] == {"base": "cannot_connect"}
 
 
-async def test_form_invalid_input(hass: HomeAssistant) -> None:
-    """Test we handle cannot connect error."""
-    result = await hass.config_entries.flow.async_init(
-        DOMAIN, context={"source": config_entries.SOURCE_USER}
-    )
-
-    with patch("aioairq.AirQ.validate", side_effect=InvalidInput):
-        result2 = await hass.config_entries.flow.async_configure(
-            result["flow_id"], TEST_USER_DATA | {CONF_IP_ADDRESS: "invalid_ip"}
-        )
-
-    assert result2["type"] == FlowResultType.FORM
-    assert result2["errors"] == {"base": "invalid_input"}
-
-
 async def test_duplicate_error(hass: HomeAssistant) -> None:
     """Test that errors are shown when duplicates are added."""
     MockConfigEntry(