🧪 Testing Infrastructure: - Unit tests for authentication system with JWT validation - Integration tests for API endpoints and cluster management - End-to-end tests for complete workflows and performance - Test runner script with pytest configuration - pytest.ini with proper markers and settings 📚 Documentation: - mkdocs.yml configuration for GitHub Pages deployment - Professional documentation structure with Material theme - Navigation for installation, architecture, and examples �� CI/CD Pipeline Improvements: - Fixed .drone.yml with proper test execution stages - Added unit, integration, and e2e test steps - Security scanning with Bandit and Safety - Docker multi-stage builds for controller/agent - Documentation deployment to GitHub Pages - Performance testing and coverage reporting ✅ Test Coverage: - Authentication system: JWT tokens, HMAC signatures, encryption - Database operations: agent credentials, token management - API integration: endpoints, middleware, WebSocket - E2E workflows: registration, security incidents, monitoring - Performance benchmarks: concurrent auth, API throughput 🛡️ Quality Assurance: - Code linting with flake8, black, isort - Security vulnerability scanning - Container image security checks with Trivy - Dependency safety verification - Test coverage reporting with pytest-cov
233 lines
6.4 KiB
Python
233 lines
6.4 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Test runner script for all PyGuardian tests.
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
import subprocess
|
|
import time
|
|
from pathlib import Path
|
|
|
|
def print_banner():
|
|
"""Print test banner."""
|
|
print("=" * 60)
|
|
print("🧪 PyGuardian Test Suite Runner")
|
|
print("=" * 60)
|
|
|
|
def run_unit_tests():
|
|
"""Run unit tests."""
|
|
print("\n📝 Running Unit Tests...")
|
|
print("-" * 30)
|
|
|
|
try:
|
|
# Run unit tests
|
|
result = subprocess.run([
|
|
sys.executable, '-m', 'pytest',
|
|
'tests/unit/',
|
|
'-v', '--tb=short'
|
|
], capture_output=True, text=True, cwd=Path(__file__).parent.parent)
|
|
|
|
print(result.stdout)
|
|
if result.stderr:
|
|
print("STDERR:", result.stderr)
|
|
|
|
return result.returncode == 0
|
|
except Exception as e:
|
|
print(f"❌ Unit tests failed: {e}")
|
|
return False
|
|
|
|
def run_integration_tests():
|
|
"""Run integration tests."""
|
|
print("\n🔄 Running Integration Tests...")
|
|
print("-" * 30)
|
|
|
|
try:
|
|
result = subprocess.run([
|
|
sys.executable, '-m', 'pytest',
|
|
'tests/integration/',
|
|
'-v', '--tb=short'
|
|
], capture_output=True, text=True, cwd=Path(__file__).parent.parent)
|
|
|
|
print(result.stdout)
|
|
if result.stderr:
|
|
print("STDERR:", result.stderr)
|
|
|
|
return result.returncode == 0
|
|
except Exception as e:
|
|
print(f"❌ Integration tests failed: {e}")
|
|
return False
|
|
|
|
def run_e2e_tests():
|
|
"""Run end-to-end tests."""
|
|
print("\n🎯 Running End-to-End Tests...")
|
|
print("-" * 30)
|
|
|
|
try:
|
|
result = subprocess.run([
|
|
sys.executable, '-m', 'pytest',
|
|
'tests/e2e/',
|
|
'-v', '--tb=short'
|
|
], capture_output=True, text=True, cwd=Path(__file__).parent.parent)
|
|
|
|
print(result.stdout)
|
|
if result.stderr:
|
|
print("STDERR:", result.stderr)
|
|
|
|
return result.returncode == 0
|
|
except Exception as e:
|
|
print(f"❌ E2E tests failed: {e}")
|
|
return False
|
|
|
|
def run_coverage_report():
|
|
"""Generate coverage report."""
|
|
print("\n📊 Generating Coverage Report...")
|
|
print("-" * 30)
|
|
|
|
try:
|
|
# Run tests with coverage
|
|
result = subprocess.run([
|
|
sys.executable, '-m', 'pytest',
|
|
'--cov=src',
|
|
'--cov-report=html',
|
|
'--cov-report=term-missing',
|
|
'tests/'
|
|
], capture_output=True, text=True, cwd=Path(__file__).parent.parent)
|
|
|
|
print(result.stdout)
|
|
if result.stderr:
|
|
print("STDERR:", result.stderr)
|
|
|
|
return result.returncode == 0
|
|
except Exception as e:
|
|
print(f"❌ Coverage report failed: {e}")
|
|
return False
|
|
|
|
def run_linting():
|
|
"""Run code linting."""
|
|
print("\n🔍 Running Code Linting...")
|
|
print("-" * 30)
|
|
|
|
try:
|
|
# Run flake8 linting
|
|
result = subprocess.run([
|
|
sys.executable, '-m', 'flake8',
|
|
'src/', 'tests/',
|
|
'--max-line-length=100',
|
|
'--ignore=E203,W503'
|
|
], capture_output=True, text=True, cwd=Path(__file__).parent.parent)
|
|
|
|
if result.stdout:
|
|
print("Linting issues found:")
|
|
print(result.stdout)
|
|
else:
|
|
print("✅ No linting issues found")
|
|
|
|
return result.returncode == 0
|
|
except Exception as e:
|
|
print(f"❌ Linting failed: {e}")
|
|
return False
|
|
|
|
def check_dependencies():
|
|
"""Check if required dependencies are installed."""
|
|
print("\n📦 Checking Dependencies...")
|
|
print("-" * 30)
|
|
|
|
required_packages = [
|
|
'pytest',
|
|
'pytest-cov',
|
|
'flake8',
|
|
'PyJWT',
|
|
'cryptography'
|
|
]
|
|
|
|
missing_packages = []
|
|
|
|
for package in required_packages:
|
|
try:
|
|
__import__(package.replace('-', '_').lower())
|
|
print(f"✅ {package}")
|
|
except ImportError:
|
|
print(f"❌ {package}")
|
|
missing_packages.append(package)
|
|
|
|
if missing_packages:
|
|
print(f"\n⚠️ Missing packages: {', '.join(missing_packages)}")
|
|
print("Install with: pip install " + " ".join(missing_packages))
|
|
return False
|
|
|
|
return True
|
|
|
|
def main():
|
|
"""Main test runner."""
|
|
print_banner()
|
|
|
|
start_time = time.time()
|
|
|
|
# Check dependencies first
|
|
if not check_dependencies():
|
|
print("\n❌ Dependency check failed. Please install missing packages.")
|
|
return 1
|
|
|
|
# Track results
|
|
results = {
|
|
'unit': True,
|
|
'integration': True,
|
|
'e2e': True,
|
|
'linting': True,
|
|
'coverage': True
|
|
}
|
|
|
|
# Run different test suites based on arguments
|
|
if len(sys.argv) > 1:
|
|
test_type = sys.argv[1]
|
|
if test_type == 'unit':
|
|
results['unit'] = run_unit_tests()
|
|
elif test_type == 'integration':
|
|
results['integration'] = run_integration_tests()
|
|
elif test_type == 'e2e':
|
|
results['e2e'] = run_e2e_tests()
|
|
elif test_type == 'lint':
|
|
results['linting'] = run_linting()
|
|
elif test_type == 'coverage':
|
|
results['coverage'] = run_coverage_report()
|
|
else:
|
|
print(f"Unknown test type: {test_type}")
|
|
print("Available types: unit, integration, e2e, lint, coverage")
|
|
return 1
|
|
else:
|
|
# Run all tests
|
|
results['linting'] = run_linting()
|
|
results['unit'] = run_unit_tests()
|
|
results['integration'] = run_integration_tests()
|
|
results['e2e'] = run_e2e_tests()
|
|
results['coverage'] = run_coverage_report()
|
|
|
|
# Print final summary
|
|
end_time = time.time()
|
|
duration = end_time - start_time
|
|
|
|
print("\n" + "=" * 60)
|
|
print("📊 Test Summary")
|
|
print("=" * 60)
|
|
|
|
total_tests = len(results)
|
|
passed_tests = sum(1 for result in results.values() if result)
|
|
failed_tests = total_tests - passed_tests
|
|
|
|
for test_name, result in results.items():
|
|
status = "✅ PASS" if result else "❌ FAIL"
|
|
print(f"{test_name.upper():12} {status}")
|
|
|
|
print("-" * 60)
|
|
print(f"Total: {total_tests}")
|
|
print(f"Passed: {passed_tests}")
|
|
print(f"Failed: {failed_tests}")
|
|
print(f"Duration: {duration:.2f}s")
|
|
print("=" * 60)
|
|
|
|
# Return appropriate exit code
|
|
return 0 if all(results.values()) else 1
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main()) |