From cca6965cd19c3133830ae3c6b64c5bef30c061e1 Mon Sep 17 00:00:00 2001
From: David Bonnes <zxdavb@bonnes.me>
Date: Fri, 25 Oct 2024 12:23:17 +0100
Subject: [PATCH] Fix evohome regression preventing helpful messages when setup
 fails (#126441)

Co-authored-by: Robert Resch <robert@resch.dev>
---
 homeassistant/components/evohome/__init__.py |   2 +-
 tests/components/evohome/test_init.py        | 117 +++++++++++++++++++
 2 files changed, 118 insertions(+), 1 deletion(-)

diff --git a/homeassistant/components/evohome/__init__.py b/homeassistant/components/evohome/__init__.py
index 58e0e16e059..64994a4f63a 100644
--- a/homeassistant/components/evohome/__init__.py
+++ b/homeassistant/components/evohome/__init__.py
@@ -223,7 +223,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
             config[DOMAIN][CONF_PASSWORD],
         )
 
-    except evo.AuthenticationFailed as err:
+    except (evo.AuthenticationFailed, evo.RequestFailed) as err:
         handle_evo_exception(err)
         return False
 
diff --git a/tests/components/evohome/test_init.py b/tests/components/evohome/test_init.py
index b61efe9b066..968a5512641 100644
--- a/tests/components/evohome/test_init.py
+++ b/tests/components/evohome/test_init.py
@@ -2,11 +2,19 @@
 
 from __future__ import annotations
 
+from http import HTTPStatus
+import logging
+from unittest.mock import patch
+
+from evohomeasync2 import exceptions as exc
+from evohomeasync2.broker import _ERR_MSG_LOOKUP_AUTH, _ERR_MSG_LOOKUP_BASE
 from freezegun.api import FrozenDateTimeFactory
 import pytest
 from syrupy import SnapshotAssertion
 
+from homeassistant.components.evohome import DOMAIN
 from homeassistant.core import HomeAssistant
+from homeassistant.setup import async_setup_component
 
 from .conftest import setup_evohome
 from .const import TEST_INSTALLS
@@ -29,3 +37,112 @@ async def test_entities(
         pass
 
     assert hass.states.async_all() == snapshot
+
+
+SETUP_FAILED_ANTICIPATED = (
+    "homeassistant.setup",
+    logging.ERROR,
+    "Setup failed for 'evohome': Integration failed to initialize.",
+)
+SETUP_FAILED_UNEXPECTED = (
+    "homeassistant.setup",
+    logging.ERROR,
+    "Error during setup of component evohome",
+)
+AUTHENTICATION_FAILED = (
+    "homeassistant.components.evohome.helpers",
+    logging.ERROR,
+    "Failed to authenticate with the vendor's server. Check your username"
+    " and password. NB: Some special password characters that work"
+    " correctly via the website will not work via the web API. Message"
+    " is: ",
+)
+REQUEST_FAILED_NONE = (
+    "homeassistant.components.evohome.helpers",
+    logging.WARNING,
+    "Unable to connect with the vendor's server. "
+    "Check your network and the vendor's service status page. "
+    "Message is: ",
+)
+REQUEST_FAILED_503 = (
+    "homeassistant.components.evohome.helpers",
+    logging.WARNING,
+    "The vendor says their server is currently unavailable. "
+    "Check the vendor's service status page",
+)
+REQUEST_FAILED_429 = (
+    "homeassistant.components.evohome.helpers",
+    logging.WARNING,
+    "The vendor's API rate limit has been exceeded. "
+    "If this message persists, consider increasing the scan_interval",
+)
+
+REQUEST_FAILED_LOOKUP = {
+    None: [
+        REQUEST_FAILED_NONE,
+        SETUP_FAILED_ANTICIPATED,
+    ],
+    HTTPStatus.SERVICE_UNAVAILABLE: [
+        REQUEST_FAILED_503,
+        SETUP_FAILED_ANTICIPATED,
+    ],
+    HTTPStatus.TOO_MANY_REQUESTS: [
+        REQUEST_FAILED_429,
+        SETUP_FAILED_ANTICIPATED,
+    ],
+}
+
+
+@pytest.mark.parametrize(
+    "status", [*sorted([*_ERR_MSG_LOOKUP_AUTH, HTTPStatus.BAD_GATEWAY]), None]
+)
+async def test_authentication_failure_v2(
+    hass: HomeAssistant,
+    config: dict[str, str],
+    status: HTTPStatus,
+    caplog: pytest.LogCaptureFixture,
+) -> None:
+    """Test failure to setup an evohome-compatible system.
+
+    In this instance, the failure occurs in the v2 API.
+    """
+
+    with patch("evohomeasync2.broker.Broker.get") as mock_fcn:
+        mock_fcn.side_effect = exc.AuthenticationFailed("", status=status)
+
+        with caplog.at_level(logging.WARNING):
+            result = await async_setup_component(hass, DOMAIN, {DOMAIN: config})
+
+    assert result is False
+
+    assert caplog.record_tuples == [
+        AUTHENTICATION_FAILED,
+        SETUP_FAILED_ANTICIPATED,
+    ]
+
+
+@pytest.mark.parametrize(
+    "status", [*sorted([*_ERR_MSG_LOOKUP_BASE, HTTPStatus.BAD_GATEWAY]), None]
+)
+async def test_client_request_failure_v2(
+    hass: HomeAssistant,
+    config: dict[str, str],
+    status: HTTPStatus,
+    caplog: pytest.LogCaptureFixture,
+) -> None:
+    """Test failure to setup an evohome-compatible system.
+
+    In this instance, the failure occurs in the v2 API.
+    """
+
+    with patch("evohomeasync2.broker.Broker.get") as mock_fcn:
+        mock_fcn.side_effect = exc.RequestFailed("", status=status)
+
+        with caplog.at_level(logging.WARNING):
+            result = await async_setup_component(hass, DOMAIN, {DOMAIN: config})
+
+    assert result is False
+
+    assert caplog.record_tuples == REQUEST_FAILED_LOOKUP.get(
+        status, [SETUP_FAILED_UNEXPECTED]
+    )
-- 
GitLab