| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 |
- """Tests de la vérification de la clé API et du modèle au démarrage. Lancer depuis la racine du projet : python -m unittest"""
- import asyncio
- import unittest
- from types import SimpleNamespace
- from unittest import mock
- import anthropic
- from bot.claude_client import ClaudeClient
- from bot.discord_bot import ChatBot
- def fake_client(retrieve) -> ClaudeClient:
- # Sans __init__ : pas de client Anthropic à créer.
- client = ClaudeClient.__new__(ClaudeClient)
- client.settings = SimpleNamespace(api_timeout=0.2, model="claude-opus-5-5")
- client._client = SimpleNamespace(models=SimpleNamespace(retrieve=retrieve))
- return client
- def api_error(cls, status: int):
- response = mock.Mock(status_code=status, headers={})
- return cls("erreur", response=response, body={"error": {"message": "détail de l'API"}})
- class CheckAccessTest(unittest.IsolatedAsyncioTestCase):
- async def check(self, error):
- return await fake_client(mock.AsyncMock(side_effect=error)).check_access()
- async def test_valid_key_and_model(self):
- self.assertIsNone(await fake_client(mock.AsyncMock()).check_access())
- async def test_invalid_key(self):
- self.assertIn("ANTHROPIC_API_KEY", await self.check(api_error(anthropic.AuthenticationError, 401)))
- async def test_permission_denied(self):
- self.assertIn("détail de l'API", await self.check(api_error(anthropic.PermissionDeniedError, 403)))
- async def test_unknown_model(self):
- problem = await self.check(api_error(anthropic.NotFoundError, 404))
- self.assertIn("CLAUDE_MODEL", problem)
- self.assertIn("claude-opus-5-5", problem)
- async def test_api_down_does_not_block(self):
- # Panne passagère : on démarre quand même, avec un avertissement.
- for error in (api_error(anthropic.InternalServerError, 500),
- anthropic.APIConnectionError(request=mock.Mock())):
- with self.subTest(error=type(error).__name__), self.assertLogs("chatbot.claude", "WARNING"):
- self.assertIsNone(await self.check(error))
- async def test_slow_api_does_not_block(self):
- async def slow(_):
- await asyncio.sleep(10)
- with self.assertLogs("chatbot.claude", "WARNING") as logs:
- self.assertIsNone(await fake_client(slow).check_access())
- self.assertIn("délai dépassé", logs.output[0])
- class SetupHookTest(unittest.IsolatedAsyncioTestCase):
- async def test_bad_key_stops_bot(self):
- bot = mock.Mock(config_error=None)
- bot.claude.check_access = mock.AsyncMock(return_value="clé API Anthropic invalide")
- bot.close = mock.AsyncMock()
- with self.assertLogs("chatbot", "CRITICAL"):
- await ChatBot.setup_hook(bot)
- self.assertEqual(bot.config_error, "clé API Anthropic invalide")
- bot.close.assert_awaited_once()
- bot.tree.add_command.assert_not_called()
- if __name__ == "__main__":
- unittest.main()
|