Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  namespace core_cache;
  18  
  19  use cache;
  20  use cache_application;
  21  use cache_config;
  22  use cache_config_disabled;
  23  use cache_config_testing;
  24  use cache_definition;
  25  use cache_disabled;
  26  use cache_factory;
  27  use cache_factory_disabled;
  28  use cache_helper;
  29  use cache_loader;
  30  use cache_phpunit_application;
  31  use cache_phpunit_cache;
  32  use cache_phpunit_dummy_object;
  33  use cache_phpunit_dummy_overrideclass;
  34  use cache_phpunit_factory;
  35  use cache_phpunit_request;
  36  use cache_phpunit_session;
  37  use cache_request;
  38  use cache_session;
  39  use cache_store;
  40  use cacheable_object_array;
  41  
  42  defined('MOODLE_INTERNAL') || die();
  43  
  44  // Include the necessary evils.
  45  global $CFG;
  46  require_once($CFG->dirroot.'/cache/locallib.php');
  47  require_once($CFG->dirroot.'/cache/tests/fixtures/lib.php');
  48  
  49  /**
  50   * PHPunit tests for the cache API
  51   *
  52   * This file is part of Moodle's cache API, affectionately called MUC.
  53   * It contains the components that are requried in order to use caching.
  54   *
  55   * @package    core
  56   * @category   cache
  57   * @copyright  2012 Sam Hemelryk
  58   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  59   */
  60  class cache_test extends \advanced_testcase {
  61  
  62      /**
  63       * Set things back to the default before each test.
  64       */
  65      public function setUp(): void {
  66          parent::setUp();
  67          cache_factory::reset();
  68          cache_config_testing::create_default_configuration();
  69      }
  70  
  71      /**
  72       * Final task is to reset the cache system
  73       */
  74      public static function tearDownAfterClass(): void {
  75          parent::tearDownAfterClass();
  76          cache_factory::reset();
  77      }
  78  
  79      /**
  80       * Returns the expected application cache store.
  81       * @return string
  82       */
  83      protected function get_expected_application_cache_store() {
  84          global $CFG;
  85          $expected = 'cachestore_file';
  86  
  87          // Verify if we are using any of the available ways to use a different application store within tests.
  88          if (defined('TEST_CACHE_USING_APPLICATION_STORE') && preg_match('#[a-zA-Z][a-zA-Z0-9_]*#', TEST_CACHE_USING_APPLICATION_STORE)) {
  89              // 1st way. Using some of the testing servers.
  90              $expected = 'cachestore_'.(string)TEST_CACHE_USING_APPLICATION_STORE;
  91  
  92          } else if (defined('TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH') && TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH && !empty($CFG->altcacheconfigpath)) {
  93              // 2nd way. Using an alternative configuration.
  94              $defaultstores = cache_helper::get_stores_suitable_for_mode_default();
  95              $instance = cache_config::instance();
  96              // Iterate over defined mode mappings until we get an application one not being the default.
  97              foreach ($instance->get_mode_mappings() as $mapping) {
  98                  // If the store is not for application mode, ignore.
  99                  if ($mapping['mode'] !== cache_store::MODE_APPLICATION) {
 100                      continue;
 101                  }
 102                  // If the store matches some default mapping store name, ignore.
 103                  if (array_key_exists($mapping['store'], $defaultstores) && !empty($defaultstores[$mapping['store']]['default'])) {
 104                      continue;
 105                  }
 106                  // Arrived here, have found an application mode store not being the default mapped one (file),
 107                  // that's the one we are using in the configuration for sure.
 108                  $expected = 'cachestore_'.$mapping['store'];
 109              }
 110          }
 111  
 112          return $expected;
 113      }
 114  
 115      /**
 116       * Tests cache configuration
 117       */
 118      public function test_cache_config() {
 119          global $CFG;
 120  
 121          if (defined('TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH') && TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH &&
 122              !empty($CFG->altcacheconfigpath)) {
 123              // We need to skip this test - it checks the default config structure, but very likely we arn't using the
 124              // default config structure here so theres no point in running the test.
 125              $this->markTestSkipped('Skipped testing default cache config structure as alt cache path is being used.');
 126          }
 127  
 128          if (defined('TEST_CACHE_USING_APPLICATION_STORE')) {
 129              // We need to skip this test - it checks the default config structure, but very likely we arn't using the
 130              // default config structure here because we are testing against an alternative application store.
 131              $this->markTestSkipped('Skipped testing default cache config structure as alt application store is being used.');
 132          }
 133  
 134          $instance = cache_config::instance();
 135          $this->assertInstanceOf(cache_config_testing::class, $instance);
 136  
 137          $this->assertTrue(cache_config_testing::config_file_exists());
 138  
 139          $stores = $instance->get_all_stores();
 140          $this->assertCount(3, $stores);
 141          foreach ($stores as $name => $store) {
 142              // Check its an array.
 143              $this->assertIsArray($store);
 144              // Check the name is the key.
 145              $this->assertEquals($name, $store['name']);
 146              // Check that it has been declared default.
 147              $this->assertTrue($store['default']);
 148              // Required attributes = name + plugin + configuration + modes + features.
 149              $this->assertArrayHasKey('name', $store);
 150              $this->assertArrayHasKey('plugin', $store);
 151              $this->assertArrayHasKey('configuration', $store);
 152              $this->assertArrayHasKey('modes', $store);
 153              $this->assertArrayHasKey('features', $store);
 154          }
 155  
 156          $modemappings = $instance->get_mode_mappings();
 157          $this->assertCount(3, $modemappings);
 158          $modes = array(
 159              cache_store::MODE_APPLICATION => false,
 160              cache_store::MODE_SESSION => false,
 161              cache_store::MODE_REQUEST => false,
 162          );
 163          foreach ($modemappings as $mapping) {
 164              // We expect 3 properties.
 165              $this->assertCount(3, $mapping);
 166              // Required attributes = mode + store.
 167              $this->assertArrayHasKey('mode', $mapping);
 168              $this->assertArrayHasKey('store', $mapping);
 169              // Record the mode.
 170              $modes[$mapping['mode']] = true;
 171          }
 172  
 173          // Must have the default 3 modes and no more.
 174          $this->assertCount(3, $mapping);
 175          foreach ($modes as $mode) {
 176              $this->assertTrue($mode);
 177          }
 178  
 179          $definitions = $instance->get_definitions();
 180          // The event invalidation definition is required for the cache API and must be there.
 181          $this->assertArrayHasKey('core/eventinvalidation', $definitions);
 182  
 183          $definitionmappings = $instance->get_definition_mappings();
 184          foreach ($definitionmappings as $mapping) {
 185              // Required attributes = definition + store.
 186              $this->assertArrayHasKey('definition', $mapping);
 187              $this->assertArrayHasKey('store', $mapping);
 188          }
 189      }
 190  
 191      /**
 192       * Tests for cache keys that would break on windows.
 193       */
 194      public function test_windows_nasty_keys() {
 195          $instance = cache_config_testing::instance();
 196          $instance->phpunit_add_definition('phpunit/windowskeytest', array(
 197              'mode' => cache_store::MODE_APPLICATION,
 198              'component' => 'phpunit',
 199              'area' => 'windowskeytest',
 200              'simplekeys' => true,
 201              'simpledata' => true
 202          ));
 203          $cache = cache::make('phpunit', 'windowskeytest');
 204          $this->assertTrue($cache->set('contest', 'test data 1'));
 205          $this->assertEquals('test data 1', $cache->get('contest'));
 206      }
 207  
 208      /**
 209       * Tests set_identifiers fails post cache creation.
 210       *
 211       * set_identifiers cannot be called after initial cache instantiation, as you need to create a difference cache.
 212       */
 213      public function test_set_identifiers() {
 214          $instance = cache_config_testing::instance();
 215          $instance->phpunit_add_definition('phpunit/identifier', array(
 216              'mode' => cache_store::MODE_APPLICATION,
 217              'component' => 'phpunit',
 218              'area' => 'identifier',
 219              'simplekeys' => true,
 220              'simpledata' => true,
 221              'staticacceleration' => true
 222          ));
 223          $cache = cache::make('phpunit', 'identifier', array('area'));
 224          $this->assertTrue($cache->set('contest', 'test data 1'));
 225          $this->assertEquals('test data 1', $cache->get('contest'));
 226  
 227          $this->expectException('coding_exception');
 228          $cache->set_identifiers(array());
 229      }
 230  
 231      /**
 232       * Tests the default application cache
 233       */
 234      public function test_default_application_cache() {
 235          $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'phpunit', 'applicationtest');
 236          $this->assertInstanceOf(cache_application::class, $cache);
 237          $this->run_on_cache($cache);
 238  
 239          $instance = cache_config_testing::instance(true);
 240          $instance->phpunit_add_definition('phpunit/test_default_application_cache', array(
 241              'mode' => cache_store::MODE_APPLICATION,
 242              'component' => 'phpunit',
 243              'area' => 'test_default_application_cache',
 244              'staticacceleration' => true,
 245              'staticaccelerationsize' => 1
 246          ));
 247          $cache = cache::make('phpunit', 'test_default_application_cache');
 248          $this->assertInstanceOf(cache_application::class, $cache);
 249          $this->run_on_cache($cache);
 250      }
 251  
 252      /**
 253       * Tests the default session cache
 254       */
 255      public function test_default_session_cache() {
 256          $cache = cache::make_from_params(cache_store::MODE_SESSION, 'phpunit', 'applicationtest');
 257          $this->assertInstanceOf(cache_session::class, $cache);
 258          $this->run_on_cache($cache);
 259      }
 260  
 261      /**
 262       * Tests the default request cache
 263       */
 264      public function test_default_request_cache() {
 265          $cache = cache::make_from_params(cache_store::MODE_REQUEST, 'phpunit', 'applicationtest');
 266          $this->assertInstanceOf(cache_request::class, $cache);
 267          $this->run_on_cache($cache);
 268      }
 269  
 270      /**
 271       * Tests using a cache system when there are no stores available (who knows what the admin did to achieve this).
 272       */
 273      public function test_on_cache_without_store() {
 274          $instance = cache_config_testing::instance(true);
 275          $instance->phpunit_add_definition('phpunit/nostoretest1', array(
 276              'mode' => cache_store::MODE_APPLICATION,
 277              'component' => 'phpunit',
 278              'area' => 'nostoretest1',
 279          ));
 280          $instance->phpunit_add_definition('phpunit/nostoretest2', array(
 281              'mode' => cache_store::MODE_APPLICATION,
 282              'component' => 'phpunit',
 283              'area' => 'nostoretest2',
 284              'staticacceleration' => true
 285          ));
 286          $instance->phpunit_remove_stores();
 287  
 288          $cache = cache::make('phpunit', 'nostoretest1');
 289          $this->run_on_cache($cache);
 290  
 291          $cache = cache::make('phpunit', 'nostoretest2');
 292          $this->run_on_cache($cache);
 293      }
 294  
 295      /**
 296       * Runs a standard series of access and use tests on a cache instance.
 297       *
 298       * This function is great because we can use it to ensure all of the loaders perform exactly the same way.
 299       *
 300       * @param cache_loader $cache
 301       */
 302      protected function run_on_cache(cache_loader $cache) {
 303          $key = 'contestkey';
 304          $datascalars = array('test data', null);
 305          $dataarray = array('contest' => 'data', 'part' => 'two');
 306          $dataobject = (object)$dataarray;
 307  
 308          foreach ($datascalars as $datascalar) {
 309              $this->assertTrue($cache->purge());
 310  
 311              // Check all read methods.
 312              $this->assertFalse($cache->get($key));
 313              $this->assertFalse($cache->has($key));
 314              $result = $cache->get_many(array($key));
 315              $this->assertCount(1, $result);
 316              $this->assertFalse(reset($result));
 317              $this->assertFalse($cache->has_any(array($key)));
 318              $this->assertFalse($cache->has_all(array($key)));
 319  
 320              // Set the data.
 321              $this->assertTrue($cache->set($key, $datascalar));
 322              // Setting it more than once should be permitted.
 323              $this->assertTrue($cache->set($key, $datascalar));
 324  
 325              // Recheck the read methods.
 326              $this->assertEquals($datascalar, $cache->get($key));
 327              $this->assertTrue($cache->has($key));
 328              $result = $cache->get_many(array($key));
 329              $this->assertCount(1, $result);
 330              $this->assertEquals($datascalar, reset($result));
 331              $this->assertTrue($cache->has_any(array($key)));
 332              $this->assertTrue($cache->has_all(array($key)));
 333  
 334              // Delete it.
 335              $this->assertTrue($cache->delete($key));
 336  
 337              // Check its gone.
 338              $this->assertFalse($cache->get($key));
 339              $this->assertFalse($cache->has($key));
 340          }
 341  
 342          // Test arrays.
 343          $this->assertTrue($cache->set($key, $dataarray));
 344          $this->assertEquals($dataarray, $cache->get($key));
 345  
 346          // Test objects.
 347          $this->assertTrue($cache->set($key, $dataobject));
 348          $this->assertEquals($dataobject, $cache->get($key));
 349  
 350          $starttime = microtime(true);
 351          $specobject = new cache_phpunit_dummy_object('red', 'blue', $starttime);
 352          $this->assertTrue($cache->set($key, $specobject));
 353          $result = $cache->get($key);
 354          $this->assertInstanceOf(cache_phpunit_dummy_object::class, $result);
 355          $this->assertEquals('red_ptc_wfc', $result->property1);
 356          $this->assertEquals('blue_ptc_wfc', $result->property2);
 357          $this->assertGreaterThan($starttime, $result->propertytime);
 358  
 359          // Test array of objects.
 360          $specobject = new cache_phpunit_dummy_object('red', 'blue', $starttime);
 361          $data = new cacheable_object_array(array(
 362              clone($specobject),
 363              clone($specobject),
 364              clone($specobject))
 365          );
 366          $this->assertTrue($cache->set($key, $data));
 367          $result = $cache->get($key);
 368          $this->assertInstanceOf(cacheable_object_array::class, $result);
 369          $this->assertCount(3, $data);
 370          foreach ($result as $item) {
 371              $this->assertInstanceOf(cache_phpunit_dummy_object::class, $item);
 372              $this->assertEquals('red_ptc_wfc', $item->property1);
 373              $this->assertEquals('blue_ptc_wfc', $item->property2);
 374              // Ensure that wake from cache is called in all cases.
 375              $this->assertGreaterThan($starttime, $item->propertytime);
 376          }
 377  
 378          // Test set many.
 379          $cache->set_many(array('key1' => 'data1', 'key2' => 'data2', 'key3' => null));
 380          $this->assertEquals('data1', $cache->get('key1'));
 381          $this->assertEquals('data2', $cache->get('key2'));
 382          $this->assertEquals(null, $cache->get('key3'));
 383          $this->assertTrue($cache->delete('key1'));
 384          $this->assertTrue($cache->delete('key2'));
 385          $this->assertTrue($cache->delete('key3'));
 386  
 387          $cache->set_many(array(
 388              'key1' => array(1, 2, 3),
 389              'key2' => array(3, 2, 1),
 390          ));
 391          $this->assertIsArray($cache->get('key1'));
 392          $this->assertIsArray($cache->get('key2'));
 393          $this->assertCount(3, $cache->get('key1'));
 394          $this->assertCount(3, $cache->get('key2'));
 395          $this->assertIsArray($cache->get_many(array('key1', 'key2')));
 396          $this->assertCount(2, $cache->get_many(array('key1', 'key2')));
 397          $this->assertEquals(2, $cache->delete_many(array('key1', 'key2')));
 398  
 399          // Test delete many.
 400          $this->assertTrue($cache->set('key1', 'data1'));
 401          $this->assertTrue($cache->set('key2', 'data2'));
 402          $this->assertTrue($cache->set('key3', null));
 403  
 404          $this->assertEquals('data1', $cache->get('key1'));
 405          $this->assertEquals('data2', $cache->get('key2'));
 406          $this->assertEquals(null, $cache->get('key3'));
 407  
 408          $this->assertEquals(3, $cache->delete_many(array('key1', 'key2', 'key3')));
 409  
 410          $this->assertFalse($cache->get('key1'));
 411          $this->assertFalse($cache->get('key2'));
 412          $this->assertFalse($cache->get('key3'));
 413  
 414          // Quick reference test.
 415          $obj = new \stdClass;
 416          $obj->key = 'value';
 417          $ref =& $obj;
 418          $this->assertTrue($cache->set('obj', $obj));
 419  
 420          $obj->key = 'eulav';
 421          $var = $cache->get('obj');
 422          $this->assertInstanceOf(\stdClass::class, $var);
 423          $this->assertEquals('value', $var->key);
 424  
 425          $ref->key = 'eulav';
 426          $var = $cache->get('obj');
 427          $this->assertInstanceOf(\stdClass::class, $var);
 428          $this->assertEquals('value', $var->key);
 429  
 430          $this->assertTrue($cache->delete('obj'));
 431  
 432          // Deep reference test.
 433          $obj1 = new \stdClass;
 434          $obj1->key = 'value';
 435          $obj2 = new \stdClass;
 436          $obj2->key = 'test';
 437          $obj3 = new \stdClass;
 438          $obj3->key = 'pork';
 439          $obj1->subobj =& $obj2;
 440          $obj2->subobj =& $obj3;
 441          $this->assertTrue($cache->set('obj', $obj1));
 442  
 443          $obj1->key = 'eulav';
 444          $obj2->key = 'tset';
 445          $obj3->key = 'krop';
 446          $var = $cache->get('obj');
 447          $this->assertInstanceOf(\stdClass::class, $var);
 448          $this->assertEquals('value', $var->key);
 449          $this->assertInstanceOf(\stdClass::class, $var->subobj);
 450          $this->assertEquals('test', $var->subobj->key);
 451          $this->assertInstanceOf(\stdClass::class, $var->subobj->subobj);
 452          $this->assertEquals('pork', $var->subobj->subobj->key);
 453          $this->assertTrue($cache->delete('obj'));
 454  
 455          // Death reference test... basically we don't want this to die.
 456          $obj = new \stdClass;
 457          $obj->key = 'value';
 458          $obj->self =& $obj;
 459          $this->assertTrue($cache->set('obj', $obj));
 460          $var = $cache->get('obj');
 461          $this->assertInstanceOf(\stdClass::class, $var);
 462          $this->assertEquals('value', $var->key);
 463  
 464          // Reference test after retrieve.
 465          $obj = new \stdClass;
 466          $obj->key = 'value';
 467          $this->assertTrue($cache->set('obj', $obj));
 468  
 469          $var1 = $cache->get('obj');
 470          $this->assertInstanceOf(\stdClass::class, $var1);
 471          $this->assertEquals('value', $var1->key);
 472          $var1->key = 'eulav';
 473          $this->assertEquals('eulav', $var1->key);
 474  
 475          $var2 = $cache->get('obj');
 476          $this->assertInstanceOf(\stdClass::class, $var2);
 477          $this->assertEquals('value', $var2->key);
 478  
 479          $this->assertTrue($cache->delete('obj'));
 480  
 481          // Death reference test on get_many... basically we don't want this to die.
 482          $obj = new \stdClass;
 483          $obj->key = 'value';
 484          $obj->self =& $obj;
 485          $this->assertEquals(1, $cache->set_many(array('obj' => $obj)));
 486          $var = $cache->get_many(array('obj'));
 487          $this->assertInstanceOf(\stdClass::class, $var['obj']);
 488          $this->assertEquals('value', $var['obj']->key);
 489  
 490          // Reference test after retrieve.
 491          $obj = new \stdClass;
 492          $obj->key = 'value';
 493          $this->assertEquals(1, $cache->set_many(array('obj' => $obj)));
 494  
 495          $var1 = $cache->get_many(array('obj'));
 496          $this->assertInstanceOf(\stdClass::class, $var1['obj']);
 497          $this->assertEquals('value', $var1['obj']->key);
 498          $var1['obj']->key = 'eulav';
 499          $this->assertEquals('eulav', $var1['obj']->key);
 500  
 501          $var2 = $cache->get_many(array('obj'));
 502          $this->assertInstanceOf(\stdClass::class, $var2['obj']);
 503          $this->assertEquals('value', $var2['obj']->key);
 504  
 505          $this->assertTrue($cache->delete('obj'));
 506  
 507          // Test strictness exceptions.
 508          try {
 509              $cache->get('exception', MUST_EXIST);
 510              $this->fail('Exception expected from cache::get using MUST_EXIST');
 511          } catch (\Exception $e) {
 512              $this->assertTrue(true);
 513          }
 514          try {
 515              $cache->get_many(array('exception1', 'exception2'), MUST_EXIST);
 516              $this->fail('Exception expected from cache::get_many using MUST_EXIST');
 517          } catch (\Exception $e) {
 518              $this->assertTrue(true);
 519          }
 520          $cache->set('test', 'test');
 521          try {
 522              $cache->get_many(array('test', 'exception'), MUST_EXIST);
 523              $this->fail('Exception expected from cache::get_many using MUST_EXIST');
 524          } catch (\Exception $e) {
 525              $this->assertTrue(true);
 526          }
 527      }
 528  
 529      /**
 530       * Tests a definition using a data loader
 531       */
 532      public function test_definition_data_loader() {
 533          $instance = cache_config_testing::instance(true);
 534          $instance->phpunit_add_definition('phpunit/datasourcetest', array(
 535              'mode' => cache_store::MODE_APPLICATION,
 536              'component' => 'phpunit',
 537              'area' => 'datasourcetest',
 538              'datasource' => 'cache_phpunit_dummy_datasource',
 539              'datasourcefile' => 'cache/tests/fixtures/lib.php'
 540          ));
 541  
 542          $cache = cache::make('phpunit', 'datasourcetest');
 543          $this->assertInstanceOf(cache_application::class, $cache);
 544  
 545          // Purge it to be sure.
 546          $this->assertTrue($cache->purge());
 547          // It won't be there yet.
 548          $this->assertFalse($cache->has('Test'));
 549          // It should load it ;).
 550          $this->assertTrue($cache->has('Test', true));
 551  
 552          // Purge it to be sure.
 553          $this->assertTrue($cache->purge());
 554          $this->assertEquals('Test has no value really.', $cache->get('Test'));
 555  
 556          // Test multiple values.
 557          $this->assertTrue($cache->purge());
 558          $this->assertTrue($cache->set('b', 'B'));
 559          $result = $cache->get_many(array('a', 'b', 'c'));
 560          $this->assertIsArray($result);
 561          $this->assertCount(3, $result);
 562          $this->assertArrayHasKey('a', $result);
 563          $this->assertArrayHasKey('b', $result);
 564          $this->assertArrayHasKey('c', $result);
 565          $this->assertEquals('a has no value really.', $result['a']);
 566          $this->assertEquals('B', $result['b']);
 567          $this->assertEquals('c has no value really.', $result['c']);
 568      }
 569  
 570      /**
 571       * Tests a definition using an overridden loader
 572       */
 573      public function test_definition_overridden_loader() {
 574          $instance = cache_config_testing::instance(true);
 575          $instance->phpunit_add_definition('phpunit/overridetest', array(
 576              'mode' => cache_store::MODE_APPLICATION,
 577              'component' => 'phpunit',
 578              'area' => 'overridetest',
 579              'overrideclass' => 'cache_phpunit_dummy_overrideclass',
 580              'overrideclassfile' => 'cache/tests/fixtures/lib.php'
 581          ));
 582          $cache = cache::make('phpunit', 'overridetest');
 583          $this->assertInstanceOf(cache_phpunit_dummy_overrideclass::class, $cache);
 584          $this->assertInstanceOf(cache_application::class, $cache);
 585          // Purge it to be sure.
 586          $this->assertTrue($cache->purge());
 587          // It won't be there yet.
 588          $this->assertFalse($cache->has('Test'));
 589          // Add it.
 590          $this->assertTrue($cache->set('Test', 'Test has no value really.'));
 591          // Check its there.
 592          $this->assertEquals('Test has no value really.', $cache->get('Test'));
 593      }
 594  
 595      /**
 596       * Test the mappingsonly setting.
 597       */
 598      public function test_definition_mappings_only() {
 599          /** @var cache_config_testing $instance */
 600          $instance = cache_config_testing::instance(true);
 601          $instance->phpunit_add_definition('phpunit/mappingsonly', array(
 602              'mode' => cache_store::MODE_APPLICATION,
 603              'component' => 'phpunit',
 604              'area' => 'mappingsonly',
 605              'mappingsonly' => true
 606          ), false);
 607          $instance->phpunit_add_definition('phpunit/nonmappingsonly', array(
 608              'mode' => cache_store::MODE_APPLICATION,
 609              'component' => 'phpunit',
 610              'area' => 'nonmappingsonly',
 611              'mappingsonly' => false
 612          ), false);
 613  
 614          $cacheonly = cache::make('phpunit', 'mappingsonly');
 615          $this->assertInstanceOf(cache_application::class, $cacheonly);
 616          $this->assertEquals('cachestore_dummy', $cacheonly->phpunit_get_store_class());
 617  
 618          $expected = $this->get_expected_application_cache_store();
 619          $cachenon = cache::make('phpunit', 'nonmappingsonly');
 620          $this->assertInstanceOf(cache_application::class, $cachenon);
 621          $this->assertEquals($expected, $cachenon->phpunit_get_store_class());
 622      }
 623  
 624      /**
 625       * Test a very basic definition.
 626       */
 627      public function test_definition() {
 628          $instance = cache_config_testing::instance();
 629          $instance->phpunit_add_definition('phpunit/test', array(
 630              'mode' => cache_store::MODE_APPLICATION,
 631              'component' => 'phpunit',
 632              'area' => 'test',
 633          ));
 634          $cache = cache::make('phpunit', 'test');
 635  
 636          $this->assertTrue($cache->set('testkey1', 'test data 1'));
 637          $this->assertEquals('test data 1', $cache->get('testkey1'));
 638          $this->assertTrue($cache->set('testkey2', 'test data 2'));
 639          $this->assertEquals('test data 2', $cache->get('testkey2'));
 640      }
 641  
 642      /**
 643       * Test a definition using the simple keys.
 644       */
 645      public function test_definition_simplekeys() {
 646          $instance = cache_config_testing::instance();
 647          $instance->phpunit_add_definition('phpunit/simplekeytest', array(
 648              'mode' => cache_store::MODE_APPLICATION,
 649              'component' => 'phpunit',
 650              'area' => 'simplekeytest',
 651              'simplekeys' => true
 652          ));
 653          $cache = cache::make('phpunit', 'simplekeytest');
 654  
 655          $this->assertTrue($cache->set('testkey1', 'test data 1'));
 656          $this->assertEquals('test data 1', $cache->get('testkey1'));
 657          $this->assertTrue($cache->set('testkey2', 'test data 2'));
 658          $this->assertEquals('test data 2', $cache->get('testkey2'));
 659  
 660          $cache->purge();
 661  
 662          $this->assertTrue($cache->set('1', 'test data 1'));
 663          $this->assertEquals('test data 1', $cache->get('1'));
 664          $this->assertTrue($cache->set('2', 'test data 2'));
 665          $this->assertEquals('test data 2', $cache->get('2'));
 666      }
 667  
 668      /**
 669       * Test a negative TTL on an application cache.
 670       */
 671      public function test_application_ttl_negative() {
 672          $instance = cache_config_testing::instance(true);
 673          $instance->phpunit_add_definition('phpunit/ttltest', array(
 674              'mode' => cache_store::MODE_APPLICATION,
 675              'component' => 'phpunit',
 676              'area' => 'ttltest',
 677              'ttl' => -86400 // Set to a day in the past to be extra sure.
 678          ));
 679          $cache = cache::make('phpunit', 'ttltest');
 680          $this->assertInstanceOf(cache_application::class, $cache);
 681  
 682          // Purge it to be sure.
 683          $this->assertTrue($cache->purge());
 684          // It won't be there yet.
 685          $this->assertFalse($cache->has('Test'));
 686          // Set it now.
 687          $this->assertTrue($cache->set('Test', 'Test'));
 688          // Check its not there.
 689          $this->assertFalse($cache->has('Test'));
 690          // Double check by trying to get it.
 691          $this->assertFalse($cache->get('Test'));
 692  
 693          // Test with multiple keys.
 694          $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C')));
 695          $result = $cache->get_many(array('a', 'b', 'c'));
 696          $this->assertIsArray($result);
 697          $this->assertCount(3, $result);
 698          $this->assertArrayHasKey('a', $result);
 699          $this->assertArrayHasKey('b', $result);
 700          $this->assertArrayHasKey('c', $result);
 701          $this->assertFalse($result['a']);
 702          $this->assertFalse($result['b']);
 703          $this->assertFalse($result['c']);
 704  
 705          // Test with multiple keys including missing ones.
 706          $result = $cache->get_many(array('a', 'c', 'e'));
 707          $this->assertIsArray($result);
 708          $this->assertCount(3, $result);
 709          $this->assertArrayHasKey('a', $result);
 710          $this->assertArrayHasKey('c', $result);
 711          $this->assertArrayHasKey('e', $result);
 712          $this->assertFalse($result['a']);
 713          $this->assertFalse($result['c']);
 714          $this->assertFalse($result['e']);
 715      }
 716  
 717      /**
 718       * Test a positive TTL on an application cache.
 719       */
 720      public function test_application_ttl_positive() {
 721          $instance = cache_config_testing::instance(true);
 722          $instance->phpunit_add_definition('phpunit/ttltest', array(
 723              'mode' => cache_store::MODE_APPLICATION,
 724              'component' => 'phpunit',
 725              'area' => 'ttltest',
 726              'ttl' => 86400 // Set to a day in the future to be extra sure.
 727          ));
 728          $cache = cache::make('phpunit', 'ttltest');
 729          $this->assertInstanceOf(cache_application::class, $cache);
 730  
 731          // Purge it to be sure.
 732          $this->assertTrue($cache->purge());
 733          // It won't be there yet.
 734          $this->assertFalse($cache->has('Test'));
 735          // Set it now.
 736          $this->assertTrue($cache->set('Test', 'Test'));
 737          // Check its there.
 738          $this->assertTrue($cache->has('Test'));
 739          // Double check by trying to get it.
 740          $this->assertEquals('Test', $cache->get('Test'));
 741  
 742          // Test with multiple keys.
 743          $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C')));
 744          $result = $cache->get_many(array('a', 'b', 'c'));
 745          $this->assertIsArray($result);
 746          $this->assertCount(3, $result);
 747          $this->assertArrayHasKey('a', $result);
 748          $this->assertArrayHasKey('b', $result);
 749          $this->assertArrayHasKey('c', $result);
 750          $this->assertEquals('A', $result['a']);
 751          $this->assertEquals('B', $result['b']);
 752          $this->assertEquals('C', $result['c']);
 753  
 754          // Test with multiple keys including missing ones.
 755          $result = $cache->get_many(array('a', 'c', 'e'));
 756          $this->assertIsArray($result);
 757          $this->assertCount(3, $result);
 758          $this->assertArrayHasKey('a', $result);
 759          $this->assertArrayHasKey('c', $result);
 760          $this->assertArrayHasKey('e', $result);
 761          $this->assertEquals('A', $result['a']);
 762          $this->assertEquals('C', $result['c']);
 763          $this->assertEquals(false, $result['e']);
 764      }
 765  
 766      /**
 767       * Test a negative TTL on an session cache.
 768       */
 769      public function test_session_ttl_positive() {
 770          $instance = cache_config_testing::instance(true);
 771          $instance->phpunit_add_definition('phpunit/ttltest', array(
 772              'mode' => cache_store::MODE_SESSION,
 773              'component' => 'phpunit',
 774              'area' => 'ttltest',
 775              'ttl' => 86400 // Set to a day in the future to be extra sure.
 776          ));
 777          $cache = cache::make('phpunit', 'ttltest');
 778          $this->assertInstanceOf(cache_session::class, $cache);
 779  
 780          // Purge it to be sure.
 781          $this->assertTrue($cache->purge());
 782          // It won't be there yet.
 783          $this->assertFalse($cache->has('Test'));
 784          // Set it now.
 785          $this->assertTrue($cache->set('Test', 'Test'));
 786          // Check its there.
 787          $this->assertTrue($cache->has('Test'));
 788          // Double check by trying to get it.
 789          $this->assertEquals('Test', $cache->get('Test'));
 790  
 791          // Test with multiple keys.
 792          $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C')));
 793          $result = $cache->get_many(array('a', 'b', 'c'));
 794          $this->assertIsArray($result);
 795          $this->assertCount(3, $result);
 796          $this->assertArrayHasKey('a', $result);
 797          $this->assertArrayHasKey('b', $result);
 798          $this->assertArrayHasKey('c', $result);
 799          $this->assertEquals('A', $result['a']);
 800          $this->assertEquals('B', $result['b']);
 801          $this->assertEquals('C', $result['c']);
 802  
 803          // Test with multiple keys including missing ones.
 804          $result = $cache->get_many(array('a', 'c', 'e'));
 805          $this->assertIsArray($result);
 806          $this->assertCount(3, $result);
 807          $this->assertArrayHasKey('a', $result);
 808          $this->assertArrayHasKey('c', $result);
 809          $this->assertArrayHasKey('e', $result);
 810          $this->assertEquals('A', $result['a']);
 811          $this->assertEquals('C', $result['c']);
 812          $this->assertEquals(false, $result['e']);
 813      }
 814  
 815      /**
 816       * Tests manual locking operations on an application cache
 817       */
 818      public function test_application_manual_locking() {
 819          $instance = cache_config_testing::instance();
 820          $instance->phpunit_add_definition('phpunit/lockingtest', array(
 821              'mode' => cache_store::MODE_APPLICATION,
 822              'component' => 'phpunit',
 823              'area' => 'lockingtest'
 824          ));
 825          $cache1 = cache::make('phpunit', 'lockingtest');
 826          $cache2 = clone($cache1);
 827  
 828          $this->assertTrue($cache1->set('testkey', 'test data'));
 829          $this->assertTrue($cache2->set('testkey', 'test data'));
 830  
 831          $this->assertTrue($cache1->acquire_lock('testkey'));
 832          $this->assertFalse($cache2->acquire_lock('testkey'));
 833  
 834          $this->assertTrue($cache1->check_lock_state('testkey'));
 835          $this->assertFalse($cache2->check_lock_state('testkey'));
 836  
 837          $this->assertTrue($cache1->release_lock('testkey'));
 838          $this->assertFalse($cache2->release_lock('testkey'));
 839  
 840          $this->assertTrue($cache1->set('testkey', 'test data'));
 841          $this->assertTrue($cache2->set('testkey', 'test data'));
 842      }
 843  
 844      /**
 845       * Tests application cache event invalidation
 846       */
 847      public function test_application_event_invalidation() {
 848          $instance = cache_config_testing::instance();
 849          $instance->phpunit_add_definition('phpunit/eventinvalidationtest', array(
 850              'mode' => cache_store::MODE_APPLICATION,
 851              'component' => 'phpunit',
 852              'area' => 'eventinvalidationtest',
 853              'invalidationevents' => array(
 854                  'crazyevent'
 855              )
 856          ));
 857          $cache = cache::make('phpunit', 'eventinvalidationtest');
 858  
 859          $this->assertTrue($cache->set('testkey1', 'test data 1'));
 860          $this->assertEquals('test data 1', $cache->get('testkey1'));
 861          $this->assertTrue($cache->set('testkey2', 'test data 2'));
 862          $this->assertEquals('test data 2', $cache->get('testkey2'));
 863  
 864          // Test invalidating a single entry.
 865          cache_helper::invalidate_by_event('crazyevent', array('testkey1'));
 866  
 867          $this->assertFalse($cache->get('testkey1'));
 868          $this->assertEquals('test data 2', $cache->get('testkey2'));
 869  
 870          $this->assertTrue($cache->set('testkey1', 'test data 1'));
 871  
 872          // Test invalidating both entries.
 873          cache_helper::invalidate_by_event('crazyevent', array('testkey1', 'testkey2'));
 874  
 875          $this->assertFalse($cache->get('testkey1'));
 876          $this->assertFalse($cache->get('testkey2'));
 877      }
 878  
 879      /**
 880       * Tests session cache event invalidation
 881       */
 882      public function test_session_event_invalidation() {
 883          $instance = cache_config_testing::instance();
 884          $instance->phpunit_add_definition('phpunit/test_session_event_invalidation', array(
 885              'mode' => cache_store::MODE_SESSION,
 886              'component' => 'phpunit',
 887              'area' => 'test_session_event_invalidation',
 888              'invalidationevents' => array(
 889                  'crazyevent'
 890              )
 891          ));
 892          $cache = cache::make('phpunit', 'test_session_event_invalidation');
 893          $this->assertInstanceOf(cache_session::class, $cache);
 894  
 895          $this->assertTrue($cache->set('testkey1', 'test data 1'));
 896          $this->assertEquals('test data 1', $cache->get('testkey1'));
 897          $this->assertTrue($cache->set('testkey2', 'test data 2'));
 898          $this->assertEquals('test data 2', $cache->get('testkey2'));
 899  
 900          // Test invalidating a single entry.
 901          cache_helper::invalidate_by_event('crazyevent', array('testkey1'));
 902  
 903          $this->assertFalse($cache->get('testkey1'));
 904          $this->assertEquals('test data 2', $cache->get('testkey2'));
 905  
 906          $this->assertTrue($cache->set('testkey1', 'test data 1'));
 907  
 908          // Test invalidating both entries.
 909          cache_helper::invalidate_by_event('crazyevent', array('testkey1', 'testkey2'));
 910  
 911          $this->assertFalse($cache->get('testkey1'));
 912          $this->assertFalse($cache->get('testkey2'));
 913      }
 914  
 915      /**
 916       * Tests application cache definition invalidation
 917       */
 918      public function test_application_definition_invalidation() {
 919          $instance = cache_config_testing::instance();
 920          $instance->phpunit_add_definition('phpunit/definitioninvalidation', array(
 921              'mode' => cache_store::MODE_APPLICATION,
 922              'component' => 'phpunit',
 923              'area' => 'definitioninvalidation'
 924          ));
 925          $cache = cache::make('phpunit', 'definitioninvalidation');
 926          $this->assertTrue($cache->set('testkey1', 'test data 1'));
 927          $this->assertEquals('test data 1', $cache->get('testkey1'));
 928          $this->assertTrue($cache->set('testkey2', 'test data 2'));
 929          $this->assertEquals('test data 2', $cache->get('testkey2'));
 930  
 931          cache_helper::invalidate_by_definition('phpunit', 'definitioninvalidation', array(), 'testkey1');
 932  
 933          $this->assertFalse($cache->get('testkey1'));
 934          $this->assertEquals('test data 2', $cache->get('testkey2'));
 935  
 936          $this->assertTrue($cache->set('testkey1', 'test data 1'));
 937  
 938          cache_helper::invalidate_by_definition('phpunit', 'definitioninvalidation', array(), array('testkey1'));
 939  
 940          $this->assertFalse($cache->get('testkey1'));
 941          $this->assertEquals('test data 2', $cache->get('testkey2'));
 942  
 943          $this->assertTrue($cache->set('testkey1', 'test data 1'));
 944  
 945          cache_helper::invalidate_by_definition('phpunit', 'definitioninvalidation', array(), array('testkey1', 'testkey2'));
 946  
 947          $this->assertFalse($cache->get('testkey1'));
 948          $this->assertFalse($cache->get('testkey2'));
 949      }
 950  
 951      /**
 952       * Tests session cache definition invalidation
 953       */
 954      public function test_session_definition_invalidation() {
 955          $instance = cache_config_testing::instance();
 956          $instance->phpunit_add_definition('phpunit/test_session_definition_invalidation', array(
 957              'mode' => cache_store::MODE_SESSION,
 958              'component' => 'phpunit',
 959              'area' => 'test_session_definition_invalidation'
 960          ));
 961          $cache = cache::make('phpunit', 'test_session_definition_invalidation');
 962          $this->assertInstanceOf(cache_session::class, $cache);
 963          $this->assertTrue($cache->set('testkey1', 'test data 1'));
 964          $this->assertEquals('test data 1', $cache->get('testkey1'));
 965          $this->assertTrue($cache->set('testkey2', 'test data 2'));
 966          $this->assertEquals('test data 2', $cache->get('testkey2'));
 967  
 968          cache_helper::invalidate_by_definition('phpunit', 'test_session_definition_invalidation', array(), 'testkey1');
 969  
 970          $this->assertFalse($cache->get('testkey1'));
 971          $this->assertEquals('test data 2', $cache->get('testkey2'));
 972  
 973          $this->assertTrue($cache->set('testkey1', 'test data 1'));
 974  
 975          cache_helper::invalidate_by_definition('phpunit', 'test_session_definition_invalidation', array(),
 976                  array('testkey1'));
 977  
 978          $this->assertFalse($cache->get('testkey1'));
 979          $this->assertEquals('test data 2', $cache->get('testkey2'));
 980  
 981          $this->assertTrue($cache->set('testkey1', 'test data 1'));
 982  
 983          cache_helper::invalidate_by_definition('phpunit', 'test_session_definition_invalidation', array(),
 984                  array('testkey1', 'testkey2'));
 985  
 986          $this->assertFalse($cache->get('testkey1'));
 987          $this->assertFalse($cache->get('testkey2'));
 988      }
 989  
 990      /**
 991       * Tests application cache event invalidation over a distributed setup.
 992       */
 993      public function test_distributed_application_event_invalidation() {
 994          global $CFG;
 995          // This is going to be an intense wee test.
 996          // We need to add data the to cache, invalidate it by event, manually force it back without MUC knowing to simulate a
 997          // disconnected/distributed setup (think load balanced server using local cache), instantiate the cache again and finally
 998          // check that it is not picked up.
 999          $instance = cache_config_testing::instance();
1000          $instance->phpunit_add_definition('phpunit/eventinvalidationtest', array(
1001              'mode' => cache_store::MODE_APPLICATION,
1002              'component' => 'phpunit',
1003              'area' => 'eventinvalidationtest',
1004              'simplekeys' => true,
1005              'simpledata' => true,
1006              'invalidationevents' => array(
1007                  'crazyevent'
1008              )
1009          ));
1010          $cache = cache::make('phpunit', 'eventinvalidationtest');
1011          $this->assertTrue($cache->set('testkey1', 'test data 1'));
1012          $this->assertEquals('test data 1', $cache->get('testkey1'));
1013  
1014          cache_helper::invalidate_by_event('crazyevent', array('testkey1'));
1015  
1016          $this->assertFalse($cache->get('testkey1'));
1017  
1018          // OK data added, data invalidated, and invalidation time has been set.
1019          // Now we need to manually add back the data and adjust the invalidation time.
1020          $hash = md5(cache_store::MODE_APPLICATION.'/phpunit/eventinvalidationtest/'.$CFG->wwwroot.'phpunit');
1021          $timefile = $CFG->dataroot."/cache/cachestore_file/default_application/phpunit_eventinvalidationtest/las-cache/lastinvalidation-$hash.cache";
1022          // Make sure the file is correct.
1023          $this->assertTrue(file_exists($timefile));
1024          $timecont = serialize(cache::now(true) - 60); // Back 60sec in the past to force it to re-invalidate.
1025          make_writable_directory(dirname($timefile));
1026          file_put_contents($timefile, $timecont);
1027          $this->assertTrue(file_exists($timefile));
1028  
1029          $datafile = $CFG->dataroot."/cache/cachestore_file/default_application/phpunit_eventinvalidationtest/tes-cache/testkey1-$hash.cache";
1030          $datacont = serialize("test data 1");
1031          make_writable_directory(dirname($datafile));
1032          file_put_contents($datafile, $datacont);
1033          $this->assertTrue(file_exists($datafile));
1034  
1035          // Test 1: Rebuild without the event and test its there.
1036          cache_factory::reset();
1037          $instance = cache_config_testing::instance();
1038          $instance->phpunit_add_definition('phpunit/eventinvalidationtest', array(
1039              'mode' => cache_store::MODE_APPLICATION,
1040              'component' => 'phpunit',
1041              'area' => 'eventinvalidationtest',
1042              'simplekeys' => true,
1043              'simpledata' => true,
1044          ));
1045          $cache = cache::make('phpunit', 'eventinvalidationtest');
1046          $this->assertEquals('test data 1', $cache->get('testkey1'));
1047  
1048          // Test 2: Rebuild and test the invalidation of the event via the invalidation cache.
1049          cache_factory::reset();
1050  
1051          $instance = cache_config_testing::instance();
1052          $instance->phpunit_add_definition('phpunit/eventinvalidationtest', array(
1053              'mode' => cache_store::MODE_APPLICATION,
1054              'component' => 'phpunit',
1055              'area' => 'eventinvalidationtest',
1056              'simplekeys' => true,
1057              'simpledata' => true,
1058              'invalidationevents' => array(
1059                  'crazyevent'
1060              )
1061          ));
1062  
1063          $cache = cache::make('phpunit', 'eventinvalidationtest');
1064          $this->assertFalse($cache->get('testkey1'));
1065  
1066          // Test 3: Verify that an existing lastinvalidation cache file is updated when needed.
1067  
1068          // Make a new cache class.  This should should invalidate testkey2.
1069          $cache = cache::make('phpunit', 'eventinvalidationtest');
1070  
1071          // Invalidation token should have been reset.
1072          $this->assertEquals(cache::get_purge_token(), $cache->get('lastinvalidation'));
1073  
1074          // Set testkey2 data.
1075          $cache->set('testkey2', 'test data 2');
1076  
1077          // Backdate the event invalidation time by 30 seconds.
1078          $invalidationcache = cache::make('core', 'eventinvalidation');
1079          $invalidationcache->set('crazyevent', array('testkey2' => cache::now() - 30));
1080  
1081          // Lastinvalidation should already be cache::now().
1082          $this->assertEquals(cache::get_purge_token(), $cache->get('lastinvalidation'));
1083  
1084          // Set it to 15 seconds ago so that we know if it changes.
1085          $pasttime = cache::now(true) - 15;
1086          $cache->set('lastinvalidation', $pasttime);
1087  
1088          // Make a new cache class.  This should not invalidate anything.
1089          cache_factory::instance()->reset_cache_instances();
1090          $cache = cache::make('phpunit', 'eventinvalidationtest');
1091  
1092          // Lastinvalidation shouldn't change since it was already newer than invalidation event.
1093          $this->assertEquals($pasttime, $cache->get('lastinvalidation'));
1094  
1095          // Now set the event invalidation to newer than the lastinvalidation time.
1096          $invalidationcache->set('crazyevent', array('testkey2' => cache::now() - 5));
1097          // Make a new cache class.  This should should invalidate testkey2.
1098          cache_factory::instance()->reset_cache_instances();
1099          $cache = cache::make('phpunit', 'eventinvalidationtest');
1100          // Lastinvalidation timestamp should have updated to cache::now().
1101          $this->assertEquals(cache::get_purge_token(), $cache->get('lastinvalidation'));
1102  
1103          // Now simulate a purge_by_event 5 seconds ago.
1104          $invalidationcache = cache::make('core', 'eventinvalidation');
1105          $invalidationcache->set('crazyevent', array('purged' => cache::now(true) - 5));
1106          // Set our lastinvalidation timestamp to 15 seconds ago.
1107          $cache->set('lastinvalidation', cache::now(true) - 15);
1108          // Make a new cache class.  This should invalidate the cache.
1109          cache_factory::instance()->reset_cache_instances();
1110          $cache = cache::make('phpunit', 'eventinvalidationtest');
1111          // Lastinvalidation timestamp should have updated to cache::now().
1112          $this->assertEquals(cache::get_purge_token(), $cache->get('lastinvalidation'));
1113  
1114      }
1115  
1116      /**
1117       * Tests application cache event purge
1118       */
1119      public function test_application_event_purge() {
1120          $instance = cache_config_testing::instance();
1121          $instance->phpunit_add_definition('phpunit/eventpurgetest', array(
1122              'mode' => cache_store::MODE_APPLICATION,
1123              'component' => 'phpunit',
1124              'area' => 'eventpurgetest',
1125              'invalidationevents' => array(
1126                  'crazyevent'
1127              )
1128          ));
1129          $instance->phpunit_add_definition('phpunit/eventpurgetestaccelerated', array(
1130              'mode' => cache_store::MODE_APPLICATION,
1131              'component' => 'phpunit',
1132              'area' => 'eventpurgetestaccelerated',
1133              'staticacceleration' => true,
1134              'invalidationevents' => array(
1135                  'crazyevent'
1136              )
1137          ));
1138          $cache = cache::make('phpunit', 'eventpurgetest');
1139  
1140          $this->assertTrue($cache->set('testkey1', 'test data 1'));
1141          $this->assertEquals('test data 1', $cache->get('testkey1'));
1142          $this->assertTrue($cache->set('testkey2', 'test data 2'));
1143          $this->assertEquals('test data 2', $cache->get('testkey2'));
1144  
1145          // Purge the event.
1146          cache_helper::purge_by_event('crazyevent');
1147  
1148          // Check things have been removed.
1149          $this->assertFalse($cache->get('testkey1'));
1150          $this->assertFalse($cache->get('testkey2'));
1151  
1152          // Now test the static acceleration array.
1153          $cache = cache::make('phpunit', 'eventpurgetestaccelerated');
1154          $this->assertTrue($cache->set('testkey1', 'test data 1'));
1155          $this->assertEquals('test data 1', $cache->get('testkey1'));
1156          $this->assertTrue($cache->set('testkey2', 'test data 2'));
1157          $this->assertEquals('test data 2', $cache->get('testkey2'));
1158  
1159          // Purge the event.
1160          cache_helper::purge_by_event('crazyevent');
1161  
1162          // Check things have been removed.
1163          $this->assertFalse($cache->get('testkey1'));
1164          $this->assertFalse($cache->get('testkey2'));
1165      }
1166  
1167      /**
1168       * Tests session cache event purge
1169       */
1170      public function test_session_event_purge() {
1171          $instance = cache_config_testing::instance();
1172          $instance->phpunit_add_definition('phpunit/eventpurgetest', array(
1173              'mode' => cache_store::MODE_SESSION,
1174              'component' => 'phpunit',
1175              'area' => 'eventpurgetest',
1176              'invalidationevents' => array(
1177                  'crazyevent'
1178              )
1179          ));
1180          $instance->phpunit_add_definition('phpunit/eventpurgetestaccelerated', array(
1181              'mode' => cache_store::MODE_SESSION,
1182              'component' => 'phpunit',
1183              'area' => 'eventpurgetestaccelerated',
1184              'staticacceleration' => true,
1185              'invalidationevents' => array(
1186                  'crazyevent'
1187              )
1188          ));
1189          $cache = cache::make('phpunit', 'eventpurgetest');
1190  
1191          $this->assertTrue($cache->set('testkey1', 'test data 1'));
1192          $this->assertEquals('test data 1', $cache->get('testkey1'));
1193          $this->assertTrue($cache->set('testkey2', 'test data 2'));
1194          $this->assertEquals('test data 2', $cache->get('testkey2'));
1195  
1196          // Purge the event.
1197          cache_helper::purge_by_event('crazyevent');
1198  
1199          // Check things have been removed.
1200          $this->assertFalse($cache->get('testkey1'));
1201          $this->assertFalse($cache->get('testkey2'));
1202  
1203          // Now test the static acceleration array.
1204          $cache = cache::make('phpunit', 'eventpurgetestaccelerated');
1205          $this->assertTrue($cache->set('testkey1', 'test data 1'));
1206          $this->assertEquals('test data 1', $cache->get('testkey1'));
1207          $this->assertTrue($cache->set('testkey2', 'test data 2'));
1208          $this->assertEquals('test data 2', $cache->get('testkey2'));
1209  
1210          // Purge the event.
1211          cache_helper::purge_by_event('crazyevent');
1212  
1213          // Check things have been removed.
1214          $this->assertFalse($cache->get('testkey1'));
1215          $this->assertFalse($cache->get('testkey2'));
1216      }
1217  
1218      /**
1219       * Tests application cache definition purge
1220       */
1221      public function test_application_definition_purge() {
1222          $instance = cache_config_testing::instance();
1223          $instance->phpunit_add_definition('phpunit/definitionpurgetest', array(
1224              'mode' => cache_store::MODE_APPLICATION,
1225              'component' => 'phpunit',
1226              'area' => 'definitionpurgetest',
1227              'invalidationevents' => array(
1228                  'crazyevent'
1229              )
1230          ));
1231          $cache = cache::make('phpunit', 'definitionpurgetest');
1232  
1233          $this->assertTrue($cache->set('testkey1', 'test data 1'));
1234          $this->assertEquals('test data 1', $cache->get('testkey1'));
1235          $this->assertTrue($cache->set('testkey2', 'test data 2'));
1236          $this->assertEquals('test data 2', $cache->get('testkey2'));
1237  
1238          // Purge the event.
1239          cache_helper::purge_by_definition('phpunit', 'definitionpurgetest');
1240  
1241          // Check things have been removed.
1242          $this->assertFalse($cache->get('testkey1'));
1243          $this->assertFalse($cache->get('testkey2'));
1244      }
1245  
1246      /**
1247       * Test the use of an alt path.
1248       * If we can generate a config instance we are done :)
1249       */
1250      public function test_alt_cache_path() {
1251          global $CFG;
1252          if ((defined('TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH') && TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH) || !empty($CFG->altcacheconfigpath)) {
1253              $this->markTestSkipped('Skipped testing alt cache path as it is already being used.');
1254          }
1255          $this->resetAfterTest();
1256          $CFG->altcacheconfigpath = $CFG->dataroot.'/cache/altcacheconfigpath';
1257          $instance = cache_config_testing::instance();
1258          $this->assertInstanceOf(cache_config::class, $instance);
1259      }
1260  
1261      /**
1262       * Test disabling the cache stores.
1263       */
1264      public function test_disable_stores() {
1265          $instance = cache_config_testing::instance();
1266          $instance->phpunit_add_definition('phpunit/disabletest1', array(
1267              'mode' => cache_store::MODE_APPLICATION,
1268              'component' => 'phpunit',
1269              'area' => 'disabletest1'
1270          ));
1271          $instance->phpunit_add_definition('phpunit/disabletest2', array(
1272              'mode' => cache_store::MODE_SESSION,
1273              'component' => 'phpunit',
1274              'area' => 'disabletest2'
1275          ));
1276          $instance->phpunit_add_definition('phpunit/disabletest3', array(
1277              'mode' => cache_store::MODE_REQUEST,
1278              'component' => 'phpunit',
1279              'area' => 'disabletest3'
1280          ));
1281  
1282          $caches = array(
1283              'disabletest1' => cache::make('phpunit', 'disabletest1'),
1284              'disabletest2' => cache::make('phpunit', 'disabletest2'),
1285              'disabletest3' => cache::make('phpunit', 'disabletest3')
1286          );
1287  
1288          $this->assertInstanceOf(cache_phpunit_application::class, $caches['disabletest1']);
1289          $this->assertInstanceOf(cache_phpunit_session::class, $caches['disabletest2']);
1290          $this->assertInstanceOf(cache_phpunit_request::class, $caches['disabletest3']);
1291  
1292          $this->assertEquals('cachestore_file', $caches['disabletest1']->phpunit_get_store_class());
1293          $this->assertEquals('cachestore_session', $caches['disabletest2']->phpunit_get_store_class());
1294          $this->assertEquals('cachestore_static', $caches['disabletest3']->phpunit_get_store_class());
1295  
1296          foreach ($caches as $cache) {
1297              $this->assertFalse($cache->get('test'));
1298              $this->assertTrue($cache->set('test', 'test'));
1299              $this->assertEquals('test', $cache->get('test'));
1300          }
1301  
1302          cache_factory::disable_stores();
1303  
1304          $caches = array(
1305              'disabletest1' => cache::make('phpunit', 'disabletest1'),
1306              'disabletest2' => cache::make('phpunit', 'disabletest2'),
1307              'disabletest3' => cache::make('phpunit', 'disabletest3')
1308          );
1309  
1310          $this->assertInstanceOf(cache_phpunit_application::class, $caches['disabletest1']);
1311          $this->assertInstanceOf(cache_phpunit_session::class, $caches['disabletest2']);
1312          $this->assertInstanceOf(cache_phpunit_request::class, $caches['disabletest3']);
1313  
1314          $this->assertEquals('cachestore_dummy', $caches['disabletest1']->phpunit_get_store_class());
1315          $this->assertEquals('cachestore_dummy', $caches['disabletest2']->phpunit_get_store_class());
1316          $this->assertEquals('cachestore_dummy', $caches['disabletest3']->phpunit_get_store_class());
1317  
1318          foreach ($caches as $cache) {
1319              $this->assertFalse($cache->get('test'));
1320              $this->assertTrue($cache->set('test', 'test'));
1321              $this->assertEquals('test', $cache->get('test'));
1322          }
1323      }
1324  
1325      /**
1326       * Test disabling the cache.
1327       */
1328      public function test_disable() {
1329          global $CFG;
1330  
1331          if ((defined('TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH') && TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH) || !empty($CFG->altcacheconfigpath)) {
1332              // We can't run this test as it requires us to delete the cache configuration script which we just
1333              // cant do with a custom path in play.
1334              $this->markTestSkipped('Skipped testing cache disable functionality as alt cache path is being used.');
1335          }
1336  
1337          $configfile = $CFG->dataroot.'/muc/config.php';
1338  
1339          // The config file will not exist yet as we've not done anything with the cache.
1340          // reset_all_data removes the file and without a call to create a configuration it doesn't exist
1341          // as yet.
1342          $this->assertFileDoesNotExist($configfile);
1343  
1344          // Disable the cache
1345          cache_phpunit_factory::phpunit_disable();
1346  
1347          // Check we get the expected disabled factory.
1348          $factory = cache_factory::instance();
1349          $this->assertInstanceOf(cache_factory_disabled::class, $factory);
1350  
1351          // Check we get the expected disabled config.
1352          $config = $factory->create_config_instance();
1353          $this->assertInstanceOf(cache_config_disabled::class, $config);
1354  
1355          // Check we get the expected disabled caches.
1356          $cache = cache::make('core', 'string');
1357          $this->assertInstanceOf(cache_disabled::class, $cache);
1358  
1359          // Test an application cache.
1360          $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'phpunit', 'disable');
1361          $this->assertInstanceOf(cache_disabled::class, $cache);
1362  
1363          $this->assertFalse($cache->get('test'));
1364          $this->assertFalse($cache->set('test', 'test'));
1365          $this->assertFalse($cache->delete('test'));
1366          $this->assertTrue($cache->purge());
1367  
1368          // Test a session cache.
1369          $cache = cache::make_from_params(cache_store::MODE_SESSION, 'phpunit', 'disable');
1370          $this->assertInstanceOf(cache_disabled::class, $cache);
1371  
1372          $this->assertFalse($cache->get('test'));
1373          $this->assertFalse($cache->set('test', 'test'));
1374          $this->assertFalse($cache->delete('test'));
1375          $this->assertTrue($cache->purge());
1376  
1377          // Finally test a request cache.
1378          $cache = cache::make_from_params(cache_store::MODE_REQUEST, 'phpunit', 'disable');
1379          $this->assertInstanceOf(cache_disabled::class, $cache);
1380  
1381          $this->assertFalse($cache->get('test'));
1382          $this->assertFalse($cache->set('test', 'test'));
1383          $this->assertFalse($cache->delete('test'));
1384          $this->assertTrue($cache->purge());
1385  
1386          cache_factory::reset();
1387  
1388          $factory = cache_factory::instance(true);
1389          $config = $factory->create_config_instance();
1390          $this->assertEquals('cache_config_testing', get_class($config));
1391      }
1392  
1393      /**
1394       * Test that multiple application loaders work ok.
1395       */
1396      public function test_multiple_application_loaders() {
1397          $instance = cache_config_testing::instance(true);
1398          $instance->phpunit_add_file_store('phpunittest1');
1399          $instance->phpunit_add_file_store('phpunittest2');
1400          $instance->phpunit_add_definition('phpunit/multi_loader', array(
1401              'mode' => cache_store::MODE_APPLICATION,
1402              'component' => 'phpunit',
1403              'area' => 'multi_loader'
1404          ));
1405          $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'phpunittest1', 3);
1406          $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'phpunittest2', 2);
1407  
1408          $cache = cache::make('phpunit', 'multi_loader');
1409          $this->assertInstanceOf(cache_application::class, $cache);
1410          $this->assertFalse($cache->get('test'));
1411          $this->assertTrue($cache->set('test', 'test'));
1412          $this->assertEquals('test', $cache->get('test'));
1413          $this->assertTrue($cache->delete('test'));
1414          $this->assertFalse($cache->get('test'));
1415          $this->assertTrue($cache->set('test', 'test'));
1416          $this->assertTrue($cache->purge());
1417          $this->assertFalse($cache->get('test'));
1418  
1419          // Test the many commands.
1420          $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C')));
1421          $result = $cache->get_many(array('a', 'b', 'c'));
1422          $this->assertIsArray($result);
1423          $this->assertCount(3, $result);
1424          $this->assertArrayHasKey('a', $result);
1425          $this->assertArrayHasKey('b', $result);
1426          $this->assertArrayHasKey('c', $result);
1427          $this->assertEquals('A', $result['a']);
1428          $this->assertEquals('B', $result['b']);
1429          $this->assertEquals('C', $result['c']);
1430          $this->assertEquals($result, $cache->get_many(array('a', 'b', 'c')));
1431          $this->assertEquals(2, $cache->delete_many(array('a', 'c')));
1432          $result = $cache->get_many(array('a', 'b', 'c'));
1433          $this->assertIsArray($result);
1434          $this->assertCount(3, $result);
1435          $this->assertArrayHasKey('a', $result);
1436          $this->assertArrayHasKey('b', $result);
1437          $this->assertArrayHasKey('c', $result);
1438          $this->assertFalse($result['a']);
1439          $this->assertEquals('B', $result['b']);
1440          $this->assertFalse($result['c']);
1441  
1442          // Test non-recursive deletes.
1443          $this->assertTrue($cache->set('test', 'test'));
1444          $this->assertSame('test', $cache->get('test'));
1445          $this->assertTrue($cache->delete('test', false));
1446          // We should still have it on a deeper loader.
1447          $this->assertSame('test', $cache->get('test'));
1448          // Test non-recusive with many functions.
1449          $this->assertSame(3, $cache->set_many(array(
1450              'one' => 'one',
1451              'two' => 'two',
1452              'three' => 'three'
1453          )));
1454          $this->assertSame('one', $cache->get('one'));
1455          $this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three')));
1456          $this->assertSame(3, $cache->delete_many(array('one', 'two', 'three'), false));
1457          $this->assertSame('one', $cache->get('one'));
1458          $this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three')));
1459      }
1460  
1461      /**
1462       * Test that multiple application loaders work ok.
1463       */
1464      public function test_multiple_session_loaders() {
1465          /* @var cache_config_testing $instance */
1466          $instance = cache_config_testing::instance(true);
1467          $instance->phpunit_add_session_store('phpunittest1');
1468          $instance->phpunit_add_session_store('phpunittest2');
1469          $instance->phpunit_add_definition('phpunit/multi_loader', array(
1470              'mode' => cache_store::MODE_SESSION,
1471              'component' => 'phpunit',
1472              'area' => 'multi_loader'
1473          ));
1474          $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'phpunittest1', 3);
1475          $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'phpunittest2', 2);
1476  
1477          $cache = cache::make('phpunit', 'multi_loader');
1478          $this->assertInstanceOf(cache_session::class, $cache);
1479          $this->assertFalse($cache->get('test'));
1480          $this->assertTrue($cache->set('test', 'test'));
1481          $this->assertEquals('test', $cache->get('test'));
1482          $this->assertTrue($cache->delete('test'));
1483          $this->assertFalse($cache->get('test'));
1484          $this->assertTrue($cache->set('test', 'test'));
1485          $this->assertTrue($cache->purge());
1486          $this->assertFalse($cache->get('test'));
1487  
1488          // Test the many commands.
1489          $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C')));
1490          $result = $cache->get_many(array('a', 'b', 'c'));
1491          $this->assertIsArray($result);
1492          $this->assertCount(3, $result);
1493          $this->assertArrayHasKey('a', $result);
1494          $this->assertArrayHasKey('b', $result);
1495          $this->assertArrayHasKey('c', $result);
1496          $this->assertEquals('A', $result['a']);
1497          $this->assertEquals('B', $result['b']);
1498          $this->assertEquals('C', $result['c']);
1499          $this->assertEquals($result, $cache->get_many(array('a', 'b', 'c')));
1500          $this->assertEquals(2, $cache->delete_many(array('a', 'c')));
1501          $result = $cache->get_many(array('a', 'b', 'c'));
1502          $this->assertIsArray($result);
1503          $this->assertCount(3, $result);
1504          $this->assertArrayHasKey('a', $result);
1505          $this->assertArrayHasKey('b', $result);
1506          $this->assertArrayHasKey('c', $result);
1507          $this->assertFalse($result['a']);
1508          $this->assertEquals('B', $result['b']);
1509          $this->assertFalse($result['c']);
1510  
1511          // Test non-recursive deletes.
1512          $this->assertTrue($cache->set('test', 'test'));
1513          $this->assertSame('test', $cache->get('test'));
1514          $this->assertTrue($cache->delete('test', false));
1515          // We should still have it on a deeper loader.
1516          $this->assertSame('test', $cache->get('test'));
1517          // Test non-recusive with many functions.
1518          $this->assertSame(3, $cache->set_many(array(
1519              'one' => 'one',
1520              'two' => 'two',
1521              'three' => 'three'
1522          )));
1523          $this->assertSame('one', $cache->get('one'));
1524          $this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three')));
1525          $this->assertSame(3, $cache->delete_many(array('one', 'two', 'three'), false));
1526          $this->assertSame('one', $cache->get('one'));
1527          $this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three')));
1528      }
1529  
1530      /**
1531       * Test switching users with session caches.
1532       */
1533      public function test_session_cache_switch_user() {
1534          $this->resetAfterTest(true);
1535          $cache = cache::make_from_params(cache_store::MODE_SESSION, 'phpunit', 'sessioncache');
1536          $user1 = $this->getDataGenerator()->create_user();
1537          $user2 = $this->getDataGenerator()->create_user();
1538  
1539          // Log in as the first user.
1540          $this->setUser($user1);
1541          $sesskey1 = sesskey();
1542  
1543          // Set a basic value in the cache.
1544          $cache->set('var', 1);
1545          $this->assertTrue($cache->has('var'));
1546          $this->assertEquals(1, $cache->get('var'));
1547  
1548          // Change to the second user.
1549          $this->setUser($user2);
1550          $sesskey2 = sesskey();
1551  
1552          // Make sure the cache doesn't give us the data for the last user.
1553          $this->assertNotEquals($sesskey1, $sesskey2);
1554          $this->assertFalse($cache->has('var'));
1555          $this->assertEquals(false, $cache->get('var'));
1556      }
1557  
1558      /**
1559       * Test switching users with session caches.
1560       */
1561      public function test_session_cache_switch_user_application_mapping() {
1562          $this->resetAfterTest(true);
1563          $instance = cache_config_testing::instance(true);
1564          $instance->phpunit_add_file_store('testfilestore');
1565          $instance->phpunit_add_definition('phpunit/testappsession', array(
1566              'mode' => cache_store::MODE_SESSION,
1567              'component' => 'phpunit',
1568              'area' => 'testappsession'
1569          ));
1570          $instance->phpunit_add_definition_mapping('phpunit/testappsession', 'testfilestore', 3);
1571          $cache = cache::make('phpunit', 'testappsession');
1572          $user1 = $this->getDataGenerator()->create_user();
1573          $user2 = $this->getDataGenerator()->create_user();
1574  
1575          // Log in as the first user.
1576          $this->setUser($user1);
1577          $sesskey1 = sesskey();
1578  
1579          // Set a basic value in the cache.
1580          $cache->set('var', 1);
1581          $this->assertTrue($cache->has('var'));
1582          $this->assertEquals(1, $cache->get('var'));
1583  
1584          // Change to the second user.
1585          $this->setUser($user2);
1586          $sesskey2 = sesskey();
1587  
1588          // Make sure the cache doesn't give us the data for the last user.
1589          $this->assertNotEquals($sesskey1, $sesskey2);
1590          $this->assertFalse($cache->has('var'));
1591          $this->assertEquals(false, $cache->get('var'));
1592      }
1593  
1594      /**
1595       * Test two session caches being used at once to confirm collisions don't occur.
1596       */
1597      public function test_dual_session_caches() {
1598          $instance = cache_config_testing::instance(true);
1599          $instance->phpunit_add_definition('phpunit/testsess1', array(
1600              'mode' => cache_store::MODE_SESSION,
1601              'component' => 'phpunit',
1602              'area' => 'testsess1'
1603          ));
1604          $instance->phpunit_add_definition('phpunit/testsess2', array(
1605              'mode' => cache_store::MODE_SESSION,
1606              'component' => 'phpunit',
1607              'area' => 'testsess2'
1608          ));
1609          $cache1 = cache::make('phpunit', 'testsess1');
1610          $cache2 = cache::make('phpunit', 'testsess2');
1611  
1612          $this->assertFalse($cache1->has('test'));
1613          $this->assertFalse($cache2->has('test'));
1614  
1615          $this->assertTrue($cache1->set('test', '1'));
1616  
1617          $this->assertTrue($cache1->has('test'));
1618          $this->assertFalse($cache2->has('test'));
1619  
1620          $this->assertTrue($cache2->set('test', '2'));
1621  
1622          $this->assertEquals(1, $cache1->get('test'));
1623          $this->assertEquals(2, $cache2->get('test'));
1624  
1625          $this->assertTrue($cache1->delete('test'));
1626      }
1627  
1628      /**
1629       * Test multiple session caches when switching user.
1630       */
1631      public function test_session_cache_switch_user_multiple() {
1632          $this->resetAfterTest(true);
1633          $cache1 = cache::make_from_params(cache_store::MODE_SESSION, 'phpunit', 'sessioncache1');
1634          $cache2 = cache::make_from_params(cache_store::MODE_SESSION, 'phpunit', 'sessioncache2');
1635          $user1 = $this->getDataGenerator()->create_user();
1636          $user2 = $this->getDataGenerator()->create_user();
1637  
1638          // Log in as the first user.
1639          $this->setUser($user1);
1640          $sesskey1 = sesskey();
1641  
1642          // Set a basic value in the caches.
1643          $cache1->set('var', 1);
1644          $cache2->set('var', 2);
1645          $this->assertEquals(1, $cache1->get('var'));
1646          $this->assertEquals(2, $cache2->get('var'));
1647  
1648          // Change to the second user.
1649          $this->setUser($user2);
1650          $sesskey2 = sesskey();
1651  
1652          // Make sure the cache doesn't give us the data for the last user.
1653          // Also make sure that switching the user has lead to both caches being purged.
1654          $this->assertNotEquals($sesskey1, $sesskey2);
1655          $this->assertEquals(false, $cache1->get('var'));
1656          $this->assertEquals(false, $cache2->get('var'));
1657      }
1658  
1659      /**
1660       * Test application locking.
1661       */
1662      public function test_application_locking() {
1663          $instance = cache_config_testing::instance(true);
1664          $instance->phpunit_add_definition('phpunit/test_application_locking', array(
1665              'mode' => cache_store::MODE_APPLICATION,
1666              'component' => 'phpunit',
1667              'area' => 'test_application_locking',
1668              'staticacceleration' => true,
1669              'staticaccelerationsize' => 1,
1670              'requirelockingread' => true,
1671              'requirelockingwrite' => true
1672          ));
1673          $cache = cache::make('phpunit', 'test_application_locking');
1674          $this->assertInstanceOf(cache_application::class, $cache);
1675  
1676          $this->assertTrue($cache->set('a', 'A'));
1677          $this->assertTrue($cache->set('b', 'B'));
1678          $this->assertTrue($cache->set('c', 'C'));
1679          $this->assertEquals('A', $cache->get('a'));
1680          $this->assertEquals(array('b' => 'B', 'c' => 'C'), $cache->get_many(array('b', 'c')));
1681          $this->assertTrue($cache->delete('a'));
1682          $this->assertFalse($cache->has('a'));
1683      }
1684  
1685      /**
1686       * Test the static cache_helper method purge_stores_used_by_definition.
1687       */
1688      public function test_purge_stores_used_by_definition() {
1689          $instance = cache_config_testing::instance(true);
1690          $instance->phpunit_add_definition('phpunit/test_purge_stores_used_by_definition', array(
1691              'mode' => cache_store::MODE_APPLICATION,
1692              'component' => 'phpunit',
1693              'area' => 'test_purge_stores_used_by_definition'
1694          ));
1695          $cache = cache::make('phpunit', 'test_purge_stores_used_by_definition');
1696          $this->assertInstanceOf(cache_application::class, $cache);
1697          $this->assertTrue($cache->set('test', 'test'));
1698          unset($cache);
1699  
1700          cache_helper::purge_stores_used_by_definition('phpunit', 'test_purge_stores_used_by_definition');
1701  
1702          $cache = cache::make('phpunit', 'test_purge_stores_used_by_definition');
1703          $this->assertInstanceOf(cache_application::class, $cache);
1704          $this->assertFalse($cache->get('test'));
1705      }
1706  
1707      /**
1708       * Test purge routines.
1709       */
1710      public function test_purge_routines() {
1711          $instance = cache_config_testing::instance(true);
1712          $instance->phpunit_add_definition('phpunit/purge1', array(
1713              'mode' => cache_store::MODE_APPLICATION,
1714              'component' => 'phpunit',
1715              'area' => 'purge1'
1716          ));
1717          $instance->phpunit_add_definition('phpunit/purge2', array(
1718              'mode' => cache_store::MODE_APPLICATION,
1719              'component' => 'phpunit',
1720              'area' => 'purge2',
1721              'requireidentifiers' => array(
1722                  'id'
1723              )
1724          ));
1725  
1726          $factory = cache_factory::instance();
1727          $definition = $factory->create_definition('phpunit', 'purge1');
1728          $this->assertFalse($definition->has_required_identifiers());
1729          $cache = $factory->create_cache($definition);
1730          $this->assertInstanceOf(cache_application::class, $cache);
1731          $this->assertTrue($cache->set('test', 'test'));
1732          $this->assertTrue($cache->has('test'));
1733          cache_helper::purge_by_definition('phpunit', 'purge1');
1734          $this->assertFalse($cache->has('test'));
1735  
1736          $factory = cache_factory::instance();
1737          $definition = $factory->create_definition('phpunit', 'purge2');
1738          $this->assertTrue($definition->has_required_identifiers());
1739          $cache = $factory->create_cache($definition);
1740          $this->assertInstanceOf(cache_application::class, $cache);
1741          $this->assertTrue($cache->set('test', 'test'));
1742          $this->assertTrue($cache->has('test'));
1743          cache_helper::purge_stores_used_by_definition('phpunit', 'purge2');
1744          $this->assertFalse($cache->has('test'));
1745  
1746          try {
1747              cache_helper::purge_by_definition('phpunit', 'purge2');
1748              $this->fail('Should not be able to purge a definition required identifiers without providing them.');
1749          } catch (\coding_exception $ex) {
1750              $this->assertStringContainsString('Identifier required for cache has not been provided', $ex->getMessage());
1751          }
1752      }
1753  
1754      /**
1755       * Tests that ad-hoc caches are correctly purged with a purge_all call.
1756       */
1757      public function test_purge_all_with_adhoc_caches() {
1758          $cache = cache::make_from_params(cache_store::MODE_REQUEST, 'core_cache', 'test');
1759          $cache->set('test', 123);
1760          cache_helper::purge_all();
1761          $this->assertFalse($cache->get('test'));
1762      }
1763  
1764      /**
1765       * Test that the default stores all support searching.
1766       */
1767      public function test_defaults_support_searching() {
1768          $instance = cache_config_testing::instance(true);
1769          $instance->phpunit_add_definition('phpunit/search1', array(
1770              'mode' => cache_store::MODE_APPLICATION,
1771              'component' => 'phpunit',
1772              'area' => 'search1',
1773              'requiresearchable' => true
1774          ));
1775          $instance->phpunit_add_definition('phpunit/search2', array(
1776              'mode' => cache_store::MODE_SESSION,
1777              'component' => 'phpunit',
1778              'area' => 'search2',
1779              'requiresearchable' => true
1780          ));
1781          $instance->phpunit_add_definition('phpunit/search3', array(
1782              'mode' => cache_store::MODE_REQUEST,
1783              'component' => 'phpunit',
1784              'area' => 'search3',
1785              'requiresearchable' => true
1786          ));
1787          $factory = cache_factory::instance();
1788  
1789          // Test application cache is searchable.
1790          $definition = $factory->create_definition('phpunit', 'search1');
1791          $this->assertInstanceOf(cache_definition::class, $definition);
1792          $this->assertEquals(cache_store::IS_SEARCHABLE, $definition->get_requirements_bin() & cache_store::IS_SEARCHABLE);
1793          $cache = $factory->create_cache($definition);
1794          $this->assertInstanceOf(cache_application::class, $cache);
1795          $this->assertArrayHasKey('cache_is_searchable', $cache->phpunit_get_store_implements());
1796  
1797          // Test session cache is searchable.
1798          $definition = $factory->create_definition('phpunit', 'search2');
1799          $this->assertInstanceOf(cache_definition::class, $definition);
1800          $this->assertEquals(cache_store::IS_SEARCHABLE, $definition->get_requirements_bin() & cache_store::IS_SEARCHABLE);
1801          $cache = $factory->create_cache($definition);
1802          $this->assertInstanceOf(cache_session::class, $cache);
1803          $this->assertArrayHasKey('cache_is_searchable', $cache->phpunit_get_store_implements());
1804  
1805          // Test request cache is searchable.
1806          $definition = $factory->create_definition('phpunit', 'search3');
1807          $this->assertInstanceOf(cache_definition::class, $definition);
1808          $this->assertEquals(cache_store::IS_SEARCHABLE, $definition->get_requirements_bin() & cache_store::IS_SEARCHABLE);
1809          $cache = $factory->create_cache($definition);
1810          $this->assertInstanceOf(cache_request::class, $cache);
1811          $this->assertArrayHasKey('cache_is_searchable', $cache->phpunit_get_store_implements());
1812      }
1813  
1814      /**
1815       * Test static acceleration
1816       *
1817       * Note: All the assertGreaterThanOrEqual() in this test should be assertGreaterThan() be because of some microtime()
1818       * resolution problems under some OSs / PHP versions, we are accepting equal as valid outcome. For more info see MDL-57147.
1819       */
1820      public function test_static_acceleration() {
1821          $instance = cache_config_testing::instance();
1822          $instance->phpunit_add_definition('phpunit/accelerated', array(
1823              'mode' => cache_store::MODE_APPLICATION,
1824              'component' => 'phpunit',
1825              'area' => 'accelerated',
1826              'staticacceleration' => true,
1827              'staticaccelerationsize' => 3,
1828          ));
1829          $instance->phpunit_add_definition('phpunit/accelerated2', array(
1830              'mode' => cache_store::MODE_APPLICATION,
1831              'component' => 'phpunit',
1832              'area' => 'accelerated2',
1833              'staticacceleration' => true,
1834              'staticaccelerationsize' => 3,
1835          ));
1836          $instance->phpunit_add_definition('phpunit/accelerated3', array(
1837              'mode' => cache_store::MODE_APPLICATION,
1838              'component' => 'phpunit',
1839              'area' => 'accelerated3',
1840              'staticacceleration' => true,
1841              'staticaccelerationsize' => 3,
1842          ));
1843          $instance->phpunit_add_definition('phpunit/accelerated4', array(
1844              'mode' => cache_store::MODE_APPLICATION,
1845              'component' => 'phpunit',
1846              'area' => 'accelerated4',
1847              'staticacceleration' => true,
1848              'staticaccelerationsize' => 4,
1849          ));
1850          $instance->phpunit_add_definition('phpunit/simpledataarea1', array(
1851              'mode' => cache_store::MODE_APPLICATION,
1852              'component' => 'phpunit',
1853              'area' => 'simpledataarea1',
1854              'staticacceleration' => true,
1855              'simpledata' => false
1856          ));
1857          $instance->phpunit_add_definition('phpunit/simpledataarea2', array(
1858              'mode' => cache_store::MODE_APPLICATION,
1859              'component' => 'phpunit',
1860              'area' => 'simpledataarea2',
1861              'staticacceleration' => true,
1862              'simpledata' => true
1863          ));
1864  
1865          $cache = cache::make('phpunit', 'accelerated');
1866          $this->assertInstanceOf(cache_phpunit_application::class, $cache);
1867  
1868          // Set and get three elements.
1869          $this->assertTrue($cache->set('a', 'A'));
1870          $this->assertTrue($cache->set('b', 'B'));
1871          $this->assertTrue($cache->set('c', 'C'));
1872          $this->assertEquals('A', $cache->get('a'));
1873          $this->assertEquals(array('b' => 'B', 'c' => 'C'), $cache->get_many(array('b', 'c')));
1874  
1875          // Make sure all items are in static acceleration array.
1876          $this->assertEquals('A', $cache->phpunit_static_acceleration_get('a'));
1877          $this->assertEquals('B', $cache->phpunit_static_acceleration_get('b'));
1878          $this->assertEquals('C', $cache->phpunit_static_acceleration_get('c'));
1879  
1880          // Add new value and make sure it is in cache and it is in array.
1881          $this->assertTrue($cache->set('d', 'D'));
1882          $this->assertEquals('D', $cache->phpunit_static_acceleration_get('d'));
1883          $this->assertEquals('D', $cache->get('d'));
1884  
1885          // Now the least recent accessed item (a) is no longer in acceleration array.
1886          $this->assertFalse($cache->phpunit_static_acceleration_get('a'));
1887          $this->assertEquals('B', $cache->phpunit_static_acceleration_get('b'));
1888          $this->assertEquals('C', $cache->phpunit_static_acceleration_get('c'));
1889  
1890          // Adding and deleting element.
1891          $this->assertTrue($cache->set('a', 'A'));
1892          $this->assertTrue($cache->delete('a'));
1893          $this->assertFalse($cache->phpunit_static_acceleration_get('a'));
1894          $this->assertFalse($cache->has('a'));
1895  
1896          // Make sure "purge" deletes from the array as well.
1897          $cache->purge();
1898          $this->assertFalse($cache->phpunit_static_acceleration_get('a'));
1899          $this->assertFalse($cache->phpunit_static_acceleration_get('b'));
1900          $this->assertFalse($cache->phpunit_static_acceleration_get('c'));
1901          $this->assertFalse($cache->phpunit_static_acceleration_get('d'));
1902          $this->assertFalse($cache->phpunit_static_acceleration_get('e'));
1903  
1904          // Check that the array holds the last accessed items by get/set.
1905          $this->assertTrue($cache->set('a', 'A'));
1906          $this->assertTrue($cache->set('b', 'B'));
1907          $this->assertTrue($cache->set('c', 'C'));
1908          $this->assertTrue($cache->set('d', 'D'));
1909          $this->assertTrue($cache->set('e', 'E'));
1910          $this->assertFalse($cache->phpunit_static_acceleration_get('a'));
1911          $this->assertFalse($cache->phpunit_static_acceleration_get('b'));
1912          $this->assertEquals('C', $cache->phpunit_static_acceleration_get('c'));
1913          $this->assertEquals('D', $cache->phpunit_static_acceleration_get('d'));
1914          $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e'));
1915  
1916          // Store a cacheable_object, get many times and ensure each time wake_for_cache is used.
1917          // Both get and get_many are tested.  Two cache entries are used to ensure the times aren't
1918          // confused with multiple calls to get()/get_many().
1919          $startmicrotime = microtime(true);
1920          $cacheableobject = new cache_phpunit_dummy_object(1, 1, $startmicrotime);
1921          $cacheableobject2 = new cache_phpunit_dummy_object(2, 2, $startmicrotime);
1922          $this->assertTrue($cache->set('a', $cacheableobject));
1923          $this->assertTrue($cache->set('b', $cacheableobject2));
1924          $staticaccelerationreturntime = $cache->phpunit_static_acceleration_get('a')->propertytime;
1925          $staticaccelerationreturntimeb = $cache->phpunit_static_acceleration_get('b')->propertytime;
1926          $this->assertGreaterThanOrEqual($startmicrotime, $staticaccelerationreturntime, 'Restore time of static must be newer.');
1927  
1928          // Reset the static cache without resetting backing store.
1929          $cache->phpunit_static_acceleration_purge();
1930  
1931          // Get the value from the backend store, populating the static cache.
1932          $cachevalue = $cache->get('a');
1933          $this->assertInstanceOf(cache_phpunit_dummy_object::class, $cachevalue);
1934          $this->assertGreaterThanOrEqual($staticaccelerationreturntime, $cachevalue->propertytime);
1935          $backingstorereturntime = $cachevalue->propertytime;
1936  
1937          $results = $cache->get_many(array('b'));
1938          $this->assertInstanceOf(cache_phpunit_dummy_object::class, $results['b']);
1939          $this->assertGreaterThanOrEqual($staticaccelerationreturntimeb, $results['b']->propertytime);
1940          $backingstorereturntimeb = $results['b']->propertytime;
1941  
1942          // Obtain the value again and confirm that static cache is using wake_from_cache.
1943          // Upon failure, the times are not adjusted as wake_from_cache is skipped as the
1944          // value is stored serialized in the static acceleration cache.
1945          $cachevalue = $cache->phpunit_static_acceleration_get('a');
1946          $this->assertInstanceOf(cache_phpunit_dummy_object::class, $cachevalue);
1947          $this->assertGreaterThanOrEqual($backingstorereturntime, $cachevalue->propertytime);
1948  
1949          $results = $cache->get_many(array('b'));
1950          $this->assertInstanceOf(cache_phpunit_dummy_object::class, $results['b']);
1951          $this->assertGreaterThanOrEqual($backingstorereturntimeb, $results['b']->propertytime);
1952  
1953          /** @var cache_phpunit_application $cache */
1954          $cache = cache::make('phpunit', 'accelerated2');
1955          $this->assertInstanceOf(cache_phpunit_application::class, $cache);
1956  
1957          // Check that the array holds the last accessed items by get/set.
1958          $this->assertTrue($cache->set('a', 'A'));
1959          $this->assertTrue($cache->set('b', 'B'));
1960          $this->assertTrue($cache->set('c', 'C'));
1961          $this->assertTrue($cache->set('d', 'D'));
1962          $this->assertTrue($cache->set('e', 'E'));
1963          // Current keys in the array: c, d, e.
1964          $this->assertEquals('C', $cache->phpunit_static_acceleration_get('c'));
1965          $this->assertEquals('D', $cache->phpunit_static_acceleration_get('d'));
1966          $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e'));
1967          $this->assertFalse($cache->phpunit_static_acceleration_get('a'));
1968          $this->assertFalse($cache->phpunit_static_acceleration_get('b'));
1969  
1970          $this->assertEquals('A', $cache->get('a'));
1971          // Current keys in the array: d, e, a.
1972          $this->assertEquals('D', $cache->phpunit_static_acceleration_get('d'));
1973          $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e'));
1974          $this->assertEquals('A', $cache->phpunit_static_acceleration_get('a'));
1975          $this->assertFalse($cache->phpunit_static_acceleration_get('b'));
1976          $this->assertFalse($cache->phpunit_static_acceleration_get('c'));
1977  
1978          // Current keys in the array: d, e, a.
1979          $this->assertEquals(array('c' => 'C'), $cache->get_many(array('c')));
1980          // Current keys in the array: e, a, c.
1981          $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e'));
1982          $this->assertEquals('A', $cache->phpunit_static_acceleration_get('a'));
1983          $this->assertEquals('C', $cache->phpunit_static_acceleration_get('c'));
1984          $this->assertFalse($cache->phpunit_static_acceleration_get('b'));
1985          $this->assertFalse($cache->phpunit_static_acceleration_get('d'));
1986  
1987  
1988          $cache = cache::make('phpunit', 'accelerated3');
1989          $this->assertInstanceOf(cache_phpunit_application::class, $cache);
1990  
1991          // Check that the array holds the last accessed items by get/set.
1992          $this->assertTrue($cache->set('a', 'A'));
1993          $this->assertTrue($cache->set('b', 'B'));
1994          $this->assertTrue($cache->set('c', 'C'));
1995          $this->assertTrue($cache->set('d', 'D'));
1996          $this->assertTrue($cache->set('e', 'E'));
1997          $this->assertFalse($cache->phpunit_static_acceleration_get('a'));
1998          $this->assertFalse($cache->phpunit_static_acceleration_get('b'));
1999          $this->assertEquals('C', $cache->phpunit_static_acceleration_get('c'));
2000          $this->assertEquals('D', $cache->phpunit_static_acceleration_get('d'));
2001          $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e'));
2002  
2003          $this->assertTrue($cache->set('b', 'B2'));
2004          $this->assertFalse($cache->phpunit_static_acceleration_get('a'));
2005          $this->assertEquals('B2', $cache->phpunit_static_acceleration_get('b'));
2006          $this->assertFalse($cache->phpunit_static_acceleration_get('c'));
2007          $this->assertEquals('D', $cache->phpunit_static_acceleration_get('d'));
2008          $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e'));
2009  
2010          $this->assertEquals(2, $cache->set_many(array('b' => 'B3', 'c' => 'C3')));
2011          $this->assertFalse($cache->phpunit_static_acceleration_get('a'));
2012          $this->assertEquals('B3', $cache->phpunit_static_acceleration_get('b'));
2013          $this->assertEquals('C3', $cache->phpunit_static_acceleration_get('c'));
2014          $this->assertFalse($cache->phpunit_static_acceleration_get('d'));
2015          $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e'));
2016  
2017          $cache = cache::make('phpunit', 'accelerated4');
2018          $this->assertInstanceOf(cache_phpunit_application::class, $cache);
2019          $this->assertTrue($cache->set('a', 'A'));
2020          $this->assertTrue($cache->set('a', 'A'));
2021          $this->assertTrue($cache->set('a', 'A'));
2022          $this->assertTrue($cache->set('a', 'A'));
2023          $this->assertTrue($cache->set('a', 'A'));
2024          $this->assertTrue($cache->set('a', 'A'));
2025          $this->assertTrue($cache->set('a', 'A'));
2026          $this->assertEquals('A', $cache->phpunit_static_acceleration_get('a'));
2027          $this->assertEquals('A', $cache->get('a'));
2028  
2029          // Setting simpledata to false objects are cloned when retrieving data.
2030          $cache = cache::make('phpunit', 'simpledataarea1');
2031          $notreallysimple = new \stdClass();
2032          $notreallysimple->name = 'a';
2033          $cache->set('a', $notreallysimple);
2034          $returnedinstance1 = $cache->get('a');
2035          $returnedinstance2 = $cache->get('a');
2036          $returnedinstance1->name = 'b';
2037          $this->assertEquals('a', $returnedinstance2->name);
2038  
2039          // Setting simpledata to true we assume that data does not contain references.
2040          $cache = cache::make('phpunit', 'simpledataarea2');
2041          $notreallysimple = new \stdClass();
2042          $notreallysimple->name = 'a';
2043          $cache->set('a', $notreallysimple);
2044          $returnedinstance1 = $cache->get('a');
2045          $returnedinstance2 = $cache->get('a');
2046          $returnedinstance1->name = 'b';
2047          $this->assertEquals('b', $returnedinstance2->name);
2048      }
2049  
2050      public function test_identifiers_have_separate_caches() {
2051          $cachepg = cache::make('core', 'databasemeta', array('dbfamily' => 'pgsql'));
2052          $cachepg->set(1, 'here');
2053          $cachemy = cache::make('core', 'databasemeta', array('dbfamily' => 'mysql'));
2054          $cachemy->set(2, 'there');
2055          $this->assertEquals('here', $cachepg->get(1));
2056          $this->assertEquals('there', $cachemy->get(2));
2057          $this->assertFalse($cachemy->get(1));
2058      }
2059  
2060      public function test_performance_debug() {
2061          global $CFG;
2062          $this->resetAfterTest(true);
2063          $CFG->perfdebug = 15;
2064  
2065          $instance = cache_config_testing::instance();
2066          $applicationid = 'phpunit/applicationperf';
2067          $instance->phpunit_add_definition($applicationid, array(
2068              'mode' => cache_store::MODE_APPLICATION,
2069              'component' => 'phpunit',
2070              'area' => 'applicationperf'
2071          ));
2072          $sessionid = 'phpunit/sessionperf';
2073          $instance->phpunit_add_definition($sessionid, array(
2074              'mode' => cache_store::MODE_SESSION,
2075              'component' => 'phpunit',
2076              'area' => 'sessionperf'
2077          ));
2078          $requestid = 'phpunit/requestperf';
2079          $instance->phpunit_add_definition($requestid, array(
2080              'mode' => cache_store::MODE_REQUEST,
2081              'component' => 'phpunit',
2082              'area' => 'requestperf'
2083          ));
2084  
2085          $application = cache::make('phpunit', 'applicationperf');
2086          $session = cache::make('phpunit', 'sessionperf');
2087          $request = cache::make('phpunit', 'requestperf');
2088  
2089          // Check that no stats are recorded for these definitions yet.
2090          $stats = cache_helper::get_stats();
2091          $this->assertArrayNotHasKey($applicationid, $stats);
2092          $this->assertArrayHasKey($sessionid, $stats);       // Session cache sets a key on construct.
2093          $this->assertArrayNotHasKey($requestid, $stats);
2094  
2095          // Check that stores register misses.
2096          $this->assertFalse($application->get('missMe'));
2097          $this->assertFalse($application->get('missMe'));
2098          $this->assertFalse($session->get('missMe'));
2099          $this->assertFalse($session->get('missMe'));
2100          $this->assertFalse($session->get('missMe'));
2101          $this->assertFalse($request->get('missMe'));
2102          $this->assertFalse($request->get('missMe'));
2103          $this->assertFalse($request->get('missMe'));
2104          $this->assertFalse($request->get('missMe'));
2105  
2106          $endstats = cache_helper::get_stats();
2107          $this->assertEquals(2, $endstats[$applicationid]['stores']['default_application']['misses']);
2108          $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['hits']);
2109          $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['sets']);
2110          $this->assertEquals(3, $endstats[$sessionid]['stores']['default_session']['misses']);
2111          $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['hits']);
2112          $this->assertEquals(1, $endstats[$sessionid]['stores']['default_session']['sets']);
2113          $this->assertEquals(4, $endstats[$requestid]['stores']['default_request']['misses']);
2114          $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['hits']);
2115          $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['sets']);
2116  
2117          $startstats = cache_helper::get_stats();
2118  
2119          // Check that stores register sets.
2120          $this->assertTrue($application->set('setMe1', 1));
2121          $this->assertTrue($application->set('setMe2', 2));
2122          $this->assertTrue($session->set('setMe1', 1));
2123          $this->assertTrue($session->set('setMe2', 2));
2124          $this->assertTrue($session->set('setMe3', 3));
2125          $this->assertTrue($request->set('setMe1', 1));
2126          $this->assertTrue($request->set('setMe2', 2));
2127          $this->assertTrue($request->set('setMe3', 3));
2128          $this->assertTrue($request->set('setMe4', 4));
2129  
2130          $endstats = cache_helper::get_stats();
2131          $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['misses'] -
2132                               $startstats[$applicationid]['stores']['default_application']['misses']);
2133          $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['hits'] -
2134                               $startstats[$applicationid]['stores']['default_application']['hits']);
2135          $this->assertEquals(2, $endstats[$applicationid]['stores']['default_application']['sets'] -
2136                               $startstats[$applicationid]['stores']['default_application']['sets']);
2137          $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['misses'] -
2138                               $startstats[$sessionid]['stores']['default_session']['misses']);
2139          $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['hits'] -
2140                               $startstats[$sessionid]['stores']['default_session']['hits']);
2141          $this->assertEquals(3, $endstats[$sessionid]['stores']['default_session']['sets'] -
2142                               $startstats[$sessionid]['stores']['default_session']['sets']);
2143          $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['misses'] -
2144                               $startstats[$requestid]['stores']['default_request']['misses']);
2145          $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['hits'] -
2146                               $startstats[$requestid]['stores']['default_request']['hits']);
2147          $this->assertEquals(4, $endstats[$requestid]['stores']['default_request']['sets'] -
2148                               $startstats[$requestid]['stores']['default_request']['sets']);
2149  
2150          $startstats = cache_helper::get_stats();
2151  
2152          // Check that stores register hits.
2153          $this->assertEquals($application->get('setMe1'), 1);
2154          $this->assertEquals($application->get('setMe2'), 2);
2155          $this->assertEquals($session->get('setMe1'), 1);
2156          $this->assertEquals($session->get('setMe2'), 2);
2157          $this->assertEquals($session->get('setMe3'), 3);
2158          $this->assertEquals($request->get('setMe1'), 1);
2159          $this->assertEquals($request->get('setMe2'), 2);
2160          $this->assertEquals($request->get('setMe3'), 3);
2161          $this->assertEquals($request->get('setMe4'), 4);
2162  
2163          $endstats = cache_helper::get_stats();
2164          $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['misses'] -
2165                               $startstats[$applicationid]['stores']['default_application']['misses']);
2166          $this->assertEquals(2, $endstats[$applicationid]['stores']['default_application']['hits'] -
2167                               $startstats[$applicationid]['stores']['default_application']['hits']);
2168          $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['sets'] -
2169                               $startstats[$applicationid]['stores']['default_application']['sets']);
2170          $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['misses'] -
2171                               $startstats[$sessionid]['stores']['default_session']['misses']);
2172          $this->assertEquals(3, $endstats[$sessionid]['stores']['default_session']['hits'] -
2173                               $startstats[$sessionid]['stores']['default_session']['hits']);
2174          $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['sets'] -
2175                               $startstats[$sessionid]['stores']['default_session']['sets']);
2176          $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['misses'] -
2177                               $startstats[$requestid]['stores']['default_request']['misses']);
2178          $this->assertEquals(4, $endstats[$requestid]['stores']['default_request']['hits'] -
2179                               $startstats[$requestid]['stores']['default_request']['hits']);
2180          $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['sets'] -
2181                               $startstats[$requestid]['stores']['default_request']['sets']);
2182  
2183          $startstats = cache_helper::get_stats();
2184  
2185          // Check that stores register through get_many.
2186          $application->get_many(array('setMe1', 'setMe2'));
2187          $session->get_many(array('setMe1', 'setMe2', 'setMe3'));
2188          $request->get_many(array('setMe1', 'setMe2', 'setMe3', 'setMe4'));
2189  
2190          $endstats = cache_helper::get_stats();
2191          $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['misses'] -
2192                               $startstats[$applicationid]['stores']['default_application']['misses']);
2193          $this->assertEquals(2, $endstats[$applicationid]['stores']['default_application']['hits'] -
2194                               $startstats[$applicationid]['stores']['default_application']['hits']);
2195          $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['sets'] -
2196                               $startstats[$applicationid]['stores']['default_application']['sets']);
2197          $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['misses'] -
2198                               $startstats[$sessionid]['stores']['default_session']['misses']);
2199          $this->assertEquals(3, $endstats[$sessionid]['stores']['default_session']['hits'] -
2200                               $startstats[$sessionid]['stores']['default_session']['hits']);
2201          $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['sets'] -
2202                               $startstats[$sessionid]['stores']['default_session']['sets']);
2203          $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['misses'] -
2204                               $startstats[$requestid]['stores']['default_request']['misses']);
2205          $this->assertEquals(4, $endstats[$requestid]['stores']['default_request']['hits'] -
2206                               $startstats[$requestid]['stores']['default_request']['hits']);
2207          $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['sets'] -
2208                               $startstats[$requestid]['stores']['default_request']['sets']);
2209  
2210          $startstats = cache_helper::get_stats();
2211  
2212          // Check that stores register through set_many.
2213          $this->assertEquals(2, $application->set_many(['setMe1' => 1, 'setMe2' => 2]));
2214          $this->assertEquals(3, $session->set_many(['setMe1' => 1, 'setMe2' => 2, 'setMe3' => 3]));
2215          $this->assertEquals(4, $request->set_many(['setMe1' => 1, 'setMe2' => 2, 'setMe3' => 3, 'setMe4' => 4]));
2216  
2217          $endstats = cache_helper::get_stats();
2218  
2219          $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['misses'] -
2220              $startstats[$applicationid]['stores']['default_application']['misses']);
2221          $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['hits'] -
2222              $startstats[$applicationid]['stores']['default_application']['hits']);
2223          $this->assertEquals(2, $endstats[$applicationid]['stores']['default_application']['sets'] -
2224              $startstats[$applicationid]['stores']['default_application']['sets']);
2225          $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['misses'] -
2226              $startstats[$sessionid]['stores']['default_session']['misses']);
2227          $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['hits'] -
2228              $startstats[$sessionid]['stores']['default_session']['hits']);
2229          $this->assertEquals(3, $endstats[$sessionid]['stores']['default_session']['sets'] -
2230              $startstats[$sessionid]['stores']['default_session']['sets']);
2231          $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['misses'] -
2232              $startstats[$requestid]['stores']['default_request']['misses']);
2233          $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['hits'] -
2234              $startstats[$requestid]['stores']['default_request']['hits']);
2235          $this->assertEquals(4, $endstats[$requestid]['stores']['default_request']['sets'] -
2236              $startstats[$requestid]['stores']['default_request']['sets']);
2237      }
2238  
2239      public function test_static_cache() {
2240          global $CFG;
2241          $this->resetAfterTest(true);
2242          $CFG->perfdebug = 15;
2243  
2244          // Create cache store with static acceleration.
2245          $instance = cache_config_testing::instance();
2246          $applicationid = 'phpunit/applicationperf';
2247          $instance->phpunit_add_definition($applicationid, array(
2248              'mode' => cache_store::MODE_APPLICATION,
2249              'component' => 'phpunit',
2250              'area' => 'applicationperf',
2251              'simplekeys' => true,
2252              'staticacceleration' => true,
2253              'staticaccelerationsize' => 3
2254          ));
2255  
2256          $application = cache::make('phpunit', 'applicationperf');
2257  
2258          // Check that stores register sets.
2259          $this->assertTrue($application->set('setMe1', 1));
2260          $this->assertTrue($application->set('setMe2', 0));
2261          $this->assertTrue($application->set('setMe3', array()));
2262          $this->assertTrue($application->get('setMe1') !== false);
2263          $this->assertTrue($application->get('setMe2') !== false);
2264          $this->assertTrue($application->get('setMe3') !== false);
2265  
2266          // Check that the static acceleration worked, even on empty arrays and the number 0.
2267          $endstats = cache_helper::get_stats();
2268          $this->assertEquals(0, $endstats[$applicationid]['stores']['** static accel. **']['misses']);
2269          $this->assertEquals(3, $endstats[$applicationid]['stores']['** static accel. **']['hits']);
2270      }
2271  
2272      public function test_performance_debug_off() {
2273          global $CFG;
2274          $this->resetAfterTest(true);
2275          $CFG->perfdebug = 7;
2276  
2277          $instance = cache_config_testing::instance();
2278          $applicationid = 'phpunit/applicationperfoff';
2279          $instance->phpunit_add_definition($applicationid, array(
2280              'mode' => cache_store::MODE_APPLICATION,
2281              'component' => 'phpunit',
2282              'area' => 'applicationperfoff'
2283          ));
2284          $sessionid = 'phpunit/sessionperfoff';
2285          $instance->phpunit_add_definition($sessionid, array(
2286              'mode' => cache_store::MODE_SESSION,
2287              'component' => 'phpunit',
2288              'area' => 'sessionperfoff'
2289          ));
2290          $requestid = 'phpunit/requestperfoff';
2291          $instance->phpunit_add_definition($requestid, array(
2292              'mode' => cache_store::MODE_REQUEST,
2293              'component' => 'phpunit',
2294              'area' => 'requestperfoff'
2295          ));
2296  
2297          $application = cache::make('phpunit', 'applicationperfoff');
2298          $session = cache::make('phpunit', 'sessionperfoff');
2299          $request = cache::make('phpunit', 'requestperfoff');
2300  
2301          // Check that no stats are recorded for these definitions yet.
2302          $stats = cache_helper::get_stats();
2303          $this->assertArrayNotHasKey($applicationid, $stats);
2304          $this->assertArrayNotHasKey($sessionid, $stats);
2305          $this->assertArrayNotHasKey($requestid, $stats);
2306  
2307          // Trigger cache misses, cache sets and cache hits.
2308          $this->assertFalse($application->get('missMe'));
2309          $this->assertTrue($application->set('setMe', 1));
2310          $this->assertEquals(1, $application->get('setMe'));
2311          $this->assertFalse($session->get('missMe'));
2312          $this->assertTrue($session->set('setMe', 3));
2313          $this->assertEquals(3, $session->get('setMe'));
2314          $this->assertFalse($request->get('missMe'));
2315          $this->assertTrue($request->set('setMe', 4));
2316          $this->assertEquals(4, $request->get('setMe'));
2317  
2318          // Check that no stats are being recorded for these definitions.
2319          $endstats = cache_helper::get_stats();
2320          $this->assertArrayNotHasKey($applicationid, $endstats);
2321          $this->assertArrayNotHasKey($sessionid, $endstats);
2322          $this->assertArrayNotHasKey($requestid, $endstats);
2323      }
2324  
2325      /**
2326       * Tests session cache event purge and subsequent visit in the same request.
2327       *
2328       * This test simulates a cache being created, a value being set, then the value being purged.
2329       * A subsequent use of the same cache is started in the same request which fills the cache.
2330       * A new request is started a short time later.
2331       * The cache should be filled.
2332       */
2333      public function test_session_event_purge_same_second() {
2334          $instance = cache_config_testing::instance();
2335          $instance->phpunit_add_definition('phpunit/eventpurgetest', array(
2336              'mode' => cache_store::MODE_SESSION,
2337              'component' => 'phpunit',
2338              'area' => 'eventpurgetest',
2339              'invalidationevents' => array(
2340                  'crazyevent',
2341              )
2342          ));
2343  
2344          // Create the cache, set a value, and immediately purge it by event.
2345          $cache = cache::make('phpunit', 'eventpurgetest');
2346          $cache->set('testkey1', 'test data 1');
2347          $this->assertEquals('test data 1', $cache->get('testkey1'));
2348          cache_helper::purge_by_event('crazyevent');
2349          $this->assertFalse($cache->get('testkey1'));
2350  
2351          // Set up the cache again in the same request and add a new value back in.
2352          $factory = cache_factory::instance();
2353          $factory->reset_cache_instances();
2354          $cache = cache::make('phpunit', 'eventpurgetest');
2355          $cache->set('testkey1', 'test data 2');
2356          $this->assertEquals('test data 2', $cache->get('testkey1'));
2357  
2358          // Trick the cache into thinking that this is a new request.
2359          cache_phpunit_cache::simulate_new_request();
2360          $factory = cache_factory::instance();
2361          $factory->reset_cache_instances();
2362  
2363          // Set up the cache again.
2364          // This is a subsequent request at a new time, so we instead the invalidation time will be checked.
2365          // The invalidation time should match the last purged time and the cache will not be re-purged.
2366          $cache = cache::make('phpunit', 'eventpurgetest');
2367          $this->assertEquals('test data 2', $cache->get('testkey1'));
2368      }
2369  
2370      /**
2371       * Test that values set in different sessions are stored with different key prefixes.
2372       */
2373      public function test_session_distinct_storage_key() {
2374          $this->resetAfterTest();
2375  
2376          // Prepare a dummy session cache configuration.
2377          $config = cache_config_testing::instance();
2378          $config->phpunit_add_definition('phpunit/test_session_distinct_storage_key', array(
2379              'mode' => cache_store::MODE_SESSION,
2380              'component' => 'phpunit',
2381              'area' => 'test_session_distinct_storage_key'
2382          ));
2383  
2384          // First anonymous user's session cache.
2385          cache_phpunit_session::phpunit_mockup_session_id('foo');
2386          $this->setUser(0);
2387          $cache1 = cache::make('phpunit', 'test_session_distinct_storage_key');
2388  
2389          // Reset cache instances to emulate a new request.
2390          cache_factory::instance()->reset_cache_instances();
2391  
2392          // Another anonymous user's session cache.
2393          cache_phpunit_session::phpunit_mockup_session_id('bar');
2394          $this->setUser(0);
2395          $cache2 = cache::make('phpunit', 'test_session_distinct_storage_key');
2396  
2397          cache_factory::instance()->reset_cache_instances();
2398  
2399          // Guest user's session cache.
2400          cache_phpunit_session::phpunit_mockup_session_id('baz');
2401          $this->setGuestUser();
2402          $cache3 = cache::make('phpunit', 'test_session_distinct_storage_key');
2403  
2404          cache_factory::instance()->reset_cache_instances();
2405  
2406          // Same guest user's session cache but in another browser window.
2407          cache_phpunit_session::phpunit_mockup_session_id('baz');
2408          $this->setGuestUser();
2409          $cache4 = cache::make('phpunit', 'test_session_distinct_storage_key');
2410  
2411          // Assert that different PHP session implies different key prefix for storing values.
2412          $this->assertNotEquals($cache1->phpunit_get_key_prefix(), $cache2->phpunit_get_key_prefix());
2413  
2414          // Assert that same PHP session implies same key prefix for storing values.
2415          $this->assertEquals($cache3->phpunit_get_key_prefix(), $cache4->phpunit_get_key_prefix());
2416      }
2417  }