prepareDatabasePrefix(); // Prepare the environment for running tests. $this->prepareEnvironment(); if (!$this->setupEnvironment) { return FALSE; } // Reset all statics and variables to perform tests in a clean environment. $conf = array(); drupal_static_reset(); // Setup our own memcache variables here. We can't use variable_set() yet. if ($this->default_bin) { $conf["cache_flush_$this->default_bin"] = 0; $conf["cache_class_$this->default_bin"] = 'MemcacheDrupal'; } // Change the database prefix. // All static variables need to be reset before the database prefix is // changed, since DrupalCacheArray implementations attempt to // write back to persistent caches when they are destructed. $this->changeDatabasePrefix(); if (!$this->setupDatabasePrefix) { return FALSE; } // Preset the 'install_profile' system variable, so the first call into // system_rebuild_module_data() (in drupal_install_system()) will register // the test's profile as a module. Without this, the installation profile of // the parent site (executing the test) is registered, and the test // profile's hook_install() and other hook implementations are never // invoked. $conf['install_profile'] = $this->profile; // Perform the actual Drupal installation. include_once DRUPAL_ROOT . '/includes/install.inc'; drupal_install_system(); $this->preloadRegistry(); // Set path variables. variable_set('file_public_path', $this->public_files_directory); variable_set('file_private_path', $this->private_files_directory); variable_set('file_temporary_path', $this->temp_files_directory); // Set the 'simpletest_parent_profile' variable to add the parent profile's // search path to the child site's search paths. // @see drupal_system_listing() // @todo This may need to be primed like 'install_profile' above. variable_set('simpletest_parent_profile', $this->originalProfile); // Include the testing profile. variable_set('install_profile', $this->profile); $profile_details = install_profile_info($this->profile, 'en'); // Install the modules specified by the testing profile. module_enable($profile_details['dependencies'], FALSE); // Install modules needed for this test. This could have been passed in as // either a single array argument or a variable number of string arguments. // @todo Remove this compatibility layer in Drupal 8, and only accept // $modules as a single array argument. $modules = func_get_args(); if (isset($modules[0]) && is_array($modules[0])) { $modules = $modules[0]; } if ($modules) { $success = module_enable($modules, TRUE); $this->assertTrue($success, t('Enabled modules: %modules', array('%modules' => implode(', ', $modules)))); } // Run the profile tasks. $install_profile_module_exists = db_query("SELECT 1 FROM {system} WHERE type = 'module' AND name = :name", array( ':name' => $this->profile, ))->fetchField(); if ($install_profile_module_exists) { module_enable(array($this->profile), FALSE); } // Reset/rebuild all data structures after enabling the modules. $this->resetAll(); // Run cron once in that environment, as install.php does at the end of // the installation process. drupal_cron_run(); // Ensure that the session is not written to the new environment and replace // the global $user session with uid 1 from the new test site. drupal_save_session(FALSE); // Login as uid 1. $user = user_load(1); // Restore necessary variables. variable_set('install_task', 'done'); variable_set('clean_url', $this->originalCleanUrl); variable_set('site_mail', 'simpletest@example.com'); variable_set('date_default_timezone', date_default_timezone_get()); // Set up English language. unset($conf['language_default']); $language = language_default(); // Use the test mail class instead of the default mail handler class. variable_set('mail_system', array('default-system' => 'TestingMailSystem')); drupal_set_time_limit($this->timeLimit); $this->setup = TRUE; if ($this->default_bin) { // Save our memcache variables. variable_set("cache_flush_$this->default_bin", 0); variable_set("cache_class_$this->default_bin", 'MemcacheDrupal'); } $this->resetVariables(); } /** * Test that memcache is configured correctly. */ public function testCacheBin() { if ($this->default_bin) { // Confirm that the default cache bin is handled by memcache. $this->assertEqual(get_class(_cache_get_object($this->default_bin)), 'MemCacheDrupal', t('Memcache caching is configured correctly.')); } } /** * Check whether or not a cache entry exists. * * @param string $cid * The cache id. * @param mixed $var * The variable the cache should contain. * @param string $bin * Defaults to $this->default_bin. The bin the cache item was stored in. * * @return bool * TRUE on pass, FALSE on fail. */ protected function checkCacheExists($cid, $var, $bin = NULL) { if ($bin == NULL) { $bin = $this->default_bin; } $cache = cache_get($cid, $bin); return isset($cache->data) && $cache->data == $var; } /** * Assert or a cache entry exists. * * @param string $message * Message to display. * @param mixed $var * Defaults to $this->default_value. The variable the cache should contain. * @param string $cid * Defaults to $this->default_cid. The cache id. * @param string $bin * Defaults to $this->default_bin. The bin the cache item was stored in. */ protected function assertCacheExists($message, $var = NULL, $cid = NULL, $bin = NULL) { if ($bin == NULL) { $bin = $this->default_bin; } if ($cid == NULL) { $cid = $this->default_cid; } if ($var == NULL) { $var = $this->default_value; } $this->assertTrue($this->checkCacheExists($cid, $var, $bin), $message); } /** * Assert or a cache entry has been removed. * * @param string $message * Message to display. * @param string $cid * Defaults to $this->default_cid. The cache id. * @param string $bin * Defaults to $this->default_bin. The bin the cache item was stored in. */ public function assertCacheRemoved($message, $cid = NULL, $bin = NULL) { if ($bin == NULL) { $bin = $this->default_bin; } if ($cid == NULL) { $cid = $this->default_cid; } $cache = cache_get($cid, $bin); $this->assertFalse($cache, $message); } /** * Perform the general wipe. * * @param string $bin * Defaults to $this->default_bin. The bin to perform the wipe on. */ protected function generalWipe($bin = NULL) { if ($bin == NULL) { $bin = $this->default_bin; } cache_clear_all(NULL, $bin); } /** * Reloads internal MemCacheDrupal variables. */ protected function resetVariables() { if ($this->default_bin) { $_SESSION['cache_flush'][$this->default_bin] = 0; $cache = _cache_get_object($this->default_bin); if ($cache instanceof MemCacheDrupal) { $cache->reloadVariables(); } } } } class MemCacheSavingCase extends MemcacheTestCase { public static function getInfo() { return array( 'name' => 'Memcache saving test', 'description' => 'Check our variables are saved and restored the right way.', 'group' => 'Memcache', ); } /** * @see MemcacheTestCase::setUp() */ public function setUp() { parent::setUp(); } /** * Test the saving and restoring of a string. */ public function testString() { $this->checkVariable($this->randomName(100)); } /** * Test the saving and restoring of an integer. */ public function testInteger() { $this->checkVariable(100); } /** * Test the saving and restoring of a double. */ public function testDouble() { $this->checkVariable(1.29); } /** * Test the saving and restoring of an array. */ public function testArray() { $this->checkVariable(array( 'drupal1', 'drupal2' => 'drupal3', 'drupal4' => array('drupal5', 'drupal6'), )); } /** * Test the saving and restoring of an object. */ public 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, $this->default_bin); $cache = cache_get('test_object', $this->default_bin); $this->assertTrue(isset($cache->data) && $cache->data == $test_object, t('Object is saved and restored properly.')); } /** * Test save and restoring a string with a long key. */ public function testStringLongKey() { $this->checkVariable($this->randomName(100), 'ThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydog'); } /** * Test save and restoring a string using a key with special characters. */ public function testStringSpecialKey() { $this->checkVariable($this->randomName(100), 'Qwerty!@#$%^&*()_+-=[]\;\',./<>?:"{}|£¢'); } /** * Test saving and restoring an integer value directly with dmemcache_set(). */ function testIntegerValue() { $key = $this->randomName(100); $val = rand(1, 1000); dmemcache_set($key, $val, 0, 'cache'); $cache = dmemcache_get($key, 'cache'); $this->assertTrue($val === $cache, t('Integer is saved and restored properly with key @key', array('@key' => $key))); } /** * Test saving and restoring a very large value (>1MiB). */ function testLargeValue() { $this->checkVariable(array_fill(0, 500000, rand())); } /** * Test save and restoring a string with a long key and a very large value. */ function testLongKeyLargeValue() { $this->checkVariable(array_fill(0, 500000, rand()), $this->randomName(300)); } /** * Check or a variable is stored and restored properly. */ public function checkVariable($var, $key = 'test_var') { cache_set($key, $var, $this->default_bin); $cache = cache_get($key, $this->default_bin); $this->assertTrue(isset($cache->data) && $cache->data === $var, t('@type is saved and restored properly!key.', array('@type' => ucfirst(gettype($var)), '!key' => ($key != 'test_var') ? t(' with key @key', array('@key' => $key)) : ''))); } } /** * Test cache_get_multiple(). */ class MemCacheGetMultipleUnitTest extends MemcacheTestCase { public static function getInfo() { return array( 'name' => 'Fetching multiple cache items', 'description' => 'Confirm that multiple records are fetched correctly.', 'group' => 'Memcache', ); } /** * @see MemcacheTestCase::setUp() */ function setUp() { parent::setUp(); } /** * Test cache_get_multiple(). */ public function testCacheMultiple() { $item1 = $this->randomName(10); $item2 = $this->randomName(10); cache_set('test:item1', $item1, $this->default_bin); cache_set('test:item2', $item2, $this->default_bin); $this->assertTrue($this->checkCacheExists('test:item1', $item1), t('Item 1 is cached.')); $this->assertTrue($this->checkCacheExists('test:item2', $item2), t('Item 2 is cached.')); // Fetch both records from the database with cache_get_multiple(). $item_ids = array('test:item1', 'test:item2'); $items = cache_get_multiple($item_ids, $this->default_bin); $this->assertEqual($items['test:item1']->data, $item1, t('Item was returned from cache successfully.')); $this->assertEqual($items['test:item2']->data, $item2, t('Item was returned from cache successfully.')); $this->assertTrue(empty($item_ids), t('Ids of returned items have been removed.')); // Remove one item from the cache. cache_clear_all('test:item2', $this->default_bin); // Confirm that only one item is returned by cache_get_multiple(). $item_ids = array('test:item1', 'test:item2'); $items = cache_get_multiple($item_ids, $this->default_bin); $this->assertEqual($items['test:item1']->data, $item1, t('Item was returned from cache successfully.')); $this->assertFalse(isset($items['test:item2']), t('Item was not returned from the cache.')); $this->assertTrue(count($items) == 1, t('Only valid cache entries returned.')); $this->assertTrue(count($item_ids) == 1, t('Invalid cache ids still present.')); } } /** * Test cache clearing methods. */ class MemCacheClearCase extends MemcacheTestCase { public static function getInfo() { return array( 'name' => 'Cache clear test', 'description' => 'Check our clearing is done the proper way.', 'group' => 'Memcache', ); } /** * @see MemcacheTestCase::setUp() */ public function setUp() { parent::setUp('memcache_test'); $this->default_value = $this->randomName(10); } /** * Test clearing the cache with a cid, no cache lifetime. */ public function testClearCidNoLifetime() { $this->clearCidTest(); } /** * Test clearing the cache with a cid, with cache lifetime. */ public function testClearCidLifetime() { variable_set('cache_lifetime', 6000); $this->clearCidTest(); } /** * Test clearing using wildcard prefixes, no cache lifetime. */ public function testClearWildcardNoLifetime() { $this->clearWildcardPrefixTest(); } /** * Test clearing using wildcard prefix, with cache lifetime. */ public function testClearWildcardLifetime() { variable_set('cache_lifetime', 6000); $this->clearWildcardPrefixTest(); } /** * Test full bin flushes with no cache lifetime. */ public function testClearWildcardFull() { cache_set('test_cid_clear1', $this->default_value, $this->default_bin); cache_set('test_cid_clear2', $this->default_value, $this->default_bin); $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_clear_all('*', $this->default_bin, TRUE); $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.')); } /** * Test full bin flushes with cache lifetime. */ public function testClearCacheLifetime() { variable_set('cache_lifetime', 600); $this->resetVariables(); // Set a cache item with an expiry. cache_set('test_cid', $this->default_value, $this->default_bin, time() + 3600); $this->assertTrue($this->checkCacheExists('test_cid', $this->default_value), 'Cache item was created successfully.'); // Set a permanent cache item. cache_set('test_cid_2', $this->default_value, $this->default_bin); // Clear the page and block caches. cache_clear_all(MEMCACHE_CONTENT_CLEAR, $this->default_bin); // Since the cache was cleared within the current session, cache_get() // should return false. $this->assertFalse($this->checkCacheExists('test_cid', $this->default_value), 'Cache item was cleared successfully.'); // However permament items should stay in place. $this->assertTrue($this->checkCacheExists('test_cid_2', $this->default_value), 'Cache item was not cleared'); // If $_SESSION['cache_flush'] is not set, then the expired item should // be returned. unset($_SESSION['cache_flush']); $this->assertTrue($this->checkCacheExists('test_cid', $this->default_value), 'Cache item is still returned due to minimum cache lifetime.'); // Set a much shorter cache lifetime. variable_set('cache_content_flush_' . $this->default_bin, 0); variable_set('cache_lifetime', 1); cache_set('test_cid', $this->default_value, $this->default_bin, time() + 6000); $this->assertTrue($this->checkCacheExists('test_cid', $this->default_value), 'Cache item was created successfully.'); cache_clear_all(MEMCACHE_CONTENT_CLEAR, $this->default_bin); $this->assertFalse($this->checkCacheExists('test_cid', $this->default_value), 'Cache item is not returned once minimum cache lifetime has expired.'); // Reset the cache clear variables. variable_set('cache_content_flush_' . $this->default_bin, 0); variable_set('cache_lifetime', 6000); $this->resetVariables(); // Confirm that cache_lifetime does not take effect for full bin flushes. cache_set('test_cid', $this->default_value, $this->default_bin, time() + 6000); $this->assertTrue($this->checkCacheExists('test_cid', $this->default_value), 'Cache item was created successfully.'); cache_set('test_cid_2', $this->default_value, $this->default_bin); $this->assertTrue($this->checkCacheExists('test_cid_2', $this->default_value), 'Cache item was created successfully.'); // Now flush the bin. cache_clear_all('*', $this->default_bin, TRUE); $this->assertFalse($this->checkCacheExists('test_cid', $this->default_value), 'Cache item was cleared successfully.'); $this->assertFalse($this->checkCacheExists('test_cid_2', $this->default_value), 'Cache item was cleared successfully.'); } /** * Test different wildcards to verify the wildcard optimizations. */ public function testWildCardOptimizations() { // Set and clear a cache with a short cid/wildcard. cache_set('foo:1', $this->default_value, $this->default_bin); $this->assertCacheExists(t('Foo cache was set.'), $this->default_value, 'foo:1'); cache_clear_all('foo', $this->default_bin, TRUE); $this->assertCacheRemoved(t('Foo cache was invalidated.'), 'foo:1'); // Set additional longer caches. cache_set('foobar', $this->default_value, $this->default_bin); cache_set('foofoo', $this->default_value, $this->default_bin); $this->assertCacheExists(t('Foobar cache set.'), $this->default_value, 'foobar'); $this->assertCacheExists(t('Foofoo cache set.'), $this->default_value, 'foofoo'); // Clear one of them with a wildcard and make sure the other one is still // valid. cache_clear_all('foobar', $this->default_bin, TRUE); $this->assertCacheRemoved(t('Foobar cache invalidated.'), 'foobar'); $this->assertCacheExists(t('Foofoo cache still valid.'), $this->default_value, 'foofoo'); // Set and clear a cache with a different, equally short cid/wildcard. cache_set('bar:1', $this->default_value, $this->default_bin); $this->assertCacheExists(t('Bar cache was set.'), $this->default_value, 'bar:1'); cache_clear_all('bar', $this->default_bin, TRUE); $this->assertCacheRemoved(t('Bar cache invalidated.'), 'bar:1'); $this->assertCacheExists(t('Foofoo cache still valid.'), $this->default_value, 'foofoo'); // Clear cache with an even shorter wildcard. This results in a full bin // bin clear, all entries are marked invalid. cache_set('bar:2', $this->default_value, $this->default_bin); cache_clear_all('ba', $this->default_bin, TRUE); $this->assertCacheRemoved(t('Bar:1 cache invalidated.'), 'bar:1'); $this->assertCacheRemoved(t('Bar:2 cache invalidated.'), 'bar:2'); $this->assertCacheRemoved(t('Foofoo cache invalidated.'), 'foofoo'); } /** * Test CACHE_TEMPORARY and CACHE_PERMANENT behaviour. */ public function testClearTemporaryPermanent() { cache_set('test_cid_clear_temporary', $this->default_value, $this->default_bin, CACHE_TEMPORARY); cache_set('test_cid_clear_permanent', $this->default_value, $this->default_bin, CACHE_PERMANENT); cache_set('test_cid_clear_future', $this->default_value, $this->default_bin, time() + 3600); $this->assertTrue($this->checkCacheExists('test_cid_clear_temporary', $this->default_value) && $this->checkCacheExists('test_cid_clear_permanent', $this->default_value) && $this->checkCacheExists('test_cid_clear_future', $this->default_value), t('Three cache items were created for checking cache expiry.')); // This should clear only expirable items (CACHE_TEMPORARY). cache_clear_all(NULL, $this->default_bin, TRUE); $this->assertFalse($this->checkCacheExists('test_cid_clear_temporary', $this->default_value), t('Temporary cache item was removed after clearing cid NULL.')); $this->assertTrue($this->checkCacheExists('test_cid_clear_permanent', $this->default_value), t('Permanent cache item was not removed after clearing cid NULL.')); $this->assertTrue($this->checkCacheExists('test_cid_clear_future', $this->default_value), t('Future cache item was not removed after clearing cid NULL.')); } /** * Test clearing using a cid. */ public function clearCidTest() { cache_set('test_cid_clear', $this->default_value, $this->default_bin); $this->assertCacheExists(t('Cache was set for clearing cid.'), $this->default_value, 'test_cid_clear'); cache_clear_all('test_cid_clear', $this->default_bin); $this->assertCacheRemoved(t('Cache was removed after clearing cid.'), 'test_cid_clear'); cache_set('test_cid_clear1', $this->default_value, $this->default_bin); cache_set('test_cid_clear2', $this->default_value, $this->default_bin); $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 false.')); cache_clear_all('*', $this->default_bin); $this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value) && $this->checkCacheExists('test_cid_clear2', $this->default_value), t('Two caches still exists after clearing cid "*" with wildcard false.')); } /** * Test cache clears using wildcard prefixes. */ public function clearWildcardPrefixTest() { $this->resetVariables(); cache_set('test_cid_clear:1', $this->default_value, $this->default_bin); cache_set('test_cid_clear:2', $this->default_value, $this->default_bin); $this->assertTrue($this->checkCacheExists('test_cid_clear:1', $this->default_value) && $this->checkCacheExists('test_cid_clear:2', $this->default_value), t('Two caches were created for checking cid substring with wildcard true.')); cache_clear_all('test_cid_clear:', $this->default_bin, TRUE); $this->assertFalse($this->checkCacheExists('test_cid_clear:1', $this->default_value) || $this->checkCacheExists('test_cid_clear:2', $this->default_value), t('Two caches removed after clearing cid substring with wildcard true.')); // Test for the case where a wildcard object disappears, for example a // partial memcache restart or eviction. cache_set('test_cid_clear:1', $this->default_value, $this->default_bin); $this->assertTrue($this->checkCacheExists('test_cid_clear:1', $this->default_value), 'The cache was created successfully.'); cache_clear_all('test_', $this->default_bin, TRUE); $this->assertFalse($this->checkCacheExists('test_cid_clear:1', $this->default_value), 'The cache was cleared successfully.'); // Delete the wildcard manually to simulate an eviction. $wildcard = '.wildcard-test_cid_clear:'; dmemcache_delete($wildcard, $this->default_bin); // Reset the memcache_wildcards() static cache. // @todo: this is a class object in D7. // memcache_wildcards(FALSE, FALSE, FALSE, TRUE); $this->assertFalse($this->checkCacheExists('test_cid_clear:1', $this->default_value), 'The cache was cleared successfully.'); } /** * Test wildcard flushing on separate pages to ensure no static cache is used. */ public function testClearWildcardOnSeparatePages() { $random_wildcard = $this->randomName(2) . ':' . $this->randomName(3); $random_key = $random_wildcard . ':' . $this->randomName(4) . ':' . $this->randomName(2); $random_value = $this->randomName(); $this->drupalGetAJAX('memcache-test/clear-cache'); $data = $this->drupalGetAJAX('memcache-test/set/' . $random_key . '/' . $random_value); $this->assertTrue(is_array($data), 'Cache has data.'); $this->assertEqual($random_key, $data['cid'], 'Cache keys match.'); $this->assertEqual($random_value, $data['data'], 'Cache values match.'); $data = $this->drupalGetAJAX('memcache-test/get/' . $random_key); $this->assertEqual($random_key, $data['cid'], 'Cache keys match.'); $this->assertEqual($random_value, $data['data'], 'Cache values match.'); $this->drupalGet('memcache-test/clear/' . $random_key); $data = $this->drupalGetAJAX('memcache-test/get/' . $random_key); $this->assertFalse($data, 'Cache value at specific key was properly flushed.'); $data = $this->drupalGetAJAX('memcache-test/set/' . $random_key . '/' . $random_value); $this->assertTrue(is_array($data), 'Cache has data.'); $this->assertEqual($random_key, $data['cid'], 'Cache keys match.'); $this->assertEqual($random_value, $data['data'], 'Cache values match.'); $data = $this->drupalGetAJAX('memcache-test/get/' . $random_key); $this->assertEqual($random_key, $data['cid'], 'Cache keys match.'); $this->assertEqual($random_value, $data['data'], 'Cache values match.'); $this->drupalGet('memcache-test/wildcard-clear/' . $random_wildcard); $data = $this->drupalGetAJAX('memcache-test/get/' . $random_key); $this->assertFalse($data, 'Cache was properly flushed.'); } } /** * Tests memcache stampede protection. */ class MemCacheStampedeProtection extends MemcacheTestCase { public static function getInfo() { return array( 'name' => 'Memcache stampede protection', 'description' => 'Tests memcache stampede protection.', 'group' => 'Memcache', ); } /** * Tests the opt out functionality of stampede protection using a unit test. */ public function testStampedeProtectionIgnoringUnit() { global $conf; // Setup a new test bin, to be able to override the used class. $conf['cache_flush_test_bin'] = 0; $conf['cache_class_test_bin'] = 'MockMemCacheDrupal'; $conf['cache_flush_test_bin_2'] = 0; $conf['cache_class_test_bin_2'] = 'MockMemCacheDrupal'; // Setup stampede protection. $conf['memcache_stampede_protection'] = TRUE; $conf['memcache_stampede_protection_ignore'] = array( 'test_bin', 'test_bin_2' => array( 'cid_no_prefix', 'cid_with_prefix:*', ), ); // Ensure the mock object is used. /** @var \MockMemCacheDrupal $cache_object_bin */ $cache_object_bin = _cache_get_object('test_bin'); $this->assertEqual(get_class($cache_object_bin), 'MockMemCacheDrupal'); /** @var \MockMemCacheDrupal $cache_object_bin2 */ $cache_object_bin2 = _cache_get_object('test_bin_2'); $this->assertEqual(get_class($cache_object_bin2), 'MockMemCacheDrupal'); // Test ignoring of an entire bin. $this->assertFalse($cache_object_bin->stampedeProtected('test_cid'), t('Disable stampede protection for cid contained in a disabled bin.')); $this->assertFalse($cache_object_bin->stampedeProtected('cid_no_prefix'), t('Disable stampede protection for cid without prefix in a disabled bin.')); $this->assertFalse($cache_object_bin->stampedeProtected('cid_with_prefix:example'), t('Disable stampede protection for cid with prefix in a disabled bin.')); // Test ignoring of specific CIDs. $this->assertTrue($cache_object_bin2->stampedeProtected('test_cid'), t('Don\'t disable stampede protection for a specific non-matching cid.')); $this->assertFalse($cache_object_bin2->stampedeProtected('cid_no_prefix'), t('Disable stampede protection for a specific cid.')); $this->assertFalse($cache_object_bin2->stampedeProtected('cid_with_prefix:example'), t('Disable stampede protection for a specific cid with disabled prefix.')); $this->assertTrue($cache_object_bin2->stampedeProtected('cid_with_other_prefix:example'), t('Don\'t disable stampede protection for a specific cid with a different prefix.')); } } include_once dirname(__DIR__) . '/memcache.inc'; /** * Wraps the MemCacheDrupal class in order to be able to call a protected method. */ class MockMemCacheDrupal extends MemCacheDrupal { public function stampedeProtected($cid) { return parent::stampedeProtected($cid); } } /** * Test some real world cache scenarios with default modules. * * Please make sure you've set the proper memcache settings in the settings.php. * Looks like I've not chance to change the cache settings to what's needed by * this test. */ class MemCacheRealWorldCase extends MemcacheTestCase { protected $profile = 'standard'; protected $default_bin = 'cache_menu'; public static function getInfo() { return array( 'name' => 'Real world cache tests', 'description' => 'Test some real world cache scenarios.', 'group' => 'Memcache', ); } /** * @see MemcacheTestCase::setUp() */ public function setUp() { parent::setUp('menu'); } /** * Test if the menu module caching acts as expected. * * The menu module clears the affected menu if an menu item is changed using * wildcards. */ public function testMenu() { // Create and login user. $account = $this->drupalCreateUser(array( 'access administration pages', 'administer blocks', 'administer menu', 'create article content', )); $this->drupalLogin($account); // Add Menu Link to test with. $item = $this->addMenuLink(); $original_title = $item['link_title']; // Check if menu link is displayed. $this->drupalGet(''); $this->assertText($original_title, 'Menu item displayed in frontend'); // Change menu item multiple times and check if the change is reflected. for ($i = 0; $i < 3; $i++) { // Edit menu link. $edit = array(); $edit['link_title'] = $this->randomName(16);; $this->drupalPost("admin/structure/menu/item/{$item['mlid']}/edit", $edit, t('Save')); if (!$this->assertResponse(200)) { // One fail is enough. break; } // Verify edited menu link. if (!$this->drupalGet('admin/structure/menu/manage/' . $item['menu_name'])) { // One fail is enough. break; } $this->assertText($edit['link_title'], 'Menu link was edited'); $this->drupalGet(''); if (!$this->assertText($edit['link_title'], 'Change is reflected in frontend')) { // One fail is enough. break; } } } /** * Adds a menu link. * * @see MenuTestCase::addMenuLink() */ public function addMenuLink($plid = 0, $link = '', $menu_name = 'main-menu') { // View add menu link page. $this->drupalGet("admin/structure/menu/manage/$menu_name/add"); $this->assertResponse(200); $title = '!OriginalLink_' . $this->randomName(16); $edit = array( 'link_path' => $link, 'link_title' => $title, 'description' => '', // Use this to disable the menu and test. 'enabled' => TRUE, // Setting this to true should test whether it works when we do the // std_user tests. 'expanded' => TRUE, 'parent' => $menu_name . ':' . $plid, 'weight' => '0', ); // Add menu link. $this->drupalPost(NULL, $edit, t('Save')); $this->assertResponse(200); // Unlike most other modules, there is no confirmation message displayed. $this->assertText($title, 'Menu link was added'); $item = db_query('SELECT * FROM {menu_links} WHERE link_title = :title', array(':title' => $title))->fetchAssoc(); return $item; } } /** * Test statistics generation. */ class MemCacheStatisticsTestCase extends MemcacheTestCase { public static function getInfo() { return array( 'name' => 'Statistics tests', 'description' => 'Test that statistics are being recorded appropriately.', 'group' => 'Memcache', ); } /** * @see MemcacheTestCase::setUp() */ public function setUp() { parent::setUp('memcache_admin'); $conf['cache_default_class'] = 'MemCacheDrupal'; $conf['cache_class_cache_form'] = 'DrupalDatabaseCache'; } /** * Checks for early bootstrap statistics. * * Tests that bootstrap cache commands are recorded when statistics are * enabled and tests that statistics are not recorded when the user doesn't * have access or displaying statistics is disabled. */ public function testBootstrapStatistics() { global $_dmemcache_stats; // Expected statistics for cache_set() and cache_get(). $test_full_key = dmemcache_key($this->default_cid, $this->default_bin); // List of bootstrap cids to check for. $cache_bootstrap_cids = array( 'variables', 'bootstrap_modules', 'lookup_cache', 'system_list', 'module_implements' ); // Turn on memcache statistics. variable_set('show_memcache_statistics', TRUE); drupal_static_reset('dmemcache_stats_init'); $this->drupalGet(''); // Check that statistics are not displayed for anonymous users. $this->assertNoRaw('
', 'Statistics not present.'); // Create and login a user without access to view statistics. $account = $this->drupalCreateUser(); $this->drupalLogin($account); // Check that statistics are not displayed for authenticated users without // permission. $this->assertNoRaw('
', 'Statistics not present.'); // Create and login a user with access to view statistics. $account = $this->drupalCreateUser(array('access memcache statistics')); $this->drupalLogin($account); $this->drupalGet(''); // Check that bootstrap statistics are visible. foreach ($cache_bootstrap_cids as $stat) { $key = $GLOBALS['drupal_test_info']['test_run_id'] . 'cache_bootstrap-' . $stat; $this->assertRaw("getcache_bootstrap{$key}", t('Key @key found.', array('@key' => $key))); } // Clear boostrap cache items. foreach ($cache_bootstrap_cids as $stat) { _cache_get_object('cache_bootstrap')->clear($stat); } $this->drupalGet(''); // Check that early bootstrap statistics are still visible and are being // set too, after they were removed. foreach ($cache_bootstrap_cids as $stat) { $key = $GLOBALS['drupal_test_info']['test_run_id'] . 'cache_bootstrap-' . $stat; $this->assertRaw("getcache_bootstrap{$key}", t('Key @key found (get).', array('@key' => $key))); $this->assertRaw("setcache_bootstrap{$key}", t('Key @key found (set).', array('@key' => $key))); } // Clear the internal statistics store. $_dmemcache_stats = array('all' => array(), 'ops' => array()); // Check that cache_set() statistics are being recorded. cache_set($this->default_cid, $this->default_value, $this->default_bin); $this->assertEqual($_dmemcache_stats['all'][0][1], 'set', 'Set action recorded.'); $this->assertEqual($_dmemcache_stats['all'][0][4], 'hit', 'Set action successful.'); $this->assertNotNull($_dmemcache_stats['ops']['set']); // Clear the internal statistics store. $_dmemcache_stats = array('all' => array(), 'ops' => array()); // Check that cache_get() statistics are being recorded. cache_get($this->default_cid, $this->default_bin); $this->assertEqual($_dmemcache_stats['all'][0][1], 'get', 'Get action recorded.'); $this->assertEqual($_dmemcache_stats['all'][0][4], 'hit', 'Get action successful.'); $this->assertNotNull($_dmemcache_stats['ops']['get']); // Turn off memcache statistics. variable_set('show_memcache_statistics', FALSE); drupal_static_reset('dmemcache_stats_init'); $this->drupalGet(''); // Check that statistics are not recorded when the user has access, but // statistics are disabled. $this->assertNoRaw('
', 'Statistics not present.'); // Clear the internal statistics store. $_dmemcache_stats = array('all' => array(), 'ops' => array()); // Confirm that statistics are not recorded for get()'s when disabled. cache_set($this->default_cid, $this->default_value, $this->default_bin); $this->assertEqual($_dmemcache_stats, array('all' => array(), 'ops' => array())); // Clear the internal statistics store. $_dmemcache_stats = array('all' => array(), 'ops' => array()); // Confirm that statistics are not recorded for set()'s when disabled. cache_get($this->default_cid, $this->default_bin); $this->assertEqual($_dmemcache_stats, array('all' => array(), 'ops' => array())); } }