Skip to main content
Glama
test_search_pagination.py11.2 kB
"""Tests for search client pagination functionality.""" import os from unittest.mock import AsyncMock, MagicMock, patch import pytest from client.search.client import SearchClient from models.types.pagination import PaginatedResponse @pytest.mark.asyncio async def test_search_shows_no_page_returns_all(): """Test that search shows with no page parameter auto-paginates all results.""" # Mock first page response mock_response_page1 = MagicMock() mock_response_page1.json.return_value = [ {"show": {"title": "Breaking Bad", "year": 2008, "ids": {"trakt": 1}}}, {"show": {"title": "Better Call Saul", "year": 2015, "ids": {"trakt": 2}}}, ] mock_response_page1.headers = { "X-Pagination-Page": "1", "X-Pagination-Limit": "2", "X-Pagination-Page-Count": "2", "X-Pagination-Item-Count": "4", } mock_response_page1.raise_for_status = MagicMock() # Mock second page response mock_response_page2 = MagicMock() mock_response_page2.json.return_value = [ {"show": {"title": "Breaking Point", "year": 2021, "ids": {"trakt": 3}}}, {"show": {"title": "Breakthrough", "year": 2022, "ids": {"trakt": 4}}}, ] mock_response_page2.headers = { "X-Pagination-Page": "2", "X-Pagination-Limit": "2", "X-Pagination-Page-Count": "2", "X-Pagination-Item-Count": "4", } mock_response_page2.raise_for_status = MagicMock() with ( patch("httpx.AsyncClient") as mock_client, patch.dict( os.environ, {"TRAKT_CLIENT_ID": "test_id", "TRAKT_CLIENT_SECRET": "test_secret"}, ), ): # Create mock instance with async methods mock_instance = MagicMock() mock_instance.get = AsyncMock( side_effect=[mock_response_page1, mock_response_page2] ) mock_instance.post = AsyncMock() mock_instance.aclose = AsyncMock() mock_client.return_value = mock_instance client = SearchClient() result = await client.search_shows(query="breaking", limit=2, page=None) # Should return a plain list with all 4 shows assert isinstance(result, list) assert len(result) == 4 show_0 = result[0].get("show") assert show_0 is not None assert show_0["title"] == "Breaking Bad" show_3 = result[3].get("show") assert show_3 is not None assert show_3["title"] == "Breakthrough" @pytest.mark.asyncio async def test_search_shows_with_page_returns_paginated(): """Test that search shows with page parameter returns PaginatedResponse.""" mock_response = MagicMock() mock_response.json.return_value = [ {"show": {"title": "Breaking Bad", "year": 2008, "ids": {"trakt": 1}}}, {"show": {"title": "Better Call Saul", "year": 2015, "ids": {"trakt": 2}}}, ] mock_response.headers = { "X-Pagination-Page": "1", "X-Pagination-Limit": "2", "X-Pagination-Page-Count": "3", "X-Pagination-Item-Count": "6", } mock_response.raise_for_status = MagicMock() with ( patch("httpx.AsyncClient") as mock_client, patch.dict( os.environ, {"TRAKT_CLIENT_ID": "test_id", "TRAKT_CLIENT_SECRET": "test_secret"}, ), ): # Create mock instance with async methods mock_instance = MagicMock() mock_instance.get = AsyncMock(return_value=mock_response) mock_instance.post = AsyncMock() mock_instance.aclose = AsyncMock() mock_client.return_value = mock_instance client = SearchClient() result = await client.search_shows(query="breaking", limit=2, page=1) # Should return PaginatedResponse assert isinstance(result, PaginatedResponse) assert len(result.data) == 2 assert result.pagination.current_page == 1 assert result.pagination.total_pages == 3 assert result.pagination.total_items == 6 show_0 = result.data[0].get("show") assert show_0 is not None assert show_0["title"] == "Breaking Bad" @pytest.mark.asyncio async def test_search_movies_no_page_returns_all(): """Test that search movies with no page parameter auto-paginates all results.""" # Mock first page response mock_response_page1 = MagicMock() mock_response_page1.json.return_value = [ {"movie": {"title": "Inception", "year": 2010, "ids": {"trakt": 10}}}, {"movie": {"title": "Interstellar", "year": 2014, "ids": {"trakt": 11}}}, ] mock_response_page1.headers = { "X-Pagination-Page": "1", "X-Pagination-Limit": "2", "X-Pagination-Page-Count": "2", "X-Pagination-Item-Count": "3", } mock_response_page1.raise_for_status = MagicMock() # Mock second page response mock_response_page2 = MagicMock() mock_response_page2.json.return_value = [ {"movie": {"title": "Insidious", "year": 2010, "ids": {"trakt": 12}}}, ] mock_response_page2.headers = { "X-Pagination-Page": "2", "X-Pagination-Limit": "2", "X-Pagination-Page-Count": "2", "X-Pagination-Item-Count": "3", } mock_response_page2.raise_for_status = MagicMock() with ( patch("httpx.AsyncClient") as mock_client, patch.dict( os.environ, {"TRAKT_CLIENT_ID": "test_id", "TRAKT_CLIENT_SECRET": "test_secret"}, ), ): # Create mock instance with async methods mock_instance = MagicMock() mock_instance.get = AsyncMock( side_effect=[mock_response_page1, mock_response_page2] ) mock_instance.post = AsyncMock() mock_instance.aclose = AsyncMock() mock_client.return_value = mock_instance client = SearchClient() result = await client.search_movies(query="in", limit=2, page=None) # Should return a plain list with all 3 movies assert isinstance(result, list) assert len(result) == 3 movie_0 = result[0].get("movie") assert movie_0 is not None assert movie_0["title"] == "Inception" movie_2 = result[2].get("movie") assert movie_2 is not None assert movie_2["title"] == "Insidious" @pytest.mark.asyncio async def test_search_movies_with_page_returns_paginated(): """Test that search movies with page parameter returns PaginatedResponse.""" mock_response = MagicMock() mock_response.json.return_value = [ {"movie": {"title": "Inception", "year": 2010, "ids": {"trakt": 10}}}, {"movie": {"title": "Interstellar", "year": 2014, "ids": {"trakt": 11}}}, ] mock_response.headers = { "X-Pagination-Page": "2", "X-Pagination-Limit": "2", "X-Pagination-Page-Count": "5", "X-Pagination-Item-Count": "10", } mock_response.raise_for_status = MagicMock() with ( patch("httpx.AsyncClient") as mock_client, patch.dict( os.environ, {"TRAKT_CLIENT_ID": "test_id", "TRAKT_CLIENT_SECRET": "test_secret"}, ), ): # Create mock instance with async methods mock_instance = MagicMock() mock_instance.get = AsyncMock(return_value=mock_response) mock_instance.post = AsyncMock() mock_instance.aclose = AsyncMock() mock_client.return_value = mock_instance client = SearchClient() result = await client.search_movies(query="in", limit=2, page=2) # Should return PaginatedResponse assert isinstance(result, PaginatedResponse) assert len(result.data) == 2 assert result.pagination.current_page == 2 assert result.pagination.total_pages == 5 assert result.pagination.total_items == 10 movie_0 = result.data[0].get("movie") assert movie_0 is not None assert movie_0["title"] == "Inception" @pytest.mark.asyncio async def test_search_pagination_metadata(): """Test that pagination metadata is correctly extracted and computed.""" mock_response = MagicMock() mock_response.json.return_value = [ {"show": {"title": "Show 1", "year": 2020, "ids": {"trakt": 1}}}, ] mock_response.headers = { "X-Pagination-Page": "3", "X-Pagination-Limit": "1", "X-Pagination-Page-Count": "5", "X-Pagination-Item-Count": "5", } mock_response.raise_for_status = MagicMock() with ( patch("httpx.AsyncClient") as mock_client, patch.dict( os.environ, {"TRAKT_CLIENT_ID": "test_id", "TRAKT_CLIENT_SECRET": "test_secret"}, ), ): # Create mock instance with async methods mock_instance = MagicMock() mock_instance.get = AsyncMock(return_value=mock_response) mock_instance.post = AsyncMock() mock_instance.aclose = AsyncMock() mock_client.return_value = mock_instance client = SearchClient() result = await client.search_shows(query="show", limit=1, page=3) # Verify pagination metadata assert result.pagination.current_page == 3 assert result.pagination.items_per_page == 1 assert result.pagination.total_pages == 5 assert result.pagination.total_items == 5 # Verify navigation properties assert result.pagination.has_previous_page assert result.pagination.has_next_page assert result.pagination.previous_page() == 2 assert result.pagination.next_page() == 4 @pytest.mark.asyncio async def test_search_empty_results(): """Test search with no results.""" mock_response = MagicMock() mock_response.json.return_value = [] mock_response.headers = { "X-Pagination-Page": "1", "X-Pagination-Limit": "10", "X-Pagination-Page-Count": "1", "X-Pagination-Item-Count": "0", } mock_response.raise_for_status = MagicMock() with ( patch("httpx.AsyncClient") as mock_client, patch.dict( os.environ, {"TRAKT_CLIENT_ID": "test_id", "TRAKT_CLIENT_SECRET": "test_secret"}, ), ): # Create mock instance with async methods mock_instance = MagicMock() mock_instance.get = AsyncMock(return_value=mock_response) mock_instance.post = AsyncMock() mock_instance.aclose = AsyncMock() mock_client.return_value = mock_instance client = SearchClient() # Test with page parameter result_paginated = await client.search_shows( query="nonexistent", limit=10, page=1 ) assert isinstance(result_paginated, PaginatedResponse) assert len(result_paginated.data) == 0 assert result_paginated.pagination.total_items == 0 # Reset mock for next test mock_instance.get.return_value = mock_response # Test without page parameter (auto-paginate) result_list = await client.search_movies( query="nonexistent", limit=10, page=None ) assert isinstance(result_list, list) assert len(result_list) == 0

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/wwiens/trakt_mcpserver'

If you have feedback or need assistance with the MCP directory API, please join our Discord server