toString(); $queueName = 'email-queue'; $metrics = JobMetrics::create($jobId, $queueName); expect($metrics->jobId)->toBe($jobId); expect($metrics->queueName)->toBe($queueName); expect($metrics->status)->toBe('pending'); expect($metrics->attempts)->toBe(0); expect($metrics->maxAttempts)->toBe(3); expect($metrics->executionTimeMs)->toBe(0.0); expect($metrics->memoryUsageBytes)->toBe(0); expect($metrics->errorMessage)->toBeNull(); expect($metrics->createdAt)->toBeString(); expect($metrics->startedAt)->toBeNull(); expect($metrics->completedAt)->toBeNull(); expect($metrics->failedAt)->toBeNull(); expect($metrics->metadata)->toBe([]); }); it('can create job metrics with custom parameters', function () { $jobId = JobId::generate()->toString(); $queueName = 'report-queue'; $status = 'running'; $attempts = 2; $maxAttempts = 5; $metrics = JobMetrics::create($jobId, $queueName, $status, $attempts, $maxAttempts); expect($metrics->status)->toBe($status); expect($metrics->attempts)->toBe($attempts); expect($metrics->maxAttempts)->toBe($maxAttempts); }); it('is readonly and immutable', function () { $metrics = JobMetrics::create('test-job', 'test-queue'); $reflection = new ReflectionClass($metrics); expect($reflection->isReadOnly())->toBeTrue(); // All properties should be readonly $properties = ['jobId', 'queueName', 'status', 'attempts', 'maxAttempts', 'executionTimeMs', 'memoryUsageBytes', 'errorMessage', 'createdAt', 'startedAt', 'completedAt', 'failedAt', 'metadata']; foreach ($properties as $prop) { $property = $reflection->getProperty($prop); expect($property->isReadOnly())->toBeTrue("Property {$prop} should be readonly"); } }); }); describe('Job State Transitions', function () { beforeEach(function () { $this->baseMetrics = JobMetrics::create('test-job-123', 'email-queue'); }); it('can transition from pending to running', function () { $startTime = microtime(true) * 1000; // milliseconds $memoryUsage = 1024 * 1024; // 1MB $runningMetrics = $this->baseMetrics->withStarted($startTime, $memoryUsage); expect($runningMetrics->status)->toBe('running'); expect($runningMetrics->attempts)->toBe(1); // Incremented from 0 expect($runningMetrics->executionTimeMs)->toBe($startTime); expect($runningMetrics->memoryUsageBytes)->toBe($memoryUsage); expect($runningMetrics->startedAt)->toBeString(); expect($runningMetrics->startedAt)->not->toBeNull(); // Original should be unchanged expect($this->baseMetrics->status)->toBe('pending'); expect($this->baseMetrics->attempts)->toBe(0); }); it('can transition from running to completed', function () { $startTime = microtime(true) * 1000; $runningMetrics = $this->baseMetrics->withStarted($startTime, 1024 * 1024); $totalExecutionTime = 5500.0; // 5.5 seconds in milliseconds $peakMemoryUsage = 2 * 1024 * 1024; // 2MB $completedMetrics = $runningMetrics->withCompleted($totalExecutionTime, $peakMemoryUsage); expect($completedMetrics->status)->toBe('completed'); expect($completedMetrics->executionTimeMs)->toBe($totalExecutionTime); expect($completedMetrics->memoryUsageBytes)->toBe($peakMemoryUsage); expect($completedMetrics->completedAt)->toBeString(); expect($completedMetrics->completedAt)->not->toBeNull(); expect($completedMetrics->attempts)->toBe(1); // Same as running state }); it('can transition from running to failed', function () { $startTime = microtime(true) * 1000; $runningMetrics = $this->baseMetrics->withStarted($startTime, 1024 * 1024); $errorMessage = 'Database connection timeout'; $executionTime = 2500.0; // 2.5 seconds $memoryUsage = 1.5 * 1024 * 1024; // 1.5MB $failedMetrics = $runningMetrics->withFailed($errorMessage, $executionTime, $memoryUsage); expect($failedMetrics->status)->toBe('failed'); expect($failedMetrics->errorMessage)->toBe($errorMessage); expect($failedMetrics->executionTimeMs)->toBe($executionTime); expect($failedMetrics->memoryUsageBytes)->toBe($memoryUsage); expect($failedMetrics->failedAt)->toBeString(); expect($failedMetrics->failedAt)->not->toBeNull(); }); it('preserves metadata across state transitions', function () { $originalMetadata = ['batch_id' => 123, 'priority' => 'high']; $metricsWithMetadata = $this->baseMetrics->withMetadata($originalMetadata); $runningMetrics = $metricsWithMetadata->withStarted(1000.0, 1024 * 1024); expect($runningMetrics->metadata)->toBe($originalMetadata); $completedMetrics = $runningMetrics->withCompleted(5000.0, 2 * 1024 * 1024); expect($completedMetrics->metadata)->toBe($originalMetadata); }); }); describe('Metadata Management', function () { beforeEach(function () { $this->baseMetrics = JobMetrics::create('test-job', 'test-queue'); }); it('can add metadata to metrics', function () { $metadata = [ 'user_id' => 12345, 'email_template' => 'newsletter', 'batch_size' => 1000, ]; $metricsWithMetadata = $this->baseMetrics->withMetadata($metadata); expect($metricsWithMetadata->metadata)->toBe($metadata); expect($this->baseMetrics->metadata)->toBe([]); // Original unchanged }); it('merges metadata when called multiple times', function () { $firstMetadata = ['user_id' => 123, 'type' => 'email']; $secondMetadata = ['priority' => 'high', 'retry_count' => 2]; $metrics = $this->baseMetrics ->withMetadata($firstMetadata) ->withMetadata($secondMetadata); expect($metrics->metadata)->toBe([ 'user_id' => 123, 'type' => 'email', 'priority' => 'high', 'retry_count' => 2, ]); }); it('overwrites existing metadata keys', function () { $firstMetadata = ['priority' => 'low', 'attempts' => 1]; $secondMetadata = ['priority' => 'high']; // Overwrites priority $metrics = $this->baseMetrics ->withMetadata($firstMetadata) ->withMetadata($secondMetadata); expect($metrics->metadata['priority'])->toBe('high'); expect($metrics->metadata['attempts'])->toBe(1); // Preserved }); }); describe('Status Check Methods', function () { beforeEach(function () { $this->jobId = 'status-test-job'; $this->queueName = 'status-queue'; }); it('correctly identifies pending status', function () { $metrics = JobMetrics::create($this->jobId, $this->queueName, 'pending'); expect($metrics->isPending())->toBeTrue(); expect($metrics->isRunning())->toBeFalse(); expect($metrics->isCompleted())->toBeFalse(); expect($metrics->isFailed())->toBeFalse(); }); it('correctly identifies running status', function () { $metrics = JobMetrics::create($this->jobId, $this->queueName, 'running'); expect($metrics->isRunning())->toBeTrue(); expect($metrics->isPending())->toBeFalse(); expect($metrics->isCompleted())->toBeFalse(); expect($metrics->isFailed())->toBeFalse(); }); it('correctly identifies completed status', function () { $metrics = JobMetrics::create($this->jobId, $this->queueName, 'completed'); expect($metrics->isCompleted())->toBeTrue(); expect($metrics->isPending())->toBeFalse(); expect($metrics->isRunning())->toBeFalse(); expect($metrics->isFailed())->toBeFalse(); }); it('correctly identifies failed status', function () { $metrics = JobMetrics::create($this->jobId, $this->queueName, 'failed'); expect($metrics->isFailed())->toBeTrue(); expect($metrics->isPending())->toBeFalse(); expect($metrics->isRunning())->toBeFalse(); expect($metrics->isCompleted())->toBeFalse(); }); it('correctly checks max attempts', function () { $metrics = JobMetrics::create($this->jobId, $this->queueName, 'running', 2, 3); expect($metrics->hasMaxAttempts())->toBeFalse(); $maxedMetrics = JobMetrics::create($this->jobId, $this->queueName, 'failed', 3, 3); expect($maxedMetrics->hasMaxAttempts())->toBeTrue(); $exceededMetrics = JobMetrics::create($this->jobId, $this->queueName, 'failed', 5, 3); expect($exceededMetrics->hasMaxAttempts())->toBeTrue(); }); }); describe('Calculation Methods', function () { it('calculates success rate correctly', function () { // Job not started yet $pendingMetrics = JobMetrics::create('job', 'queue', 'pending', 0); expect($pendingMetrics->getSuccessRate()->getValue())->toBe(100.0); // Failed job with attempts $failedMetrics = JobMetrics::create('job', 'queue', 'failed', 2); expect($failedMetrics->getSuccessRate()->getValue())->toBe(0.0); // Completed job $completedMetrics = JobMetrics::create('job', 'queue', 'completed', 1); expect($completedMetrics->getSuccessRate()->getValue())->toBe(100.0); }); it('converts execution time from milliseconds to seconds', function () { $metrics = JobMetrics::create('job', 'queue') ->withCompleted(5500.0, 1024 * 1024); // 5.5 seconds expect($metrics->getExecutionTimeSeconds())->toBe(5.5); }); it('converts memory usage from bytes to MB', function () { $metrics = JobMetrics::create('job', 'queue') ->withCompleted(1000.0, 2.5 * 1024 * 1024); // 2.5 MB expect($metrics->getMemoryUsageMB())->toBe(2.5); }); it('calculates duration correctly', function () { $metrics = JobMetrics::create('job', 'queue'); // No duration for pending job expect($metrics->getDuration())->toBeNull(); // Mock started/completed times $startedMetrics = new JobMetrics( jobId: 'job', queueName: 'queue', status: 'completed', attempts: 1, maxAttempts: 3, executionTimeMs: 1000.0, memoryUsageBytes: 1024, errorMessage: null, createdAt: '2024-01-01 10:00:00', startedAt: '2024-01-01 10:00:05', completedAt: '2024-01-01 10:00:15', failedAt: null ); $duration = $startedMetrics->getDuration(); expect($duration)->toBe(10); // 10 seconds difference }); it('calculates duration for failed jobs', function () { $failedMetrics = new JobMetrics( jobId: 'job', queueName: 'queue', status: 'failed', attempts: 2, maxAttempts: 3, executionTimeMs: 500.0, memoryUsageBytes: 1024, errorMessage: 'Error occurred', createdAt: '2024-01-01 10:00:00', startedAt: '2024-01-01 10:00:05', completedAt: null, failedAt: '2024-01-01 10:00:08' ); $duration = $failedMetrics->getDuration(); expect($duration)->toBe(3); // 3 seconds from start to failure }); }); describe('Array Conversion', function () { it('provides comprehensive metrics information', function () { $metrics = JobMetrics::create('test-job-456', 'email-queue', 'completed', 1, 3) ->withCompleted(3750.0, 1.5 * 1024 * 1024) ->withMetadata(['batch_id' => 789, 'template' => 'welcome']); $array = $metrics->toArray(); // Verify all expected keys exist $expectedKeys = [ 'job_id', 'queue_name', 'status', 'attempts', 'max_attempts', 'execution_time_ms', 'execution_time_seconds', 'memory_usage_bytes', 'memory_usage_mb', 'success_rate', 'duration_seconds', 'error_message', 'created_at', 'started_at', 'completed_at', 'failed_at', 'metadata', ]; foreach ($expectedKeys as $key) { expect($array)->toHaveKey($key); } // Verify calculated values expect($array['job_id'])->toBe('test-job-456'); expect($array['queue_name'])->toBe('email-queue'); expect($array['status'])->toBe('completed'); expect($array['execution_time_seconds'])->toBe(3.75); expect($array['memory_usage_mb'])->toBe(1.5); expect($array['success_rate'])->toBe(100.0); expect($array['metadata'])->toBe(['batch_id' => 789, 'template' => 'welcome']); }); it('handles null values correctly in array conversion', function () { $pendingMetrics = JobMetrics::create('pending-job', 'test-queue'); $array = $pendingMetrics->toArray(); expect($array['error_message'])->toBeNull(); expect($array['started_at'])->toBeNull(); expect($array['completed_at'])->toBeNull(); expect($array['failed_at'])->toBeNull(); expect($array['duration_seconds'])->toBeNull(); }); }); describe('Edge Cases and Error Handling', function () { it('handles zero execution time', function () { $metrics = JobMetrics::create('instant-job', 'fast-queue') ->withCompleted(0.0, 1024); expect($metrics->getExecutionTimeSeconds())->toBe(0.0); }); it('handles zero memory usage', function () { $metrics = JobMetrics::create('no-memory-job', 'efficient-queue') ->withCompleted(1000.0, 0); expect($metrics->getMemoryUsageMB())->toBe(0.0); }); it('handles very large execution times', function () { $largeTime = 3600000.0; // 1 hour in milliseconds $metrics = JobMetrics::create('long-job', 'slow-queue') ->withCompleted($largeTime, 1024); expect($metrics->getExecutionTimeSeconds())->toBe(3600.0); // 1 hour }); it('handles very large memory usage', function () { $largeMemory = 10 * 1024 * 1024 * 1024; // 10GB $metrics = JobMetrics::create('memory-intensive-job', 'heavy-queue') ->withCompleted(1000.0, $largeMemory); expect($metrics->getMemoryUsageMB())->toBe(10240.0); // 10GB in MB }); it('handles empty metadata gracefully', function () { $metrics = JobMetrics::create('no-metadata-job', 'simple-queue') ->withMetadata([]); expect($metrics->metadata)->toBe([]); }); it('handles complex metadata structures', function () { $complexMetadata = [ 'nested' => ['level1' => ['level2' => 'value']], 'array' => [1, 2, 3, 4, 5], 'mixed' => ['string', 42, true, null], ]; $metrics = JobMetrics::create('complex-job', 'data-queue') ->withMetadata($complexMetadata); expect($metrics->metadata)->toBe($complexMetadata); }); }); }); describe('Job Metrics Collection Mock System', function () { beforeEach(function () { // Create a mock metrics manager for testing $this->metricsManager = new class () { private array $jobMetrics = []; private array $queueStats = []; public function recordJobExecution(string $jobId, float $executionTimeMs, int $memoryUsage): void { if (! isset($this->jobMetrics[$jobId])) { $this->jobMetrics[$jobId] = JobMetrics::create($jobId, 'default-queue'); } $this->jobMetrics[$jobId] = $this->jobMetrics[$jobId] ->withCompleted($executionTimeMs, $memoryUsage); } public function recordJobFailure(string $jobId, string $errorMessage, float $executionTimeMs, int $memoryUsage): void { if (! isset($this->jobMetrics[$jobId])) { $this->jobMetrics[$jobId] = JobMetrics::create($jobId, 'default-queue'); } $this->jobMetrics[$jobId] = $this->jobMetrics[$jobId] ->withFailed($errorMessage, $executionTimeMs, $memoryUsage); } public function getJobMetrics(string $jobId): ?JobMetrics { return $this->jobMetrics[$jobId] ?? null; } public function getQueueMetrics(string $queueName): array { $jobs = array_filter($this->jobMetrics, fn ($metrics) => $metrics->queueName === $queueName); if (empty($jobs)) { return [ 'queue_name' => $queueName, 'total_jobs' => 0, 'completed_jobs' => 0, 'failed_jobs' => 0, 'average_execution_time_ms' => 0.0, 'average_memory_usage_mb' => 0.0, 'success_rate' => 100.0, ]; } $totalJobs = count($jobs); $completedJobs = count(array_filter($jobs, fn ($m) => $m->isCompleted())); $failedJobs = count(array_filter($jobs, fn ($m) => $m->isFailed())); $avgExecutionTime = array_sum(array_map(fn ($m) => $m->executionTimeMs, $jobs)) / $totalJobs; $avgMemoryUsage = array_sum(array_map(fn ($m) => $m->getMemoryUsageMB(), $jobs)) / $totalJobs; $successRate = ($completedJobs / $totalJobs) * 100; return [ 'queue_name' => $queueName, 'total_jobs' => $totalJobs, 'completed_jobs' => $completedJobs, 'failed_jobs' => $failedJobs, 'average_execution_time_ms' => round($avgExecutionTime, 2), 'average_memory_usage_mb' => round($avgMemoryUsage, 2), 'success_rate' => round($successRate, 2), ]; } public function getSystemMetrics(): array { if (empty($this->jobMetrics)) { return [ 'total_jobs' => 0, 'completed_jobs' => 0, 'failed_jobs' => 0, 'running_jobs' => 0, 'overall_success_rate' => 100.0, 'average_execution_time_ms' => 0.0, 'peak_memory_usage_mb' => 0.0, ]; } $totalJobs = count($this->jobMetrics); $completedJobs = count(array_filter($this->jobMetrics, fn ($m) => $m->isCompleted())); $failedJobs = count(array_filter($this->jobMetrics, fn ($m) => $m->isFailed())); $runningJobs = count(array_filter($this->jobMetrics, fn ($m) => $m->isRunning())); $overallSuccessRate = ($completedJobs / $totalJobs) * 100; $avgExecutionTime = array_sum(array_map(fn ($m) => $m->executionTimeMs, $this->jobMetrics)) / $totalJobs; $peakMemoryUsage = max(array_map(fn ($m) => $m->getMemoryUsageMB(), $this->jobMetrics)); return [ 'total_jobs' => $totalJobs, 'completed_jobs' => $completedJobs, 'failed_jobs' => $failedJobs, 'running_jobs' => $runningJobs, 'overall_success_rate' => round($overallSuccessRate, 2), 'average_execution_time_ms' => round($avgExecutionTime, 2), 'peak_memory_usage_mb' => round($peakMemoryUsage, 2), ]; } public function getTopSlowJobs(int $limit = 10): array { $jobs = $this->jobMetrics; usort($jobs, fn ($a, $b) => $b->executionTimeMs <=> $a->executionTimeMs); return array_slice($jobs, 0, $limit); } public function getTopMemoryJobs(int $limit = 10): array { $jobs = $this->jobMetrics; usort($jobs, fn ($a, $b) => $b->memoryUsageBytes <=> $a->memoryUsageBytes); return array_slice($jobs, 0, $limit); } public function getJobsByQueue(string $queueName): array { return array_filter($this->jobMetrics, fn ($metrics) => $metrics->queueName === $queueName); } }; }); describe('Job Metrics Recording', function () { it('can record successful job execution', function () { $jobId = 'success-job-123'; $executionTime = 2500.0; // 2.5 seconds $memoryUsage = 3 * 1024 * 1024; // 3MB $this->metricsManager->recordJobExecution($jobId, $executionTime, $memoryUsage); $metrics = $this->metricsManager->getJobMetrics($jobId); expect($metrics)->not->toBeNull(); expect($metrics->isCompleted())->toBeTrue(); expect($metrics->executionTimeMs)->toBe($executionTime); expect($metrics->memoryUsageBytes)->toBe($memoryUsage); }); it('can record failed job execution', function () { $jobId = 'failed-job-456'; $errorMessage = 'Database connection timeout'; $executionTime = 1200.0; // 1.2 seconds $memoryUsage = 1.5 * 1024 * 1024; // 1.5MB $this->metricsManager->recordJobFailure($jobId, $errorMessage, $executionTime, $memoryUsage); $metrics = $this->metricsManager->getJobMetrics($jobId); expect($metrics)->not->toBeNull(); expect($metrics->isFailed())->toBeTrue(); expect($metrics->errorMessage)->toBe($errorMessage); expect($metrics->executionTimeMs)->toBe($executionTime); expect($metrics->memoryUsageBytes)->toBe($memoryUsage); }); it('handles non-existent job metrics', function () { $metrics = $this->metricsManager->getJobMetrics('non-existent-job'); expect($metrics)->toBeNull(); }); }); describe('Queue-Level Metrics', function () { beforeEach(function () { // Set up test data with different queue metrics // Email queue jobs $this->metricsManager->recordJobExecution('email-1', 1500.0, 2 * 1024 * 1024); $this->metricsManager->recordJobExecution('email-2', 2000.0, 2.5 * 1024 * 1024); $this->metricsManager->recordJobFailure('email-3', 'SMTP error', 800.0, 1 * 1024 * 1024); // Report queue jobs $this->metricsManager->recordJobExecution('report-1', 5000.0, 10 * 1024 * 1024); $this->metricsManager->recordJobExecution('report-2', 7500.0, 15 * 1024 * 1024); }); it('calculates queue metrics correctly', function () { $emailMetrics = $this->metricsManager->getQueueMetrics('email-queue'); expect($emailMetrics['queue_name'])->toBe('email-queue'); expect($emailMetrics['total_jobs'])->toBe(3); expect($emailMetrics['completed_jobs'])->toBe(2); expect($emailMetrics['failed_jobs'])->toBe(1); expect($emailMetrics['success_rate'])->toBe(66.67); // 2/3 * 100 }); it('handles empty queue metrics', function () { $emptyMetrics = $this->metricsManager->getQueueMetrics('empty-queue'); expect($emptyMetrics['total_jobs'])->toBe(0); expect($emptyMetrics['completed_jobs'])->toBe(0); expect($emptyMetrics['failed_jobs'])->toBe(0); expect($emptyMetrics['success_rate'])->toBe(100.0); expect($emptyMetrics['average_execution_time_ms'])->toBe(0.0); }); }); describe('System-Level Metrics', function () { beforeEach(function () { // Add various jobs across different queues $this->metricsManager->recordJobExecution('job-1', 1000.0, 1 * 1024 * 1024); $this->metricsManager->recordJobExecution('job-2', 2000.0, 2 * 1024 * 1024); $this->metricsManager->recordJobExecution('job-3', 3000.0, 4 * 1024 * 1024); $this->metricsManager->recordJobFailure('job-4', 'Error', 500.0, 0.5 * 1024 * 1024); $this->metricsManager->recordJobFailure('job-5', 'Error', 750.0, 1 * 1024 * 1024); }); it('calculates system-wide metrics correctly', function () { $systemMetrics = $this->metricsManager->getSystemMetrics(); expect($systemMetrics['total_jobs'])->toBe(5); expect($systemMetrics['completed_jobs'])->toBe(3); expect($systemMetrics['failed_jobs'])->toBe(2); expect($systemMetrics['overall_success_rate'])->toBe(60.0); // 3/5 * 100 expect($systemMetrics['average_execution_time_ms'])->toBe(1450.0); // (1000+2000+3000+500+750)/5 expect($systemMetrics['peak_memory_usage_mb'])->toBe(4.0); // Highest from job-3 }); it('handles empty system gracefully', function () { $emptyManager = new class () { private array $jobMetrics = []; public function getSystemMetrics(): array { return [ 'total_jobs' => 0, 'completed_jobs' => 0, 'failed_jobs' => 0, 'running_jobs' => 0, 'overall_success_rate' => 100.0, 'average_execution_time_ms' => 0.0, 'peak_memory_usage_mb' => 0.0, ]; } }; $systemMetrics = $emptyManager->getSystemMetrics(); expect($systemMetrics['total_jobs'])->toBe(0); expect($systemMetrics['overall_success_rate'])->toBe(100.0); }); }); describe('Performance Analysis', function () { beforeEach(function () { // Add jobs with varying performance characteristics $this->metricsManager->recordJobExecution('fast-job', 100.0, 0.5 * 1024 * 1024); $this->metricsManager->recordJobExecution('medium-job', 2500.0, 2 * 1024 * 1024); $this->metricsManager->recordJobExecution('slow-job', 10000.0, 1 * 1024 * 1024); $this->metricsManager->recordJobExecution('memory-heavy', 1500.0, 50 * 1024 * 1024); $this->metricsManager->recordJobExecution('balanced-job', 3000.0, 3 * 1024 * 1024); }); it('identifies slowest jobs correctly', function () { $slowJobs = $this->metricsManager->getTopSlowJobs(3); expect(count($slowJobs))->toBe(3); expect($slowJobs[0]->jobId)->toBe('slow-job'); expect($slowJobs[1]->jobId)->toBe('balanced-job'); expect($slowJobs[2]->jobId)->toBe('medium-job'); }); it('identifies memory-intensive jobs correctly', function () { $memoryJobs = $this->metricsManager->getTopMemoryJobs(3); expect(count($memoryJobs))->toBe(3); expect($memoryJobs[0]->jobId)->toBe('memory-heavy'); expect($memoryJobs[1]->jobId)->toBe('balanced-job'); expect($memoryJobs[2]->jobId)->toBe('medium-job'); }); it('respects limit parameter for top jobs', function () { $limitedSlowJobs = $this->metricsManager->getTopSlowJobs(2); expect(count($limitedSlowJobs))->toBe(2); $limitedMemoryJobs = $this->metricsManager->getTopMemoryJobs(1); expect(count($limitedMemoryJobs))->toBe(1); }); }); describe('Queue Filtering and Analysis', function () { beforeEach(function () { // This would require modifying the mock to support different queues // For now, we'll test the interface }); it('can retrieve jobs by queue', function () { $this->metricsManager->recordJobExecution('email-1', 1000.0, 1024 * 1024); $this->metricsManager->recordJobExecution('email-2', 2000.0, 2048 * 1024); $queueJobs = $this->metricsManager->getJobsByQueue('default-queue'); expect(count($queueJobs))->toBe(2); }); it('handles non-existent queue filtering', function () { $emptyQueue = $this->metricsManager->getJobsByQueue('non-existent-queue'); expect($emptyQueue)->toBe([]); }); }); });