"""Tests for Google People contact label tools."""
import pytest
from .base_test_config import TEST_EMAIL
from .test_helpers import ToolTestRunner, print_test_result
@pytest.mark.service("people")
class TestPeopleContactLabelTools:
"""Comprehensive tests for People contact label management tools."""
@pytest.mark.asyncio
async def test_people_label_tools_available(self, client):
"""Ensure People contact label tools are registered."""
tools = await client.list_tools()
tool_names = [tool.name for tool in tools]
has_list_tool = "list_people_contact_labels" in tool_names
has_manage_tool = "manage_people_contact_labels" in tool_names
if not has_list_tool and not has_manage_tool:
pytest.skip("People contact label tools not available in this server")
@pytest.mark.asyncio
async def test_list_people_contact_labels_explicit_email(self, client):
"""Test list_people_contact_labels with explicit email."""
runner = ToolTestRunner(client, TEST_EMAIL)
if not await runner.test_tool_availability("list_people_contact_labels"):
pytest.skip("list_people_contact_labels tool not available")
result = await runner.test_tool_with_explicit_email(
"list_people_contact_labels", {}
)
print_test_result("list_people_contact_labels explicit email", result)
# Should either succeed or give a clear auth-related response
assert (
result["success"] or result["is_auth_related"]
), "list_people_contact_labels should succeed or produce an auth-related error"
# If successful, validate response structure
if result["success"]:
# Response may be in 'content' or parsed from text
import json
response_data = result.get("content") or result.get("response")
if isinstance(response_data, str):
try:
response = json.loads(response_data)
except (json.JSONDecodeError, TypeError):
pytest.skip(f"Could not parse response as JSON: {response_data}")
else:
response = response_data or {}
assert "labels" in response, "Response should contain 'labels' field"
assert (
"total_count" in response
), "Response should contain 'total_count' field"
assert isinstance(response["labels"], list), "'labels' should be a list"
@pytest.mark.asyncio
async def test_list_people_contact_labels_response_structure(self, client):
"""Validate the structure of list_people_contact_labels response."""
runner = ToolTestRunner(client, TEST_EMAIL)
if not await runner.test_tool_availability("list_people_contact_labels"):
pytest.skip("list_people_contact_labels tool not available")
result = await runner.test_tool_with_explicit_email(
"list_people_contact_labels", {}
)
if not result["success"]:
pytest.skip("Could not test response structure - auth or API error")
# Parse response data
import json
response_data = result.get("content") or result.get("response")
if isinstance(response_data, str):
try:
response = json.loads(response_data)
except (json.JSONDecodeError, TypeError):
pytest.skip(f"Could not parse response as JSON: {response_data}")
else:
response = response_data or {}
# Verify top-level structure
assert "labels" in response
assert "total_count" in response
assert "user_email" in response
# Verify each label has required fields
for label in response["labels"]:
assert "resourceName" in label, "Each label should have resourceName"
assert "name" in label, "Each label should have name"
assert "memberCount" in label, "Each label should have memberCount"
assert "groupType" in label, "Each label should have groupType"
@pytest.mark.asyncio
async def test_manage_people_contact_labels_auth_patterns_label_add(self, client):
"""Test auth patterns for manage_people_contact_labels(label_add)."""
runner = ToolTestRunner(client, TEST_EMAIL)
if not await runner.test_tool_availability("manage_people_contact_labels"):
pytest.skip("manage_people_contact_labels tool not available")
label_name = "MCP Test Label"
auth_results = await runner.test_auth_patterns(
"manage_people_contact_labels",
{
"action": "label_add",
"email": TEST_EMAIL,
"label": label_name,
},
)
explicit = auth_results["explicit_email"]
middleware = auth_results["middleware_injection"]
print_test_result("manage_people_contact_labels explicit (label_add)", explicit)
print_test_result(
"manage_people_contact_labels middleware (label_add)", middleware
)
explicit_valid = explicit["success"] or explicit["is_auth_related"]
middleware_valid = middleware.get("success", False) or middleware.get(
"param_required_at_client", False
)
assert explicit_valid, "Explicit auth pattern should work or give auth error"
assert middleware_valid, (
"Middleware auth pattern should work, be auth-related, "
"or clearly require user_google_email at client"
)
@pytest.mark.asyncio
async def test_manage_people_contact_labels_label_remove(self, client):
"""Test manage_people_contact_labels with label_remove action."""
runner = ToolTestRunner(client, TEST_EMAIL)
if not await runner.test_tool_availability("manage_people_contact_labels"):
pytest.skip("manage_people_contact_labels tool not available")
label_name = "MCP Test Label Remove"
result = await runner.test_tool_with_explicit_email(
"manage_people_contact_labels",
{
"action": "label_remove",
"email": TEST_EMAIL,
"label": label_name,
},
)
print_test_result("manage_people_contact_labels (label_remove)", result)
# Should succeed or be auth-related
assert (
result["success"] or result["is_auth_related"]
), "label_remove should succeed or produce auth-related error"
@pytest.mark.asyncio
async def test_manage_people_contact_labels_multiple_emails(self, client):
"""Test manage_people_contact_labels with multiple emails."""
runner = ToolTestRunner(client, TEST_EMAIL)
if not await runner.test_tool_availability("manage_people_contact_labels"):
pytest.skip("manage_people_contact_labels tool not available")
label_name = "MCP Multi Email Test"
# Use comma-separated emails
multi_emails = f"{TEST_EMAIL},test2@example.com"
result = await runner.test_tool_with_explicit_email(
"manage_people_contact_labels",
{
"action": "label_add",
"email": multi_emails,
"label": label_name,
},
)
print_test_result("manage_people_contact_labels (multiple emails)", result)
# Should succeed or be auth-related
assert (
result["success"] or result["is_auth_related"]
), "Multiple email handling should succeed or produce auth-related error"
@pytest.mark.asyncio
async def test_manage_people_contact_labels_invalid_action(self, client):
"""Test manage_people_contact_labels with invalid action."""
runner = ToolTestRunner(client, TEST_EMAIL)
if not await runner.test_tool_availability("manage_people_contact_labels"):
pytest.skip("manage_people_contact_labels tool not available")
result = await runner.test_tool_with_explicit_email(
"manage_people_contact_labels",
{
"action": "invalid_action",
"email": TEST_EMAIL,
"label": "Test Label",
},
)
print_test_result("manage_people_contact_labels (invalid action)", result)
# Should fail with error message about unsupported action
if result["success"]:
response_text = str(result.get("content") or result.get("response", ""))
assert (
"unsupported" in response_text.lower()
or "invalid" in response_text.lower()
), "Invalid action should be rejected with appropriate error message"
@pytest.mark.asyncio
async def test_manage_people_contact_labels_missing_label(self, client):
"""Test manage_people_contact_labels without label parameter."""
runner = ToolTestRunner(client, TEST_EMAIL)
if not await runner.test_tool_availability("manage_people_contact_labels"):
pytest.skip("manage_people_contact_labels tool not available")
result = await runner.test_tool_with_explicit_email(
"manage_people_contact_labels",
{
"action": "label_add",
"email": TEST_EMAIL,
# No label parameter
},
)
print_test_result("manage_people_contact_labels (missing label)", result)
# Should fail with error about missing label
if result["success"]:
response_text = str(result.get("content") or result.get("response", ""))
assert (
"required" in response_text.lower() or "label" in response_text.lower()
), "Missing label should be rejected with appropriate error message"
@pytest.mark.asyncio
async def test_manage_people_contact_labels_empty_email(self, client):
"""Test manage_people_contact_labels with empty email."""
runner = ToolTestRunner(client, TEST_EMAIL)
if not await runner.test_tool_availability("manage_people_contact_labels"):
pytest.skip("manage_people_contact_labels tool not available")
result = await runner.test_tool_with_explicit_email(
"manage_people_contact_labels",
{
"action": "label_add",
"email": "",
"label": "Test Label",
},
)
print_test_result("manage_people_contact_labels (empty email)", result)
# Should fail with error about missing/invalid email
if result["success"]:
response_text = str(result.get("content") or result.get("response", ""))
assert (
"email" in response_text.lower() or "required" in response_text.lower()
), "Empty email should be rejected with appropriate error message"
@pytest.mark.asyncio
async def test_manage_people_contact_labels_scope_verification(self, client):
"""Verify that proper scopes are required for contact group management."""
runner = ToolTestRunner(client, TEST_EMAIL)
if not await runner.test_tool_availability("manage_people_contact_labels"):
pytest.skip("manage_people_contact_labels tool not available")
label_name = "MCP Scope Test Label"
result = await runner.test_tool_with_explicit_email(
"manage_people_contact_labels",
{
"action": "label_add",
"email": TEST_EMAIL,
"label": label_name,
},
)
# If it fails with auth error, check that it mentions scopes
if not result["success"] and result.get("is_auth_related"):
error_text = str(result.get("error", "")).lower()
# Should mention scopes or permissions
assert (
"scope" in error_text or "permission" in error_text
), "Auth errors should clearly indicate scope/permission issues"