diff --git a/core/lib/Drupal/Component/Cache/ApcuFileCacheBackend.php b/core/lib/Drupal/Component/Cache/ApcuFileCacheBackend.php index 0e14d6b..3d4c6cb 100644 --- a/core/lib/Drupal/Component/Cache/ApcuFileCacheBackend.php +++ b/core/lib/Drupal/Component/Cache/ApcuFileCacheBackend.php @@ -9,6 +9,8 @@ /** * Allows to cache data based on file modification dates in APCu. + * + * @codeCoverageIgnore */ class ApcuFileCacheBackend implements FileCacheBackendInterface { diff --git a/core/lib/Drupal/Component/Cache/ChainedFileCacheBackend.php b/core/lib/Drupal/Component/Cache/ChainedFileCacheBackend.php index e893602..a4a9f35 100644 --- a/core/lib/Drupal/Component/Cache/ChainedFileCacheBackend.php +++ b/core/lib/Drupal/Component/Cache/ChainedFileCacheBackend.php @@ -13,6 +13,13 @@ */ class ChainedFileCacheBackend implements FileCacheBackendInterface { + /** + * The backends to use. + * + * @var \Drupal\Component\Cache\FileCacheBackendInterface[] + */ + protected $cacheBackends; + /** * Constructs a ChainedFileCacheBackend object. * diff --git a/core/lib/Drupal/Component/Cache/FileCache.php b/core/lib/Drupal/Component/Cache/FileCache.php index e8d43e3..5af4574 100644 --- a/core/lib/Drupal/Component/Cache/FileCache.php +++ b/core/lib/Drupal/Component/Cache/FileCache.php @@ -110,7 +110,7 @@ public function getMultiple(array $filepaths) { // If the file exists but realpath returns nothing, it is using a stream // wrapper, those are not supported. if (empty($realpath)) { - continue; + continue; // @codeCoverageIgnore } $cid = static::CACHE_PREFIX . ':' . $this->identifier . ':' . $realpath; diff --git a/core/lib/Drupal/Component/Cache/FileCacheFactory.php b/core/lib/Drupal/Component/Cache/FileCacheFactory.php index 75461bd..c075c24 100644 --- a/core/lib/Drupal/Component/Cache/FileCacheFactory.php +++ b/core/lib/Drupal/Component/Cache/FileCacheFactory.php @@ -36,14 +36,14 @@ public static function get($identifier, $default_configuration = []) { 'class' => '\Drupal\Component\Cache\FileCache', 'identifier' => $identifier, 'cache_backend_class' => NULL, - ]; + ]; // @codeCoverageIgnore $configuration = []; if (isset(static::$configuration[$identifier])) { $configuration = static::$configuration[$identifier]; } - elseif (isset(static::$configuration['default'])) { - $configuration = static::$configuration['default']; + elseif (isset(static::$configuration['default'])) { // @codeCoverageIgnore + $configuration = static::$configuration['default']; // @codeCoverageIgnore } // Add defaults to the configuration. @@ -59,7 +59,7 @@ public static function get($identifier, $default_configuration = []) { * @return array * The configuration that is used. */ - public static function getConfiguration($configuration) { + public static function getConfiguration() { return static::$configuration; } diff --git a/core/lib/Drupal/Core/Cache/PhpStorageFileCacheBackend.php b/core/lib/Drupal/Core/Cache/PhpStorageFileCacheBackend.php index 817f7c0..f937f4a 100644 --- a/core/lib/Drupal/Core/Cache/PhpStorageFileCacheBackend.php +++ b/core/lib/Drupal/Core/Cache/PhpStorageFileCacheBackend.php @@ -27,6 +27,8 @@ class PhpStorageFileCacheBackend implements FileCacheBackendInterface { * * @param array $configuration * (optional) Configuration used to configure this object. + * + * @codeCoverageIgnore */ public function __construct($configuration) { $name = isset($configuration['name']) ? $configuration['name'] : 'file_cache'; diff --git a/core/phpunit.xml.dist b/core/phpunit.xml.dist index bd0edc9..f5cf4ff 100644 --- a/core/phpunit.xml.dist +++ b/core/phpunit.xml.dist @@ -28,11 +28,8 @@ - ./includes - ./lib - ./modules - ../modules - ../sites + ./lib/Drupal/Component/Cache + ./lib/Drupal/Core/Cache/PhpStorageFileCacheBackend.php diff --git a/core/tests/Drupal/Tests/Component/Cache/ChainedFileCacheBackendTest.php b/core/tests/Drupal/Tests/Component/Cache/ChainedFileCacheBackendTest.php new file mode 100644 index 0000000..cc116b1 --- /dev/null +++ b/core/tests/Drupal/Tests/Component/Cache/ChainedFileCacheBackendTest.php @@ -0,0 +1,162 @@ + [ + 'bin' => 'preseeded_cache', + ], + ]; + + $this->cache = new ChainedFileCacheBackend($configuration); + } + + /** + * @covers ::__construct + * @covers ::fetch + */ + public function testFetch() { + $backend_outer = $this->getMockBuilder('\Drupal\Component\Cache\CacheBackendInterface') + ->setMethods(['fetch', 'store']) + ->getMock(); + $backend_outer->expects($this->once()) + ->method('store') + ->with($this->equalTo('foo'), $this->equalTo(42)); + + $backend_outer->expects($this->once()) + ->method('fetch') + ->with($this->equalTo(['foo', 'bar', 'not_found'])) + ->willReturn(['bar' => 23]); + + $backend_inner = $this->getMockBuilder('\Drupal\Component\Cache\CacheBackendInterface') + ->setMethods(['fetch']) + ->getMock(); + $backend_inner->expects($this->once()) + ->method('fetch') + ->with($this->equalTo(['foo', 'not_found'])) + ->willReturn(['foo' => 42]); + + $backend_third = $this->getMockBuilder('\Drupal\Component\Cache\CacheBackendInterface') + ->setMethods(['fetch']) + ->getMock(); + $backend_third->expects($this->once()) + ->method('fetch') + ->with($this->equalTo(['not_found'])) + ->willReturn([]); + + $this->setCacheBackends([$backend_outer, $backend_inner, $backend_third]); + + $result = $this->cache->fetch(['foo', 'bar', 'not_found']); + $this->assertEquals(['foo' => 42, 'bar' => 23], $result); + } + + /** + * @covers ::fetch + */ + public function testFetchEmpty() { + $backend_outer = $this->getMockBuilder('\Drupal\Component\Cache\CacheBackendInterface') + ->setMethods(['fetch', 'store']) + ->getMock(); + + $backend_outer->expects($this->once()) + ->method('fetch') + ->with($this->equalTo(['foo'])) + ->willReturn(['foo' => 42]); + + $backend_inner = $this->getMockBuilder('\Drupal\Component\Cache\CacheBackendInterface') + ->setMethods(['fetch']) + ->getMock(); + $backend_inner->expects($this->never()) + ->method('fetch'); + + $this->setCacheBackends([$backend_outer, $backend_inner]); + + $result = $this->cache->fetch(['foo']); + $this->assertEquals(['foo' => 42], $result); + } + + /** + * @covers ::store + */ + public function testStore() { + $backend_outer = $this->getMockBuilder('\Drupal\Component\Cache\CacheBackendInterface') + ->setMethods(['store']) + ->getMock(); + $backend_outer->expects($this->once()) + ->method('store') + ->with($this->equalTo('foo'), $this->equalTo(42)); + + $backend_inner = $this->getMockBuilder('\Drupal\Component\Cache\CacheBackendInterface') + ->setMethods(['store']) + ->getMock(); + $backend_inner->expects($this->once()) + ->method('store') + ->with($this->equalTo('foo'), $this->equalTo(42)); + + $this->setCacheBackends([$backend_outer, $backend_inner]); + $this->cache->store('foo', 42); + } + + /** + * @covers ::delete + */ + public function testDelete() { + $backend_outer = $this->getMockBuilder('\Drupal\Component\Cache\CacheBackendInterface') + ->setMethods(['delete']) + ->getMock(); + $backend_outer->expects($this->once()) + ->method('delete') + ->with($this->equalTo('foo')); + + $backend_inner = $this->getMockBuilder('\Drupal\Component\Cache\CacheBackendInterface') + ->setMethods(['delete']) + ->getMock(); + $backend_inner->expects($this->once()) + ->method('delete') + ->with($this->equalTo('foo')); + + $this->setCacheBackends([$backend_outer, $backend_inner]); + $this->cache->delete('foo'); + } + + /** + * Sets the protected cacheBackends value of the chained cache backend. + * + * @param \Drupal\Component\Cache\FileCacheBackendInterface[] $backends + * The backends to set on the class. + */ + protected function setCacheBackends($backends) { + $reflection = new \ReflectionClass($this->cache); + $reflection_property = $reflection->getProperty('cacheBackends'); + $reflection_property->setAccessible(TRUE); + $reflection_property->setValue($this->cache, $backends); + } +} diff --git a/core/tests/Drupal/Tests/Component/Cache/FileCacheFactoryTest.php b/core/tests/Drupal/Tests/Component/Cache/FileCacheFactoryTest.php new file mode 100644 index 0000000..ab69c94 --- /dev/null +++ b/core/tests/Drupal/Tests/Component/Cache/FileCacheFactoryTest.php @@ -0,0 +1,80 @@ + 'test-23', + 'cache_backend_class' => [ + '\Drupal\Tests\Component\Cache\StaticFileCacheBackend' => [ + 'bin' => 'dog', + ], + ], + ]; + $configuration = FileCacheFactory::getConfiguration(); + if (!$configuration) { + $configuration = []; + } + $configuration += [ 'test_foo_settings' => $settings ]; + FileCacheFactory::setConfiguration($configuration); + } + + /** + * @covers ::get + */ + public function testGet() { + $file_cache = FileCacheFactory::get('test_foo_settings', []); + + // Ensure the right backend and configuration is used. + $filename = __DIR__ . '/Fixtures/llama-23.txt'; + $realpath = realpath($filename); + $cid = 'drupal_file_cache:test-23:' . $realpath; + + $file_cache->set($filename, 23); + + $static_cache = new StaticFileCacheBackend(['bin' => 'dog']); + $result = $static_cache->fetch([$cid]); + $this->assertNotEmpty($result); + + // Cleanup static caches. + $file_cache->delete($filename); + } + + /** + * @covers ::setConfiguration + */ + public function testSetConfiguration() { + $configuration = FileCacheFactory::getConfiguration(); + $configuration['test_foo_bar'] = ['bar' => 'llama']; + FileCacheFactory::setConfiguration($configuration); + } + + /** + * @covers ::getConfiguration + * + * @depends testSetConfiguration + */ + public function testGetConfiguration() { + $configuration = FileCacheFactory::getConfiguration(); + $this->assertEquals(['bar' => 'llama'], $configuration['test_foo_bar']); + } +} diff --git a/core/tests/Drupal/Tests/Component/Cache/FileCacheTest.php b/core/tests/Drupal/Tests/Component/Cache/FileCacheTest.php new file mode 100644 index 0000000..f2db88e --- /dev/null +++ b/core/tests/Drupal/Tests/Component/Cache/FileCacheTest.php @@ -0,0 +1,152 @@ + [ + 'bin' => 'llama', + ], + ]; + $this->fileCache = new FileCache('test', $settings); + $this->staticFileCache = new StaticFileCacheBackend(['bin' => 'llama']); + } + + /** + * @covers ::get + * @covers ::__construct + */ + public function testGet() { + // Test a cache miss. + $result = $this->fileCache->get(__DIR__ . '/Fixtures/no-llama-42.yml'); + $this->assertNull($result); + + // Test a cache hit. + $filename = __DIR__ . '/Fixtures/llama-42.txt'; + $realpath = realpath($filename); + $cid = 'drupal_file_cache:test:' . $realpath; + $data = [ + 'mtime' => filemtime($realpath), + 'filepath' => $realpath, + 'data' => 42, + ]; + + $this->staticFileCache->store($cid, $data); + + $result = $this->fileCache->get($filename); + $this->assertEquals(42, $result); + + // Cleanup static caches. + $this->fileCache->delete($filename); + } + + /** + * @covers ::getMultiple + */ + public function testGetMultiple() { + // Test a cache miss. + $result = $this->fileCache->getMultiple([__DIR__ . '/Fixtures/no-llama-42.yml']); + $this->assertEmpty($result); + + // Test a cache hit. + $filename = __DIR__ . '/Fixtures/llama-42.txt'; + $realpath = realpath($filename); + $cid = 'drupal_file_cache:test:' . $realpath; + $data = [ + 'mtime' => filemtime($realpath), + 'filepath' => $realpath, + 'data' => 42, + ]; + + $this->staticFileCache->store($cid, $data); + + $result = $this->fileCache->getMultiple([$filename]); + $this->assertEquals([$filename => 42], $result); + + // Test a static cache hit. + $file2 = __DIR__ . '/Fixtures/llama-23.txt'; + $this->fileCache->set($file2, 23); + + $result = $this->fileCache->getMultiple([$filename, $file2]); + $this->assertEquals([$filename => 42, $file2 => 23], $result); + + // Cleanup static caches. + $this->fileCache->delete($filename); + $this->fileCache->delete($file2); + } + + /** + * @covers ::set + */ + public function testSet() { + $filename = __DIR__ . '/Fixtures/llama-23.txt'; + $realpath = realpath($filename); + $cid = 'drupal_file_cache:test:' . $realpath; + $data = [ + 'mtime' => filemtime($realpath), + 'filepath' => $realpath, + 'data' => 23, + ]; + + $this->fileCache->set($filename, 23); + $result = $this->staticFileCache->fetch([$cid]); + $this->assertEquals([$cid => $data], $result); + + // Cleanup static caches. + $this->fileCache->delete($filename); + } + + /** + * @covers ::delete + */ + public function testDelete() { + $filename = __DIR__ . '/Fixtures/llama-23.txt'; + $realpath = realpath($filename); + $cid = 'drupal_file_cache:test:' . $realpath; + + $this->fileCache->set($filename, 23); + + // Ensure data is removed after deletion. + $this->fileCache->delete($filename); + + $result = $this->staticFileCache->fetch([$cid]); + $this->assertEquals([], $result); + + $result = $this->fileCache->get($cid); + $this->assertNull($result); + } + +} diff --git a/core/tests/Drupal/Tests/Component/Cache/Fixtures/llama-23.txt b/core/tests/Drupal/Tests/Component/Cache/Fixtures/llama-23.txt new file mode 100644 index 0000000..4099407 --- /dev/null +++ b/core/tests/Drupal/Tests/Component/Cache/Fixtures/llama-23.txt @@ -0,0 +1 @@ +23 diff --git a/core/tests/Drupal/Tests/Component/Cache/Fixtures/llama-42.txt b/core/tests/Drupal/Tests/Component/Cache/Fixtures/llama-42.txt new file mode 100644 index 0000000..d81cc07 --- /dev/null +++ b/core/tests/Drupal/Tests/Component/Cache/Fixtures/llama-42.txt @@ -0,0 +1 @@ +42 diff --git a/core/tests/Drupal/Tests/Component/Cache/StaticFileCacheBackend.php b/core/tests/Drupal/Tests/Component/Cache/StaticFileCacheBackend.php new file mode 100644 index 0000000..7587ea0 --- /dev/null +++ b/core/tests/Drupal/Tests/Component/Cache/StaticFileCacheBackend.php @@ -0,0 +1,77 @@ +bin = isset($configuration['bin']) ? $configuration['bin'] : 'file_cache'; + } + + /** + * {@inheritdoc} + */ + public function fetch(array $cids) { + $result = []; + foreach ($cids as $cid) { + if (isset(static::$cache[$this->bin][$cid])) { + $result[$cid] = static::$cache[$this->bin][$cid]; + } + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function store($cid, $data) { + static::$cache[$this->bin][$cid] = $data; + } + + /** + * {@inheritdoc} + */ + public function delete($cid) { + unset(static::$cache[$this->bin][$cid]); + } + + /** + * Allows tests to reset the static cache to avoid side effects. + */ + public static function reset() { + static::$cache = []; + } +} diff --git a/core/tests/Drupal/Tests/Core/Cache/Fixtures/42.php b/core/tests/Drupal/Tests/Core/Cache/Fixtures/42.php new file mode 100644 index 0000000..8c7eb97 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Cache/Fixtures/42.php @@ -0,0 +1 @@ +cache = $this->getMockBuilder('\Drupal\Core\Cache\PhpStorageFileCacheBackend') + ->disableOriginalConstructor() + ->setMethods(null) + ->getMock(); + + $this->storageMock = $this->getMockBuilder('\Drupal\Component\PhpStorage\PhpStorageInterface') + ->setMethods(['getFullPath', 'save', 'delete', 'exists', 'load', 'writeable', 'deleteAll', 'listAll']) + ->getMock(); + + // Set the storageMock for the cache. + $reflection = new \ReflectionClass($this->cache); + $reflection_property = $reflection->getProperty('storage'); + $reflection_property->setAccessible(TRUE); + $reflection_property->setValue($this->cache, $this->storageMock); + } + + /** + * @covers ::__construct + * @covers ::fetch + */ + public function testFetch() { + $cid = 'foo/bar.txt'; + $cid_hash = basename($cid) . '-' . md5($cid) . '.php'; + + $this->storageMock->expects($this->once()) + ->method('getFullPath') + ->with($this->equalTo($cid_hash)) + ->willReturn(__DIR__ . '/Fixtures/42.php'); + + $result = $this->cache->fetch([$cid]); + $this->assertEquals([$cid => 42], $result); + } + + /** + * @covers ::store + */ + public function testStore() { + $cid = 'foo/bar.txt'; + $cid_hash = basename($cid) . '-' . md5($cid) . '.php'; + + $this->storageMock->expects($this->once()) + ->method('save') + ->with($this->equalTo($cid_hash), $this->equalTo('cache->store($cid, 42); + } + + /** + * @covers ::delete + */ + public function testDelete() { + $cid = 'foo/bar.txt'; + $cid_hash = basename($cid) . '-' . md5($cid) . '.php'; + + $this->storageMock->expects($this->once()) + ->method('delete') + ->with($this->equalTo($cid_hash)); + + $this->cache->delete($cid); + } +}