View source  
  <?php
class MemcacheTestCase extends DrupalWebTestCase {
  protected $profile = 'testing';
  protected $default_bin = 'cache_memcache';
  protected $default_cid = 'test_temporary';
  protected $default_value = 'MemcacheTest';
  function setUp() {
    parent::setUp(func_get_args());
    variable_set("cache_flush_{$this->default_bin}", 0);
    variable_set('cache_class_cache_memcache', 'MemcacheDrupal');
    $this
      ->resetVariables();
  }
  
  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;
  }
  
  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);
  }
  
  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);
  }
  
  protected function generalWipe($bin = NULL) {
    if ($bin == NULL) {
      $bin = $this->default_bin;
    }
    cache_clear_all(NULL, $bin);
  }
  function resetVariables() {
    _cache_get_object($this->default_bin)
      ->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',
    );
  }
  function setUp() {
    parent::setUp();
  }
  
  function testString() {
    $this
      ->checkVariable($this
      ->randomName(100));
  }
  
  function testInteger() {
    $this
      ->checkVariable(100);
  }
  
  function testDouble() {
    $this
      ->checkVariable(1.29);
  }
  
  function testArray() {
    $this
      ->checkVariable(array(
      'drupal1',
      'drupal2' => 'drupal3',
      'drupal4' => array(
        'drupal5',
        'drupal6',
      ),
    ));
  }
  
  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, 'cache');
    $cache = cache_get('test_object', 'cache');
    $this
      ->assertTrue(isset($cache->data) && $cache->data == $test_object, t('Object is saved and restored properly.'));
  }
  
  function testStringLongKey() {
    $this
      ->checkVariable($this
      ->randomName(100), 'ThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydog');
  }
  
  function testStringSpecialKey() {
    $this
      ->checkVariable($this
      ->randomName(100), 'Qwerty!@#$%^&*()_+-=[]\\;\',./<>?:"{}|£¢');
  }
  
  function checkVariable($var, $key = 'test_var') {
    cache_set($key, $var, 'cache');
    $cache = cache_get($key, 'cache');
    $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,
      )) : '',
    )));
  }
}
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',
    );
  }
  function setUp() {
    parent::setUp();
  }
  
  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.'));
    
    $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.'));
    
    cache_clear_all('test:item2', $this->default_bin);
    
    $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.'));
  }
}
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',
    );
  }
  function setUp() {
    parent::setUp('memcache_test');
    $this->default_value = $this
      ->randomName(10);
  }
  
  function testClearCidNoLifetime() {
    $this
      ->clearCidTest();
  }
  
  function testClearCidLifetime() {
    variable_set('cache_lifetime', 6000);
    $this
      ->clearCidTest();
  }
  
  function testClearWildcardNoLifetime() {
    $this
      ->clearWildcardPrefixTest();
  }
  
  function testClearWildcardLifetime() {
    variable_set('cache_lifetime', 6000);
    $this
      ->clearWildcardPrefixTest();
  }
  
  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.'));
  }
  
  function testClearCacheLifetime() {
    variable_set('cache_lifetime', 600);
    $this
      ->resetVariables();
    
    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.');
    
    cache_set('test_cid_2', $this->default_value, $this->default_bin);
    
    cache_clear_all(MEMCACHE_CONTENT_CLEAR, $this->default_bin);
    
    $this
      ->assertFalse($this
      ->checkCacheExists('test_cid', $this->default_value), 'Cache item was cleared successfully.');
    
    $this
      ->assertTrue($this
      ->checkCacheExists('test_cid_2', $this->default_value), 'Cache item was not cleared');
    
    unset($_SESSION['cache_flush']);
    $this
      ->assertTrue($this
      ->checkCacheExists('test_cid', $this->default_value), 'Cache item is still returned due to minimum cache lifetime.');
    
    variable_set('cache_content_flush_' . $this->default_bin, 0);
    variable_set('cache_lifetime', 1);
    cache_set('test_cid_1', $this->default_value, $this->default_bin, time() + 6000);
    $this
      ->assertTrue($this
      ->checkCacheExists('test_cid', $this->default_value), 'Cache item was created successfully.');
    sleep(2);
    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.');
    
    variable_set('cache_content_flush_' . $this->default_bin, 0);
    variable_set('cache_lifetime', 6000);
    $this
      ->resetVariables();
    sleep(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_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.');
    
    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.');
  }
  
  function testWildCardOptimizations() {
    
    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');
    
    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');
    
    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');
    
    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');
    
    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');
  }
  
  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.'));
  }
  
  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.'));
    
    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.');
    
    $wildcard = '.wildcard-' . 'test_cid_clear:';
    dmemcache_delete($wildcard, $this->default_bin);
    
    
    $this
      ->assertFalse($this
      ->checkCacheExists('test_cid_clear:1', $this->default_value), 'The cache was cleared successfully.');
  }
  
  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/wildcard-clear/' . $random_wildcard);
    $data = $this
      ->drupalGetAJAX('memcache-test/get/' . $random_key);
    $this
      ->assertFalse($data, 'Cache 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.');
  }
}
class MemCacheRealWorldCase extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'Real world cache tests',
      'description' => 'Test some real world cache scenarios.',
      'group' => 'Memcache',
    );
  }
  function setUp() {
    parent::setUp('menu');
  }
  
  function testMenu() {
    
    $account = $this
      ->drupalCreateUser(array(
      'access administration pages',
      'administer blocks',
      'administer menu',
      'create article content',
    ));
    $this
      ->drupalLogin($account);
    
    $item = $this
      ->addMenuLink();
    $original_title = $item['link_title'];
    
    $this
      ->drupalGet('');
    $this
      ->assertText($original_title, 'Menu item displayed in frontend');
    
    for ($i = 0; $i < 3; $i++) {
      
      $edit = array();
      $edit['link_title'] = $this
        ->randomName(16);
      $this
        ->drupalPost("admin/structure/menu/item/{$item['mlid']}/edit", $edit, t('Save'));
      if (!$this
        ->assertResponse(200)) {
        
        break;
      }
      
      if (!$this
        ->drupalGet('admin/structure/menu/manage/' . $item['menu_name'])) {
        
        break;
      }
      $this
        ->assertText($edit['link_title'], 'Menu link was edited');
      $this
        ->drupalGet('');
      if (!$this
        ->assertText($edit['link_title'], 'Change is reflected in frontend')) {
        
        break;
      }
    }
  }
  
  function addMenuLink($plid = 0, $link = '<front>', $menu_name = 'main-menu') {
    
    $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' => '',
      'enabled' => TRUE,
      
      'expanded' => TRUE,
      
      'parent' => $menu_name . ':' . $plid,
      'weight' => '0',
    );
    
    $this
      ->drupalPost(NULL, $edit, t('Save'));
    $this
      ->assertResponse(200);
    
    $this
      ->assertText($title, 'Menu link was added');
    $item = db_query('SELECT * FROM {menu_links} WHERE link_title = :title', array(
      ':title' => $title,
    ))
      ->fetchAssoc();
    return $item;
  }
}
class MemCacheStatisticsTestCase extends MemcacheTestCase {
  public static function getInfo() {
    return array(
      'name' => 'Statistics tests',
      'description' => 'Test that statistics are being recorded appropriately.',
      'group' => 'Memcache',
    );
  }
  function setUp() {
    parent::setUp('memcache_admin');
    $conf['cache_default_class'] = 'MemCacheDrupal';
    $conf['cache_class_cache_form'] = 'DrupalDatabaseCache';
  }
  
  function testBootstrapStatistics() {
    global $_memcache_statistics;
    
    $test_full_key = dmemcache_key($this->default_cid, $this->default_bin);
    $expected_statistic_set[] = array(
      'set',
      $this->default_bin,
      $test_full_key,
      '',
    );
    $expected_statistic_get[] = array(
      'get',
      $this->default_bin,
      $test_full_key,
      1,
    );
    
    $cache_bootstrap_cids = array(
      'variables',
      'bootstrap_modules',
      'lookup_cache',
      'system_list',
      'module_implements',
    );
    
    variable_set('show_memcache_statistics', TRUE);
    drupal_static_reset('dmemcache_collect_stats');
    $this
      ->drupalGet('<front>');
    
    $this
      ->assertNoRaw('<div id="memcache-devel">', 'Statistics not present.');
    
    $account = $this
      ->drupalCreateUser();
    $this
      ->drupalLogin($account);
    
    $this
      ->assertNoRaw('<div id="memcache-devel">', 'Statistics not present.');
    
    $account = $this
      ->drupalCreateUser(array(
      'access memcache statistics',
    ));
    $this
      ->drupalLogin($account);
    $this
      ->drupalGet('<front>');
    
    foreach ($cache_bootstrap_cids as $stat) {
      $key = $GLOBALS['drupal_test_info']['test_run_id'] . 'cache_bootstrap-' . $stat;
      $this
        ->assertRaw("<td>get</td><td>cache_bootstrap</td><td>{$key}</td>", t('Key @key found.', array(
        '@key' => $key,
      )));
    }
    
    foreach ($cache_bootstrap_cids as $stat) {
      _cache_get_object('cache_bootstrap')
        ->clear($stat);
    }
    $this
      ->drupalGet('<front>');
    
    foreach ($cache_bootstrap_cids as $stat) {
      $key = $GLOBALS['drupal_test_info']['test_run_id'] . 'cache_bootstrap-' . $stat;
      $this
        ->assertRaw("<td>get</td><td>cache_bootstrap</td><td>{$key}</td>", t('Key @key found (get).', array(
        '@key' => $key,
      )));
      $this
        ->assertRaw("<td>set</td><td>cache_bootstrap</td><td>{$key}</td>", t('Key @key found (set).', array(
        '@key' => $key,
      )));
    }
    
    $_memcache_statistics = array();
    
    cache_set($this->default_cid, $this->default_value, $this->default_bin);
    $this
      ->assertEqual($_memcache_statistics, $expected_statistic_set);
    
    $_memcache_statistics = array();
    
    cache_get($this->default_cid, $this->default_bin);
    $this
      ->assertEqual($_memcache_statistics, $expected_statistic_get);
    
    variable_set('show_memcache_statistics', FALSE);
    drupal_static_reset('dmemcache_collect_stats');
    $this
      ->drupalGet('<front>');
    
    $this
      ->assertNoRaw('<div id="memcache-devel">', 'Statistics not present.');
    
    $_memcache_statistics = array();
    
    cache_set($this->default_cid, $this->default_value, $this->default_bin);
    $this
      ->assertEqual($_memcache_statistics, array());
    
    $_memcache_statistics = array();
    
    cache_get($this->default_cid, $this->default_bin);
    $this
      ->assertEqual($_memcache_statistics, array());
  }
}