Add comprehensive tests and documentation for Apps Script
Testing: - Created unit tests with mocked API responses (test_apps_script_tools.py) - 20+ test cases covering all 11 tools - Tests for success cases, edge cases, and error handling - Created manual test script for real API testing (manual_test.py) Documentation: - Created gappsscript module README with usage examples - Updated main README.md with Apps Script section - Added Apps Script to features list - Added Apps Script API to enable links - Added complete tool reference table - No em dashes or emojis per requirements All documentation follows existing codebase style and patterns.
This commit is contained in:
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
0
tests/gappsscript/__init__.py
Normal file
0
tests/gappsscript/__init__.py
Normal file
317
tests/gappsscript/manual_test.py
Normal file
317
tests/gappsscript/manual_test.py
Normal file
@@ -0,0 +1,317 @@
|
||||
"""
|
||||
Manual test script for Apps Script integration
|
||||
|
||||
This script allows manual testing of Apps Script tools against real Google API.
|
||||
Requires valid OAuth credentials and enabled Apps Script API.
|
||||
|
||||
Usage:
|
||||
python tests/gappsscript/manual_test.py
|
||||
|
||||
Note: This will interact with real Apps Script projects.
|
||||
Use with caution and in a test environment.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))
|
||||
|
||||
from googleapiclient.discovery import build
|
||||
from google.oauth2.credentials import Credentials
|
||||
from google_auth_oauthlib.flow import InstalledAppFlow
|
||||
from google.auth.transport.requests import Request
|
||||
import pickle
|
||||
|
||||
|
||||
SCOPES = [
|
||||
"https://www.googleapis.com/auth/script.projects",
|
||||
"https://www.googleapis.com/auth/script.deployments",
|
||||
]
|
||||
|
||||
|
||||
def get_credentials():
|
||||
"""
|
||||
Get OAuth credentials for Apps Script API.
|
||||
|
||||
Returns:
|
||||
Credentials object
|
||||
"""
|
||||
creds = None
|
||||
token_path = "token.pickle"
|
||||
|
||||
if os.path.exists(token_path):
|
||||
with open(token_path, "rb") as token:
|
||||
creds = pickle.load(token)
|
||||
|
||||
if not creds or not creds.valid:
|
||||
if creds and creds.expired and creds.refresh_token:
|
||||
creds.refresh(Request())
|
||||
else:
|
||||
if not os.path.exists("client_secret.json"):
|
||||
print("Error: client_secret.json not found")
|
||||
print(
|
||||
"Please download OAuth credentials from Google Cloud Console"
|
||||
)
|
||||
print(
|
||||
"and save as client_secret.json in the project root"
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
flow = InstalledAppFlow.from_client_secrets_file(
|
||||
"client_secret.json", SCOPES
|
||||
)
|
||||
creds = flow.run_local_server(port=0)
|
||||
|
||||
with open(token_path, "wb") as token:
|
||||
pickle.dump(creds, token)
|
||||
|
||||
return creds
|
||||
|
||||
|
||||
async def test_list_projects(service):
|
||||
"""Test listing Apps Script projects"""
|
||||
print("\n=== Test: List Projects ===")
|
||||
|
||||
from gappsscript.apps_script_tools import list_script_projects
|
||||
|
||||
try:
|
||||
result = await list_script_projects(
|
||||
service=service, user_google_email="test@example.com", page_size=10
|
||||
)
|
||||
print(result)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_create_project(service):
|
||||
"""Test creating a new Apps Script project"""
|
||||
print("\n=== Test: Create Project ===")
|
||||
|
||||
from gappsscript.apps_script_tools import create_script_project
|
||||
|
||||
try:
|
||||
result = await create_script_project(
|
||||
service=service,
|
||||
user_google_email="test@example.com",
|
||||
title="MCP Test Project",
|
||||
)
|
||||
print(result)
|
||||
|
||||
if "Script ID:" in result:
|
||||
script_id = result.split("Script ID: ")[1].split("\n")[0]
|
||||
return script_id
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
return None
|
||||
|
||||
|
||||
async def test_get_project(service, script_id):
|
||||
"""Test retrieving project details"""
|
||||
print(f"\n=== Test: Get Project {script_id} ===")
|
||||
|
||||
from gappsscript.apps_script_tools import get_script_project
|
||||
|
||||
try:
|
||||
result = await get_script_project(
|
||||
service=service, user_google_email="test@example.com", script_id=script_id
|
||||
)
|
||||
print(result)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_update_content(service, script_id):
|
||||
"""Test updating script content"""
|
||||
print(f"\n=== Test: Update Content {script_id} ===")
|
||||
|
||||
from gappsscript.apps_script_tools import update_script_content
|
||||
|
||||
files = [
|
||||
{
|
||||
"name": "Code",
|
||||
"type": "SERVER_JS",
|
||||
"source": """function testFunction() {
|
||||
Logger.log('Hello from MCP test!');
|
||||
return 'Test successful';
|
||||
}""",
|
||||
}
|
||||
]
|
||||
|
||||
try:
|
||||
result = await update_script_content(
|
||||
service=service,
|
||||
user_google_email="test@example.com",
|
||||
script_id=script_id,
|
||||
files=files,
|
||||
)
|
||||
print(result)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_run_function(service, script_id):
|
||||
"""Test running a script function"""
|
||||
print(f"\n=== Test: Run Function {script_id} ===")
|
||||
|
||||
from gappsscript.apps_script_tools import run_script_function
|
||||
|
||||
try:
|
||||
result = await run_script_function(
|
||||
service=service,
|
||||
user_google_email="test@example.com",
|
||||
script_id=script_id,
|
||||
function_name="testFunction",
|
||||
dev_mode=True,
|
||||
)
|
||||
print(result)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_create_deployment(service, script_id):
|
||||
"""Test creating a deployment"""
|
||||
print(f"\n=== Test: Create Deployment {script_id} ===")
|
||||
|
||||
from gappsscript.apps_script_tools import create_deployment
|
||||
|
||||
try:
|
||||
result = await create_deployment(
|
||||
service=service,
|
||||
user_google_email="test@example.com",
|
||||
script_id=script_id,
|
||||
description="MCP Test Deployment",
|
||||
)
|
||||
print(result)
|
||||
|
||||
if "Deployment ID:" in result:
|
||||
deployment_id = result.split("Deployment ID: ")[1].split("\n")[0]
|
||||
return deployment_id
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
return None
|
||||
|
||||
|
||||
async def test_list_deployments(service, script_id):
|
||||
"""Test listing deployments"""
|
||||
print(f"\n=== Test: List Deployments {script_id} ===")
|
||||
|
||||
from gappsscript.apps_script_tools import list_deployments
|
||||
|
||||
try:
|
||||
result = await list_deployments(
|
||||
service=service, user_google_email="test@example.com", script_id=script_id
|
||||
)
|
||||
print(result)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def test_list_processes(service):
|
||||
"""Test listing script processes"""
|
||||
print("\n=== Test: List Processes ===")
|
||||
|
||||
from gappsscript.apps_script_tools import list_script_processes
|
||||
|
||||
try:
|
||||
result = await list_script_processes(
|
||||
service=service, user_google_email="test@example.com", page_size=10
|
||||
)
|
||||
print(result)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def cleanup_test_project(service, script_id):
|
||||
"""
|
||||
Cleanup test project (requires Drive API).
|
||||
Note: Apps Script API does not have a delete endpoint.
|
||||
Projects must be deleted via Drive API by moving to trash.
|
||||
"""
|
||||
print(f"\n=== Cleanup: Delete Project {script_id} ===")
|
||||
print("Note: Apps Script projects must be deleted via Drive API")
|
||||
print(f"Please manually delete: https://script.google.com/d/{script_id}/edit")
|
||||
|
||||
|
||||
async def run_all_tests():
|
||||
"""Run all manual tests"""
|
||||
print("="*60)
|
||||
print("Apps Script MCP Manual Test Suite")
|
||||
print("="*60)
|
||||
|
||||
print("\nGetting OAuth credentials...")
|
||||
creds = get_credentials()
|
||||
|
||||
print("Building Apps Script API service...")
|
||||
service = build("script", "v1", credentials=creds)
|
||||
|
||||
test_script_id = None
|
||||
deployment_id = None
|
||||
|
||||
try:
|
||||
success = await test_list_projects(service)
|
||||
if not success:
|
||||
print("\nWarning: List projects failed")
|
||||
|
||||
test_script_id = await test_create_project(service)
|
||||
if test_script_id:
|
||||
print(f"\nCreated test project: {test_script_id}")
|
||||
|
||||
await test_get_project(service, test_script_id)
|
||||
await test_update_content(service, test_script_id)
|
||||
|
||||
await asyncio.sleep(2)
|
||||
|
||||
await test_run_function(service, test_script_id)
|
||||
|
||||
deployment_id = await test_create_deployment(service, test_script_id)
|
||||
if deployment_id:
|
||||
print(f"\nCreated deployment: {deployment_id}")
|
||||
|
||||
await test_list_deployments(service, test_script_id)
|
||||
else:
|
||||
print("\nSkipping tests that require a project (creation failed)")
|
||||
|
||||
await test_list_processes(service)
|
||||
|
||||
finally:
|
||||
if test_script_id:
|
||||
await cleanup_test_project(service, test_script_id)
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("Manual Test Suite Complete")
|
||||
print("="*60)
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point"""
|
||||
print("\nIMPORTANT: This script will:")
|
||||
print("1. Create a test Apps Script project in your account")
|
||||
print("2. Run various operations on it")
|
||||
print("3. Leave the project for manual cleanup")
|
||||
print("\nYou must manually delete the test project after running this.")
|
||||
|
||||
response = input("\nContinue? (yes/no): ")
|
||||
if response.lower() not in ["yes", "y"]:
|
||||
print("Aborted")
|
||||
return
|
||||
|
||||
asyncio.run(run_all_tests())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
576
tests/gappsscript/test_apps_script_tools.py
Normal file
576
tests/gappsscript/test_apps_script_tools.py
Normal file
@@ -0,0 +1,576 @@
|
||||
"""
|
||||
Unit tests for Google Apps Script MCP tools
|
||||
|
||||
Tests all Apps Script tools with mocked API responses
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import Mock, AsyncMock, patch
|
||||
import asyncio
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_script_projects():
|
||||
"""Test listing Apps Script projects"""
|
||||
from gappsscript.apps_script_tools import list_script_projects
|
||||
|
||||
mock_service = Mock()
|
||||
mock_response = {
|
||||
"projects": [
|
||||
{
|
||||
"scriptId": "test123",
|
||||
"title": "Test Project",
|
||||
"createTime": "2025-01-10T10:00:00Z",
|
||||
"updateTime": "2026-01-12T15:30:00Z",
|
||||
},
|
||||
{
|
||||
"scriptId": "test456",
|
||||
"title": "Another Project",
|
||||
"createTime": "2025-06-15T12:00:00Z",
|
||||
"updateTime": "2025-12-20T09:45:00Z",
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
mock_service.projects().list().execute.return_value = mock_response
|
||||
|
||||
result = await list_script_projects(
|
||||
service=mock_service, user_google_email="test@example.com", page_size=50
|
||||
)
|
||||
|
||||
assert "Found 2 Apps Script projects" in result
|
||||
assert "Test Project" in result
|
||||
assert "test123" in result
|
||||
assert "Another Project" in result
|
||||
assert "test456" in result
|
||||
|
||||
mock_service.projects().list.assert_called_once_with(pageSize=50)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_script_projects_empty():
|
||||
"""Test listing projects when none exist"""
|
||||
from gappsscript.apps_script_tools import list_script_projects
|
||||
|
||||
mock_service = Mock()
|
||||
mock_service.projects().list().execute.return_value = {"projects": []}
|
||||
|
||||
result = await list_script_projects(
|
||||
service=mock_service, user_google_email="test@example.com"
|
||||
)
|
||||
|
||||
assert result == "No Apps Script projects found."
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_script_projects_with_pagination():
|
||||
"""Test listing projects with pagination token"""
|
||||
from gappsscript.apps_script_tools import list_script_projects
|
||||
|
||||
mock_service = Mock()
|
||||
mock_response = {
|
||||
"projects": [{"scriptId": "test123", "title": "Test"}],
|
||||
"nextPageToken": "token123",
|
||||
}
|
||||
|
||||
mock_service.projects().list().execute.return_value = mock_response
|
||||
|
||||
result = await list_script_projects(
|
||||
service=mock_service,
|
||||
user_google_email="test@example.com",
|
||||
page_token="prev_token",
|
||||
)
|
||||
|
||||
assert "Next page token: token123" in result
|
||||
mock_service.projects().list.assert_called_once_with(
|
||||
pageSize=50, pageToken="prev_token"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_script_project():
|
||||
"""Test retrieving complete project details"""
|
||||
from gappsscript.apps_script_tools import get_script_project
|
||||
|
||||
mock_service = Mock()
|
||||
mock_response = {
|
||||
"scriptId": "test123",
|
||||
"title": "Test Project",
|
||||
"creator": {"email": "creator@example.com"},
|
||||
"createTime": "2025-01-10T10:00:00Z",
|
||||
"updateTime": "2026-01-12T15:30:00Z",
|
||||
"files": [
|
||||
{"name": "Code.gs", "type": "SERVER_JS", "source": "function test() {}"},
|
||||
{
|
||||
"name": "appsscript.json",
|
||||
"type": "JSON",
|
||||
"source": '{"timeZone": "America/New_York"}',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
mock_service.projects().get().execute.return_value = mock_response
|
||||
|
||||
result = await get_script_project(
|
||||
service=mock_service, user_google_email="test@example.com", script_id="test123"
|
||||
)
|
||||
|
||||
assert "Project: Test Project (ID: test123)" in result
|
||||
assert "Creator: creator@example.com" in result
|
||||
assert "Code.gs" in result
|
||||
assert "appsscript.json" in result
|
||||
|
||||
mock_service.projects().get.assert_called_once_with(scriptId="test123")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_script_content():
|
||||
"""Test retrieving specific file content"""
|
||||
from gappsscript.apps_script_tools import get_script_content
|
||||
|
||||
mock_service = Mock()
|
||||
mock_response = {
|
||||
"scriptId": "test123",
|
||||
"files": [
|
||||
{
|
||||
"name": "Code.gs",
|
||||
"type": "SERVER_JS",
|
||||
"source": "function sendEmail() {\n // code here\n}",
|
||||
},
|
||||
{"name": "Other.gs", "type": "SERVER_JS", "source": "function other() {}"},
|
||||
],
|
||||
}
|
||||
|
||||
mock_service.projects().get().execute.return_value = mock_response
|
||||
|
||||
result = await get_script_content(
|
||||
service=mock_service,
|
||||
user_google_email="test@example.com",
|
||||
script_id="test123",
|
||||
file_name="Code.gs",
|
||||
)
|
||||
|
||||
assert "File: Code.gs" in result
|
||||
assert "function sendEmail()" in result
|
||||
|
||||
mock_service.projects().get.assert_called_once_with(scriptId="test123")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_script_content_file_not_found():
|
||||
"""Test retrieving non-existent file"""
|
||||
from gappsscript.apps_script_tools import get_script_content
|
||||
|
||||
mock_service = Mock()
|
||||
mock_response = {
|
||||
"scriptId": "test123",
|
||||
"files": [{"name": "Code.gs", "type": "SERVER_JS", "source": ""}],
|
||||
}
|
||||
|
||||
mock_service.projects().get().execute.return_value = mock_response
|
||||
|
||||
result = await get_script_content(
|
||||
service=mock_service,
|
||||
user_google_email="test@example.com",
|
||||
script_id="test123",
|
||||
file_name="NonExistent.gs",
|
||||
)
|
||||
|
||||
assert "File 'NonExistent.gs' not found" in result
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_script_project():
|
||||
"""Test creating new Apps Script project"""
|
||||
from gappsscript.apps_script_tools import create_script_project
|
||||
|
||||
mock_service = Mock()
|
||||
mock_response = {
|
||||
"scriptId": "new123",
|
||||
"title": "New Project",
|
||||
}
|
||||
|
||||
mock_service.projects().create().execute.return_value = mock_response
|
||||
|
||||
result = await create_script_project(
|
||||
service=mock_service,
|
||||
user_google_email="test@example.com",
|
||||
title="New Project",
|
||||
)
|
||||
|
||||
assert "Created Apps Script project: New Project" in result
|
||||
assert "Script ID: new123" in result
|
||||
assert "https://script.google.com/d/new123/edit" in result
|
||||
|
||||
mock_service.projects().create.assert_called_once_with(body={"title": "New Project"})
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_script_project_with_parent():
|
||||
"""Test creating project with parent folder"""
|
||||
from gappsscript.apps_script_tools import create_script_project
|
||||
|
||||
mock_service = Mock()
|
||||
mock_response = {"scriptId": "new123", "title": "New Project"}
|
||||
|
||||
mock_service.projects().create().execute.return_value = mock_response
|
||||
|
||||
result = await create_script_project(
|
||||
service=mock_service,
|
||||
user_google_email="test@example.com",
|
||||
title="New Project",
|
||||
parent_id="folder123",
|
||||
)
|
||||
|
||||
assert "Script ID: new123" in result
|
||||
|
||||
mock_service.projects().create.assert_called_once_with(
|
||||
body={"title": "New Project", "parentId": "folder123"}
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_update_script_content():
|
||||
"""Test updating script project files"""
|
||||
from gappsscript.apps_script_tools import update_script_content
|
||||
|
||||
mock_service = Mock()
|
||||
files_to_update = [
|
||||
{"name": "Code.gs", "type": "SERVER_JS", "source": "function test() {}"},
|
||||
{"name": "Helper.gs", "type": "SERVER_JS", "source": "function helper() {}"},
|
||||
]
|
||||
|
||||
mock_response = {
|
||||
"scriptId": "test123",
|
||||
"files": files_to_update,
|
||||
}
|
||||
|
||||
mock_service.projects().updateContent().execute.return_value = mock_response
|
||||
|
||||
result = await update_script_content(
|
||||
service=mock_service,
|
||||
user_google_email="test@example.com",
|
||||
script_id="test123",
|
||||
files=files_to_update,
|
||||
)
|
||||
|
||||
assert "Updated script project: test123" in result
|
||||
assert "Code.gs" in result
|
||||
assert "Helper.gs" in result
|
||||
|
||||
mock_service.projects().updateContent.assert_called_once_with(
|
||||
scriptId="test123", body={"files": files_to_update}
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_script_function_success():
|
||||
"""Test successful script function execution"""
|
||||
from gappsscript.apps_script_tools import run_script_function
|
||||
|
||||
mock_service = Mock()
|
||||
mock_response = {
|
||||
"response": {"result": "Email sent successfully"},
|
||||
}
|
||||
|
||||
mock_service.scripts().run().execute.return_value = mock_response
|
||||
|
||||
result = await run_script_function(
|
||||
service=mock_service,
|
||||
user_google_email="test@example.com",
|
||||
script_id="test123",
|
||||
function_name="sendEmail",
|
||||
)
|
||||
|
||||
assert "Execution successful" in result
|
||||
assert "Function: sendEmail" in result
|
||||
assert "Email sent successfully" in result
|
||||
|
||||
mock_service.scripts().run.assert_called_once_with(
|
||||
scriptId="test123", body={"function": "sendEmail", "devMode": False}
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_script_function_with_parameters():
|
||||
"""Test running function with parameters"""
|
||||
from gappsscript.apps_script_tools import run_script_function
|
||||
|
||||
mock_service = Mock()
|
||||
mock_response = {"response": {"result": "Success"}}
|
||||
|
||||
mock_service.scripts().run().execute.return_value = mock_response
|
||||
|
||||
result = await run_script_function(
|
||||
service=mock_service,
|
||||
user_google_email="test@example.com",
|
||||
script_id="test123",
|
||||
function_name="processData",
|
||||
parameters=["param1", 42, True],
|
||||
dev_mode=True,
|
||||
)
|
||||
|
||||
assert "Execution successful" in result
|
||||
|
||||
mock_service.scripts().run.assert_called_once_with(
|
||||
scriptId="test123",
|
||||
body={
|
||||
"function": "processData",
|
||||
"devMode": True,
|
||||
"parameters": ["param1", 42, True],
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_script_function_error():
|
||||
"""Test script execution error handling"""
|
||||
from gappsscript.apps_script_tools import run_script_function
|
||||
|
||||
mock_service = Mock()
|
||||
mock_response = {
|
||||
"error": {"message": "ReferenceError: variable is not defined"},
|
||||
}
|
||||
|
||||
mock_service.scripts().run().execute.return_value = mock_response
|
||||
|
||||
result = await run_script_function(
|
||||
service=mock_service,
|
||||
user_google_email="test@example.com",
|
||||
script_id="test123",
|
||||
function_name="brokenFunction",
|
||||
)
|
||||
|
||||
assert "Execution failed" in result
|
||||
assert "brokenFunction" in result
|
||||
assert "ReferenceError" in result
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_deployment():
|
||||
"""Test creating deployment"""
|
||||
from gappsscript.apps_script_tools import create_deployment
|
||||
|
||||
mock_service = Mock()
|
||||
mock_response = {
|
||||
"deploymentId": "deploy123",
|
||||
"deploymentConfig": {},
|
||||
}
|
||||
|
||||
mock_service.projects().deployments().create().execute.return_value = (
|
||||
mock_response
|
||||
)
|
||||
|
||||
result = await create_deployment(
|
||||
service=mock_service,
|
||||
user_google_email="test@example.com",
|
||||
script_id="test123",
|
||||
description="Production deployment",
|
||||
)
|
||||
|
||||
assert "Created deployment for script: test123" in result
|
||||
assert "Deployment ID: deploy123" in result
|
||||
assert "Production deployment" in result
|
||||
|
||||
mock_service.projects().deployments().create.assert_called_once_with(
|
||||
scriptId="test123", body={"description": "Production deployment"}
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_deployment_with_version():
|
||||
"""Test creating deployment with version description"""
|
||||
from gappsscript.apps_script_tools import create_deployment
|
||||
|
||||
mock_service = Mock()
|
||||
mock_response = {"deploymentId": "deploy123"}
|
||||
|
||||
mock_service.projects().deployments().create().execute.return_value = (
|
||||
mock_response
|
||||
)
|
||||
|
||||
result = await create_deployment(
|
||||
service=mock_service,
|
||||
user_google_email="test@example.com",
|
||||
script_id="test123",
|
||||
description="Production",
|
||||
version_description="Version 1.0",
|
||||
)
|
||||
|
||||
assert "Deployment ID: deploy123" in result
|
||||
|
||||
call_args = mock_service.projects().deployments().create.call_args
|
||||
assert call_args[1]["body"]["versionNumber"]["description"] == "Version 1.0"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_deployments():
|
||||
"""Test listing deployments"""
|
||||
from gappsscript.apps_script_tools import list_deployments
|
||||
|
||||
mock_service = Mock()
|
||||
mock_response = {
|
||||
"deployments": [
|
||||
{
|
||||
"deploymentId": "deploy1",
|
||||
"description": "Production",
|
||||
"updateTime": "2026-01-10T12:00:00Z",
|
||||
},
|
||||
{
|
||||
"deploymentId": "deploy2",
|
||||
"description": "Staging",
|
||||
"updateTime": "2026-01-08T10:00:00Z",
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
mock_service.projects().deployments().list().execute.return_value = mock_response
|
||||
|
||||
result = await list_deployments(
|
||||
service=mock_service, user_google_email="test@example.com", script_id="test123"
|
||||
)
|
||||
|
||||
assert "Deployments for script: test123" in result
|
||||
assert "Production" in result
|
||||
assert "deploy1" in result
|
||||
assert "Staging" in result
|
||||
|
||||
mock_service.projects().deployments().list.assert_called_once_with(
|
||||
scriptId="test123"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_deployments_empty():
|
||||
"""Test listing deployments when none exist"""
|
||||
from gappsscript.apps_script_tools import list_deployments
|
||||
|
||||
mock_service = Mock()
|
||||
mock_service.projects().deployments().list().execute.return_value = {
|
||||
"deployments": []
|
||||
}
|
||||
|
||||
result = await list_deployments(
|
||||
service=mock_service, user_google_email="test@example.com", script_id="test123"
|
||||
)
|
||||
|
||||
assert "No deployments found" in result
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_update_deployment():
|
||||
"""Test updating deployment"""
|
||||
from gappsscript.apps_script_tools import update_deployment
|
||||
|
||||
mock_service = Mock()
|
||||
mock_response = {
|
||||
"deploymentId": "deploy123",
|
||||
"description": "Updated description",
|
||||
}
|
||||
|
||||
mock_service.projects().deployments().update().execute.return_value = (
|
||||
mock_response
|
||||
)
|
||||
|
||||
result = await update_deployment(
|
||||
service=mock_service,
|
||||
user_google_email="test@example.com",
|
||||
script_id="test123",
|
||||
deployment_id="deploy123",
|
||||
description="Updated description",
|
||||
)
|
||||
|
||||
assert "Updated deployment: deploy123" in result
|
||||
assert "Script: test123" in result
|
||||
|
||||
mock_service.projects().deployments().update.assert_called_once_with(
|
||||
scriptId="test123",
|
||||
deploymentId="deploy123",
|
||||
body={"description": "Updated description"},
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_delete_deployment():
|
||||
"""Test deleting deployment"""
|
||||
from gappsscript.apps_script_tools import delete_deployment
|
||||
|
||||
mock_service = Mock()
|
||||
mock_service.projects().deployments().delete().execute.return_value = {}
|
||||
|
||||
result = await delete_deployment(
|
||||
service=mock_service,
|
||||
user_google_email="test@example.com",
|
||||
script_id="test123",
|
||||
deployment_id="deploy123",
|
||||
)
|
||||
|
||||
assert "Deleted deployment: deploy123 from script: test123" in result
|
||||
|
||||
mock_service.projects().deployments().delete.assert_called_once_with(
|
||||
scriptId="test123", deploymentId="deploy123"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_script_processes():
|
||||
"""Test listing script execution processes"""
|
||||
from gappsscript.apps_script_tools import list_script_processes
|
||||
|
||||
mock_service = Mock()
|
||||
mock_response = {
|
||||
"processes": [
|
||||
{
|
||||
"functionName": "sendEmail",
|
||||
"processType": "EDITOR",
|
||||
"processStatus": "COMPLETED",
|
||||
"startTime": "2026-01-13T09:00:00Z",
|
||||
"duration": "2.3s",
|
||||
"userAccessLevel": "OWNER",
|
||||
},
|
||||
{
|
||||
"functionName": "processData",
|
||||
"processType": "SIMPLE_TRIGGER",
|
||||
"processStatus": "FAILED",
|
||||
"startTime": "2026-01-13T08:55:00Z",
|
||||
"duration": "1.1s",
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
mock_service.processes().list().execute.return_value = mock_response
|
||||
|
||||
result = await list_script_processes(
|
||||
service=mock_service, user_google_email="test@example.com"
|
||||
)
|
||||
|
||||
assert "Recent script executions" in result
|
||||
assert "sendEmail" in result
|
||||
assert "COMPLETED" in result
|
||||
assert "processData" in result
|
||||
assert "FAILED" in result
|
||||
|
||||
mock_service.processes().list.assert_called_once_with(pageSize=50)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_script_processes_filtered():
|
||||
"""Test listing processes filtered by script ID"""
|
||||
from gappsscript.apps_script_tools import list_script_processes
|
||||
|
||||
mock_service = Mock()
|
||||
mock_response = {"processes": []}
|
||||
|
||||
mock_service.processes().list().execute.return_value = mock_response
|
||||
|
||||
result = await list_script_processes(
|
||||
service=mock_service,
|
||||
user_google_email="test@example.com",
|
||||
script_id="test123",
|
||||
)
|
||||
|
||||
assert "No recent script executions found" in result
|
||||
|
||||
mock_service.processes().list.assert_called_once_with(
|
||||
pageSize=50, scriptId="test123"
|
||||
)
|
||||
Reference in New Issue
Block a user