We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/brianirish/laravel-mcp-companion'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
"""Pytest configuration and fixtures for Laravel MCP Companion tests."""
import tempfile
import json
import pytest
from pathlib import Path
from unittest.mock import MagicMock, patch
from typing import Dict, Any, Generator
# Import the modules we'll be testing
import laravel_mcp_companion
import docs_updater
from shutdown_handler import GracefulShutdown
# Register custom markers to avoid warnings
def pytest_configure(config):
config.addinivalue_line("markers", "slow: marks tests as slow (deselect with '-m \"not slow\"')")
config.addinivalue_line("markers", "integration: marks tests as integration tests")
config.addinivalue_line("markers", "unit: marks tests as unit tests")
config.addinivalue_line("markers", "network: marks tests that require network access")
config.addinivalue_line("markers", "external: marks tests that interact with external services")
@pytest.fixture
def temp_dir() -> Generator[Path, None, None]:
"""Create a temporary directory for test files."""
with tempfile.TemporaryDirectory() as tmp_dir:
yield Path(tmp_dir)
@pytest.fixture
def test_docs_dir(temp_dir: Path) -> Path:
"""Create a test documentation directory structure."""
docs_dir = temp_dir / "docs"
docs_dir.mkdir()
# Create version directories
for version in ["11.x", "12.x"]:
version_dir = docs_dir / version
version_dir.mkdir()
# Create sample markdown files
(version_dir / "installation.md").write_text(f"# Installation\n\nLaravel {version} installation guide.")
(version_dir / "routing.md").write_text(f"# Routing\n\nLaravel {version} routing documentation.")
(version_dir / "eloquent.md").write_text(f"# Eloquent ORM\n\nEloquent documentation for {version}.")
# Create metadata directory and file
metadata_dir = version_dir / ".metadata"
metadata_dir.mkdir()
metadata = {
"version": version,
"commit_sha": f"abc123{version[-1]}",
"commit_date": "2024-01-01T12:00:00Z",
"commit_message": f"Update {version} documentation",
"commit_url": f"https://github.com/laravel/docs/commit/abc123{version[-1]}",
"sync_time": "2024-01-01T12:00:00Z"
}
(metadata_dir / "sync_info.json").write_text(json.dumps(metadata, indent=2))
return docs_dir
@pytest.fixture
def test_external_docs_dir(temp_dir: Path) -> Path:
"""Create a test external documentation directory structure."""
external_dir = temp_dir / "docs" / "external"
external_dir.mkdir(parents=True)
# Create service directories with sample files
services = ["forge", "vapor", "envoyer", "nova"]
for service in services:
service_dir = external_dir / service
service_dir.mkdir()
# Create sample documentation files
(service_dir / "introduction.md").write_text(f"# {service.title()}\n\nIntroduction to Laravel {service.title()}.")
(service_dir / "getting-started.md").write_text(f"# Getting Started\n\nHow to get started with {service.title()}.")
# Create cache metadata
metadata = {
"service": service,
"fetched_sections": ["introduction", "getting-started"],
"total_sections": 2,
"success_rate": 1.0,
"discovery_method": "manual configuration",
"cached_at": 1704110400.0 # 2024-01-01 12:00:00
}
(service_dir / ".cache_metadata.json").write_text(json.dumps(metadata, indent=2))
return external_dir
@pytest.fixture
def sample_package_catalog() -> Dict[str, Any]:
"""Sample package catalog for testing."""
return {
"laravel/cashier": {
"name": "Laravel Cashier",
"description": "Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.",
"categories": ["payment", "billing", "subscription"],
"use_cases": [
"Implementing subscription billing",
"Processing one-time payments"
],
"installation": "composer require laravel/cashier",
"documentation_link": "laravel://packages/cashier.md"
},
"laravel/sanctum": {
"name": "Laravel Sanctum",
"description": "Laravel Sanctum provides a featherweight authentication system for SPAs.",
"categories": ["authentication", "api", "security"],
"use_cases": [
"Authenticating SPAs",
"API token authentication"
],
"installation": "composer require laravel/sanctum",
"documentation_link": "laravel://authentication/sanctum.md"
}
}
@pytest.fixture
def mock_github_api() -> Generator[MagicMock, None, None]:
"""Mock GitHub API responses."""
with patch('docs_updater.urllib.request.urlopen') as mock_urlopen:
# Mock successful API response
mock_response = MagicMock()
mock_response.read.return_value = json.dumps({
"commit": {
"sha": "abc123def456",
"commit": {
"committer": {"date": "2024-01-01T12:00:00Z"},
"message": "Update documentation"
},
"html_url": "https://github.com/laravel/docs/commit/abc123def456"
}
}).encode()
mock_response.__enter__ = lambda self: self
mock_response.__exit__ = lambda self, *args: None
mock_urlopen.return_value = mock_response
yield mock_urlopen
@pytest.fixture
def mock_file_download() -> Generator[MagicMock, None, None]:
"""Mock file downloads for testing."""
with patch('docs_updater.urllib.request.urlopen') as mock_urlopen:
# Mock successful download
mock_response = MagicMock()
mock_response.read.return_value = b"Mock file content"
mock_response.__enter__ = lambda self: self
mock_response.__exit__ = lambda self, *args: None
mock_urlopen.return_value = mock_response
yield mock_urlopen
@pytest.fixture
def mock_fastmcp():
"""Mock FastMCP for testing tool registration."""
with patch('laravel_mcp_companion.FastMCP') as mock_mcp:
mock_instance = MagicMock()
mock_mcp.return_value = mock_instance
yield mock_instance
@pytest.fixture
def docs_updater_instance(test_docs_dir: Path) -> docs_updater.DocsUpdater:
"""Create a DocsUpdater instance for testing."""
return docs_updater.DocsUpdater(test_docs_dir, "12.x")
@pytest.fixture
def external_docs_fetcher(test_docs_dir: Path) -> docs_updater.ExternalDocsFetcher:
"""Create an ExternalDocsFetcher instance for testing."""
return docs_updater.ExternalDocsFetcher(test_docs_dir)
@pytest.fixture
def multi_source_updater(test_docs_dir: Path) -> docs_updater.MultiSourceDocsUpdater:
"""Create a MultiSourceDocsUpdater instance for testing."""
return docs_updater.MultiSourceDocsUpdater(test_docs_dir, "12.x")
@pytest.fixture
def shutdown_handler() -> GracefulShutdown:
"""Create a GracefulShutdown instance for testing."""
return GracefulShutdown()
@pytest.fixture
def mock_logger():
"""Mock logger for testing."""
return MagicMock()
@pytest.fixture(autouse=True)
def clear_caches():
"""Clear all caches before each test."""
# Import mcp_tools for cache clearing
import mcp_tools
# Clear mcp_tools caches
mcp_tools.clear_caches()
# Clear main module caches if they exist
if hasattr(laravel_mcp_companion, '_file_content_cache'):
laravel_mcp_companion._file_content_cache.clear()
if hasattr(laravel_mcp_companion, '_search_result_cache'):
laravel_mcp_companion._search_result_cache.clear()
# Clear function cache if it exists
if hasattr(laravel_mcp_companion, 'get_file_content_cached') and hasattr(laravel_mcp_companion.get_file_content_cached, 'cache_clear'):
laravel_mcp_companion.get_file_content_cached.cache_clear()
yield
# Clear caches after test
mcp_tools.clear_caches()
if hasattr(laravel_mcp_companion, '_file_content_cache'):
laravel_mcp_companion._file_content_cache.clear()
if hasattr(laravel_mcp_companion, '_search_result_cache'):
laravel_mcp_companion._search_result_cache.clear()
if hasattr(laravel_mcp_companion, 'get_file_content_cached') and hasattr(laravel_mcp_companion.get_file_content_cached, 'cache_clear'):
laravel_mcp_companion.get_file_content_cached.cache_clear()
@pytest.fixture
def sample_html_content() -> str:
"""Sample HTML content for testing HTML processing."""
return """
<!DOCTYPE html>
<html>
<head><title>Laravel Documentation</title></head>
<body>
<main>
<h1>Laravel Installation</h1>
<p>Welcome to Laravel! This guide will help you install Laravel.</p>
<h2>Requirements</h2>
<ul>
<li>PHP >= 8.1</li>
<li>Composer</li>
</ul>
<h2>Installation Steps</h2>
<ol>
<li>Run <code>composer create-project laravel/laravel myapp</code></li>
<li>Navigate to your project: <code>cd myapp</code></li>
<li>Start the development server: <code>php artisan serve</code></li>
</ol>
</main>
</body>
</html>
"""
# Mock environment variables for consistent testing
@pytest.fixture(autouse=True)
def setup_test_environment(monkeypatch):
"""Set up test environment variables."""
monkeypatch.setenv("PYTEST_RUNNING", "1")
# Ensure we don't accidentally hit real APIs during tests
monkeypatch.setenv("GITHUB_API_URL", "http://mock-api.test")