diff --git a/core/lib/Drupal/Core/Cache/MemoryBackend.php b/core/lib/Drupal/Core/Cache/MemoryBackend.php new file mode 100644 index 0000000000000000000000000000000000000000..1cd5f84fdd486ae28821cd1bb11e52046ee45f5d --- /dev/null +++ b/core/lib/Drupal/Core/Cache/MemoryBackend.php @@ -0,0 +1,238 @@ +cache[$cid])) { + return $this->prepareItem($this->cache[$cid]); + } + else { + return FALSE; + } + } + + /** + * Implements Drupal\Core\Cache\CacheBackendInterface::getMultiple(). + */ + public function getMultiple(&$cids) { + $ret = array(); + + $items = array_intersect_key($this->cache, array_flip($cids)); + + foreach ($items as $item) { + $item = $this->prepareItem($item); + if ($item) { + $ret[$item->cid] = $item; + } + } + + $cids = array_diff($cids, array_keys($ret)); + + return $ret; + } + + /** + * Prepares a cached item. + * + * Checks that items are either permanent or did not expire, and returns data + * as appropriate. + * + * @param stdClass $cache + * An item loaded from cache_get() or cache_get_multiple(). + * + * @return mixed + * The item with data as appropriate or FALSE if there is no + * valid item to load. + */ + protected function prepareItem($cache) { + if (!isset($cache->data)) { + return FALSE; + } + + // The cache data is invalid if any of its tags have been cleared since. + if (count($cache->tags) && $this->hasInvalidatedTags($cache)) { + return FALSE; + } + + return $cache; + } + + /** + * Implements Drupal\Core\Cache\CacheBackendInterface::set(). + */ + public function set($cid, $data, $expire = CACHE_PERMANENT, array $tags = array()) { + $this->cache[$cid] = (object) array( + 'cid' => $cid, + 'data' => $data, + 'expire' => $expire, + 'tags' => $tags, + 'checksum' => $this->checksum($this->flattenTags($tags)), + ); + } + + /* + * Calculates a checksum so data can be invalidated using tags. + */ + function checksum($tags) { + $checksum = ""; + + foreach($tags as $tag) { + // Has the tag already been invalidated. + if (isset($this->invalidatedTags[$tag])) { + $checksum = $checksum . $tag . ':' . $this->invalidatedTags[$tag]; + } + } + + return $checksum; + } + + /** + * Implements Drupal\Core\Cache\CacheBackendInterface::delete(). + */ + public function delete($cid) { + unset($this->cache[$cid]); + } + + /** + * Implements Drupal\Core\Cache\CacheBackendInterface::deleteMultiple(). + */ + public function deleteMultiple(array $cids) { + $this->cache = array_diff_key($this->cache, array_flip($cids)); + } + + /** + * Implements Drupal\Core\Cache\CacheBackendInterface::deletePrefix(). + */ + public function deletePrefix($prefix) { + foreach ($this->cache as $cid => $item) { + if (strpos($cid, $prefix) === 0) { + unset($this->cache[$cid]); + } + } + } + + /** + * Implements Drupal\Core\Cache\CacheBackendInterface::flush(). + */ + public function flush() { + $this->cache = array(); + } + + /** + * Implements Drupal\Core\Cache\CacheBackendInterface::expire(). + * + * Cache expiration is not implemented for PHP ArrayBackend as this backend + * only persists during a single request and expiration are done using + * REQUEST_TIME. + */ + public function expire() { + } + + /** + * Checks to see if any of the tags associated with a cache object have been + * invalidated. + * + * @param object @cache + * An cache object to calculate and compare it's original checksum for. + * + * @return boolean + * TRUE if the a tag has been invalidated, FALSE otherwise. + */ + protected function hasInvalidatedTags($cache) { + if ($cache->checksum != $this->checksum($this->flattenTags($cache->tags))) { + return TRUE; + } + return FALSE; + } + + /** + * Flattens a tags array into a numeric array suitable for string storage. + * + * @param array $tags + * Associative array of tags to flatten. + * + * @return + * An array of flattened tag identifiers. + */ + protected function flattenTags(array $tags) { + if (isset($tags[0])) { + return $tags; + } + + $flat_tags = array(); + foreach ($tags as $namespace => $values) { + if (is_array($values)) { + foreach ($values as $value) { + $flat_tags["$namespace:$value"] = "$namespace:$value"; + } + } + else { + $flat_tags["$namespace:$value"] = "$namespace:$values"; + } + } + return $flat_tags; + } + + /** + * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateTags(). + */ + public function invalidateTags(array $tags) { + $flat_tags = $this->flattenTags($tags); + foreach($flat_tags as $tag) { + if (isset($this->invalidatedTags[$tag])) { + $this->invalidatedTags[$tag] = $this->invalidatedTags[$tag] + 1; + } + else { + $this->invalidatedTags[$tag] = 1; + } + } + } + + /** + * Implements Drupal\Core\Cache\CacheBackendInterface::isEmpty(). + */ + public function isEmpty() { + return empty($this->cache); + } + + /** + * Implements Drupal\Core\Cache\CacheBackendInterface::garbageCollection() + */ + public function garbageCollection() { + } +} diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/CacheTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Cache/CacheTestBase.php index 90465578653676dd1f46426e78f272d101e08c98..e4b275eefe7d8f7fed16211d92807640de15e0b1 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Cache/CacheTestBase.php +++ b/core/modules/system/lib/Drupal/system/Tests/Cache/CacheTestBase.php @@ -13,6 +13,7 @@ * Provides helper methods for cache tests. */ abstract class CacheTestBase extends WebTestBase { + protected $default_bin = 'page'; protected $default_cid = 'test_temporary'; protected $default_value = 'CacheTest'; diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/ClearTest.php b/core/modules/system/lib/Drupal/system/Tests/Cache/ClearTest.php index ea9b02e66cdb10e3e6736ee9b22360ef777cb503..4f7cfca2f9cd1cdcbfcd1696101e5eee78eec1d4 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Cache/ClearTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Cache/ClearTest.php @@ -11,6 +11,7 @@ * Tests cache clearing methods. */ class ClearTest extends CacheTestBase { + public static function getInfo() { return array( 'name' => 'Cache clear test', @@ -26,83 +27,6 @@ function setUp() { parent::setUp(); } - /** - * Test clearing using a cid. - */ - function testClearCid() { - $cache = cache($this->default_bin); - $cache->set('test_cid_clear', $this->default_value); - - $this->assertCacheExists(t('Cache was set for clearing cid.'), $this->default_value, 'test_cid_clear'); - $cache->delete('test_cid_clear'); - - $this->assertCacheRemoved(t('Cache was removed after clearing cid.'), 'test_cid_clear'); - } - - /** - * Test clearing using wildcard. - */ - function testClearWildcard() { - $cache = cache($this->default_bin); - $cache->set('test_cid_clear1', $this->default_value); - $cache->set('test_cid_clear2', $this->default_value); - $this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value) - && $this->checkCacheExists('test_cid_clear2', $this->default_value), - t('Two caches were created for checking cid "*" with wildcard true.')); - $cache->flush(); - $this->assertFalse($this->checkCacheExists('test_cid_clear1', $this->default_value) - || $this->checkCacheExists('test_cid_clear2', $this->default_value), - t('Two caches removed after clearing cid "*" with wildcard true.')); - - $cache->set('test_cid_clear1', $this->default_value); - $cache->set('test_cid_clear2', $this->default_value); - $this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value) - && $this->checkCacheExists('test_cid_clear2', $this->default_value), - t('Two caches were created for checking cid substring with wildcard true.')); - $cache->deletePrefix('test_'); - $this->assertFalse($this->checkCacheExists('test_cid_clear1', $this->default_value) - || $this->checkCacheExists('test_cid_clear2', $this->default_value), - t('Two caches removed after clearing cid substring with wildcard true.')); - } - - /** - * Test clearing using an array. - */ - function testClearArray() { - // Create three cache entries. - $cache = cache($this->default_bin); - $cache->set('test_cid_clear1', $this->default_value); - $cache->set('test_cid_clear2', $this->default_value); - $cache->set('test_cid_clear3', $this->default_value); - $this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value) - && $this->checkCacheExists('test_cid_clear2', $this->default_value) - && $this->checkCacheExists('test_cid_clear3', $this->default_value), - t('Three cache entries were created.')); - - // Clear two entries using an array. - $cache->deleteMultiple(array('test_cid_clear1', 'test_cid_clear2')); - $this->assertFalse($this->checkCacheExists('test_cid_clear1', $this->default_value) - || $this->checkCacheExists('test_cid_clear2', $this->default_value), - t('Two cache entries removed after clearing with an array.')); - - $this->assertTrue($this->checkCacheExists('test_cid_clear3', $this->default_value), - t('Entry was not cleared from the cache')); - - // Set the cache clear threshold to 2 to confirm that the full bin is cleared - // when the threshold is exceeded. - variable_set('cache_clear_threshold', 2); - $cache->set('test_cid_clear1', $this->default_value); - $cache->set('test_cid_clear2', $this->default_value); - $this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value) - && $this->checkCacheExists('test_cid_clear2', $this->default_value), - t('Two cache entries were created.')); - $cache->deleteMultiple(array('test_cid_clear1', 'test_cid_clear2', 'test_cid_clear3')); - $this->assertFalse($this->checkCacheExists('test_cid_clear1', $this->default_value) - || $this->checkCacheExists('test_cid_clear2', $this->default_value) - || $this->checkCacheExists('test_cid_clear3', $this->default_value), - t('All cache entries removed when the array exceeded the cache clear threshold.')); - } - /** * Test drupal_flush_all_caches(). */ @@ -124,49 +48,4 @@ function testFlushAllCaches() { $this->assertFalse($this->checkCacheExists($cid, $this->default_value, $bin), t('All cache entries removed from @bin.', array('@bin' => $bin))); } } - - /** - * Test clearing using cache tags. - */ - function testClearTags() { - $cache = cache($this->default_bin); - $cache->set('test_cid_clear1', $this->default_value, CACHE_PERMANENT, array('test_tag' => array(1))); - $cache->set('test_cid_clear2', $this->default_value, CACHE_PERMANENT, array('test_tag' => array(1))); - $this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value) - && $this->checkCacheExists('test_cid_clear2', $this->default_value), - t('Two cache items were created.')); - cache_invalidate(array('test_tag' => array(1))); - $this->assertFalse($this->checkCacheExists('test_cid_clear1', $this->default_value) - || $this->checkCacheExists('test_cid_clear2', $this->default_value), - t('Two caches removed after clearing a cache tag.')); - - $cache->set('test_cid_clear1', $this->default_value, CACHE_PERMANENT, array('test_tag' => array(1))); - $cache->set('test_cid_clear2', $this->default_value, CACHE_PERMANENT, array('test_tag' => array(2))); - $cache->set('test_cid_clear3', $this->default_value, CACHE_PERMANENT, array('test_tag_foo' => array(3))); - $this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value) - && $this->checkCacheExists('test_cid_clear2', $this->default_value) - && $this->checkCacheExists('test_cid_clear3', $this->default_value), - t('Two cached items were created.')); - cache_invalidate(array('test_tag_foo' => array(3))); - $this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value) - && $this->checkCacheExists('test_cid_clear2', $this->default_value), - t('Cached items not matching the tag were not cleared.')); - - $this->assertFalse($this->checkCacheExists('test_cid_clear3', $this->default_value), - t('Cached item matching the tag was removed.')); - - // For our next trick, we will attempt to clear data in multiple bins. - $tags = array('test_tag' => array(1, 2, 3)); - $bins = array('cache', 'cache_page', 'cache_bootstrap'); - foreach ($bins as $bin) { - cache($bin)->set('test', $this->default_value, CACHE_PERMANENT, $tags); - $this->assertTrue($this->checkCacheExists('test', $this->default_value, $bin), 'Cache item was set in bin.'); - } - cache_invalidate(array('test_tag' => array(2))); - foreach ($bins as $bin) { - $this->assertFalse($this->checkCacheExists('test', $this->default_value, $bin), 'Tag expire affected item in bin.'); - } - $this->assertFalse($this->checkCacheExists('test_cid_clear2', $this->default_value), 'Cached items matching tag were cleared.'); - $this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value), 'Cached items not matching tag were not cleared.'); - } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/DatabaseBackendUnitTest.php b/core/modules/system/lib/Drupal/system/Tests/Cache/DatabaseBackendUnitTest.php new file mode 100644 index 0000000000000000000000000000000000000000..585a3ff6ffa7742cb8c6aa646e25a09a0ae13127 --- /dev/null +++ b/core/modules/system/lib/Drupal/system/Tests/Cache/DatabaseBackendUnitTest.php @@ -0,0 +1,36 @@ + 'Database backend', + 'description' => 'Unit test of the database backend using the generic cache unit test base.', + 'group' => 'Cache', + ); + } + + protected function createCacheBackend($bin) { + return new DatabaseBackend($bin); + } + + public function setUpCacheBackend() { + drupal_install_schema('system'); + } + + public function tearDownCacheBackend() { + drupal_uninstall_schema('system'); + } +} diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/GenericCacheBackendUnitTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Cache/GenericCacheBackendUnitTestBase.php new file mode 100644 index 0000000000000000000000000000000000000000..931b46d6cb4a0c20cb9c272c3866b3bcc8985785 --- /dev/null +++ b/core/modules/system/lib/Drupal/system/Tests/Cache/GenericCacheBackendUnitTestBase.php @@ -0,0 +1,464 @@ +testBin)) { + $this->testBin = 'page'; + } + return $this->testBin; + } + + /** + * Create a cache backend to test. + * + * Override this method to test a CacheBackend. + * + * @param string $bin + * Bin name to use for this backend instance. + * + * @return Drupal\Core\Cache\CacheBackendInterface + * Cache backend to test. + */ + protected abstract function createCacheBackend($bin); + + /** + * Allow specific implementation to change the environement before test run. + */ + public function setUpCacheBackend() { + } + + /** + * Allow specific implementation to alter the environement after test run but + * before the real tear down, which will changes things such as the database + * prefix. + */ + public function tearDownCacheBackend() { + } + + /** + * Get backend to test, this will get a shared instance set in the object. + * + * @return Drupal\Core\Cache\CacheBackendInterface + * Cache backend to test. + */ + final function getCacheBackend($bin = null) { + if (!isset($bin)) { + $bin = $this->getTestBin(); + } + if (!isset($this->cachebackends[$bin])) { + $this->cachebackends[$bin] = $this->createCacheBackend($bin); + // Ensure the backend is empty. + $this->cachebackends[$bin]->flush(); + } + return $this->cachebackends[$bin]; + } + + public function setUp() { + $this->cachebackends = array(); + $this->defaultValue = $this->randomName(10); + + parent::setUp(); + + $this->setUpCacheBackend(); + } + + public function tearDown() { + // Destruct the registered backend, each test will get a fresh instance, + // properly flushing it here ensure that on persistant data backends they + // will come up empty the next test. + foreach ($this->cachebackends as $bin => $cachebackend) { + $this->cachebackends[$bin]->flush(); + } + unset($this->cachebackends); + + $this->tearDownCacheBackend(); + + parent::tearDown(); + } + + /** + * Test Drupal\Core\Cache\CacheBackendInterface::get() and + * Drupal\Core\Cache\CacheBackendInterface::set(). + */ + public function testSetGet() { + $backend = $this->getCacheBackend(); + + $data = 7; + $this->assertIdentical(FALSE, $backend->get('test1'), "Backend does not contain data for cache id test1."); + $backend->set('test1', $data); + $cached = $backend->get('test1'); + $this->assert(is_object($cached), "Backend returned an object for cache id test1."); + $this->assertIdentical($data, $cached->data); + + $data = array('value' => 3); + $this->assertIdentical(FALSE, $backend->get('test2'), "Backend does not contain data for cache id test2."); + $backend->set('test2', $data); + $cached = $backend->get('test2'); + $this->assert(is_object($cached), "Backend returned an object for cache id test2."); + $this->assertIdentical($data, $cached->data); + } + + /** + * Test Drupal\Core\Cache\CacheBackendInterface::delete(). + */ + public function testDelete() { + $backend = $this->getCacheBackend(); + + $this->assertIdentical(FALSE, $backend->get('test1'), "Backend does not contain data for cache id test1."); + $backend->set('test1', 7); + $this->assert(is_object($backend->get('test1')), "Backend returned an object for cache id test1."); + + $this->assertIdentical(FALSE, $backend->get('test2'), "Backend does not contain data for cache id test2."); + $backend->set('test2', 3); + $this->assert(is_object($backend->get('test2')), "Backend returned an object for cache id %cid."); + + $backend->delete('test1'); + $this->assertIdentical(FALSE, $backend->get('test1'), "Backend does not contain data for cache id test1 after deletion."); + + $cached = $backend->get('test2'); + $this->assert(is_object($backend->get('test2')), "Backend still has an object for cache id test2."); + + $backend->delete('test2'); + $this->assertIdentical(FALSE, $backend->get('test2'), "Backend does not contain data for cache id test2 after deletion."); + } + + /** + * Test data type perservation. + */ + public function testValueTypeIsKept() { + $backend = $this->getCacheBackend(); + + $variables = array( + 'test1' => 1, + 'test2' => '0', + 'test3' => '', + 'test4' => 12.64, + 'test5' => false, + 'test6' => array(1,2,3), + ); + + // Create cache entries. + foreach ($variables as $cid => $data) { + $backend->set($cid, $data); + } + + // Retrieve and test cache objects. + foreach ($variables as $cid => $value) { + $object = $backend->get($cid); + $this->assert(is_object($object), sprintf("Backend returned an object for cache id %s.", $cid)); + $this->assertIdentical($value, $object->data, sprintf("Data of cached id %s kept is identical in type and value", $cid)); + } + } + + /** + * Test Drupal\Core\Cache\CacheBackendInterface::getMultiple(). + */ + public function testGetMultiple() { + $backend = $this->getCacheBackend(); + + // Set numerous testing keys. + $backend->set('test1', 1); + $backend->set('test2', 3); + $backend->set('test3', 5); + $backend->set('test4', 7); + $backend->set('test5', 11); + $backend->set('test6', 13); + $backend->set('test7', 17); + + // Mismatch order for harder testing. + $reference = array( + 'test3', + 'test7', + 'test21', // Cid does not exist. + 'test6', + 'test19', // Cid does not exist until added before second getMulitple(). + 'test2', + ); + + $cids = $reference; + $ret = $backend->getMultiple($cids); + // Test return - ensure it contains existing cache ids. + $this->assert(isset($ret['test2']), "Existing cache id test2 is set."); + $this->assert(isset($ret['test3']), "Existing cache id test3 is set."); + $this->assert(isset($ret['test6']), "Existing cache id test6 is set."); + $this->assert(isset($ret['test7']), "Existing cache id test7 is set."); + // Test return - ensure it does not contain nonexistent cache ids. + $this->assertFalse(isset($ret['test19']), "Nonexistent cache id test19 is not set."); + $this->assertFalse(isset($ret['test21']), "Nonexistent cache id test21 is not set."); + // Test values. + $this->assertIdentical($ret['test2']->data, 3, "Existing cache id test2 has the correct value."); + $this->assertIdentical($ret['test3']->data, 5, "Existing cache id test3 has the correct value."); + $this->assertIdentical($ret['test6']->data, 13, "Existing cache id test6 has the correct value."); + $this->assertIdentical($ret['test7']->data, 17, "Existing cache id test7 has the correct value."); + // Test $cids array - ensure it contains cache id's that do not exist. + $this->assert(in_array('test19', $cids), "Nonexistent cache id test19 is in cids array."); + $this->assert(in_array('test21', $cids), "Nonexistent cache id test21 is in cids array."); + // Test $cids array - ensure it does not contain cache id's that exist. + $this->assertFalse(in_array('test2', $cids), "Existing cache id test2 is not in cids array."); + $this->assertFalse(in_array('test3', $cids), "Existing cache id test3 is not in cids array."); + $this->assertFalse(in_array('test6', $cids), "Existing cache id test6 is not in cids array."); + $this->assertFalse(in_array('test7', $cids), "Existing cache id test7 is not in cids array."); + + // Test a second time after deleting and setting new keys which ensures that + // if the backend uses statics it does not cause unexpected results. + $backend->delete('test3'); + $backend->delete('test6'); + $backend->set('test19', 57); + + $cids = $reference; + $ret = $backend->getMultiple($cids); + // Test return - ensure it contains existing cache ids. + $this->assert(isset($ret['test2']), "Existing cache id test2 is set"); + $this->assert(isset($ret['test7']), "Existing cache id test7 is set"); + $this->assert(isset($ret['test19']), "Added cache id test19 is set"); + // Test return - ensure it does not contain nonexistent cache ids. + $this->assertFalse(isset($ret['test3']), "Deleted cache id test3 is not set"); + $this->assertFalse(isset($ret['test6']), "Deleted cache id test6 is not set"); + $this->assertFalse(isset($ret['test21']), "Nonexistent cache id test21 is not set"); + // Test values. + $this->assertIdentical($ret['test2']->data, 3, "Existing cache id test2 has the correct value."); + $this->assertIdentical($ret['test7']->data, 17, "Existing cache id test7 has the correct value."); + $this->assertIdentical($ret['test19']->data, 57, "Added cache id test19 has the correct value."); + // Test $cids array - ensure it contains cache id's that do not exist. + $this->assert(in_array('test3', $cids), "Deleted cache id test3 is in cids array."); + $this->assert(in_array('test6', $cids), "Deleted cache id test6 is in cids array."); + $this->assert(in_array('test21', $cids), "Nonexistent cache id test21 is in cids array."); + // Test $cids array - ensure it does not contain cache id's that exist. + $this->assertFalse(in_array('test2', $cids), "Existing cache id test2 is not in cids array."); + $this->assertFalse(in_array('test7', $cids), "Existing cache id test7 is not in cids array."); + $this->assertFalse(in_array('test19', $cids), "Added cache id test19 is not in cids array."); + } + + /** + * Test Drupal\Core\Cache\CacheBackendInterface::isEmpty(). + */ + public function testIsEmpty() { + $backend = $this->getCacheBackend(); + + $this->assertTrue($backend->isEmpty(), "Backend is empty."); + + $backend->set('pony', "Shetland"); + $this->assertFalse($backend->isEmpty(), "Backend is not empty."); + + $backend->delete('pony'); + $this->assertTrue($backend->isEmpty(), "Backend is empty."); + } + + /** + * Test Drupal\Core\Cache\CacheBackendInterface::deleteMultiple(). + */ + public function testDeleteMultiple() { + $backend = $this->getCacheBackend(); + + // Set numerous testing keys. + $backend->set('test1', 1); + $backend->set('test2', 3); + $backend->set('test3', 5); + $backend->set('test4', 7); + $backend->set('test5', 11); + $backend->set('test6', 13); + $backend->set('test7', 17); + + $backend->deleteMultiple(array( + 'test1', + 'test3', + 'test5', + 'test7', + 'test19', // Nonexistent key should not cause an error. + 'test21', // Nonexistent key should not cause an error. + )); + + // Test if expected keys have been deleted. + $this->assertIdentical(FALSE, $backend->get('test1'), "Cache id test1 deleted."); + $this->assertIdentical(FALSE, $backend->get('test3'), "Cache id test3 deleted."); + $this->assertIdentical(FALSE, $backend->get('test5'), "Cache id test5 deleted."); + $this->assertIdentical(FALSE, $backend->get('test7'), "Cache id test7 deleted."); + + // Test if expected keys exist. + $this->assertNotIdentical(FALSE, $backend->get('test2'), "Cache id test2 exists."); + $this->assertNotIdentical(FALSE, $backend->get('test4'), "Cache id test4 exists."); + $this->assertNotIdentical(FALSE, $backend->get('test6'), "Cache id test6 exists."); + + // Test if that expected keys do not exist. + $this->assertIdentical(FALSE, $backend->get('test19'), "Cache id test19 does not exist."); + $this->assertIdentical(FALSE, $backend->get('test21'), "Cache id test21 does not exist."); + } + + /** + * Test Drupal\Core\Cache\CacheBackendInterface::deletePrefix(). + */ + public function testDeletePrefix() { + $backend = $this->getCacheBackend(); + + // Set numerous testing keys. + $backend->set('banana_test1', 1); + $backend->set('monkey_test2', 3); + $backend->set('monkey_banana_test3', 5); + $backend->set('banana_test_4', 7); + $backend->set('pony_monkey_test5_banana', 11); + $backend->set('monkey_test6', 13); + $backend->set('banana_pony_test7_monkey', 17); + + $backend->deletePrefix('banana'); + // Keys starting with banana have been deleted. + $this->assertIdentical(FALSE, $backend->get('banana_test1'), "Cache id banana_test1 deleted."); + $this->assertIdentical(FALSE, $backend->get('banana_test_4'), "Cache id banana_test_4 deleted."); + $this->assertIdentical(FALSE, $backend->get('banana_pony_test7_monkey'), "Cache id banana_pony_test7_monkey deleted."); + // Keys not starting with banana still exist. + $this->assertNotIdentical(FALSE, $backend->get('monkey_test2'), "Cache id monkey_test2 exists."); + $this->assertNotIdentical(FALSE, $backend->get('monkey_banana_test3'), "Cache id monkey_banana_test3 exists."); + $this->assertNotIdentical(FALSE, $backend->get('pony_monkey_test5_banana'), "Cache id poney_monkey_test5_banana exists."); + $this->assertNotIdentical(FALSE, $backend->get('monkey_test6'), "Cache id monkey_test6 exists."); + + $backend->deletePrefix('monkey'); + // Keys starting with monkey have been deleted. + $this->assertIdentical(FALSE, $backend->get('monkey_test2'), "Cache id monkey_test2 deleted."); + $this->assertIdentical(FALSE, $backend->get('monkey_banana_test3'), "Cache id monkey_banana_test3 deleted."); + $this->assertIdentical(FALSE, $backend->get('banana_pony_test7_monkey'), "Cache id banana_pony_test7_monkey deleted."); + // Keys not starting with monkey still exist. + $this->assertNotIdentical(FALSE, $backend->get('pony_monkey_test5_banana'), "Cache id pony_monkey_test5_banana exists."); + } + + /** + * Test Drupal\Core\Cache\CacheBackendInterface::flush(). + */ + public function testFlush() { + $backend = $this->getCacheBackend(); + + // Set both expiring and permanent keys. + $backend->set('test1', 1, CACHE_PERMANENT); + $backend->set('test2', 3, time() + 1000); + + $backend->flush(); + + $this->assertTrue($backend->isEmpty(), "Backend is empty after flush."); + + $this->assertIdentical(FALSE, $backend->get('test1'), "First key has been flushed."); + $this->assertIdentical(FALSE, $backend->get('test2'), "Second key has been flushed."); + } + + /** + * Check whether or not a cache entry exists. + * + * @param $cid + * The cache id. + * @param $bin + * The cache bin to use. If not provided the default test bin wil be used. + * + * @return + * TRUE on pass, FALSE on fail. + */ + protected function checkCacheExists($cid, $bin = null) { + $cached = $this->getCacheBackend($bin)->get($cid); + return isset($cached->data); + } + + /** + * Test Drupal\Core\Cache\CacheBackendInterface::invalidateTags(). + */ + function testClearTags() { + $backend = $this->getCacheBackend(); + + // Create two cache entries with the same tag and tag value. + $backend->set('test_cid_clear1', $this->defaultValue, CACHE_PERMANENT, array('test_tag' => array(1))); + $backend->set('test_cid_clear2', $this->defaultValue, CACHE_PERMANENT, array('test_tag' => array(1))); + $this->assertTrue($this->checkCacheExists('test_cid_clear1') + && $this->checkCacheExists('test_cid_clear2'), + 'Two cache items were created.'); + // Invalidate test_tag of value 1. This should invalidate both entries. + $backend->invalidateTags(array('test_tag' => array(1))); + $this->assertFalse($this->checkCacheExists('test_cid_clear1') + || $this->checkCacheExists('test_cid_clear2'), + 'Two caches removed after clearing a cache tag.'); + + // Create three cache entries with a mix of tags and tag values. + $backend->set('test_cid_clear1', $this->defaultValue, CACHE_PERMANENT, array('test_tag' => array(1))); + $backend->set('test_cid_clear2', $this->defaultValue, CACHE_PERMANENT, array('test_tag' => array(2))); + $backend->set('test_cid_clear3', $this->defaultValue, CACHE_PERMANENT, array('test_tag_foo' => array(3))); + $this->assertTrue($this->checkCacheExists('test_cid_clear1') + && $this->checkCacheExists('test_cid_clear2') + && $this->checkCacheExists('test_cid_clear3'), + 'Two cached items were created.'); + $backend->invalidateTags(array('test_tag_foo' => array(3))); + $this->assertTrue($this->checkCacheExists('test_cid_clear1') + && $this->checkCacheExists('test_cid_clear2'), + 'Cached items not matching the tag were not cleared.'); + + $this->assertFalse($this->checkCacheExists('test_cid_clear3'), + 'Cached item matching the tag was removed.'); + + // Create cache entry in multiple bins. Two cache entries (test_cid_clear1 + // and test_cid_clear2) still exist from previous tests. + $tags = array('test_tag' => array(1, 2, 3)); + $bins = array('path', 'bootstrap', 'page'); + foreach ($bins as $bin) { + $this->getCacheBackend($bin)->set('test', $this->defaultValue, CACHE_PERMANENT, $tags); + $this->assertTrue($this->checkCacheExists('test', $bin), 'Cache item was set in bin.'); + } + + // Invalidate tag in mulitple bins. + foreach ($bins as $bin) { + $this->getCacheBackend($bin)->invalidateTags(array('test_tag' => array(2))); + } + + // Test that cache entry has been invalidated in multple bins. + foreach ($bins as $bin) { + $this->assertFalse($this->checkCacheExists('test', $bin), 'Tag expire affected item in bin.'); + } + // Test that the cache entry with a matching tag has been invalidated. + $this->assertFalse($this->checkCacheExists('test_cid_clear2', $bin), 'Cached items matching tag were cleared.'); + // Test that the cache entry with without a matching tag still exists. + $this->assertTrue($this->checkCacheExists('test_cid_clear1', $bin), 'Cached items not matching tag were not cleared.'); + } +} diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/GetMultipleTest.php b/core/modules/system/lib/Drupal/system/Tests/Cache/GetMultipleTest.php deleted file mode 100644 index f9812127fa6ed5228f7418ef47ac5195d1e575d7..0000000000000000000000000000000000000000 --- a/core/modules/system/lib/Drupal/system/Tests/Cache/GetMultipleTest.php +++ /dev/null @@ -1,56 +0,0 @@ - 'Fetching multiple cache items', - 'description' => 'Confirm that multiple records are fetched correctly.', - 'group' => 'Cache', - ); - } - - function setUp() { - $this->default_bin = 'page'; - parent::setUp(); - } - - /** - * Test getMultiple(). - */ - function testCacheMultiple() { - $item1 = $this->randomName(10); - $item2 = $this->randomName(10); - $cache = cache($this->default_bin); - $cache->set('item1', $item1); - $cache->set('item2', $item2); - $this->assertTrue($this->checkCacheExists('item1', $item1), t('Item 1 is cached.')); - $this->assertTrue($this->checkCacheExists('item2', $item2), t('Item 2 is cached.')); - - // Fetch both records from the database with getMultiple(). - $item_ids = array('item1', 'item2'); - $items = $cache->getMultiple($item_ids); - $this->assertEqual($items['item1']->data, $item1, t('Item was returned from cache successfully.')); - $this->assertEqual($items['item2']->data, $item2, t('Item was returned from cache successfully.')); - - // Remove one item from the cache. - $cache->delete('item2'); - - // Confirm that only one item is returned by getMultiple(). - $item_ids = array('item1', 'item2'); - $items = $cache->getMultiple($item_ids); - $this->assertEqual($items['item1']->data, $item1, t('Item was returned from cache successfully.')); - $this->assertFalse(isset($items['item2']), t('Item was not returned from the cache.')); - $this->assertTrue(count($items) == 1, t('Only valid cache entries returned.')); - } -} diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/IsEmptyTest.php b/core/modules/system/lib/Drupal/system/Tests/Cache/IsEmptyTest.php deleted file mode 100644 index bd0d6ca640d5c28d2a9c420d9e60e4ec4b593904..0000000000000000000000000000000000000000 --- a/core/modules/system/lib/Drupal/system/Tests/Cache/IsEmptyTest.php +++ /dev/null @@ -1,46 +0,0 @@ - 'Cache emptiness test', - 'description' => 'Check if a cache bin is empty after performing clear operations.', - 'group' => 'Cache' - ); - } - - function setUp() { - $this->default_bin = 'page'; - $this->default_value = $this->randomName(10); - - parent::setUp(); - } - - /** - * Test clearing using a cid. - */ - function testIsEmpty() { - // Clear the cache bin. - $cache = cache($this->default_bin); - $cache->flush(); - $this->assertTrue($cache->isEmpty(), t('The cache bin is empty')); - // Add some data to the cache bin. - $cache->set($this->default_cid, $this->default_value); - $this->assertCacheExists(t('Cache was set.'), $this->default_value, $this->default_cid); - $this->assertFalse($cache->isEmpty(), t('The cache bin is not empty')); - // Remove the cached data. - $cache->delete($this->default_cid); - $this->assertCacheRemoved(t('Cache was removed.'), $this->default_cid); - $this->assertTrue($cache->isEmpty(), t('The cache bin is empty')); - } -} diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/MemoryBackendUnitTest.php b/core/modules/system/lib/Drupal/system/Tests/Cache/MemoryBackendUnitTest.php new file mode 100644 index 0000000000000000000000000000000000000000..843eb23b957bca877eadbba8abebc4de9592e28e --- /dev/null +++ b/core/modules/system/lib/Drupal/system/Tests/Cache/MemoryBackendUnitTest.php @@ -0,0 +1,28 @@ + 'Memory cache backend', + 'description' => 'Unit test of the memory cache backend using the generic cache unit test base.', + 'group' => 'Cache', + ); + } + + protected function createCacheBackend($bin) { + return new MemoryBackend($bin); + } +} diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/NullBackendTest.php b/core/modules/system/lib/Drupal/system/Tests/Cache/NullBackendTest.php index 5a42e5defb622d8869f37e2c96769e4155c83a35..3882401729f4ba79940783e1b1af87712fddfe98 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Cache/NullBackendTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Cache/NullBackendTest.php @@ -14,6 +14,7 @@ * Tests the cache NullBackend. */ class NullBackendTest extends UnitTestBase { + public static function getInfo() { return array( 'name' => 'Cache NullBackend test', diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/SavingTest.php b/core/modules/system/lib/Drupal/system/Tests/Cache/SavingTest.php deleted file mode 100644 index 410de25654f6832c09dc09011b08f3421c9e420e..0000000000000000000000000000000000000000 --- a/core/modules/system/lib/Drupal/system/Tests/Cache/SavingTest.php +++ /dev/null @@ -1,83 +0,0 @@ - 'Cache saving test', - 'description' => 'Check our variables are saved and restored the right way.', - 'group' => 'Cache' - ); - } - - /** - * Test the saving and restoring of a string. - */ - function testString() { - $this->checkVariable($this->randomName(100)); - } - - /** - * Test the saving and restoring of an integer. - */ - function testInteger() { - $this->checkVariable(100); - } - - /** - * Test the saving and restoring of a double. - */ - function testDouble() { - $this->checkVariable(1.29); - } - - /** - * Test the saving and restoring of an array. - */ - function testArray() { - $this->checkVariable(array('drupal1', 'drupal2' => 'drupal3', 'drupal4' => array('drupal5', 'drupal6'))); - } - - /** - * Test the saving and restoring of an object. - */ - function testObject() { - $test_object = new stdClass(); - $test_object->test1 = $this->randomName(100); - $test_object->test2 = 100; - $test_object->test3 = array('drupal1', 'drupal2' => 'drupal3', 'drupal4' => array('drupal5', 'drupal6')); - - - cache()->set('test_object', $test_object); - $cached = cache()->get('test_object'); - $this->assertTrue(isset($cached->data) && $cached->data == $test_object, t('Object is saved and restored properly.')); - } - - /** - * Check or a variable is stored and restored properly. - */ - function checkVariable($var) { - cache()->set('test_var', $var); - $cached = cache()->get('test_var'); - $this->assertTrue(isset($cached->data) && $cached->data === $var, t('@type is saved and restored properly.', array('@type' => ucfirst(gettype($var))))); - } - - /** - * Test no empty cids are written in cache table. - */ - function testNoEmptyCids() { - $this->drupalGet('user/register'); - $this->assertFalse(cache()->get(''), t('No cache entry is written with an empty cid.')); - } -}