- Migrated from HIVE branding to WHOOSH across all components - Enhanced backend API with new services: AI models, BZZZ integration, templates, members - Added comprehensive testing suite with security, performance, and integration tests - Improved frontend with new components for project setup, AI models, and team management - Updated MCP server implementation with WHOOSH-specific tools and resources - Enhanced deployment configurations with production-ready Docker setups - Added comprehensive documentation and setup guides - Implemented age encryption service and UCXL integration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
449 lines
17 KiB
Python
449 lines
17 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
WHOOSH Integration Test Suite - Phase 5 Comprehensive Testing
|
|
Tests all major system components and their interactions.
|
|
"""
|
|
|
|
import asyncio
|
|
import json
|
|
import os
|
|
import sys
|
|
import time
|
|
import requests
|
|
import subprocess
|
|
from pathlib import Path
|
|
from typing import Dict, List, Optional, Tuple
|
|
from datetime import datetime
|
|
|
|
class WHOOSHIntegrationTester:
|
|
"""Comprehensive integration test suite for WHOOSH system"""
|
|
|
|
def __init__(self):
|
|
self.backend_url = "http://localhost:8087"
|
|
self.frontend_url = "http://localhost:3000"
|
|
self.gitea_url = "http://gitea.home.deepblack.cloud"
|
|
self.test_results = []
|
|
self.failed_tests = []
|
|
|
|
def log_test(self, test_name: str, success: bool, message: str, details: Optional[Dict] = None):
|
|
"""Log test results"""
|
|
result = {
|
|
'test': test_name,
|
|
'success': success,
|
|
'message': message,
|
|
'timestamp': datetime.now().isoformat(),
|
|
'details': details or {}
|
|
}
|
|
self.test_results.append(result)
|
|
|
|
status = "✅" if success else "❌"
|
|
print(f"{status} {test_name}: {message}")
|
|
|
|
if not success:
|
|
self.failed_tests.append(result)
|
|
if details:
|
|
print(f" Details: {json.dumps(details, indent=2)}")
|
|
|
|
def test_system_health(self) -> bool:
|
|
"""Test basic system health and connectivity"""
|
|
print("\n🏥 SYSTEM HEALTH CHECKS")
|
|
print("=" * 50)
|
|
|
|
all_passed = True
|
|
|
|
# Test 1: Backend API Health
|
|
try:
|
|
response = requests.get(f"{self.backend_url}/health", timeout=5)
|
|
success = response.status_code == 200
|
|
data = response.json() if success else None
|
|
|
|
self.log_test(
|
|
"Backend Health Check",
|
|
success,
|
|
f"Status {response.status_code}" + (f" - Version {data.get('version')}" if data else ""),
|
|
{'status_code': response.status_code, 'response': data}
|
|
)
|
|
all_passed &= success
|
|
|
|
except Exception as e:
|
|
self.log_test("Backend Health Check", False, f"Connection failed: {e}")
|
|
all_passed = False
|
|
|
|
# Test 2: Database Connection (through API)
|
|
try:
|
|
response = requests.get(f"{self.backend_url}/api/health", timeout=10)
|
|
success = response.status_code == 200
|
|
data = response.json() if success else None
|
|
|
|
self.log_test(
|
|
"Database Health Check",
|
|
success,
|
|
f"Database connectivity: {'OK' if success else 'FAILED'}",
|
|
{'status_code': response.status_code, 'components': data.get('components', []) if data else []}
|
|
)
|
|
# Note: Database test might fail in development environment, don't mark as critical
|
|
|
|
except Exception as e:
|
|
self.log_test("Database Health Check", False, f"API call failed: {e}")
|
|
|
|
# Test 3: GITEA Connectivity
|
|
try:
|
|
response = requests.get(f"{self.gitea_url}/api/v1/version", timeout=5)
|
|
success = response.status_code == 200
|
|
data = response.json() if success else None
|
|
|
|
self.log_test(
|
|
"GITEA Connectivity",
|
|
success,
|
|
f"GITEA version: {data.get('version', 'Unknown') if data else 'Unavailable'}",
|
|
{'status_code': response.status_code, 'version_info': data}
|
|
)
|
|
all_passed &= success
|
|
|
|
except Exception as e:
|
|
self.log_test("GITEA Connectivity", False, f"Connection failed: {e}")
|
|
all_passed = False
|
|
|
|
# Test 4: File System Permissions
|
|
try:
|
|
templates_path = Path("/home/tony/chorus/project-queues/active/WHOOSH/backend/templates")
|
|
can_read = templates_path.exists() and templates_path.is_dir()
|
|
can_write = os.access(templates_path.parent, os.W_OK)
|
|
|
|
self.log_test(
|
|
"File System Access",
|
|
can_read and can_write,
|
|
f"Templates directory: {'✓ Read' if can_read else '✗ Read'}, {'✓ Write' if can_write else '✗ Write'}",
|
|
{'templates_exist': can_read, 'can_write': can_write, 'path': str(templates_path)}
|
|
)
|
|
all_passed &= (can_read and can_write)
|
|
|
|
except Exception as e:
|
|
self.log_test("File System Access", False, f"Permission check failed: {e}")
|
|
all_passed = False
|
|
|
|
return all_passed
|
|
|
|
def test_template_system(self) -> bool:
|
|
"""Test the template system functionality"""
|
|
print("\n📋 TEMPLATE SYSTEM TESTS")
|
|
print("=" * 50)
|
|
|
|
all_passed = True
|
|
|
|
# Test 1: Template API Endpoint
|
|
try:
|
|
response = requests.get(f"{self.backend_url}/api/templates", timeout=10)
|
|
success = response.status_code == 200
|
|
data = response.json() if success else None
|
|
|
|
template_count = len(data.get('templates', [])) if data else 0
|
|
|
|
self.log_test(
|
|
"Template API Listing",
|
|
success,
|
|
f"Found {template_count} templates",
|
|
{'status_code': response.status_code, 'template_count': template_count}
|
|
)
|
|
all_passed &= success
|
|
|
|
# Test 2: Template Details
|
|
if success and template_count > 0:
|
|
template_id = data['templates'][0]['template_id']
|
|
detail_response = requests.get(f"{self.backend_url}/api/templates/{template_id}", timeout=10)
|
|
detail_success = detail_response.status_code == 200
|
|
detail_data = detail_response.json() if detail_success else None
|
|
|
|
file_count = len(detail_data.get('starter_files', {})) if detail_data else 0
|
|
|
|
self.log_test(
|
|
"Template Detail Retrieval",
|
|
detail_success,
|
|
f"Template '{template_id}' has {file_count} starter files",
|
|
{'template_id': template_id, 'file_count': file_count}
|
|
)
|
|
all_passed &= detail_success
|
|
|
|
except Exception as e:
|
|
self.log_test("Template API Listing", False, f"API call failed: {e}")
|
|
all_passed = False
|
|
|
|
# Test 3: Template File Generation
|
|
try:
|
|
# Test the template service directly (simulated)
|
|
templates_path = Path("/home/tony/chorus/project-queues/active/WHOOSH/backend/templates")
|
|
template_dirs = [d for d in templates_path.iterdir() if d.is_dir()]
|
|
|
|
valid_templates = 0
|
|
for template_dir in template_dirs:
|
|
metadata_file = template_dir / "template.json"
|
|
files_dir = template_dir / "files"
|
|
|
|
if metadata_file.exists() and files_dir.exists():
|
|
valid_templates += 1
|
|
|
|
self.log_test(
|
|
"Template File Structure",
|
|
valid_templates > 0,
|
|
f"{valid_templates} valid templates with complete file structures",
|
|
{'valid_templates': valid_templates, 'total_dirs': len(template_dirs)}
|
|
)
|
|
all_passed &= (valid_templates > 0)
|
|
|
|
except Exception as e:
|
|
self.log_test("Template File Structure", False, f"File system check failed: {e}")
|
|
all_passed = False
|
|
|
|
return all_passed
|
|
|
|
def test_gitea_integration(self) -> bool:
|
|
"""Test GITEA integration functionality"""
|
|
print("\n🔗 GITEA INTEGRATION TESTS")
|
|
print("=" * 50)
|
|
|
|
all_passed = True
|
|
|
|
# Test 1: GITEA API Token Validation
|
|
try:
|
|
# This would test the GITEA service but we need the token
|
|
# For now, just test that the service endpoints exist
|
|
response = requests.get(f"{self.backend_url}/api/projects", timeout=5)
|
|
success = response.status_code in [200, 401] # 401 is OK, means auth is working
|
|
|
|
self.log_test(
|
|
"GITEA Integration Endpoints",
|
|
success,
|
|
f"Projects API accessible (Status: {response.status_code})",
|
|
{'status_code': response.status_code}
|
|
)
|
|
all_passed &= success
|
|
|
|
except Exception as e:
|
|
self.log_test("GITEA Integration Endpoints", False, f"Endpoint test failed: {e}")
|
|
all_passed = False
|
|
|
|
# Test 2: Repository Creation Logic (Mock)
|
|
try:
|
|
# Test the project setup endpoint structure
|
|
test_payload = {
|
|
"project_info": {"name": "test-integration-project", "description": "Test project"},
|
|
"git_config": {"repo_type": "new", "repo_name": "test-repo"},
|
|
"age_config": {"generate_new_key": True},
|
|
"member_config": {"initial_members": []},
|
|
"bzzz_config": {"enable_bzzz": False},
|
|
"advanced_config": {"project_visibility": "private"}
|
|
}
|
|
|
|
# Don't actually create, just test the endpoint structure
|
|
response = requests.post(
|
|
f"{self.backend_url}/api/projects/setup",
|
|
json=test_payload,
|
|
timeout=5
|
|
)
|
|
|
|
# We expect this to fail due to auth/db, but not due to malformed request
|
|
success = response.status_code in [401, 422, 503] # Auth, validation, or service errors are OK
|
|
|
|
self.log_test(
|
|
"Project Setup Endpoint",
|
|
success,
|
|
f"Endpoint properly structured (Status: {response.status_code})",
|
|
{'status_code': response.status_code, 'expected_errors': [401, 422, 503]}
|
|
)
|
|
|
|
except Exception as e:
|
|
self.log_test("Project Setup Endpoint", False, f"Endpoint test failed: {e}")
|
|
all_passed = False
|
|
|
|
return all_passed
|
|
|
|
def test_security_features(self) -> bool:
|
|
"""Test security features and configurations"""
|
|
print("\n🔐 SECURITY FEATURE TESTS")
|
|
print("=" * 50)
|
|
|
|
all_passed = True
|
|
|
|
# Test 1: Age Key Service Structure
|
|
try:
|
|
# Test age key endpoint accessibility
|
|
response = requests.get(f"{self.backend_url}/api/crypto/generate-age-keys", timeout=5)
|
|
# We expect this to require authentication or specific methods
|
|
success = response.status_code in [401, 405, 422]
|
|
|
|
self.log_test(
|
|
"Age Key Endpoints",
|
|
success,
|
|
f"Age key endpoints properly secured (Status: {response.status_code})",
|
|
{'status_code': response.status_code}
|
|
)
|
|
|
|
except Exception as e:
|
|
self.log_test("Age Key Endpoints", False, f"Security test failed: {e}")
|
|
all_passed = False
|
|
|
|
# Test 2: CORS Configuration
|
|
try:
|
|
response = requests.options(f"{self.backend_url}/api/templates", timeout=5)
|
|
headers = response.headers
|
|
has_cors = 'Access-Control-Allow-Origin' in headers
|
|
|
|
self.log_test(
|
|
"CORS Configuration",
|
|
has_cors,
|
|
f"CORS headers {'present' if has_cors else 'missing'}",
|
|
{'cors_headers': dict(headers) if has_cors else {}}
|
|
)
|
|
all_passed &= has_cors
|
|
|
|
except Exception as e:
|
|
self.log_test("CORS Configuration", False, f"CORS test failed: {e}")
|
|
all_passed = False
|
|
|
|
# Test 3: API Documentation Security
|
|
try:
|
|
# Test that docs are accessible but properly configured
|
|
response = requests.get(f"{self.backend_url}/docs", timeout=5)
|
|
success = response.status_code == 200
|
|
|
|
self.log_test(
|
|
"API Documentation",
|
|
success,
|
|
f"OpenAPI documentation {'accessible' if success else 'unavailable'}",
|
|
{'status_code': response.status_code}
|
|
)
|
|
|
|
except Exception as e:
|
|
self.log_test("API Documentation", False, f"Documentation test failed: {e}")
|
|
all_passed = False
|
|
|
|
return all_passed
|
|
|
|
def test_performance_baseline(self) -> bool:
|
|
"""Test basic performance characteristics"""
|
|
print("\n⚡ PERFORMANCE BASELINE TESTS")
|
|
print("=" * 50)
|
|
|
|
all_passed = True
|
|
|
|
# Test 1: API Response Times
|
|
endpoints_to_test = [
|
|
("/health", "Health Check"),
|
|
("/api/templates", "Template Listing"),
|
|
("/docs", "API Documentation")
|
|
]
|
|
|
|
for endpoint, name in endpoints_to_test:
|
|
try:
|
|
start_time = time.time()
|
|
response = requests.get(f"{self.backend_url}{endpoint}", timeout=10)
|
|
response_time = time.time() - start_time
|
|
|
|
# Consider under 2 seconds as acceptable for development
|
|
success = response_time < 2.0 and response.status_code in [200, 401]
|
|
|
|
self.log_test(
|
|
f"Response Time - {name}",
|
|
success,
|
|
f"{response_time:.2f}s (Status: {response.status_code})",
|
|
{'response_time': response_time, 'status_code': response.status_code}
|
|
)
|
|
all_passed &= success
|
|
|
|
except Exception as e:
|
|
self.log_test(f"Response Time - {name}", False, f"Performance test failed: {e}")
|
|
all_passed = False
|
|
|
|
return all_passed
|
|
|
|
def run_all_tests(self) -> Dict:
|
|
"""Run all integration tests and return summary"""
|
|
print("🚀 WHOOSH INTEGRATION TEST SUITE")
|
|
print("=" * 60)
|
|
print(f"Starting comprehensive testing at {datetime.now().isoformat()}")
|
|
print()
|
|
|
|
start_time = time.time()
|
|
|
|
# Run all test suites
|
|
test_suites = [
|
|
("System Health", self.test_system_health),
|
|
("Template System", self.test_template_system),
|
|
("GITEA Integration", self.test_gitea_integration),
|
|
("Security Features", self.test_security_features),
|
|
("Performance Baseline", self.test_performance_baseline)
|
|
]
|
|
|
|
suite_results = {}
|
|
overall_success = True
|
|
|
|
for suite_name, test_func in test_suites:
|
|
try:
|
|
suite_success = test_func()
|
|
suite_results[suite_name] = suite_success
|
|
overall_success &= suite_success
|
|
except Exception as e:
|
|
print(f"❌ {suite_name} suite failed: {e}")
|
|
suite_results[suite_name] = False
|
|
overall_success = False
|
|
|
|
# Generate final report
|
|
end_time = time.time()
|
|
duration = end_time - start_time
|
|
|
|
print("\n📊 TEST SUMMARY")
|
|
print("=" * 60)
|
|
|
|
total_tests = len(self.test_results)
|
|
passed_tests = len([r for r in self.test_results if r['success']])
|
|
failed_tests = len(self.failed_tests)
|
|
|
|
print(f"Total Tests: {total_tests}")
|
|
print(f"Passed: {passed_tests}")
|
|
print(f"Failed: {failed_tests}")
|
|
print(f"Success Rate: {(passed_tests/total_tests*100):.1f}%")
|
|
print(f"Duration: {duration:.2f}s")
|
|
|
|
print(f"\nSuite Results:")
|
|
for suite, success in suite_results.items():
|
|
status = "✅ PASS" if success else "❌ FAIL"
|
|
print(f" {status} {suite}")
|
|
|
|
if self.failed_tests:
|
|
print(f"\n❌ FAILED TESTS ({len(self.failed_tests)}):")
|
|
for test in self.failed_tests:
|
|
print(f" • {test['test']}: {test['message']}")
|
|
|
|
return {
|
|
'overall_success': overall_success,
|
|
'total_tests': total_tests,
|
|
'passed_tests': passed_tests,
|
|
'failed_tests': failed_tests,
|
|
'success_rate': passed_tests/total_tests*100,
|
|
'duration': duration,
|
|
'suite_results': suite_results,
|
|
'detailed_results': self.test_results,
|
|
'failed_test_details': self.failed_tests
|
|
}
|
|
|
|
def main():
|
|
"""Main test runner"""
|
|
tester = WHOOSHIntegrationTester()
|
|
results = tester.run_all_tests()
|
|
|
|
# Save results to file
|
|
results_file = f"integration_test_results_{int(time.time())}.json"
|
|
with open(results_file, 'w') as f:
|
|
json.dump(results, f, indent=2, default=str)
|
|
|
|
print(f"\n📄 Detailed results saved to: {results_file}")
|
|
|
|
if results['overall_success']:
|
|
print("\n🎉 ALL INTEGRATION TESTS PASSED!")
|
|
sys.exit(0)
|
|
else:
|
|
print(f"\n⚠️ SOME TESTS FAILED - Success rate: {results['success_rate']:.1f}%")
|
|
sys.exit(1)
|
|
|
|
if __name__ == "__main__":
|
|
main() |