from __future__ import annotations from unittest.mock import AsyncMock, MagicMock import pytest from yuxi.channel.application.service.auth_service import AuthService class TestAuthService: @pytest.fixture def mock_rate_limiter(self): return AsyncMock() @pytest.fixture def auth_service(self, mock_rate_limiter): return AuthService( mock_rate_limiter, token="test_token", password="test_password", max_attempts=3, lockout_seconds=300, ) @pytest.mark.asyncio async def test_authenticate_no_credentials_configured(self, mock_rate_limiter): service = AuthService(mock_rate_limiter) passed, reason = await service.authenticate("") assert passed is True assert reason == "" @pytest.mark.asyncio async def test_authenticate_with_valid_bearer_token(self, auth_service, mock_rate_limiter): mock_rate_limiter.is_locked.return_value = (False, 0) passed, reason = await auth_service.authenticate("Bearer test_token") assert passed is True assert reason == "" mock_rate_limiter.reset.assert_awaited_once() @pytest.mark.asyncio async def test_authenticate_with_invalid_bearer_token(self, auth_service, mock_rate_limiter): mock_rate_limiter.is_locked.return_value = (False, 0) mock_rate_limiter.check_and_incr.return_value = True passed, reason = await auth_service.authenticate("Bearer wrong_token") assert passed is False assert reason == "auth failed" @pytest.mark.asyncio async def test_authenticate_with_valid_basic_password(self, auth_service, mock_rate_limiter): import base64 mock_rate_limiter.is_locked.return_value = (False, 0) credentials = base64.b64encode(b"user:test_password").decode() passed, reason = await auth_service.authenticate(f"Basic {credentials}") assert passed is True assert reason == "" @pytest.mark.asyncio async def test_authenticate_with_invalid_basic_password(self, auth_service, mock_rate_limiter): import base64 mock_rate_limiter.is_locked.return_value = (False, 0) mock_rate_limiter.check_and_incr.return_value = True credentials = base64.b64encode(b"user:wrong_password").decode() passed, reason = await auth_service.authenticate(f"Basic {credentials}") assert passed is False @pytest.mark.asyncio async def test_authenticate_when_locked(self, auth_service, mock_rate_limiter): mock_rate_limiter.is_locked.return_value = (True, 120) passed, reason = await auth_service.authenticate("Bearer test_token") assert passed is False assert "retry after" in reason @pytest.mark.asyncio async def test_authenticate_rate_limited(self, auth_service, mock_rate_limiter): mock_rate_limiter.is_locked.return_value = (False, 0) mock_rate_limiter.check_and_incr.return_value = False passed, reason = await auth_service.authenticate("Bearer wrong_token") assert passed is False assert reason == "auth rate limited" def test_update_credentials(self, auth_service): auth_service.update_credentials(token="new_token", password="new_password") assert auth_service._token == "new_token" assert auth_service._password == "new_password" @pytest.mark.asyncio async def test_authenticate_empty_header_with_credentials(self, auth_service, mock_rate_limiter): mock_rate_limiter.is_locked.return_value = (False, 0) mock_rate_limiter.check_and_incr.return_value = True passed, reason = await auth_service.authenticate("") assert passed is False @pytest.mark.asyncio async def test_authenticate_malformed_basic(self, auth_service, mock_rate_limiter): mock_rate_limiter.is_locked.return_value = (False, 0) mock_rate_limiter.check_and_incr.return_value = True passed, reason = await auth_service.authenticate("Basic invalid_base64!!!") assert passed is False