MDL-41106 cache: several fixes for the session cache.
[moodle.git] / cache / tests / cache_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * PHPunit tests for the cache API
19  *
20  * This file is part of Moodle's cache API, affectionately called MUC.
21  * It contains the components that are requried in order to use caching.
22  *
23  * @package    core
24  * @category   cache
25  * @copyright  2012 Sam Hemelryk
26  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27  */
29 defined('MOODLE_INTERNAL') || die();
31 // Include the necessary evils.
32 global $CFG;
33 require_once($CFG->dirroot.'/cache/locallib.php');
34 require_once($CFG->dirroot.'/cache/tests/fixtures/lib.php');
36 /**
37  * PHPunit tests for the cache API
38  *
39  * @copyright  2012 Sam Hemelryk
40  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41  */
42 class core_cache_testcase extends advanced_testcase {
44     /**
45      * Set things back to the default before each test.
46      */
47     public function setUp() {
48         parent::setUp();
49         cache_factory::reset();
50         cache_config_phpunittest::create_default_configuration();
51     }
53     /**
54      * Final task is to reset the cache system
55      */
56     public static function tearDownAfterClass() {
57         parent::tearDownAfterClass();
58         cache_factory::reset();
59     }
61     /**
62      * Tests cache configuration
63      */
64     public function test_cache_config() {
65         $instance = cache_config::instance();
66         $this->assertInstanceOf('cache_config_phpunittest', $instance);
68         $this->assertTrue(cache_config_phpunittest::config_file_exists());
70         $stores = $instance->get_all_stores();
71         $this->assertCount(3, $stores);
72         foreach ($stores as $name => $store) {
73             // Check its an array.
74             $this->assertInternalType('array', $store);
75             // Check the name is the key.
76             $this->assertEquals($name, $store['name']);
77             // Check that it has been declared default.
78             $this->assertTrue($store['default']);
79             // Required attributes = name + plugin + configuration + modes + features.
80             $this->assertArrayHasKey('name', $store);
81             $this->assertArrayHasKey('plugin', $store);
82             $this->assertArrayHasKey('configuration', $store);
83             $this->assertArrayHasKey('modes', $store);
84             $this->assertArrayHasKey('features', $store);
85         }
87         $modemappings = $instance->get_mode_mappings();
88         $this->assertCount(3, $modemappings);
89         $modes = array(
90             cache_store::MODE_APPLICATION => false,
91             cache_store::MODE_SESSION => false,
92             cache_store::MODE_REQUEST => false,
93         );
94         foreach ($modemappings as $mapping) {
95             // We expect 3 properties.
96             $this->assertCount(3, $mapping);
97             // Required attributes = mode + store.
98             $this->assertArrayHasKey('mode', $mapping);
99             $this->assertArrayHasKey('store', $mapping);
100             // Record the mode.
101             $modes[$mapping['mode']] = true;
102         }
104         // Must have the default 3 modes and no more.
105         $this->assertCount(3, $mapping);
106         foreach ($modes as $mode) {
107             $this->assertTrue($mode);
108         }
110         $definitions = $instance->get_definitions();
111         // The event invalidation definition is required for the cache API and must be there.
112         $this->assertArrayHasKey('core/eventinvalidation', $definitions);
114         $definitionmappings = $instance->get_definition_mappings();
115         foreach ($definitionmappings as $mapping) {
116             // Required attributes = definition + store.
117             $this->assertArrayHasKey('definition', $mapping);
118             $this->assertArrayHasKey('store', $mapping);
119         }
120     }
122     /**
123      * Tests for cache keys that would break on windows.
124      */
125     public function test_windows_nasty_keys() {
126         $instance = cache_config_phpunittest::instance();
127         $instance->phpunit_add_definition('phpunit/windowskeytest', array(
128             'mode' => cache_store::MODE_APPLICATION,
129             'component' => 'phpunit',
130             'area' => 'windowskeytest',
131             'simplekeys' => true,
132             'simpledata' => true
133         ));
134         $cache = cache::make('phpunit', 'windowskeytest');
135         $this->assertTrue($cache->set('contest', 'test data 1'));
136         $this->assertEquals('test data 1', $cache->get('contest'));
137     }
139     /**
140      * Tests the default application cache
141      */
142     public function test_default_application_cache() {
143         $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'phpunit', 'applicationtest');
144         $this->assertInstanceOf('cache_application', $cache);
145         $this->run_on_cache($cache);
147         $instance = cache_config_phpunittest::instance(true);
148         $instance->phpunit_add_definition('phpunit/test_default_application_cache', array(
149             'mode' => cache_store::MODE_APPLICATION,
150             'component' => 'phpunit',
151             'area' => 'test_default_application_cache',
152             'persistent' => true,
153             'persistentmaxsize' => 1
154         ));
155         $cache = cache::make('phpunit', 'test_default_application_cache');
156         $this->assertInstanceOf('cache_application', $cache);
157         $this->run_on_cache($cache);
158     }
160     /**
161      * Tests the default session cache
162      */
163     public function test_default_session_cache() {
164         $cache = cache::make_from_params(cache_store::MODE_SESSION, 'phpunit', 'applicationtest');
165         $this->assertInstanceOf('cache_session', $cache);
166         $this->run_on_cache($cache);
167     }
169     /**
170      * Tests the default request cache
171      */
172     public function test_default_request_cache() {
173         $cache = cache::make_from_params(cache_store::MODE_REQUEST, 'phpunit', 'applicationtest');
174         $this->assertInstanceOf('cache_request', $cache);
175         $this->run_on_cache($cache);
176     }
178     /**
179      * Tests using a cache system when there are no stores available (who knows what the admin did to achieve this).
180      */
181     public function test_on_cache_without_store() {
182         $instance = cache_config_phpunittest::instance(true);
183         $instance->phpunit_add_definition('phpunit/nostoretest1', array(
184             'mode' => cache_store::MODE_APPLICATION,
185             'component' => 'phpunit',
186             'area' => 'nostoretest1',
187         ));
188         $instance->phpunit_add_definition('phpunit/nostoretest2', array(
189             'mode' => cache_store::MODE_APPLICATION,
190             'component' => 'phpunit',
191             'area' => 'nostoretest2',
192             'persistent' => true
193         ));
194         $instance->phpunit_remove_stores();
196         $cache = cache::make('phpunit', 'nostoretest1');
197         $this->run_on_cache($cache);
199         $cache = cache::make('phpunit', 'nostoretest2');
200         $this->run_on_cache($cache);
201     }
203     /**
204      * Runs a standard series of access and use tests on a cache instance.
205      *
206      * This function is great because we can use it to ensure all of the loaders perform exactly the same way.
207      *
208      * @param cache_loader $cache
209      */
210     protected function run_on_cache(cache_loader $cache) {
211         $key = 'contestkey';
212         $datascalars = array('test data', null);
213         $dataarray = array('contest' => 'data', 'part' => 'two');
214         $dataobject = (object)$dataarray;
216         foreach ($datascalars as $datascalar) {
217             $this->assertTrue($cache->purge());
219             // Check all read methods.
220             $this->assertFalse($cache->get($key));
221             $this->assertFalse($cache->has($key));
222             $result = $cache->get_many(array($key));
223             $this->assertCount(1, $result);
224             $this->assertFalse(reset($result));
225             $this->assertFalse($cache->has_any(array($key)));
226             $this->assertFalse($cache->has_all(array($key)));
228             // Set the data.
229             $this->assertTrue($cache->set($key, $datascalar));
230             // Setting it more than once should be permitted.
231             $this->assertTrue($cache->set($key, $datascalar));
233             // Recheck the read methods.
234             $this->assertEquals($datascalar, $cache->get($key));
235             $this->assertTrue($cache->has($key));
236             $result = $cache->get_many(array($key));
237             $this->assertCount(1, $result);
238             $this->assertEquals($datascalar, reset($result));
239             $this->assertTrue($cache->has_any(array($key)));
240             $this->assertTrue($cache->has_all(array($key)));
242             // Delete it.
243             $this->assertTrue($cache->delete($key));
245             // Check its gone.
246             $this->assertFalse($cache->get($key));
247             $this->assertFalse($cache->has($key));
248         }
250         // Test arrays.
251         $this->assertTrue($cache->set($key, $dataarray));
252         $this->assertEquals($dataarray, $cache->get($key));
254         // Test objects.
255         $this->assertTrue($cache->set($key, $dataobject));
256         $this->assertEquals($dataobject, $cache->get($key));
258         $specobject = new cache_phpunit_dummy_object('red', 'blue');
259         $this->assertTrue($cache->set($key, $specobject));
260         $result = $cache->get($key);
261         $this->assertInstanceOf('cache_phpunit_dummy_object', $result);
262         $this->assertEquals('red_ptc_wfc', $result->property1);
263         $this->assertEquals('blue_ptc_wfc', $result->property2);
265         // Test array of objects.
266         $specobject = new cache_phpunit_dummy_object('red', 'blue');
267         $data = new cacheable_object_array(array(
268             clone($specobject),
269             clone($specobject),
270             clone($specobject))
271         );
272         $this->assertTrue($cache->set($key, $data));
273         $result = $cache->get($key);
274         $this->assertInstanceOf('cacheable_object_array', $result);
275         $this->assertCount(3, $data);
276         foreach ($result as $item) {
277             $this->assertInstanceOf('cache_phpunit_dummy_object', $item);
278             $this->assertEquals('red_ptc_wfc', $item->property1);
279             $this->assertEquals('blue_ptc_wfc', $item->property2);
280         }
282         // Test set many.
283         $cache->set_many(array('key1' => 'data1', 'key2' => 'data2', 'key3' => null));
284         $this->assertEquals('data1', $cache->get('key1'));
285         $this->assertEquals('data2', $cache->get('key2'));
286         $this->assertEquals(null, $cache->get('key3'));
287         $this->assertTrue($cache->delete('key1'));
288         $this->assertTrue($cache->delete('key2'));
289         $this->assertTrue($cache->delete('key3'));
291         $cache->set_many(array(
292             'key1' => array(1, 2, 3),
293             'key2' => array(3, 2, 1),
294         ));
295         $this->assertInternalType('array', $cache->get('key1'));
296         $this->assertInternalType('array', $cache->get('key2'));
297         $this->assertCount(3, $cache->get('key1'));
298         $this->assertCount(3, $cache->get('key2'));
299         $this->assertInternalType('array', $cache->get_many(array('key1', 'key2')));
300         $this->assertCount(2, $cache->get_many(array('key1', 'key2')));
301         $this->assertEquals(2, $cache->delete_many(array('key1', 'key2')));
303         // Test delete many.
304         $this->assertTrue($cache->set('key1', 'data1'));
305         $this->assertTrue($cache->set('key2', 'data2'));
306         $this->assertTrue($cache->set('key3', null));
308         $this->assertEquals('data1', $cache->get('key1'));
309         $this->assertEquals('data2', $cache->get('key2'));
310         $this->assertEquals(null, $cache->get('key3'));
312         $this->assertEquals(3, $cache->delete_many(array('key1', 'key2', 'key3')));
314         $this->assertFalse($cache->get('key1'));
315         $this->assertFalse($cache->get('key2'));
316         $this->assertFalse($cache->get('key3'));
318         // Quick reference test.
319         $obj = new stdClass;
320         $obj->key = 'value';
321         $ref =& $obj;
322         $this->assertTrue($cache->set('obj', $obj));
324         $obj->key = 'eulav';
325         $var = $cache->get('obj');
326         $this->assertInstanceOf('stdClass', $var);
327         $this->assertEquals('value', $var->key);
329         $ref->key = 'eulav';
330         $var = $cache->get('obj');
331         $this->assertInstanceOf('stdClass', $var);
332         $this->assertEquals('value', $var->key);
334         $this->assertTrue($cache->delete('obj'));
336         // Deep reference test.
337         $obj1 = new stdClass;
338         $obj1->key = 'value';
339         $obj2 = new stdClass;
340         $obj2->key = 'test';
341         $obj3 = new stdClass;
342         $obj3->key = 'pork';
343         $obj1->subobj =& $obj2;
344         $obj2->subobj =& $obj3;
345         $this->assertTrue($cache->set('obj', $obj1));
347         $obj1->key = 'eulav';
348         $obj2->key = 'tset';
349         $obj3->key = 'krop';
350         $var = $cache->get('obj');
351         $this->assertInstanceOf('stdClass', $var);
352         $this->assertEquals('value', $var->key);
353         $this->assertInstanceOf('stdClass', $var->subobj);
354         $this->assertEquals('test', $var->subobj->key);
355         $this->assertInstanceOf('stdClass', $var->subobj->subobj);
356         $this->assertEquals('pork', $var->subobj->subobj->key);
357         $this->assertTrue($cache->delete('obj'));
359         // Death reference test... basicaly we don't want this to die.
360         $obj = new stdClass;
361         $obj->key = 'value';
362         $obj->self =& $obj;
363         $this->assertTrue($cache->set('obj', $obj));
364         $var = $cache->get('obj');
365         $this->assertInstanceOf('stdClass', $var);
366         $this->assertEquals('value', $var->key);
368         // Reference test after retrieve.
369         $obj = new stdClass;
370         $obj->key = 'value';
371         $this->assertTrue($cache->set('obj', $obj));
373         $var1 = $cache->get('obj');
374         $this->assertInstanceOf('stdClass', $var1);
375         $this->assertEquals('value', $var1->key);
376         $var1->key = 'eulav';
377         $this->assertEquals('eulav', $var1->key);
379         $var2 = $cache->get('obj');
380         $this->assertInstanceOf('stdClass', $var2);
381         $this->assertEquals('value', $var2->key);
383         $this->assertTrue($cache->delete('obj'));
385         // Test strictness exceptions.
386         try {
387             $cache->get('exception', MUST_EXIST);
388             $this->fail('Exception expected from cache::get using MUST_EXIST');
389         } catch (Exception $e) {
390             $this->assertTrue(true);
391         }
392         try {
393             $cache->get_many(array('exception1', 'exception2'), MUST_EXIST);
394             $this->fail('Exception expected from cache::get_many using MUST_EXIST');
395         } catch (Exception $e) {
396             $this->assertTrue(true);
397         }
398         $cache->set('test', 'test');
399         try {
400             $cache->get_many(array('test', 'exception'), MUST_EXIST);
401             $this->fail('Exception expected from cache::get_many using MUST_EXIST');
402         } catch (Exception $e) {
403             $this->assertTrue(true);
404         }
405     }
407     /**
408      * Tests a definition using a data loader
409      */
410     public function test_definition_data_loader() {
411         $instance = cache_config_phpunittest::instance(true);
412         $instance->phpunit_add_definition('phpunit/datasourcetest', array(
413             'mode' => cache_store::MODE_APPLICATION,
414             'component' => 'phpunit',
415             'area' => 'datasourcetest',
416             'datasource' => 'cache_phpunit_dummy_datasource',
417             'datasourcefile' => 'cache/tests/fixtures/lib.php'
418         ));
420         $cache = cache::make('phpunit', 'datasourcetest');
421         $this->assertInstanceOf('cache_application', $cache);
423         // Purge it to be sure.
424         $this->assertTrue($cache->purge());
425         // It won't be there yet.
426         $this->assertFalse($cache->has('Test'));
427         // It should load it ;).
428         $this->assertTrue($cache->has('Test', true));
430         // Purge it to be sure.
431         $this->assertTrue($cache->purge());
432         $this->assertEquals('Test has no value really.', $cache->get('Test'));
434         // Test multiple values.
435         $this->assertTrue($cache->purge());
436         $this->assertTrue($cache->set('b', 'B'));
437         $result = $cache->get_many(array('a', 'b', 'c'));
438         $this->assertInternalType('array', $result);
439         $this->assertCount(3, $result);
440         $this->assertArrayHasKey('a', $result);
441         $this->assertArrayHasKey('b', $result);
442         $this->assertArrayHasKey('c', $result);
443         $this->assertEquals('a has no value really.', $result['a']);
444         $this->assertEquals('B', $result['b']);
445         $this->assertEquals('c has no value really.', $result['c']);
446     }
448     /**
449      * Tests a definition using an overridden loader
450      */
451     public function test_definition_overridden_loader() {
452         $instance = cache_config_phpunittest::instance(true);
453         $instance->phpunit_add_definition('phpunit/overridetest', array(
454             'mode' => cache_store::MODE_APPLICATION,
455             'component' => 'phpunit',
456             'area' => 'overridetest',
457             'overrideclass' => 'cache_phpunit_dummy_overrideclass',
458             'overrideclassfile' => 'cache/tests/fixtures/lib.php'
459         ));
460         $cache = cache::make('phpunit', 'overridetest');
461         $this->assertInstanceOf('cache_phpunit_dummy_overrideclass', $cache);
462         $this->assertInstanceOf('cache_application', $cache);
463         // Purge it to be sure.
464         $this->assertTrue($cache->purge());
465         // It won't be there yet.
466         $this->assertFalse($cache->has('Test'));
467         // Add it.
468         $this->assertTrue($cache->set('Test', 'Test has no value really.'));
469         // Check its there.
470         $this->assertEquals('Test has no value really.', $cache->get('Test'));
471     }
473     /**
474      * Test a very basic definition.
475      */
476     public function test_definition() {
477         $instance = cache_config_phpunittest::instance();
478         $instance->phpunit_add_definition('phpunit/test', array(
479             'mode' => cache_store::MODE_APPLICATION,
480             'component' => 'phpunit',
481             'area' => 'test',
482         ));
483         $cache = cache::make('phpunit', 'test');
485         $this->assertTrue($cache->set('testkey1', 'test data 1'));
486         $this->assertEquals('test data 1', $cache->get('testkey1'));
487         $this->assertTrue($cache->set('testkey2', 'test data 2'));
488         $this->assertEquals('test data 2', $cache->get('testkey2'));
489     }
491     /**
492      * Test a definition using the simple keys.
493      */
494     public function test_definition_simplekeys() {
495         $instance = cache_config_phpunittest::instance();
496         $instance->phpunit_add_definition('phpunit/simplekeytest', array(
497             'mode' => cache_store::MODE_APPLICATION,
498             'component' => 'phpunit',
499             'area' => 'simplekeytest',
500             'simplekeys' => true
501         ));
502         $cache = cache::make('phpunit', 'simplekeytest');
504         $this->assertTrue($cache->set('testkey1', 'test data 1'));
505         $this->assertEquals('test data 1', $cache->get('testkey1'));
506         $this->assertTrue($cache->set('testkey2', 'test data 2'));
507         $this->assertEquals('test data 2', $cache->get('testkey2'));
509         $cache->purge();
511         $this->assertTrue($cache->set('1', 'test data 1'));
512         $this->assertEquals('test data 1', $cache->get('1'));
513         $this->assertTrue($cache->set('2', 'test data 2'));
514         $this->assertEquals('test data 2', $cache->get('2'));
515     }
517     /**
518      * Test a negative TTL on an application cache.
519      */
520     public function test_application_ttl_negative() {
521         $instance = cache_config_phpunittest::instance(true);
522         $instance->phpunit_add_definition('phpunit/ttltest', array(
523             'mode' => cache_store::MODE_APPLICATION,
524             'component' => 'phpunit',
525             'area' => 'ttltest',
526             'ttl' => -86400 // Set to a day in the past to be extra sure.
527         ));
528         $cache = cache::make('phpunit', 'ttltest');
529         $this->assertInstanceOf('cache_application', $cache);
531         // Purge it to be sure.
532         $this->assertTrue($cache->purge());
533         // It won't be there yet.
534         $this->assertFalse($cache->has('Test'));
535         // Set it now.
536         $this->assertTrue($cache->set('Test', 'Test'));
537         // Check its not there.
538         $this->assertFalse($cache->has('Test'));
539         // Double check by trying to get it.
540         $this->assertFalse($cache->get('Test'));
542         // Test with multiple keys.
543         $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C')));
544         $result = $cache->get_many(array('a', 'b', 'c'));
545         $this->assertInternalType('array', $result);
546         $this->assertCount(3, $result);
547         $this->assertArrayHasKey('a', $result);
548         $this->assertArrayHasKey('b', $result);
549         $this->assertArrayHasKey('c', $result);
550         $this->assertFalse($result['a']);
551         $this->assertFalse($result['b']);
552         $this->assertFalse($result['c']);
554         // Test with multiple keys including missing ones.
555         $result = $cache->get_many(array('a', 'c', 'e'));
556         $this->assertInternalType('array', $result);
557         $this->assertCount(3, $result);
558         $this->assertArrayHasKey('a', $result);
559         $this->assertArrayHasKey('c', $result);
560         $this->assertArrayHasKey('e', $result);
561         $this->assertFalse($result['a']);
562         $this->assertFalse($result['c']);
563         $this->assertFalse($result['e']);
564     }
566     /**
567      * Test a positive TTL on an application cache.
568      */
569     public function test_application_ttl_positive() {
570         $instance = cache_config_phpunittest::instance(true);
571         $instance->phpunit_add_definition('phpunit/ttltest', array(
572             'mode' => cache_store::MODE_APPLICATION,
573             'component' => 'phpunit',
574             'area' => 'ttltest',
575             'ttl' => 86400 // Set to a day in the future to be extra sure.
576         ));
577         $cache = cache::make('phpunit', 'ttltest');
578         $this->assertInstanceOf('cache_application', $cache);
580         // Purge it to be sure.
581         $this->assertTrue($cache->purge());
582         // It won't be there yet.
583         $this->assertFalse($cache->has('Test'));
584         // Set it now.
585         $this->assertTrue($cache->set('Test', 'Test'));
586         // Check its there.
587         $this->assertTrue($cache->has('Test'));
588         // Double check by trying to get it.
589         $this->assertEquals('Test', $cache->get('Test'));
591         // Test with multiple keys.
592         $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C')));
593         $result = $cache->get_many(array('a', 'b', 'c'));
594         $this->assertInternalType('array', $result);
595         $this->assertCount(3, $result);
596         $this->assertArrayHasKey('a', $result);
597         $this->assertArrayHasKey('b', $result);
598         $this->assertArrayHasKey('c', $result);
599         $this->assertEquals('A', $result['a']);
600         $this->assertEquals('B', $result['b']);
601         $this->assertEquals('C', $result['c']);
603         // Test with multiple keys including missing ones.
604         $result = $cache->get_many(array('a', 'c', 'e'));
605         $this->assertInternalType('array', $result);
606         $this->assertCount(3, $result);
607         $this->assertArrayHasKey('a', $result);
608         $this->assertArrayHasKey('c', $result);
609         $this->assertArrayHasKey('e', $result);
610         $this->assertEquals('A', $result['a']);
611         $this->assertEquals('C', $result['c']);
612         $this->assertEquals(false, $result['e']);
613     }
615     /**
616      * Test a negative TTL on an session cache.
617      */
618     public function test_session_ttl_positive() {
619         $instance = cache_config_phpunittest::instance(true);
620         $instance->phpunit_add_definition('phpunit/ttltest', array(
621             'mode' => cache_store::MODE_SESSION,
622             'component' => 'phpunit',
623             'area' => 'ttltest',
624             'ttl' => 86400 // Set to a day in the future to be extra sure.
625         ));
626         $cache = cache::make('phpunit', 'ttltest');
627         $this->assertInstanceOf('cache_session', $cache);
629         // Purge it to be sure.
630         $this->assertTrue($cache->purge());
631         // It won't be there yet.
632         $this->assertFalse($cache->has('Test'));
633         // Set it now.
634         $this->assertTrue($cache->set('Test', 'Test'));
635         // Check its there.
636         $this->assertTrue($cache->has('Test'));
637         // Double check by trying to get it.
638         $this->assertEquals('Test', $cache->get('Test'));
640         // Test with multiple keys.
641         $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C')));
642         $result = $cache->get_many(array('a', 'b', 'c'));
643         $this->assertInternalType('array', $result);
644         $this->assertCount(3, $result);
645         $this->assertArrayHasKey('a', $result);
646         $this->assertArrayHasKey('b', $result);
647         $this->assertArrayHasKey('c', $result);
648         $this->assertEquals('A', $result['a']);
649         $this->assertEquals('B', $result['b']);
650         $this->assertEquals('C', $result['c']);
652         // Test with multiple keys including missing ones.
653         $result = $cache->get_many(array('a', 'c', 'e'));
654         $this->assertInternalType('array', $result);
655         $this->assertCount(3, $result);
656         $this->assertArrayHasKey('a', $result);
657         $this->assertArrayHasKey('c', $result);
658         $this->assertArrayHasKey('e', $result);
659         $this->assertEquals('A', $result['a']);
660         $this->assertEquals('C', $result['c']);
661         $this->assertEquals(false, $result['e']);
662     }
664     /**
665      * Tests manual locking operations on an application cache
666      */
667     public function test_application_manual_locking() {
668         $instance = cache_config_phpunittest::instance();
669         $instance->phpunit_add_definition('phpunit/lockingtest', array(
670             'mode' => cache_store::MODE_APPLICATION,
671             'component' => 'phpunit',
672             'area' => 'lockingtest'
673         ));
674         $cache1 = cache::make('phpunit', 'lockingtest');
675         $cache2 = clone($cache1);
677         $this->assertTrue($cache1->set('testkey', 'test data'));
678         $this->assertTrue($cache2->set('testkey', 'test data'));
680         $this->assertTrue($cache1->acquire_lock('testkey'));
681         $this->assertFalse($cache2->acquire_lock('testkey'));
683         $this->assertTrue($cache1->check_lock_state('testkey'));
684         $this->assertFalse($cache2->check_lock_state('testkey'));
686         $this->assertTrue($cache1->release_lock('testkey'));
687         $this->assertFalse($cache2->release_lock('testkey'));
689         $this->assertTrue($cache1->set('testkey', 'test data'));
690         $this->assertTrue($cache2->set('testkey', 'test data'));
691     }
693     /**
694      * Tests application cache event invalidation
695      */
696     public function test_application_event_invalidation() {
697         $instance = cache_config_phpunittest::instance();
698         $instance->phpunit_add_definition('phpunit/eventinvalidationtest', array(
699             'mode' => cache_store::MODE_APPLICATION,
700             'component' => 'phpunit',
701             'area' => 'eventinvalidationtest',
702             'invalidationevents' => array(
703                 'crazyevent'
704             )
705         ));
706         $cache = cache::make('phpunit', 'eventinvalidationtest');
708         $this->assertTrue($cache->set('testkey1', 'test data 1'));
709         $this->assertEquals('test data 1', $cache->get('testkey1'));
710         $this->assertTrue($cache->set('testkey2', 'test data 2'));
711         $this->assertEquals('test data 2', $cache->get('testkey2'));
713         // Test invalidating a single entry.
714         cache_helper::invalidate_by_event('crazyevent', array('testkey1'));
716         $this->assertFalse($cache->get('testkey1'));
717         $this->assertEquals('test data 2', $cache->get('testkey2'));
719         $this->assertTrue($cache->set('testkey1', 'test data 1'));
721         // Test invalidating both entries.
722         cache_helper::invalidate_by_event('crazyevent', array('testkey1', 'testkey2'));
724         $this->assertFalse($cache->get('testkey1'));
725         $this->assertFalse($cache->get('testkey2'));
726     }
728     /**
729      * Tests session cache event invalidation
730      */
731     public function test_session_event_invalidation() {
732         $instance = cache_config_phpunittest::instance();
733         $instance->phpunit_add_definition('phpunit/test_session_event_invalidation', array(
734             'mode' => cache_store::MODE_SESSION,
735             'component' => 'phpunit',
736             'area' => 'test_session_event_invalidation',
737             'invalidationevents' => array(
738                 'crazyevent'
739             )
740         ));
741         $cache = cache::make('phpunit', 'test_session_event_invalidation');
742         $this->assertInstanceOf('cache_session', $cache);
744         $this->assertTrue($cache->set('testkey1', 'test data 1'));
745         $this->assertEquals('test data 1', $cache->get('testkey1'));
746         $this->assertTrue($cache->set('testkey2', 'test data 2'));
747         $this->assertEquals('test data 2', $cache->get('testkey2'));
749         // Test invalidating a single entry.
750         cache_helper::invalidate_by_event('crazyevent', array('testkey1'));
752         $this->assertFalse($cache->get('testkey1'));
753         $this->assertEquals('test data 2', $cache->get('testkey2'));
755         $this->assertTrue($cache->set('testkey1', 'test data 1'));
757         // Test invalidating both entries.
758         cache_helper::invalidate_by_event('crazyevent', array('testkey1', 'testkey2'));
760         $this->assertFalse($cache->get('testkey1'));
761         $this->assertFalse($cache->get('testkey2'));
762     }
764     /**
765      * Tests application cache definition invalidation
766      */
767     public function test_application_definition_invalidation() {
768         $instance = cache_config_phpunittest::instance();
769         $instance->phpunit_add_definition('phpunit/definitioninvalidation', array(
770             'mode' => cache_store::MODE_APPLICATION,
771             'component' => 'phpunit',
772             'area' => 'definitioninvalidation'
773         ));
774         $cache = cache::make('phpunit', 'definitioninvalidation');
775         $this->assertTrue($cache->set('testkey1', 'test data 1'));
776         $this->assertEquals('test data 1', $cache->get('testkey1'));
777         $this->assertTrue($cache->set('testkey2', 'test data 2'));
778         $this->assertEquals('test data 2', $cache->get('testkey2'));
780         cache_helper::invalidate_by_definition('phpunit', 'definitioninvalidation', array(), 'testkey1');
782         $this->assertFalse($cache->get('testkey1'));
783         $this->assertEquals('test data 2', $cache->get('testkey2'));
785         $this->assertTrue($cache->set('testkey1', 'test data 1'));
787         cache_helper::invalidate_by_definition('phpunit', 'definitioninvalidation', array(), array('testkey1'));
789         $this->assertFalse($cache->get('testkey1'));
790         $this->assertEquals('test data 2', $cache->get('testkey2'));
792         $this->assertTrue($cache->set('testkey1', 'test data 1'));
794         cache_helper::invalidate_by_definition('phpunit', 'definitioninvalidation', array(), array('testkey1', 'testkey2'));
796         $this->assertFalse($cache->get('testkey1'));
797         $this->assertFalse($cache->get('testkey2'));
798     }
800     /**
801      * Tests session cache definition invalidation
802      */
803     public function test_session_definition_invalidation() {
804         $instance = cache_config_phpunittest::instance();
805         $instance->phpunit_add_definition('phpunit/test_session_definition_invalidation', array(
806             'mode' => cache_store::MODE_SESSION,
807             'component' => 'phpunit',
808             'area' => 'test_session_definition_invalidation'
809         ));
810         $cache = cache::make('phpunit', 'test_session_definition_invalidation');
811         $this->assertInstanceOf('cache_session', $cache);
812         $this->assertTrue($cache->set('testkey1', 'test data 1'));
813         $this->assertEquals('test data 1', $cache->get('testkey1'));
814         $this->assertTrue($cache->set('testkey2', 'test data 2'));
815         $this->assertEquals('test data 2', $cache->get('testkey2'));
817         cache_helper::invalidate_by_definition('phpunit', 'test_session_definition_invalidation', array(), 'testkey1');
819         $this->assertFalse($cache->get('testkey1'));
820         $this->assertEquals('test data 2', $cache->get('testkey2'));
822         $this->assertTrue($cache->set('testkey1', 'test data 1'));
824         cache_helper::invalidate_by_definition('phpunit', 'test_session_definition_invalidation', array(),
825                 array('testkey1'));
827         $this->assertFalse($cache->get('testkey1'));
828         $this->assertEquals('test data 2', $cache->get('testkey2'));
830         $this->assertTrue($cache->set('testkey1', 'test data 1'));
832         cache_helper::invalidate_by_definition('phpunit', 'test_session_definition_invalidation', array(),
833                 array('testkey1', 'testkey2'));
835         $this->assertFalse($cache->get('testkey1'));
836         $this->assertFalse($cache->get('testkey2'));
837     }
839     /**
840      * Tests application cache event invalidation over a distributed setup.
841      */
842     public function test_distributed_application_event_invalidation() {
843         global $CFG;
844         // This is going to be an intense wee test.
845         // We need to add data the to cache, invalidate it by event, manually force it back without MUC knowing to simulate a
846         // disconnected/distributed setup (think load balanced server using local cache), instantiate the cache again and finally
847         // check that it is not picked up.
848         $instance = cache_config_phpunittest::instance();
849         $instance->phpunit_add_definition('phpunit/eventinvalidationtest', array(
850             'mode' => cache_store::MODE_APPLICATION,
851             'component' => 'phpunit',
852             'area' => 'eventinvalidationtest',
853             'simplekeys' => true,
854             'simpledata' => true,
855             'invalidationevents' => array(
856                 'crazyevent'
857             )
858         ));
859         $cache = cache::make('phpunit', 'eventinvalidationtest');
860         $this->assertTrue($cache->set('testkey1', 'test data 1'));
861         $this->assertEquals('test data 1', $cache->get('testkey1'));
863         cache_helper::invalidate_by_event('crazyevent', array('testkey1'));
865         $this->assertFalse($cache->get('testkey1'));
867         // OK data added, data invalidated, and invalidation time has been set.
868         // Now we need to manually add back the data and adjust the invalidation time.
869         $hash = md5(cache_store::MODE_APPLICATION.'/phpunit/eventinvalidationtest/'.$CFG->wwwroot.'phpunit');
870         $timefile = $CFG->dataroot."/cache/cachestore_file/default_application/phpunit_eventinvalidationtest/las-cache/lastinvalidation-$hash.cache";
871         // Make sure the file is correct.
872         $this->assertTrue(file_exists($timefile));
873         $timecont = serialize(cache::now() - 60); // Back 60sec in the past to force it to re-invalidate.
874         make_writable_directory(dirname($timefile));
875         file_put_contents($timefile, $timecont);
876         $this->assertTrue(file_exists($timefile));
878         $datafile = $CFG->dataroot."/cache/cachestore_file/default_application/phpunit_eventinvalidationtest/tes-cache/testkey1-$hash.cache";
879         $datacont = serialize("test data 1");
880         make_writable_directory(dirname($datafile));
881         file_put_contents($datafile, $datacont);
882         $this->assertTrue(file_exists($datafile));
884         // Test 1: Rebuild without the event and test its there.
885         cache_factory::reset();
886         $instance = cache_config_phpunittest::instance();
887         $instance->phpunit_add_definition('phpunit/eventinvalidationtest', array(
888             'mode' => cache_store::MODE_APPLICATION,
889             'component' => 'phpunit',
890             'area' => 'eventinvalidationtest',
891             'simplekeys' => true,
892             'simpledata' => true,
893         ));
894         $cache = cache::make('phpunit', 'eventinvalidationtest');
895         $this->assertEquals('test data 1', $cache->get('testkey1'));
897         // Test 2: Rebuild and test the invalidation of the event via the invalidation cache.
898         cache_factory::reset();
899         $instance = cache_config_phpunittest::instance();
900         $instance->phpunit_add_definition('phpunit/eventinvalidationtest', array(
901             'mode' => cache_store::MODE_APPLICATION,
902             'component' => 'phpunit',
903             'area' => 'eventinvalidationtest',
904             'simplekeys' => true,
905             'simpledata' => true,
906             'invalidationevents' => array(
907                 'crazyevent'
908             )
909         ));
910         $cache = cache::make('phpunit', 'eventinvalidationtest');
911         $this->assertFalse($cache->get('testkey1'));
912     }
914     /**
915      * Tests application cache event purge
916      */
917     public function test_application_event_purge() {
918         $instance = cache_config_phpunittest::instance();
919         $instance->phpunit_add_definition('phpunit/eventpurgetest', array(
920             'mode' => cache_store::MODE_APPLICATION,
921             'component' => 'phpunit',
922             'area' => 'eventpurgetest',
923             'invalidationevents' => array(
924                 'crazyevent'
925             )
926         ));
927         $instance->phpunit_add_definition('phpunit/eventpurgetestpersistent', array(
928             'mode' => cache_store::MODE_APPLICATION,
929             'component' => 'phpunit',
930             'area' => 'eventpurgetestpersistent',
931             'persistent' => true,
932             'invalidationevents' => array(
933                 'crazyevent'
934             )
935         ));
936         $cache = cache::make('phpunit', 'eventpurgetest');
938         $this->assertTrue($cache->set('testkey1', 'test data 1'));
939         $this->assertEquals('test data 1', $cache->get('testkey1'));
940         $this->assertTrue($cache->set('testkey2', 'test data 2'));
941         $this->assertEquals('test data 2', $cache->get('testkey2'));
943         // Purge the event.
944         cache_helper::purge_by_event('crazyevent');
946         // Check things have been removed.
947         $this->assertFalse($cache->get('testkey1'));
948         $this->assertFalse($cache->get('testkey2'));
950         // Now test the persistent cache.
951         $cache = cache::make('phpunit', 'eventpurgetestpersistent');
952         $this->assertTrue($cache->set('testkey1', 'test data 1'));
953         $this->assertEquals('test data 1', $cache->get('testkey1'));
954         $this->assertTrue($cache->set('testkey2', 'test data 2'));
955         $this->assertEquals('test data 2', $cache->get('testkey2'));
957         // Purge the event.
958         cache_helper::purge_by_event('crazyevent');
960         // Check things have been removed.
961         $this->assertFalse($cache->get('testkey1'));
962         $this->assertFalse($cache->get('testkey2'));
963     }
965     /**
966      * Tests session cache event purge
967      */
968     public function test_session_event_purge() {
969         $instance = cache_config_phpunittest::instance();
970         $instance->phpunit_add_definition('phpunit/eventpurgetest', array(
971             'mode' => cache_store::MODE_SESSION,
972             'component' => 'phpunit',
973             'area' => 'eventpurgetest',
974             'invalidationevents' => array(
975                 'crazyevent'
976             )
977         ));
978         $instance->phpunit_add_definition('phpunit/eventpurgetestpersistent', array(
979             'mode' => cache_store::MODE_SESSION,
980             'component' => 'phpunit',
981             'area' => 'eventpurgetestpersistent',
982             'persistent' => true,
983             'invalidationevents' => array(
984                 'crazyevent'
985             )
986         ));
987         $cache = cache::make('phpunit', 'eventpurgetest');
989         $this->assertTrue($cache->set('testkey1', 'test data 1'));
990         $this->assertEquals('test data 1', $cache->get('testkey1'));
991         $this->assertTrue($cache->set('testkey2', 'test data 2'));
992         $this->assertEquals('test data 2', $cache->get('testkey2'));
994         // Purge the event.
995         cache_helper::purge_by_event('crazyevent');
997         // Check things have been removed.
998         $this->assertFalse($cache->get('testkey1'));
999         $this->assertFalse($cache->get('testkey2'));
1001         // Now test the persistent cache.
1002         $cache = cache::make('phpunit', 'eventpurgetestpersistent');
1003         $this->assertTrue($cache->set('testkey1', 'test data 1'));
1004         $this->assertEquals('test data 1', $cache->get('testkey1'));
1005         $this->assertTrue($cache->set('testkey2', 'test data 2'));
1006         $this->assertEquals('test data 2', $cache->get('testkey2'));
1008         // Purge the event.
1009         cache_helper::purge_by_event('crazyevent');
1011         // Check things have been removed.
1012         $this->assertFalse($cache->get('testkey1'));
1013         $this->assertFalse($cache->get('testkey2'));
1014     }
1016     /**
1017      * Tests application cache definition purge
1018      */
1019     public function test_application_definition_purge() {
1020         $instance = cache_config_phpunittest::instance();
1021         $instance->phpunit_add_definition('phpunit/definitionpurgetest', array(
1022             'mode' => cache_store::MODE_APPLICATION,
1023             'component' => 'phpunit',
1024             'area' => 'definitionpurgetest',
1025             'invalidationevents' => array(
1026                 'crazyevent'
1027             )
1028         ));
1029         $cache = cache::make('phpunit', 'definitionpurgetest');
1031         $this->assertTrue($cache->set('testkey1', 'test data 1'));
1032         $this->assertEquals('test data 1', $cache->get('testkey1'));
1033         $this->assertTrue($cache->set('testkey2', 'test data 2'));
1034         $this->assertEquals('test data 2', $cache->get('testkey2'));
1036         // Purge the event.
1037         cache_helper::purge_by_definition('phpunit', 'definitionpurgetest');
1039         // Check things have been removed.
1040         $this->assertFalse($cache->get('testkey1'));
1041         $this->assertFalse($cache->get('testkey2'));
1042     }
1044     /**
1045      * Test the use of an alt path.
1046      * If we can generate a config instance we are done :)
1047      */
1048     public function test_alt_cache_path() {
1049         global $CFG;
1050         $this->resetAfterTest();
1051         $CFG->altcacheconfigpath = $CFG->dataroot.'/cache/altcacheconfigpath';
1052         $instance = cache_config_phpunittest::instance();
1053         $this->assertInstanceOf('cache_config', $instance);
1054     }
1056     /**
1057      * Test disabling the cache stores.
1058      */
1059     public function test_disable_stores() {
1060         $instance = cache_config_phpunittest::instance();
1061         $instance->phpunit_add_definition('phpunit/disabletest', array(
1062             'mode' => cache_store::MODE_APPLICATION,
1063             'component' => 'phpunit',
1064             'area' => 'disabletest'
1065         ));
1066         $cache = cache::make('phpunit', 'disabletest');
1067         $this->assertInstanceOf('cache_phpunit_application', $cache);
1068         $this->assertEquals('cachestore_file', $cache->phpunit_get_store_class());
1070         $this->assertFalse($cache->get('test'));
1071         $this->assertTrue($cache->set('test', 'test'));
1072         $this->assertEquals('test', $cache->get('test'));
1074         cache_factory::disable_stores();
1076         $cache = cache::make('phpunit', 'disabletest');
1077         $this->assertInstanceOf('cache_phpunit_application', $cache);
1078         $this->assertEquals('cachestore_dummy', $cache->phpunit_get_store_class());
1080         $this->assertFalse($cache->get('test'));
1081         $this->assertTrue($cache->set('test', 'test'));
1082         $this->assertEquals('test', $cache->get('test'));
1083     }
1085     /**
1086      * Test disabling the cache.
1087      */
1088     public function test_disable() {
1089         global $CFG;
1091         $configfile = $CFG->dataroot.'/muc/config.php';
1093         // That's right, we're deleting the config file.
1094         $this->assertTrue(@unlink($configfile));
1096         // Disable the cache
1097         cache_phpunit_factory::phpunit_disable();
1099         // Check we get the expected disabled factory.
1100         $factory = cache_factory::instance();
1101         $this->assertInstanceOf('cache_factory_disabled', $factory);
1103         // Check we get the expected disabled config.
1104         $config = $factory->create_config_instance();
1105         $this->assertInstanceOf('cache_config_disabled', $config);
1107         // Check we get the expected disabled caches.
1108         $cache = cache::make('phpunit', 'disable');
1109         $this->assertInstanceOf('cache_disabled', $cache);
1111         $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'phpunit', 'disable');
1112         $this->assertInstanceOf('cache_disabled', $cache);
1114         $this->assertFalse(file_exists($configfile));
1116         $this->assertFalse($cache->get('test'));
1117         $this->assertFalse($cache->set('test', 'test'));
1118         $this->assertFalse($cache->delete('test'));
1119         $this->assertTrue($cache->purge());
1121         cache_factory::reset();
1123         $factory = cache_factory::instance(true);
1124         $config = $factory->create_config_instance();
1125         $this->assertEquals('cache_config_phpunittest', get_class($config));
1126     }
1128     /**
1129      * Test that multiple application loaders work ok.
1130      */
1131     public function test_multiple_application_loaders() {
1132         $instance = cache_config_phpunittest::instance(true);
1133         $instance->phpunit_add_file_store('phpunittest1');
1134         $instance->phpunit_add_file_store('phpunittest2');
1135         $instance->phpunit_add_definition('phpunit/multi_loader', array(
1136             'mode' => cache_store::MODE_APPLICATION,
1137             'component' => 'phpunit',
1138             'area' => 'multi_loader'
1139         ));
1140         $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'phpunittest1', 3);
1141         $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'phpunittest2', 2);
1143         $cache = cache::make('phpunit', 'multi_loader');
1144         $this->assertInstanceOf('cache_application', $cache);
1145         $this->assertFalse($cache->get('test'));
1146         $this->assertTrue($cache->set('test', 'test'));
1147         $this->assertEquals('test', $cache->get('test'));
1148         $this->assertTrue($cache->delete('test'));
1149         $this->assertFalse($cache->get('test'));
1150         $this->assertTrue($cache->set('test', 'test'));
1151         $this->assertTrue($cache->purge());
1152         $this->assertFalse($cache->get('test'));
1154         // Test the many commands.
1155         $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C')));
1156         $result = $cache->get_many(array('a', 'b', 'c'));
1157         $this->assertInternalType('array', $result);
1158         $this->assertCount(3, $result);
1159         $this->assertArrayHasKey('a', $result);
1160         $this->assertArrayHasKey('b', $result);
1161         $this->assertArrayHasKey('c', $result);
1162         $this->assertEquals('A', $result['a']);
1163         $this->assertEquals('B', $result['b']);
1164         $this->assertEquals('C', $result['c']);
1165         $this->assertEquals($result, $cache->get_many(array('a', 'b', 'c')));
1166         $this->assertEquals(2, $cache->delete_many(array('a', 'c')));
1167         $result = $cache->get_many(array('a', 'b', 'c'));
1168         $this->assertInternalType('array', $result);
1169         $this->assertCount(3, $result);
1170         $this->assertArrayHasKey('a', $result);
1171         $this->assertArrayHasKey('b', $result);
1172         $this->assertArrayHasKey('c', $result);
1173         $this->assertFalse($result['a']);
1174         $this->assertEquals('B', $result['b']);
1175         $this->assertFalse($result['c']);
1177         // Test non-recursive deletes.
1178         $this->assertTrue($cache->set('test', 'test'));
1179         $this->assertSame('test', $cache->get('test'));
1180         $this->assertTrue($cache->delete('test', false));
1181         // We should still have it on a deeper loader.
1182         $this->assertSame('test', $cache->get('test'));
1183         // Test non-recusive with many functions.
1184         $this->assertSame(3, $cache->set_many(array(
1185             'one' => 'one',
1186             'two' => 'two',
1187             'three' => 'three'
1188         )));
1189         $this->assertSame('one', $cache->get('one'));
1190         $this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three')));
1191         $this->assertSame(3, $cache->delete_many(array('one', 'two', 'three'), false));
1192         $this->assertSame('one', $cache->get('one'));
1193         $this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three')));
1194     }
1196     /**
1197      * Test that multiple application loaders work ok.
1198      */
1199     public function test_multiple_session_loaders() {
1200         /* @var cache_config_phpunittest $instance */
1201         $instance = cache_config_phpunittest::instance(true);
1202         $instance->phpunit_add_session_store('phpunittest1');
1203         $instance->phpunit_add_session_store('phpunittest2');
1204         $instance->phpunit_add_definition('phpunit/multi_loader', array(
1205             'mode' => cache_store::MODE_SESSION,
1206             'component' => 'phpunit',
1207             'area' => 'multi_loader'
1208         ));
1209         $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'phpunittest1', 3);
1210         $instance->phpunit_add_definition_mapping('phpunit/multi_loader', 'phpunittest2', 2);
1212         $cache = cache::make('phpunit', 'multi_loader');
1213         $this->assertInstanceOf('cache_session', $cache);
1214         $this->assertFalse($cache->get('test'));
1215         $this->assertTrue($cache->set('test', 'test'));
1216         $this->assertEquals('test', $cache->get('test'));
1217         $this->assertTrue($cache->delete('test'));
1218         $this->assertFalse($cache->get('test'));
1219         $this->assertTrue($cache->set('test', 'test'));
1220         $this->assertTrue($cache->purge());
1221         $this->assertFalse($cache->get('test'));
1223         // Test the many commands.
1224         $this->assertEquals(3, $cache->set_many(array('a' => 'A', 'b' => 'B', 'c' => 'C')));
1225         $result = $cache->get_many(array('a', 'b', 'c'));
1226         $this->assertInternalType('array', $result);
1227         $this->assertCount(3, $result);
1228         $this->assertArrayHasKey('a', $result);
1229         $this->assertArrayHasKey('b', $result);
1230         $this->assertArrayHasKey('c', $result);
1231         $this->assertEquals('A', $result['a']);
1232         $this->assertEquals('B', $result['b']);
1233         $this->assertEquals('C', $result['c']);
1234         $this->assertEquals($result, $cache->get_many(array('a', 'b', 'c')));
1235         $this->assertEquals(2, $cache->delete_many(array('a', 'c')));
1236         $result = $cache->get_many(array('a', 'b', 'c'));
1237         $this->assertInternalType('array', $result);
1238         $this->assertCount(3, $result);
1239         $this->assertArrayHasKey('a', $result);
1240         $this->assertArrayHasKey('b', $result);
1241         $this->assertArrayHasKey('c', $result);
1242         $this->assertFalse($result['a']);
1243         $this->assertEquals('B', $result['b']);
1244         $this->assertFalse($result['c']);
1246         // Test non-recursive deletes.
1247         $this->assertTrue($cache->set('test', 'test'));
1248         $this->assertSame('test', $cache->get('test'));
1249         $this->assertTrue($cache->delete('test', false));
1250         // We should still have it on a deeper loader.
1251         $this->assertSame('test', $cache->get('test'));
1252         // Test non-recusive with many functions.
1253         $this->assertSame(3, $cache->set_many(array(
1254             'one' => 'one',
1255             'two' => 'two',
1256             'three' => 'three'
1257         )));
1258         $this->assertSame('one', $cache->get('one'));
1259         $this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three')));
1260         $this->assertSame(3, $cache->delete_many(array('one', 'two', 'three'), false));
1261         $this->assertSame('one', $cache->get('one'));
1262         $this->assertSame(array('two' => 'two', 'three' => 'three'), $cache->get_many(array('two', 'three')));
1263     }
1265     /**
1266      * Test switching users with session caches.
1267      */
1268     public function test_session_cache_switch_user() {
1269         $this->resetAfterTest(true);
1270         $cache = cache::make_from_params(cache_store::MODE_SESSION, 'phpunit', 'sessioncache');
1271         $user1 = $this->getDataGenerator()->create_user();
1272         $user2 = $this->getDataGenerator()->create_user();
1274         // Log in as the first user.
1275         $this->setUser($user1);
1276         $sesskey1 = sesskey();
1278         // Set a basic value in the cache.
1279         $cache->set('var', 1);
1280         $this->assertTrue($cache->has('var'));
1281         $this->assertEquals(1, $cache->get('var'));
1283         // Change to the second user.
1284         $this->setUser($user2);
1285         $sesskey2 = sesskey();
1287         // Make sure the cache doesn't give us the data for the last user.
1288         $this->assertNotEquals($sesskey1, $sesskey2);
1289         $this->assertFalse($cache->has('var'));
1290         $this->assertEquals(false, $cache->get('var'));
1291     }
1293     /**
1294      * Test switching users with session caches.
1295      */
1296     public function test_session_cache_switch_user_application_mapping() {
1297         $this->resetAfterTest(true);
1298         $instance = cache_config_phpunittest::instance(true);
1299         $instance->phpunit_add_file_store('testfilestore');
1300         $instance->phpunit_add_definition('phpunit/testappsession', array(
1301             'mode' => cache_store::MODE_SESSION,
1302             'component' => 'phpunit',
1303             'area' => 'testappsession'
1304         ));
1305         $instance->phpunit_add_definition_mapping('phpunit/testappsession', 'testfilestore', 3);
1306         $cache = cache::make('phpunit', 'testappsession');
1307         $user1 = $this->getDataGenerator()->create_user();
1308         $user2 = $this->getDataGenerator()->create_user();
1310         // Log in as the first user.
1311         $this->setUser($user1);
1312         $sesskey1 = sesskey();
1314         // Set a basic value in the cache.
1315         $cache->set('var', 1);
1316         $this->assertTrue($cache->has('var'));
1317         $this->assertEquals(1, $cache->get('var'));
1319         // Change to the second user.
1320         $this->setUser($user2);
1321         $sesskey2 = sesskey();
1323         // Make sure the cache doesn't give us the data for the last user.
1324         $this->assertNotEquals($sesskey1, $sesskey2);
1325         $this->assertFalse($cache->has('var'));
1326         $this->assertEquals(false, $cache->get('var'));
1327     }
1329     /**
1330      * Test two session caches being used at once to confirm collisions don't occur.
1331      */
1332     public function test_dual_session_caches() {
1333         $instance = cache_config_phpunittest::instance(true);
1334         $instance->phpunit_add_definition('phpunit/testsess1', array(
1335             'mode' => cache_store::MODE_SESSION,
1336             'component' => 'phpunit',
1337             'area' => 'testsess1'
1338         ));
1339         $instance->phpunit_add_definition('phpunit/testsess2', array(
1340             'mode' => cache_store::MODE_SESSION,
1341             'component' => 'phpunit',
1342             'area' => 'testsess2'
1343         ));
1344         $cache1 = cache::make('phpunit', 'testsess1');
1345         $cache2 = cache::make('phpunit', 'testsess2');
1347         $this->assertFalse($cache1->has('test'));
1348         $this->assertFalse($cache2->has('test'));
1350         $this->assertTrue($cache1->set('test', '1'));
1352         $this->assertTrue($cache1->has('test'));
1353         $this->assertFalse($cache2->has('test'));
1355         $this->assertTrue($cache2->set('test', '2'));
1357         $this->assertEquals(1, $cache1->get('test'));
1358         $this->assertEquals(2, $cache2->get('test'));
1360         $this->assertTrue($cache1->delete('test'));
1361     }
1363     /**
1364      * Test multiple session caches when switching user.
1365      */
1366     public function test_session_cache_switch_user_multiple() {
1367         $this->resetAfterTest(true);
1368         $cache1 = cache::make_from_params(cache_store::MODE_SESSION, 'phpunit', 'sessioncache1');
1369         $cache2 = cache::make_from_params(cache_store::MODE_SESSION, 'phpunit', 'sessioncache2');
1370         $user1 = $this->getDataGenerator()->create_user();
1371         $user2 = $this->getDataGenerator()->create_user();
1373         // Log in as the first user.
1374         $this->setUser($user1);
1375         $sesskey1 = sesskey();
1377         // Set a basic value in the caches.
1378         $cache1->set('var', 1);
1379         $cache2->set('var', 2);
1380         $this->assertEquals(1, $cache1->get('var'));
1381         $this->assertEquals(2, $cache2->get('var'));
1383         // Change to the second user.
1384         $this->setUser($user2);
1385         $sesskey2 = sesskey();
1387         // Make sure the cache doesn't give us the data for the last user.
1388         // Also make sure that switching the user has lead to both caches being purged.
1389         $this->assertNotEquals($sesskey1, $sesskey2);
1390         $this->assertEquals(false, $cache1->get('var'));
1391         $this->assertEquals(false, $cache2->get('var'));
1392     }
1394     /**
1395      * Test application locking.
1396      */
1397     public function test_application_locking() {
1398         $instance = cache_config_phpunittest::instance(true);
1399         $instance->phpunit_add_definition('phpunit/test_application_locking', array(
1400             'mode' => cache_store::MODE_APPLICATION,
1401             'component' => 'phpunit',
1402             'area' => 'test_application_locking',
1403             'persistent' => true,
1404             'persistentmaxsize' => 1,
1405             'requirelockingread' => true,
1406             'requirelockingwrite' => true
1407         ));
1408         $cache = cache::make('phpunit', 'test_application_locking');
1409         $this->assertInstanceOf('cache_application', $cache);
1411         $this->assertTrue($cache->set('a', 'A'));
1412         $this->assertTrue($cache->set('b', 'B'));
1413         $this->assertTrue($cache->set('c', 'C'));
1414         $this->assertEquals('A', $cache->get('a'));
1415         $this->assertEquals(array('b' => 'B', 'c' => 'C'), $cache->get_many(array('b', 'c')));
1416         $this->assertTrue($cache->delete('a'));
1417         $this->assertFalse($cache->has('a'));
1418     }
1420     /**
1421      * Test the static cache_helper method purge_stores_used_by_definition.
1422      */
1423     public function test_purge_stores_used_by_definition() {
1424         $instance = cache_config_phpunittest::instance(true);
1425         $instance->phpunit_add_definition('phpunit/test_purge_stores_used_by_definition', array(
1426             'mode' => cache_store::MODE_APPLICATION,
1427             'component' => 'phpunit',
1428             'area' => 'test_purge_stores_used_by_definition'
1429         ));
1430         $cache = cache::make('phpunit', 'test_purge_stores_used_by_definition');
1431         $this->assertInstanceOf('cache_application', $cache);
1432         $this->assertTrue($cache->set('test', 'test'));
1433         unset($cache);
1435         cache_helper::purge_stores_used_by_definition('phpunit', 'test_purge_stores_used_by_definition');
1437         $cache = cache::make('phpunit', 'test_purge_stores_used_by_definition');
1438         $this->assertInstanceOf('cache_application', $cache);
1439         $this->assertFalse($cache->get('test'));
1440     }
1442     /**
1443      * Test purge routines.
1444      */
1445     public function test_purge_routines() {
1446         $instance = cache_config_phpunittest::instance(true);
1447         $instance->phpunit_add_definition('phpunit/purge1', array(
1448             'mode' => cache_store::MODE_APPLICATION,
1449             'component' => 'phpunit',
1450             'area' => 'purge1'
1451         ));
1452         $instance->phpunit_add_definition('phpunit/purge2', array(
1453             'mode' => cache_store::MODE_APPLICATION,
1454             'component' => 'phpunit',
1455             'area' => 'purge2',
1456             'requireidentifiers' => array(
1457                 'id'
1458             )
1459         ));
1461         $factory = cache_factory::instance();
1462         $definition = $factory->create_definition('phpunit', 'purge1');
1463         $this->assertFalse($definition->has_required_identifiers());
1464         $cache = $factory->create_cache($definition);
1465         $this->assertInstanceOf('cache_application', $cache);
1466         $this->assertTrue($cache->set('test', 'test'));
1467         $this->assertTrue($cache->has('test'));
1468         cache_helper::purge_by_definition('phpunit', 'purge1');
1469         $this->assertFalse($cache->has('test'));
1471         $factory = cache_factory::instance();
1472         $definition = $factory->create_definition('phpunit', 'purge2');
1473         $this->assertTrue($definition->has_required_identifiers());
1474         $cache = $factory->create_cache($definition);
1475         $this->assertInstanceOf('cache_application', $cache);
1476         $this->assertTrue($cache->set('test', 'test'));
1477         $this->assertTrue($cache->has('test'));
1478         cache_helper::purge_stores_used_by_definition('phpunit', 'purge2');
1479         $this->assertFalse($cache->has('test'));
1481         try {
1482             cache_helper::purge_by_definition('phpunit', 'purge2');
1483             $this->fail('Should not be able to purge a definition required identifiers without providing them.');
1484         } catch (coding_exception $ex) {
1485             $this->assertContains('Identifier required for cache has not been provided', $ex->getMessage());
1486         }
1487     }
1489     /**
1490      * Test that the default stores all support searching.
1491      */
1492     public function test_defaults_support_searching() {
1493         $instance = cache_config_phpunittest::instance(true);
1494         $instance->phpunit_add_definition('phpunit/search1', array(
1495             'mode' => cache_store::MODE_APPLICATION,
1496             'component' => 'phpunit',
1497             'area' => 'search1',
1498             'requiresearchable' => true
1499         ));
1500         $instance->phpunit_add_definition('phpunit/search2', array(
1501             'mode' => cache_store::MODE_SESSION,
1502             'component' => 'phpunit',
1503             'area' => 'search2',
1504             'requiresearchable' => true
1505         ));
1506         $instance->phpunit_add_definition('phpunit/search3', array(
1507             'mode' => cache_store::MODE_REQUEST,
1508             'component' => 'phpunit',
1509             'area' => 'search3',
1510             'requiresearchable' => true
1511         ));
1512         $factory = cache_factory::instance();
1514         // Test application cache is searchable.
1515         $definition = $factory->create_definition('phpunit', 'search1');
1516         $this->assertInstanceOf('cache_definition', $definition);
1517         $this->assertEquals(cache_store::IS_SEARCHABLE, $definition->get_requirements_bin() & cache_store::IS_SEARCHABLE);
1518         $cache = $factory->create_cache($definition);
1519         $this->assertInstanceOf('cache_application', $cache);
1520         $this->assertArrayHasKey('cache_is_searchable', $cache->phpunit_get_store_implements());
1522         // Test session cache is searchable.
1523         $definition = $factory->create_definition('phpunit', 'search2');
1524         $this->assertInstanceOf('cache_definition', $definition);
1525         $this->assertEquals(cache_store::IS_SEARCHABLE, $definition->get_requirements_bin() & cache_store::IS_SEARCHABLE);
1526         $cache = $factory->create_cache($definition);
1527         $this->assertInstanceOf('cache_session', $cache);
1528         $this->assertArrayHasKey('cache_is_searchable', $cache->phpunit_get_store_implements());
1530         // Test request cache is searchable.
1531         $definition = $factory->create_definition('phpunit', 'search3');
1532         $this->assertInstanceOf('cache_definition', $definition);
1533         $this->assertEquals(cache_store::IS_SEARCHABLE, $definition->get_requirements_bin() & cache_store::IS_SEARCHABLE);
1534         $cache = $factory->create_cache($definition);
1535         $this->assertInstanceOf('cache_request', $cache);
1536         $this->assertArrayHasKey('cache_is_searchable', $cache->phpunit_get_store_implements());
1537     }