99 lines
2.6 KiB
Python
99 lines
2.6 KiB
Python
from datetime import datetime, timezone
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
import pytest
|
|
|
|
from grist_mcp.proxy import parse_proxy_request, ProxyRequest, ProxyError, dispatch_proxy_request
|
|
from grist_mcp.session import SessionToken
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_session():
|
|
return SessionToken(
|
|
token="sess_test",
|
|
document="sales",
|
|
permissions=["read", "write"],
|
|
agent_name="test-agent",
|
|
created_at=datetime.now(timezone.utc),
|
|
expires_at=datetime.now(timezone.utc),
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_auth():
|
|
auth = MagicMock()
|
|
doc = MagicMock()
|
|
doc.url = "https://grist.example.com"
|
|
doc.doc_id = "abc123"
|
|
doc.api_key = "key"
|
|
auth.get_document.return_value = doc
|
|
return auth
|
|
|
|
|
|
def test_parse_proxy_request_valid_add_records():
|
|
body = {
|
|
"method": "add_records",
|
|
"table": "Orders",
|
|
"records": [{"item": "Widget", "qty": 10}],
|
|
}
|
|
|
|
request = parse_proxy_request(body)
|
|
|
|
assert request.method == "add_records"
|
|
assert request.table == "Orders"
|
|
assert request.records == [{"item": "Widget", "qty": 10}]
|
|
|
|
|
|
def test_parse_proxy_request_missing_method():
|
|
body = {"table": "Orders"}
|
|
|
|
with pytest.raises(ProxyError) as exc_info:
|
|
parse_proxy_request(body)
|
|
|
|
assert exc_info.value.code == "INVALID_REQUEST"
|
|
assert "method" in str(exc_info.value)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_dispatch_add_records(mock_session, mock_auth):
|
|
request = ProxyRequest(
|
|
method="add_records",
|
|
table="Orders",
|
|
records=[{"item": "Widget"}],
|
|
)
|
|
|
|
mock_client = AsyncMock()
|
|
mock_client.add_records.return_value = [1, 2, 3]
|
|
|
|
result = await dispatch_proxy_request(
|
|
request, mock_session, mock_auth, client=mock_client
|
|
)
|
|
|
|
assert result["success"] is True
|
|
assert result["data"]["record_ids"] == [1, 2, 3]
|
|
mock_client.add_records.assert_called_once_with("Orders", [{"item": "Widget"}])
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_dispatch_denies_without_permission(mock_auth):
|
|
# Session only has read permission
|
|
session = SessionToken(
|
|
token="sess_test",
|
|
document="sales",
|
|
permissions=["read"], # No write
|
|
agent_name="test-agent",
|
|
created_at=datetime.now(timezone.utc),
|
|
expires_at=datetime.now(timezone.utc),
|
|
)
|
|
|
|
request = ProxyRequest(
|
|
method="add_records", # Requires write
|
|
table="Orders",
|
|
records=[{"item": "Widget"}],
|
|
)
|
|
|
|
with pytest.raises(ProxyError) as exc_info:
|
|
await dispatch_proxy_request(request, session, mock_auth)
|
|
|
|
assert exc_info.value.code == "UNAUTHORIZED"
|