Files
michaelschiemer/tests/Performance/PerformanceTestCase.php
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
2025-10-25 19:18:37 +02:00

167 lines
5.2 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Performance;
use App\Framework\Performance\Contracts\PerformanceCollectorInterface;
use App\Framework\Performance\PerformanceCategory;
use App\Framework\Core\ValueObjects\Duration;
/**
* Base class for performance tests
*
* Provides utilities for benchmarking and performance measurement
*/
abstract readonly class PerformanceTestCase
{
public function __construct(
protected PerformanceCollectorInterface $collector
) {}
/**
* Benchmark a callable operation
*
* @param callable $operation The operation to benchmark
* @param int $iterations Number of iterations to run
* @param string $name Benchmark name for reporting
* @return PerformanceBenchmarkResult
*/
protected function benchmark(
callable $operation,
int $iterations = 1000,
string $name = 'benchmark'
): PerformanceBenchmarkResult {
// Warmup run
$operation();
// Clear any existing metrics
gc_collect_cycles();
$durations = [];
$memoryUsages = [];
$startMemory = memory_get_usage(true);
$startTime = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$iterationStart = hrtime(true);
$iterationMemoryStart = memory_get_usage(true);
$operation();
$iterationEnd = hrtime(true);
$iterationMemoryEnd = memory_get_usage(true);
$durations[] = ($iterationEnd - $iterationStart) / 1e6; // Convert to milliseconds
$memoryUsages[] = $iterationMemoryEnd - $iterationMemoryStart;
}
$endTime = microtime(true);
$endMemory = memory_get_usage(true);
$totalTime = ($endTime - $startTime) * 1000; // milliseconds
$avgTime = $totalTime / $iterations;
$minTime = min($durations);
$maxTime = max($durations);
$medianTime = $this->calculateMedian($durations);
$p95Time = $this->calculatePercentile($durations, 95);
$p99Time = $this->calculatePercentile($durations, 99);
$avgMemory = array_sum($memoryUsages) / count($memoryUsages);
$peakMemory = $endMemory - $startMemory;
$operationsPerSecond = 1000 / $avgTime;
return new PerformanceBenchmarkResult(
name: $name,
iterations: $iterations,
totalTimeMs: $totalTime,
avgTimeMs: $avgTime,
minTimeMs: $minTime,
maxTimeMs: $maxTime,
medianTimeMs: $medianTime,
p95TimeMs: $p95Time,
p99TimeMs: $p99Time,
avgMemoryBytes: (int) $avgMemory,
peakMemoryBytes: $peakMemory,
operationsPerSecond: $operationsPerSecond
);
}
/**
* Assert performance meets threshold
*/
protected function assertPerformanceThreshold(
PerformanceBenchmarkResult $result,
float $maxAvgTimeMs,
?int $maxMemoryBytes = null
): void {
if ($result->avgTimeMs > $maxAvgTimeMs) {
throw new \RuntimeException(
"Performance threshold exceeded: {$result->name} took {$result->avgTimeMs}ms (limit: {$maxAvgTimeMs}ms)"
);
}
if ($maxMemoryBytes !== null && $result->peakMemoryBytes > $maxMemoryBytes) {
$peakMb = round($result->peakMemoryBytes / 1024 / 1024, 2);
$limitMb = round($maxMemoryBytes / 1024 / 1024, 2);
throw new \RuntimeException(
"Memory threshold exceeded: {$result->name} used {$peakMb}MB (limit: {$limitMb}MB)"
);
}
}
/**
* Record benchmark result in performance collector
*/
protected function recordBenchmark(
PerformanceBenchmarkResult $result,
PerformanceCategory $category = PerformanceCategory::CUSTOM
): void {
$this->collector->recordMetric(
"benchmark_{$result->name}",
$category,
$result->avgTimeMs,
[
'iterations' => $result->iterations,
'min_ms' => $result->minTimeMs,
'max_ms' => $result->maxTimeMs,
'median_ms' => $result->medianTimeMs,
'p95_ms' => $result->p95TimeMs,
'p99_ms' => $result->p99TimeMs,
'ops_per_sec' => $result->operationsPerSecond,
'memory_avg_mb' => round($result->avgMemoryBytes / 1024 / 1024, 2),
'memory_peak_mb' => round($result->peakMemoryBytes / 1024 / 1024, 2)
]
);
}
/**
* Calculate median value
*/
private function calculateMedian(array $values): float
{
sort($values);
$count = count($values);
$middle = floor($count / 2);
if ($count % 2 === 0) {
return ($values[$middle - 1] + $values[$middle]) / 2;
}
return $values[$middle];
}
/**
* Calculate percentile value
*/
private function calculatePercentile(array $values, int $percentile): float
{
sort($values);
$count = count($values);
$index = ceil($count * ($percentile / 100)) - 1;
return $values[(int) max(0, min($index, $count - 1))];
}
}