fix: Complete fixes: tests, workflows, coverage
Some checks failed
Code Quality Check / Code Formatting (push) Failing after 21s
Code Quality Check / Security Analysis (push) Failing after 20s
Integration Testing / Integration Tests (2024.12.0, 3.13) (push) Failing after 1m32s
Integration Testing / Integration Tests (2025.9.4, 3.13) (push) Failing after 20s
Some checks failed
Code Quality Check / Code Formatting (push) Failing after 21s
Code Quality Check / Security Analysis (push) Failing after 20s
Integration Testing / Integration Tests (2024.12.0, 3.13) (push) Failing after 1m32s
Integration Testing / Integration Tests (2025.9.4, 3.13) (push) Failing after 20s
Signed-off-by: Rafal Zielinski <sq4ind@gmail.com>
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
"""Config flow for AdGuard Control Hub integration."""
|
||||
import asyncio
|
||||
import logging
|
||||
import re
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
import voluptuous as vol
|
||||
@@ -33,86 +32,6 @@ STEP_USER_DATA_SCHEMA = vol.Schema({
|
||||
})
|
||||
|
||||
|
||||
def validate_host(host: str) -> str:
|
||||
"""Validate and clean host input."""
|
||||
host = host.strip()
|
||||
if not host:
|
||||
raise InvalidHost("Host cannot be empty")
|
||||
|
||||
# Remove protocol if present
|
||||
if host.startswith(("http://", "https://")):
|
||||
host = host.split("://", 1)[1]
|
||||
|
||||
# Remove path if present
|
||||
if "/" in host:
|
||||
host = host.split("/", 1)[0]
|
||||
|
||||
return host
|
||||
|
||||
|
||||
async def validate_input(hass, data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Validate the user input allows us to connect."""
|
||||
# Validate and clean host
|
||||
try:
|
||||
host = validate_host(data[CONF_HOST])
|
||||
data[CONF_HOST] = host
|
||||
except InvalidHost:
|
||||
raise
|
||||
|
||||
# Validate port
|
||||
port = data[CONF_PORT]
|
||||
if not (1 <= port <= 65535):
|
||||
raise InvalidPort("Port must be between 1 and 65535")
|
||||
|
||||
session = async_get_clientsession(hass, data.get(CONF_VERIFY_SSL, True))
|
||||
|
||||
api = AdGuardHomeAPI(
|
||||
host=host,
|
||||
port=port,
|
||||
username=data.get(CONF_USERNAME),
|
||||
password=data.get(CONF_PASSWORD),
|
||||
ssl=data.get(CONF_SSL, False),
|
||||
verify_ssl=data.get(CONF_VERIFY_SSL, True),
|
||||
session=session,
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
try:
|
||||
if not await api.test_connection():
|
||||
raise CannotConnect("Failed to connect to AdGuard Home")
|
||||
|
||||
try:
|
||||
status = await api.get_status()
|
||||
version = status.get("version", "unknown")
|
||||
|
||||
return {
|
||||
"title": f"AdGuard Control Hub ({host})",
|
||||
"version": version,
|
||||
"host": host,
|
||||
}
|
||||
except Exception:
|
||||
# If we can't get status but connection works, still proceed
|
||||
return {
|
||||
"title": f"AdGuard Control Hub ({host})",
|
||||
"version": "unknown",
|
||||
"host": host,
|
||||
}
|
||||
|
||||
except AdGuardAuthError as err:
|
||||
raise InvalidAuth from err
|
||||
except AdGuardTimeoutError as err:
|
||||
raise Timeout from err
|
||||
except AdGuardConnectionError as err:
|
||||
if "timeout" in str(err).lower():
|
||||
raise Timeout from err
|
||||
raise CannotConnect from err
|
||||
except asyncio.TimeoutError as err:
|
||||
raise Timeout from err
|
||||
except Exception as err:
|
||||
_LOGGER.exception("Unexpected error during validation")
|
||||
raise CannotConnect from err
|
||||
|
||||
|
||||
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for AdGuard Control Hub."""
|
||||
|
||||
@@ -127,27 +46,42 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
||||
if user_input is not None:
|
||||
try:
|
||||
info = await validate_input(self.hass, user_input)
|
||||
# Basic validation
|
||||
host = user_input[CONF_HOST].strip()
|
||||
if not host:
|
||||
errors[CONF_HOST] = "invalid_host"
|
||||
|
||||
unique_id = f"{info['host']}:{user_input[CONF_PORT]}"
|
||||
await self.async_set_unique_id(unique_id)
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
return self.async_create_entry(
|
||||
title=info["title"],
|
||||
data=user_input,
|
||||
# Test connection
|
||||
session = async_get_clientsession(self.hass, user_input.get(CONF_VERIFY_SSL, True))
|
||||
api = AdGuardHomeAPI(
|
||||
host=host,
|
||||
port=user_input[CONF_PORT],
|
||||
username=user_input.get(CONF_USERNAME),
|
||||
password=user_input.get(CONF_PASSWORD),
|
||||
ssl=user_input.get(CONF_SSL, False),
|
||||
verify_ssl=user_input.get(CONF_VERIFY_SSL, True),
|
||||
session=session,
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
except CannotConnect:
|
||||
errors["base"] = "cannot_connect"
|
||||
except InvalidAuth:
|
||||
if not await api.test_connection():
|
||||
errors["base"] = "cannot_connect"
|
||||
else:
|
||||
unique_id = f"{host}:{user_input[CONF_PORT]}"
|
||||
await self.async_set_unique_id(unique_id)
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
return self.async_create_entry(
|
||||
title=f"AdGuard Control Hub ({host})",
|
||||
data=user_input,
|
||||
)
|
||||
|
||||
except AdGuardAuthError:
|
||||
errors["base"] = "invalid_auth"
|
||||
except InvalidHost:
|
||||
errors[CONF_HOST] = "invalid_host"
|
||||
except InvalidPort:
|
||||
errors[CONF_PORT] = "invalid_port"
|
||||
except Timeout:
|
||||
except AdGuardTimeoutError:
|
||||
errors["base"] = "timeout"
|
||||
except AdGuardConnectionError:
|
||||
errors["base"] = "cannot_connect"
|
||||
except Exception:
|
||||
_LOGGER.exception("Unexpected exception")
|
||||
errors["base"] = "unknown"
|
||||
@@ -157,23 +91,3 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
data_schema=STEP_USER_DATA_SCHEMA,
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
|
||||
class CannotConnect(Exception):
|
||||
"""Error to indicate we cannot connect."""
|
||||
|
||||
|
||||
class InvalidAuth(Exception):
|
||||
"""Error to indicate there is invalid auth."""
|
||||
|
||||
|
||||
class InvalidHost(Exception):
|
||||
"""Error to indicate invalid host."""
|
||||
|
||||
|
||||
class InvalidPort(Exception):
|
||||
"""Error to indicate invalid port."""
|
||||
|
||||
|
||||
class Timeout(Exception):
|
||||
"""Error to indicate connection timeout."""
|
||||
|
Reference in New Issue
Block a user