Community edition generated from private repo via sync pipeline. Includes 9 plugins (WordPress, WooCommerce, WP Advanced, Gitea, n8n, Supabase, OpenPanel, Appwrite, Directus) with ~587 tools. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
310 lines
10 KiB
Python
310 lines
10 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Integration Test Script for WordPress MCP Server
|
|
|
|
Usage:
|
|
python tests/run_integration_tests.py
|
|
|
|
Requirements:
|
|
- Server must be running
|
|
- WordPress sites configured in environment variables
|
|
- Valid API keys set up
|
|
|
|
This script tests:
|
|
1. Plugin imports and initialization
|
|
2. Handler functionality with real WordPress sites
|
|
3. Error handling
|
|
4. Tool specifications
|
|
|
|
Results are output as JSON for easy parsing.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
from datetime import UTC, datetime
|
|
|
|
# Add parent directory to path
|
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
|
|
|
|
|
class IntegrationTester:
|
|
"""Run integration tests for WordPress MCP server"""
|
|
|
|
def __init__(self):
|
|
self.results = {
|
|
"timestamp": datetime.now(UTC).isoformat(),
|
|
"tests": [],
|
|
"summary": {"total": 0, "passed": 0, "failed": 0, "skipped": 0},
|
|
}
|
|
|
|
def add_result(self, test_name, status, message="", details=None):
|
|
"""Add a test result"""
|
|
self.results["tests"].append(
|
|
{"name": test_name, "status": status, "message": message, "details": details or {}}
|
|
)
|
|
self.results["summary"]["total"] += 1
|
|
self.results["summary"][status] += 1
|
|
|
|
def test_imports(self):
|
|
"""Test 1: Import all modules"""
|
|
try:
|
|
|
|
self.add_result("imports", "passed", "All modules imported successfully")
|
|
return True
|
|
except Exception as e:
|
|
self.add_result("imports", "failed", f"Import error: {str(e)}")
|
|
return False
|
|
|
|
def test_base_plugin(self):
|
|
"""Test 2: BasePlugin architecture"""
|
|
try:
|
|
from plugins.base import BasePlugin
|
|
from plugins.wordpress.plugin import WordPressPlugin
|
|
|
|
# Check that get_tools is not abstract
|
|
assert hasattr(BasePlugin, "get_tools"), "BasePlugin missing get_tools"
|
|
assert hasattr(
|
|
BasePlugin, "get_tool_specifications"
|
|
), "BasePlugin missing get_tool_specifications"
|
|
|
|
# Check WordPress plugin has get_tool_specifications
|
|
assert hasattr(
|
|
WordPressPlugin, "get_tool_specifications"
|
|
), "WordPress missing get_tool_specifications"
|
|
|
|
# Get tool specifications without instantiation
|
|
specs = WordPressPlugin.get_tool_specifications()
|
|
|
|
self.add_result(
|
|
"base_plugin",
|
|
"passed",
|
|
"BasePlugin architecture correct",
|
|
{"tool_count": len(specs)},
|
|
)
|
|
return True
|
|
except Exception as e:
|
|
self.add_result("base_plugin", "failed", f"BasePlugin error: {str(e)}")
|
|
return False
|
|
|
|
def test_wordpress_plugin_init(self):
|
|
"""Test 3: WordPress plugin initialization"""
|
|
try:
|
|
from plugins.wordpress.plugin import WordPressPlugin
|
|
|
|
# Try to create instance with dummy config
|
|
config = {"url": "https://example.com", "username": "test", "app_password": "test"}
|
|
|
|
plugin = WordPressPlugin(config)
|
|
|
|
# Check handlers initialized
|
|
assert hasattr(plugin, "posts"), "Missing posts handler"
|
|
assert hasattr(plugin, "media"), "Missing media handler"
|
|
assert hasattr(plugin, "products"), "Missing products handler"
|
|
assert hasattr(plugin, "orders"), "Missing orders handler"
|
|
|
|
self.add_result(
|
|
"wordpress_plugin_init", "passed", "WordPress plugin initializes correctly"
|
|
)
|
|
return True
|
|
except Exception as e:
|
|
self.add_result("wordpress_plugin_init", "failed", f"Plugin init error: {str(e)}")
|
|
return False
|
|
|
|
def test_tool_specifications(self):
|
|
"""Test 4: Tool specifications format"""
|
|
try:
|
|
from plugins.wordpress.plugin import WordPressPlugin
|
|
|
|
specs = WordPressPlugin.get_tool_specifications()
|
|
|
|
if not specs:
|
|
self.add_result("tool_specifications", "failed", "No tool specifications returned")
|
|
return False
|
|
|
|
# Check first spec has required fields
|
|
first_spec = specs[0]
|
|
required_fields = ["name", "method_name", "description", "schema", "scope"]
|
|
|
|
for field in required_fields:
|
|
if field not in first_spec:
|
|
self.add_result(
|
|
"tool_specifications",
|
|
"failed",
|
|
f"Tool spec missing required field: {field}",
|
|
)
|
|
return False
|
|
|
|
self.add_result(
|
|
"tool_specifications",
|
|
"passed",
|
|
f"Tool specifications format correct ({len(specs)} tools)",
|
|
{"total_tools": len(specs), "sample_tool": first_spec.get("name")},
|
|
)
|
|
return True
|
|
except Exception as e:
|
|
self.add_result("tool_specifications", "failed", f"Tool specifications error: {str(e)}")
|
|
return False
|
|
|
|
def test_handlers_structure(self):
|
|
"""Test 5: Handlers structure"""
|
|
try:
|
|
from plugins.wordpress import handlers
|
|
|
|
expected_handlers = [
|
|
"PostsHandler",
|
|
"MediaHandler",
|
|
"TaxonomyHandler",
|
|
"CommentsHandler",
|
|
"UsersHandler",
|
|
"SiteHandler",
|
|
"ProductsHandler",
|
|
"OrdersHandler",
|
|
"CustomersHandler",
|
|
"ReportsHandler",
|
|
"CouponsHandler",
|
|
"SEOHandler",
|
|
"WPCLIHandler",
|
|
"MenusHandler",
|
|
]
|
|
|
|
missing = []
|
|
for handler_name in expected_handlers:
|
|
if not hasattr(handlers, handler_name):
|
|
missing.append(handler_name)
|
|
|
|
if missing:
|
|
self.add_result(
|
|
"handlers_structure", "failed", f"Missing handlers: {', '.join(missing)}"
|
|
)
|
|
return False
|
|
|
|
self.add_result(
|
|
"handlers_structure", "passed", f"All {len(expected_handlers)} handlers present"
|
|
)
|
|
return True
|
|
except Exception as e:
|
|
self.add_result("handlers_structure", "failed", f"Handlers structure error: {str(e)}")
|
|
return False
|
|
|
|
def test_pydantic_schemas(self):
|
|
"""Test 6: Pydantic schemas"""
|
|
try:
|
|
from plugins.wordpress.schemas import (
|
|
PaginationParams,
|
|
)
|
|
|
|
# Test basic validation
|
|
pagination = PaginationParams(per_page=10, page=1)
|
|
assert pagination.per_page == 10
|
|
assert pagination.page == 1
|
|
|
|
# Test validation errors
|
|
try:
|
|
PaginationParams(per_page=200, page=1) # Should fail (max 100)
|
|
self.add_result(
|
|
"pydantic_schemas",
|
|
"failed",
|
|
"Pydantic validation not working (should reject per_page > 100)",
|
|
)
|
|
return False
|
|
except Exception:
|
|
pass # Expected error
|
|
|
|
self.add_result("pydantic_schemas", "passed", "Pydantic schemas validate correctly")
|
|
return True
|
|
except Exception as e:
|
|
self.add_result("pydantic_schemas", "failed", f"Pydantic schemas error: {str(e)}")
|
|
return False
|
|
|
|
def test_option_b_integration(self):
|
|
"""Test 7: Option B architecture integration"""
|
|
try:
|
|
from core import SiteManager, ToolGenerator
|
|
|
|
# Create site manager
|
|
site_manager = SiteManager()
|
|
|
|
# Create tool generator
|
|
tool_generator = ToolGenerator(site_manager)
|
|
|
|
# This would normally generate tools, but we can't test without real sites
|
|
# Just check the method exists
|
|
assert hasattr(tool_generator, "generate_tools")
|
|
|
|
self.add_result(
|
|
"option_b_integration", "passed", "Option B architecture integration ready"
|
|
)
|
|
return True
|
|
except Exception as e:
|
|
self.add_result(
|
|
"option_b_integration", "failed", f"Option B integration error: {str(e)}"
|
|
)
|
|
return False
|
|
|
|
def run_all_tests(self):
|
|
"""Run all tests"""
|
|
print("🧪 Running Integration Tests for WordPress MCP Server")
|
|
print("=" * 60)
|
|
|
|
tests = [
|
|
self.test_imports,
|
|
self.test_base_plugin,
|
|
self.test_wordpress_plugin_init,
|
|
self.test_tool_specifications,
|
|
self.test_handlers_structure,
|
|
self.test_pydantic_schemas,
|
|
self.test_option_b_integration,
|
|
]
|
|
|
|
for test in tests:
|
|
test_name = test.__name__.replace("test_", "").replace("_", " ").title()
|
|
print(f"\n📋 Running: {test_name}...", end=" ")
|
|
|
|
try:
|
|
success = test()
|
|
if success:
|
|
print("✅ PASSED")
|
|
else:
|
|
print("❌ FAILED")
|
|
except Exception as e:
|
|
print(f"❌ ERROR: {str(e)}")
|
|
self.add_result(test.__name__, "failed", f"Unexpected error: {str(e)}")
|
|
|
|
# Print summary
|
|
print("\n" + "=" * 60)
|
|
print("📊 Test Summary:")
|
|
print(f" Total: {self.results['summary']['total']}")
|
|
print(f" ✅ Passed: {self.results['summary']['passed']}")
|
|
print(f" ❌ Failed: {self.results['summary']['failed']}")
|
|
print(f" ⏭️ Skipped: {self.results['summary']['skipped']}")
|
|
|
|
# Print detailed results
|
|
print("\n📝 Detailed Results:")
|
|
for test in self.results["tests"]:
|
|
status_emoji = "✅" if test["status"] == "passed" else "❌"
|
|
print(f" {status_emoji} {test['name']}: {test['message']}")
|
|
|
|
return self.results
|
|
|
|
|
|
def main():
|
|
"""Main entry point"""
|
|
tester = IntegrationTester()
|
|
results = tester.run_all_tests()
|
|
|
|
# Output JSON for programmatic parsing
|
|
print("\n" + "=" * 60)
|
|
print("📄 JSON Results:")
|
|
print(json.dumps(results, indent=2))
|
|
|
|
# Exit with error code if any tests failed
|
|
if results["summary"]["failed"] > 0:
|
|
sys.exit(1)
|
|
else:
|
|
sys.exit(0)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|