Issue #1637478 by alexpott, pounard, catch: Add a PHP array cache backend.

8.0.x
catch 2012-08-23 15:26:14 +02:00
parent 6e8a671f83
commit 3d94f559c8
10 changed files with 769 additions and 307 deletions

View File

@ -0,0 +1,238 @@
<?php
/**
* @file
* Definition of Drupal\Core\Cache\ArrayBackend.
*/
namespace Drupal\Core\Cache;
/**
* Defines a memory cache implementation.
*
* Stores cache items in memory using a PHP array.
*
* Should be used for unit tests and specialist use-cases only, does not
* store cached items between requests.
*
*/
class MemoryBackend implements CacheBackendInterface {
/**
* Array to store cache objects.
*/
protected $cache;
/**
* All tags invalidated during the request.
*/
protected $invalidatedTags = array();
/**
* Implements Drupal\Core\Cache\CacheBackendInterface::__construct().
*/
public function __construct($bin) {
}
/**
* Implements Drupal\Core\Cache\CacheBackendInterface::get().
*/
public function get($cid) {
if (isset($this->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() {
}
}

View File

@ -13,6 +13,7 @@ use Drupal\simpletest\WebTestBase;
* Provides helper methods for cache tests.
*/
abstract class CacheTestBase extends WebTestBase {
protected $default_bin = 'page';
protected $default_cid = 'test_temporary';
protected $default_value = 'CacheTest';

View File

@ -11,6 +11,7 @@ namespace Drupal\system\Tests\Cache;
* Tests cache clearing methods.
*/
class ClearTest extends CacheTestBase {
public static function getInfo() {
return array(
'name' => 'Cache clear test',
@ -26,83 +27,6 @@ class ClearTest extends CacheTestBase {
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 @@ class ClearTest extends CacheTestBase {
$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.');
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* @file
* Definition of Drupal\system\Tests\Cache\DatabaseBackendUnitTest.
*/
namespace Drupal\system\Tests\Cache;
use Drupal\Core\Cache\DatabaseBackend;
/**
* Tests DatabaseBackend using GenericCacheBackendUnitTestBase.
*/
class DatabaseBackendUnitTest extends GenericCacheBackendUnitTestBase {
public static function getInfo() {
return array(
'name' => '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');
}
}

View File

@ -0,0 +1,464 @@
<?php
/**
* @file
* Definition of Drupal\system\Tests\Cache\GenericCacheBackendUnitTestBase.
*/
namespace Drupal\system\Tests\Cache;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\simpletest\UnitTestBase;
use stdClass;
/**
* Full generic unit test suite for any cache backend. In order to use it for a
* cache backend implementation extend this class and override the
* createBackendInstace() method to return an object.
*
* @see DatabaseBackendUnitTestCase
* For a full working implementation.
*/
abstract class GenericCacheBackendUnitTestBase extends UnitTestBase {
/**
* Array of objects implementing Drupal\Core\Cache\CacheBackendInterface.
*
* @var array
*/
protected $cachebackends;
/**
* Cache bin to use for testing.
*
* @var string
*/
protected $testBin;
/**
* Random value to use in tests.
*
* @var string
*/
protected $defaultValue;
/**
* Get testing bin.
*
* Override this method if you want to work on a different bin than the
* default one.
*
* @return string
* Bin name.
*/
protected function getTestBin() {
if (!isset($this->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.');
}
}

View File

@ -1,56 +0,0 @@
<?php
/**
* @file
* Definition of Drupal\system\Tests\Cache\GetMultipleTest.
*/
namespace Drupal\system\Tests\Cache;
/**
* Tests getMultiple().
*/
class GetMultipleTest extends CacheTestBase {
public static function getInfo() {
return array(
'name' => '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.'));
}
}

View File

@ -1,46 +0,0 @@
<?php
/**
* @file
* Definition of Drupal\system\Tests\Cache\IsEmptyTest.
*/
namespace Drupal\system\Tests\Cache;
/**
* Tests the isEmpty() method.
*/
class IsEmptyTest extends CacheTestBase {
public static function getInfo() {
return array(
'name' => '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'));
}
}

View File

@ -0,0 +1,28 @@
<?php
/**
* @file
* Definition of Drupal\system\Tests\Cache\ArrayBackendUnitTest.
*/
namespace Drupal\system\Tests\Cache;
use Drupal\Core\Cache\MemoryBackend;
/**
* Tests MemoryBackend using GenericCacheBackendUnitTestBase.
*/
class MemoryBackendUnitTest extends GenericCacheBackendUnitTestBase {
public static function getInfo() {
return array(
'name' => '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);
}
}

View File

@ -14,6 +14,7 @@ use Drupal\simpletest\UnitTestBase;
* Tests the cache NullBackend.
*/
class NullBackendTest extends UnitTestBase {
public static function getInfo() {
return array(
'name' => 'Cache NullBackend test',

View File

@ -1,83 +0,0 @@
<?php
/**
* @file
* Definition of Drupal\system\Tests\Cache\SavingTest.
*/
namespace Drupal\system\Tests\Cache;
use stdClass;
/**
* Tests that variables are saved and restored in the right way.
*/
class SavingTest extends CacheTestBase {
public static function getInfo() {
return array(
'name' => '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.'));
}
}