LruMemoryCacheTest.php
Namespace
Drupal\Tests\Core\CacheFile
-
core/
tests/ Drupal/ Tests/ Core/ Cache/ LruMemoryCacheTest.php
View source
<?php
declare (strict_types=1);
namespace Drupal\Tests\Core\Cache;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Cache\MemoryCache\LruMemoryCache;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Core\Cache\MemoryCache\LruMemoryCache
* @group Cache
*/
class LruMemoryCacheTest extends UnitTestCase {
/**
* Tests getting, setting and deleting items from the LRU memory cache.
*
* @covers ::get
* @covers ::set
* @covers ::delete
* @covers ::getMultiple
*/
public function testGetSetDelete() : void {
$lru_cache = $this->getLruMemoryCache(3);
$cache_data = [
[
'sparrow',
'sparrow',
],
[
'pigeon',
'pigeon',
],
[
'crow',
'crow',
],
];
foreach ($cache_data as $items) {
$lru_cache->set($items[0], $items[1]);
}
$this->assertCacheData($lru_cache, [
[
'sparrow',
'sparrow',
],
[
'pigeon',
'pigeon',
],
[
'crow',
'crow',
],
]);
$lru_cache->set('cuckoo', 'cuckoo');
$this->assertCacheData($lru_cache, [
[
'pigeon',
'pigeon',
],
[
'crow',
'crow',
],
[
'cuckoo',
'cuckoo',
],
]);
// Now bring pigeon to the most recently used spot.
$lru_cache->get('pigeon');
$this->assertCacheData($lru_cache, [
[
'crow',
'crow',
],
[
'cuckoo',
'cuckoo',
],
[
'pigeon',
'pigeon',
],
]);
// Confirm that setting the same item multiple times only uses one slot.
$lru_cache->set('bigger_cuckoo', 'bigger_cuckoo');
$lru_cache->set('bigger_cuckoo', 'bigger_cuckoo');
$lru_cache->set('bigger_cuckoo', 'bigger_cuckoo');
$lru_cache->set('bigger_cuckoo', 'bigger_cuckoo');
$lru_cache->set('bigger_cuckoo', 'bigger_cuckoo');
$this->assertCacheData($lru_cache, [
[
'cuckoo',
'cuckoo',
],
[
'pigeon',
'pigeon',
],
[
'bigger_cuckoo',
'bigger_cuckoo',
],
]);
// Confirm that deleting the same item multiple times only frees up one
// slot.
$lru_cache->delete('bigger_cuckoo');
$lru_cache->delete('bigger_cuckoo');
$lru_cache->delete('bigger_cuckoo');
$lru_cache->delete('bigger_cuckoo');
$lru_cache->delete('bigger_cuckoo');
$lru_cache->delete('bigger_cuckoo');
$this->assertCacheData($lru_cache, [
[
'cuckoo',
'cuckoo',
],
[
'pigeon',
'pigeon',
],
]);
$lru_cache->set('crow', 'crow');
$this->assertCacheData($lru_cache, [
[
'cuckoo',
'cuckoo',
],
[
'pigeon',
'pigeon',
],
[
'crow',
'crow',
],
]);
// Ensure nothing changes on cache miss for ::get().
$this->assertFalse($lru_cache->get('dodo'));
$this->assertCacheData($lru_cache, [
[
'cuckoo',
'cuckoo',
],
[
'pigeon',
'pigeon',
],
[
'crow',
'crow',
],
]);
// Ensure nothing changes on cache miss for ::getMultiple().
$cids = [
'dodo',
'great_auk',
];
$this->assertEmpty($lru_cache->getMultiple($cids));
$this->assertCacheData($lru_cache, [
[
'cuckoo',
'cuckoo',
],
[
'pigeon',
'pigeon',
],
[
'crow',
'crow',
],
]);
$this->assertSame([
'dodo',
'great_auk',
], $cids);
$cids = [
'pigeon',
'cuckoo',
];
$lru_cache->getMultiple($cids);
// @todo This result suggests the order of the arguments in the
// \Drupal\Core\Cache\MemoryBackend::getMultiple() array_intersect_key()
// should be swapped as this order of the cache items returned should
// probably be in the same order as the passed in $cache_data. I.e. cuckoo
// should be at the ends of the array and not crow.
$this->assertCacheData($lru_cache, [
[
'crow',
'crow',
],
[
'cuckoo',
'cuckoo',
],
[
'pigeon',
'pigeon',
],
]);
$this->assertEmpty($cids);
}
/**
* Tests setting items with numeric keys in the LRU memory cache.
*
* @covers ::set
*/
public function testSetNumericKeys() : void {
$lru_cache = $this->getLruMemoryCache(3);
$cache_data = [
[
4,
'sparrow',
],
[
10,
'pigeon',
],
[
7,
'crow',
],
];
foreach ($cache_data as $item) {
$lru_cache->set($item[0], $item[1]);
}
$this->assertCacheData($lru_cache, $cache_data);
$lru_cache->set(1, 'cuckoo');
$this->assertCacheData($lru_cache, [
[
10,
'pigeon',
],
[
7,
'crow',
],
[
1,
'cuckoo',
],
]);
$lru_cache->set(7, 'crow');
$this->assertCacheData($lru_cache, [
[
10,
'pigeon',
],
[
1,
'cuckoo',
],
[
7,
'crow',
],
]);
}
/**
* Tests setting multiple items in the LRU memory cache.
*
* @covers ::setMultiple
*/
public function testSetMultiple() : void {
$lru_cache = $this->getLruMemoryCache(3);
$lru_cache->setMultiple([
'sparrow' => [
'data' => 'sparrow',
],
'pigeon' => [
'data' => 'pigeon',
],
'crow' => [
'data' => 'crow',
],
]);
$this->assertCacheData($lru_cache, [
[
'sparrow',
'sparrow',
],
[
'pigeon',
'pigeon',
],
[
'crow',
'crow',
],
]);
$lru_cache->setMultiple([
'sparrow' => [
'data' => 'sparrow2',
],
'bluejay' => [
'data' => 'bluejay',
],
]);
$this->assertCacheData($lru_cache, [
[
'crow',
'crow',
],
[
'sparrow',
'sparrow2',
],
[
'bluejay',
'bluejay',
],
]);
$lru_cache->setMultiple([
3 => [
'data' => 'pigeon',
],
2 => [
'data' => 'eagle',
],
1 => [
'data' => 'wren',
],
]);
$this->assertCacheData($lru_cache, [
[
3,
'pigeon',
],
[
2,
'eagle',
],
[
1,
'wren',
],
]);
$lru_cache->setMultiple([
2 => [
'data' => 'eagle2',
],
4 => [
'data' => 'cuckoo',
],
]);
$this->assertCacheData($lru_cache, [
[
1,
'wren',
],
[
2,
'eagle2',
],
[
4,
'cuckoo',
],
]);
}
/**
* Tests invalidation from the LRU memory cache.
*
* @covers ::invalidate
* @covers ::invalidateMultiple
* @covers ::invalidateTags
*/
public function testInvalidate() : void {
$lru_cache = $this->getLruMemoryCache(3);
$cache_data = [
[
'sparrow',
'sparrow',
],
[
'pigeon',
'pigeon',
],
[
'crow',
'crow',
],
];
foreach ($cache_data as $items) {
$lru_cache->set($items[0], $items[1]);
}
$this->assertCacheData($lru_cache, [
[
'sparrow',
'sparrow',
],
[
'pigeon',
'pigeon',
],
[
'crow',
'crow',
],
]);
$lru_cache->invalidate('crow');
$this->assertCacheData($lru_cache, [
[
'crow',
'crow',
],
[
'sparrow',
'sparrow',
],
[
'pigeon',
'pigeon',
],
]);
$this->assertFalse($lru_cache->get('crow'));
// Ensure that getting an invalid cache does not move it to the end of the
// array.
$this->assertSame('crow', $lru_cache->get('crow', TRUE)->data);
$this->assertCacheData($lru_cache, [
[
'crow',
'crow',
],
[
'sparrow',
'sparrow',
],
[
'pigeon',
'pigeon',
],
]);
$lru_cache->set('cuckoo', 'cuckoo', LruMemoryCache::CACHE_PERMANENT, [
'cuckoo',
]);
$this->assertCacheData($lru_cache, [
[
'sparrow',
'sparrow',
],
[
'pigeon',
'pigeon',
],
[
'cuckoo',
'cuckoo',
],
]);
$lru_cache->invalidateTags([
'cuckoo',
]);
$this->assertFalse($lru_cache->get('cuckoo'));
$this->assertSame('cuckoo', $lru_cache->get('cuckoo', TRUE)->data);
$lru_cache->set('crow', 'crow');
$this->assertCacheData($lru_cache, [
[
'sparrow',
'sparrow',
],
[
'pigeon',
'pigeon',
],
[
'crow',
'crow',
],
]);
$lru_cache->invalidateMultiple([
'pigeon',
'crow',
]);
$cids = [
'pigeon',
'crow',
];
$this->assertEmpty($lru_cache->getMultiple($cids));
$this->assertSame([
'pigeon',
'crow',
], $cids);
$this->assertCount(2, $lru_cache->getMultiple($cids, TRUE));
$this->assertSame([], $cids);
$this->assertCacheData($lru_cache, [
[
'pigeon',
'pigeon',
],
[
'crow',
'crow',
],
[
'sparrow',
'sparrow',
],
]);
$lru_cache->set('duck', 'duck');
$lru_cache->set('chicken', 'chicken');
$this->assertCacheData($lru_cache, [
[
'sparrow',
'sparrow',
],
[
'duck',
'duck',
],
[
'chicken',
'chicken',
],
]);
}
/**
* Tests invalidation with numeric keys from the LRU memory cache.
*
* @covers ::invalidate
* @covers ::invalidateMultiple
* @covers ::invalidateTags
*/
public function testInvalidateNumeric() : void {
$lru_cache = $this->getLruMemoryCache(3);
$cache_data = [
[
3,
'sparrow',
],
[
10,
'pigeon',
],
[
5,
'crow',
],
];
foreach ($cache_data as $items) {
$lru_cache->set($items[0], $items[1], tags: [
'bird',
]);
}
$this->assertCacheData($lru_cache, [
[
3,
'sparrow',
],
[
10,
'pigeon',
],
[
5,
'crow',
],
]);
// Invalidate something not in the cache and ensure nothing changes.
$lru_cache->invalidate(0);
$this->assertCacheData($lru_cache, [
[
3,
'sparrow',
],
[
10,
'pigeon',
],
[
5,
'crow',
],
]);
$lru_cache->invalidate(10);
$this->assertCacheData($lru_cache, [
[
10,
'pigeon',
],
[
3,
'sparrow',
],
[
5,
'crow',
],
]);
$this->assertFalse($lru_cache->get(10));
$this->assertSame('pigeon', $lru_cache->get(10, TRUE)->data);
$lru_cache->invalidateTags([
'mammal',
]);
$this->assertCacheData($lru_cache, [
[
10,
'pigeon',
],
[
3,
'sparrow',
],
[
5,
'crow',
],
]);
$this->assertSame('sparrow', $lru_cache->get(3)->data);
$this->assertCacheData($lru_cache, [
[
10,
'pigeon',
],
[
5,
'crow',
],
[
3,
'sparrow',
],
]);
$lru_cache->invalidateTags([
'mammal',
'bird',
]);
$this->assertFalse($lru_cache->get(3));
$this->assertFalse($lru_cache->get(10));
$this->assertFalse($lru_cache->get(5));
$this->assertCacheData($lru_cache, [
[
10,
'pigeon',
],
[
5,
'crow',
],
[
3,
'sparrow',
],
]);
}
/**
* Asserts that the given cache data matches the data in the memory cache.
*
* @param \Drupal\Core\Cache\MemoryCache\LruMemoryCache $lru_cache
* The LRU cache under test.
* @param array $cache_data
* Array whose first element is the cache ID and whose second element is
* the value to check. This should contain all the keys in the cache and in
* the expected order.
*/
protected function assertCacheData(LruMemoryCache $lru_cache, array $cache_data) : void {
// Use reflection to access data because using ::get() affects the LRU
// cache.
$reflectedClass = new \ReflectionClass($lru_cache);
$reflection = $reflectedClass->getProperty('cache');
$cache = $reflection->getValue($lru_cache);
$keys = [];
foreach ($cache_data as $item) {
$keys[] = $item[0];
$this->assertSame($item[1], $cache[$item[0]]->data, "{$item[0]} found in cache.");
}
// Ensure the cache only contains the supply keys and the order is as
// expected.
$this->assertSame($keys, array_keys($cache));
}
/**
* Creates a LRU cache for testing.
*
* @param int $slots
* The number of slots in the LRU cache.
*
* @return \Drupal\Core\Cache\MemoryCache\LruMemoryCache
* The LRU cache.
*/
private function getLruMemoryCache(int $slots) : LruMemoryCache {
$time_mock = $this->createMock(TimeInterface::class);
$time_mock->expects($this->any())
->method('getRequestTime')
->willReturnCallback('time');
return new LruMemoryCache($time_mock, $slots);
}
}
Classes
Title | Deprecated | Summary |
---|---|---|
LruMemoryCacheTest | @coversDefaultClass \Drupal\Core\Cache\MemoryCache\LruMemoryCache @group Cache |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.