logger = Mockery::mock(Logger::class); $this->logger->shouldReceive('info')->andReturnNull(); $this->logger->shouldReceive('debug')->andReturnNull(); $this->logger->shouldReceive('error')->andReturnNull(); }); afterEach(function () { Mockery::close(); }); it('warms all strategies', function () { $strategy1 = Mockery::mock(WarmupStrategy::class); $strategy1->shouldReceive('getName')->andReturn('strategy1'); $strategy1->shouldReceive('getPriority')->andReturn(WarmupPriority::HIGH->value); $strategy1->shouldReceive('shouldRun')->andReturn(true); $strategy1->shouldReceive('getEstimatedDuration')->andReturn(1); $strategy1->shouldReceive('warmup')->andReturn(new WarmupResult( strategyName: 'strategy1', itemsWarmed: 10, itemsFailed: 0, durationSeconds: 1.0, memoryUsedBytes: 1024 )); $strategy2 = Mockery::mock(WarmupStrategy::class); $strategy2->shouldReceive('getName')->andReturn('strategy2'); $strategy2->shouldReceive('getPriority')->andReturn(WarmupPriority::MEDIUM->value); $strategy2->shouldReceive('shouldRun')->andReturn(true); $strategy2->shouldReceive('getEstimatedDuration')->andReturn(2); $strategy2->shouldReceive('warmup')->andReturn(new WarmupResult( strategyName: 'strategy2', itemsWarmed: 20, itemsFailed: 0, durationSeconds: 2.0, memoryUsedBytes: 2048 )); $service = new CacheWarmingService( strategies: [$strategy1, $strategy2], logger: $this->logger ); $metrics = $service->warmAll(); expect($metrics->totalStrategiesExecuted)->toBe(2); expect($metrics->totalItemsWarmed)->toBe(30); }); it('skips strategies when shouldRun returns false', function () { $strategy1 = Mockery::mock(WarmupStrategy::class); $strategy1->shouldReceive('getName')->andReturn('strategy1'); $strategy1->shouldReceive('getPriority')->andReturn(WarmupPriority::HIGH->value); $strategy1->shouldReceive('shouldRun')->andReturn(false); $strategy1->shouldNotReceive('warmup'); $service = new CacheWarmingService( strategies: [$strategy1], logger: $this->logger ); $metrics = $service->warmAll(force: false); expect($metrics->totalStrategiesExecuted)->toBe(0); }); it('forces execution when force is true', function () { $strategy1 = Mockery::mock(WarmupStrategy::class); $strategy1->shouldReceive('getName')->andReturn('strategy1'); $strategy1->shouldReceive('getPriority')->andReturn(WarmupPriority::HIGH->value); $strategy1->shouldReceive('shouldRun')->andReturn(false); $strategy1->shouldReceive('getEstimatedDuration')->andReturn(1); $strategy1->shouldReceive('warmup')->andReturn(new WarmupResult( strategyName: 'strategy1', itemsWarmed: 10, itemsFailed: 0, durationSeconds: 1.0, memoryUsedBytes: 1024 )); $service = new CacheWarmingService( strategies: [$strategy1], logger: $this->logger ); $metrics = $service->warmAll(force: true); expect($metrics->totalStrategiesExecuted)->toBe(1); expect($metrics->totalItemsWarmed)->toBe(10); }); it('sorts strategies by priority', function () { $lowPriority = Mockery::mock(WarmupStrategy::class); $lowPriority->shouldReceive('getName')->andReturn('low'); $lowPriority->shouldReceive('getPriority')->andReturn(WarmupPriority::LOW->value); $lowPriority->shouldReceive('shouldRun')->andReturn(true); $lowPriority->shouldReceive('getEstimatedDuration')->andReturn(1); $lowPriority->shouldReceive('warmup')->andReturn(new WarmupResult( strategyName: 'low', itemsWarmed: 5, itemsFailed: 0, durationSeconds: 1.0, memoryUsedBytes: 512 )); $highPriority = Mockery::mock(WarmupStrategy::class); $highPriority->shouldReceive('getName')->andReturn('high'); $highPriority->shouldReceive('getPriority')->andReturn(WarmupPriority::HIGH->value); $highPriority->shouldReceive('shouldRun')->andReturn(true); $highPriority->shouldReceive('getEstimatedDuration')->andReturn(1); $highPriority->shouldReceive('warmup')->andReturn(new WarmupResult( strategyName: 'high', itemsWarmed: 10, itemsFailed: 0, durationSeconds: 1.0, memoryUsedBytes: 1024 )); // Pass in wrong order - service should sort by priority $service = new CacheWarmingService( strategies: [$lowPriority, $highPriority], logger: $this->logger ); $strategies = $service->getStrategies(); expect($strategies[0]->getName())->toBe('high'); expect($strategies[1]->getName())->toBe('low'); }); it('warms specific strategy by name', function () { $strategy1 = Mockery::mock(WarmupStrategy::class); $strategy1->shouldReceive('getName')->andReturn('strategy1'); $strategy1->shouldReceive('getPriority')->andReturn(WarmupPriority::HIGH->value); $strategy1->shouldReceive('getEstimatedDuration')->andReturn(1); $strategy1->shouldReceive('warmup')->andReturn(new WarmupResult( strategyName: 'strategy1', itemsWarmed: 10, itemsFailed: 0, durationSeconds: 1.0, memoryUsedBytes: 1024 )); $service = new CacheWarmingService( strategies: [$strategy1], logger: $this->logger ); $result = $service->warmStrategy('strategy1'); expect($result->strategyName)->toBe('strategy1'); expect($result->itemsWarmed)->toBe(10); }); it('throws when strategy not found', function () { $service = new CacheWarmingService( strategies: [], logger: $this->logger ); $service->warmStrategy('nonexistent'); })->throws(InvalidArgumentException::class, 'Strategy not found: nonexistent'); it('warms by priority threshold', function () { $critical = Mockery::mock(WarmupStrategy::class); $critical->shouldReceive('getName')->andReturn('critical'); $critical->shouldReceive('getPriority')->andReturn(WarmupPriority::CRITICAL->value); $critical->shouldReceive('shouldRun')->andReturn(true); $critical->shouldReceive('getEstimatedDuration')->andReturn(1); $critical->shouldReceive('warmup')->andReturn(new WarmupResult( strategyName: 'critical', itemsWarmed: 10, itemsFailed: 0, durationSeconds: 1.0, memoryUsedBytes: 1024 )); $low = Mockery::mock(WarmupStrategy::class); $low->shouldReceive('getName')->andReturn('low'); $low->shouldReceive('getPriority')->andReturn(WarmupPriority::LOW->value); $low->shouldNotReceive('warmup'); $service = new CacheWarmingService( strategies: [$critical, $low], logger: $this->logger ); $metrics = $service->warmByPriority(WarmupPriority::HIGH->value); // Should only warm critical (priority 1000 >= 500) expect($metrics->totalStrategiesExecuted)->toBe(1); }); it('calculates estimated total duration', function () { $strategy1 = Mockery::mock(WarmupStrategy::class); $strategy1->shouldReceive('getName')->andReturn('strategy1'); $strategy1->shouldReceive('getPriority')->andReturn(WarmupPriority::HIGH->value); $strategy1->shouldReceive('getEstimatedDuration')->andReturn(5); $strategy1->shouldReceive('shouldRun')->andReturn(true); $strategy2 = Mockery::mock(WarmupStrategy::class); $strategy2->shouldReceive('getName')->andReturn('strategy2'); $strategy2->shouldReceive('getPriority')->andReturn(WarmupPriority::MEDIUM->value); $strategy2->shouldReceive('getEstimatedDuration')->andReturn(3); $strategy2->shouldReceive('shouldRun')->andReturn(true); $service = new CacheWarmingService( strategies: [$strategy1, $strategy2], logger: $this->logger ); $duration = $service->getEstimatedTotalDuration(); expect($duration)->toBe(8); }); it('handles strategy exceptions gracefully', function () { $failingStrategy = Mockery::mock(WarmupStrategy::class); $failingStrategy->shouldReceive('getName')->andReturn('failing'); $failingStrategy->shouldReceive('getPriority')->andReturn(WarmupPriority::HIGH->value); $failingStrategy->shouldReceive('shouldRun')->andReturn(true); $failingStrategy->shouldReceive('getEstimatedDuration')->andReturn(1); $failingStrategy->shouldReceive('warmup')->andThrow(new RuntimeException('Test error')); $service = new CacheWarmingService( strategies: [$failingStrategy], logger: $this->logger ); $metrics = $service->warmAll(); // Should handle error and return failed result expect($metrics->totalStrategiesExecuted)->toBe(1); expect($metrics->totalItemsFailed)->toBeGreaterThan(0); }); });