From 3888c3cd01cae5db32c862325f3b4b09799c24a4 Mon Sep 17 00:00:00 2001 From: deadzilla Date: Tue, 14 Jul 2026 22:27:30 +0500 Subject: [PATCH] =?UTF-8?q?fetch=5Fcat()=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4?= =?UTF-8?q?=D0=B0=D1=91=D1=82=20x-api-key=20=D0=BF=D1=80=D0=B8=20=D0=BD?= =?UTF-8?q?=D0=B0=D0=BB=D0=B8=D1=87=D0=B8=D0=B8=20CAT=5FAPI=5FKEY=20=D0=B2?= =?UTF-8?q?=20=D0=BE=D0=BA=D1=80=D1=83=D0=B6=D0=B5=D0=BD=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 1 + tests/test_fetch_cat.py | 25 +++++++++++++++++++++++++ utils/cat.py | 9 ++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index e4e5646..f0b307e 100644 --- a/.env.example +++ b/.env.example @@ -2,6 +2,7 @@ DISCORD_TOKEN=your_bot_token_here MORNING_TIME=07:00 MORNING_CHANNEL_ID=channel_id LOG_LEVEL=INFO +CAT_API_KEY=your_cat_api_key_here CAT_API_RATE=1 CAT_API_BURST=3 WEATHER_API_RATE=1 diff --git a/tests/test_fetch_cat.py b/tests/test_fetch_cat.py index 9f31afe..4a5bb79 100644 --- a/tests/test_fetch_cat.py +++ b/tests/test_fetch_cat.py @@ -97,3 +97,28 @@ class TestFetchCat: mock_get.return_value = mock_response result = await fetch_cat() assert result == "https://example.com/cat?w=100&h=200" + + @patch("utils.cat._session.get") + @patch("utils.cat._cat_api_key", "test-api-key-123") + async def test_fetch_cat_sends_api_key_header(self, mock_get) -> None: + """При заданном CAT_API_KEY должен передаваться заголовок x-api-key.""" + mock_response = MagicMock() + mock_response.json.return_value = [{"url": "https://example.com/cat.jpg"}] + mock_response.raise_for_status = MagicMock() + mock_get.return_value = mock_response + await fetch_cat() + # Проверяем, что headers переданы с x-api-key + call_kwargs = mock_get.call_args + assert call_kwargs[1].get("headers") == {"x-api-key": "test-api-key-123"} + + @patch("utils.cat._session.get") + @patch("utils.cat._cat_api_key", None) + async def test_fetch_cat_no_api_key_header(self, mock_get) -> None: + """При отсутствии CAT_API_KEY заголовок x-api-key не передаётся.""" + mock_response = MagicMock() + mock_response.json.return_value = [{"url": "https://example.com/cat.jpg"}] + mock_response.raise_for_status = MagicMock() + mock_get.return_value = mock_response + await fetch_cat() + call_kwargs = mock_get.call_args + assert call_kwargs[1].get("headers") is None diff --git a/utils/cat.py b/utils/cat.py index 8179376..0b4867f 100644 --- a/utils/cat.py +++ b/utils/cat.py @@ -1,5 +1,6 @@ import asyncio import logging +import os import requests @@ -8,6 +9,7 @@ from utils.rate_limiter import cat_limiter logger = logging.getLogger(__name__) CAT_API_URL = "https://api.thecatapi.com/v1/images/search" +_cat_api_key: str | None = os.getenv("CAT_API_KEY") _session = requests.Session() @@ -15,8 +17,13 @@ _session = requests.Session() async def fetch_cat() -> str | None: """Получить URL случайного котика. Вернуть None при ошибке.""" await cat_limiter.acquire() + headers: dict[str, str] | None = None + if _cat_api_key: + headers = {"x-api-key": _cat_api_key} try: - response = await asyncio.to_thread(_session.get, CAT_API_URL, timeout=10) + response = await asyncio.to_thread( + _session.get, CAT_API_URL, timeout=10, headers=headers + ) response.raise_for_status() data = response.json() return data[0]["url"]