Files
michaelschiemer/tests/debug/test-ml-adapters.php
Michael Schiemer 3b623e7afb feat(Deployment): Integrate Ansible deployment via PHP deployment pipeline
- Create AnsibleDeployStage using framework's Process module for secure command execution
- Integrate AnsibleDeployStage into DeploymentPipelineCommands for production deployments
- Add force_deploy flag support in Ansible playbook to override stale locks
- Use PHP deployment module as orchestrator (php console.php deploy:production)
- Fix ErrorAggregationInitializer to use Environment class instead of $_ENV superglobal

Architecture:
- BuildStage → AnsibleDeployStage → HealthCheckStage for production
- Process module provides timeout, error handling, and output capture
- Ansible playbook supports rollback via rollback-git-based.yml
- Zero-downtime deployments with health checks
2025-10-26 14:08:07 +01:00

272 lines
12 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
/**
* ML Adapter Integration Tests
*
* Tests all 3 ML adapters with ModelRegistry and ModelPerformanceMonitor:
* 1. QueueAnomalyModelAdapter
* 2. WafBehavioralModelAdapter
* 3. NPlusOneModelAdapter
*/
require_once __DIR__ . '/../../vendor/autoload.php';
use App\Framework\Queue\MachineLearning\QueueAnomalyModelAdapter;
use App\Framework\Queue\MachineLearning\JobAnomalyDetector;
use App\Framework\Queue\MachineLearning\ValueObjects\JobFeatures;
use App\Framework\Waf\MachineLearning\WafBehavioralModelAdapter;
use App\Framework\Waf\MachineLearning\BehaviorAnomalyDetector;
use App\Framework\Waf\MachineLearning\ValueObjects\BehaviorFeatures;
use App\Framework\Database\NPlusOneDetection\MachineLearning\NPlusOneModelAdapter;
use App\Framework\Database\NPlusOneDetection\MachineLearning\NPlusOneDetectionEngine;
use App\Framework\MachineLearning\ModelManagement\InMemoryModelRegistry;
use App\Framework\MachineLearning\ModelManagement\ModelPerformanceMonitor;
use App\Framework\MachineLearning\ModelManagement\InMemoryPerformanceStorage;
use App\Framework\MachineLearning\ModelManagement\NullAlertingService;
use App\Framework\Core\ValueObjects\Score;
echo "=== ML Adapter Integration Tests ===\n\n";
try {
// Initialize shared infrastructure
echo "1. Initializing Model Management Infrastructure...\n";
$registry = new InMemoryModelRegistry();
$storage = new InMemoryPerformanceStorage();
$alerting = new NullAlertingService();
$performanceMonitor = new ModelPerformanceMonitor($registry, $storage, $alerting);
echo " ✓ ModelRegistry created\n";
echo " ✓ PerformanceStorage created\n";
echo " ✓ ModelPerformanceMonitor created\n\n";
// ========================================================================
// Test 1: QueueAnomalyModelAdapter
// ========================================================================
echo "2. Testing QueueAnomalyModelAdapter...\n";
// Create detector and adapter
$queueDetector = new JobAnomalyDetector(
anomalyThreshold: new Score(0.4),
zScoreThreshold: 3.0,
iqrMultiplier: 1.5
);
$queueAdapter = new QueueAnomalyModelAdapter(
$registry,
$performanceMonitor,
$queueDetector
);
// Register model
echo " → Registering queue-anomaly model...\n";
$queueMetadata = $queueAdapter->registerCurrentModel();
echo " ✓ Model registered: {$queueMetadata->modelName} v{$queueMetadata->version->toString()}\n";
// Test with normal features
echo " → Testing with normal job features...\n";
$normalFeatures = new JobFeatures(
executionTimeVariance: 0.15,
memoryUsagePattern: 0.10,
retryFrequency: 0.0,
failureRate: 0.05,
queueDepthCorrelation: 0.10,
dependencyChainComplexity: 0.08,
payloadSizeAnomaly: 0.05,
executionTimingRegularity: 0.30
);
$normalResult = $queueAdapter->analyzeWithTracking($normalFeatures, groundTruth: false);
echo " ✓ Analysis: " . ($normalResult['is_anomalous'] ? "ANOMALOUS" : "NORMAL") . "\n";
echo " ✓ Score: " . sprintf("%.2f%%", $normalResult['anomaly_score'] * 100) . "\n";
echo " ✓ Tracking: {$normalResult['tracking']['prediction']} (ground truth: false)\n";
// Test with anomalous features
echo " → Testing with anomalous job features...\n";
$anomalousFeatures = new JobFeatures(
executionTimeVariance: 0.85,
memoryUsagePattern: 0.75,
retryFrequency: 0.85,
failureRate: 0.65,
queueDepthCorrelation: 0.50,
dependencyChainComplexity: 0.30,
payloadSizeAnomaly: 0.35,
executionTimingRegularity: 0.20
);
$anomalousResult = $queueAdapter->analyzeWithTracking($anomalousFeatures, groundTruth: true);
echo " ✓ Analysis: " . ($anomalousResult['is_anomalous'] ? "ANOMALOUS" : "NORMAL") . "\n";
echo " ✓ Score: " . sprintf("%.2f%%", $anomalousResult['anomaly_score'] * 100) . "\n";
echo " ✓ Tracking: {$anomalousResult['tracking']['prediction']} (ground truth: true)\n";
// Get performance metrics
echo " → Checking performance metrics...\n";
$queueMetrics = $queueAdapter->getCurrentPerformanceMetrics();
echo " ✓ Total predictions: {$queueMetrics['total_predictions']}\n";
echo " ✓ Accuracy: " . sprintf("%.2f%%", $queueMetrics['accuracy'] * 100) . "\n\n";
// ========================================================================
// Test 2: WafBehavioralModelAdapter
// ========================================================================
echo "3. Testing WafBehavioralModelAdapter...\n";
// Create detector and adapter
$wafDetector = new BehaviorAnomalyDetector(
anomalyThreshold: new Score(0.5),
zScoreThreshold: 2.5,
iqrMultiplier: 1.5
);
$wafAdapter = new WafBehavioralModelAdapter(
$registry,
$performanceMonitor,
$wafDetector
);
// Register model
echo " → Registering waf-behavioral model...\n";
$wafMetadata = $wafAdapter->registerCurrentModel();
echo " ✓ Model registered: {$wafMetadata->modelName} v{$wafMetadata->version->toString()}\n";
// Test with benign request
echo " → Testing with benign request features...\n";
$benignFeatures = new BehaviorFeatures(
requestFrequency: 0.2,
endpointDiversity: 2.5, // Moderate diversity
parameterEntropy: 3.0, // Normal entropy
userAgentConsistency: 0.9, // Consistent UA
geographicAnomaly: 0.1, // Same location
timePatternRegularity: 0.3, // Human-like timing
payloadSimilarity: 0.4, // Varied payloads
httpMethodDistribution: 0.6 // Mixed methods
);
$benignResult = $wafAdapter->analyzeWithTracking($benignFeatures, historicalBaseline: [], groundTruth: false);
echo " ✓ Analysis: " . ($benignResult['is_anomalous'] ? "MALICIOUS" : "BENIGN") . "\n";
echo " ✓ Score: " . sprintf("%.2f%%", $benignResult['anomaly_score'] * 100) . "\n";
echo " ✓ Tracking: {$benignResult['tracking']['prediction']} (ground truth: false)\n";
// Test with malicious request
echo " → Testing with malicious request features...\n";
$maliciousFeatures = new BehaviorFeatures(
requestFrequency: 20.0, // Very high frequency (>10/s)
endpointDiversity: 0.5, // Low diversity (scanning)
parameterEntropy: 7.0, // High entropy (probing)
userAgentConsistency: 0.1, // Inconsistent UA
geographicAnomaly: 0.85, // Suspicious location changes
timePatternRegularity: 0.95, // Automated timing
payloadSimilarity: 0.9, // Repetitive payloads
httpMethodDistribution: 0.2 // Limited methods
);
$maliciousResult = $wafAdapter->analyzeWithTracking($maliciousFeatures, historicalBaseline: [], groundTruth: true);
echo " ✓ Analysis: " . ($maliciousResult['is_anomalous'] ? "MALICIOUS" : "BENIGN") . "\n";
echo " ✓ Score: " . sprintf("%.2f%%", $maliciousResult['anomaly_score'] * 100) . "\n";
echo " ✓ Tracking: {$maliciousResult['tracking']['prediction']} (ground truth: true)\n";
// Get performance metrics
echo " → Checking performance metrics...\n";
$wafMetrics = $wafAdapter->getCurrentPerformanceMetrics();
echo " ✓ Total predictions: {$wafMetrics['total_predictions']}\n";
echo " ✓ Accuracy: " . sprintf("%.2f%%", $wafMetrics['accuracy'] * 100) . "\n\n";
// ========================================================================
// Test 3: NPlusOneModelAdapter
// ========================================================================
echo "4. Testing NPlusOneModelAdapter...\n";
echo " Requires QueryExecutionContext and full NPlusOneDetectionEngine\n";
echo " Skipping for now (database-dependent)\n\n";
// ========================================================================
// Model Registry Tests
// ========================================================================
echo "5. Testing ModelRegistry Integration...\n";
// List all registered models
echo " → Listing registered models...\n";
$modelNames = $registry->getAllModelNames();
echo " ✓ Total model types registered: " . count($modelNames) . "\n";
foreach ($modelNames as $modelName) {
$versions = $registry->getAll($modelName);
foreach ($versions as $metadata) {
echo " - {$metadata->modelName} v{$metadata->version->toString()}\n";
echo " Type: {$metadata->modelType->value}\n";
echo " Created: {$metadata->createdAt->format('Y-m-d H:i:s')}\n";
}
}
// Test model existence
echo " → Testing model existence checks...\n";
$queueExists = $registry->exists('queue-anomaly', \App\Framework\Core\ValueObjects\Version::fromString('1.0.0'));
$wafExists = $registry->exists('waf-behavioral', \App\Framework\Core\ValueObjects\Version::fromString('1.0.0'));
echo " ✓ queue-anomaly exists: " . ($queueExists ? "YES" : "NO") . "\n";
echo " ✓ waf-behavioral exists: " . ($wafExists ? "YES" : "NO") . "\n\n";
// ========================================================================
// Performance Monitor Tests
// ========================================================================
echo "6. Testing ModelPerformanceMonitor Integration...\n";
// Get metrics for each registered model
echo " → Getting metrics for all registered models...\n";
$allMetrics = [];
foreach ($modelNames as $modelName) {
$versions = $registry->getAll($modelName);
foreach ($versions as $metadata) {
$metrics = $performanceMonitor->getCurrentMetrics(
$metadata->modelName,
$metadata->version
);
$modelKey = "{$metadata->modelName}@{$metadata->version->toString()}";
$allMetrics[$modelKey] = $metrics;
}
}
echo " ✓ Models tracked: " . count($allMetrics) . "\n";
foreach ($allMetrics as $modelKey => $metrics) {
echo " - $modelKey:\n";
echo " Predictions: {$metrics['total_predictions']}\n";
echo " Accuracy: " . sprintf("%.2f%%", $metrics['accuracy'] * 100) . "\n";
if ($metrics['total_predictions'] > 0) {
echo " Avg Confidence: " . sprintf("%.2f%%", $metrics['average_confidence'] * 100) . "\n";
}
}
// Check for performance degradation
echo "\n → Checking for performance degradation...\n";
$queueDegradation = $queueAdapter->checkPerformanceDegradation(0.05);
$wafDegradation = $wafAdapter->checkPerformanceDegradation(0.05);
echo " ✓ queue-anomaly degraded: " . ($queueDegradation['has_degraded'] ? "YES" : "NO") . "\n";
echo " ✓ waf-behavioral degraded: " . ($wafDegradation['has_degraded'] ? "YES" : "NO") . "\n\n";
// ========================================================================
// Test Summary
// ========================================================================
echo "=== Test Summary ===\n";
echo "✓ QueueAnomalyModelAdapter: Working\n";
echo "✓ WafBehavioralModelAdapter: Working\n";
echo "✓ NPlusOneModelAdapter: Skipped (database-dependent)\n";
echo "✓ ModelRegistry: Working\n";
echo "✓ ModelPerformanceMonitor: Working\n";
echo "✓ Model registration: Working\n";
echo "✓ Performance tracking: Working\n";
echo "✓ Accuracy calculation: Working\n\n";
echo "Test Results:\n";
echo " - Queue Adapter: 2 predictions, " . sprintf("%.0f%%", $queueMetrics['accuracy'] * 100) . " accuracy\n";
echo " - WAF Adapter: 2 predictions, " . sprintf("%.0f%%", $wafMetrics['accuracy'] * 100) . " accuracy\n";
echo " - Total models registered: " . $registry->getTotalCount() . "\n";
echo " - Total predictions tracked: " . array_sum(array_column($allMetrics, 'total_predictions')) . "\n\n";
echo "=== ML Adapter Tests PASSED ===\n";
} catch (\Throwable $e) {
echo "\n!!! TEST FAILED !!!\n";
echo "Error: " . $e->getMessage() . "\n";
echo "File: " . $e->getFile() . ":" . $e->getLine() . "\n";
echo "\nStack trace:\n" . $e->getTraceAsString() . "\n";
exit(1);
}