Skip to main content
Glama

MCP Atlassian

by ArconixForge
test_confluence_models.py24.6 kB
""" Tests for the Confluence Pydantic models. These tests validate the conversion of Confluence API responses to structured models and the simplified dictionary conversion for API responses. """ import pytest from src.mcp_atlassian.models import ( ConfluenceAttachment, ConfluenceComment, ConfluenceLabel, ConfluencePage, ConfluenceSearchResult, ConfluenceSpace, ConfluenceUser, ConfluenceVersion, ) from src.mcp_atlassian.models.constants import EMPTY_STRING # Optional: Import real API client for optional real-data testing try: from src.mcp_atlassian.confluence.client import ConfluenceClient # noqa: F401 except ImportError: pass class TestConfluenceAttachment: """Tests for the ConfluenceAttachment model.""" def test_from_api_response_with_valid_data(self): """Test creating a ConfluenceAttachment from valid API data.""" attachment_data = { "id": "att105348", "type": "attachment", "status": "current", "title": "random_geometric_image.svg", "extensions": {"mediaType": "application/binary", "fileSize": 1098}, } attachment = ConfluenceAttachment.from_api_response(attachment_data) assert attachment.id == "att105348" assert attachment.title == "random_geometric_image.svg" assert attachment.type == "attachment" assert attachment.status == "current" assert attachment.media_type == "application/binary" assert attachment.file_size == 1098 def test_from_api_response_with_empty_data(self): """Test creating a ConfluenceAttachment from empty data.""" attachment = ConfluenceAttachment.from_api_response({}) # Should use default values assert attachment.id is None assert attachment.title is None assert attachment.type is None assert attachment.status is None assert attachment.media_type is None assert attachment.file_size is None def test_from_api_response_with_none_data(self): """Test creating a ConfluenceAttachment from None data.""" attachment = ConfluenceAttachment.from_api_response(None) # Should use default values assert attachment.id is None assert attachment.title is None assert attachment.type is None assert attachment.status is None assert attachment.media_type is None assert attachment.file_size is None def test_to_simplified_dict(self): """Test converting ConfluenceAttachment to a simplified dictionary.""" attachment = ConfluenceAttachment( id="att105348", title="random_geometric_image.svg", type="attachment", status="current", media_type="application/binary", file_size=1098, ) simplified = attachment.to_simplified_dict() assert isinstance(simplified, dict) assert simplified["id"] == "att105348" assert simplified["title"] == "random_geometric_image.svg" assert simplified["type"] == "attachment" assert simplified["status"] == "current" assert simplified["media_type"] == "application/binary" assert simplified["file_size"] == 1098 class TestConfluenceUser: """Tests for the ConfluenceUser model.""" def test_from_api_response_with_valid_data(self): """Test creating a ConfluenceUser from valid API data.""" user_data = { "accountId": "user123", "displayName": "Test User", "email": "test@example.com", "profilePicture": { "path": "/wiki/aa-avatar/user123", "width": 48, "height": 48, }, "accountStatus": "active", "locale": "en_US", } user = ConfluenceUser.from_api_response(user_data) assert user.account_id == "user123" assert user.display_name == "Test User" assert user.email == "test@example.com" assert user.profile_picture == "/wiki/aa-avatar/user123" assert user.is_active is True assert user.locale == "en_US" def test_from_api_response_with_empty_data(self): """Test creating a ConfluenceUser from empty data.""" user = ConfluenceUser.from_api_response({}) # Should use default values assert user.account_id is None assert user.display_name == "Unassigned" assert user.email is None assert user.profile_picture is None assert user.is_active is True assert user.locale is None def test_from_api_response_with_none_data(self): """Test creating a ConfluenceUser from None data.""" user = ConfluenceUser.from_api_response(None) # Should use default values assert user.account_id is None assert user.display_name == "Unassigned" assert user.email is None assert user.profile_picture is None assert user.is_active is True assert user.locale is None def test_to_simplified_dict(self): """Test converting ConfluenceUser to a simplified dictionary.""" user = ConfluenceUser( account_id="user123", display_name="Test User", email="test@example.com", profile_picture="/wiki/aa-avatar/user123", is_active=True, locale="en_US", ) simplified = user.to_simplified_dict() assert isinstance(simplified, dict) assert simplified["display_name"] == "Test User" assert simplified["email"] == "test@example.com" assert simplified["profile_picture"] == "/wiki/aa-avatar/user123" assert "account_id" not in simplified # Not included in simplified dict assert "locale" not in simplified # Not included in simplified dict class TestConfluenceSpace: """Tests for the ConfluenceSpace model.""" def test_from_api_response_with_valid_data(self): """Test creating a ConfluenceSpace from valid API data.""" space_data = { "id": "123456", "key": "TEST", "name": "Test Space", "type": "global", "status": "current", } space = ConfluenceSpace.from_api_response(space_data) assert space.id == "123456" assert space.key == "TEST" assert space.name == "Test Space" assert space.type == "global" assert space.status == "current" def test_from_api_response_with_empty_data(self): """Test creating a ConfluenceSpace from empty data.""" space = ConfluenceSpace.from_api_response({}) # Should use default values assert space.id == "0" assert space.key == "" assert space.name == "Unknown" assert space.type == "global" assert space.status == "current" def test_to_simplified_dict(self): """Test converting ConfluenceSpace to a simplified dictionary.""" space = ConfluenceSpace( id="123456", key="TEST", name="Test Space", type="global", status="current" ) simplified = space.to_simplified_dict() assert isinstance(simplified, dict) assert simplified["key"] == "TEST" assert simplified["name"] == "Test Space" assert simplified["type"] == "global" assert simplified["status"] == "current" assert "id" not in simplified # Not included in simplified dict class TestConfluenceVersion: """Tests for the ConfluenceVersion model.""" def test_from_api_response_with_valid_data(self): """Test creating a ConfluenceVersion from valid API data.""" version_data = { "number": 5, "when": "2024-01-01T09:00:00.000Z", "message": "Updated content", "by": { "accountId": "user123", "displayName": "Test User", "email": "test@example.com", }, } version = ConfluenceVersion.from_api_response(version_data) assert version.number == 5 assert version.when == "2024-01-01T09:00:00.000Z" assert version.message == "Updated content" assert version.by is not None assert version.by.display_name == "Test User" def test_from_api_response_with_empty_data(self): """Test creating a ConfluenceVersion from empty data.""" version = ConfluenceVersion.from_api_response({}) # Should use default values assert version.number == 0 assert version.when == "" assert version.message is None assert version.by is None def test_to_simplified_dict(self): """Test converting ConfluenceVersion to a simplified dictionary.""" version = ConfluenceVersion( number=5, when="2024-01-01T09:00:00.000Z", message="Updated content", by=ConfluenceUser(account_id="user123", display_name="Test User"), ) simplified = version.to_simplified_dict() assert isinstance(simplified, dict) assert simplified["number"] == 5 assert simplified["when"] == "2024-01-01 09:00:00" # Formatted timestamp assert simplified["message"] == "Updated content" assert simplified["by"] == "Test User" class TestConfluenceComment: """Tests for the ConfluenceComment model.""" def test_from_api_response_with_valid_data(self, confluence_comments_data): """Test creating a ConfluenceComment from valid API data.""" comment_data = confluence_comments_data["results"][0] comment = ConfluenceComment.from_api_response(comment_data) assert comment.id == "456789123" assert comment.title == "Re: Technical Design Document" assert comment.body != "" # Body should be populated from "value" field assert comment.author is not None assert comment.author.display_name == "John Doe" assert comment.type == "comment" def test_from_api_response_with_empty_data(self): """Test creating a ConfluenceComment from empty data.""" comment = ConfluenceComment.from_api_response({}) # Should use default values assert comment.id == "0" assert comment.title is None assert comment.body == "" assert comment.created == "" assert comment.updated == "" assert comment.author is None assert comment.type == "comment" def test_to_simplified_dict(self): """Test converting ConfluenceComment to a simplified dictionary.""" comment = ConfluenceComment( id="456789123", title="Test Comment", body="This is a test comment", created="2024-01-01T10:00:00.000Z", updated="2024-01-01T10:00:00.000Z", author=ConfluenceUser(account_id="user123", display_name="Comment Author"), type="comment", ) simplified = comment.to_simplified_dict() assert isinstance(simplified, dict) assert simplified["id"] == "456789123" assert simplified["title"] == "Test Comment" assert simplified["body"] == "This is a test comment" assert simplified["created"] == "2024-01-01 10:00:00" # Formatted timestamp assert simplified["updated"] == "2024-01-01 10:00:00" # Formatted timestamp assert simplified["author"] == "Comment Author" class TestConfluenceLabel: """Tests for the ConfluenceLabel model.""" def test_from_api_response_with_valid_data(self, confluence_labels_data): """Test creating a ConfluenceLabel from valid API data.""" label_data = confluence_labels_data["results"][0] label = ConfluenceLabel.from_api_response(label_data) assert label.id == "456789123" assert label.name == "meeting-notes" assert label.prefix == "global" assert label.label == "meeting-notes" assert label.type == "label" def test_from_api_response_with_empty_data(self): """Test creating a ConfluenceLabel from empty data.""" label = ConfluenceLabel.from_api_response({}) # Should use default values assert label.id == "0" assert label.name == EMPTY_STRING assert label.prefix == "global" assert label.label == EMPTY_STRING assert label.type == "label" def test_to_simplified_dict(self): """Test converting ConfluenceLabel to a simplified dictionary.""" label = ConfluenceLabel( id="456789123", name="test", prefix="my", label="test", type="label", ) simplified = label.to_simplified_dict() assert isinstance(simplified, dict) assert simplified["id"] == "456789123" assert simplified["name"] == "test" assert simplified["prefix"] == "my" assert simplified["label"] == "test" class TestConfluencePage: """Tests for the ConfluencePage model.""" def test_from_api_response_with_valid_data(self, confluence_page_data): """Test creating a ConfluencePage from valid API data.""" page = ConfluencePage.from_api_response(confluence_page_data) assert page.id == "987654321" assert page.title == "Example Meeting Notes" assert page.type == "page" assert page.status == "current" # Verify nested objects assert page.space is not None assert page.space.key == "PROJ" assert page.space.name == "Project Space" assert page.version is not None assert page.version.number == 1 assert page.version.by is not None assert page.version.by.display_name == "Example User (Unlicensed)" # Content extraction depends on the implementation # If it's not extracting from the mock data, let's skip this check # assert "<h2>" in page.content # Check timestamps assert page.version.when == "2024-01-01T09:00:00.000Z" def test_from_api_response_with_empty_data(self): """Test creating a ConfluencePage from empty data.""" page = ConfluencePage.from_api_response({}) # Should use default values assert page.id == "0" assert page.title == "" assert page.type == "page" assert page.status == "current" assert page.space is None assert page.content == "" assert page.content_format == "view" assert page.created == "" assert page.updated == "" assert page.author is None assert page.version is None assert len(page.ancestors) == 0 assert isinstance(page.children, dict) assert page.url is None def test_from_api_response_with_search_result(self, confluence_search_data): """Test creating a ConfluencePage from search result content.""" content_data = confluence_search_data["results"][0]["content"] page = ConfluencePage.from_api_response(content_data) assert page.id == "123456789" assert page.title == "2024-01-01: Team Progress Meeting 01" assert page.type == "page" assert page.status == "current" def test_to_simplified_dict(self, confluence_page_data): """Test converting ConfluencePage to a simplified dictionary.""" page = ConfluencePage.from_api_response(confluence_page_data) simplified = page.to_simplified_dict() assert isinstance(simplified, dict) assert simplified["id"] == "987654321" assert simplified["title"] == "Example Meeting Notes" # The keys in the simplified dict depend on the implementation # Let's check for space information in a more flexible way assert page.space is not None assert page.space.key == "PROJ" # Check space information - could be a string or a dict if "space_key" in simplified: assert simplified["space_key"] == "PROJ" elif "space" in simplified: # The space field might be a dictionary with key and name fields if isinstance(simplified["space"], dict): assert simplified["space"]["key"] == "PROJ" assert simplified["space"]["name"] == "Project Space" # Or it might be a string with just the key else: assert ( simplified["space"] == "PROJ" or simplified["space"] == "Project Space" ) # Check version is included assert "version" in simplified assert simplified["version"] == 1 # URL should be included assert "url" in simplified def test_from_api_response_with_expandable_space(self): """Test creating a ConfluencePage from data with space info in _expandable.""" page_data = { "id": "123456", "title": "Test Page", "_expandable": {"space": "/rest/api/space/TEST"}, } page = ConfluencePage.from_api_response( page_data, base_url="https://confluence.example.com", is_cloud=True ) assert page.space is not None assert page.space.key == "TEST" assert page.space.name == "Space TEST" assert page.url == "https://confluence.example.com/spaces/TEST/pages/123456" def test_from_api_response_with_missing_space(self): """Test creating a ConfluencePage with no space information.""" page_data = {"id": "123456", "title": "Test Page"} page = ConfluencePage.from_api_response( page_data, base_url="https://confluence.example.com", is_cloud=True ) assert page.space is not None assert page.space.key == "" # Default from ConfluenceSpace assert page.url == "https://confluence.example.com/spaces/unknown/pages/123456" def test_from_api_response_with_empty_space_data(self): """Test creating a ConfluencePage with empty space data.""" page_data = { "id": "123456", "title": "Test Page", "space": {}, # Empty space data } page = ConfluencePage.from_api_response( page_data, base_url="https://confluence.example.com", is_cloud=True ) assert page.space is not None assert page.space.key == "" # Default from ConfluenceSpace assert page.url == "https://confluence.example.com/spaces/unknown/pages/123456" def test_from_api_response_url_construction_without_base_url(self): """Test that URL is None when base_url is not provided.""" page_data = { "id": "123456", "title": "Test Page", "space": {"key": "TEST", "name": "Test Space"}, } page = ConfluencePage.from_api_response(page_data) # No base_url provided assert page.url is None assert page.space is not None assert page.space.key == "TEST" def test_url_construction_cloud_format(self): """Test URL construction in cloud format.""" page_data = { "id": "123456", "title": "Test Page", "space": {"key": "TEST", "name": "Test Space"}, } page = ConfluencePage.from_api_response( page_data, base_url="https://example.atlassian.net/wiki", is_cloud=True ) assert page.url == "https://example.atlassian.net/wiki/spaces/TEST/pages/123456" def test_url_construction_server_format(self): """Test URL construction in server format.""" page_data = { "id": "123456", "title": "Test Page", "space": {"key": "TEST", "name": "Test Space"}, } page = ConfluencePage.from_api_response( page_data, base_url="https://wiki.corp.example.com", is_cloud=False ) assert ( page.url == "https://wiki.corp.example.com/pages/viewpage.action?pageId=123456" ) class TestConfluenceSearchResult: """Tests for the ConfluenceSearchResult model.""" def test_from_api_response_with_valid_data(self, confluence_search_data): """Test creating a ConfluenceSearchResult from valid API data.""" search_result = ConfluenceSearchResult.from_api_response(confluence_search_data) assert search_result.total_size == 1 assert search_result.start == 0 assert search_result.limit == 50 assert search_result.cql_query == "parent = 123456789" assert search_result.search_duration == 156 assert len(search_result.results) == 1 # Verify that results are properly converted to ConfluencePage objects page = search_result.results[0] assert isinstance(page, ConfluencePage) assert page.id == "123456789" assert page.title == "2024-01-01: Team Progress Meeting 01" def test_from_api_response_with_empty_data(self): """Test creating a ConfluenceSearchResult from empty data.""" search_result = ConfluenceSearchResult.from_api_response({}) # Should use default values assert search_result.total_size == 0 assert search_result.start == 0 assert search_result.limit == 0 assert search_result.cql_query is None assert search_result.search_duration is None assert len(search_result.results) == 0 class TestRealConfluenceData: """Tests using real Confluence data (only run if environment is configured).""" def test_real_confluence_page( self, use_real_confluence_data, default_confluence_page_id ): """Test with real Confluence page data from the API.""" if not use_real_confluence_data: pytest.skip("Real Confluence data testing is disabled") try: # Initialize the Confluence client from src.mcp_atlassian.confluence.client import ConfluenceClient from src.mcp_atlassian.confluence.config import ConfluenceConfig from src.mcp_atlassian.confluence.pages import PagesMixin # Use the from_env method to create the config config = ConfluenceConfig.from_env() confluence_client = ConfluenceClient(config=config) pages_client = PagesMixin(config=config) # Use the provided page ID from environment or fixture page_id = default_confluence_page_id # Get page data directly from the Confluence API page_data = confluence_client.confluence.get_page_by_id( page_id=page_id, expand="body.storage,version,space,children.attachment" ) # Convert to model from src.mcp_atlassian.models import ConfluencePage page = ConfluencePage.from_api_response(page_data) # Verify basic properties assert page.id == page_id assert page.title is not None assert page.space is not None assert page.space.key is not None assert page.attachments is not None # Verify that to_simplified_dict works simplified = page.to_simplified_dict() assert isinstance(simplified, dict) assert simplified["id"] == page_id # Get and test comments if available try: from src.mcp_atlassian.models import ConfluenceComment comments_data = confluence_client.confluence.get_page_comments( page_id=page_id, expand="body.view,version" ) if comments_data and comments_data.get("results"): comment_data = comments_data["results"][0] comment = ConfluenceComment.from_api_response(comment_data) assert comment.id is not None assert comment.body is not None # Test simplified dict comment_dict = comment.to_simplified_dict() assert isinstance(comment_dict, dict) assert "body" in comment_dict except Exception as e: print(f"Comments test skipped: {e}") print( f"Successfully tested real Confluence page {page_id} in space {page.space.key}" ) except ImportError as e: pytest.skip(f"Could not import Confluence client: {e}") except Exception as e: pytest.fail(f"Error testing real Confluence page: {e}")

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/ArconixForge/mcp-atlassian'

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