arcade-mcp/toolkits/google/tests/test_drive.py
Eric Gustin ab889f9f1d
Lint all toolkits (#183)
# PR Description
* Adds/updates the following files to all toolkits:
    - `.pre-commit-config.yaml`
    - `.ruff.toml`
    - `LICENSE`
    - `Makefile`
    - `pyproject.toml`
* Lint all toolkits such that they pass `make check` and `make test` (a
total doozy). This includes adding some unit tests and evals.
* Github workflow for testing toolkits before merge into main (courtesy
of @sdreyer)
* Added a QOL improvement for tool developers for when they need to get
the context's auth token.
* Minor updates to `arcade new` template.
2024-12-20 09:49:45 -08:00

117 lines
3.7 KiB
Python

from unittest.mock import AsyncMock, patch
import pytest
from arcade.sdk.errors import ToolExecutionError
from googleapiclient.errors import HttpError
from arcade_google.tools.drive import list_documents
from arcade_google.tools.models import Corpora, OrderBy
from arcade_google.tools.utils import build_drive_service
@pytest.fixture
def mock_context():
context = AsyncMock()
context.authorization.token = "mock_token" # noqa: S105
return context
@pytest.fixture
def mock_service():
with patch("arcade_google.tools.drive." + build_drive_service.__name__) as mock_build_service:
yield mock_build_service.return_value
@pytest.mark.asyncio
async def test_list_documents_success(mock_context, mock_service):
# Mock the service.files().list().execute() method
mock_service.files.return_value.list.return_value.execute.side_effect = [
{
"files": [
{"id": "file1", "name": "Document 1"},
{"id": "file2", "name": "Document 2"},
],
"nextPageToken": None,
}
]
result = await list_documents(mock_context, limit=2)
assert result["documents_count"] == 2
assert len(result["documents"]) == 2
assert result["documents"][0]["id"] == "file1"
assert result["documents"][1]["id"] == "file2"
@pytest.mark.asyncio
async def test_list_documents_pagination(mock_context, mock_service):
# Simulate multiple pages
mock_service.files.return_value.list.return_value.execute.side_effect = [
{
"files": [{"id": f"file{i}", "name": f"Document {i}"} for i in range(1, 11)],
"nextPageToken": "token1",
},
{
"files": [{"id": f"file{i}", "name": f"Document {i}"} for i in range(11, 21)],
"nextPageToken": None,
},
]
result = await list_documents(mock_context, limit=15)
assert result["documents_count"] == 15
assert len(result["documents"]) == 15
assert result["documents"][0]["id"] == "file1"
assert result["documents"][-1]["id"] == "file15"
@pytest.mark.asyncio
async def test_list_documents_http_error(mock_context, mock_service):
# Simulate HttpError
mock_service.files.return_value.list.return_value.execute.side_effect = HttpError(
resp=AsyncMock(status=403), content=b'{"error": {"message": "Forbidden"}}'
)
with pytest.raises(ToolExecutionError, match="Error in execution of ListDocuments"):
await list_documents(mock_context)
@pytest.mark.asyncio
async def test_list_documents_unexpected_error(mock_context, mock_service):
# Simulate unexpected exception
mock_service.files.return_value.list.return_value.execute.side_effect = Exception(
"Unexpected error"
)
with pytest.raises(ToolExecutionError, match="Error in execution of ListDocuments"):
await list_documents(mock_context)
@pytest.mark.asyncio
async def test_list_documents_with_parameters(mock_context, mock_service):
# Mock the service.files().list().execute() method
mock_service.files.return_value.list.return_value.execute.side_effect = [
{
"files": [
{"id": "file1", "name": "Document 1"},
],
"nextPageToken": None,
}
]
result = await list_documents(
mock_context,
corpora=Corpora.USER,
order_by=OrderBy.MODIFIED_TIME_DESC,
supports_all_drives=False,
limit=1,
)
assert result["documents_count"] == 1
mock_service.files.return_value.list.assert_called_with(
q="mimeType = 'application/vnd.google-apps.document' and trashed = false",
pageSize=1,
orderBy="modifiedTime desc",
corpora="user",
supportsAllDrives=False,
)