from __future__ import annotations from unittest.mock import AsyncMock, Mock import aiohttp import pytest from yuxi.channels.adapters.twitch.helix import HelixClient def _make_mock_resp(status: int, data: dict | None = None, body: str = "error"): mock_resp = AsyncMock() mock_resp.status = status if data is not None: mock_resp.json = AsyncMock(return_value=data) mock_resp.text = AsyncMock(return_value=body) mock_resp.__aenter__ = AsyncMock(return_value=mock_resp) mock_resp.__aexit__ = AsyncMock(return_value=None) return mock_resp def _make_session(**methods): session = AsyncMock() session.closed = False for name, return_value in methods.items(): setattr(session, name, Mock(return_value=return_value)) return session class TestHelixGet: @pytest.mark.asyncio async def test_get_200_returns_data(self): client = HelixClient(client_id="test_id", access_token="test_token") client._session = _make_session( get=_make_mock_resp(200, {"data": [{"id": "123"}]}) ) result = await client._get("/helix/users", login="testuser") assert result == {"data": [{"id": "123"}]} @pytest.mark.asyncio async def test_get_401_returns_none(self): client = HelixClient(client_id="test_id", access_token="test_token") client._session = _make_session(get=_make_mock_resp(401)) result = await client._get("/helix/users") assert result is None @pytest.mark.asyncio async def test_get_404_returns_none(self): client = HelixClient(client_id="test_id", access_token="test_token") client._session = _make_session(get=_make_mock_resp(404)) result = await client._get("/helix/users") assert result is None @pytest.mark.asyncio async def test_get_500_returns_none(self): client = HelixClient(client_id="test_id", access_token="test_token") client._session = _make_session( get=_make_mock_resp(500, body="Internal Server Error") ) result = await client._get("/helix/users") assert result is None @pytest.mark.asyncio async def test_get_connection_error_returns_none(self): client = HelixClient(client_id="test_id", access_token="test_token") client._session = _make_session(get=AsyncMock(side_effect=aiohttp.ClientError("Connection refused"))) result = await client._get("/helix/users") assert result is None class TestHelixPost: @pytest.mark.asyncio async def test_create_eventsub_subscription_200(self): client = HelixClient(client_id="test_id", access_token="test_token") client._session = _make_session( post=_make_mock_resp(200, {"data": [{"id": "sub_123"}]}) ) result = await client.create_eventsub_subscription({"type": "channel.follow"}) assert result == "sub_123" @pytest.mark.asyncio async def test_create_eventsub_409_returns_none(self): client = HelixClient(client_id="test_id", access_token="test_token") client._session = _make_session(post=_make_mock_resp(409)) result = await client.create_eventsub_subscription({"type": "channel.follow"}) assert result is None @pytest.mark.asyncio async def test_create_eventsub_429_returns_none(self): client = HelixClient(client_id="test_id", access_token="test_token") client._session = _make_session(post=_make_mock_resp(429)) result = await client.create_eventsub_subscription({"type": "channel.follow"}) assert result is None @pytest.mark.asyncio async def test_create_eventsub_connection_error_returns_none(self): client = HelixClient(client_id="test_id", access_token="test_token") client._session = _make_session(post=AsyncMock(side_effect=aiohttp.ClientError("Connection refused"))) result = await client.create_eventsub_subscription({"type": "channel.follow"}) assert result is None @pytest.mark.asyncio async def test_delete_eventsub_subscription_204(self): client = HelixClient(client_id="test_id", access_token="test_token") client._session = _make_session(delete=_make_mock_resp(204)) result = await client.delete_eventsub_subscription("sub_123") assert result is True @pytest.mark.asyncio async def test_delete_eventsub_connection_error(self): client = HelixClient(client_id="test_id", access_token="test_token") client._session = _make_session(delete=AsyncMock(side_effect=aiohttp.ClientError("Connection refused"))) result = await client.delete_eventsub_subscription("sub_123") assert result is False class TestHelixToken: @pytest.mark.asyncio async def test_get_app_access_token_200(self): client = HelixClient(client_id="test_id", access_token="test_token") client._session = _make_session( post=_make_mock_resp(200, {"access_token": "app_token_123"}) ) result = await client.get_app_access_token("secret") assert result is not None @pytest.mark.asyncio async def test_get_app_access_token_connection_error(self): client = HelixClient(client_id="test_id", access_token="test_token") client._session = _make_session(post=AsyncMock(side_effect=aiohttp.ClientError("Connection refused"))) result = await client.get_app_access_token("secret") assert result is None @pytest.mark.asyncio async def test_refresh_user_token_200(self): client = HelixClient(client_id="test_id", access_token="test_token") client._session = _make_session( post=_make_mock_resp( 200, {"access_token": "new_token", "refresh_token": "new_refresh"} ) ) result = await client.refresh_user_token("secret", "refresh_123") assert result is not None @pytest.mark.asyncio async def test_refresh_user_token_connection_error(self): client = HelixClient(client_id="test_id", access_token="test_token") client._session = _make_session(post=AsyncMock(side_effect=aiohttp.ClientError("Connection refused"))) result = await client.refresh_user_token("secret", "refresh_123") assert result is None