Newer
Older
cortex-hub / ai-hub / tests / api / routes / test_mcp_files.py
import pytest
import json
from unittest.mock import MagicMock, AsyncMock, patch
from app.db import models

def test_mcp_list_tools_discovery(client):
    """Tests that the new file explorer tools are present in tools/list."""
    test_client, mock_services = client
    
    # Ensure all required services are mocked
    mock_services.mesh_service = MagicMock()
    mock_services.orchestrator = MagicMock()
    mock_services.user_service = MagicMock()
    mock_services.stt_service = MagicMock()
    mock_services.tts_service = MagicMock()
    mock_services.tool_service = MagicMock()
    mock_services.browser_service = MagicMock()
    
    # Mocking the discovery process
    # The route calls _execute for tools/list
    response = test_client.post("/mcp?token=test_user", json={
        "jsonrpc": "2.0",
        "id": 1,
        "method": "tools/list",
        "params": {}
    }, headers={"X-User-ID": "test_user"})
    
    assert response.status_code == 200
    res_body = response.json()
    assert "result" in res_body
    tools = res_body["result"].get("tools", [])
    tool_names = [t["name"] for t in tools]
    
    assert "list_files" in tool_names
    assert "upload_file" in tool_names
    assert "download_file" in tool_names
    assert "remove_file" in tool_names
    assert "create_file" in tool_names

def test_mcp_list_files_success(client):
    """Tests list_files tool via MCP dispatch."""
    test_client, mock_services = client
    
    # Mock services
    mock_services.mesh_service = MagicMock()
    mock_services.orchestrator = MagicMock()
    
    # Mock node access and orchestrator assistant
    mock_services.mesh_service.require_node_access.return_value = True
    mock_services.orchestrator.assistant.ls.return_value = {
        "files": [{"path": "test.txt", "is_dir": False, "size": 123}]
    }
    
    response = test_client.post("/mcp?token=test_user", json={
        "jsonrpc": "2.0",
        "id": 1,
        "method": "tools/call",
        "params": {
            "name": "list_files",
            "arguments": {
                "node_id": "test-node",
                "path": "."
            }
        }
    }, headers={"X-User-ID": "test_user"})
    
    assert response.status_code == 200
    res_body = response.json()
    assert "result" in res_body
    res_data = res_body["result"]
    assert "content" in res_data
    content_text = res_data["content"][0]["text"]
    data = json.loads(content_text)
    assert "files" in data
    assert data["files"][0]["path"] == "test.txt"
    
    mock_services.mesh_service.require_node_access.assert_called_once()
    mock_services.orchestrator.assistant.ls.assert_called_once_with("test-node", ".", session_id="__fs_explorer__")

def test_mcp_upload_file_success(client):
    """Tests upload_file tool via MCP dispatch (aliased to write_file)."""
    test_client, mock_services = client
    
    mock_services.mesh_service = MagicMock()
    mock_services.orchestrator = MagicMock()
    
    mock_services.mesh_service.require_node_access.return_value = True
    mock_services.orchestrator.assistant.write.return_value = {"status": "success"}
    
    response = test_client.post("/mcp?token=test_user", json={
        "jsonrpc": "2.0",
        "id": 1,
        "method": "tools/call",
        "params": {
            "name": "upload_file",
            "arguments": {
                "node_id": "test-node",
                "path": "hello.txt",
                "content": "hello world"
            }
        }
    }, headers={"X-User-ID": "test_user"})
    
    assert response.status_code == 200
    res_data = response.json()["result"]
    assert "content" in res_data
    content_text = res_data["content"][0]["text"]
    assert json.loads(content_text) == {"status": "success"}
    
    mock_services.orchestrator.assistant.write.assert_called_once_with(
        "test-node", "hello.txt", "hello world", False, session_id="__fs_explorer__"
    )

def test_mcp_download_file_success(client):
    """Tests download_file tool via MCP dispatch (aliased to cat)."""
    test_client, mock_services = client
    
    mock_services.mesh_service = MagicMock()
    mock_services.orchestrator = MagicMock()
    
    mock_services.mesh_service.require_node_access.return_value = True
    mock_services.orchestrator.assistant.cat.return_value = "file content"
    
    response = test_client.post("/mcp?token=test_user", json={
        "jsonrpc": "2.0",
        "id": 1,
        "method": "tools/call",
        "params": {
            "name": "download_file",
            "arguments": {
                "node_id": "test-node",
                "path": "hello.txt"
            }
        }
    }, headers={"X-User-ID": "test_user"})
    
    assert response.status_code == 200
    res_data = response.json()["result"]
    assert "content" in res_data
    assert res_data["content"][0]["text"] == "file content"
    
    mock_services.orchestrator.assistant.cat.assert_called_once_with(
        "test-node", "hello.txt", session_id="__fs_explorer__"
    )

def test_mcp_remove_file_success(client):
    """Tests remove_file tool via MCP dispatch (aliased to delete_file)."""
    test_client, mock_services = client
    
    mock_services.mesh_service = MagicMock()
    mock_services.orchestrator = MagicMock()
    
    mock_services.mesh_service.require_node_access.return_value = True
    mock_services.orchestrator.assistant.rm.return_value = {"status": "success"}
    
    response = test_client.post("/mcp?token=test_user", json={
        "jsonrpc": "2.0",
        "id": 1,
        "method": "tools/call",
        "params": {
            "name": "remove_file",
            "arguments": {
                "node_id": "test-node",
                "path": "old.txt"
            }
        }
    }, headers={"X-User-ID": "test_user"})
    
    assert response.status_code == 200
    res_data = response.json()["result"]
    assert "content" in res_data
    content_text = res_data["content"][0]["text"]
    assert json.loads(content_text) == {"status": "success"}
    
    mock_services.orchestrator.assistant.rm.assert_called_once_with(
        "test-node", "old.txt", session_id="__fs_explorer__"
    )

def test_mcp_create_file_success(client):
    """Tests create_file tool via MCP dispatch (empty content)."""
    test_client, mock_services = client
    
    mock_services.mesh_service = MagicMock()
    mock_services.orchestrator = MagicMock()
    
    mock_services.mesh_service.require_node_access.return_value = True
    mock_services.orchestrator.assistant.write.return_value = {"status": "success"}
    
    response = test_client.post("/mcp?token=test_user", json={
        "jsonrpc": "2.0",
        "id": 1,
        "method": "tools/call",
        "params": {
            "name": "create_file",
            "arguments": {
                "node_id": "test-node",
                "path": "new_dir",
                "is_dir": True
            }
        }
    }, headers={"X-User-ID": "test_user"})
    
    assert response.status_code == 200
    res_data = response.json()["result"]
    assert "content" in res_data
    content_text = res_data["content"][0]["text"]
    assert json.loads(content_text) == {"status": "success"}
    
    mock_services.orchestrator.assistant.write.assert_called_once_with(
        "test-node", "new_dir", "", True, session_id="__fs_explorer__"
    )