Differences Between: [Versions 310 and 400] [Versions 311 and 400] [Versions 39 and 400] [Versions 400 and 401] [Versions 400 and 402] [Versions 400 and 403]
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 /** 43 * PHPunit tests for the cache API 44 * 45 * This file is part of Moodle's cache API, affectionately called MUC. 46 * It contains the components that are requried in order to use caching. 47 * 48 * @package core 49 * @category cache 50 * @copyright 2012 Sam Hemelryk 51 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 52 * @coversDefaultClass \cache 53 * @covers \cache 54 */ 55 class cache_test extends \advanced_testcase { 56 57 /** 58 * Load required libraries and fixtures. 59 */ 60 public static function setUpBeforeClass(): void { 61 global $CFG; 62 63 require_once($CFG->dirroot . '/cache/locallib.php'); 64 require_once($CFG->dirroot . '/cache/tests/fixtures/lib.php'); 65 require_once($CFG->dirroot . '/cache/tests/fixtures/cache_phpunit_dummy_datasource_versionable.php'); 66 } 67 68 /** 69 * Set things back to the default before each test. 70 */ 71 public function setUp(): void { 72 parent::setUp(); 73 cache_factory::reset(); 74 cache_config_testing::create_default_configuration(); 75 } 76 77 /** 78 * Final task is to reset the cache system 79 */ 80 public static function tearDownAfterClass(): void { 81 parent::tearDownAfterClass(); 82 cache_factory::reset(); 83 } 84 85 /** 86 * Returns the expected application cache store. 87 * @return string 88 */ 89 protected function get_expected_application_cache_store() { 90 global $CFG; 91 $expected = 'cachestore_file'; 92 93 // Verify if we are using any of the available ways to use a different application store within tests. 94 if (defined('TEST_CACHE_USING_APPLICATION_STORE') && preg_match('#[a-zA-Z][a-zA-Z0-9_]*#', TEST_CACHE_USING_APPLICATION_STORE)) { 95 // 1st way. Using some of the testing servers. 96 $expected = 'cachestore_'.(string)TEST_CACHE_USING_APPLICATION_STORE; 97 98 } else if (defined('TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH') && TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH && !empty($CFG->altcacheconfigpath)) { 99 // 2nd way. Using an alternative configuration. 100 $defaultstores = cache_helper::get_stores_suitable_for_mode_default(); 101 $instance = cache_config::instance(); 102 // Iterate over defined mode mappings until we get an application one not being the default. 103 foreach ($instance->get_mode_mappings() as $mapping) { 104 // If the store is not for application mode, ignore. 105 if ($mapping['mode'] !== cache_store::MODE_APPLICATION) { 106 continue; 107 } 108 // If the store matches some default mapping store name, ignore. 109 if (array_key_exists($mapping['store'], $defaultstores) && !empty($defaultstores[$mapping['store']]['default'])) { 110 continue; 111 } 112 // Arrived here, have found an application mode store not being the default mapped one (file), 113 // that's the one we are using in the configuration for sure. 114 $expected = 'cachestore_'.$mapping['store']; 115 } 116 } 117 118 return $expected; 119 } 120 121 /** 122 * Tests cache configuration 123 */ 124 public function test_cache_config() { 125 global $CFG; 126 127 if (defined('TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH') && TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH && 128 !empty($CFG->altcacheconfigpath)) { 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 so theres no point in running the test. 131 $this->markTestSkipped('Skipped testing default cache config structure as alt cache path is being used.'); 132 } 133 134 if (defined('TEST_CACHE_USING_APPLICATION_STORE')) { 135 // We need to skip this test - it checks the default config structure, but very likely we arn't using the 136 // default config structure here because we are testing against an alternative application store. 137 $this->markTestSkipped('Skipped testing default cache config structure as alt application store is being used.'); 138 } 139 140 $instance = cache_config::instance(); 141 $this->assertInstanceOf(cache_config_testing::class, $instance); 142 143 $this->assertTrue(cache_config_testing::config_file_exists()); 144 145 $stores = $instance->get_all_stores(); 146 $this->assertCount(3, $stores); 147 foreach ($stores as $name => $store) { 148 // Check its an array. 149 $this->assertIsArray($store); 150 // Check the name is the key. 151 $this->assertEquals($name, $store['name']); 152 // Check that it has been declared default. 153 $this->assertTrue($store['default']); 154 // Required attributes = name + plugin + configuration + modes + features. 155 $this->assertArrayHasKey('name', $store); 156 $this->assertArrayHasKey('plugin', $store); 157 $this->assertArrayHasKey('configuration', $store); 158 $this->assertArrayHasKey('modes', $store); 159 $this->assertArrayHasKey('features', $store); 160 } 161 162 $modemappings = $instance->get_mode_mappings(); 163 $this->assertCount(3, $modemappings); 164 $modes = array( 165 cache_store::MODE_APPLICATION => false, 166 cache_store::MODE_SESSION => false, 167 cache_store::MODE_REQUEST => false, 168 ); 169 foreach ($modemappings as $mapping) { 170 // We expect 3 properties. 171 $this->assertCount(3, $mapping); 172 // Required attributes = mode + store. 173 $this->assertArrayHasKey('mode', $mapping); 174 $this->assertArrayHasKey('store', $mapping); 175 // Record the mode. 176 $modes[$mapping['mode']] = true; 177 } 178 179 // Must have the default 3 modes and no more. 180 $this->assertCount(3, $mapping); 181 foreach ($modes as $mode) { 182 $this->assertTrue($mode); 183 } 184 185 $definitions = $instance->get_definitions(); 186 // The event invalidation definition is required for the cache API and must be there. 187 $this->assertArrayHasKey('core/eventinvalidation', $definitions); 188 189 $definitionmappings = $instance->get_definition_mappings(); 190 foreach ($definitionmappings as $mapping) { 191 // Required attributes = definition + store. 192 $this->assertArrayHasKey('definition', $mapping); 193 $this->assertArrayHasKey('store', $mapping); 194 } 195 } 196 197 /** 198 * Tests for cache keys that would break on windows. 199 */ 200 public function test_windows_nasty_keys() { 201 $instance = cache_config_testing::instance(); 202 $instance->phpunit_add_definition('phpunit/windowskeytest', array( 203 'mode' => cache_store::MODE_APPLICATION, 204 'component' => 'phpunit', 205 'area' => 'windowskeytest', 206 'simplekeys' => true, 207 'simpledata' => true 208 )); 209 $cache = cache::make('phpunit', 'windowskeytest'); 210 $this->assertTrue($cache->set('contest', 'test data 1')); 211 $this->assertEquals('test data 1', $cache->get('contest')); 212 } 213 214 /** 215 * Tests set_identifiers fails post cache creation. 216 * 217 * set_identifiers cannot be called after initial cache instantiation, as you need to create a difference cache. 218 */ 219 public function test_set_identifiers() { 220 $instance = cache_config_testing::instance(); 221 $instance->phpunit_add_definition('phpunit/identifier', array( 222 'mode' => cache_store::MODE_APPLICATION, 223 'component' => 'phpunit', 224 'area' => 'identifier', 225 'simplekeys' => true, 226 'simpledata' => true, 227 'staticacceleration' => true 228 )); 229 $cache = cache::make('phpunit', 'identifier', array('area')); 230 $this->assertTrue($cache->set('contest', 'test data 1')); 231 $this->assertEquals('test data 1', $cache->get('contest')); 232 233 $this->expectException('coding_exception'); 234 $cache->set_identifiers(array()); 235 } 236 237 /** 238 * Tests the default application cache 239 */ 240 public function test_default_application_cache() { 241 $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'phpunit', 'applicationtest'); 242 $this->assertInstanceOf(cache_application::class, $cache); 243 $this->run_on_cache($cache); 244 245 $instance = cache_config_testing::instance(true); 246 $instance->phpunit_add_definition('phpunit/test_default_application_cache', array( 247 'mode' => cache_store::MODE_APPLICATION, 248 'component' => 'phpunit', 249 'area' => 'test_default_application_cache', 250 'staticacceleration' => true, 251 'staticaccelerationsize' => 1 252 )); 253 $cache = cache::make('phpunit', 'test_default_application_cache'); 254 $this->assertInstanceOf(cache_application::class, $cache); 255 $this->run_on_cache($cache); 256 } 257 258 /** 259 * Tests the default session cache 260 */ 261 public function test_default_session_cache() { 262 $cache = cache::make_from_params(cache_store::MODE_SESSION, 'phpunit', 'applicationtest'); 263 $this->assertInstanceOf(cache_session::class, $cache); 264 $this->run_on_cache($cache); 265 } 266 267 /** 268 * Tests the default request cache 269 */ 270 public function test_default_request_cache() { 271 $cache = cache::make_from_params(cache_store::MODE_REQUEST, 'phpunit', 'applicationtest'); 272 $this->assertInstanceOf(cache_request::class, $cache); 273 $this->run_on_cache($cache); 274 } 275 276 /** 277 * Tests using a cache system when there are no stores available (who knows what the admin did to achieve this). 278 */ 279 public function test_on_cache_without_store() { 280 $instance = cache_config_testing::instance(true); 281 $instance->phpunit_add_definition('phpunit/nostoretest1', array( 282 'mode' => cache_store::MODE_APPLICATION, 283 'component' => 'phpunit', 284 'area' => 'nostoretest1', 285 )); 286 $instance->phpunit_add_definition('phpunit/nostoretest2', array( 287 'mode' => cache_store::MODE_APPLICATION, 288 'component' => 'phpunit', 289 'area' => 'nostoretest2', 290 'staticacceleration' => true 291 )); 292 $instance->phpunit_remove_stores(); 293 294 $cache = cache::make('phpunit', 'nostoretest1'); 295 $this->run_on_cache($cache); 296 297 $cache = cache::make('phpunit', 'nostoretest2'); 298 $this->run_on_cache($cache); 299 } 300 301 /** 302 * Runs a standard series of access and use tests on a cache instance. 303 * 304 * This function is great because we can use it to ensure all of the loaders perform exactly the same way. 305 * 306 * @param cache_loader $cache 307 */ 308 protected function run_on_cache(cache_loader $cache) { 309 $key = 'contestkey'; 310 $datascalars = array('test data', null); 311 $dataarray = array('contest' => 'data', 'part' => 'two'); 312 $dataobject = (object)$dataarray; 313 314 foreach ($datascalars as $datascalar) { 315 $this->assertTrue($cache->purge()); 316 317 // Check all read methods. 318 $this->assertFalse($cache->get($key)); 319 $this->assertFalse($cache->has($key)); 320 $result = $cache->get_many(array($key)); 321 $this->assertCount(1, $result); 322 $this->assertFalse(reset($result)); 323 $this->assertFalse($cache->has_any(array($key))); 324 $this->assertFalse($cache->has_all(array($key))); 325 326 // Set the data. 327 $this->assertTrue($cache->set($key, $datascalar)); 328 // Setting it more than once should be permitted. 329 $this->assertTrue($cache->set($key, $datascalar)); 330 331 // Recheck the read methods. 332 $this->assertEquals($datascalar, $cache->get($key)); 333 $this->assertTrue($cache->has($key)); 334 $result = $cache->get_many(array($key)); 335 $this->assertCount(1, $result); 336 $this->assertEquals($datascalar, reset($result)); 337 $this->assertTrue($cache->has_any(array($key))); 338 $this->assertTrue($cache->has_all(array($key))); 339 340 // Delete it. 341 $this->assertTrue($cache->delete($key)); 342 343 // Check its gone. 344 $this->assertFalse($cache->get($key)); 345 $this->assertFalse($cache->has($key)); 346 } 347 348 // Test arrays. 349 $this->assertTrue($cache->set($key, $dataarray)); 350 $this->assertEquals($dataarray, $cache->get($key)); 351 352 // Test objects. 353 $this->assertTrue($cache->set($key, $dataobject)); 354 $this->assertEquals($dataobject, $cache->get($key)); 355 356 $starttime = microtime(true); 357 $specobject = new cache_phpunit_dummy_object('red', 'blue', $starttime); 358 $this->assertTrue($cache->set($key, $specobject)); 359 $result = $cache->get($key); 360 $this->assertInstanceOf(cache_phpunit_dummy_object::class, $result); 361 $this->assertEquals('red_ptc_wfc', $result->property1); 362 $this->assertEquals('blue_ptc_wfc', $result->property2); 363 $this->assertGreaterThan($starttime, $result->propertytime); 364 365 // Test array of objects. 366 $specobject = new cache_phpunit_dummy_object('red', 'blue', $starttime); 367 $data = new cacheable_object_array(array( 368 clone($specobject), 369 clone($specobject), 370 clone($specobject)) 371 ); 372 $this->assertTrue($cache->set($key, $data)); 373 $result = $cache->get($key); 374 $this->assertInstanceOf(cacheable_object_array::class, $result); 375 $this->assertCount(3, $data); 376 foreach ($result as $item) { 377 $this->assertInstanceOf(cache_phpunit_dummy_object::class, $item); 378 $this->assertEquals('red_ptc_wfc', $item->property1); 379 $this->assertEquals('blue_ptc_wfc', $item->property2); 380 // Ensure that wake from cache is called in all cases. 381 $this->assertGreaterThan($starttime, $item->propertytime); 382 } 383 384 // Test set many. 385 $cache->set_many(array('key1' => 'data1', 'key2' => 'data2', 'key3' => null)); 386 $this->assertEquals('data1', $cache->get('key1')); 387 $this->assertEquals('data2', $cache->get('key2')); 388 $this->assertEquals(null, $cache->get('key3')); 389 $this->assertTrue($cache->delete('key1')); 390 $this->assertTrue($cache->delete('key2')); 391 $this->assertTrue($cache->delete('key3')); 392 393 $cache->set_many(array( 394 'key1' => array(1, 2, 3), 395 'key2' => array(3, 2, 1), 396 )); 397 $this->assertIsArray($cache->get('key1')); 398 $this->assertIsArray($cache->get('key2')); 399 $this->assertCount(3, $cache->get('key1')); 400 $this->assertCount(3, $cache->get('key2')); 401 $this->assertIsArray($cache->get_many(array('key1', 'key2'))); 402 $this->assertCount(2, $cache->get_many(array('key1', 'key2'))); 403 $this->assertEquals(2, $cache->delete_many(array('key1', 'key2'))); 404 405 // Test delete many. 406 $this->assertTrue($cache->set('key1', 'data1')); 407 $this->assertTrue($cache->set('key2', 'data2')); 408 $this->assertTrue($cache->set('key3', null)); 409 410 $this->assertEquals('data1', $cache->get('key1')); 411 $this->assertEquals('data2', $cache->get('key2')); 412 $this->assertEquals(null, $cache->get('key3')); 413 414 $this->assertEquals(3, $cache->delete_many(array('key1', 'key2', 'key3'))); 415 416 $this->assertFalse($cache->get('key1')); 417 $this->assertFalse($cache->get('key2')); 418 $this->assertFalse($cache->get('key3')); 419 420 // Quick reference test. 421 $obj = new \stdClass; 422 $obj->key = 'value'; 423 $ref =& $obj; 424 $this->assertTrue($cache->set('obj', $obj)); 425 426 $obj->key = 'eulav'; 427 $var = $cache->get('obj'); 428 $this->assertInstanceOf(\stdClass::class, $var); 429 $this->assertEquals('value', $var->key); 430 431 $ref->key = 'eulav'; 432 $var = $cache->get('obj'); 433 $this->assertInstanceOf(\stdClass::class, $var); 434 $this->assertEquals('value', $var->key); 435 436 $this->assertTrue($cache->delete('obj')); 437 438 // Deep reference test. 439 $obj1 = new \stdClass; 440 $obj1->key = 'value'; 441 $obj2 = new \stdClass; 442 $obj2->key = 'test'; 443 $obj3 = new \stdClass; 444 $obj3->key = 'pork'; 445 $obj1->subobj =& $obj2; 446 $obj2->subobj =& $obj3; 447 $this->assertTrue($cache->set('obj', $obj1)); 448 449 $obj1->key = 'eulav'; 450 $obj2->key = 'tset'; 451 $obj3->key = 'krop'; 452 $var = $cache->get('obj'); 453 $this->assertInstanceOf(\stdClass::class, $var); 454 $this->assertEquals('value', $var->key); 455 $this->assertInstanceOf(\stdClass::class, $var->subobj); 456 $this->assertEquals('test', $var->subobj->key); 457 $this->assertInstanceOf(\stdClass::class, $var->subobj->subobj); 458 $this->assertEquals('pork', $var->subobj->subobj->key); 459 $this->assertTrue($cache->delete('obj')); 460 461 // Death reference test... basically we don't want this to die. 462 $obj = new \stdClass; 463 $obj->key = 'value'; 464 $obj->self =& $obj; 465 $this->assertTrue($cache->set('obj', $obj)); 466 $var = $cache->get('obj'); 467 $this->assertInstanceOf(\stdClass::class, $var); 468 $this->assertEquals('value', $var->key); 469 470 // Reference test after retrieve. 471 $obj = new \stdClass; 472 $obj->key = 'value'; 473 $this->assertTrue($cache->set('obj', $obj)); 474 475 $var1 = $cache->get('obj'); 476 $this->assertInstanceOf(\stdClass::class, $var1); 477 $this->assertEquals('value', $var1->key); 478 $var1->key = 'eulav'; 479 $this->assertEquals('eulav', $var1->key); 480 481 $var2 = $cache->get('obj'); 482 $this->assertInstanceOf(\stdClass::class, $var2); 483 $this->assertEquals('value', $var2->key); 484 485 $this->assertTrue($cache->delete('obj')); 486 487 // Death reference test on get_many... basically we don't want this to die. 488 $obj = new \stdClass; 489 $obj->key = 'value'; 490 $obj->self =& $obj; 491 $this->assertEquals(1, $cache->set_many(array('obj' => $obj))); 492 $var = $cache->get_many(array('obj')); 493 $this->assertInstanceOf(\stdClass::class, $var['obj']); 494 $this->assertEquals('value', $var['obj']->key); 495 496 // Reference test after retrieve. 497 $obj = new \stdClass; 498 $obj->key = 'value'; 499 $this->assertEquals(1, $cache->set_many(array('obj' => $obj))); 500 501 $var1 = $cache->get_many(array('obj')); 502 $this->assertInstanceOf(\stdClass::class, $var1['obj']); 503 $this->assertEquals('value', $var1['obj']->key); 504 $var1['obj']->key = 'eulav'; 505 $this->assertEquals('eulav', $var1['obj']->key); 506 507 $var2 = $cache->get_many(array('obj')); 508 $this->assertInstanceOf(\stdClass::class, $var2['obj']); 509 $this->assertEquals('value', $var2['obj']->key); 510 511 $this->assertTrue($cache->delete('obj')); 512 513 // Test strictness exceptions. 514 try { 515 $cache->get('exception', MUST_EXIST); 516 $this->fail('Exception expected from cache::get using MUST_EXIST'); 517 } catch (\Exception $e) { 518 $this->assertTrue(true); 519 } 520 try { 521 $cache->get_many(array('exception1', 'exception2'), MUST_EXIST); 522 $this->fail('Exception expected from cache::get_many using MUST_EXIST'); 523 } catch (\Exception $e) { 524 $this->assertTrue(true); 525 } 526 $cache->set('test', 'test'); 527 try { 528 $cache->get_many(array('test', 'exception'), MUST_EXIST); 529 $this->fail('Exception expected from cache::get_many using MUST_EXIST'); 530 } catch (\Exception $e) { 531 $this->assertTrue(true); 532 } 533 } 534 535 /** 536 * Tests a definition using a data loader 537 */ 538 public function test_definition_data_loader() { 539 $instance = cache_config_testing::instance(true); 540 $instance->phpunit_add_definition('phpunit/datasourcetest', array( 541 'mode' => cache_store::MODE_APPLICATION, 542 'component' => 'phpunit', 543 'area' => 'datasourcetest', 544 'datasource' => 'cache_phpunit_dummy_datasource', 545 'datasourcefile' => 'cache/tests/fixtures/lib.php' 546 )); 547 548 $cache = cache::make('phpunit', 'datasourcetest'); 549 $this->assertInstanceOf(cache_application::class, $cache); 550 551 // Purge it to be sure. 552 $this->assertTrue($cache->purge()); 553 // It won't be there yet. 554 $this->assertFalse($cache->has('Test')); 555 // It should load it ;). 556 $this->assertTrue($cache->has('Test', true)); 557 558 // Purge it to be sure. 559 $this->assertTrue($cache->purge()); 560 $this->assertEquals('Test has no value really.', $cache->get('Test')); 561 562 // Test multiple values. 563 $this->assertTrue($cache->purge()); 564 $this->assertTrue($cache->set('b', 'B')); 565 $result = $cache->get_many(array('a', 'b', 'c')); 566 $this->assertIsArray($result); 567 $this->assertCount(3, $result); 568 $this->assertArrayHasKey('a', $result); 569 $this->assertArrayHasKey('b', $result); 570 $this->assertArrayHasKey('c', $result); 571 $this->assertEquals('a has no value really.', $result['a']); 572 $this->assertEquals('B', $result['b']); 573 $this->assertEquals('c has no value really.', $result['c']); 574 } 575 576 /** 577 * Tests a definition using a data loader with versioned keys. 578 * 579 * @covers ::get_versioned 580 * @covers ::set_versioned 581 */ 582 public function test_definition_data_loader_versioned() { 583 // Create two definitions, one using a non-versionable data source and the other using 584 // a versionable one. 585 $instance = cache_config_testing::instance(true); 586 $instance->phpunit_add_definition('phpunit/datasourcetest1', array( 587 'mode' => cache_store::MODE_APPLICATION, 588 'component' => 'phpunit', 589 'area' => 'datasourcetest1', 590 'datasource' => 'cache_phpunit_dummy_datasource', 591 'datasourcefile' => 'cache/tests/fixtures/lib.php' 592 )); 593 $instance->phpunit_add_definition('phpunit/datasourcetest2', array( 594 'mode' => cache_store::MODE_APPLICATION, 595 'component' => 'phpunit', 596 'area' => 'datasourcetest2', 597 'datasource' => 'cache_phpunit_dummy_datasource_versionable', 598 'datasourcefile' => 'cache/tests/fixtures/lib.php' 599 )); 600 601 // The first data source works for normal 'get'. 602 $cache1 = cache::make('phpunit', 'datasourcetest1'); 603 $this->assertEquals('Frog has no value really.', $cache1->get('Frog')); 604 605 // But it doesn't work for get_versioned. 606 try { 607 $cache1->get_versioned('zombie', 1); 608 $this->fail(); 609 } catch (\coding_exception $e) { 610 $this->assertStringContainsString('Data source is not versionable', $e->getMessage()); 611 } 612 613 // The second data source works for get_versioned. Set up the datasource first. 614 $cache2 = cache::make('phpunit', 'datasourcetest2'); 615 616 $datasource = \cache_phpunit_dummy_datasource_versionable::get_last_instance(); 617 $datasource->has_value('frog', 3, 'Kermit'); 618 619 // Check data with no value. 620 $this->assertFalse($cache2->get_versioned('zombie', 1)); 621 622 // Check data with value in datastore of required version. 623 $result = $cache2->get_versioned('frog', 3, IGNORE_MISSING, $actualversion); 624 $this->assertEquals('Kermit', $result); 625 $this->assertEquals(3, $actualversion); 626 627 // Check when the datastore doesn't have required version. 628 $this->assertFalse($cache2->get_versioned('frog', 4)); 629 } 630 631 /** 632 * Tests a definition using an overridden loader 633 */ 634 public function test_definition_overridden_loader() { 635 $instance = cache_config_testing::instance(true); 636 $instance->phpunit_add_definition('phpunit/overridetest', array( 637 'mode' => cache_store::MODE_APPLICATION, 638 'component' => 'phpunit', 639 'area' => 'overridetest', 640 'overrideclass' => 'cache_phpunit_dummy_overrideclass', 641 'overrideclassfile' => 'cache/tests/fixtures/lib.php' 642 )); 643 $cache = cache::make('phpunit', 'overridetest'); 644 $this->assertInstanceOf(cache_phpunit_dummy_overrideclass::class, $cache); 645 $this->assertInstanceOf(cache_application::class, $cache); 646 // Purge it to be sure. 647 $this->assertTrue($cache->purge()); 648 // It won't be there yet. 649 $this->assertFalse($cache->has('Test')); 650 // Add it. 651 $this->assertTrue($cache->set('Test', 'Test has no value really.')); 652 // Check its there. 653 $this->assertEquals('Test has no value really.', $cache->get('Test')); 654 } 655 656 /** 657 * Test the mappingsonly setting. 658 */ 659 public function test_definition_mappings_only() { 660 /** @var cache_config_testing $instance */ 661 $instance = cache_config_testing::instance(true); 662 $instance->phpunit_add_definition('phpunit/mappingsonly', array( 663 'mode' => cache_store::MODE_APPLICATION, 664 'component' => 'phpunit', 665 'area' => 'mappingsonly', 666 'mappingsonly' => true 667 ), false); 668 $instance->phpunit_add_definition('phpunit/nonmappingsonly', array( 669 'mode' => cache_store::MODE_APPLICATION, 670 'component' => 'phpunit', 671 'area' => 'nonmappingsonly', 672 'mappingsonly' => false 673 ), false); 674 675 $cacheonly = cache::make('phpunit', 'mappingsonly'); 676 $this->assertInstanceOf(cache_application::class, $cacheonly); 677 $this->assertEquals('cachestore_dummy', $cacheonly->phpunit_get_store_class()); 678 679 $expected = $this->get_expected_application_cache_store(); 680 $cachenon = cache::make('phpunit', 'nonmappingsonly'); 681 $this->assertInstanceOf(cache_application::class, $cachenon); 682 $this->assertEquals($expected, $cachenon->phpunit_get_store_class()); 683 } 684 685 /** 686 * Test a very basic definition. 687 */ 688 public function test_definition() { 689 $instance = cache_config_testing::instance(); 690 $instance->phpunit_add_definition('phpunit/test', array( 691 'mode' => cache_store::MODE_APPLICATION, 692 'component' => 'phpunit', 693 'area' => 'test', 694 )); 695 $cache = cache::make('phpunit', 'test'); 696 697 $this->assertTrue($cache->set('testkey1', 'test data 1')); 698 $this->assertEquals('test data 1', $cache->get('testkey1')); 699 $this->assertTrue($cache->set('testkey2', 'test data 2')); 700 $this->assertEquals('test data 2', $cache->get('testkey2')); 701 } 702 703 /** 704 * Test a definition using the simple keys. 705 */ 706 public function test_definition_simplekeys() { 707 $instance = cache_config_testing::instance(); 708 $instance->phpunit_add_definition('phpunit/simplekeytest', array( 709 'mode' => cache_store::MODE_APPLICATION, 710 'component' => 'phpunit', 711 'area' => 'simplekeytest', 712 'simplekeys' => true 713 )); 714 $cache = cache::make('phpunit', 'simplekeytest'); 715 716 $this->assertTrue($cache->set('testkey1', 'test data 1')); 717 $this->assertEquals('test data 1', $cache->get('testkey1')); 718 $this->assertTrue($cache->set('testkey2', 'test data 2')); 719 $this->assertEquals('test data 2', $cache->get('testkey2')); 720 721 $cache->purge(); 722 723 $this->assertTrue($cache->set('1', 'test data 1')); 724 $this->assertEquals('test data 1', $cache->get('1')); 725 $this->assertTrue($cache->set('2', 'test data 2')); 726 $this->assertEquals('test data 2', $cache->get('2')); 727 } 728 729 /** 730 * Test a negative TTL on an application cache. 731 */ 732 public function test_application_ttl_negative() { 733 $instance = cache_config_testing::instance(true); 734 $instance->phpunit_add_definition('phpunit/ttltest', array( 735 'mode' => cache_store::MODE_APPLICATION, 736 'component' => 'phpunit', 737 'area' => 'ttltest', 738 'ttl' => -86400 // Set to a day in the past to be extra sure. 739 )); 740 $cache = cache::make('phpunit', 'ttltest'); 741 $this->assertInstanceOf(cache_application::class, $cache); 742 743 // Purge it to be sure. 744 $this->assertTrue($cache->purge()); 745 // It won't be there yet. 746 $this->assertFalse($cache->has('Test')); 747 // Set it now. 748 $this->assertTrue($cache->set('Test', 'Test')); 749 // Check its not there. 750 $this->assertFalse($cache->has('Test')); 751 // Double check by trying to get it. 752 $this->assertFalse($cache->get('Test')); 753 754 // Test with multiple keys. 755 $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C'))); 756 $result = $cache->get_many(array('a', 'b', 'c')); 757 $this->assertIsArray($result); 758 $this->assertCount(3, $result); 759 $this->assertArrayHasKey('a', $result); 760 $this->assertArrayHasKey('b', $result); 761 $this->assertArrayHasKey('c', $result); 762 $this->assertFalse($result['a']); 763 $this->assertFalse($result['b']); 764 $this->assertFalse($result['c']); 765 766 // Test with multiple keys including missing ones. 767 $result = $cache->get_many(array('a', 'c', 'e')); 768 $this->assertIsArray($result); 769 $this->assertCount(3, $result); 770 $this->assertArrayHasKey('a', $result); 771 $this->assertArrayHasKey('c', $result); 772 $this->assertArrayHasKey('e', $result); 773 $this->assertFalse($result['a']); 774 $this->assertFalse($result['c']); 775 $this->assertFalse($result['e']); 776 } 777 778 /** 779 * Test a positive TTL on an application cache. 780 */ 781 public function test_application_ttl_positive() { 782 $instance = cache_config_testing::instance(true); 783 $instance->phpunit_add_definition('phpunit/ttltest', array( 784 'mode' => cache_store::MODE_APPLICATION, 785 'component' => 'phpunit', 786 'area' => 'ttltest', 787 'ttl' => 86400 // Set to a day in the future to be extra sure. 788 )); 789 $cache = cache::make('phpunit', 'ttltest'); 790 $this->assertInstanceOf(cache_application::class, $cache); 791 792 // Purge it to be sure. 793 $this->assertTrue($cache->purge()); 794 // It won't be there yet. 795 $this->assertFalse($cache->has('Test')); 796 // Set it now. 797 $this->assertTrue($cache->set('Test', 'Test')); 798 // Check its there. 799 $this->assertTrue($cache->has('Test')); 800 // Double check by trying to get it. 801 $this->assertEquals('Test', $cache->get('Test')); 802 803 // Test with multiple keys. 804 $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C'))); 805 $result = $cache->get_many(array('a', 'b', 'c')); 806 $this->assertIsArray($result); 807 $this->assertCount(3, $result); 808 $this->assertArrayHasKey('a', $result); 809 $this->assertArrayHasKey('b', $result); 810 $this->assertArrayHasKey('c', $result); 811 $this->assertEquals('A', $result['a']); 812 $this->assertEquals('B', $result['b']); 813 $this->assertEquals('C', $result['c']); 814 815 // Test with multiple keys including missing ones. 816 $result = $cache->get_many(array('a', 'c', 'e')); 817 $this->assertIsArray($result); 818 $this->assertCount(3, $result); 819 $this->assertArrayHasKey('a', $result); 820 $this->assertArrayHasKey('c', $result); 821 $this->assertArrayHasKey('e', $result); 822 $this->assertEquals('A', $result['a']); 823 $this->assertEquals('C', $result['c']); 824 $this->assertEquals(false, $result['e']); 825 } 826 827 /** 828 * Test a negative TTL on an session cache. 829 */ 830 public function test_session_ttl_positive() { 831 $instance = cache_config_testing::instance(true); 832 $instance->phpunit_add_definition('phpunit/ttltest', array( 833 'mode' => cache_store::MODE_SESSION, 834 'component' => 'phpunit', 835 'area' => 'ttltest', 836 'ttl' => 86400 // Set to a day in the future to be extra sure. 837 )); 838 $cache = cache::make('phpunit', 'ttltest'); 839 $this->assertInstanceOf(cache_session::class, $cache); 840 841 // Purge it to be sure. 842 $this->assertTrue($cache->purge()); 843 // It won't be there yet. 844 $this->assertFalse($cache->has('Test')); 845 // Set it now. 846 $this->assertTrue($cache->set('Test', 'Test')); 847 // Check its there. 848 $this->assertTrue($cache->has('Test')); 849 // Double check by trying to get it. 850 $this->assertEquals('Test', $cache->get('Test')); 851 852 // Test with multiple keys. 853 $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C'))); 854 $result = $cache->get_many(array('a', 'b', 'c')); 855 $this->assertIsArray($result); 856 $this->assertCount(3, $result); 857 $this->assertArrayHasKey('a', $result); 858 $this->assertArrayHasKey('b', $result); 859 $this->assertArrayHasKey('c', $result); 860 $this->assertEquals('A', $result['a']); 861 $this->assertEquals('B', $result['b']); 862 $this->assertEquals('C', $result['c']); 863 864 // Test with multiple keys including missing ones. 865 $result = $cache->get_many(array('a', 'c', 'e')); 866 $this->assertIsArray($result); 867 $this->assertCount(3, $result); 868 $this->assertArrayHasKey('a', $result); 869 $this->assertArrayHasKey('c', $result); 870 $this->assertArrayHasKey('e', $result); 871 $this->assertEquals('A', $result['a']); 872 $this->assertEquals('C', $result['c']); 873 $this->assertEquals(false, $result['e']); 874 } 875 876 /** 877 * Tests manual locking operations on an application cache 878 */ 879 public function test_application_manual_locking() { 880 $instance = cache_config_testing::instance(); 881 $instance->phpunit_add_definition('phpunit/lockingtest', array( 882 'mode' => cache_store::MODE_APPLICATION, 883 'component' => 'phpunit', 884 'area' => 'lockingtest' 885 )); 886 $cache1 = cache::make('phpunit', 'lockingtest'); 887 $cache2 = clone($cache1); 888 889 $this->assertTrue($cache1->set('testkey', 'test data')); 890 $this->assertTrue($cache2->set('testkey', 'test data')); 891 892 $this->assertTrue($cache1->acquire_lock('testkey')); 893 $this->assertFalse($cache2->acquire_lock('testkey')); 894 895 $this->assertTrue($cache1->check_lock_state('testkey')); 896 $this->assertFalse($cache2->check_lock_state('testkey')); 897 898 $this->assertTrue($cache1->release_lock('testkey')); 899 $this->assertFalse($cache2->release_lock('testkey')); 900 901 $this->assertTrue($cache1->set('testkey', 'test data')); 902 $this->assertTrue($cache2->set('testkey', 'test data')); 903 } 904 905 /** 906 * Tests application cache event invalidation 907 */ 908 public function test_application_event_invalidation() { 909 $instance = cache_config_testing::instance(); 910 $instance->phpunit_add_definition('phpunit/eventinvalidationtest', array( 911 'mode' => cache_store::MODE_APPLICATION, 912 'component' => 'phpunit', 913 'area' => 'eventinvalidationtest', 914 'invalidationevents' => array( 915 'crazyevent' 916 ) 917 )); 918 $cache = cache::make('phpunit', 'eventinvalidationtest'); 919 920 $this->assertTrue($cache->set('testkey1', 'test data 1')); 921 $this->assertEquals('test data 1', $cache->get('testkey1')); 922 $this->assertTrue($cache->set('testkey2', 'test data 2')); 923 $this->assertEquals('test data 2', $cache->get('testkey2')); 924 925 // Test invalidating a single entry. 926 cache_helper::invalidate_by_event('crazyevent', array('testkey1')); 927 928 $this->assertFalse($cache->get('testkey1')); 929 $this->assertEquals('test data 2', $cache->get('testkey2')); 930 931 $this->assertTrue($cache->set('testkey1', 'test data 1')); 932 933 // Test invalidating both entries. 934 cache_helper::invalidate_by_event('crazyevent', array('testkey1', 'testkey2')); 935 936 $this->assertFalse($cache->get('testkey1')); 937 $this->assertFalse($cache->get('testkey2')); 938 } 939 940 /** 941 * Tests session cache event invalidation 942 */ 943 public function test_session_event_invalidation() { 944 $instance = cache_config_testing::instance(); 945 $instance->phpunit_add_definition('phpunit/test_session_event_invalidation', array( 946 'mode' => cache_store::MODE_SESSION, 947 'component' => 'phpunit', 948 'area' => 'test_session_event_invalidation', 949 'invalidationevents' => array( 950 'crazyevent' 951 ) 952 )); 953 $cache = cache::make('phpunit', 'test_session_event_invalidation'); 954 $this->assertInstanceOf(cache_session::class, $cache); 955 956 $this->assertTrue($cache->set('testkey1', 'test data 1')); 957 $this->assertEquals('test data 1', $cache->get('testkey1')); 958 $this->assertTrue($cache->set('testkey2', 'test data 2')); 959 $this->assertEquals('test data 2', $cache->get('testkey2')); 960 961 // Test invalidating a single entry. 962 cache_helper::invalidate_by_event('crazyevent', array('testkey1')); 963 964 $this->assertFalse($cache->get('testkey1')); 965 $this->assertEquals('test data 2', $cache->get('testkey2')); 966 967 $this->assertTrue($cache->set('testkey1', 'test data 1')); 968 969 // Test invalidating both entries. 970 cache_helper::invalidate_by_event('crazyevent', array('testkey1', 'testkey2')); 971 972 $this->assertFalse($cache->get('testkey1')); 973 $this->assertFalse($cache->get('testkey2')); 974 } 975 976 /** 977 * Tests application cache definition invalidation 978 */ 979 public function test_application_definition_invalidation() { 980 $instance = cache_config_testing::instance(); 981 $instance->phpunit_add_definition('phpunit/definitioninvalidation', array( 982 'mode' => cache_store::MODE_APPLICATION, 983 'component' => 'phpunit', 984 'area' => 'definitioninvalidation' 985 )); 986 $cache = cache::make('phpunit', 'definitioninvalidation'); 987 $this->assertTrue($cache->set('testkey1', 'test data 1')); 988 $this->assertEquals('test data 1', $cache->get('testkey1')); 989 $this->assertTrue($cache->set('testkey2', 'test data 2')); 990 $this->assertEquals('test data 2', $cache->get('testkey2')); 991 992 cache_helper::invalidate_by_definition('phpunit', 'definitioninvalidation', array(), 'testkey1'); 993 994 $this->assertFalse($cache->get('testkey1')); 995 $this->assertEquals('test data 2', $cache->get('testkey2')); 996 997 $this->assertTrue($cache->set('testkey1', 'test data 1')); 998 999 cache_helper::invalidate_by_definition('phpunit', 'definitioninvalidation', array(), array('testkey1')); 1000 1001 $this->assertFalse($cache->get('testkey1')); 1002 $this->assertEquals('test data 2', $cache->get('testkey2')); 1003 1004 $this->assertTrue($cache->set('testkey1', 'test data 1')); 1005 1006 cache_helper::invalidate_by_definition('phpunit', 'definitioninvalidation', array(), array('testkey1', 'testkey2')); 1007 1008 $this->assertFalse($cache->get('testkey1')); 1009 $this->assertFalse($cache->get('testkey2')); 1010 } 1011 1012 /** 1013 * Tests session cache definition invalidation 1014 */ 1015 public function test_session_definition_invalidation() { 1016 $instance = cache_config_testing::instance(); 1017 $instance->phpunit_add_definition('phpunit/test_session_definition_invalidation', array( 1018 'mode' => cache_store::MODE_SESSION, 1019 'component' => 'phpunit', 1020 'area' => 'test_session_definition_invalidation' 1021 )); 1022 $cache = cache::make('phpunit', 'test_session_definition_invalidation'); 1023 $this->assertInstanceOf(cache_session::class, $cache); 1024 $this->assertTrue($cache->set('testkey1', 'test data 1')); 1025 $this->assertEquals('test data 1', $cache->get('testkey1')); 1026 $this->assertTrue($cache->set('testkey2', 'test data 2')); 1027 $this->assertEquals('test data 2', $cache->get('testkey2')); 1028 1029 cache_helper::invalidate_by_definition('phpunit', 'test_session_definition_invalidation', array(), 'testkey1'); 1030 1031 $this->assertFalse($cache->get('testkey1')); 1032 $this->assertEquals('test data 2', $cache->get('testkey2')); 1033 1034 $this->assertTrue($cache->set('testkey1', 'test data 1')); 1035 1036 cache_helper::invalidate_by_definition('phpunit', 'test_session_definition_invalidation', array(), 1037 array('testkey1')); 1038 1039 $this->assertFalse($cache->get('testkey1')); 1040 $this->assertEquals('test data 2', $cache->get('testkey2')); 1041 1042 $this->assertTrue($cache->set('testkey1', 'test data 1')); 1043 1044 cache_helper::invalidate_by_definition('phpunit', 'test_session_definition_invalidation', array(), 1045 array('testkey1', 'testkey2')); 1046 1047 $this->assertFalse($cache->get('testkey1')); 1048 $this->assertFalse($cache->get('testkey2')); 1049 } 1050 1051 /** 1052 * Tests application cache event invalidation over a distributed setup. 1053 */ 1054 public function test_distributed_application_event_invalidation() { 1055 global $CFG; 1056 // This is going to be an intense wee test. 1057 // We need to add data the to cache, invalidate it by event, manually force it back without MUC knowing to simulate a 1058 // disconnected/distributed setup (think load balanced server using local cache), instantiate the cache again and finally 1059 // check that it is not picked up. 1060 $instance = cache_config_testing::instance(); 1061 $instance->phpunit_add_definition('phpunit/eventinvalidationtest', array( 1062 'mode' => cache_store::MODE_APPLICATION, 1063 'component' => 'phpunit', 1064 'area' => 'eventinvalidationtest', 1065 'simplekeys' => true, 1066 'simpledata' => true, 1067 'invalidationevents' => array( 1068 'crazyevent' 1069 ) 1070 )); 1071 $cache = cache::make('phpunit', 'eventinvalidationtest'); 1072 $this->assertTrue($cache->set('testkey1', 'test data 1')); 1073 $this->assertEquals('test data 1', $cache->get('testkey1')); 1074 1075 cache_helper::invalidate_by_event('crazyevent', array('testkey1')); 1076 1077 $this->assertFalse($cache->get('testkey1')); 1078 1079 // OK data added, data invalidated, and invalidation time has been set. 1080 // Now we need to manually add back the data and adjust the invalidation time. 1081 $hash = md5(cache_store::MODE_APPLICATION.'/phpunit/eventinvalidationtest/'.$CFG->wwwroot.'phpunit'); 1082 $timefile = $CFG->dataroot."/cache/cachestore_file/default_application/phpunit_eventinvalidationtest/las-cache/lastinvalidation-$hash.cache"; 1083 // Make sure the file is correct. 1084 $this->assertTrue(file_exists($timefile)); 1085 $timecont = serialize(cache::now(true) - 60); // Back 60sec in the past to force it to re-invalidate. 1086 make_writable_directory(dirname($timefile)); 1087 file_put_contents($timefile, $timecont); 1088 $this->assertTrue(file_exists($timefile)); 1089 1090 $datafile = $CFG->dataroot."/cache/cachestore_file/default_application/phpunit_eventinvalidationtest/tes-cache/testkey1-$hash.cache"; 1091 $datacont = serialize("test data 1"); 1092 make_writable_directory(dirname($datafile)); 1093 file_put_contents($datafile, $datacont); 1094 $this->assertTrue(file_exists($datafile)); 1095 1096 // Test 1: Rebuild without the event and test its there. 1097 cache_factory::reset(); 1098 $instance = cache_config_testing::instance(); 1099 $instance->phpunit_add_definition('phpunit/eventinvalidationtest', array( 1100 'mode' => cache_store::MODE_APPLICATION, 1101 'component' => 'phpunit', 1102 'area' => 'eventinvalidationtest', 1103 'simplekeys' => true, 1104 'simpledata' => true, 1105 )); 1106 $cache = cache::make('phpunit', 'eventinvalidationtest'); 1107 $this->assertEquals('test data 1', $cache->get('testkey1')); 1108 1109 // Test 2: Rebuild and test the invalidation of the event via the invalidation cache. 1110 cache_factory::reset(); 1111 1112 $instance = cache_config_testing::instance(); 1113 $instance->phpunit_add_definition('phpunit/eventinvalidationtest', array( 1114 'mode' => cache_store::MODE_APPLICATION, 1115 'component' => 'phpunit', 1116 'area' => 'eventinvalidationtest', 1117 'simplekeys' => true, 1118 'simpledata' => true, 1119 'invalidationevents' => array( 1120 'crazyevent' 1121 ) 1122 )); 1123 1124 $cache = cache::make('phpunit', 'eventinvalidationtest'); 1125 $this->assertFalse($cache->get('testkey1')); 1126 1127 // Test 3: Verify that an existing lastinvalidation cache file is updated when needed. 1128 1129 // Make a new cache class. This should should invalidate testkey2. 1130 $cache = cache::make('phpunit', 'eventinvalidationtest'); 1131 1132 // Invalidation token should have been reset. 1133 $this->assertEquals(cache::get_purge_token(), $cache->get('lastinvalidation')); 1134 1135 // Set testkey2 data. 1136 $cache->set('testkey2', 'test data 2'); 1137 1138 // Backdate the event invalidation time by 30 seconds. 1139 $invalidationcache = cache::make('core', 'eventinvalidation'); 1140 $invalidationcache->set('crazyevent', array('testkey2' => cache::now() - 30)); 1141 1142 // Lastinvalidation should already be cache::now(). 1143 $this->assertEquals(cache::get_purge_token(), $cache->get('lastinvalidation')); 1144 1145 // Set it to 15 seconds ago so that we know if it changes. 1146 $pasttime = cache::now(true) - 15; 1147 $cache->set('lastinvalidation', $pasttime); 1148 1149 // Make a new cache class. This should not invalidate anything. 1150 cache_factory::instance()->reset_cache_instances(); 1151 $cache = cache::make('phpunit', 'eventinvalidationtest'); 1152 1153 // Lastinvalidation shouldn't change since it was already newer than invalidation event. 1154 $this->assertEquals($pasttime, $cache->get('lastinvalidation')); 1155 1156 // Now set the event invalidation to newer than the lastinvalidation time. 1157 $invalidationcache->set('crazyevent', array('testkey2' => cache::now() - 5)); 1158 // Make a new cache class. This should should invalidate testkey2. 1159 cache_factory::instance()->reset_cache_instances(); 1160 $cache = cache::make('phpunit', 'eventinvalidationtest'); 1161 // Lastinvalidation timestamp should have updated to cache::now(). 1162 $this->assertEquals(cache::get_purge_token(), $cache->get('lastinvalidation')); 1163 1164 // Now simulate a purge_by_event 5 seconds ago. 1165 $invalidationcache = cache::make('core', 'eventinvalidation'); 1166 $invalidationcache->set('crazyevent', array('purged' => cache::now(true) - 5)); 1167 // Set our lastinvalidation timestamp to 15 seconds ago. 1168 $cache->set('lastinvalidation', cache::now(true) - 15); 1169 // Make a new cache class. This should invalidate the cache. 1170 cache_factory::instance()->reset_cache_instances(); 1171 $cache = cache::make('phpunit', 'eventinvalidationtest'); 1172 // Lastinvalidation timestamp should have updated to cache::now(). 1173 $this->assertEquals(cache::get_purge_token(), $cache->get('lastinvalidation')); 1174 1175 } 1176 1177 /** 1178 * Tests application cache event purge 1179 */ 1180 public function test_application_event_purge() { 1181 $instance = cache_config_testing::instance(); 1182 $instance->phpunit_add_definition('phpunit/eventpurgetest', array( 1183 'mode' => cache_store::MODE_APPLICATION, 1184 'component' => 'phpunit', 1185 'area' => 'eventpurgetest', 1186 'invalidationevents' => array( 1187 'crazyevent' 1188 ) 1189 )); 1190 $instance->phpunit_add_definition('phpunit/eventpurgetestaccelerated', array( 1191 'mode' => cache_store::MODE_APPLICATION, 1192 'component' => 'phpunit', 1193 'area' => 'eventpurgetestaccelerated', 1194 'staticacceleration' => true, 1195 'invalidationevents' => array( 1196 'crazyevent' 1197 ) 1198 )); 1199 $cache = cache::make('phpunit', 'eventpurgetest'); 1200 1201 $this->assertTrue($cache->set('testkey1', 'test data 1')); 1202 $this->assertEquals('test data 1', $cache->get('testkey1')); 1203 $this->assertTrue($cache->set('testkey2', 'test data 2')); 1204 $this->assertEquals('test data 2', $cache->get('testkey2')); 1205 1206 // Purge the event. 1207 cache_helper::purge_by_event('crazyevent'); 1208 1209 // Check things have been removed. 1210 $this->assertFalse($cache->get('testkey1')); 1211 $this->assertFalse($cache->get('testkey2')); 1212 1213 // Now test the static acceleration array. 1214 $cache = cache::make('phpunit', 'eventpurgetestaccelerated'); 1215 $this->assertTrue($cache->set('testkey1', 'test data 1')); 1216 $this->assertEquals('test data 1', $cache->get('testkey1')); 1217 $this->assertTrue($cache->set('testkey2', 'test data 2')); 1218 $this->assertEquals('test data 2', $cache->get('testkey2')); 1219 1220 // Purge the event. 1221 cache_helper::purge_by_event('crazyevent'); 1222 1223 // Check things have been removed. 1224 $this->assertFalse($cache->get('testkey1')); 1225 $this->assertFalse($cache->get('testkey2')); 1226 } 1227 1228 /** 1229 * Tests session cache event purge 1230 */ 1231 public function test_session_event_purge() { 1232 $instance = cache_config_testing::instance(); 1233 $instance->phpunit_add_definition('phpunit/eventpurgetest', array( 1234 'mode' => cache_store::MODE_SESSION, 1235 'component' => 'phpunit', 1236 'area' => 'eventpurgetest', 1237 'invalidationevents' => array( 1238 'crazyevent' 1239 ) 1240 )); 1241 $instance->phpunit_add_definition('phpunit/eventpurgetestaccelerated', array( 1242 'mode' => cache_store::MODE_SESSION, 1243 'component' => 'phpunit', 1244 'area' => 'eventpurgetestaccelerated', 1245 'staticacceleration' => true, 1246 'invalidationevents' => array( 1247 'crazyevent' 1248 ) 1249 )); 1250 $cache = cache::make('phpunit', 'eventpurgetest'); 1251 1252 $this->assertTrue($cache->set('testkey1', 'test data 1')); 1253 $this->assertEquals('test data 1', $cache->get('testkey1')); 1254 $this->assertTrue($cache->set('testkey2', 'test data 2')); 1255 $this->assertEquals('test data 2', $cache->get('testkey2')); 1256 1257 // Purge the event. 1258 cache_helper::purge_by_event('crazyevent'); 1259 1260 // Check things have been removed. 1261 $this->assertFalse($cache->get('testkey1')); 1262 $this->assertFalse($cache->get('testkey2')); 1263 1264 // Now test the static acceleration array. 1265 $cache = cache::make('phpunit', 'eventpurgetestaccelerated'); 1266 $this->assertTrue($cache->set('testkey1', 'test data 1')); 1267 $this->assertEquals('test data 1', $cache->get('testkey1')); 1268 $this->assertTrue($cache->set('testkey2', 'test data 2')); 1269 $this->assertEquals('test data 2', $cache->get('testkey2')); 1270 1271 // Purge the event. 1272 cache_helper::purge_by_event('crazyevent'); 1273 1274 // Check things have been removed. 1275 $this->assertFalse($cache->get('testkey1')); 1276 $this->assertFalse($cache->get('testkey2')); 1277 } 1278 1279 /** 1280 * Tests application cache definition purge 1281 */ 1282 public function test_application_definition_purge() { 1283 $instance = cache_config_testing::instance(); 1284 $instance->phpunit_add_definition('phpunit/definitionpurgetest', array( 1285 'mode' => cache_store::MODE_APPLICATION, 1286 'component' => 'phpunit', 1287 'area' => 'definitionpurgetest', 1288 'invalidationevents' => array( 1289 'crazyevent' 1290 ) 1291 )); 1292 $cache = cache::make('phpunit', 'definitionpurgetest'); 1293 1294 $this->assertTrue($cache->set('testkey1', 'test data 1')); 1295 $this->assertEquals('test data 1', $cache->get('testkey1')); 1296 $this->assertTrue($cache->set('testkey2', 'test data 2')); 1297 $this->assertEquals('test data 2', $cache->get('testkey2')); 1298 1299 // Purge the event. 1300 cache_helper::purge_by_definition('phpunit', 'definitionpurgetest'); 1301 1302 // Check things have been removed. 1303 $this->assertFalse($cache->get('testkey1')); 1304 $this->assertFalse($cache->get('testkey2')); 1305 } 1306 1307 /** 1308 * Test the use of an alt path. 1309 * If we can generate a config instance we are done :) 1310 */ 1311 public function test_alt_cache_path() { 1312 global $CFG; 1313 if ((defined('TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH') && TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH) || !empty($CFG->altcacheconfigpath)) { 1314 $this->markTestSkipped('Skipped testing alt cache path as it is already being used.'); 1315 } 1316 $this->resetAfterTest(); 1317 $CFG->altcacheconfigpath = $CFG->dataroot.'/cache/altcacheconfigpath'; 1318 $instance = cache_config_testing::instance(); 1319 $this->assertInstanceOf(cache_config::class, $instance); 1320 } 1321 1322 /** 1323 * Test disabling the cache stores. 1324 */ 1325 public function test_disable_stores() { 1326 $instance = cache_config_testing::instance(); 1327 $instance->phpunit_add_definition('phpunit/disabletest1', array( 1328 'mode' => cache_store::MODE_APPLICATION, 1329 'component' => 'phpunit', 1330 'area' => 'disabletest1' 1331 )); 1332 $instance->phpunit_add_definition('phpunit/disabletest2', array( 1333 'mode' => cache_store::MODE_SESSION, 1334 'component' => 'phpunit', 1335 'area' => 'disabletest2' 1336 )); 1337 $instance->phpunit_add_definition('phpunit/disabletest3', array( 1338 'mode' => cache_store::MODE_REQUEST, 1339 'component' => 'phpunit', 1340 'area' => 'disabletest3' 1341 )); 1342 1343 $caches = array( 1344 'disabletest1' => cache::make('phpunit', 'disabletest1'), 1345 'disabletest2' => cache::make('phpunit', 'disabletest2'), 1346 'disabletest3' => cache::make('phpunit', 'disabletest3') 1347 ); 1348 1349 $this->assertInstanceOf(cache_phpunit_application::class, $caches['disabletest1']); 1350 $this->assertInstanceOf(cache_phpunit_session::class, $caches['disabletest2']); 1351 $this->assertInstanceOf(cache_phpunit_request::class, $caches['disabletest3']); 1352 1353 $this->assertEquals('cachestore_file', $caches['disabletest1']->phpunit_get_store_class()); 1354 $this->assertEquals('cachestore_session', $caches['disabletest2']->phpunit_get_store_class()); 1355 $this->assertEquals('cachestore_static', $caches['disabletest3']->phpunit_get_store_class()); 1356 1357 foreach ($caches as $cache) { 1358 $this->assertFalse($cache->get('test')); 1359 $this->assertTrue($cache->set('test', 'test')); 1360 $this->assertEquals('test', $cache->get('test')); 1361 } 1362 1363 cache_factory::disable_stores(); 1364 1365 $caches = array( 1366 'disabletest1' => cache::make('phpunit', 'disabletest1'), 1367 'disabletest2' => cache::make('phpunit', 'disabletest2'), 1368 'disabletest3' => cache::make('phpunit', 'disabletest3') 1369 ); 1370 1371 $this->assertInstanceOf(cache_phpunit_application::class, $caches['disabletest1']); 1372 $this->assertInstanceOf(cache_phpunit_session::class, $caches['disabletest2']); 1373 $this->assertInstanceOf(cache_phpunit_request::class, $caches['disabletest3']); 1374 1375 $this->assertEquals('cachestore_dummy', $caches['disabletest1']->phpunit_get_store_class()); 1376 $this->assertEquals('cachestore_dummy', $caches['disabletest2']->phpunit_get_store_class()); 1377 $this->assertEquals('cachestore_dummy', $caches['disabletest3']->phpunit_get_store_class()); 1378 1379 foreach ($caches as $cache) { 1380 $this->assertFalse($cache->get('test')); 1381 $this->assertTrue($cache->set('test', 'test')); 1382 $this->assertEquals('test', $cache->get('test')); 1383 } 1384 } 1385 1386 /** 1387 * Test disabling the cache. 1388 */ 1389 public function test_disable() { 1390 global $CFG; 1391 1392 if ((defined('TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH') && TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH) || !empty($CFG->altcacheconfigpath)) { 1393 // We can't run this test as it requires us to delete the cache configuration script which we just 1394 // cant do with a custom path in play. 1395 $this->markTestSkipped('Skipped testing cache disable functionality as alt cache path is being used.'); 1396 } 1397 1398 $configfile = $CFG->dataroot.'/muc/config.php'; 1399 1400 // The config file will not exist yet as we've not done anything with the cache. 1401 // reset_all_data removes the file and without a call to create a configuration it doesn't exist 1402 // as yet. 1403 $this->assertFileDoesNotExist($configfile); 1404 1405 // Disable the cache 1406 cache_phpunit_factory::phpunit_disable(); 1407 1408 // Check we get the expected disabled factory. 1409 $factory = cache_factory::instance(); 1410 $this->assertInstanceOf(cache_factory_disabled::class, $factory); 1411 1412 // Check we get the expected disabled config. 1413 $config = $factory->create_config_instance(); 1414 $this->assertInstanceOf(cache_config_disabled::class, $config); 1415 1416 // Check we get the expected disabled caches. 1417 $cache = cache::make('core', 'string'); 1418 $this->assertInstanceOf(cache_disabled::class, $cache); 1419 1420 // Test an application cache. 1421 $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'phpunit', 'disable'); 1422 $this->assertInstanceOf(cache_disabled::class, $cache); 1423 1424 $this->assertFalse($cache->get('test')); 1425 $this->assertFalse($cache->get_versioned('v', 1)); 1426 $this->assertFalse($cache->set('test', 'test')); 1427 $this->assertFalse($cache->set_versioned('v', 1, 'data')); 1428 $this->assertFalse($cache->delete('test')); 1429 $this->assertTrue($cache->purge()); 1430 1431 // Test a session cache. 1432 $cache = cache::make_from_params(cache_store::MODE_SESSION, 'phpunit', 'disable'); 1433 $this->assertInstanceOf(cache_disabled::class, $cache); 1434 1435 $this->assertFalse($cache->get('test')); 1436 $this->assertFalse($cache->get_versioned('v', 1)); 1437 $this->assertFalse($cache->set('test', 'test')); 1438 $this->assertFalse($cache->set_versioned('v', 1, 'data')); 1439 $this->assertFalse($cache->delete('test')); 1440 $this->assertTrue($cache->purge()); 1441 1442 // Finally test a request cache. 1443 $cache = cache::make_from_params(cache_store::MODE_REQUEST, 'phpunit', 'disable'); 1444 $this->assertInstanceOf(cache_disabled::class, $cache); 1445 1446 $this->assertFalse($cache->get('test')); 1447 $this->assertFalse($cache->get_versioned('v', 1)); 1448 $this->assertFalse($cache->set('test', 'test')); 1449 $this->assertFalse($cache->set_versioned('v', 1, 'data')); 1450 $this->assertFalse($cache->delete('test')); 1451 $this->assertTrue($cache->purge()); 1452 1453 cache_factory::reset(); 1454 1455 $factory = cache_factory::instance(true); 1456 $config = $factory->create_config_instance(); 1457 $this->assertEquals('cache_config_testing', get_class($config)); 1458 } 1459 1460 /** 1461 * Test that multiple application loaders work ok. 1462 */ 1463 public function test_multiple_application_loaders() { 1464 $instance = cache_config_testing::instance(true); 1465 $instance->phpunit_add_file_store('phpunittest1'); 1466 $instance->phpunit_add_file_store('phpunittest2'); 1467 $instance->phpunit_add_definition('phpunit/multi_loader', array( 1468 'mode' => cache_store::MODE_APPLICATION, 1469 'component' => 'phpunit', 1470 'area' => 'multi_loader' 1471 )); 1472 $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'phpunittest1', 3); 1473 $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'phpunittest2', 2); 1474 1475 $cache = cache::make('phpunit', 'multi_loader'); 1476 $this->assertInstanceOf(cache_application::class, $cache); 1477 $this->assertFalse($cache->get('test')); 1478 $this->assertTrue($cache->set('test', 'test')); 1479 $this->assertEquals('test', $cache->get('test')); 1480 $this->assertTrue($cache->delete('test')); 1481 $this->assertFalse($cache->get('test')); 1482 $this->assertTrue($cache->set('test', 'test')); 1483 $this->assertTrue($cache->purge()); 1484 $this->assertFalse($cache->get('test')); 1485 1486 // Test the many commands. 1487 $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C'))); 1488 $result = $cache->get_many(array('a', 'b', 'c')); 1489 $this->assertIsArray($result); 1490 $this->assertCount(3, $result); 1491 $this->assertArrayHasKey('a', $result); 1492 $this->assertArrayHasKey('b', $result); 1493 $this->assertArrayHasKey('c', $result); 1494 $this->assertEquals('A', $result['a']); 1495 $this->assertEquals('B', $result['b']); 1496 $this->assertEquals('C', $result['c']); 1497 $this->assertEquals($result, $cache->get_many(array('a', 'b', 'c'))); 1498 $this->assertEquals(2, $cache->delete_many(array('a', 'c'))); 1499 $result = $cache->get_many(array('a', 'b', 'c')); 1500 $this->assertIsArray($result); 1501 $this->assertCount(3, $result); 1502 $this->assertArrayHasKey('a', $result); 1503 $this->assertArrayHasKey('b', $result); 1504 $this->assertArrayHasKey('c', $result); 1505 $this->assertFalse($result['a']); 1506 $this->assertEquals('B', $result['b']); 1507 $this->assertFalse($result['c']); 1508 1509 // Test non-recursive deletes. 1510 $this->assertTrue($cache->set('test', 'test')); 1511 $this->assertSame('test', $cache->get('test')); 1512 $this->assertTrue($cache->delete('test', false)); 1513 // We should still have it on a deeper loader. 1514 $this->assertSame('test', $cache->get('test')); 1515 // Test non-recusive with many functions. 1516 $this->assertSame(3, $cache->set_many(array( 1517 'one' => 'one', 1518 'two' => 'two', 1519 'three' => 'three' 1520 ))); 1521 $this->assertSame('one', $cache->get('one')); 1522 $this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three'))); 1523 $this->assertSame(3, $cache->delete_many(array('one', 'two', 'three'), false)); 1524 $this->assertSame('one', $cache->get('one')); 1525 $this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three'))); 1526 } 1527 1528 /** 1529 * Data provider to try using a TTL or non-TTL cache. 1530 * 1531 * @return array 1532 */ 1533 public function ttl_or_not(): array { 1534 return [[false], [true]]; 1535 } 1536 1537 /** 1538 * Data provider to try using a TTL or non-TTL cache, and static acceleration or not. 1539 * 1540 * @return array 1541 */ 1542 public function ttl_and_static_acceleration_or_not(): array { 1543 return [[false, false], [false, true], [true, false], [true, true]]; 1544 } 1545 1546 /** 1547 * Data provider to try using a TTL or non-TTL cache, and simple data on or off. 1548 * 1549 * @return array 1550 */ 1551 public function ttl_and_simple_data_or_not(): array { 1552 // Same values as for ttl and static acceleration (two booleans). 1553 return $this->ttl_and_static_acceleration_or_not(); 1554 } 1555 1556 /** 1557 * Shared code to set up a two or three-layer versioned cache for testing. 1558 * 1559 * @param bool $ttl If true, sets TTL in the definition 1560 * @param bool $threelayer If true, uses a 3-layer instead of 2-layer cache 1561 * @param bool $staticacceleration If true, enables static acceleration 1562 * @param bool $simpledata If true, enables simple data 1563 * @return \cache_application Cache 1564 */ 1565 protected function create_versioned_cache(bool $ttl, bool $threelayer = false, 1566 bool $staticacceleration = false, bool $simpledata = false): \cache_application { 1567 $instance = cache_config_testing::instance(true); 1568 $instance->phpunit_add_file_store('a', false); 1569 $instance->phpunit_add_file_store('b', false); 1570 if ($threelayer) { 1571 $instance->phpunit_add_file_store('c', false); 1572 } 1573 $defarray = [ 1574 'mode' => cache_store::MODE_APPLICATION, 1575 'component' => 'phpunit', 1576 'area' => 'multi_loader' 1577 ]; 1578 if ($ttl) { 1579 $defarray['ttl'] = '600'; 1580 } 1581 if ($staticacceleration) { 1582 $defarray['staticacceleration'] = true; 1583 $defarray['staticaccelerationsize'] = 10; 1584 } 1585 if ($simpledata) { 1586 $defarray['simpledata'] = true; 1587 } 1588 $instance->phpunit_add_definition('phpunit/multi_loader', $defarray, false); 1589 $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'a', 1); 1590 $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'b', 2); 1591 if ($threelayer) { 1592 $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'c', 3); 1593 } 1594 1595 $multicache = cache::make('phpunit', 'multi_loader'); 1596 return $multicache; 1597 } 1598 1599 /** 1600 * Tests basic use of versioned cache. 1601 * 1602 * @dataProvider ttl_and_simple_data_or_not 1603 * @param bool $ttl If true, uses a TTL cache. 1604 * @param bool $simpledata If true, turns on simple data flag 1605 * @covers ::set_versioned 1606 * @covers ::get_versioned 1607 */ 1608 public function test_versioned_cache_basic(bool $ttl, bool $simpledata): void { 1609 $multicache = $this->create_versioned_cache($ttl, false, false, $simpledata); 1610 1611 $this->assertTrue($multicache->set_versioned('game', 1, 'Pooh-sticks')); 1612 1613 $result = $multicache->get_versioned('game', 1, IGNORE_MISSING, $actualversion); 1614 $this->assertEquals('Pooh-sticks', $result); 1615 $this->assertEquals(1, $actualversion); 1616 } 1617 1618 /** 1619 * Tests versioned cache with objects. 1620 * 1621 * @dataProvider ttl_and_static_acceleration_or_not 1622 * @param bool $ttl If true, uses a TTL cache. 1623 * @param bool $staticacceleration If true, enables static acceleration 1624 * @covers ::set_versioned 1625 * @covers ::get_versioned 1626 */ 1627 public function test_versioned_cache_objects(bool $ttl, bool $staticacceleration): void { 1628 $multicache = $this->create_versioned_cache($ttl, false, $staticacceleration); 1629 1630 // Set an object value. 1631 $data = (object)['game' => 'Pooh-sticks']; 1632 $this->assertTrue($multicache->set_versioned('game', 1, $data)); 1633 1634 // Get it. 1635 $result = $multicache->get_versioned('game', 1); 1636 $this->assertEquals('Pooh-sticks', $result->game); 1637 1638 // Mess about with the value in the returned object. 1639 $result->game = 'Tag'; 1640 1641 // Get it again and confirm the cached object has not been affected. 1642 $result = $multicache->get_versioned('game', 1); 1643 $this->assertEquals('Pooh-sticks', $result->game); 1644 } 1645 1646 /** 1647 * Tests requesting a version that doesn't exist. 1648 * 1649 * @dataProvider ttl_or_not 1650 * @param bool $ttl If true, uses a TTL cache. 1651 * @covers ::set_versioned 1652 * @covers ::get_versioned 1653 */ 1654 public function test_versioned_cache_not_exist(bool $ttl): void { 1655 $multicache = $this->create_versioned_cache($ttl); 1656 1657 $multicache->set_versioned('game', 1, 'Pooh-sticks'); 1658 1659 // Exists but with wrong version. 1660 $this->assertFalse($multicache->get_versioned('game', 2)); 1661 1662 // Doesn't exist at all. 1663 $this->assertFalse($multicache->get_versioned('frog', 0)); 1664 } 1665 1666 /** 1667 * Tests attempts to use get after set_version or get_version after set. 1668 * 1669 * @dataProvider ttl_or_not 1670 * @param bool $ttl If true, uses a TTL cache. 1671 * @covers ::set_versioned 1672 * @covers ::get_versioned 1673 */ 1674 public function test_versioned_cache_incompatible_versioning(bool $ttl): void { 1675 $multicache = $this->create_versioned_cache($ttl); 1676 1677 // What if you use get on a get_version cache? 1678 $multicache->set_versioned('game', 1, 'Pooh-sticks'); 1679 try { 1680 $multicache->get('game'); 1681 $this->fail(); 1682 } catch (\coding_exception $e) { 1683 $this->assertStringContainsString('Unexpectedly found versioned cache entry', $e->getMessage()); 1684 } 1685 1686 // Or get_version on a get cache? 1687 $multicache->set('toy', 'Train set'); 1688 try { 1689 $multicache->get_versioned('toy', 1); 1690 $this->fail(); 1691 } catch (\coding_exception $e) { 1692 $this->assertStringContainsString('Unexpectedly found non-versioned cache entry', $e->getMessage()); 1693 } 1694 } 1695 1696 /** 1697 * Versions are only stored once, so if you set a newer version you will always get it even 1698 * if you ask for the lower version number. 1699 * 1700 * @dataProvider ttl_or_not 1701 * @param bool $ttl If true, uses a TTL cache. 1702 * @covers ::set_versioned 1703 * @covers ::get_versioned 1704 */ 1705 public function test_versioned_cache_single_copy(bool $ttl): void { 1706 $multicache = $this->create_versioned_cache($ttl); 1707 1708 $multicache->set_versioned('game', 1, 'Pooh-sticks'); 1709 $multicache->set_versioned('game', 2, 'Tag'); 1710 $this->assertEquals('Tag', $multicache->get_versioned('game', 1, IGNORE_MISSING, $actualversion)); 1711 1712 // The reported version number matches the one returned, not requested. 1713 $this->assertEquals(2, $actualversion); 1714 } 1715 1716 /** 1717 * If the first (local) store has an outdated copy but the second (shared) store has a newer 1718 * one, then it should automatically be retrieved. 1719 * 1720 * @dataProvider ttl_or_not 1721 * @param bool $ttl If true, uses a TTL cache. 1722 * @covers ::set_versioned 1723 * @covers ::get_versioned 1724 */ 1725 public function test_versioned_cache_outdated_local(bool $ttl): void { 1726 $multicache = $this->create_versioned_cache($ttl); 1727 1728 // Set initial value to version 2, 'Tag', in both stores. 1729 $multicache->set_versioned('game', 2, 'Tag'); 1730 1731 // Get the two separate cache stores for the multi-level cache. 1732 $factory = cache_factory::instance(); 1733 $definition = $factory->create_definition('phpunit', 'multi_loader'); 1734 [0 => $storea, 1 => $storeb] = $factory->get_store_instances_in_use($definition); 1735 1736 // Simulate what happens if the shared cache is updated with a new version but the 1737 // local one still has an old version. 1738 $hashgame = cache_helper::hash_key('game', $definition); 1739 $data = 'British Bulldog'; 1740 if ($ttl) { 1741 $data = new \cache_ttl_wrapper($data, 600); 1742 } 1743 $storeb->set($hashgame, new \core_cache\version_wrapper($data, 3)); 1744 1745 // If we ask for the old one we'll get it straight off from local cache. 1746 $this->assertEquals('Tag', $multicache->get_versioned('game', 2)); 1747 1748 // But if we ask for the new one it will still get it via the shared cache. 1749 $this->assertEquals('British Bulldog', $multicache->get_versioned('game', 3)); 1750 1751 // Also, now it will have been updated in the local cache as well. 1752 $localvalue = $storea->get($hashgame); 1753 if ($ttl) { 1754 // In case the time has changed slightly since the first set, we can't do an exact 1755 // compare, so check it ignoring the time field. 1756 $this->assertEquals(3, $localvalue->version); 1757 $ttldata = $localvalue->data; 1758 $this->assertInstanceOf('cache_ttl_wrapper', $ttldata); 1759 $this->assertEquals('British Bulldog', $ttldata->data); 1760 } else { 1761 $this->assertEquals(new \core_cache\version_wrapper('British Bulldog', 3), $localvalue); 1762 } 1763 } 1764 1765 /** 1766 * When we request a newer version, older ones are automatically deleted in every level of the 1767 * cache (to save I/O if there are multiple requests, as if there is another request it will 1768 * not have to retrieve the values to find out that they're old). 1769 * 1770 * @dataProvider ttl_or_not 1771 * @param bool $ttl If true, uses a TTL cache. 1772 * @covers ::set_versioned 1773 * @covers ::get_versioned 1774 */ 1775 public function test_versioned_cache_deleting_outdated(bool $ttl): void { 1776 $multicache = $this->create_versioned_cache($ttl); 1777 1778 // Set initial value to version 2, 'Tag', in both stores. 1779 $multicache->set_versioned('game', 2, 'Tag'); 1780 1781 // Get the two separate cache stores for the multi-level cache. 1782 $factory = cache_factory::instance(); 1783 $definition = $factory->create_definition('phpunit', 'multi_loader'); 1784 [0 => $storea, 1 => $storeb] = $factory->get_store_instances_in_use($definition); 1785 1786 // If we request a newer version, then any older version should be deleted in each 1787 // cache level. 1788 $this->assertFalse($multicache->get_versioned('game', 4)); 1789 $hashgame = cache_helper::hash_key('game', $definition); 1790 $this->assertFalse($storea->get($hashgame)); 1791 $this->assertFalse($storeb->get($hashgame)); 1792 } 1793 1794 /** 1795 * Tests a versioned cache when using static cache. 1796 * 1797 * @covers ::set_versioned 1798 * @covers ::get_versioned 1799 */ 1800 public function test_versioned_cache_static(): void { 1801 $staticcache = $this->create_versioned_cache(false, false, true); 1802 1803 // Set a value in the cache, version 1. This will store it in static acceleration. 1804 $staticcache->set_versioned('game', 1, 'Pooh-sticks'); 1805 1806 // Get the first cache store (we don't need the second one for this test). 1807 $factory = cache_factory::instance(); 1808 $definition = $factory->create_definition('phpunit', 'multi_loader'); 1809 [0 => $storea] = $factory->get_store_instances_in_use($definition); 1810 1811 // Hack a newer version into cache store without directly calling set (now the static 1812 // has v1, store has v2). This simulates another client updating the cache. 1813 $hashgame = cache_helper::hash_key('game', $definition); 1814 $storea->set($hashgame, new \core_cache\version_wrapper('Tag', 2)); 1815 1816 // Get the key from the cache, v1. This will use static acceleration. 1817 $this->assertEquals('Pooh-sticks', $staticcache->get_versioned('game', 1)); 1818 1819 // Now if we ask for a newer version, it should not use the static cached one. 1820 $this->assertEquals('Tag', $staticcache->get_versioned('game', 2)); 1821 1822 // This get should have updated static acceleration, so it will be used next time without 1823 // a store request. 1824 $storea->set($hashgame, new \core_cache\version_wrapper('British Bulldog', 3)); 1825 $this->assertEquals('Tag', $staticcache->get_versioned('game', 2)); 1826 1827 // Requesting the higher version will get rid of static acceleration again. 1828 $this->assertEquals('British Bulldog', $staticcache->get_versioned('game', 3)); 1829 1830 // Finally ask for a version that doesn't exist anywhere, just to confirm it returns null. 1831 $this->assertFalse($staticcache->get_versioned('game', 4)); 1832 } 1833 1834 /** 1835 * Tests basic use of 3-layer versioned caches. 1836 * 1837 * @covers ::set_versioned 1838 * @covers ::get_versioned 1839 */ 1840 public function test_versioned_cache_3_layers_basic(): void { 1841 $multicache = $this->create_versioned_cache(false, true); 1842 1843 // Basic use of set_versioned and get_versioned. 1844 $multicache->set_versioned('game', 1, 'Pooh-sticks'); 1845 $this->assertEquals('Pooh-sticks', $multicache->get_versioned('game', 1)); 1846 1847 // What if you ask for a version that doesn't exist? 1848 $this->assertFalse($multicache->get_versioned('game', 2)); 1849 1850 // Setting a new version wipes out the old version; if you request it, you get the new one. 1851 $multicache->set_versioned('game', 2, 'Tag'); 1852 $this->assertEquals('Tag', $multicache->get_versioned('game', 1)); 1853 } 1854 1855 /** 1856 * Tests use of 3-layer versioned caches where the 3 layers currently have different versions. 1857 * 1858 * @covers ::set_versioned 1859 * @covers ::get_versioned 1860 */ 1861 public function test_versioned_cache_3_layers_different_data(): void { 1862 // Set version 2 using normal method. 1863 $multicache = $this->create_versioned_cache(false, true); 1864 $multicache->set_versioned('game', 2, 'Tag'); 1865 1866 // Get the three separate cache stores for the multi-level cache. 1867 $factory = cache_factory::instance(); 1868 $definition = $factory->create_definition('phpunit', 'multi_loader'); 1869 [0 => $storea, 1 => $storeb, 2 => $storec] = $factory->get_store_instances_in_use($definition); 1870 1871 // Set up two other versions so every level has a different version. 1872 $hashgame = cache_helper::hash_key('game', $definition); 1873 $storeb->set($hashgame, new \core_cache\version_wrapper('British Bulldog', 3)); 1874 $storec->set($hashgame, new \core_cache\version_wrapper('Hopscotch', 4)); 1875 1876 // First request can be satisfied from A; second request requires B... 1877 $this->assertEquals('Tag', $multicache->get_versioned('game', 2)); 1878 $this->assertEquals('British Bulldog', $multicache->get_versioned('game', 3)); 1879 1880 // And should update the data in A. 1881 $this->assertEquals(new \core_cache\version_wrapper('British Bulldog', 3), $storea->get($hashgame)); 1882 $this->assertEquals('British Bulldog', $multicache->get_versioned('game', 1)); 1883 1884 // But newer data should still be in C. 1885 $this->assertEquals('Hopscotch', $multicache->get_versioned('game', 4)); 1886 // Now it's stored in A and B too. 1887 $this->assertEquals(new \core_cache\version_wrapper('Hopscotch', 4), $storea->get($hashgame)); 1888 $this->assertEquals(new \core_cache\version_wrapper('Hopscotch', 4), $storeb->get($hashgame)); 1889 } 1890 1891 /** 1892 * Test that multiple application loaders work ok. 1893 */ 1894 public function test_multiple_session_loaders() { 1895 /* @var cache_config_testing $instance */ 1896 $instance = cache_config_testing::instance(true); 1897 $instance->phpunit_add_session_store('phpunittest1'); 1898 $instance->phpunit_add_session_store('phpunittest2'); 1899 $instance->phpunit_add_definition('phpunit/multi_loader', array( 1900 'mode' => cache_store::MODE_SESSION, 1901 'component' => 'phpunit', 1902 'area' => 'multi_loader' 1903 )); 1904 $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'phpunittest1', 3); 1905 $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'phpunittest2', 2); 1906 1907 $cache = cache::make('phpunit', 'multi_loader'); 1908 $this->assertInstanceOf(cache_session::class, $cache); 1909 $this->assertFalse($cache->get('test')); 1910 $this->assertTrue($cache->set('test', 'test')); 1911 $this->assertEquals('test', $cache->get('test')); 1912 $this->assertTrue($cache->delete('test')); 1913 $this->assertFalse($cache->get('test')); 1914 $this->assertTrue($cache->set('test', 'test')); 1915 $this->assertTrue($cache->purge()); 1916 $this->assertFalse($cache->get('test')); 1917 1918 // Test the many commands. 1919 $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C'))); 1920 $result = $cache->get_many(array('a', 'b', 'c')); 1921 $this->assertIsArray($result); 1922 $this->assertCount(3, $result); 1923 $this->assertArrayHasKey('a', $result); 1924 $this->assertArrayHasKey('b', $result); 1925 $this->assertArrayHasKey('c', $result); 1926 $this->assertEquals('A', $result['a']); 1927 $this->assertEquals('B', $result['b']); 1928 $this->assertEquals('C', $result['c']); 1929 $this->assertEquals($result, $cache->get_many(array('a', 'b', 'c'))); 1930 $this->assertEquals(2, $cache->delete_many(array('a', 'c'))); 1931 $result = $cache->get_many(array('a', 'b', 'c')); 1932 $this->assertIsArray($result); 1933 $this->assertCount(3, $result); 1934 $this->assertArrayHasKey('a', $result); 1935 $this->assertArrayHasKey('b', $result); 1936 $this->assertArrayHasKey('c', $result); 1937 $this->assertFalse($result['a']); 1938 $this->assertEquals('B', $result['b']); 1939 $this->assertFalse($result['c']); 1940 1941 // Test non-recursive deletes. 1942 $this->assertTrue($cache->set('test', 'test')); 1943 $this->assertSame('test', $cache->get('test')); 1944 $this->assertTrue($cache->delete('test', false)); 1945 // We should still have it on a deeper loader. 1946 $this->assertSame('test', $cache->get('test')); 1947 // Test non-recusive with many functions. 1948 $this->assertSame(3, $cache->set_many(array( 1949 'one' => 'one', 1950 'two' => 'two', 1951 'three' => 'three' 1952 ))); 1953 $this->assertSame('one', $cache->get('one')); 1954 $this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three'))); 1955 $this->assertSame(3, $cache->delete_many(array('one', 'two', 'three'), false)); 1956 $this->assertSame('one', $cache->get('one')); 1957 $this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three'))); 1958 } 1959 1960 /** 1961 * Test switching users with session caches. 1962 */ 1963 public function test_session_cache_switch_user() { 1964 $this->resetAfterTest(true); 1965 $cache = cache::make_from_params(cache_store::MODE_SESSION, 'phpunit', 'sessioncache'); 1966 $user1 = $this->getDataGenerator()->create_user(); 1967 $user2 = $this->getDataGenerator()->create_user(); 1968 1969 // Log in as the first user. 1970 $this->setUser($user1); 1971 $sesskey1 = sesskey(); 1972 1973 // Set a basic value in the cache. 1974 $cache->set('var', 1); 1975 $this->assertTrue($cache->has('var')); 1976 $this->assertEquals(1, $cache->get('var')); 1977 1978 // Change to the second user. 1979 $this->setUser($user2); 1980 $sesskey2 = sesskey(); 1981 1982 // Make sure the cache doesn't give us the data for the last user. 1983 $this->assertNotEquals($sesskey1, $sesskey2); 1984 $this->assertFalse($cache->has('var')); 1985 $this->assertEquals(false, $cache->get('var')); 1986 } 1987 1988 /** 1989 * Test switching users with session caches. 1990 */ 1991 public function test_session_cache_switch_user_application_mapping() { 1992 $this->resetAfterTest(true); 1993 $instance = cache_config_testing::instance(true); 1994 $instance->phpunit_add_file_store('testfilestore'); 1995 $instance->phpunit_add_definition('phpunit/testappsession', array( 1996 'mode' => cache_store::MODE_SESSION, 1997 'component' => 'phpunit', 1998 'area' => 'testappsession' 1999 )); 2000 $instance->phpunit_add_definition_mapping('phpunit/testappsession', 'testfilestore', 3); 2001 $cache = cache::make('phpunit', 'testappsession'); 2002 $user1 = $this->getDataGenerator()->create_user(); 2003 $user2 = $this->getDataGenerator()->create_user(); 2004 2005 // Log in as the first user. 2006 $this->setUser($user1); 2007 $sesskey1 = sesskey(); 2008 2009 // Set a basic value in the cache. 2010 $cache->set('var', 1); 2011 $this->assertTrue($cache->has('var')); 2012 $this->assertEquals(1, $cache->get('var')); 2013 2014 // Change to the second user. 2015 $this->setUser($user2); 2016 $sesskey2 = sesskey(); 2017 2018 // Make sure the cache doesn't give us the data for the last user. 2019 $this->assertNotEquals($sesskey1, $sesskey2); 2020 $this->assertFalse($cache->has('var')); 2021 $this->assertEquals(false, $cache->get('var')); 2022 } 2023 2024 /** 2025 * Test two session caches being used at once to confirm collisions don't occur. 2026 */ 2027 public function test_dual_session_caches() { 2028 $instance = cache_config_testing::instance(true); 2029 $instance->phpunit_add_definition('phpunit/testsess1', array( 2030 'mode' => cache_store::MODE_SESSION, 2031 'component' => 'phpunit', 2032 'area' => 'testsess1' 2033 )); 2034 $instance->phpunit_add_definition('phpunit/testsess2', array( 2035 'mode' => cache_store::MODE_SESSION, 2036 'component' => 'phpunit', 2037 'area' => 'testsess2' 2038 )); 2039 $cache1 = cache::make('phpunit', 'testsess1'); 2040 $cache2 = cache::make('phpunit', 'testsess2'); 2041 2042 $this->assertFalse($cache1->has('test')); 2043 $this->assertFalse($cache2->has('test')); 2044 2045 $this->assertTrue($cache1->set('test', '1')); 2046 2047 $this->assertTrue($cache1->has('test')); 2048 $this->assertFalse($cache2->has('test')); 2049 2050 $this->assertTrue($cache2->set('test', '2')); 2051 2052 $this->assertEquals(1, $cache1->get('test')); 2053 $this->assertEquals(2, $cache2->get('test')); 2054 2055 $this->assertTrue($cache1->delete('test')); 2056 } 2057 2058 /** 2059 * Test multiple session caches when switching user. 2060 */ 2061 public function test_session_cache_switch_user_multiple() { 2062 $this->resetAfterTest(true); 2063 $cache1 = cache::make_from_params(cache_store::MODE_SESSION, 'phpunit', 'sessioncache1'); 2064 $cache2 = cache::make_from_params(cache_store::MODE_SESSION, 'phpunit', 'sessioncache2'); 2065 $user1 = $this->getDataGenerator()->create_user(); 2066 $user2 = $this->getDataGenerator()->create_user(); 2067 2068 // Log in as the first user. 2069 $this->setUser($user1); 2070 $sesskey1 = sesskey(); 2071 2072 // Set a basic value in the caches. 2073 $cache1->set('var', 1); 2074 $cache2->set('var', 2); 2075 $this->assertEquals(1, $cache1->get('var')); 2076 $this->assertEquals(2, $cache2->get('var')); 2077 2078 // Change to the second user. 2079 $this->setUser($user2); 2080 $sesskey2 = sesskey(); 2081 2082 // Make sure the cache doesn't give us the data for the last user. 2083 // Also make sure that switching the user has lead to both caches being purged. 2084 $this->assertNotEquals($sesskey1, $sesskey2); 2085 $this->assertEquals(false, $cache1->get('var')); 2086 $this->assertEquals(false, $cache2->get('var')); 2087 } 2088 2089 /** 2090 * Test application locking. 2091 */ 2092 public function test_application_locking() { 2093 $instance = cache_config_testing::instance(true); 2094 $instance->phpunit_add_definition('phpunit/test_application_locking', array( 2095 'mode' => cache_store::MODE_APPLICATION, 2096 'component' => 'phpunit', 2097 'area' => 'test_application_locking', 2098 'staticacceleration' => true, 2099 'staticaccelerationsize' => 1, 2100 'requirelockingread' => true, 2101 'requirelockingwrite' => true 2102 )); 2103 $cache = cache::make('phpunit', 'test_application_locking'); 2104 $this->assertInstanceOf(cache_application::class, $cache); 2105 2106 $this->assertTrue($cache->set('a', 'A')); 2107 $this->assertTrue($cache->set('b', 'B')); 2108 $this->assertTrue($cache->set('c', 'C')); 2109 $this->assertEquals('A', $cache->get('a')); 2110 $this->assertEquals(array('b' => 'B', 'c' => 'C'), $cache->get_many(array('b', 'c'))); 2111 $this->assertTrue($cache->delete('a')); 2112 $this->assertFalse($cache->has('a')); 2113 } 2114 2115 /** 2116 * Test the static cache_helper method purge_stores_used_by_definition. 2117 */ 2118 public function test_purge_stores_used_by_definition() { 2119 $instance = cache_config_testing::instance(true); 2120 $instance->phpunit_add_definition('phpunit/test_purge_stores_used_by_definition', array( 2121 'mode' => cache_store::MODE_APPLICATION, 2122 'component' => 'phpunit', 2123 'area' => 'test_purge_stores_used_by_definition' 2124 )); 2125 $cache = cache::make('phpunit', 'test_purge_stores_used_by_definition'); 2126 $this->assertInstanceOf(cache_application::class, $cache); 2127 $this->assertTrue($cache->set('test', 'test')); 2128 unset($cache); 2129 2130 cache_helper::purge_stores_used_by_definition('phpunit', 'test_purge_stores_used_by_definition'); 2131 2132 $cache = cache::make('phpunit', 'test_purge_stores_used_by_definition'); 2133 $this->assertInstanceOf(cache_application::class, $cache); 2134 $this->assertFalse($cache->get('test')); 2135 } 2136 2137 /** 2138 * Test purge routines. 2139 */ 2140 public function test_purge_routines() { 2141 $instance = cache_config_testing::instance(true); 2142 $instance->phpunit_add_definition('phpunit/purge1', array( 2143 'mode' => cache_store::MODE_APPLICATION, 2144 'component' => 'phpunit', 2145 'area' => 'purge1' 2146 )); 2147 $instance->phpunit_add_definition('phpunit/purge2', array( 2148 'mode' => cache_store::MODE_APPLICATION, 2149 'component' => 'phpunit', 2150 'area' => 'purge2', 2151 'requireidentifiers' => array( 2152 'id' 2153 ) 2154 )); 2155 2156 $factory = cache_factory::instance(); 2157 $definition = $factory->create_definition('phpunit', 'purge1'); 2158 $this->assertFalse($definition->has_required_identifiers()); 2159 $cache = $factory->create_cache($definition); 2160 $this->assertInstanceOf(cache_application::class, $cache); 2161 $this->assertTrue($cache->set('test', 'test')); 2162 $this->assertTrue($cache->has('test')); 2163 cache_helper::purge_by_definition('phpunit', 'purge1'); 2164 $this->assertFalse($cache->has('test')); 2165 2166 $factory = cache_factory::instance(); 2167 $definition = $factory->create_definition('phpunit', 'purge2'); 2168 $this->assertTrue($definition->has_required_identifiers()); 2169 $cache = $factory->create_cache($definition); 2170 $this->assertInstanceOf(cache_application::class, $cache); 2171 $this->assertTrue($cache->set('test', 'test')); 2172 $this->assertTrue($cache->has('test')); 2173 cache_helper::purge_stores_used_by_definition('phpunit', 'purge2'); 2174 $this->assertFalse($cache->has('test')); 2175 2176 try { 2177 cache_helper::purge_by_definition('phpunit', 'purge2'); 2178 $this->fail('Should not be able to purge a definition required identifiers without providing them.'); 2179 } catch (\coding_exception $ex) { 2180 $this->assertStringContainsString('Identifier required for cache has not been provided', $ex->getMessage()); 2181 } 2182 } 2183 2184 /** 2185 * Tests that ad-hoc caches are correctly purged with a purge_all call. 2186 */ 2187 public function test_purge_all_with_adhoc_caches() { 2188 $cache = cache::make_from_params(cache_store::MODE_REQUEST, 'core_cache', 'test'); 2189 $cache->set('test', 123); 2190 cache_helper::purge_all(); 2191 $this->assertFalse($cache->get('test')); 2192 } 2193 2194 /** 2195 * Test that the default stores all support searching. 2196 */ 2197 public function test_defaults_support_searching() { 2198 $instance = cache_config_testing::instance(true); 2199 $instance->phpunit_add_definition('phpunit/search1', array( 2200 'mode' => cache_store::MODE_APPLICATION, 2201 'component' => 'phpunit', 2202 'area' => 'search1', 2203 'requiresearchable' => true 2204 )); 2205 $instance->phpunit_add_definition('phpunit/search2', array( 2206 'mode' => cache_store::MODE_SESSION, 2207 'component' => 'phpunit', 2208 'area' => 'search2', 2209 'requiresearchable' => true 2210 )); 2211 $instance->phpunit_add_definition('phpunit/search3', array( 2212 'mode' => cache_store::MODE_REQUEST, 2213 'component' => 'phpunit', 2214 'area' => 'search3', 2215 'requiresearchable' => true 2216 )); 2217 $factory = cache_factory::instance(); 2218 2219 // Test application cache is searchable. 2220 $definition = $factory->create_definition('phpunit', 'search1'); 2221 $this->assertInstanceOf(cache_definition::class, $definition); 2222 $this->assertEquals(cache_store::IS_SEARCHABLE, $definition->get_requirements_bin() & cache_store::IS_SEARCHABLE); 2223 $cache = $factory->create_cache($definition); 2224 $this->assertInstanceOf(cache_application::class, $cache); 2225 $this->assertArrayHasKey('cache_is_searchable', $cache->phpunit_get_store_implements()); 2226 2227 // Test session cache is searchable. 2228 $definition = $factory->create_definition('phpunit', 'search2'); 2229 $this->assertInstanceOf(cache_definition::class, $definition); 2230 $this->assertEquals(cache_store::IS_SEARCHABLE, $definition->get_requirements_bin() & cache_store::IS_SEARCHABLE); 2231 $cache = $factory->create_cache($definition); 2232 $this->assertInstanceOf(cache_session::class, $cache); 2233 $this->assertArrayHasKey('cache_is_searchable', $cache->phpunit_get_store_implements()); 2234 2235 // Test request cache is searchable. 2236 $definition = $factory->create_definition('phpunit', 'search3'); 2237 $this->assertInstanceOf(cache_definition::class, $definition); 2238 $this->assertEquals(cache_store::IS_SEARCHABLE, $definition->get_requirements_bin() & cache_store::IS_SEARCHABLE); 2239 $cache = $factory->create_cache($definition); 2240 $this->assertInstanceOf(cache_request::class, $cache); 2241 $this->assertArrayHasKey('cache_is_searchable', $cache->phpunit_get_store_implements()); 2242 } 2243 2244 /** 2245 * Test static acceleration 2246 * 2247 * Note: All the assertGreaterThanOrEqual() in this test should be assertGreaterThan() be because of some microtime() 2248 * resolution problems under some OSs / PHP versions, we are accepting equal as valid outcome. For more info see MDL-57147. 2249 */ 2250 public function test_static_acceleration() { 2251 $instance = cache_config_testing::instance(); 2252 $instance->phpunit_add_definition('phpunit/accelerated', array( 2253 'mode' => cache_store::MODE_APPLICATION, 2254 'component' => 'phpunit', 2255 'area' => 'accelerated', 2256 'staticacceleration' => true, 2257 'staticaccelerationsize' => 3, 2258 )); 2259 $instance->phpunit_add_definition('phpunit/accelerated2', array( 2260 'mode' => cache_store::MODE_APPLICATION, 2261 'component' => 'phpunit', 2262 'area' => 'accelerated2', 2263 'staticacceleration' => true, 2264 'staticaccelerationsize' => 3, 2265 )); 2266 $instance->phpunit_add_definition('phpunit/accelerated3', array( 2267 'mode' => cache_store::MODE_APPLICATION, 2268 'component' => 'phpunit', 2269 'area' => 'accelerated3', 2270 'staticacceleration' => true, 2271 'staticaccelerationsize' => 3, 2272 )); 2273 $instance->phpunit_add_definition('phpunit/accelerated4', array( 2274 'mode' => cache_store::MODE_APPLICATION, 2275 'component' => 'phpunit', 2276 'area' => 'accelerated4', 2277 'staticacceleration' => true, 2278 'staticaccelerationsize' => 4, 2279 )); 2280 $instance->phpunit_add_definition('phpunit/simpledataarea1', array( 2281 'mode' => cache_store::MODE_APPLICATION, 2282 'component' => 'phpunit', 2283 'area' => 'simpledataarea1', 2284 'staticacceleration' => true, 2285 'simpledata' => false 2286 )); 2287 $instance->phpunit_add_definition('phpunit/simpledataarea2', array( 2288 'mode' => cache_store::MODE_APPLICATION, 2289 'component' => 'phpunit', 2290 'area' => 'simpledataarea2', 2291 'staticacceleration' => true, 2292 'simpledata' => true 2293 )); 2294 2295 $cache = cache::make('phpunit', 'accelerated'); 2296 $this->assertInstanceOf(cache_phpunit_application::class, $cache); 2297 2298 // Set and get three elements. 2299 $this->assertTrue($cache->set('a', 'A')); 2300 $this->assertTrue($cache->set('b', 'B')); 2301 $this->assertTrue($cache->set('c', 'C')); 2302 $this->assertEquals('A', $cache->get('a')); 2303 $this->assertEquals(array('b' => 'B', 'c' => 'C'), $cache->get_many(array('b', 'c'))); 2304 2305 // Make sure all items are in static acceleration array. 2306 $this->assertEquals('A', $cache->phpunit_static_acceleration_get('a')); 2307 $this->assertEquals('B', $cache->phpunit_static_acceleration_get('b')); 2308 $this->assertEquals('C', $cache->phpunit_static_acceleration_get('c')); 2309 2310 // Add new value and make sure it is in cache and it is in array. 2311 $this->assertTrue($cache->set('d', 'D')); 2312 $this->assertEquals('D', $cache->phpunit_static_acceleration_get('d')); 2313 $this->assertEquals('D', $cache->get('d')); 2314 2315 // Now the least recent accessed item (a) is no longer in acceleration array. 2316 $this->assertFalse($cache->phpunit_static_acceleration_get('a')); 2317 $this->assertEquals('B', $cache->phpunit_static_acceleration_get('b')); 2318 $this->assertEquals('C', $cache->phpunit_static_acceleration_get('c')); 2319 2320 // Adding and deleting element. 2321 $this->assertTrue($cache->set('a', 'A')); 2322 $this->assertTrue($cache->delete('a')); 2323 $this->assertFalse($cache->phpunit_static_acceleration_get('a')); 2324 $this->assertFalse($cache->has('a')); 2325 2326 // Make sure "purge" deletes from the array as well. 2327 $cache->purge(); 2328 $this->assertFalse($cache->phpunit_static_acceleration_get('a')); 2329 $this->assertFalse($cache->phpunit_static_acceleration_get('b')); 2330 $this->assertFalse($cache->phpunit_static_acceleration_get('c')); 2331 $this->assertFalse($cache->phpunit_static_acceleration_get('d')); 2332 $this->assertFalse($cache->phpunit_static_acceleration_get('e')); 2333 2334 // Check that the array holds the last accessed items by get/set. 2335 $this->assertTrue($cache->set('a', 'A')); 2336 $this->assertTrue($cache->set('b', 'B')); 2337 $this->assertTrue($cache->set('c', 'C')); 2338 $this->assertTrue($cache->set('d', 'D')); 2339 $this->assertTrue($cache->set('e', 'E')); 2340 $this->assertFalse($cache->phpunit_static_acceleration_get('a')); 2341 $this->assertFalse($cache->phpunit_static_acceleration_get('b')); 2342 $this->assertEquals('C', $cache->phpunit_static_acceleration_get('c')); 2343 $this->assertEquals('D', $cache->phpunit_static_acceleration_get('d')); 2344 $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e')); 2345 2346 // Store a cacheable_object, get many times and ensure each time wake_for_cache is used. 2347 // Both get and get_many are tested. Two cache entries are used to ensure the times aren't 2348 // confused with multiple calls to get()/get_many(). 2349 $startmicrotime = microtime(true); 2350 $cacheableobject = new cache_phpunit_dummy_object(1, 1, $startmicrotime); 2351 $cacheableobject2 = new cache_phpunit_dummy_object(2, 2, $startmicrotime); 2352 $this->assertTrue($cache->set('a', $cacheableobject)); 2353 $this->assertTrue($cache->set('b', $cacheableobject2)); 2354 $staticaccelerationreturntime = $cache->phpunit_static_acceleration_get('a')->propertytime; 2355 $staticaccelerationreturntimeb = $cache->phpunit_static_acceleration_get('b')->propertytime; 2356 $this->assertGreaterThanOrEqual($startmicrotime, $staticaccelerationreturntime, 'Restore time of static must be newer.'); 2357 2358 // Reset the static cache without resetting backing store. 2359 $cache->phpunit_static_acceleration_purge(); 2360 2361 // Get the value from the backend store, populating the static cache. 2362 $cachevalue = $cache->get('a'); 2363 $this->assertInstanceOf(cache_phpunit_dummy_object::class, $cachevalue); 2364 $this->assertGreaterThanOrEqual($staticaccelerationreturntime, $cachevalue->propertytime); 2365 $backingstorereturntime = $cachevalue->propertytime; 2366 2367 $results = $cache->get_many(array('b')); 2368 $this->assertInstanceOf(cache_phpunit_dummy_object::class, $results['b']); 2369 $this->assertGreaterThanOrEqual($staticaccelerationreturntimeb, $results['b']->propertytime); 2370 $backingstorereturntimeb = $results['b']->propertytime; 2371 2372 // Obtain the value again and confirm that static cache is using wake_from_cache. 2373 // Upon failure, the times are not adjusted as wake_from_cache is skipped as the 2374 // value is stored serialized in the static acceleration cache. 2375 $cachevalue = $cache->phpunit_static_acceleration_get('a'); 2376 $this->assertInstanceOf(cache_phpunit_dummy_object::class, $cachevalue); 2377 $this->assertGreaterThanOrEqual($backingstorereturntime, $cachevalue->propertytime); 2378 2379 $results = $cache->get_many(array('b')); 2380 $this->assertInstanceOf(cache_phpunit_dummy_object::class, $results['b']); 2381 $this->assertGreaterThanOrEqual($backingstorereturntimeb, $results['b']->propertytime); 2382 2383 /** @var cache_phpunit_application $cache */ 2384 $cache = cache::make('phpunit', 'accelerated2'); 2385 $this->assertInstanceOf(cache_phpunit_application::class, $cache); 2386 2387 // Check that the array holds the last accessed items by get/set. 2388 $this->assertTrue($cache->set('a', 'A')); 2389 $this->assertTrue($cache->set('b', 'B')); 2390 $this->assertTrue($cache->set('c', 'C')); 2391 $this->assertTrue($cache->set('d', 'D')); 2392 $this->assertTrue($cache->set('e', 'E')); 2393 // Current keys in the array: c, d, e. 2394 $this->assertEquals('C', $cache->phpunit_static_acceleration_get('c')); 2395 $this->assertEquals('D', $cache->phpunit_static_acceleration_get('d')); 2396 $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e')); 2397 $this->assertFalse($cache->phpunit_static_acceleration_get('a')); 2398 $this->assertFalse($cache->phpunit_static_acceleration_get('b')); 2399 2400 $this->assertEquals('A', $cache->get('a')); 2401 // Current keys in the array: d, e, a. 2402 $this->assertEquals('D', $cache->phpunit_static_acceleration_get('d')); 2403 $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e')); 2404 $this->assertEquals('A', $cache->phpunit_static_acceleration_get('a')); 2405 $this->assertFalse($cache->phpunit_static_acceleration_get('b')); 2406 $this->assertFalse($cache->phpunit_static_acceleration_get('c')); 2407 2408 // Current keys in the array: d, e, a. 2409 $this->assertEquals(array('c' => 'C'), $cache->get_many(array('c'))); 2410 // Current keys in the array: e, a, c. 2411 $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e')); 2412 $this->assertEquals('A', $cache->phpunit_static_acceleration_get('a')); 2413 $this->assertEquals('C', $cache->phpunit_static_acceleration_get('c')); 2414 $this->assertFalse($cache->phpunit_static_acceleration_get('b')); 2415 $this->assertFalse($cache->phpunit_static_acceleration_get('d')); 2416 2417 2418 $cache = cache::make('phpunit', 'accelerated3'); 2419 $this->assertInstanceOf(cache_phpunit_application::class, $cache); 2420 2421 // Check that the array holds the last accessed items by get/set. 2422 $this->assertTrue($cache->set('a', 'A')); 2423 $this->assertTrue($cache->set('b', 'B')); 2424 $this->assertTrue($cache->set('c', 'C')); 2425 $this->assertTrue($cache->set('d', 'D')); 2426 $this->assertTrue($cache->set('e', 'E')); 2427 $this->assertFalse($cache->phpunit_static_acceleration_get('a')); 2428 $this->assertFalse($cache->phpunit_static_acceleration_get('b')); 2429 $this->assertEquals('C', $cache->phpunit_static_acceleration_get('c')); 2430 $this->assertEquals('D', $cache->phpunit_static_acceleration_get('d')); 2431 $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e')); 2432 2433 $this->assertTrue($cache->set('b', 'B2')); 2434 $this->assertFalse($cache->phpunit_static_acceleration_get('a')); 2435 $this->assertEquals('B2', $cache->phpunit_static_acceleration_get('b')); 2436 $this->assertFalse($cache->phpunit_static_acceleration_get('c')); 2437 $this->assertEquals('D', $cache->phpunit_static_acceleration_get('d')); 2438 $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e')); 2439 2440 $this->assertEquals(2, $cache->set_many(array('b' => 'B3', 'c' => 'C3'))); 2441 $this->assertFalse($cache->phpunit_static_acceleration_get('a')); 2442 $this->assertEquals('B3', $cache->phpunit_static_acceleration_get('b')); 2443 $this->assertEquals('C3', $cache->phpunit_static_acceleration_get('c')); 2444 $this->assertFalse($cache->phpunit_static_acceleration_get('d')); 2445 $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e')); 2446 2447 $cache = cache::make('phpunit', 'accelerated4'); 2448 $this->assertInstanceOf(cache_phpunit_application::class, $cache); 2449 $this->assertTrue($cache->set('a', 'A')); 2450 $this->assertTrue($cache->set('a', 'A')); 2451 $this->assertTrue($cache->set('a', 'A')); 2452 $this->assertTrue($cache->set('a', 'A')); 2453 $this->assertTrue($cache->set('a', 'A')); 2454 $this->assertTrue($cache->set('a', 'A')); 2455 $this->assertTrue($cache->set('a', 'A')); 2456 $this->assertEquals('A', $cache->phpunit_static_acceleration_get('a')); 2457 $this->assertEquals('A', $cache->get('a')); 2458 2459 // Setting simpledata to false objects are cloned when retrieving data. 2460 $cache = cache::make('phpunit', 'simpledataarea1'); 2461 $notreallysimple = new \stdClass(); 2462 $notreallysimple->name = 'a'; 2463 $cache->set('a', $notreallysimple); 2464 $returnedinstance1 = $cache->get('a'); 2465 $returnedinstance2 = $cache->get('a'); 2466 $returnedinstance1->name = 'b'; 2467 $this->assertEquals('a', $returnedinstance2->name); 2468 2469 // Setting simpledata to true we assume that data does not contain references. 2470 $cache = cache::make('phpunit', 'simpledataarea2'); 2471 $notreallysimple = new \stdClass(); 2472 $notreallysimple->name = 'a'; 2473 $cache->set('a', $notreallysimple); 2474 $returnedinstance1 = $cache->get('a'); 2475 $returnedinstance2 = $cache->get('a'); 2476 $returnedinstance1->name = 'b'; 2477 $this->assertEquals('b', $returnedinstance2->name); 2478 } 2479 2480 public function test_identifiers_have_separate_caches() { 2481 $cachepg = cache::make('core', 'databasemeta', array('dbfamily' => 'pgsql')); 2482 $cachepg->set(1, 'here'); 2483 $cachemy = cache::make('core', 'databasemeta', array('dbfamily' => 'mysql')); 2484 $cachemy->set(2, 'there'); 2485 $this->assertEquals('here', $cachepg->get(1)); 2486 $this->assertEquals('there', $cachemy->get(2)); 2487 $this->assertFalse($cachemy->get(1)); 2488 } 2489 2490 public function test_performance_debug() { 2491 global $CFG; 2492 $this->resetAfterTest(true); 2493 $CFG->perfdebug = 15; 2494 2495 $instance = cache_config_testing::instance(); 2496 $applicationid = 'phpunit/applicationperf'; 2497 $instance->phpunit_add_definition($applicationid, array( 2498 'mode' => cache_store::MODE_APPLICATION, 2499 'component' => 'phpunit', 2500 'area' => 'applicationperf' 2501 )); 2502 $sessionid = 'phpunit/sessionperf'; 2503 $instance->phpunit_add_definition($sessionid, array( 2504 'mode' => cache_store::MODE_SESSION, 2505 'component' => 'phpunit', 2506 'area' => 'sessionperf' 2507 )); 2508 $requestid = 'phpunit/requestperf'; 2509 $instance->phpunit_add_definition($requestid, array( 2510 'mode' => cache_store::MODE_REQUEST, 2511 'component' => 'phpunit', 2512 'area' => 'requestperf' 2513 )); 2514 2515 $application = cache::make('phpunit', 'applicationperf'); 2516 $session = cache::make('phpunit', 'sessionperf'); 2517 $request = cache::make('phpunit', 'requestperf'); 2518 2519 // Check that no stats are recorded for these definitions yet. 2520 $stats = cache_helper::get_stats(); 2521 $this->assertArrayNotHasKey($applicationid, $stats); 2522 $this->assertArrayHasKey($sessionid, $stats); // Session cache sets a key on construct. 2523 $this->assertArrayNotHasKey($requestid, $stats); 2524 2525 // Check that stores register misses. 2526 $this->assertFalse($application->get('missMe')); 2527 $this->assertFalse($application->get('missMe')); 2528 $this->assertFalse($session->get('missMe')); 2529 $this->assertFalse($session->get('missMe')); 2530 $this->assertFalse($session->get('missMe')); 2531 $this->assertFalse($request->get('missMe')); 2532 $this->assertFalse($request->get('missMe')); 2533 $this->assertFalse($request->get('missMe')); 2534 $this->assertFalse($request->get('missMe')); 2535 2536 $endstats = cache_helper::get_stats(); 2537 $this->assertEquals(2, $endstats[$applicationid]['stores']['default_application']['misses']); 2538 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['hits']); 2539 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['sets']); 2540 $this->assertEquals(3, $endstats[$sessionid]['stores']['default_session']['misses']); 2541 $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['hits']); 2542 $this->assertEquals(1, $endstats[$sessionid]['stores']['default_session']['sets']); 2543 $this->assertEquals(4, $endstats[$requestid]['stores']['default_request']['misses']); 2544 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['hits']); 2545 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['sets']); 2546 2547 $startstats = cache_helper::get_stats(); 2548 2549 // Check that stores register sets. 2550 $this->assertTrue($application->set('setMe1', 1)); 2551 $this->assertTrue($application->set('setMe2', 2)); 2552 $this->assertTrue($session->set('setMe1', 1)); 2553 $this->assertTrue($session->set('setMe2', 2)); 2554 $this->assertTrue($session->set('setMe3', 3)); 2555 $this->assertTrue($request->set('setMe1', 1)); 2556 $this->assertTrue($request->set('setMe2', 2)); 2557 $this->assertTrue($request->set('setMe3', 3)); 2558 $this->assertTrue($request->set('setMe4', 4)); 2559 2560 $endstats = cache_helper::get_stats(); 2561 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['misses'] - 2562 $startstats[$applicationid]['stores']['default_application']['misses']); 2563 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['hits'] - 2564 $startstats[$applicationid]['stores']['default_application']['hits']); 2565 $this->assertEquals(2, $endstats[$applicationid]['stores']['default_application']['sets'] - 2566 $startstats[$applicationid]['stores']['default_application']['sets']); 2567 $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['misses'] - 2568 $startstats[$sessionid]['stores']['default_session']['misses']); 2569 $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['hits'] - 2570 $startstats[$sessionid]['stores']['default_session']['hits']); 2571 $this->assertEquals(3, $endstats[$sessionid]['stores']['default_session']['sets'] - 2572 $startstats[$sessionid]['stores']['default_session']['sets']); 2573 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['misses'] - 2574 $startstats[$requestid]['stores']['default_request']['misses']); 2575 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['hits'] - 2576 $startstats[$requestid]['stores']['default_request']['hits']); 2577 $this->assertEquals(4, $endstats[$requestid]['stores']['default_request']['sets'] - 2578 $startstats[$requestid]['stores']['default_request']['sets']); 2579 2580 $startstats = cache_helper::get_stats(); 2581 2582 // Check that stores register hits. 2583 $this->assertEquals($application->get('setMe1'), 1); 2584 $this->assertEquals($application->get('setMe2'), 2); 2585 $this->assertEquals($session->get('setMe1'), 1); 2586 $this->assertEquals($session->get('setMe2'), 2); 2587 $this->assertEquals($session->get('setMe3'), 3); 2588 $this->assertEquals($request->get('setMe1'), 1); 2589 $this->assertEquals($request->get('setMe2'), 2); 2590 $this->assertEquals($request->get('setMe3'), 3); 2591 $this->assertEquals($request->get('setMe4'), 4); 2592 2593 $endstats = cache_helper::get_stats(); 2594 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['misses'] - 2595 $startstats[$applicationid]['stores']['default_application']['misses']); 2596 $this->assertEquals(2, $endstats[$applicationid]['stores']['default_application']['hits'] - 2597 $startstats[$applicationid]['stores']['default_application']['hits']); 2598 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['sets'] - 2599 $startstats[$applicationid]['stores']['default_application']['sets']); 2600 $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['misses'] - 2601 $startstats[$sessionid]['stores']['default_session']['misses']); 2602 $this->assertEquals(3, $endstats[$sessionid]['stores']['default_session']['hits'] - 2603 $startstats[$sessionid]['stores']['default_session']['hits']); 2604 $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['sets'] - 2605 $startstats[$sessionid]['stores']['default_session']['sets']); 2606 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['misses'] - 2607 $startstats[$requestid]['stores']['default_request']['misses']); 2608 $this->assertEquals(4, $endstats[$requestid]['stores']['default_request']['hits'] - 2609 $startstats[$requestid]['stores']['default_request']['hits']); 2610 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['sets'] - 2611 $startstats[$requestid]['stores']['default_request']['sets']); 2612 2613 $startstats = cache_helper::get_stats(); 2614 2615 // Check that stores register through get_many. 2616 $application->get_many(array('setMe1', 'setMe2')); 2617 $session->get_many(array('setMe1', 'setMe2', 'setMe3')); 2618 $request->get_many(array('setMe1', 'setMe2', 'setMe3', 'setMe4')); 2619 2620 $endstats = cache_helper::get_stats(); 2621 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['misses'] - 2622 $startstats[$applicationid]['stores']['default_application']['misses']); 2623 $this->assertEquals(2, $endstats[$applicationid]['stores']['default_application']['hits'] - 2624 $startstats[$applicationid]['stores']['default_application']['hits']); 2625 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['sets'] - 2626 $startstats[$applicationid]['stores']['default_application']['sets']); 2627 $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['misses'] - 2628 $startstats[$sessionid]['stores']['default_session']['misses']); 2629 $this->assertEquals(3, $endstats[$sessionid]['stores']['default_session']['hits'] - 2630 $startstats[$sessionid]['stores']['default_session']['hits']); 2631 $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['sets'] - 2632 $startstats[$sessionid]['stores']['default_session']['sets']); 2633 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['misses'] - 2634 $startstats[$requestid]['stores']['default_request']['misses']); 2635 $this->assertEquals(4, $endstats[$requestid]['stores']['default_request']['hits'] - 2636 $startstats[$requestid]['stores']['default_request']['hits']); 2637 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['sets'] - 2638 $startstats[$requestid]['stores']['default_request']['sets']); 2639 2640 $startstats = cache_helper::get_stats(); 2641 2642 // Check that stores register through set_many. 2643 $this->assertEquals(2, $application->set_many(['setMe1' => 1, 'setMe2' => 2])); 2644 $this->assertEquals(3, $session->set_many(['setMe1' => 1, 'setMe2' => 2, 'setMe3' => 3])); 2645 $this->assertEquals(4, $request->set_many(['setMe1' => 1, 'setMe2' => 2, 'setMe3' => 3, 'setMe4' => 4])); 2646 2647 $endstats = cache_helper::get_stats(); 2648 2649 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['misses'] - 2650 $startstats[$applicationid]['stores']['default_application']['misses']); 2651 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['hits'] - 2652 $startstats[$applicationid]['stores']['default_application']['hits']); 2653 $this->assertEquals(2, $endstats[$applicationid]['stores']['default_application']['sets'] - 2654 $startstats[$applicationid]['stores']['default_application']['sets']); 2655 $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['misses'] - 2656 $startstats[$sessionid]['stores']['default_session']['misses']); 2657 $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['hits'] - 2658 $startstats[$sessionid]['stores']['default_session']['hits']); 2659 $this->assertEquals(3, $endstats[$sessionid]['stores']['default_session']['sets'] - 2660 $startstats[$sessionid]['stores']['default_session']['sets']); 2661 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['misses'] - 2662 $startstats[$requestid]['stores']['default_request']['misses']); 2663 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['hits'] - 2664 $startstats[$requestid]['stores']['default_request']['hits']); 2665 $this->assertEquals(4, $endstats[$requestid]['stores']['default_request']['sets'] - 2666 $startstats[$requestid]['stores']['default_request']['sets']); 2667 } 2668 2669 /** 2670 * Data provider for static acceleration performance tests. 2671 * 2672 * @return array 2673 */ 2674 public function static_acceleration_performance_provider(): array { 2675 // Note: These are the delta values, not the absolute values. 2676 // Also note that the set will actually store the valuein the static cache immediately. 2677 $validfirst = [ 2678 'default_application' => [ 2679 'hits' => 1, 2680 'misses' => 0, 2681 ], 2682 cache_store::STATIC_ACCEL => [ 2683 'hits' => 0, 2684 'misses' => 1, 2685 ], 2686 ]; 2687 2688 $validsecond = [ 2689 'default_application' => [ 2690 'hits' => 0, 2691 'misses' => 0, 2692 ], 2693 cache_store::STATIC_ACCEL => [ 2694 'hits' => 1, 2695 'misses' => 0, 2696 ], 2697 ]; 2698 2699 $invalidfirst = [ 2700 'default_application' => [ 2701 'hits' => 0, 2702 'misses' => 1, 2703 ], 2704 cache_store::STATIC_ACCEL => [ 2705 'hits' => 0, 2706 'misses' => 1, 2707 ], 2708 ]; 2709 $invalidsecond = [ 2710 'default_application' => [ 2711 'hits' => 0, 2712 'misses' => 1, 2713 ], 2714 cache_store::STATIC_ACCEL => [ 2715 'hits' => 0, 2716 'misses' => 1, 2717 ], 2718 ];; 2719 2720 return [ 2721 'Truthy' => [ 2722 true, 2723 $validfirst, 2724 $validsecond, 2725 ], 2726 'Null' => [ 2727 null, 2728 $validfirst, 2729 $validsecond, 2730 ], 2731 'Empty Array' => [ 2732 [], 2733 $validfirst, 2734 $validsecond, 2735 ], 2736 'Empty String' => [ 2737 '', 2738 $validfirst, 2739 $validsecond, 2740 ], 2741 'False' => [ 2742 false, 2743 $invalidfirst, 2744 $invalidsecond, 2745 ], 2746 ]; 2747 } 2748 2749 /** 2750 * Test performance of static acceleration caches with values which are frequently confused with missing values. 2751 * 2752 * @dataProvider static_acceleration_performance_provider 2753 * @param mixed $value The value to test 2754 * @param array $firstfetchstats The expected stats on the first fetch 2755 * @param array $secondfetchstats The expected stats on the subsequent fetch 2756 */ 2757 public function test_static_acceleration_values_performance( 2758 $value, 2759 array $firstfetchstats, 2760 array $secondfetchstats 2761 ): void { 2762 // Note: We need to modify perfdebug to test this. 2763 global $CFG; 2764 $this->resetAfterTest(true); 2765 $CFG->perfdebug = 15; 2766 2767 $instance = cache_config_testing::instance(); 2768 $instance->phpunit_add_definition('phpunit/accelerated', [ 2769 'mode' => cache_store::MODE_APPLICATION, 2770 'component' => 'phpunit', 2771 'area' => 'accelerated', 2772 'staticacceleration' => true, 2773 'staticaccelerationsize' => 1, 2774 ]); 2775 2776 $cache = cache::make('phpunit', 'accelerated'); 2777 $this->assertInstanceOf(cache_phpunit_application::class, $cache); 2778 2779 $this->assertTrue($cache->set('value', $value)); 2780 2781 $checkstats = function( 2782 array $start, 2783 array $expectedstats 2784 ): array { 2785 $applicationid = 'phpunit/accelerated'; 2786 $endstats = cache_helper::get_stats(); 2787 2788 $start = $start[$applicationid]['stores']; 2789 $end = $endstats[$applicationid]['stores']; 2790 2791 foreach ($expectedstats as $cachename => $expected) { 2792 foreach ($expected as $type => $value) { 2793 $startvalue = array_key_exists($cachename, $start) ? $start[$cachename][$type] : 0; 2794 $endvalue = array_key_exists($cachename, $end) ? $end[$cachename][$type] : 0; 2795 $diff = $endvalue - $startvalue; 2796 $this->assertEquals( 2797 $value, 2798 $diff, 2799 "Expected $cachename $type to be $value, got $diff" 2800 ); 2801 } 2802 } 2803 2804 return $endstats; 2805 }; 2806 2807 // Reset the cache factory so that we can get the stats from a fresh instance. 2808 $factory = cache_factory::instance(); 2809 $factory->reset_cache_instances(); 2810 $cache = cache::make('phpunit', 'accelerated'); 2811 2812 // Get the initial stats. 2813 $startstats = cache_helper::get_stats(); 2814 2815 // Fetching the value the first time should seed the static cache from the application cache. 2816 $this->assertEquals($value, $cache->get('value')); 2817 $startstats = $checkstats($startstats, $firstfetchstats); 2818 2819 // Fetching the value should only hit the static cache. 2820 $this->assertEquals($value, $cache->get('value')); 2821 $checkstats($startstats, $secondfetchstats); 2822 } 2823 2824 2825 public function test_static_cache() { 2826 global $CFG; 2827 $this->resetAfterTest(true); 2828 $CFG->perfdebug = 15; 2829 2830 // Create cache store with static acceleration. 2831 $instance = cache_config_testing::instance(); 2832 $applicationid = 'phpunit/applicationperf'; 2833 $instance->phpunit_add_definition($applicationid, array( 2834 'mode' => cache_store::MODE_APPLICATION, 2835 'component' => 'phpunit', 2836 'area' => 'applicationperf', 2837 'simplekeys' => true, 2838 'staticacceleration' => true, 2839 'staticaccelerationsize' => 3 2840 )); 2841 2842 $application = cache::make('phpunit', 'applicationperf'); 2843 2844 // Check that stores register sets. 2845 $this->assertTrue($application->set('setMe1', 1)); 2846 $this->assertTrue($application->set('setMe2', 0)); 2847 $this->assertTrue($application->set('setMe3', array())); 2848 $this->assertTrue($application->get('setMe1') !== false); 2849 $this->assertTrue($application->get('setMe2') !== false); 2850 $this->assertTrue($application->get('setMe3') !== false); 2851 2852 // Check that the static acceleration worked, even on empty arrays and the number 0. 2853 $endstats = cache_helper::get_stats(); 2854 $this->assertEquals(0, $endstats[$applicationid]['stores']['** static accel. **']['misses']); 2855 $this->assertEquals(3, $endstats[$applicationid]['stores']['** static accel. **']['hits']); 2856 } 2857 2858 public function test_performance_debug_off() { 2859 global $CFG; 2860 $this->resetAfterTest(true); 2861 $CFG->perfdebug = 7; 2862 2863 $instance = cache_config_testing::instance(); 2864 $applicationid = 'phpunit/applicationperfoff'; 2865 $instance->phpunit_add_definition($applicationid, array( 2866 'mode' => cache_store::MODE_APPLICATION, 2867 'component' => 'phpunit', 2868 'area' => 'applicationperfoff' 2869 )); 2870 $sessionid = 'phpunit/sessionperfoff'; 2871 $instance->phpunit_add_definition($sessionid, array( 2872 'mode' => cache_store::MODE_SESSION, 2873 'component' => 'phpunit', 2874 'area' => 'sessionperfoff' 2875 )); 2876 $requestid = 'phpunit/requestperfoff'; 2877 $instance->phpunit_add_definition($requestid, array( 2878 'mode' => cache_store::MODE_REQUEST, 2879 'component' => 'phpunit', 2880 'area' => 'requestperfoff' 2881 )); 2882 2883 $application = cache::make('phpunit', 'applicationperfoff'); 2884 $session = cache::make('phpunit', 'sessionperfoff'); 2885 $request = cache::make('phpunit', 'requestperfoff'); 2886 2887 // Check that no stats are recorded for these definitions yet. 2888 $stats = cache_helper::get_stats(); 2889 $this->assertArrayNotHasKey($applicationid, $stats); 2890 $this->assertArrayNotHasKey($sessionid, $stats); 2891 $this->assertArrayNotHasKey($requestid, $stats); 2892 2893 // Trigger cache misses, cache sets and cache hits. 2894 $this->assertFalse($application->get('missMe')); 2895 $this->assertTrue($application->set('setMe', 1)); 2896 $this->assertEquals(1, $application->get('setMe')); 2897 $this->assertFalse($session->get('missMe')); 2898 $this->assertTrue($session->set('setMe', 3)); 2899 $this->assertEquals(3, $session->get('setMe')); 2900 $this->assertFalse($request->get('missMe')); 2901 $this->assertTrue($request->set('setMe', 4)); 2902 $this->assertEquals(4, $request->get('setMe')); 2903 2904 // Check that no stats are being recorded for these definitions. 2905 $endstats = cache_helper::get_stats(); 2906 $this->assertArrayNotHasKey($applicationid, $endstats); 2907 $this->assertArrayNotHasKey($sessionid, $endstats); 2908 $this->assertArrayNotHasKey($requestid, $endstats); 2909 } 2910 2911 /** 2912 * Tests session cache event purge and subsequent visit in the same request. 2913 * 2914 * This test simulates a cache being created, a value being set, then the value being purged. 2915 * A subsequent use of the same cache is started in the same request which fills the cache. 2916 * A new request is started a short time later. 2917 * The cache should be filled. 2918 */ 2919 public function test_session_event_purge_same_second() { 2920 $instance = cache_config_testing::instance(); 2921 $instance->phpunit_add_definition('phpunit/eventpurgetest', array( 2922 'mode' => cache_store::MODE_SESSION, 2923 'component' => 'phpunit', 2924 'area' => 'eventpurgetest', 2925 'invalidationevents' => array( 2926 'crazyevent', 2927 ) 2928 )); 2929 2930 // Create the cache, set a value, and immediately purge it by event. 2931 $cache = cache::make('phpunit', 'eventpurgetest'); 2932 $cache->set('testkey1', 'test data 1'); 2933 $this->assertEquals('test data 1', $cache->get('testkey1')); 2934 cache_helper::purge_by_event('crazyevent'); 2935 $this->assertFalse($cache->get('testkey1')); 2936 2937 // Set up the cache again in the same request and add a new value back in. 2938 $factory = cache_factory::instance(); 2939 $factory->reset_cache_instances(); 2940 $cache = cache::make('phpunit', 'eventpurgetest'); 2941 $cache->set('testkey1', 'test data 2'); 2942 $this->assertEquals('test data 2', $cache->get('testkey1')); 2943 2944 // Trick the cache into thinking that this is a new request. 2945 cache_phpunit_cache::simulate_new_request(); 2946 $factory = cache_factory::instance(); 2947 $factory->reset_cache_instances(); 2948 2949 // Set up the cache again. 2950 // This is a subsequent request at a new time, so we instead the invalidation time will be checked. 2951 // The invalidation time should match the last purged time and the cache will not be re-purged. 2952 $cache = cache::make('phpunit', 'eventpurgetest'); 2953 $this->assertEquals('test data 2', $cache->get('testkey1')); 2954 } 2955 2956 /** 2957 * Test that values set in different sessions are stored with different key prefixes. 2958 */ 2959 public function test_session_distinct_storage_key() { 2960 $this->resetAfterTest(); 2961 2962 // Prepare a dummy session cache configuration. 2963 $config = cache_config_testing::instance(); 2964 $config->phpunit_add_definition('phpunit/test_session_distinct_storage_key', array( 2965 'mode' => cache_store::MODE_SESSION, 2966 'component' => 'phpunit', 2967 'area' => 'test_session_distinct_storage_key' 2968 )); 2969 2970 // First anonymous user's session cache. 2971 cache_phpunit_session::phpunit_mockup_session_id('foo'); 2972 $this->setUser(0); 2973 $cache1 = cache::make('phpunit', 'test_session_distinct_storage_key'); 2974 2975 // Reset cache instances to emulate a new request. 2976 cache_factory::instance()->reset_cache_instances(); 2977 2978 // Another anonymous user's session cache. 2979 cache_phpunit_session::phpunit_mockup_session_id('bar'); 2980 $this->setUser(0); 2981 $cache2 = cache::make('phpunit', 'test_session_distinct_storage_key'); 2982 2983 cache_factory::instance()->reset_cache_instances(); 2984 2985 // Guest user's session cache. 2986 cache_phpunit_session::phpunit_mockup_session_id('baz'); 2987 $this->setGuestUser(); 2988 $cache3 = cache::make('phpunit', 'test_session_distinct_storage_key'); 2989 2990 cache_factory::instance()->reset_cache_instances(); 2991 2992 // Same guest user's session cache but in another browser window. 2993 cache_phpunit_session::phpunit_mockup_session_id('baz'); 2994 $this->setGuestUser(); 2995 $cache4 = cache::make('phpunit', 'test_session_distinct_storage_key'); 2996 2997 // Assert that different PHP session implies different key prefix for storing values. 2998 $this->assertNotEquals($cache1->phpunit_get_key_prefix(), $cache2->phpunit_get_key_prefix()); 2999 3000 // Assert that same PHP session implies same key prefix for storing values. 3001 $this->assertEquals($cache3->phpunit_get_key_prefix(), $cache4->phpunit_get_key_prefix()); 3002 } 3003 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body