cache = Mockery::mock(Cache::class); }); afterEach(function () { Mockery::close(); }); it('has correct name', function () { $strategy = new PredictiveWarmingStrategy($this->cache); expect($strategy->getName())->toBe('predictive'); }); it('has background priority', function () { $strategy = new PredictiveWarmingStrategy($this->cache); expect($strategy->getPriority())->toBe(WarmupPriority::BACKGROUND->value); }); it('should not run without sufficient access patterns', function () { $this->cache->shouldReceive('get') ->andReturn(null); // No access patterns available $strategy = new PredictiveWarmingStrategy($this->cache); expect($strategy->shouldRun())->toBeFalse(); }); it('should run with sufficient access patterns', function () { // Mock access patterns (10+ patterns) $accessPatterns = []; for ($i = 0; $i < 15; $i++) { $accessPatterns["pattern_{$i}"] = [ 'access_count' => 10 + $i, 'hourly_distribution' => array_fill(0, 24, 0.04), 'daily_distribution' => array_fill(0, 7, 0.14), ]; } $this->cache->shouldReceive('get') ->andReturn($accessPatterns); $strategy = new PredictiveWarmingStrategy($this->cache); expect($strategy->shouldRun())->toBeTrue(); }); it('estimates reasonable duration', function () { $strategy = new PredictiveWarmingStrategy($this->cache); $duration = $strategy->getEstimatedDuration(); expect($duration)->toBeGreaterThan(0); expect($duration)->toBeLessThan(300); // Should be < 5 minutes }); it('warms predicted cache keys', function () { // Mock access patterns with high probability $currentHour = (int) date('G'); $currentDay = (int) date('N') - 1; $accessPatterns = [ 'key1' => [ 'access_count' => 50, 'hourly_distribution' => array_fill(0, 24, 0.04), 'daily_distribution' => array_fill(0, 7, 0.14), ], 'key2' => [ 'access_count' => 30, 'hourly_distribution' => array_fill(0, 24, 0.04), 'daily_distribution' => array_fill(0, 7, 0.14), ], ]; // Boost current hour/day to ensure high probability $accessPatterns['key1']['hourly_distribution'][$currentHour] = 0.5; $accessPatterns['key1']['daily_distribution'][$currentDay] = 0.5; $this->cache->shouldReceive('get') ->with(Mockery::pattern('/access_patterns/')) ->andReturn($accessPatterns); $this->cache->shouldReceive('get') ->with(Mockery::pattern('/^key[12]$/')) ->andReturn(null); // Cache miss $this->cache->shouldReceive('set') ->atLeast(1) ->andReturn(true); $strategy = new PredictiveWarmingStrategy($this->cache); $result = $strategy->warmup(); expect($result->isSuccess())->toBeTrue(); }); it('skips low probability keys', function () { $accessPatterns = [ 'low_prob_key' => [ 'access_count' => 2, // Below MIN_ACCESS_COUNT 'hourly_distribution' => array_fill(0, 24, 0.01), 'daily_distribution' => array_fill(0, 7, 0.01), ], ]; $this->cache->shouldReceive('get') ->with(Mockery::pattern('/access_patterns/')) ->andReturn($accessPatterns); $this->cache->shouldNotReceive('set'); // Should not warm low probability $strategy = new PredictiveWarmingStrategy($this->cache); $result = $strategy->warmup(); // No items warmed due to low probability expect($result->itemsWarmed)->toBe(0); }); });