2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
20 use cache_application
;
22 use cache_config_disabled
;
23 use cache_config_testing
;
27 use cache_factory_disabled
;
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
;
40 use cacheable_object_array
;
43 * PHPunit tests for the cache API
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.
50 * @copyright 2012 Sam Hemelryk
51 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
52 * @coversDefaultClass \cache
54 class cache_test
extends \advanced_testcase
{
57 * Load required libraries and fixtures.
59 public static function setUpBeforeClass(): void
{
62 require_once($CFG->dirroot
. '/cache/locallib.php');
63 require_once($CFG->dirroot
. '/cache/tests/fixtures/lib.php');
64 require_once($CFG->dirroot
. '/cache/tests/fixtures/cache_phpunit_dummy_datasource_versionable.php');
68 * Set things back to the default before each test.
70 public function setUp(): void
{
72 cache_factory
::reset();
73 cache_config_testing
::create_default_configuration();
77 * Final task is to reset the cache system
79 public static function tearDownAfterClass(): void
{
80 parent
::tearDownAfterClass();
81 cache_factory
::reset();
85 * Returns the expected application cache store.
88 protected function get_expected_application_cache_store() {
90 $expected = 'cachestore_file';
92 // Verify if we are using any of the available ways to use a different application store within tests.
93 if (defined('TEST_CACHE_USING_APPLICATION_STORE') && preg_match('#[a-zA-Z][a-zA-Z0-9_]*#', TEST_CACHE_USING_APPLICATION_STORE
)) {
94 // 1st way. Using some of the testing servers.
95 $expected = 'cachestore_'.(string)TEST_CACHE_USING_APPLICATION_STORE
;
97 } else if (defined('TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH') && TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH
&& !empty($CFG->altcacheconfigpath
)) {
98 // 2nd way. Using an alternative configuration.
99 $defaultstores = cache_helper
::get_stores_suitable_for_mode_default();
100 $instance = cache_config
::instance();
101 // Iterate over defined mode mappings until we get an application one not being the default.
102 foreach ($instance->get_mode_mappings() as $mapping) {
103 // If the store is not for application mode, ignore.
104 if ($mapping['mode'] !== cache_store
::MODE_APPLICATION
) {
107 // If the store matches some default mapping store name, ignore.
108 if (array_key_exists($mapping['store'], $defaultstores) && !empty($defaultstores[$mapping['store']]['default'])) {
111 // Arrived here, have found an application mode store not being the default mapped one (file),
112 // that's the one we are using in the configuration for sure.
113 $expected = 'cachestore_'.$mapping['store'];
121 * Tests cache configuration
123 public function test_cache_config() {
126 if (defined('TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH') && TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH
&&
127 !empty($CFG->altcacheconfigpath
)) {
128 // We need to skip this test - it checks the default config structure, but very likely we arn't using the
129 // default config structure here so theres no point in running the test.
130 $this->markTestSkipped('Skipped testing default cache config structure as alt cache path is being used.');
133 if (defined('TEST_CACHE_USING_APPLICATION_STORE')) {
134 // We need to skip this test - it checks the default config structure, but very likely we arn't using the
135 // default config structure here because we are testing against an alternative application store.
136 $this->markTestSkipped('Skipped testing default cache config structure as alt application store is being used.');
139 $instance = cache_config
::instance();
140 $this->assertInstanceOf(cache_config_testing
::class, $instance);
142 $this->assertTrue(cache_config_testing
::config_file_exists());
144 $stores = $instance->get_all_stores();
145 $this->assertCount(3, $stores);
146 foreach ($stores as $name => $store) {
147 // Check its an array.
148 $this->assertIsArray($store);
149 // Check the name is the key.
150 $this->assertEquals($name, $store['name']);
151 // Check that it has been declared default.
152 $this->assertTrue($store['default']);
153 // Required attributes = name + plugin + configuration + modes + features.
154 $this->assertArrayHasKey('name', $store);
155 $this->assertArrayHasKey('plugin', $store);
156 $this->assertArrayHasKey('configuration', $store);
157 $this->assertArrayHasKey('modes', $store);
158 $this->assertArrayHasKey('features', $store);
161 $modemappings = $instance->get_mode_mappings();
162 $this->assertCount(3, $modemappings);
164 cache_store
::MODE_APPLICATION
=> false,
165 cache_store
::MODE_SESSION
=> false,
166 cache_store
::MODE_REQUEST
=> false,
168 foreach ($modemappings as $mapping) {
169 // We expect 3 properties.
170 $this->assertCount(3, $mapping);
171 // Required attributes = mode + store.
172 $this->assertArrayHasKey('mode', $mapping);
173 $this->assertArrayHasKey('store', $mapping);
175 $modes[$mapping['mode']] = true;
178 // Must have the default 3 modes and no more.
179 $this->assertCount(3, $mapping);
180 foreach ($modes as $mode) {
181 $this->assertTrue($mode);
184 $definitions = $instance->get_definitions();
185 // The event invalidation definition is required for the cache API and must be there.
186 $this->assertArrayHasKey('core/eventinvalidation', $definitions);
188 $definitionmappings = $instance->get_definition_mappings();
189 foreach ($definitionmappings as $mapping) {
190 // Required attributes = definition + store.
191 $this->assertArrayHasKey('definition', $mapping);
192 $this->assertArrayHasKey('store', $mapping);
197 * Tests for cache keys that would break on windows.
199 public function test_windows_nasty_keys() {
200 $instance = cache_config_testing
::instance();
201 $instance->phpunit_add_definition('phpunit/windowskeytest', array(
202 'mode' => cache_store
::MODE_APPLICATION
,
203 'component' => 'phpunit',
204 'area' => 'windowskeytest',
205 'simplekeys' => true,
208 $cache = cache
::make('phpunit', 'windowskeytest');
209 $this->assertTrue($cache->set('contest', 'test data 1'));
210 $this->assertEquals('test data 1', $cache->get('contest'));
214 * Tests set_identifiers fails post cache creation.
216 * set_identifiers cannot be called after initial cache instantiation, as you need to create a difference cache.
218 public function test_set_identifiers() {
219 $instance = cache_config_testing
::instance();
220 $instance->phpunit_add_definition('phpunit/identifier', array(
221 'mode' => cache_store
::MODE_APPLICATION
,
222 'component' => 'phpunit',
223 'area' => 'identifier',
224 'simplekeys' => true,
225 'simpledata' => true,
226 'staticacceleration' => true
228 $cache = cache
::make('phpunit', 'identifier', array('area'));
229 $this->assertTrue($cache->set('contest', 'test data 1'));
230 $this->assertEquals('test data 1', $cache->get('contest'));
232 $this->expectException('coding_exception');
233 $cache->set_identifiers(array());
237 * Tests the default application cache
239 public function test_default_application_cache() {
240 $cache = cache
::make_from_params(cache_store
::MODE_APPLICATION
, 'phpunit', 'applicationtest');
241 $this->assertInstanceOf(cache_application
::class, $cache);
242 $this->run_on_cache($cache);
244 $instance = cache_config_testing
::instance(true);
245 $instance->phpunit_add_definition('phpunit/test_default_application_cache', array(
246 'mode' => cache_store
::MODE_APPLICATION
,
247 'component' => 'phpunit',
248 'area' => 'test_default_application_cache',
249 'staticacceleration' => true,
250 'staticaccelerationsize' => 1
252 $cache = cache
::make('phpunit', 'test_default_application_cache');
253 $this->assertInstanceOf(cache_application
::class, $cache);
254 $this->run_on_cache($cache);
258 * Tests the default session cache
260 public function test_default_session_cache() {
261 $cache = cache
::make_from_params(cache_store
::MODE_SESSION
, 'phpunit', 'applicationtest');
262 $this->assertInstanceOf(cache_session
::class, $cache);
263 $this->run_on_cache($cache);
267 * Tests the default request cache
269 public function test_default_request_cache() {
270 $cache = cache
::make_from_params(cache_store
::MODE_REQUEST
, 'phpunit', 'applicationtest');
271 $this->assertInstanceOf(cache_request
::class, $cache);
272 $this->run_on_cache($cache);
276 * Tests using a cache system when there are no stores available (who knows what the admin did to achieve this).
278 public function test_on_cache_without_store() {
279 $instance = cache_config_testing
::instance(true);
280 $instance->phpunit_add_definition('phpunit/nostoretest1', array(
281 'mode' => cache_store
::MODE_APPLICATION
,
282 'component' => 'phpunit',
283 'area' => 'nostoretest1',
285 $instance->phpunit_add_definition('phpunit/nostoretest2', array(
286 'mode' => cache_store
::MODE_APPLICATION
,
287 'component' => 'phpunit',
288 'area' => 'nostoretest2',
289 'staticacceleration' => true
291 $instance->phpunit_remove_stores();
293 $cache = cache
::make('phpunit', 'nostoretest1');
294 $this->run_on_cache($cache);
296 $cache = cache
::make('phpunit', 'nostoretest2');
297 $this->run_on_cache($cache);
301 * Runs a standard series of access and use tests on a cache instance.
303 * This function is great because we can use it to ensure all of the loaders perform exactly the same way.
305 * @param cache_loader $cache
307 protected function run_on_cache(cache_loader
$cache) {
309 $datascalars = array('test data', null);
310 $dataarray = array('contest' => 'data', 'part' => 'two');
311 $dataobject = (object)$dataarray;
313 foreach ($datascalars as $datascalar) {
314 $this->assertTrue($cache->purge());
316 // Check all read methods.
317 $this->assertFalse($cache->get($key));
318 $this->assertFalse($cache->has($key));
319 $result = $cache->get_many(array($key));
320 $this->assertCount(1, $result);
321 $this->assertFalse(reset($result));
322 $this->assertFalse($cache->has_any(array($key)));
323 $this->assertFalse($cache->has_all(array($key)));
326 $this->assertTrue($cache->set($key, $datascalar));
327 // Setting it more than once should be permitted.
328 $this->assertTrue($cache->set($key, $datascalar));
330 // Recheck the read methods.
331 $this->assertEquals($datascalar, $cache->get($key));
332 $this->assertTrue($cache->has($key));
333 $result = $cache->get_many(array($key));
334 $this->assertCount(1, $result);
335 $this->assertEquals($datascalar, reset($result));
336 $this->assertTrue($cache->has_any(array($key)));
337 $this->assertTrue($cache->has_all(array($key)));
340 $this->assertTrue($cache->delete($key));
343 $this->assertFalse($cache->get($key));
344 $this->assertFalse($cache->has($key));
348 $this->assertTrue($cache->set($key, $dataarray));
349 $this->assertEquals($dataarray, $cache->get($key));
352 $this->assertTrue($cache->set($key, $dataobject));
353 $this->assertEquals($dataobject, $cache->get($key));
355 $starttime = microtime(true);
356 $specobject = new cache_phpunit_dummy_object('red', 'blue', $starttime);
357 $this->assertTrue($cache->set($key, $specobject));
358 $result = $cache->get($key);
359 $this->assertInstanceOf(cache_phpunit_dummy_object
::class, $result);
360 $this->assertEquals('red_ptc_wfc', $result->property1
);
361 $this->assertEquals('blue_ptc_wfc', $result->property2
);
362 $this->assertGreaterThan($starttime, $result->propertytime
);
364 // Test array of objects.
365 $specobject = new cache_phpunit_dummy_object('red', 'blue', $starttime);
366 $data = new cacheable_object_array(array(
371 $this->assertTrue($cache->set($key, $data));
372 $result = $cache->get($key);
373 $this->assertInstanceOf(cacheable_object_array
::class, $result);
374 $this->assertCount(3, $data);
375 foreach ($result as $item) {
376 $this->assertInstanceOf(cache_phpunit_dummy_object
::class, $item);
377 $this->assertEquals('red_ptc_wfc', $item->property1
);
378 $this->assertEquals('blue_ptc_wfc', $item->property2
);
379 // Ensure that wake from cache is called in all cases.
380 $this->assertGreaterThan($starttime, $item->propertytime
);
384 $cache->set_many(array('key1' => 'data1', 'key2' => 'data2', 'key3' => null));
385 $this->assertEquals('data1', $cache->get('key1'));
386 $this->assertEquals('data2', $cache->get('key2'));
387 $this->assertEquals(null, $cache->get('key3'));
388 $this->assertTrue($cache->delete('key1'));
389 $this->assertTrue($cache->delete('key2'));
390 $this->assertTrue($cache->delete('key3'));
392 $cache->set_many(array(
393 'key1' => array(1, 2, 3),
394 'key2' => array(3, 2, 1),
396 $this->assertIsArray($cache->get('key1'));
397 $this->assertIsArray($cache->get('key2'));
398 $this->assertCount(3, $cache->get('key1'));
399 $this->assertCount(3, $cache->get('key2'));
400 $this->assertIsArray($cache->get_many(array('key1', 'key2')));
401 $this->assertCount(2, $cache->get_many(array('key1', 'key2')));
402 $this->assertEquals(2, $cache->delete_many(array('key1', 'key2')));
405 $this->assertTrue($cache->set('key1', 'data1'));
406 $this->assertTrue($cache->set('key2', 'data2'));
407 $this->assertTrue($cache->set('key3', null));
409 $this->assertEquals('data1', $cache->get('key1'));
410 $this->assertEquals('data2', $cache->get('key2'));
411 $this->assertEquals(null, $cache->get('key3'));
413 $this->assertEquals(3, $cache->delete_many(array('key1', 'key2', 'key3')));
415 $this->assertFalse($cache->get('key1'));
416 $this->assertFalse($cache->get('key2'));
417 $this->assertFalse($cache->get('key3'));
419 // Quick reference test.
420 $obj = new \stdClass
;
423 $this->assertTrue($cache->set('obj', $obj));
426 $var = $cache->get('obj');
427 $this->assertInstanceOf(\stdClass
::class, $var);
428 $this->assertEquals('value', $var->key
);
431 $var = $cache->get('obj');
432 $this->assertInstanceOf(\stdClass
::class, $var);
433 $this->assertEquals('value', $var->key
);
435 $this->assertTrue($cache->delete('obj'));
437 // Deep reference test.
438 $obj1 = new \stdClass
;
439 $obj1->key
= 'value';
440 $obj2 = new \stdClass
;
442 $obj3 = new \stdClass
;
444 $obj1->subobj
=& $obj2;
445 $obj2->subobj
=& $obj3;
446 $this->assertTrue($cache->set('obj', $obj1));
448 $obj1->key
= 'eulav';
451 $var = $cache->get('obj');
452 $this->assertInstanceOf(\stdClass
::class, $var);
453 $this->assertEquals('value', $var->key
);
454 $this->assertInstanceOf(\stdClass
::class, $var->subobj
);
455 $this->assertEquals('test', $var->subobj
->key
);
456 $this->assertInstanceOf(\stdClass
::class, $var->subobj
->subobj
);
457 $this->assertEquals('pork', $var->subobj
->subobj
->key
);
458 $this->assertTrue($cache->delete('obj'));
460 // Death reference test... basically we don't want this to die.
461 $obj = new \stdClass
;
464 $this->assertTrue($cache->set('obj', $obj));
465 $var = $cache->get('obj');
466 $this->assertInstanceOf(\stdClass
::class, $var);
467 $this->assertEquals('value', $var->key
);
469 // Reference test after retrieve.
470 $obj = new \stdClass
;
472 $this->assertTrue($cache->set('obj', $obj));
474 $var1 = $cache->get('obj');
475 $this->assertInstanceOf(\stdClass
::class, $var1);
476 $this->assertEquals('value', $var1->key
);
477 $var1->key
= 'eulav';
478 $this->assertEquals('eulav', $var1->key
);
480 $var2 = $cache->get('obj');
481 $this->assertInstanceOf(\stdClass
::class, $var2);
482 $this->assertEquals('value', $var2->key
);
484 $this->assertTrue($cache->delete('obj'));
486 // Death reference test on get_many... basically we don't want this to die.
487 $obj = new \stdClass
;
490 $this->assertEquals(1, $cache->set_many(array('obj' => $obj)));
491 $var = $cache->get_many(array('obj'));
492 $this->assertInstanceOf(\stdClass
::class, $var['obj']);
493 $this->assertEquals('value', $var['obj']->key
);
495 // Reference test after retrieve.
496 $obj = new \stdClass
;
498 $this->assertEquals(1, $cache->set_many(array('obj' => $obj)));
500 $var1 = $cache->get_many(array('obj'));
501 $this->assertInstanceOf(\stdClass
::class, $var1['obj']);
502 $this->assertEquals('value', $var1['obj']->key
);
503 $var1['obj']->key
= 'eulav';
504 $this->assertEquals('eulav', $var1['obj']->key
);
506 $var2 = $cache->get_many(array('obj'));
507 $this->assertInstanceOf(\stdClass
::class, $var2['obj']);
508 $this->assertEquals('value', $var2['obj']->key
);
510 $this->assertTrue($cache->delete('obj'));
512 // Test strictness exceptions.
514 $cache->get('exception', MUST_EXIST
);
515 $this->fail('Exception expected from cache::get using MUST_EXIST');
516 } catch (\Exception
$e) {
517 $this->assertTrue(true);
520 $cache->get_many(array('exception1', 'exception2'), MUST_EXIST
);
521 $this->fail('Exception expected from cache::get_many using MUST_EXIST');
522 } catch (\Exception
$e) {
523 $this->assertTrue(true);
525 $cache->set('test', 'test');
527 $cache->get_many(array('test', 'exception'), MUST_EXIST
);
528 $this->fail('Exception expected from cache::get_many using MUST_EXIST');
529 } catch (\Exception
$e) {
530 $this->assertTrue(true);
535 * Tests a definition using a data loader
537 public function test_definition_data_loader() {
538 $instance = cache_config_testing
::instance(true);
539 $instance->phpunit_add_definition('phpunit/datasourcetest', array(
540 'mode' => cache_store
::MODE_APPLICATION
,
541 'component' => 'phpunit',
542 'area' => 'datasourcetest',
543 'datasource' => 'cache_phpunit_dummy_datasource',
544 'datasourcefile' => 'cache/tests/fixtures/lib.php'
547 $cache = cache
::make('phpunit', 'datasourcetest');
548 $this->assertInstanceOf(cache_application
::class, $cache);
550 // Purge it to be sure.
551 $this->assertTrue($cache->purge());
552 // It won't be there yet.
553 $this->assertFalse($cache->has('Test'));
554 // It should load it ;).
555 $this->assertTrue($cache->has('Test', true));
557 // Purge it to be sure.
558 $this->assertTrue($cache->purge());
559 $this->assertEquals('Test has no value really.', $cache->get('Test'));
561 // Test multiple values.
562 $this->assertTrue($cache->purge());
563 $this->assertTrue($cache->set('b', 'B'));
564 $result = $cache->get_many(array('a', 'b', 'c'));
565 $this->assertIsArray($result);
566 $this->assertCount(3, $result);
567 $this->assertArrayHasKey('a', $result);
568 $this->assertArrayHasKey('b', $result);
569 $this->assertArrayHasKey('c', $result);
570 $this->assertEquals('a has no value really.', $result['a']);
571 $this->assertEquals('B', $result['b']);
572 $this->assertEquals('c has no value really.', $result['c']);
576 * Tests a definition using a data loader with versioned keys.
578 * @covers ::get_versioned
579 * @covers ::set_versioned
581 public function test_definition_data_loader_versioned() {
582 // Create two definitions, one using a non-versionable data source and the other using
583 // a versionable one.
584 $instance = cache_config_testing
::instance(true);
585 $instance->phpunit_add_definition('phpunit/datasourcetest1', array(
586 'mode' => cache_store
::MODE_APPLICATION
,
587 'component' => 'phpunit',
588 'area' => 'datasourcetest1',
589 'datasource' => 'cache_phpunit_dummy_datasource',
590 'datasourcefile' => 'cache/tests/fixtures/lib.php'
592 $instance->phpunit_add_definition('phpunit/datasourcetest2', array(
593 'mode' => cache_store
::MODE_APPLICATION
,
594 'component' => 'phpunit',
595 'area' => 'datasourcetest2',
596 'datasource' => 'cache_phpunit_dummy_datasource_versionable',
597 'datasourcefile' => 'cache/tests/fixtures/lib.php'
600 // The first data source works for normal 'get'.
601 $cache1 = cache
::make('phpunit', 'datasourcetest1');
602 $this->assertEquals('Frog has no value really.', $cache1->get('Frog'));
604 // But it doesn't work for get_versioned.
606 $cache1->get_versioned('zombie', 1);
608 } catch (\coding_exception
$e) {
609 $this->assertStringContainsString('Data source is not versionable', $e->getMessage());
612 // The second data source works for get_versioned. Set up the datasource first.
613 $cache2 = cache
::make('phpunit', 'datasourcetest2');
615 $datasource = \cache_phpunit_dummy_datasource_versionable
::get_last_instance();
616 $datasource->has_value('frog', 3, 'Kermit');
618 // Check data with no value.
619 $this->assertFalse($cache2->get_versioned('zombie', 1));
621 // Check data with value in datastore of required version.
622 $result = $cache2->get_versioned('frog', 3, IGNORE_MISSING
, $actualversion);
623 $this->assertEquals('Kermit', $result);
624 $this->assertEquals(3, $actualversion);
626 // Check when the datastore doesn't have required version.
627 $this->assertFalse($cache2->get_versioned('frog', 4));
631 * Tests a definition using an overridden loader
633 public function test_definition_overridden_loader() {
634 $instance = cache_config_testing
::instance(true);
635 $instance->phpunit_add_definition('phpunit/overridetest', array(
636 'mode' => cache_store
::MODE_APPLICATION
,
637 'component' => 'phpunit',
638 'area' => 'overridetest',
639 'overrideclass' => 'cache_phpunit_dummy_overrideclass',
640 'overrideclassfile' => 'cache/tests/fixtures/lib.php'
642 $cache = cache
::make('phpunit', 'overridetest');
643 $this->assertInstanceOf(cache_phpunit_dummy_overrideclass
::class, $cache);
644 $this->assertInstanceOf(cache_application
::class, $cache);
645 // Purge it to be sure.
646 $this->assertTrue($cache->purge());
647 // It won't be there yet.
648 $this->assertFalse($cache->has('Test'));
650 $this->assertTrue($cache->set('Test', 'Test has no value really.'));
652 $this->assertEquals('Test has no value really.', $cache->get('Test'));
656 * Test the mappingsonly setting.
658 public function test_definition_mappings_only() {
659 /** @var cache_config_testing $instance */
660 $instance = cache_config_testing
::instance(true);
661 $instance->phpunit_add_definition('phpunit/mappingsonly', array(
662 'mode' => cache_store
::MODE_APPLICATION
,
663 'component' => 'phpunit',
664 'area' => 'mappingsonly',
665 'mappingsonly' => true
667 $instance->phpunit_add_definition('phpunit/nonmappingsonly', array(
668 'mode' => cache_store
::MODE_APPLICATION
,
669 'component' => 'phpunit',
670 'area' => 'nonmappingsonly',
671 'mappingsonly' => false
674 $cacheonly = cache
::make('phpunit', 'mappingsonly');
675 $this->assertInstanceOf(cache_application
::class, $cacheonly);
676 $this->assertEquals('cachestore_dummy', $cacheonly->phpunit_get_store_class());
678 $expected = $this->get_expected_application_cache_store();
679 $cachenon = cache
::make('phpunit', 'nonmappingsonly');
680 $this->assertInstanceOf(cache_application
::class, $cachenon);
681 $this->assertEquals($expected, $cachenon->phpunit_get_store_class());
685 * Test a very basic definition.
687 public function test_definition() {
688 $instance = cache_config_testing
::instance();
689 $instance->phpunit_add_definition('phpunit/test', array(
690 'mode' => cache_store
::MODE_APPLICATION
,
691 'component' => 'phpunit',
694 $cache = cache
::make('phpunit', 'test');
696 $this->assertTrue($cache->set('testkey1', 'test data 1'));
697 $this->assertEquals('test data 1', $cache->get('testkey1'));
698 $this->assertTrue($cache->set('testkey2', 'test data 2'));
699 $this->assertEquals('test data 2', $cache->get('testkey2'));
703 * Test a definition using the simple keys.
705 public function test_definition_simplekeys() {
706 $instance = cache_config_testing
::instance();
707 $instance->phpunit_add_definition('phpunit/simplekeytest', array(
708 'mode' => cache_store
::MODE_APPLICATION
,
709 'component' => 'phpunit',
710 'area' => 'simplekeytest',
713 $cache = cache
::make('phpunit', 'simplekeytest');
715 $this->assertTrue($cache->set('testkey1', 'test data 1'));
716 $this->assertEquals('test data 1', $cache->get('testkey1'));
717 $this->assertTrue($cache->set('testkey2', 'test data 2'));
718 $this->assertEquals('test data 2', $cache->get('testkey2'));
722 $this->assertTrue($cache->set('1', 'test data 1'));
723 $this->assertEquals('test data 1', $cache->get('1'));
724 $this->assertTrue($cache->set('2', 'test data 2'));
725 $this->assertEquals('test data 2', $cache->get('2'));
729 * Test a negative TTL on an application cache.
731 public function test_application_ttl_negative() {
732 $instance = cache_config_testing
::instance(true);
733 $instance->phpunit_add_definition('phpunit/ttltest', array(
734 'mode' => cache_store
::MODE_APPLICATION
,
735 'component' => 'phpunit',
737 'ttl' => -86400 // Set to a day in the past to be extra sure.
739 $cache = cache
::make('phpunit', 'ttltest');
740 $this->assertInstanceOf(cache_application
::class, $cache);
742 // Purge it to be sure.
743 $this->assertTrue($cache->purge());
744 // It won't be there yet.
745 $this->assertFalse($cache->has('Test'));
747 $this->assertTrue($cache->set('Test', 'Test'));
748 // Check its not there.
749 $this->assertFalse($cache->has('Test'));
750 // Double check by trying to get it.
751 $this->assertFalse($cache->get('Test'));
753 // Test with multiple keys.
754 $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C')));
755 $result = $cache->get_many(array('a', 'b', 'c'));
756 $this->assertIsArray($result);
757 $this->assertCount(3, $result);
758 $this->assertArrayHasKey('a', $result);
759 $this->assertArrayHasKey('b', $result);
760 $this->assertArrayHasKey('c', $result);
761 $this->assertFalse($result['a']);
762 $this->assertFalse($result['b']);
763 $this->assertFalse($result['c']);
765 // Test with multiple keys including missing ones.
766 $result = $cache->get_many(array('a', 'c', 'e'));
767 $this->assertIsArray($result);
768 $this->assertCount(3, $result);
769 $this->assertArrayHasKey('a', $result);
770 $this->assertArrayHasKey('c', $result);
771 $this->assertArrayHasKey('e', $result);
772 $this->assertFalse($result['a']);
773 $this->assertFalse($result['c']);
774 $this->assertFalse($result['e']);
778 * Test a positive TTL on an application cache.
780 public function test_application_ttl_positive() {
781 $instance = cache_config_testing
::instance(true);
782 $instance->phpunit_add_definition('phpunit/ttltest', array(
783 'mode' => cache_store
::MODE_APPLICATION
,
784 'component' => 'phpunit',
786 'ttl' => 86400 // Set to a day in the future to be extra sure.
788 $cache = cache
::make('phpunit', 'ttltest');
789 $this->assertInstanceOf(cache_application
::class, $cache);
791 // Purge it to be sure.
792 $this->assertTrue($cache->purge());
793 // It won't be there yet.
794 $this->assertFalse($cache->has('Test'));
796 $this->assertTrue($cache->set('Test', 'Test'));
798 $this->assertTrue($cache->has('Test'));
799 // Double check by trying to get it.
800 $this->assertEquals('Test', $cache->get('Test'));
802 // Test with multiple keys.
803 $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C')));
804 $result = $cache->get_many(array('a', 'b', 'c'));
805 $this->assertIsArray($result);
806 $this->assertCount(3, $result);
807 $this->assertArrayHasKey('a', $result);
808 $this->assertArrayHasKey('b', $result);
809 $this->assertArrayHasKey('c', $result);
810 $this->assertEquals('A', $result['a']);
811 $this->assertEquals('B', $result['b']);
812 $this->assertEquals('C', $result['c']);
814 // Test with multiple keys including missing ones.
815 $result = $cache->get_many(array('a', 'c', 'e'));
816 $this->assertIsArray($result);
817 $this->assertCount(3, $result);
818 $this->assertArrayHasKey('a', $result);
819 $this->assertArrayHasKey('c', $result);
820 $this->assertArrayHasKey('e', $result);
821 $this->assertEquals('A', $result['a']);
822 $this->assertEquals('C', $result['c']);
823 $this->assertEquals(false, $result['e']);
827 * Test a negative TTL on an session cache.
829 public function test_session_ttl_positive() {
830 $instance = cache_config_testing
::instance(true);
831 $instance->phpunit_add_definition('phpunit/ttltest', array(
832 'mode' => cache_store
::MODE_SESSION
,
833 'component' => 'phpunit',
835 'ttl' => 86400 // Set to a day in the future to be extra sure.
837 $cache = cache
::make('phpunit', 'ttltest');
838 $this->assertInstanceOf(cache_session
::class, $cache);
840 // Purge it to be sure.
841 $this->assertTrue($cache->purge());
842 // It won't be there yet.
843 $this->assertFalse($cache->has('Test'));
845 $this->assertTrue($cache->set('Test', 'Test'));
847 $this->assertTrue($cache->has('Test'));
848 // Double check by trying to get it.
849 $this->assertEquals('Test', $cache->get('Test'));
851 // Test with multiple keys.
852 $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C')));
853 $result = $cache->get_many(array('a', 'b', 'c'));
854 $this->assertIsArray($result);
855 $this->assertCount(3, $result);
856 $this->assertArrayHasKey('a', $result);
857 $this->assertArrayHasKey('b', $result);
858 $this->assertArrayHasKey('c', $result);
859 $this->assertEquals('A', $result['a']);
860 $this->assertEquals('B', $result['b']);
861 $this->assertEquals('C', $result['c']);
863 // Test with multiple keys including missing ones.
864 $result = $cache->get_many(array('a', 'c', 'e'));
865 $this->assertIsArray($result);
866 $this->assertCount(3, $result);
867 $this->assertArrayHasKey('a', $result);
868 $this->assertArrayHasKey('c', $result);
869 $this->assertArrayHasKey('e', $result);
870 $this->assertEquals('A', $result['a']);
871 $this->assertEquals('C', $result['c']);
872 $this->assertEquals(false, $result['e']);
876 * Tests manual locking operations on an application cache
878 public function test_application_manual_locking() {
879 $instance = cache_config_testing
::instance();
880 $instance->phpunit_add_definition('phpunit/lockingtest', array(
881 'mode' => cache_store
::MODE_APPLICATION
,
882 'component' => 'phpunit',
883 'area' => 'lockingtest'
885 $cache1 = cache
::make('phpunit', 'lockingtest');
886 $cache2 = clone($cache1);
888 $this->assertTrue($cache1->set('testkey', 'test data'));
889 $this->assertTrue($cache2->set('testkey', 'test data'));
891 $this->assertTrue($cache1->acquire_lock('testkey'));
892 $this->assertFalse($cache2->acquire_lock('testkey'));
894 $this->assertTrue($cache1->check_lock_state('testkey'));
895 $this->assertFalse($cache2->check_lock_state('testkey'));
897 $this->assertTrue($cache1->release_lock('testkey'));
898 $this->assertFalse($cache2->release_lock('testkey'));
900 $this->assertTrue($cache1->set('testkey', 'test data'));
901 $this->assertTrue($cache2->set('testkey', 'test data'));
905 * Tests application cache event invalidation
907 public function test_application_event_invalidation() {
908 $instance = cache_config_testing
::instance();
909 $instance->phpunit_add_definition('phpunit/eventinvalidationtest', array(
910 'mode' => cache_store
::MODE_APPLICATION
,
911 'component' => 'phpunit',
912 'area' => 'eventinvalidationtest',
913 'invalidationevents' => array(
917 $cache = cache
::make('phpunit', 'eventinvalidationtest');
919 $this->assertTrue($cache->set('testkey1', 'test data 1'));
920 $this->assertEquals('test data 1', $cache->get('testkey1'));
921 $this->assertTrue($cache->set('testkey2', 'test data 2'));
922 $this->assertEquals('test data 2', $cache->get('testkey2'));
924 // Test invalidating a single entry.
925 cache_helper
::invalidate_by_event('crazyevent', array('testkey1'));
927 $this->assertFalse($cache->get('testkey1'));
928 $this->assertEquals('test data 2', $cache->get('testkey2'));
930 $this->assertTrue($cache->set('testkey1', 'test data 1'));
932 // Test invalidating both entries.
933 cache_helper
::invalidate_by_event('crazyevent', array('testkey1', 'testkey2'));
935 $this->assertFalse($cache->get('testkey1'));
936 $this->assertFalse($cache->get('testkey2'));
940 * Tests session cache event invalidation
942 public function test_session_event_invalidation() {
943 $instance = cache_config_testing
::instance();
944 $instance->phpunit_add_definition('phpunit/test_session_event_invalidation', array(
945 'mode' => cache_store
::MODE_SESSION
,
946 'component' => 'phpunit',
947 'area' => 'test_session_event_invalidation',
948 'invalidationevents' => array(
952 $cache = cache
::make('phpunit', 'test_session_event_invalidation');
953 $this->assertInstanceOf(cache_session
::class, $cache);
955 $this->assertTrue($cache->set('testkey1', 'test data 1'));
956 $this->assertEquals('test data 1', $cache->get('testkey1'));
957 $this->assertTrue($cache->set('testkey2', 'test data 2'));
958 $this->assertEquals('test data 2', $cache->get('testkey2'));
960 // Test invalidating a single entry.
961 cache_helper
::invalidate_by_event('crazyevent', array('testkey1'));
963 $this->assertFalse($cache->get('testkey1'));
964 $this->assertEquals('test data 2', $cache->get('testkey2'));
966 $this->assertTrue($cache->set('testkey1', 'test data 1'));
968 // Test invalidating both entries.
969 cache_helper
::invalidate_by_event('crazyevent', array('testkey1', 'testkey2'));
971 $this->assertFalse($cache->get('testkey1'));
972 $this->assertFalse($cache->get('testkey2'));
976 * Tests application cache definition invalidation
978 public function test_application_definition_invalidation() {
979 $instance = cache_config_testing
::instance();
980 $instance->phpunit_add_definition('phpunit/definitioninvalidation', array(
981 'mode' => cache_store
::MODE_APPLICATION
,
982 'component' => 'phpunit',
983 'area' => 'definitioninvalidation'
985 $cache = cache
::make('phpunit', 'definitioninvalidation');
986 $this->assertTrue($cache->set('testkey1', 'test data 1'));
987 $this->assertEquals('test data 1', $cache->get('testkey1'));
988 $this->assertTrue($cache->set('testkey2', 'test data 2'));
989 $this->assertEquals('test data 2', $cache->get('testkey2'));
991 cache_helper
::invalidate_by_definition('phpunit', 'definitioninvalidation', array(), 'testkey1');
993 $this->assertFalse($cache->get('testkey1'));
994 $this->assertEquals('test data 2', $cache->get('testkey2'));
996 $this->assertTrue($cache->set('testkey1', 'test data 1'));
998 cache_helper
::invalidate_by_definition('phpunit', 'definitioninvalidation', array(), array('testkey1'));
1000 $this->assertFalse($cache->get('testkey1'));
1001 $this->assertEquals('test data 2', $cache->get('testkey2'));
1003 $this->assertTrue($cache->set('testkey1', 'test data 1'));
1005 cache_helper
::invalidate_by_definition('phpunit', 'definitioninvalidation', array(), array('testkey1', 'testkey2'));
1007 $this->assertFalse($cache->get('testkey1'));
1008 $this->assertFalse($cache->get('testkey2'));
1012 * Tests session cache definition invalidation
1014 public function test_session_definition_invalidation() {
1015 $instance = cache_config_testing
::instance();
1016 $instance->phpunit_add_definition('phpunit/test_session_definition_invalidation', array(
1017 'mode' => cache_store
::MODE_SESSION
,
1018 'component' => 'phpunit',
1019 'area' => 'test_session_definition_invalidation'
1021 $cache = cache
::make('phpunit', 'test_session_definition_invalidation');
1022 $this->assertInstanceOf(cache_session
::class, $cache);
1023 $this->assertTrue($cache->set('testkey1', 'test data 1'));
1024 $this->assertEquals('test data 1', $cache->get('testkey1'));
1025 $this->assertTrue($cache->set('testkey2', 'test data 2'));
1026 $this->assertEquals('test data 2', $cache->get('testkey2'));
1028 cache_helper
::invalidate_by_definition('phpunit', 'test_session_definition_invalidation', array(), 'testkey1');
1030 $this->assertFalse($cache->get('testkey1'));
1031 $this->assertEquals('test data 2', $cache->get('testkey2'));
1033 $this->assertTrue($cache->set('testkey1', 'test data 1'));
1035 cache_helper
::invalidate_by_definition('phpunit', 'test_session_definition_invalidation', array(),
1038 $this->assertFalse($cache->get('testkey1'));
1039 $this->assertEquals('test data 2', $cache->get('testkey2'));
1041 $this->assertTrue($cache->set('testkey1', 'test data 1'));
1043 cache_helper
::invalidate_by_definition('phpunit', 'test_session_definition_invalidation', array(),
1044 array('testkey1', 'testkey2'));
1046 $this->assertFalse($cache->get('testkey1'));
1047 $this->assertFalse($cache->get('testkey2'));
1051 * Tests application cache event invalidation over a distributed setup.
1053 public function test_distributed_application_event_invalidation() {
1055 // This is going to be an intense wee test.
1056 // We need to add data the to cache, invalidate it by event, manually force it back without MUC knowing to simulate a
1057 // disconnected/distributed setup (think load balanced server using local cache), instantiate the cache again and finally
1058 // check that it is not picked up.
1059 $instance = cache_config_testing
::instance();
1060 $instance->phpunit_add_definition('phpunit/eventinvalidationtest', array(
1061 'mode' => cache_store
::MODE_APPLICATION
,
1062 'component' => 'phpunit',
1063 'area' => 'eventinvalidationtest',
1064 'simplekeys' => true,
1065 'simpledata' => true,
1066 'invalidationevents' => array(
1070 $cache = cache
::make('phpunit', 'eventinvalidationtest');
1071 $this->assertTrue($cache->set('testkey1', 'test data 1'));
1072 $this->assertEquals('test data 1', $cache->get('testkey1'));
1074 cache_helper
::invalidate_by_event('crazyevent', array('testkey1'));
1076 $this->assertFalse($cache->get('testkey1'));
1078 // OK data added, data invalidated, and invalidation time has been set.
1079 // Now we need to manually add back the data and adjust the invalidation time.
1080 $hash = md5(cache_store
::MODE_APPLICATION
.'/phpunit/eventinvalidationtest/'.$CFG->wwwroot
.'phpunit');
1081 $timefile = $CFG->dataroot
."/cache/cachestore_file/default_application/phpunit_eventinvalidationtest/las-cache/lastinvalidation-$hash.cache";
1082 // Make sure the file is correct.
1083 $this->assertTrue(file_exists($timefile));
1084 $timecont = serialize(cache
::now(true) - 60); // Back 60sec in the past to force it to re-invalidate.
1085 make_writable_directory(dirname($timefile));
1086 file_put_contents($timefile, $timecont);
1087 $this->assertTrue(file_exists($timefile));
1089 $datafile = $CFG->dataroot
."/cache/cachestore_file/default_application/phpunit_eventinvalidationtest/tes-cache/testkey1-$hash.cache";
1090 $datacont = serialize("test data 1");
1091 make_writable_directory(dirname($datafile));
1092 file_put_contents($datafile, $datacont);
1093 $this->assertTrue(file_exists($datafile));
1095 // Test 1: Rebuild without the event and test its there.
1096 cache_factory
::reset();
1097 $instance = cache_config_testing
::instance();
1098 $instance->phpunit_add_definition('phpunit/eventinvalidationtest', array(
1099 'mode' => cache_store
::MODE_APPLICATION
,
1100 'component' => 'phpunit',
1101 'area' => 'eventinvalidationtest',
1102 'simplekeys' => true,
1103 'simpledata' => true,
1105 $cache = cache
::make('phpunit', 'eventinvalidationtest');
1106 $this->assertEquals('test data 1', $cache->get('testkey1'));
1108 // Test 2: Rebuild and test the invalidation of the event via the invalidation cache.
1109 cache_factory
::reset();
1111 $instance = cache_config_testing
::instance();
1112 $instance->phpunit_add_definition('phpunit/eventinvalidationtest', array(
1113 'mode' => cache_store
::MODE_APPLICATION
,
1114 'component' => 'phpunit',
1115 'area' => 'eventinvalidationtest',
1116 'simplekeys' => true,
1117 'simpledata' => true,
1118 'invalidationevents' => array(
1123 $cache = cache
::make('phpunit', 'eventinvalidationtest');
1124 $this->assertFalse($cache->get('testkey1'));
1126 // Test 3: Verify that an existing lastinvalidation cache file is updated when needed.
1128 // Make a new cache class. This should should invalidate testkey2.
1129 $cache = cache
::make('phpunit', 'eventinvalidationtest');
1131 // Invalidation token should have been reset.
1132 $this->assertEquals(cache
::get_purge_token(), $cache->get('lastinvalidation'));
1134 // Set testkey2 data.
1135 $cache->set('testkey2', 'test data 2');
1137 // Backdate the event invalidation time by 30 seconds.
1138 $invalidationcache = cache
::make('core', 'eventinvalidation');
1139 $invalidationcache->set('crazyevent', array('testkey2' => cache
::now() - 30));
1141 // Lastinvalidation should already be cache::now().
1142 $this->assertEquals(cache
::get_purge_token(), $cache->get('lastinvalidation'));
1144 // Set it to 15 seconds ago so that we know if it changes.
1145 $pasttime = cache
::now(true) - 15;
1146 $cache->set('lastinvalidation', $pasttime);
1148 // Make a new cache class. This should not invalidate anything.
1149 cache_factory
::instance()->reset_cache_instances();
1150 $cache = cache
::make('phpunit', 'eventinvalidationtest');
1152 // Lastinvalidation shouldn't change since it was already newer than invalidation event.
1153 $this->assertEquals($pasttime, $cache->get('lastinvalidation'));
1155 // Now set the event invalidation to newer than the lastinvalidation time.
1156 $invalidationcache->set('crazyevent', array('testkey2' => cache
::now() - 5));
1157 // Make a new cache class. This should should invalidate testkey2.
1158 cache_factory
::instance()->reset_cache_instances();
1159 $cache = cache
::make('phpunit', 'eventinvalidationtest');
1160 // Lastinvalidation timestamp should have updated to cache::now().
1161 $this->assertEquals(cache
::get_purge_token(), $cache->get('lastinvalidation'));
1163 // Now simulate a purge_by_event 5 seconds ago.
1164 $invalidationcache = cache
::make('core', 'eventinvalidation');
1165 $invalidationcache->set('crazyevent', array('purged' => cache
::now(true) - 5));
1166 // Set our lastinvalidation timestamp to 15 seconds ago.
1167 $cache->set('lastinvalidation', cache
::now(true) - 15);
1168 // Make a new cache class. This should invalidate the cache.
1169 cache_factory
::instance()->reset_cache_instances();
1170 $cache = cache
::make('phpunit', 'eventinvalidationtest');
1171 // Lastinvalidation timestamp should have updated to cache::now().
1172 $this->assertEquals(cache
::get_purge_token(), $cache->get('lastinvalidation'));
1177 * Tests application cache event purge
1179 public function test_application_event_purge() {
1180 $instance = cache_config_testing
::instance();
1181 $instance->phpunit_add_definition('phpunit/eventpurgetest', array(
1182 'mode' => cache_store
::MODE_APPLICATION
,
1183 'component' => 'phpunit',
1184 'area' => 'eventpurgetest',
1185 'invalidationevents' => array(
1189 $instance->phpunit_add_definition('phpunit/eventpurgetestaccelerated', array(
1190 'mode' => cache_store
::MODE_APPLICATION
,
1191 'component' => 'phpunit',
1192 'area' => 'eventpurgetestaccelerated',
1193 'staticacceleration' => true,
1194 'invalidationevents' => array(
1198 $cache = cache
::make('phpunit', 'eventpurgetest');
1200 $this->assertTrue($cache->set('testkey1', 'test data 1'));
1201 $this->assertEquals('test data 1', $cache->get('testkey1'));
1202 $this->assertTrue($cache->set('testkey2', 'test data 2'));
1203 $this->assertEquals('test data 2', $cache->get('testkey2'));
1206 cache_helper
::purge_by_event('crazyevent');
1208 // Check things have been removed.
1209 $this->assertFalse($cache->get('testkey1'));
1210 $this->assertFalse($cache->get('testkey2'));
1212 // Now test the static acceleration array.
1213 $cache = cache
::make('phpunit', 'eventpurgetestaccelerated');
1214 $this->assertTrue($cache->set('testkey1', 'test data 1'));
1215 $this->assertEquals('test data 1', $cache->get('testkey1'));
1216 $this->assertTrue($cache->set('testkey2', 'test data 2'));
1217 $this->assertEquals('test data 2', $cache->get('testkey2'));
1220 cache_helper
::purge_by_event('crazyevent');
1222 // Check things have been removed.
1223 $this->assertFalse($cache->get('testkey1'));
1224 $this->assertFalse($cache->get('testkey2'));
1228 * Tests session cache event purge
1230 public function test_session_event_purge() {
1231 $instance = cache_config_testing
::instance();
1232 $instance->phpunit_add_definition('phpunit/eventpurgetest', array(
1233 'mode' => cache_store
::MODE_SESSION
,
1234 'component' => 'phpunit',
1235 'area' => 'eventpurgetest',
1236 'invalidationevents' => array(
1240 $instance->phpunit_add_definition('phpunit/eventpurgetestaccelerated', array(
1241 'mode' => cache_store
::MODE_SESSION
,
1242 'component' => 'phpunit',
1243 'area' => 'eventpurgetestaccelerated',
1244 'staticacceleration' => true,
1245 'invalidationevents' => array(
1249 $cache = cache
::make('phpunit', 'eventpurgetest');
1251 $this->assertTrue($cache->set('testkey1', 'test data 1'));
1252 $this->assertEquals('test data 1', $cache->get('testkey1'));
1253 $this->assertTrue($cache->set('testkey2', 'test data 2'));
1254 $this->assertEquals('test data 2', $cache->get('testkey2'));
1257 cache_helper
::purge_by_event('crazyevent');
1259 // Check things have been removed.
1260 $this->assertFalse($cache->get('testkey1'));
1261 $this->assertFalse($cache->get('testkey2'));
1263 // Now test the static acceleration array.
1264 $cache = cache
::make('phpunit', 'eventpurgetestaccelerated');
1265 $this->assertTrue($cache->set('testkey1', 'test data 1'));
1266 $this->assertEquals('test data 1', $cache->get('testkey1'));
1267 $this->assertTrue($cache->set('testkey2', 'test data 2'));
1268 $this->assertEquals('test data 2', $cache->get('testkey2'));
1271 cache_helper
::purge_by_event('crazyevent');
1273 // Check things have been removed.
1274 $this->assertFalse($cache->get('testkey1'));
1275 $this->assertFalse($cache->get('testkey2'));
1279 * Tests application cache definition purge
1281 public function test_application_definition_purge() {
1282 $instance = cache_config_testing
::instance();
1283 $instance->phpunit_add_definition('phpunit/definitionpurgetest', array(
1284 'mode' => cache_store
::MODE_APPLICATION
,
1285 'component' => 'phpunit',
1286 'area' => 'definitionpurgetest',
1287 'invalidationevents' => array(
1291 $cache = cache
::make('phpunit', 'definitionpurgetest');
1293 $this->assertTrue($cache->set('testkey1', 'test data 1'));
1294 $this->assertEquals('test data 1', $cache->get('testkey1'));
1295 $this->assertTrue($cache->set('testkey2', 'test data 2'));
1296 $this->assertEquals('test data 2', $cache->get('testkey2'));
1299 cache_helper
::purge_by_definition('phpunit', 'definitionpurgetest');
1301 // Check things have been removed.
1302 $this->assertFalse($cache->get('testkey1'));
1303 $this->assertFalse($cache->get('testkey2'));
1307 * Test the use of an alt path.
1308 * If we can generate a config instance we are done :)
1310 public function test_alt_cache_path() {
1312 if ((defined('TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH') && TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH
) ||
!empty($CFG->altcacheconfigpath
)) {
1313 $this->markTestSkipped('Skipped testing alt cache path as it is already being used.');
1315 $this->resetAfterTest();
1316 $CFG->altcacheconfigpath
= $CFG->dataroot
.'/cache/altcacheconfigpath';
1317 $instance = cache_config_testing
::instance();
1318 $this->assertInstanceOf(cache_config
::class, $instance);
1322 * Test disabling the cache stores.
1324 public function test_disable_stores() {
1325 $instance = cache_config_testing
::instance();
1326 $instance->phpunit_add_definition('phpunit/disabletest1', array(
1327 'mode' => cache_store
::MODE_APPLICATION
,
1328 'component' => 'phpunit',
1329 'area' => 'disabletest1'
1331 $instance->phpunit_add_definition('phpunit/disabletest2', array(
1332 'mode' => cache_store
::MODE_SESSION
,
1333 'component' => 'phpunit',
1334 'area' => 'disabletest2'
1336 $instance->phpunit_add_definition('phpunit/disabletest3', array(
1337 'mode' => cache_store
::MODE_REQUEST
,
1338 'component' => 'phpunit',
1339 'area' => 'disabletest3'
1343 'disabletest1' => cache
::make('phpunit', 'disabletest1'),
1344 'disabletest2' => cache
::make('phpunit', 'disabletest2'),
1345 'disabletest3' => cache
::make('phpunit', 'disabletest3')
1348 $this->assertInstanceOf(cache_phpunit_application
::class, $caches['disabletest1']);
1349 $this->assertInstanceOf(cache_phpunit_session
::class, $caches['disabletest2']);
1350 $this->assertInstanceOf(cache_phpunit_request
::class, $caches['disabletest3']);
1352 $this->assertEquals('cachestore_file', $caches['disabletest1']->phpunit_get_store_class());
1353 $this->assertEquals('cachestore_session', $caches['disabletest2']->phpunit_get_store_class());
1354 $this->assertEquals('cachestore_static', $caches['disabletest3']->phpunit_get_store_class());
1356 foreach ($caches as $cache) {
1357 $this->assertFalse($cache->get('test'));
1358 $this->assertTrue($cache->set('test', 'test'));
1359 $this->assertEquals('test', $cache->get('test'));
1362 cache_factory
::disable_stores();
1365 'disabletest1' => cache
::make('phpunit', 'disabletest1'),
1366 'disabletest2' => cache
::make('phpunit', 'disabletest2'),
1367 'disabletest3' => cache
::make('phpunit', 'disabletest3')
1370 $this->assertInstanceOf(cache_phpunit_application
::class, $caches['disabletest1']);
1371 $this->assertInstanceOf(cache_phpunit_session
::class, $caches['disabletest2']);
1372 $this->assertInstanceOf(cache_phpunit_request
::class, $caches['disabletest3']);
1374 $this->assertEquals('cachestore_dummy', $caches['disabletest1']->phpunit_get_store_class());
1375 $this->assertEquals('cachestore_dummy', $caches['disabletest2']->phpunit_get_store_class());
1376 $this->assertEquals('cachestore_dummy', $caches['disabletest3']->phpunit_get_store_class());
1378 foreach ($caches as $cache) {
1379 $this->assertFalse($cache->get('test'));
1380 $this->assertTrue($cache->set('test', 'test'));
1381 $this->assertEquals('test', $cache->get('test'));
1386 * Test disabling the cache.
1388 public function test_disable() {
1391 if ((defined('TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH') && TEST_CACHE_USING_ALT_CACHE_CONFIG_PATH
) ||
!empty($CFG->altcacheconfigpath
)) {
1392 // We can't run this test as it requires us to delete the cache configuration script which we just
1393 // cant do with a custom path in play.
1394 $this->markTestSkipped('Skipped testing cache disable functionality as alt cache path is being used.');
1397 $configfile = $CFG->dataroot
.'/muc/config.php';
1399 // The config file will not exist yet as we've not done anything with the cache.
1400 // reset_all_data removes the file and without a call to create a configuration it doesn't exist
1402 $this->assertFileDoesNotExist($configfile);
1404 // Disable the cache
1405 cache_phpunit_factory
::phpunit_disable();
1407 // Check we get the expected disabled factory.
1408 $factory = cache_factory
::instance();
1409 $this->assertInstanceOf(cache_factory_disabled
::class, $factory);
1411 // Check we get the expected disabled config.
1412 $config = $factory->create_config_instance();
1413 $this->assertInstanceOf(cache_config_disabled
::class, $config);
1415 // Check we get the expected disabled caches.
1416 $cache = cache
::make('core', 'string');
1417 $this->assertInstanceOf(cache_disabled
::class, $cache);
1419 // Test an application cache.
1420 $cache = cache
::make_from_params(cache_store
::MODE_APPLICATION
, 'phpunit', 'disable');
1421 $this->assertInstanceOf(cache_disabled
::class, $cache);
1423 $this->assertFalse($cache->get('test'));
1424 $this->assertFalse($cache->get_versioned('v', 1));
1425 $this->assertFalse($cache->set('test', 'test'));
1426 $this->assertFalse($cache->set_versioned('v', 1, 'data'));
1427 $this->assertFalse($cache->delete('test'));
1428 $this->assertTrue($cache->purge());
1430 // Test a session cache.
1431 $cache = cache
::make_from_params(cache_store
::MODE_SESSION
, 'phpunit', 'disable');
1432 $this->assertInstanceOf(cache_disabled
::class, $cache);
1434 $this->assertFalse($cache->get('test'));
1435 $this->assertFalse($cache->get_versioned('v', 1));
1436 $this->assertFalse($cache->set('test', 'test'));
1437 $this->assertFalse($cache->set_versioned('v', 1, 'data'));
1438 $this->assertFalse($cache->delete('test'));
1439 $this->assertTrue($cache->purge());
1441 // Finally test a request cache.
1442 $cache = cache
::make_from_params(cache_store
::MODE_REQUEST
, 'phpunit', 'disable');
1443 $this->assertInstanceOf(cache_disabled
::class, $cache);
1445 $this->assertFalse($cache->get('test'));
1446 $this->assertFalse($cache->get_versioned('v', 1));
1447 $this->assertFalse($cache->set('test', 'test'));
1448 $this->assertFalse($cache->set_versioned('v', 1, 'data'));
1449 $this->assertFalse($cache->delete('test'));
1450 $this->assertTrue($cache->purge());
1452 cache_factory
::reset();
1454 $factory = cache_factory
::instance(true);
1455 $config = $factory->create_config_instance();
1456 $this->assertEquals('cache_config_testing', get_class($config));
1460 * Test that multiple application loaders work ok.
1462 public function test_multiple_application_loaders() {
1463 $instance = cache_config_testing
::instance(true);
1464 $instance->phpunit_add_file_store('phpunittest1');
1465 $instance->phpunit_add_file_store('phpunittest2');
1466 $instance->phpunit_add_definition('phpunit/multi_loader', array(
1467 'mode' => cache_store
::MODE_APPLICATION
,
1468 'component' => 'phpunit',
1469 'area' => 'multi_loader'
1471 $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'phpunittest1', 3);
1472 $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'phpunittest2', 2);
1474 $cache = cache
::make('phpunit', 'multi_loader');
1475 $this->assertInstanceOf(cache_application
::class, $cache);
1476 $this->assertFalse($cache->get('test'));
1477 $this->assertTrue($cache->set('test', 'test'));
1478 $this->assertEquals('test', $cache->get('test'));
1479 $this->assertTrue($cache->delete('test'));
1480 $this->assertFalse($cache->get('test'));
1481 $this->assertTrue($cache->set('test', 'test'));
1482 $this->assertTrue($cache->purge());
1483 $this->assertFalse($cache->get('test'));
1485 // Test the many commands.
1486 $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C')));
1487 $result = $cache->get_many(array('a', 'b', 'c'));
1488 $this->assertIsArray($result);
1489 $this->assertCount(3, $result);
1490 $this->assertArrayHasKey('a', $result);
1491 $this->assertArrayHasKey('b', $result);
1492 $this->assertArrayHasKey('c', $result);
1493 $this->assertEquals('A', $result['a']);
1494 $this->assertEquals('B', $result['b']);
1495 $this->assertEquals('C', $result['c']);
1496 $this->assertEquals($result, $cache->get_many(array('a', 'b', 'c')));
1497 $this->assertEquals(2, $cache->delete_many(array('a', 'c')));
1498 $result = $cache->get_many(array('a', 'b', 'c'));
1499 $this->assertIsArray($result);
1500 $this->assertCount(3, $result);
1501 $this->assertArrayHasKey('a', $result);
1502 $this->assertArrayHasKey('b', $result);
1503 $this->assertArrayHasKey('c', $result);
1504 $this->assertFalse($result['a']);
1505 $this->assertEquals('B', $result['b']);
1506 $this->assertFalse($result['c']);
1508 // Test non-recursive deletes.
1509 $this->assertTrue($cache->set('test', 'test'));
1510 $this->assertSame('test', $cache->get('test'));
1511 $this->assertTrue($cache->delete('test', false));
1512 // We should still have it on a deeper loader.
1513 $this->assertSame('test', $cache->get('test'));
1514 // Test non-recusive with many functions.
1515 $this->assertSame(3, $cache->set_many(array(
1520 $this->assertSame('one', $cache->get('one'));
1521 $this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three')));
1522 $this->assertSame(3, $cache->delete_many(array('one', 'two', 'three'), false));
1523 $this->assertSame('one', $cache->get('one'));
1524 $this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three')));
1528 * Data provider to try using a TTL or non-TTL cache.
1532 public function ttl_or_not(): array {
1533 return [[false], [true]];
1537 * Data provider to try using a TTL or non-TTL cache, and static acceleration or not.
1541 public function ttl_and_static_acceleration_or_not(): array {
1542 return [[false, false], [false, true], [true, false], [true, true]];
1546 * Data provider to try using a TTL or non-TTL cache, and simple data on or off.
1550 public function ttl_and_simple_data_or_not(): array {
1551 // Same values as for ttl and static acceleration (two booleans).
1552 return $this->ttl_and_static_acceleration_or_not();
1556 * Shared code to set up a two or three-layer versioned cache for testing.
1558 * @param bool $ttl If true, sets TTL in the definition
1559 * @param bool $threelayer If true, uses a 3-layer instead of 2-layer cache
1560 * @param bool $staticacceleration If true, enables static acceleration
1561 * @param bool $simpledata If true, enables simple data
1562 * @return \cache_application Cache
1564 protected function create_versioned_cache(bool $ttl, bool $threelayer = false,
1565 bool $staticacceleration = false, bool $simpledata = false): \cache_application
{
1566 $instance = cache_config_testing
::instance(true);
1567 $instance->phpunit_add_file_store('a', false);
1568 $instance->phpunit_add_file_store('b', false);
1570 $instance->phpunit_add_file_store('c', false);
1573 'mode' => cache_store
::MODE_APPLICATION
,
1574 'component' => 'phpunit',
1575 'area' => 'multi_loader'
1578 $defarray['ttl'] = '600';
1580 if ($staticacceleration) {
1581 $defarray['staticacceleration'] = true;
1582 $defarray['staticaccelerationsize'] = 10;
1585 $defarray['simpledata'] = true;
1587 $instance->phpunit_add_definition('phpunit/multi_loader', $defarray, false);
1588 $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'a', 1);
1589 $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'b', 2);
1591 $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'c', 3);
1594 $multicache = cache
::make('phpunit', 'multi_loader');
1599 * Tests basic use of versioned cache.
1601 * @dataProvider ttl_and_simple_data_or_not
1602 * @param bool $ttl If true, uses a TTL cache.
1603 * @param bool $simpledata If true, turns on simple data flag
1604 * @covers ::set_versioned
1605 * @covers ::get_versioned
1607 public function test_versioned_cache_basic(bool $ttl, bool $simpledata): void
{
1608 $multicache = $this->create_versioned_cache($ttl, false, false, $simpledata);
1610 $this->assertTrue($multicache->set_versioned('game', 1, 'Pooh-sticks'));
1612 $result = $multicache->get_versioned('game', 1, IGNORE_MISSING
, $actualversion);
1613 $this->assertEquals('Pooh-sticks', $result);
1614 $this->assertEquals(1, $actualversion);
1618 * Tests versioned cache with objects.
1620 * @dataProvider ttl_and_static_acceleration_or_not
1621 * @param bool $ttl If true, uses a TTL cache.
1622 * @param bool $staticacceleration If true, enables static acceleration
1623 * @covers ::set_versioned
1624 * @covers ::get_versioned
1626 public function test_versioned_cache_objects(bool $ttl, bool $staticacceleration): void
{
1627 $multicache = $this->create_versioned_cache($ttl, false, $staticacceleration);
1629 // Set an object value.
1630 $data = (object)['game' => 'Pooh-sticks'];
1631 $this->assertTrue($multicache->set_versioned('game', 1, $data));
1634 $result = $multicache->get_versioned('game', 1);
1635 $this->assertEquals('Pooh-sticks', $result->game
);
1637 // Mess about with the value in the returned object.
1638 $result->game
= 'Tag';
1640 // Get it again and confirm the cached object has not been affected.
1641 $result = $multicache->get_versioned('game', 1);
1642 $this->assertEquals('Pooh-sticks', $result->game
);
1646 * Tests requesting a version that doesn't exist.
1648 * @dataProvider ttl_or_not
1649 * @param bool $ttl If true, uses a TTL cache.
1650 * @covers ::set_versioned
1651 * @covers ::get_versioned
1653 public function test_versioned_cache_not_exist(bool $ttl): void
{
1654 $multicache = $this->create_versioned_cache($ttl);
1656 $multicache->set_versioned('game', 1, 'Pooh-sticks');
1658 // Exists but with wrong version.
1659 $this->assertFalse($multicache->get_versioned('game', 2));
1661 // Doesn't exist at all.
1662 $this->assertFalse($multicache->get_versioned('frog', 0));
1666 * Tests attempts to use get after set_version or get_version after set.
1668 * @dataProvider ttl_or_not
1669 * @param bool $ttl If true, uses a TTL cache.
1670 * @covers ::set_versioned
1671 * @covers ::get_versioned
1673 public function test_versioned_cache_incompatible_versioning(bool $ttl): void
{
1674 $multicache = $this->create_versioned_cache($ttl);
1676 // What if you use get on a get_version cache?
1677 $multicache->set_versioned('game', 1, 'Pooh-sticks');
1679 $multicache->get('game');
1681 } catch (\coding_exception
$e) {
1682 $this->assertStringContainsString('Unexpectedly found versioned cache entry', $e->getMessage());
1685 // Or get_version on a get cache?
1686 $multicache->set('toy', 'Train set');
1688 $multicache->get_versioned('toy', 1);
1690 } catch (\coding_exception
$e) {
1691 $this->assertStringContainsString('Unexpectedly found non-versioned cache entry', $e->getMessage());
1696 * Versions are only stored once, so if you set a newer version you will always get it even
1697 * if you ask for the lower version number.
1699 * @dataProvider ttl_or_not
1700 * @param bool $ttl If true, uses a TTL cache.
1701 * @covers ::set_versioned
1702 * @covers ::get_versioned
1704 public function test_versioned_cache_single_copy(bool $ttl): void
{
1705 $multicache = $this->create_versioned_cache($ttl);
1707 $multicache->set_versioned('game', 1, 'Pooh-sticks');
1708 $multicache->set_versioned('game', 2, 'Tag');
1709 $this->assertEquals('Tag', $multicache->get_versioned('game', 1, IGNORE_MISSING
, $actualversion));
1711 // The reported version number matches the one returned, not requested.
1712 $this->assertEquals(2, $actualversion);
1716 * If the first (local) store has an outdated copy but the second (shared) store has a newer
1717 * one, then it should automatically be retrieved.
1719 * @dataProvider ttl_or_not
1720 * @param bool $ttl If true, uses a TTL cache.
1721 * @covers ::set_versioned
1722 * @covers ::get_versioned
1724 public function test_versioned_cache_outdated_local(bool $ttl): void
{
1725 $multicache = $this->create_versioned_cache($ttl);
1727 // Set initial value to version 2, 'Tag', in both stores.
1728 $multicache->set_versioned('game', 2, 'Tag');
1730 // Get the two separate cache stores for the multi-level cache.
1731 $factory = cache_factory
::instance();
1732 $definition = $factory->create_definition('phpunit', 'multi_loader');
1733 [0 => $storea, 1 => $storeb] = $factory->get_store_instances_in_use($definition);
1735 // Simulate what happens if the shared cache is updated with a new version but the
1736 // local one still has an old version.
1737 $hashgame = cache_helper
::hash_key('game', $definition);
1738 $data = 'British Bulldog';
1740 $data = new \
cache_ttl_wrapper($data, 600);
1742 $storeb->set($hashgame, new \core_cache\version_wrapper
($data, 3));
1744 // If we ask for the old one we'll get it straight off from local cache.
1745 $this->assertEquals('Tag', $multicache->get_versioned('game', 2));
1747 // But if we ask for the new one it will still get it via the shared cache.
1748 $this->assertEquals('British Bulldog', $multicache->get_versioned('game', 3));
1750 // Also, now it will have been updated in the local cache as well.
1751 $localvalue = $storea->get($hashgame);
1753 // In case the time has changed slightly since the first set, we can't do an exact
1754 // compare, so check it ignoring the time field.
1755 $this->assertEquals(3, $localvalue->version
);
1756 $ttldata = $localvalue->data
;
1757 $this->assertInstanceOf('cache_ttl_wrapper', $ttldata);
1758 $this->assertEquals('British Bulldog', $ttldata->data
);
1760 $this->assertEquals(new \core_cache\version_wrapper
('British Bulldog', 3), $localvalue);
1765 * When we request a newer version, older ones are automatically deleted in every level of the
1766 * cache (to save I/O if there are multiple requests, as if there is another request it will
1767 * not have to retrieve the values to find out that they're old).
1769 * @dataProvider ttl_or_not
1770 * @param bool $ttl If true, uses a TTL cache.
1771 * @covers ::set_versioned
1772 * @covers ::get_versioned
1774 public function test_versioned_cache_deleting_outdated(bool $ttl): void
{
1775 $multicache = $this->create_versioned_cache($ttl);
1777 // Set initial value to version 2, 'Tag', in both stores.
1778 $multicache->set_versioned('game', 2, 'Tag');
1780 // Get the two separate cache stores for the multi-level cache.
1781 $factory = cache_factory
::instance();
1782 $definition = $factory->create_definition('phpunit', 'multi_loader');
1783 [0 => $storea, 1 => $storeb] = $factory->get_store_instances_in_use($definition);
1785 // If we request a newer version, then any older version should be deleted in each
1787 $this->assertFalse($multicache->get_versioned('game', 4));
1788 $hashgame = cache_helper
::hash_key('game', $definition);
1789 $this->assertFalse($storea->get($hashgame));
1790 $this->assertFalse($storeb->get($hashgame));
1794 * Tests a versioned cache when using static cache.
1796 * @covers ::set_versioned
1797 * @covers ::get_versioned
1799 public function test_versioned_cache_static(): void
{
1800 $staticcache = $this->create_versioned_cache(false, false, true);
1802 // Set a value in the cache, version 1. This will store it in static acceleration.
1803 $staticcache->set_versioned('game', 1, 'Pooh-sticks');
1805 // Get the first cache store (we don't need the second one for this test).
1806 $factory = cache_factory
::instance();
1807 $definition = $factory->create_definition('phpunit', 'multi_loader');
1808 [0 => $storea] = $factory->get_store_instances_in_use($definition);
1810 // Hack a newer version into cache store without directly calling set (now the static
1811 // has v1, store has v2). This simulates another client updating the cache.
1812 $hashgame = cache_helper
::hash_key('game', $definition);
1813 $storea->set($hashgame, new \core_cache\version_wrapper
('Tag', 2));
1815 // Get the key from the cache, v1. This will use static acceleration.
1816 $this->assertEquals('Pooh-sticks', $staticcache->get_versioned('game', 1));
1818 // Now if we ask for a newer version, it should not use the static cached one.
1819 $this->assertEquals('Tag', $staticcache->get_versioned('game', 2));
1821 // This get should have updated static acceleration, so it will be used next time without
1823 $storea->set($hashgame, new \core_cache\version_wrapper
('British Bulldog', 3));
1824 $this->assertEquals('Tag', $staticcache->get_versioned('game', 2));
1826 // Requesting the higher version will get rid of static acceleration again.
1827 $this->assertEquals('British Bulldog', $staticcache->get_versioned('game', 3));
1829 // Finally ask for a version that doesn't exist anywhere, just to confirm it returns null.
1830 $this->assertFalse($staticcache->get_versioned('game', 4));
1834 * Tests basic use of 3-layer versioned caches.
1836 * @covers ::set_versioned
1837 * @covers ::get_versioned
1839 public function test_versioned_cache_3_layers_basic(): void
{
1840 $multicache = $this->create_versioned_cache(false, true);
1842 // Basic use of set_versioned and get_versioned.
1843 $multicache->set_versioned('game', 1, 'Pooh-sticks');
1844 $this->assertEquals('Pooh-sticks', $multicache->get_versioned('game', 1));
1846 // What if you ask for a version that doesn't exist?
1847 $this->assertFalse($multicache->get_versioned('game', 2));
1849 // Setting a new version wipes out the old version; if you request it, you get the new one.
1850 $multicache->set_versioned('game', 2, 'Tag');
1851 $this->assertEquals('Tag', $multicache->get_versioned('game', 1));
1855 * Tests use of 3-layer versioned caches where the 3 layers currently have different versions.
1857 * @covers ::set_versioned
1858 * @covers ::get_versioned
1860 public function test_versioned_cache_3_layers_different_data(): void
{
1861 // Set version 2 using normal method.
1862 $multicache = $this->create_versioned_cache(false, true);
1863 $multicache->set_versioned('game', 2, 'Tag');
1865 // Get the three separate cache stores for the multi-level cache.
1866 $factory = cache_factory
::instance();
1867 $definition = $factory->create_definition('phpunit', 'multi_loader');
1868 [0 => $storea, 1 => $storeb, 2 => $storec] = $factory->get_store_instances_in_use($definition);
1870 // Set up two other versions so every level has a different version.
1871 $hashgame = cache_helper
::hash_key('game', $definition);
1872 $storeb->set($hashgame, new \core_cache\version_wrapper
('British Bulldog', 3));
1873 $storec->set($hashgame, new \core_cache\version_wrapper
('Hopscotch', 4));
1875 // First request can be satisfied from A; second request requires B...
1876 $this->assertEquals('Tag', $multicache->get_versioned('game', 2));
1877 $this->assertEquals('British Bulldog', $multicache->get_versioned('game', 3));
1879 // And should update the data in A.
1880 $this->assertEquals(new \core_cache\version_wrapper
('British Bulldog', 3), $storea->get($hashgame));
1881 $this->assertEquals('British Bulldog', $multicache->get_versioned('game', 1));
1883 // But newer data should still be in C.
1884 $this->assertEquals('Hopscotch', $multicache->get_versioned('game', 4));
1885 // Now it's stored in A and B too.
1886 $this->assertEquals(new \core_cache\version_wrapper
('Hopscotch', 4), $storea->get($hashgame));
1887 $this->assertEquals(new \core_cache\version_wrapper
('Hopscotch', 4), $storeb->get($hashgame));
1891 * Test that multiple application loaders work ok.
1893 public function test_multiple_session_loaders() {
1894 /* @var cache_config_testing $instance */
1895 $instance = cache_config_testing
::instance(true);
1896 $instance->phpunit_add_session_store('phpunittest1');
1897 $instance->phpunit_add_session_store('phpunittest2');
1898 $instance->phpunit_add_definition('phpunit/multi_loader', array(
1899 'mode' => cache_store
::MODE_SESSION
,
1900 'component' => 'phpunit',
1901 'area' => 'multi_loader'
1903 $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'phpunittest1', 3);
1904 $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'phpunittest2', 2);
1906 $cache = cache
::make('phpunit', 'multi_loader');
1907 $this->assertInstanceOf(cache_session
::class, $cache);
1908 $this->assertFalse($cache->get('test'));
1909 $this->assertTrue($cache->set('test', 'test'));
1910 $this->assertEquals('test', $cache->get('test'));
1911 $this->assertTrue($cache->delete('test'));
1912 $this->assertFalse($cache->get('test'));
1913 $this->assertTrue($cache->set('test', 'test'));
1914 $this->assertTrue($cache->purge());
1915 $this->assertFalse($cache->get('test'));
1917 // Test the many commands.
1918 $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C')));
1919 $result = $cache->get_many(array('a', 'b', 'c'));
1920 $this->assertIsArray($result);
1921 $this->assertCount(3, $result);
1922 $this->assertArrayHasKey('a', $result);
1923 $this->assertArrayHasKey('b', $result);
1924 $this->assertArrayHasKey('c', $result);
1925 $this->assertEquals('A', $result['a']);
1926 $this->assertEquals('B', $result['b']);
1927 $this->assertEquals('C', $result['c']);
1928 $this->assertEquals($result, $cache->get_many(array('a', 'b', 'c')));
1929 $this->assertEquals(2, $cache->delete_many(array('a', 'c')));
1930 $result = $cache->get_many(array('a', 'b', 'c'));
1931 $this->assertIsArray($result);
1932 $this->assertCount(3, $result);
1933 $this->assertArrayHasKey('a', $result);
1934 $this->assertArrayHasKey('b', $result);
1935 $this->assertArrayHasKey('c', $result);
1936 $this->assertFalse($result['a']);
1937 $this->assertEquals('B', $result['b']);
1938 $this->assertFalse($result['c']);
1940 // Test non-recursive deletes.
1941 $this->assertTrue($cache->set('test', 'test'));
1942 $this->assertSame('test', $cache->get('test'));
1943 $this->assertTrue($cache->delete('test', false));
1944 // We should still have it on a deeper loader.
1945 $this->assertSame('test', $cache->get('test'));
1946 // Test non-recusive with many functions.
1947 $this->assertSame(3, $cache->set_many(array(
1952 $this->assertSame('one', $cache->get('one'));
1953 $this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three')));
1954 $this->assertSame(3, $cache->delete_many(array('one', 'two', 'three'), false));
1955 $this->assertSame('one', $cache->get('one'));
1956 $this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three')));
1960 * Test switching users with session caches.
1962 public function test_session_cache_switch_user() {
1963 $this->resetAfterTest(true);
1964 $cache = cache
::make_from_params(cache_store
::MODE_SESSION
, 'phpunit', 'sessioncache');
1965 $user1 = $this->getDataGenerator()->create_user();
1966 $user2 = $this->getDataGenerator()->create_user();
1968 // Log in as the first user.
1969 $this->setUser($user1);
1970 $sesskey1 = sesskey();
1972 // Set a basic value in the cache.
1973 $cache->set('var', 1);
1974 $this->assertTrue($cache->has('var'));
1975 $this->assertEquals(1, $cache->get('var'));
1977 // Change to the second user.
1978 $this->setUser($user2);
1979 $sesskey2 = sesskey();
1981 // Make sure the cache doesn't give us the data for the last user.
1982 $this->assertNotEquals($sesskey1, $sesskey2);
1983 $this->assertFalse($cache->has('var'));
1984 $this->assertEquals(false, $cache->get('var'));
1988 * Test switching users with session caches.
1990 public function test_session_cache_switch_user_application_mapping() {
1991 $this->resetAfterTest(true);
1992 $instance = cache_config_testing
::instance(true);
1993 $instance->phpunit_add_file_store('testfilestore');
1994 $instance->phpunit_add_definition('phpunit/testappsession', array(
1995 'mode' => cache_store
::MODE_SESSION
,
1996 'component' => 'phpunit',
1997 'area' => 'testappsession'
1999 $instance->phpunit_add_definition_mapping('phpunit/testappsession', 'testfilestore', 3);
2000 $cache = cache
::make('phpunit', 'testappsession');
2001 $user1 = $this->getDataGenerator()->create_user();
2002 $user2 = $this->getDataGenerator()->create_user();
2004 // Log in as the first user.
2005 $this->setUser($user1);
2006 $sesskey1 = sesskey();
2008 // Set a basic value in the cache.
2009 $cache->set('var', 1);
2010 $this->assertTrue($cache->has('var'));
2011 $this->assertEquals(1, $cache->get('var'));
2013 // Change to the second user.
2014 $this->setUser($user2);
2015 $sesskey2 = sesskey();
2017 // Make sure the cache doesn't give us the data for the last user.
2018 $this->assertNotEquals($sesskey1, $sesskey2);
2019 $this->assertFalse($cache->has('var'));
2020 $this->assertEquals(false, $cache->get('var'));
2024 * Test two session caches being used at once to confirm collisions don't occur.
2026 public function test_dual_session_caches() {
2027 $instance = cache_config_testing
::instance(true);
2028 $instance->phpunit_add_definition('phpunit/testsess1', array(
2029 'mode' => cache_store
::MODE_SESSION
,
2030 'component' => 'phpunit',
2031 'area' => 'testsess1'
2033 $instance->phpunit_add_definition('phpunit/testsess2', array(
2034 'mode' => cache_store
::MODE_SESSION
,
2035 'component' => 'phpunit',
2036 'area' => 'testsess2'
2038 $cache1 = cache
::make('phpunit', 'testsess1');
2039 $cache2 = cache
::make('phpunit', 'testsess2');
2041 $this->assertFalse($cache1->has('test'));
2042 $this->assertFalse($cache2->has('test'));
2044 $this->assertTrue($cache1->set('test', '1'));
2046 $this->assertTrue($cache1->has('test'));
2047 $this->assertFalse($cache2->has('test'));
2049 $this->assertTrue($cache2->set('test', '2'));
2051 $this->assertEquals(1, $cache1->get('test'));
2052 $this->assertEquals(2, $cache2->get('test'));
2054 $this->assertTrue($cache1->delete('test'));
2058 * Test multiple session caches when switching user.
2060 public function test_session_cache_switch_user_multiple() {
2061 $this->resetAfterTest(true);
2062 $cache1 = cache
::make_from_params(cache_store
::MODE_SESSION
, 'phpunit', 'sessioncache1');
2063 $cache2 = cache
::make_from_params(cache_store
::MODE_SESSION
, 'phpunit', 'sessioncache2');
2064 $user1 = $this->getDataGenerator()->create_user();
2065 $user2 = $this->getDataGenerator()->create_user();
2067 // Log in as the first user.
2068 $this->setUser($user1);
2069 $sesskey1 = sesskey();
2071 // Set a basic value in the caches.
2072 $cache1->set('var', 1);
2073 $cache2->set('var', 2);
2074 $this->assertEquals(1, $cache1->get('var'));
2075 $this->assertEquals(2, $cache2->get('var'));
2077 // Change to the second user.
2078 $this->setUser($user2);
2079 $sesskey2 = sesskey();
2081 // Make sure the cache doesn't give us the data for the last user.
2082 // Also make sure that switching the user has lead to both caches being purged.
2083 $this->assertNotEquals($sesskey1, $sesskey2);
2084 $this->assertEquals(false, $cache1->get('var'));
2085 $this->assertEquals(false, $cache2->get('var'));
2089 * Test application locking.
2091 public function test_application_locking() {
2092 $instance = cache_config_testing
::instance(true);
2093 $instance->phpunit_add_definition('phpunit/test_application_locking', array(
2094 'mode' => cache_store
::MODE_APPLICATION
,
2095 'component' => 'phpunit',
2096 'area' => 'test_application_locking',
2097 'staticacceleration' => true,
2098 'staticaccelerationsize' => 1,
2099 'requirelockingread' => true,
2100 'requirelockingwrite' => true
2102 $cache = cache
::make('phpunit', 'test_application_locking');
2103 $this->assertInstanceOf(cache_application
::class, $cache);
2105 $this->assertTrue($cache->set('a', 'A'));
2106 $this->assertTrue($cache->set('b', 'B'));
2107 $this->assertTrue($cache->set('c', 'C'));
2108 $this->assertEquals('A', $cache->get('a'));
2109 $this->assertEquals(array('b' => 'B', 'c' => 'C'), $cache->get_many(array('b', 'c')));
2110 $this->assertTrue($cache->delete('a'));
2111 $this->assertFalse($cache->has('a'));
2115 * Test the static cache_helper method purge_stores_used_by_definition.
2117 public function test_purge_stores_used_by_definition() {
2118 $instance = cache_config_testing
::instance(true);
2119 $instance->phpunit_add_definition('phpunit/test_purge_stores_used_by_definition', array(
2120 'mode' => cache_store
::MODE_APPLICATION
,
2121 'component' => 'phpunit',
2122 'area' => 'test_purge_stores_used_by_definition'
2124 $cache = cache
::make('phpunit', 'test_purge_stores_used_by_definition');
2125 $this->assertInstanceOf(cache_application
::class, $cache);
2126 $this->assertTrue($cache->set('test', 'test'));
2129 cache_helper
::purge_stores_used_by_definition('phpunit', 'test_purge_stores_used_by_definition');
2131 $cache = cache
::make('phpunit', 'test_purge_stores_used_by_definition');
2132 $this->assertInstanceOf(cache_application
::class, $cache);
2133 $this->assertFalse($cache->get('test'));
2137 * Test purge routines.
2139 public function test_purge_routines() {
2140 $instance = cache_config_testing
::instance(true);
2141 $instance->phpunit_add_definition('phpunit/purge1', array(
2142 'mode' => cache_store
::MODE_APPLICATION
,
2143 'component' => 'phpunit',
2146 $instance->phpunit_add_definition('phpunit/purge2', array(
2147 'mode' => cache_store
::MODE_APPLICATION
,
2148 'component' => 'phpunit',
2150 'requireidentifiers' => array(
2155 $factory = cache_factory
::instance();
2156 $definition = $factory->create_definition('phpunit', 'purge1');
2157 $this->assertFalse($definition->has_required_identifiers());
2158 $cache = $factory->create_cache($definition);
2159 $this->assertInstanceOf(cache_application
::class, $cache);
2160 $this->assertTrue($cache->set('test', 'test'));
2161 $this->assertTrue($cache->has('test'));
2162 cache_helper
::purge_by_definition('phpunit', 'purge1');
2163 $this->assertFalse($cache->has('test'));
2165 $factory = cache_factory
::instance();
2166 $definition = $factory->create_definition('phpunit', 'purge2');
2167 $this->assertTrue($definition->has_required_identifiers());
2168 $cache = $factory->create_cache($definition);
2169 $this->assertInstanceOf(cache_application
::class, $cache);
2170 $this->assertTrue($cache->set('test', 'test'));
2171 $this->assertTrue($cache->has('test'));
2172 cache_helper
::purge_stores_used_by_definition('phpunit', 'purge2');
2173 $this->assertFalse($cache->has('test'));
2176 cache_helper
::purge_by_definition('phpunit', 'purge2');
2177 $this->fail('Should not be able to purge a definition required identifiers without providing them.');
2178 } catch (\coding_exception
$ex) {
2179 $this->assertStringContainsString('Identifier required for cache has not been provided', $ex->getMessage());
2184 * Tests that ad-hoc caches are correctly purged with a purge_all call.
2186 public function test_purge_all_with_adhoc_caches() {
2187 $cache = cache
::make_from_params(cache_store
::MODE_REQUEST
, 'core_cache', 'test');
2188 $cache->set('test', 123);
2189 cache_helper
::purge_all();
2190 $this->assertFalse($cache->get('test'));
2194 * Test that the default stores all support searching.
2196 public function test_defaults_support_searching() {
2197 $instance = cache_config_testing
::instance(true);
2198 $instance->phpunit_add_definition('phpunit/search1', array(
2199 'mode' => cache_store
::MODE_APPLICATION
,
2200 'component' => 'phpunit',
2201 'area' => 'search1',
2202 'requiresearchable' => true
2204 $instance->phpunit_add_definition('phpunit/search2', array(
2205 'mode' => cache_store
::MODE_SESSION
,
2206 'component' => 'phpunit',
2207 'area' => 'search2',
2208 'requiresearchable' => true
2210 $instance->phpunit_add_definition('phpunit/search3', array(
2211 'mode' => cache_store
::MODE_REQUEST
,
2212 'component' => 'phpunit',
2213 'area' => 'search3',
2214 'requiresearchable' => true
2216 $factory = cache_factory
::instance();
2218 // Test application cache is searchable.
2219 $definition = $factory->create_definition('phpunit', 'search1');
2220 $this->assertInstanceOf(cache_definition
::class, $definition);
2221 $this->assertEquals(cache_store
::IS_SEARCHABLE
, $definition->get_requirements_bin() & cache_store
::IS_SEARCHABLE
);
2222 $cache = $factory->create_cache($definition);
2223 $this->assertInstanceOf(cache_application
::class, $cache);
2224 $this->assertArrayHasKey('cache_is_searchable', $cache->phpunit_get_store_implements());
2226 // Test session cache is searchable.
2227 $definition = $factory->create_definition('phpunit', 'search2');
2228 $this->assertInstanceOf(cache_definition
::class, $definition);
2229 $this->assertEquals(cache_store
::IS_SEARCHABLE
, $definition->get_requirements_bin() & cache_store
::IS_SEARCHABLE
);
2230 $cache = $factory->create_cache($definition);
2231 $this->assertInstanceOf(cache_session
::class, $cache);
2232 $this->assertArrayHasKey('cache_is_searchable', $cache->phpunit_get_store_implements());
2234 // Test request cache is searchable.
2235 $definition = $factory->create_definition('phpunit', 'search3');
2236 $this->assertInstanceOf(cache_definition
::class, $definition);
2237 $this->assertEquals(cache_store
::IS_SEARCHABLE
, $definition->get_requirements_bin() & cache_store
::IS_SEARCHABLE
);
2238 $cache = $factory->create_cache($definition);
2239 $this->assertInstanceOf(cache_request
::class, $cache);
2240 $this->assertArrayHasKey('cache_is_searchable', $cache->phpunit_get_store_implements());
2244 * Test static acceleration
2246 * Note: All the assertGreaterThanOrEqual() in this test should be assertGreaterThan() be because of some microtime()
2247 * resolution problems under some OSs / PHP versions, we are accepting equal as valid outcome. For more info see MDL-57147.
2249 public function test_static_acceleration() {
2250 $instance = cache_config_testing
::instance();
2251 $instance->phpunit_add_definition('phpunit/accelerated', array(
2252 'mode' => cache_store
::MODE_APPLICATION
,
2253 'component' => 'phpunit',
2254 'area' => 'accelerated',
2255 'staticacceleration' => true,
2256 'staticaccelerationsize' => 3,
2258 $instance->phpunit_add_definition('phpunit/accelerated2', array(
2259 'mode' => cache_store
::MODE_APPLICATION
,
2260 'component' => 'phpunit',
2261 'area' => 'accelerated2',
2262 'staticacceleration' => true,
2263 'staticaccelerationsize' => 3,
2265 $instance->phpunit_add_definition('phpunit/accelerated3', array(
2266 'mode' => cache_store
::MODE_APPLICATION
,
2267 'component' => 'phpunit',
2268 'area' => 'accelerated3',
2269 'staticacceleration' => true,
2270 'staticaccelerationsize' => 3,
2272 $instance->phpunit_add_definition('phpunit/accelerated4', array(
2273 'mode' => cache_store
::MODE_APPLICATION
,
2274 'component' => 'phpunit',
2275 'area' => 'accelerated4',
2276 'staticacceleration' => true,
2277 'staticaccelerationsize' => 4,
2279 $instance->phpunit_add_definition('phpunit/simpledataarea1', array(
2280 'mode' => cache_store
::MODE_APPLICATION
,
2281 'component' => 'phpunit',
2282 'area' => 'simpledataarea1',
2283 'staticacceleration' => true,
2284 'simpledata' => false
2286 $instance->phpunit_add_definition('phpunit/simpledataarea2', array(
2287 'mode' => cache_store
::MODE_APPLICATION
,
2288 'component' => 'phpunit',
2289 'area' => 'simpledataarea2',
2290 'staticacceleration' => true,
2291 'simpledata' => true
2294 $cache = cache
::make('phpunit', 'accelerated');
2295 $this->assertInstanceOf(cache_phpunit_application
::class, $cache);
2297 // Set and get three elements.
2298 $this->assertTrue($cache->set('a', 'A'));
2299 $this->assertTrue($cache->set('b', 'B'));
2300 $this->assertTrue($cache->set('c', 'C'));
2301 $this->assertEquals('A', $cache->get('a'));
2302 $this->assertEquals(array('b' => 'B', 'c' => 'C'), $cache->get_many(array('b', 'c')));
2304 // Make sure all items are in static acceleration array.
2305 $this->assertEquals('A', $cache->phpunit_static_acceleration_get('a'));
2306 $this->assertEquals('B', $cache->phpunit_static_acceleration_get('b'));
2307 $this->assertEquals('C', $cache->phpunit_static_acceleration_get('c'));
2309 // Add new value and make sure it is in cache and it is in array.
2310 $this->assertTrue($cache->set('d', 'D'));
2311 $this->assertEquals('D', $cache->phpunit_static_acceleration_get('d'));
2312 $this->assertEquals('D', $cache->get('d'));
2314 // Now the least recent accessed item (a) is no longer in acceleration array.
2315 $this->assertFalse($cache->phpunit_static_acceleration_get('a'));
2316 $this->assertEquals('B', $cache->phpunit_static_acceleration_get('b'));
2317 $this->assertEquals('C', $cache->phpunit_static_acceleration_get('c'));
2319 // Adding and deleting element.
2320 $this->assertTrue($cache->set('a', 'A'));
2321 $this->assertTrue($cache->delete('a'));
2322 $this->assertFalse($cache->phpunit_static_acceleration_get('a'));
2323 $this->assertFalse($cache->has('a'));
2325 // Make sure "purge" deletes from the array as well.
2327 $this->assertFalse($cache->phpunit_static_acceleration_get('a'));
2328 $this->assertFalse($cache->phpunit_static_acceleration_get('b'));
2329 $this->assertFalse($cache->phpunit_static_acceleration_get('c'));
2330 $this->assertFalse($cache->phpunit_static_acceleration_get('d'));
2331 $this->assertFalse($cache->phpunit_static_acceleration_get('e'));
2333 // Check that the array holds the last accessed items by get/set.
2334 $this->assertTrue($cache->set('a', 'A'));
2335 $this->assertTrue($cache->set('b', 'B'));
2336 $this->assertTrue($cache->set('c', 'C'));
2337 $this->assertTrue($cache->set('d', 'D'));
2338 $this->assertTrue($cache->set('e', 'E'));
2339 $this->assertFalse($cache->phpunit_static_acceleration_get('a'));
2340 $this->assertFalse($cache->phpunit_static_acceleration_get('b'));
2341 $this->assertEquals('C', $cache->phpunit_static_acceleration_get('c'));
2342 $this->assertEquals('D', $cache->phpunit_static_acceleration_get('d'));
2343 $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e'));
2345 // Store a cacheable_object, get many times and ensure each time wake_for_cache is used.
2346 // Both get and get_many are tested. Two cache entries are used to ensure the times aren't
2347 // confused with multiple calls to get()/get_many().
2348 $startmicrotime = microtime(true);
2349 $cacheableobject = new cache_phpunit_dummy_object(1, 1, $startmicrotime);
2350 $cacheableobject2 = new cache_phpunit_dummy_object(2, 2, $startmicrotime);
2351 $this->assertTrue($cache->set('a', $cacheableobject));
2352 $this->assertTrue($cache->set('b', $cacheableobject2));
2353 $staticaccelerationreturntime = $cache->phpunit_static_acceleration_get('a')->propertytime
;
2354 $staticaccelerationreturntimeb = $cache->phpunit_static_acceleration_get('b')->propertytime
;
2355 $this->assertGreaterThanOrEqual($startmicrotime, $staticaccelerationreturntime, 'Restore time of static must be newer.');
2357 // Reset the static cache without resetting backing store.
2358 $cache->phpunit_static_acceleration_purge();
2360 // Get the value from the backend store, populating the static cache.
2361 $cachevalue = $cache->get('a');
2362 $this->assertInstanceOf(cache_phpunit_dummy_object
::class, $cachevalue);
2363 $this->assertGreaterThanOrEqual($staticaccelerationreturntime, $cachevalue->propertytime
);
2364 $backingstorereturntime = $cachevalue->propertytime
;
2366 $results = $cache->get_many(array('b'));
2367 $this->assertInstanceOf(cache_phpunit_dummy_object
::class, $results['b']);
2368 $this->assertGreaterThanOrEqual($staticaccelerationreturntimeb, $results['b']->propertytime
);
2369 $backingstorereturntimeb = $results['b']->propertytime
;
2371 // Obtain the value again and confirm that static cache is using wake_from_cache.
2372 // Upon failure, the times are not adjusted as wake_from_cache is skipped as the
2373 // value is stored serialized in the static acceleration cache.
2374 $cachevalue = $cache->phpunit_static_acceleration_get('a');
2375 $this->assertInstanceOf(cache_phpunit_dummy_object
::class, $cachevalue);
2376 $this->assertGreaterThanOrEqual($backingstorereturntime, $cachevalue->propertytime
);
2378 $results = $cache->get_many(array('b'));
2379 $this->assertInstanceOf(cache_phpunit_dummy_object
::class, $results['b']);
2380 $this->assertGreaterThanOrEqual($backingstorereturntimeb, $results['b']->propertytime
);
2382 /** @var cache_phpunit_application $cache */
2383 $cache = cache
::make('phpunit', 'accelerated2');
2384 $this->assertInstanceOf(cache_phpunit_application
::class, $cache);
2386 // Check that the array holds the last accessed items by get/set.
2387 $this->assertTrue($cache->set('a', 'A'));
2388 $this->assertTrue($cache->set('b', 'B'));
2389 $this->assertTrue($cache->set('c', 'C'));
2390 $this->assertTrue($cache->set('d', 'D'));
2391 $this->assertTrue($cache->set('e', 'E'));
2392 // Current keys in the array: c, d, e.
2393 $this->assertEquals('C', $cache->phpunit_static_acceleration_get('c'));
2394 $this->assertEquals('D', $cache->phpunit_static_acceleration_get('d'));
2395 $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e'));
2396 $this->assertFalse($cache->phpunit_static_acceleration_get('a'));
2397 $this->assertFalse($cache->phpunit_static_acceleration_get('b'));
2399 $this->assertEquals('A', $cache->get('a'));
2400 // Current keys in the array: d, e, a.
2401 $this->assertEquals('D', $cache->phpunit_static_acceleration_get('d'));
2402 $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e'));
2403 $this->assertEquals('A', $cache->phpunit_static_acceleration_get('a'));
2404 $this->assertFalse($cache->phpunit_static_acceleration_get('b'));
2405 $this->assertFalse($cache->phpunit_static_acceleration_get('c'));
2407 // Current keys in the array: d, e, a.
2408 $this->assertEquals(array('c' => 'C'), $cache->get_many(array('c')));
2409 // Current keys in the array: e, a, c.
2410 $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e'));
2411 $this->assertEquals('A', $cache->phpunit_static_acceleration_get('a'));
2412 $this->assertEquals('C', $cache->phpunit_static_acceleration_get('c'));
2413 $this->assertFalse($cache->phpunit_static_acceleration_get('b'));
2414 $this->assertFalse($cache->phpunit_static_acceleration_get('d'));
2417 $cache = cache
::make('phpunit', 'accelerated3');
2418 $this->assertInstanceOf(cache_phpunit_application
::class, $cache);
2420 // Check that the array holds the last accessed items by get/set.
2421 $this->assertTrue($cache->set('a', 'A'));
2422 $this->assertTrue($cache->set('b', 'B'));
2423 $this->assertTrue($cache->set('c', 'C'));
2424 $this->assertTrue($cache->set('d', 'D'));
2425 $this->assertTrue($cache->set('e', 'E'));
2426 $this->assertFalse($cache->phpunit_static_acceleration_get('a'));
2427 $this->assertFalse($cache->phpunit_static_acceleration_get('b'));
2428 $this->assertEquals('C', $cache->phpunit_static_acceleration_get('c'));
2429 $this->assertEquals('D', $cache->phpunit_static_acceleration_get('d'));
2430 $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e'));
2432 $this->assertTrue($cache->set('b', 'B2'));
2433 $this->assertFalse($cache->phpunit_static_acceleration_get('a'));
2434 $this->assertEquals('B2', $cache->phpunit_static_acceleration_get('b'));
2435 $this->assertFalse($cache->phpunit_static_acceleration_get('c'));
2436 $this->assertEquals('D', $cache->phpunit_static_acceleration_get('d'));
2437 $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e'));
2439 $this->assertEquals(2, $cache->set_many(array('b' => 'B3', 'c' => 'C3')));
2440 $this->assertFalse($cache->phpunit_static_acceleration_get('a'));
2441 $this->assertEquals('B3', $cache->phpunit_static_acceleration_get('b'));
2442 $this->assertEquals('C3', $cache->phpunit_static_acceleration_get('c'));
2443 $this->assertFalse($cache->phpunit_static_acceleration_get('d'));
2444 $this->assertEquals('E', $cache->phpunit_static_acceleration_get('e'));
2446 $cache = cache
::make('phpunit', 'accelerated4');
2447 $this->assertInstanceOf(cache_phpunit_application
::class, $cache);
2448 $this->assertTrue($cache->set('a', 'A'));
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->assertEquals('A', $cache->phpunit_static_acceleration_get('a'));
2456 $this->assertEquals('A', $cache->get('a'));
2458 // Setting simpledata to false objects are cloned when retrieving data.
2459 $cache = cache
::make('phpunit', 'simpledataarea1');
2460 $notreallysimple = new \
stdClass();
2461 $notreallysimple->name
= 'a';
2462 $cache->set('a', $notreallysimple);
2463 $returnedinstance1 = $cache->get('a');
2464 $returnedinstance2 = $cache->get('a');
2465 $returnedinstance1->name
= 'b';
2466 $this->assertEquals('a', $returnedinstance2->name
);
2468 // Setting simpledata to true we assume that data does not contain references.
2469 $cache = cache
::make('phpunit', 'simpledataarea2');
2470 $notreallysimple = new \
stdClass();
2471 $notreallysimple->name
= 'a';
2472 $cache->set('a', $notreallysimple);
2473 $returnedinstance1 = $cache->get('a');
2474 $returnedinstance2 = $cache->get('a');
2475 $returnedinstance1->name
= 'b';
2476 $this->assertEquals('b', $returnedinstance2->name
);
2479 public function test_identifiers_have_separate_caches() {
2480 $cachepg = cache
::make('core', 'databasemeta', array('dbfamily' => 'pgsql'));
2481 $cachepg->set(1, 'here');
2482 $cachemy = cache
::make('core', 'databasemeta', array('dbfamily' => 'mysql'));
2483 $cachemy->set(2, 'there');
2484 $this->assertEquals('here', $cachepg->get(1));
2485 $this->assertEquals('there', $cachemy->get(2));
2486 $this->assertFalse($cachemy->get(1));
2489 public function test_performance_debug() {
2491 $this->resetAfterTest(true);
2492 $CFG->perfdebug
= 15;
2494 $instance = cache_config_testing
::instance();
2495 $applicationid = 'phpunit/applicationperf';
2496 $instance->phpunit_add_definition($applicationid, array(
2497 'mode' => cache_store
::MODE_APPLICATION
,
2498 'component' => 'phpunit',
2499 'area' => 'applicationperf'
2501 $sessionid = 'phpunit/sessionperf';
2502 $instance->phpunit_add_definition($sessionid, array(
2503 'mode' => cache_store
::MODE_SESSION
,
2504 'component' => 'phpunit',
2505 'area' => 'sessionperf'
2507 $requestid = 'phpunit/requestperf';
2508 $instance->phpunit_add_definition($requestid, array(
2509 'mode' => cache_store
::MODE_REQUEST
,
2510 'component' => 'phpunit',
2511 'area' => 'requestperf'
2514 $application = cache
::make('phpunit', 'applicationperf');
2515 $session = cache
::make('phpunit', 'sessionperf');
2516 $request = cache
::make('phpunit', 'requestperf');
2518 // Check that no stats are recorded for these definitions yet.
2519 $stats = cache_helper
::get_stats();
2520 $this->assertArrayNotHasKey($applicationid, $stats);
2521 $this->assertArrayHasKey($sessionid, $stats); // Session cache sets a key on construct.
2522 $this->assertArrayNotHasKey($requestid, $stats);
2524 // Check that stores register misses.
2525 $this->assertFalse($application->get('missMe'));
2526 $this->assertFalse($application->get('missMe'));
2527 $this->assertFalse($session->get('missMe'));
2528 $this->assertFalse($session->get('missMe'));
2529 $this->assertFalse($session->get('missMe'));
2530 $this->assertFalse($request->get('missMe'));
2531 $this->assertFalse($request->get('missMe'));
2532 $this->assertFalse($request->get('missMe'));
2533 $this->assertFalse($request->get('missMe'));
2535 $endstats = cache_helper
::get_stats();
2536 $this->assertEquals(2, $endstats[$applicationid]['stores']['default_application']['misses']);
2537 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['hits']);
2538 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['sets']);
2539 $this->assertEquals(3, $endstats[$sessionid]['stores']['default_session']['misses']);
2540 $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['hits']);
2541 $this->assertEquals(1, $endstats[$sessionid]['stores']['default_session']['sets']);
2542 $this->assertEquals(4, $endstats[$requestid]['stores']['default_request']['misses']);
2543 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['hits']);
2544 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['sets']);
2546 $startstats = cache_helper
::get_stats();
2548 // Check that stores register sets.
2549 $this->assertTrue($application->set('setMe1', 1));
2550 $this->assertTrue($application->set('setMe2', 2));
2551 $this->assertTrue($session->set('setMe1', 1));
2552 $this->assertTrue($session->set('setMe2', 2));
2553 $this->assertTrue($session->set('setMe3', 3));
2554 $this->assertTrue($request->set('setMe1', 1));
2555 $this->assertTrue($request->set('setMe2', 2));
2556 $this->assertTrue($request->set('setMe3', 3));
2557 $this->assertTrue($request->set('setMe4', 4));
2559 $endstats = cache_helper
::get_stats();
2560 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['misses'] -
2561 $startstats[$applicationid]['stores']['default_application']['misses']);
2562 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['hits'] -
2563 $startstats[$applicationid]['stores']['default_application']['hits']);
2564 $this->assertEquals(2, $endstats[$applicationid]['stores']['default_application']['sets'] -
2565 $startstats[$applicationid]['stores']['default_application']['sets']);
2566 $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['misses'] -
2567 $startstats[$sessionid]['stores']['default_session']['misses']);
2568 $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['hits'] -
2569 $startstats[$sessionid]['stores']['default_session']['hits']);
2570 $this->assertEquals(3, $endstats[$sessionid]['stores']['default_session']['sets'] -
2571 $startstats[$sessionid]['stores']['default_session']['sets']);
2572 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['misses'] -
2573 $startstats[$requestid]['stores']['default_request']['misses']);
2574 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['hits'] -
2575 $startstats[$requestid]['stores']['default_request']['hits']);
2576 $this->assertEquals(4, $endstats[$requestid]['stores']['default_request']['sets'] -
2577 $startstats[$requestid]['stores']['default_request']['sets']);
2579 $startstats = cache_helper
::get_stats();
2581 // Check that stores register hits.
2582 $this->assertEquals($application->get('setMe1'), 1);
2583 $this->assertEquals($application->get('setMe2'), 2);
2584 $this->assertEquals($session->get('setMe1'), 1);
2585 $this->assertEquals($session->get('setMe2'), 2);
2586 $this->assertEquals($session->get('setMe3'), 3);
2587 $this->assertEquals($request->get('setMe1'), 1);
2588 $this->assertEquals($request->get('setMe2'), 2);
2589 $this->assertEquals($request->get('setMe3'), 3);
2590 $this->assertEquals($request->get('setMe4'), 4);
2592 $endstats = cache_helper
::get_stats();
2593 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['misses'] -
2594 $startstats[$applicationid]['stores']['default_application']['misses']);
2595 $this->assertEquals(2, $endstats[$applicationid]['stores']['default_application']['hits'] -
2596 $startstats[$applicationid]['stores']['default_application']['hits']);
2597 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['sets'] -
2598 $startstats[$applicationid]['stores']['default_application']['sets']);
2599 $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['misses'] -
2600 $startstats[$sessionid]['stores']['default_session']['misses']);
2601 $this->assertEquals(3, $endstats[$sessionid]['stores']['default_session']['hits'] -
2602 $startstats[$sessionid]['stores']['default_session']['hits']);
2603 $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['sets'] -
2604 $startstats[$sessionid]['stores']['default_session']['sets']);
2605 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['misses'] -
2606 $startstats[$requestid]['stores']['default_request']['misses']);
2607 $this->assertEquals(4, $endstats[$requestid]['stores']['default_request']['hits'] -
2608 $startstats[$requestid]['stores']['default_request']['hits']);
2609 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['sets'] -
2610 $startstats[$requestid]['stores']['default_request']['sets']);
2612 $startstats = cache_helper
::get_stats();
2614 // Check that stores register through get_many.
2615 $application->get_many(array('setMe1', 'setMe2'));
2616 $session->get_many(array('setMe1', 'setMe2', 'setMe3'));
2617 $request->get_many(array('setMe1', 'setMe2', 'setMe3', 'setMe4'));
2619 $endstats = cache_helper
::get_stats();
2620 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['misses'] -
2621 $startstats[$applicationid]['stores']['default_application']['misses']);
2622 $this->assertEquals(2, $endstats[$applicationid]['stores']['default_application']['hits'] -
2623 $startstats[$applicationid]['stores']['default_application']['hits']);
2624 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['sets'] -
2625 $startstats[$applicationid]['stores']['default_application']['sets']);
2626 $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['misses'] -
2627 $startstats[$sessionid]['stores']['default_session']['misses']);
2628 $this->assertEquals(3, $endstats[$sessionid]['stores']['default_session']['hits'] -
2629 $startstats[$sessionid]['stores']['default_session']['hits']);
2630 $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['sets'] -
2631 $startstats[$sessionid]['stores']['default_session']['sets']);
2632 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['misses'] -
2633 $startstats[$requestid]['stores']['default_request']['misses']);
2634 $this->assertEquals(4, $endstats[$requestid]['stores']['default_request']['hits'] -
2635 $startstats[$requestid]['stores']['default_request']['hits']);
2636 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['sets'] -
2637 $startstats[$requestid]['stores']['default_request']['sets']);
2639 $startstats = cache_helper
::get_stats();
2641 // Check that stores register through set_many.
2642 $this->assertEquals(2, $application->set_many(['setMe1' => 1, 'setMe2' => 2]));
2643 $this->assertEquals(3, $session->set_many(['setMe1' => 1, 'setMe2' => 2, 'setMe3' => 3]));
2644 $this->assertEquals(4, $request->set_many(['setMe1' => 1, 'setMe2' => 2, 'setMe3' => 3, 'setMe4' => 4]));
2646 $endstats = cache_helper
::get_stats();
2648 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['misses'] -
2649 $startstats[$applicationid]['stores']['default_application']['misses']);
2650 $this->assertEquals(0, $endstats[$applicationid]['stores']['default_application']['hits'] -
2651 $startstats[$applicationid]['stores']['default_application']['hits']);
2652 $this->assertEquals(2, $endstats[$applicationid]['stores']['default_application']['sets'] -
2653 $startstats[$applicationid]['stores']['default_application']['sets']);
2654 $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['misses'] -
2655 $startstats[$sessionid]['stores']['default_session']['misses']);
2656 $this->assertEquals(0, $endstats[$sessionid]['stores']['default_session']['hits'] -
2657 $startstats[$sessionid]['stores']['default_session']['hits']);
2658 $this->assertEquals(3, $endstats[$sessionid]['stores']['default_session']['sets'] -
2659 $startstats[$sessionid]['stores']['default_session']['sets']);
2660 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['misses'] -
2661 $startstats[$requestid]['stores']['default_request']['misses']);
2662 $this->assertEquals(0, $endstats[$requestid]['stores']['default_request']['hits'] -
2663 $startstats[$requestid]['stores']['default_request']['hits']);
2664 $this->assertEquals(4, $endstats[$requestid]['stores']['default_request']['sets'] -
2665 $startstats[$requestid]['stores']['default_request']['sets']);
2668 public function test_static_cache() {
2670 $this->resetAfterTest(true);
2671 $CFG->perfdebug
= 15;
2673 // Create cache store with static acceleration.
2674 $instance = cache_config_testing
::instance();
2675 $applicationid = 'phpunit/applicationperf';
2676 $instance->phpunit_add_definition($applicationid, array(
2677 'mode' => cache_store
::MODE_APPLICATION
,
2678 'component' => 'phpunit',
2679 'area' => 'applicationperf',
2680 'simplekeys' => true,
2681 'staticacceleration' => true,
2682 'staticaccelerationsize' => 3
2685 $application = cache
::make('phpunit', 'applicationperf');
2687 // Check that stores register sets.
2688 $this->assertTrue($application->set('setMe1', 1));
2689 $this->assertTrue($application->set('setMe2', 0));
2690 $this->assertTrue($application->set('setMe3', array()));
2691 $this->assertTrue($application->get('setMe1') !== false);
2692 $this->assertTrue($application->get('setMe2') !== false);
2693 $this->assertTrue($application->get('setMe3') !== false);
2695 // Check that the static acceleration worked, even on empty arrays and the number 0.
2696 $endstats = cache_helper
::get_stats();
2697 $this->assertEquals(0, $endstats[$applicationid]['stores']['** static accel. **']['misses']);
2698 $this->assertEquals(3, $endstats[$applicationid]['stores']['** static accel. **']['hits']);
2701 public function test_performance_debug_off() {
2703 $this->resetAfterTest(true);
2704 $CFG->perfdebug
= 7;
2706 $instance = cache_config_testing
::instance();
2707 $applicationid = 'phpunit/applicationperfoff';
2708 $instance->phpunit_add_definition($applicationid, array(
2709 'mode' => cache_store
::MODE_APPLICATION
,
2710 'component' => 'phpunit',
2711 'area' => 'applicationperfoff'
2713 $sessionid = 'phpunit/sessionperfoff';
2714 $instance->phpunit_add_definition($sessionid, array(
2715 'mode' => cache_store
::MODE_SESSION
,
2716 'component' => 'phpunit',
2717 'area' => 'sessionperfoff'
2719 $requestid = 'phpunit/requestperfoff';
2720 $instance->phpunit_add_definition($requestid, array(
2721 'mode' => cache_store
::MODE_REQUEST
,
2722 'component' => 'phpunit',
2723 'area' => 'requestperfoff'
2726 $application = cache
::make('phpunit', 'applicationperfoff');
2727 $session = cache
::make('phpunit', 'sessionperfoff');
2728 $request = cache
::make('phpunit', 'requestperfoff');
2730 // Check that no stats are recorded for these definitions yet.
2731 $stats = cache_helper
::get_stats();
2732 $this->assertArrayNotHasKey($applicationid, $stats);
2733 $this->assertArrayNotHasKey($sessionid, $stats);
2734 $this->assertArrayNotHasKey($requestid, $stats);
2736 // Trigger cache misses, cache sets and cache hits.
2737 $this->assertFalse($application->get('missMe'));
2738 $this->assertTrue($application->set('setMe', 1));
2739 $this->assertEquals(1, $application->get('setMe'));
2740 $this->assertFalse($session->get('missMe'));
2741 $this->assertTrue($session->set('setMe', 3));
2742 $this->assertEquals(3, $session->get('setMe'));
2743 $this->assertFalse($request->get('missMe'));
2744 $this->assertTrue($request->set('setMe', 4));
2745 $this->assertEquals(4, $request->get('setMe'));
2747 // Check that no stats are being recorded for these definitions.
2748 $endstats = cache_helper
::get_stats();
2749 $this->assertArrayNotHasKey($applicationid, $endstats);
2750 $this->assertArrayNotHasKey($sessionid, $endstats);
2751 $this->assertArrayNotHasKey($requestid, $endstats);
2755 * Tests session cache event purge and subsequent visit in the same request.
2757 * This test simulates a cache being created, a value being set, then the value being purged.
2758 * A subsequent use of the same cache is started in the same request which fills the cache.
2759 * A new request is started a short time later.
2760 * The cache should be filled.
2762 public function test_session_event_purge_same_second() {
2763 $instance = cache_config_testing
::instance();
2764 $instance->phpunit_add_definition('phpunit/eventpurgetest', array(
2765 'mode' => cache_store
::MODE_SESSION
,
2766 'component' => 'phpunit',
2767 'area' => 'eventpurgetest',
2768 'invalidationevents' => array(
2773 // Create the cache, set a value, and immediately purge it by event.
2774 $cache = cache
::make('phpunit', 'eventpurgetest');
2775 $cache->set('testkey1', 'test data 1');
2776 $this->assertEquals('test data 1', $cache->get('testkey1'));
2777 cache_helper
::purge_by_event('crazyevent');
2778 $this->assertFalse($cache->get('testkey1'));
2780 // Set up the cache again in the same request and add a new value back in.
2781 $factory = cache_factory
::instance();
2782 $factory->reset_cache_instances();
2783 $cache = cache
::make('phpunit', 'eventpurgetest');
2784 $cache->set('testkey1', 'test data 2');
2785 $this->assertEquals('test data 2', $cache->get('testkey1'));
2787 // Trick the cache into thinking that this is a new request.
2788 cache_phpunit_cache
::simulate_new_request();
2789 $factory = cache_factory
::instance();
2790 $factory->reset_cache_instances();
2792 // Set up the cache again.
2793 // This is a subsequent request at a new time, so we instead the invalidation time will be checked.
2794 // The invalidation time should match the last purged time and the cache will not be re-purged.
2795 $cache = cache
::make('phpunit', 'eventpurgetest');
2796 $this->assertEquals('test data 2', $cache->get('testkey1'));
2800 * Test that values set in different sessions are stored with different key prefixes.
2802 public function test_session_distinct_storage_key() {
2803 $this->resetAfterTest();
2805 // Prepare a dummy session cache configuration.
2806 $config = cache_config_testing
::instance();
2807 $config->phpunit_add_definition('phpunit/test_session_distinct_storage_key', array(
2808 'mode' => cache_store
::MODE_SESSION
,
2809 'component' => 'phpunit',
2810 'area' => 'test_session_distinct_storage_key'
2813 // First anonymous user's session cache.
2814 cache_phpunit_session
::phpunit_mockup_session_id('foo');
2816 $cache1 = cache
::make('phpunit', 'test_session_distinct_storage_key');
2818 // Reset cache instances to emulate a new request.
2819 cache_factory
::instance()->reset_cache_instances();
2821 // Another anonymous user's session cache.
2822 cache_phpunit_session
::phpunit_mockup_session_id('bar');
2824 $cache2 = cache
::make('phpunit', 'test_session_distinct_storage_key');
2826 cache_factory
::instance()->reset_cache_instances();
2828 // Guest user's session cache.
2829 cache_phpunit_session
::phpunit_mockup_session_id('baz');
2830 $this->setGuestUser();
2831 $cache3 = cache
::make('phpunit', 'test_session_distinct_storage_key');
2833 cache_factory
::instance()->reset_cache_instances();
2835 // Same guest user's session cache but in another browser window.
2836 cache_phpunit_session
::phpunit_mockup_session_id('baz');
2837 $this->setGuestUser();
2838 $cache4 = cache
::make('phpunit', 'test_session_distinct_storage_key');
2840 // Assert that different PHP session implies different key prefix for storing values.
2841 $this->assertNotEquals($cache1->phpunit_get_key_prefix(), $cache2->phpunit_get_key_prefix());
2843 // Assert that same PHP session implies same key prefix for storing values.
2844 $this->assertEquals($cache3->phpunit_get_key_prefix(), $cache4->phpunit_get_key_prefix());