Skip to main content
Glama
rossshannon

Pinboard MCP Server

by rossshannon
test_integration.py11.3 kB
#!/usr/bin/env python3 """ Updated integration tests for the Pinboard MCP Server Tests the client functionality with mocked Pinboard API responses. """ import asyncio import os import sys import unittest from datetime import datetime, timedelta from unittest.mock import MagicMock, patch # Add src to path for imports sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src")) from pinboard_mcp_server.client import PinboardClient from pinboard_mcp_server.models import TagCount class TestPinboardClientIntegration(unittest.TestCase): """Test the PinboardClient integration functionality""" def setUp(self): """Set up test environment""" self.test_token = "testuser:1234567890ABCDEF" # Sample test data (using recent dates) now = datetime.now() recent_date_1 = (now - timedelta(days=5)).strftime("%Y-%m-%dT%H:%M:%SZ") recent_date_2 = (now - timedelta(days=10)).strftime("%Y-%m-%dT%H:%M:%SZ") recent_date_3 = (now - timedelta(days=15)).strftime("%Y-%m-%dT%H:%M:%SZ") old_date = (now - timedelta(days=40)).strftime("%Y-%m-%dT%H:%M:%SZ") self.sample_posts_data = [ { "href": "https://example.com/python-testing", "description": "Python Testing Best Practices", "extended": "Comprehensive guide to testing in Python with pytest", "tags": "python testing pytest", "time": recent_date_1, }, { "href": "https://example.com/fastapi-tutorial", "description": "FastAPI Tutorial", "extended": "Learn how to build APIs with FastAPI", "tags": "python fastapi web", "time": recent_date_2, }, { "href": "https://example.com/async-programming", "description": "Async Programming in Python", "extended": "", "tags": "python async asyncio", "time": recent_date_3, }, { "href": "https://example.com/react-hooks", "description": "React Hooks Guide", "extended": "Modern React development with hooks", "tags": "react javascript frontend", "time": old_date, }, ] self.sample_tags_data = { "python": 3, "testing": 1, "pytest": 1, "fastapi": 1, "web": 1, "async": 1, "asyncio": 1, "react": 1, "javascript": 1, "frontend": 1, } def create_mock_pinboard_bookmarks(self, data_list): """Convert test data to mock pinboard.Bookmark objects.""" mock_bookmarks = [] for data in data_list: mock_bookmark = MagicMock() mock_bookmark.url = data["href"] mock_bookmark.description = data["description"] mock_bookmark.extended = data["extended"] mock_bookmark.tags = data["tags"].split() if data["tags"] else [] mock_bookmark.time = datetime.fromisoformat( data["time"].replace("Z", "+00:00") ) mock_bookmarks.append(mock_bookmark) return mock_bookmarks def create_mock_pinboard_tags(self, tags_dict): """Convert test tag data to mock pinboard.Tag objects.""" mock_tags = [] for tag_name, count in tags_dict.items(): mock_tag = MagicMock() mock_tag.name = tag_name mock_tag.count = count mock_tags.append(mock_tag) return mock_tags @patch("pinboard_mcp_server.client.pinboard.Pinboard") def test_search_bookmarks_integration(self, mock_pinboard_class): """Test search bookmarks functionality end-to-end""" async def run_test(): # Mock the pinboard client mock_bookmarks = self.create_mock_pinboard_bookmarks(self.sample_posts_data) mock_pb = MagicMock() mock_pb.posts.recent.return_value = {"posts": mock_bookmarks} mock_pb.posts.update.return_value = {"update_time": "2024-01-15T12:00:00Z"} mock_pinboard_class.return_value = mock_pb client = PinboardClient(self.test_token) # Test search for "python" results = await client.search_bookmarks("python", limit=10) self.assertEqual(len(results), 3) # 3 Python-related bookmarks # Verify all results contain "python" for bookmark in results: found_python = ( "python" in bookmark.title.lower() or "python" in bookmark.notes.lower() or any("python" in tag.lower() for tag in bookmark.tags) ) self.assertTrue(found_python) # Test case-insensitive search results = await client.search_bookmarks("REACT", limit=10) self.assertEqual(len(results), 1) await client.close() asyncio.run(run_test()) @patch("pinboard_mcp_server.client.pinboard.Pinboard") def test_recent_bookmarks_integration(self, mock_pinboard_class): """Test recent bookmarks functionality end-to-end""" async def run_test(): mock_bookmarks = self.create_mock_pinboard_bookmarks(self.sample_posts_data) mock_pb = MagicMock() mock_pb.posts.recent.return_value = {"posts": mock_bookmarks} mock_pb.posts.update.return_value = {"update_time": "2024-01-15T12:00:00Z"} mock_pinboard_class.return_value = mock_pb client = PinboardClient(self.test_token) # Test getting recent bookmarks (30 days) results = await client.get_recent_bookmarks(days=30, limit=20) self.assertEqual(len(results), 3) # 3 recent bookmarks # Test with shorter timeframe (3 days) results = await client.get_recent_bookmarks(days=3, limit=20) self.assertLessEqual(len(results), 3) await client.close() asyncio.run(run_test()) @patch("pinboard_mcp_server.client.pinboard.Pinboard") def test_bookmarks_by_tags_integration(self, mock_pinboard_class): """Test bookmarks by tags functionality end-to-end""" async def run_test(): mock_bookmarks = self.create_mock_pinboard_bookmarks(self.sample_posts_data) mock_pb = MagicMock() mock_pb.posts.recent.return_value = {"posts": mock_bookmarks} mock_pb.posts.update.return_value = {"update_time": "2024-01-15T12:00:00Z"} mock_pinboard_class.return_value = mock_pb client = PinboardClient(self.test_token) # Test filtering by single tag results = await client.get_bookmarks_by_tags(["python"], limit=10) self.assertEqual(len(results), 3) # 3 Python bookmarks # Test filtering by multiple tags (intersection) results = await client.get_bookmarks_by_tags(["python", "web"], limit=10) self.assertEqual(len(results), 1) # Only FastAPI bookmark has both # Test filtering by non-existent tag results = await client.get_bookmarks_by_tags(["nonexistent"], limit=10) self.assertEqual(len(results), 0) await client.close() asyncio.run(run_test()) @patch("pinboard_mcp_server.client.pinboard.Pinboard") def test_tags_integration(self, mock_pinboard_class): """Test tags functionality end-to-end""" async def run_test(): mock_tags = self.create_mock_pinboard_tags(self.sample_tags_data) mock_pb = MagicMock() mock_pb.tags.get.return_value = mock_tags mock_pinboard_class.return_value = mock_pb client = PinboardClient(self.test_token) # Test getting all tags results = await client.get_all_tags() self.assertEqual(len(results), len(self.sample_tags_data)) self.assertTrue(all(isinstance(tag, TagCount) for tag in results)) # Check that python tag has count 3 python_tag = next((tag for tag in results if tag.tag == "python"), None) self.assertIsNotNone(python_tag) if python_tag is not None: self.assertEqual(python_tag.count, 3) await client.close() asyncio.run(run_test()) @patch("pinboard_mcp_server.client.pinboard.Pinboard") def test_field_mapping_integration(self, mock_pinboard_class): """Test that Pinboard fields are correctly mapped to our model""" async def run_test(): # Create test data with explicit field mapping test_data = [ { "href": "https://example.com/test", "description": "This is the title", # Maps to title "extended": "These are the notes", # Maps to notes "tags": "tag1 tag2 tag3", "time": "2024-01-15T10:30:00Z", } ] mock_bookmarks = self.create_mock_pinboard_bookmarks(test_data) mock_pb = MagicMock() mock_pb.posts.recent.return_value = {"posts": mock_bookmarks} mock_pb.posts.update.return_value = {"update_time": "2024-01-15T12:00:00Z"} mock_pinboard_class.return_value = mock_pb client = PinboardClient(self.test_token) bookmarks = await client.get_all_bookmarks() self.assertEqual(len(bookmarks), 1) bookmark = bookmarks[0] # Verify field mapping self.assertEqual(bookmark.url, "https://example.com/test") self.assertEqual( bookmark.title, "This is the title" ) # description -> title self.assertEqual(bookmark.notes, "These are the notes") # extended -> notes self.assertEqual(bookmark.tags, ["tag1", "tag2", "tag3"]) await client.close() asyncio.run(run_test()) @patch("pinboard_mcp_server.client.pinboard.Pinboard") def test_caching_behavior_integration(self, mock_pinboard_class): """Test that caching works correctly""" async def run_test(): mock_bookmarks = self.create_mock_pinboard_bookmarks(self.sample_posts_data) mock_pb = MagicMock() mock_pb.posts.recent.return_value = {"posts": mock_bookmarks} mock_pb.posts.update.return_value = {"update_time": "2024-01-15T12:00:00Z"} mock_pinboard_class.return_value = mock_pb client = PinboardClient(self.test_token) # First call should hit the API bookmarks1 = await client.get_all_bookmarks() self.assertEqual(len(bookmarks1), 4) # Second call should use cache (posts.recent should only be called once) bookmarks2 = await client.get_all_bookmarks() self.assertEqual(len(bookmarks2), 4) # Verify API was called only once for posts mock_pb.posts.recent.assert_called_once() await client.close() asyncio.run(run_test()) if __name__ == "__main__": unittest.main()

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/rossshannon/pinboard-bookmarks-mcp-server'

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