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>
289 lines
10 KiB
Python
289 lines
10 KiB
Python
"""Test API functionality."""
|
|
import pytest
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
from aiohttp import ClientError, ClientTimeout
|
|
|
|
from custom_components.adguard_hub.api import (
|
|
AdGuardHomeAPI,
|
|
AdGuardHomeError,
|
|
AdGuardConnectionError,
|
|
AdGuardAuthError,
|
|
AdGuardNotFoundError,
|
|
AdGuardTimeoutError,
|
|
)
|
|
|
|
|
|
class TestAdGuardHomeAPI:
|
|
"""Test the AdGuard Home API wrapper."""
|
|
|
|
def test_api_initialization(self):
|
|
"""Test API initialization."""
|
|
api = AdGuardHomeAPI(
|
|
host="192.168.1.100",
|
|
port=3000,
|
|
username="admin",
|
|
password="password",
|
|
ssl=True,
|
|
)
|
|
|
|
assert api.host == "192.168.1.100"
|
|
assert api.port == 3000
|
|
assert api.username == "admin"
|
|
assert api.password == "password"
|
|
assert api.ssl is True
|
|
assert api.base_url == "https://192.168.1.100:3000"
|
|
|
|
def test_api_initialization_defaults(self):
|
|
"""Test API initialization with defaults."""
|
|
api = AdGuardHomeAPI(host="192.168.1.100")
|
|
|
|
assert api.host == "192.168.1.100"
|
|
assert api.port == 3000
|
|
assert api.username is None
|
|
assert api.password is None
|
|
assert api.ssl is False
|
|
assert api.base_url == "http://192.168.1.100:3000"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_api_context_manager(self):
|
|
"""Test API as async context manager."""
|
|
async with AdGuardHomeAPI(host="192.168.1.100", port=3000) as api:
|
|
assert api is not None
|
|
assert api.host == "192.168.1.100"
|
|
assert api.port == 3000
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_test_connection_success(self, mock_aiohttp_session):
|
|
"""Test successful connection test."""
|
|
mock_aiohttp_session.request.return_value.__aenter__.return_value.json = AsyncMock(
|
|
return_value={"protection_enabled": True}
|
|
)
|
|
|
|
api = AdGuardHomeAPI(host="192.168.1.100", session=mock_aiohttp_session)
|
|
result = await api.test_connection()
|
|
|
|
assert result is True
|
|
mock_aiohttp_session.request.assert_called()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_test_connection_failure(self, mock_aiohttp_session):
|
|
"""Test failed connection test."""
|
|
mock_aiohttp_session.request.side_effect = ClientError("Connection failed")
|
|
|
|
api = AdGuardHomeAPI(host="192.168.1.100", session=mock_aiohttp_session)
|
|
result = await api.test_connection()
|
|
|
|
assert result is False
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_status_success(self, mock_aiohttp_session):
|
|
"""Test successful status retrieval."""
|
|
expected_status = {
|
|
"protection_enabled": True,
|
|
"version": "v0.107.0",
|
|
"running": True,
|
|
}
|
|
|
|
mock_aiohttp_session.request.return_value.__aenter__.return_value.json = AsyncMock(
|
|
return_value=expected_status
|
|
)
|
|
|
|
api = AdGuardHomeAPI(host="192.168.1.100", session=mock_aiohttp_session)
|
|
status = await api.get_status()
|
|
|
|
assert status == expected_status
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_clients_success(self, mock_aiohttp_session):
|
|
"""Test successful clients retrieval."""
|
|
expected_clients = {
|
|
"clients": [
|
|
{"name": "client1", "ids": ["192.168.1.50"]},
|
|
{"name": "client2", "ids": ["192.168.1.51"]},
|
|
]
|
|
}
|
|
|
|
mock_aiohttp_session.request.return_value.__aenter__.return_value.json = AsyncMock(
|
|
return_value=expected_clients
|
|
)
|
|
|
|
api = AdGuardHomeAPI(host="192.168.1.100", session=mock_aiohttp_session)
|
|
clients = await api.get_clients()
|
|
|
|
assert clients == expected_clients
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_statistics_success(self, mock_aiohttp_session):
|
|
"""Test successful statistics retrieval."""
|
|
expected_stats = {
|
|
"num_dns_queries": 10000,
|
|
"num_blocked_filtering": 1500,
|
|
}
|
|
|
|
mock_aiohttp_session.request.return_value.__aenter__.return_value.json = AsyncMock(
|
|
return_value=expected_stats
|
|
)
|
|
|
|
api = AdGuardHomeAPI(host="192.168.1.100", session=mock_aiohttp_session)
|
|
stats = await api.get_statistics()
|
|
|
|
assert stats == expected_stats
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_set_protection_enable(self, mock_aiohttp_session):
|
|
"""Test enabling protection."""
|
|
mock_aiohttp_session.request.return_value.__aenter__.return_value.json = AsyncMock(
|
|
return_value={"success": True}
|
|
)
|
|
|
|
api = AdGuardHomeAPI(host="192.168.1.100", session=mock_aiohttp_session)
|
|
result = await api.set_protection(True)
|
|
|
|
assert result == {"success": True}
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_add_client_success(self, mock_aiohttp_session):
|
|
"""Test successful client addition."""
|
|
client_data = {
|
|
"name": "test_client",
|
|
"ids": ["192.168.1.100"],
|
|
}
|
|
|
|
mock_aiohttp_session.request.return_value.__aenter__.return_value.json = AsyncMock(
|
|
return_value={"success": True}
|
|
)
|
|
|
|
api = AdGuardHomeAPI(host="192.168.1.100", session=mock_aiohttp_session)
|
|
result = await api.add_client(client_data)
|
|
|
|
assert result == {"success": True}
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_add_client_missing_name(self, mock_aiohttp_session):
|
|
"""Test client addition with missing name."""
|
|
client_data = {"ids": ["192.168.1.100"]}
|
|
|
|
api = AdGuardHomeAPI(host="192.168.1.100", session=mock_aiohttp_session)
|
|
|
|
with pytest.raises(ValueError, match="Client name is required"):
|
|
await api.add_client(client_data)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_add_client_missing_ids(self, mock_aiohttp_session):
|
|
"""Test client addition with missing IDs."""
|
|
client_data = {"name": "test_client"}
|
|
|
|
api = AdGuardHomeAPI(host="192.168.1.100", session=mock_aiohttp_session)
|
|
|
|
with pytest.raises(ValueError, match="Client IDs are required"):
|
|
await api.add_client(client_data)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_client_by_name_found(self, mock_aiohttp_session):
|
|
"""Test finding client by name."""
|
|
clients_data = {
|
|
"clients": [
|
|
{"name": "test_client", "ids": ["192.168.1.50"]},
|
|
{"name": "other_client", "ids": ["192.168.1.51"]},
|
|
]
|
|
}
|
|
|
|
mock_aiohttp_session.request.return_value.__aenter__.return_value.json = AsyncMock(
|
|
return_value=clients_data
|
|
)
|
|
|
|
api = AdGuardHomeAPI(host="192.168.1.100", session=mock_aiohttp_session)
|
|
client = await api.get_client_by_name("test_client")
|
|
|
|
assert client == {"name": "test_client", "ids": ["192.168.1.50"]}
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_client_by_name_not_found(self, mock_aiohttp_session):
|
|
"""Test client not found by name."""
|
|
clients_data = {"clients": []}
|
|
|
|
mock_aiohttp_session.request.return_value.__aenter__.return_value.json = AsyncMock(
|
|
return_value=clients_data
|
|
)
|
|
|
|
api = AdGuardHomeAPI(host="192.168.1.100", session=mock_aiohttp_session)
|
|
client = await api.get_client_by_name("nonexistent_client")
|
|
|
|
assert client is None
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_update_client_blocked_services_client_not_found(self, mock_aiohttp_session):
|
|
"""Test blocked services update with client not found."""
|
|
api = AdGuardHomeAPI(host="192.168.1.100", session=mock_aiohttp_session)
|
|
api.get_client_by_name = AsyncMock(return_value=None)
|
|
|
|
with pytest.raises(AdGuardNotFoundError, match="Client 'nonexistent' not found"):
|
|
await api.update_client_blocked_services("nonexistent", ["youtube"])
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_auth_error_handling(self, mock_aiohttp_session):
|
|
"""Test 401 authentication error handling."""
|
|
mock_response = mock_aiohttp_session.request.return_value.__aenter__.return_value
|
|
mock_response.status = 401
|
|
|
|
api = AdGuardHomeAPI(host="192.168.1.100", session=mock_aiohttp_session)
|
|
|
|
with pytest.raises(AdGuardAuthError, match="Authentication failed"):
|
|
await api.get_status()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_not_found_error_handling(self, mock_aiohttp_session):
|
|
"""Test 404 not found error handling."""
|
|
mock_response = mock_aiohttp_session.request.return_value.__aenter__.return_value
|
|
mock_response.status = 404
|
|
|
|
api = AdGuardHomeAPI(host="192.168.1.100", session=mock_aiohttp_session)
|
|
|
|
with pytest.raises(AdGuardNotFoundError):
|
|
await api.get_status()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_server_error_handling(self, mock_aiohttp_session):
|
|
"""Test 500 server error handling."""
|
|
mock_response = mock_aiohttp_session.request.return_value.__aenter__.return_value
|
|
mock_response.status = 500
|
|
|
|
api = AdGuardHomeAPI(host="192.168.1.100", session=mock_aiohttp_session)
|
|
|
|
with pytest.raises(AdGuardConnectionError, match="Server error 500"):
|
|
await api.get_status()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_client_error_handling(self, mock_aiohttp_session):
|
|
"""Test client error handling."""
|
|
mock_aiohttp_session.request.side_effect = ClientError("Client error")
|
|
|
|
api = AdGuardHomeAPI(host="192.168.1.100", session=mock_aiohttp_session)
|
|
|
|
with pytest.raises(AdGuardConnectionError, match="Client error"):
|
|
await api.get_status()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_empty_response_handling(self, mock_aiohttp_session):
|
|
"""Test empty response handling."""
|
|
mock_response = mock_aiohttp_session.request.return_value.__aenter__.return_value
|
|
mock_response.status = 204
|
|
mock_response.content_length = 0
|
|
|
|
api = AdGuardHomeAPI(host="192.168.1.100", session=mock_aiohttp_session)
|
|
result = await api._request("POST", "/control/protection", {"enabled": True})
|
|
|
|
assert result == {}
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_close_session(self):
|
|
"""Test closing API session."""
|
|
api = AdGuardHomeAPI(host="192.168.1.100")
|
|
|
|
# Create session
|
|
async with api:
|
|
assert api._session is not None
|
|
|
|
# Close session
|
|
await api.close()
|