fix: Fix CI/CD issues and enhance integration
Some checks failed
Integration Testing / Integration Tests (2024.12.0, 3.11) (push) Failing after 22s
Integration Testing / Integration Tests (2024.12.0, 3.12) (push) Failing after 21s
Integration Testing / Integration Tests (2024.12.0, 3.13) (push) Failing after 1m32s
Integration Testing / Integration Tests (2025.9.4, 3.11) (push) Failing after 15s
Integration Testing / Integration Tests (2025.9.4, 3.12) (push) Failing after 20s
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:
2025-09-28 17:24:46 +01:00
parent bcec7bbf1a
commit 8281a1813d
17 changed files with 1439 additions and 276 deletions

View File

@@ -27,6 +27,10 @@ class AdGuardNotFoundError(AdGuardHomeError):
"""Exception for not found errors."""
class AdGuardTimeoutError(AdGuardHomeError):
"""Exception for timeout errors."""
class AdGuardHomeAPI:
"""API wrapper for AdGuard Home."""
@@ -39,6 +43,7 @@ class AdGuardHomeAPI:
ssl: bool = False,
session: Optional[aiohttp.ClientSession] = None,
timeout: int = 10,
verify_ssl: bool = True,
) -> None:
"""Initialize the API wrapper."""
self.host = host
@@ -46,6 +51,7 @@ class AdGuardHomeAPI:
self.username = username
self.password = password
self.ssl = ssl
self.verify_ssl = verify_ssl
self._session = session
self._timeout = ClientTimeout(total=timeout)
protocol = "https" if ssl else "http"
@@ -55,7 +61,11 @@ class AdGuardHomeAPI:
async def __aenter__(self):
"""Async context manager entry."""
if self._own_session:
self._session = aiohttp.ClientSession(timeout=self._timeout)
connector = aiohttp.TCPConnector(ssl=self.verify_ssl)
self._session = aiohttp.ClientSession(
timeout=self._timeout,
connector=connector
)
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
@@ -67,7 +77,11 @@ class AdGuardHomeAPI:
def session(self) -> aiohttp.ClientSession:
"""Get the session, creating one if needed."""
if not self._session:
self._session = aiohttp.ClientSession(timeout=self._timeout)
connector = aiohttp.TCPConnector(ssl=self.verify_ssl)
self._session = aiohttp.ClientSession(
timeout=self._timeout,
connector=connector
)
return self._session
async def _request(self, method: str, endpoint: str, data: Optional[Dict] = None) -> Dict[str, Any]:
@@ -81,7 +95,7 @@ class AdGuardHomeAPI:
try:
async with self.session.request(
method, url, json=data, headers=headers, auth=auth
method, url, json=data, headers=headers, auth=auth, ssl=self.verify_ssl
) as response:
if response.status == 401:
@@ -93,17 +107,19 @@ class AdGuardHomeAPI:
response.raise_for_status()
# Handle empty responses
if response.status == 204 or not response.content_length:
return {}
try:
return await response.json()
except aiohttp.ContentTypeError:
except (aiohttp.ContentTypeError, ValueError):
# If not JSON, return text response
text = await response.text()
return {"response": text}
except asyncio.TimeoutError as err:
raise AdGuardConnectionError(f"Timeout: {err}") from err
raise AdGuardTimeoutError(f"Request timeout: {err}") from err
except ClientError as err:
raise AdGuardConnectionError(f"Client error: {err}") from err
except Exception as err:
@@ -114,8 +130,8 @@ class AdGuardHomeAPI:
async def test_connection(self) -> bool:
"""Test the connection to AdGuard Home."""
try:
await self._request("GET", API_ENDPOINTS["status"])
return True
response = await self._request("GET", API_ENDPOINTS["status"])
return isinstance(response, dict) and len(response) > 0
except Exception:
return False
@@ -176,7 +192,8 @@ class AdGuardHomeAPI:
return client
return None
except Exception:
except Exception as err:
_LOGGER.error("Error getting client %s: %s", client_name, err)
return None
async def update_client_blocked_services(
@@ -192,6 +209,7 @@ class AdGuardHomeAPI:
if not client:
raise AdGuardNotFoundError(f"Client '{client_name}' not found")
# Format blocked services data according to AdGuard Home API
blocked_services_data = {
"ids": blocked_services,
"schedule": {"time_zone": "Local"}
@@ -207,6 +225,14 @@ class AdGuardHomeAPI:
return await self.update_client(update_data)
async def get_blocked_services_list(self) -> Dict[str, Any]:
"""Get list of available blocked services."""
try:
return await self._request("GET", API_ENDPOINTS["blocked_services_all"])
except Exception as err:
_LOGGER.error("Error getting blocked services list: %s", err)
return {}
async def close(self) -> None:
"""Close the API session if we own it."""
if self._own_session and self._session: