21e63fc156605ca25b493323034f868eed984e22
[Packages/TYPO3.CMS.git] / tests / t3lib / cache / backend / t3lib_cache_backend_dbbackendtestcase.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2009 Ingo Renner <ingo@typo3.org>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 *
17 * This script is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * This copyright notice MUST APPEAR in all copies of the script!
23 ***************************************************************/
24
25
26 // TODO implement autoloading so that we only require stuff we really need
27 require_once(PATH_t3lib . 'class.t3lib_cache.php');
28
29 require_once(PATH_t3lib . 'cache/backend/interfaces/interface.t3lib_cache_backend_backend.php');
30 require_once(PATH_t3lib . 'cache/frontend/interfaces/interface.t3lib_cache_frontend_frontend.php');
31
32 require_once(PATH_t3lib . 'cache/backend/class.t3lib_cache_backend_abstractbackend.php');
33 require_once(PATH_t3lib . 'cache/frontend/class.t3lib_cache_frontend_abstractfrontend.php');
34 require_once(PATH_t3lib . 'cache/class.t3lib_cache_exception.php');
35 require_once(PATH_t3lib . 'cache/class.t3lib_cache_factory.php');
36 require_once(PATH_t3lib . 'cache/class.t3lib_cache_manager.php');
37 require_once(PATH_t3lib . 'cache/frontend/class.t3lib_cache_frontend_variablefrontend.php');
38
39 require_once(PATH_t3lib . 'cache/exception/class.t3lib_cache_exception_classalreadyloaded.php');
40 require_once(PATH_t3lib . 'cache/exception/class.t3lib_cache_exception_duplicateidentifier.php');
41 require_once(PATH_t3lib . 'cache/exception/class.t3lib_cache_exception_invalidbackend.php');
42 require_once(PATH_t3lib . 'cache/exception/class.t3lib_cache_exception_invalidcache.php');
43 require_once(PATH_t3lib . 'cache/exception/class.t3lib_cache_exception_invaliddata.php');
44 require_once(PATH_t3lib . 'cache/exception/class.t3lib_cache_exception_nosuchcache.php');
45
46 require_once(PATH_t3lib . 'cache/backend/class.t3lib_cache_backend_dbbackend.php');
47
48 /**
49 * Testcase for the DB cache backend
50 *
51 * @author Ingo Renner <ingo@typo3.org>
52 * @package TYPO3
53 * @subpackage tests
54 * @version $Id$
55 */
56 class t3lib_cache_backend_DbBackendTestCase extends tx_phpunit_testcase {
57
58 /**
59 * If set, the tearDown() method will clean up the cache table used by this unit test.
60 *
61 * @var t3lib_cache_backend_DbBackend
62 */
63 protected $backend;
64
65 protected $testingCacheTable;
66
67 /**
68 * Sets up this testcase
69 *
70 * @return void
71 * @author Ingo Renner <ingo@typo3.org>
72 */
73 public function setUp() {
74 $this->testingCacheTable = 'test_cache_dbbackend';
75
76 $GLOBALS['TYPO3_DB']->sql_query('CREATE TABLE ' . $this->testingCacheTable . ' (
77 id int(11) unsigned NOT NULL auto_increment,
78 identifier varchar(250) DEFAULT \'\' NOT NULL,
79 crdate int(11) unsigned DEFAULT \'0\' NOT NULL,
80 content mediumtext,
81 tags mediumtext,
82 lifetime int(11) unsigned DEFAULT \'0\' NOT NULL,
83 PRIMARY KEY (id),
84 KEY cache_id (identifier)
85 ) ENGINE=InnoDB;
86 ');
87
88 $this->backend = t3lib_div::makeInstance(
89 't3lib_cache_backend_DbBackend',
90 array('cacheTable' => $this->testingCacheTable)
91 );
92 }
93
94 /**
95 * @test
96 * @expectedException t3lib_cache_Exception
97 * @author Ingo Renner <ingo@typo3.org>
98 */
99 # deactivated as the according check in the DB backend causes trouble during TYPO3's initialization
100 # public function setCacheTableThrowsExceptionOnNonExistentTable() {
101 # $this->backend->setCacheTable('test_cache_non_existent_table');
102 # }
103
104 /**
105 * @test
106 * @author Ingo Renner <ingo@typo3.org>
107 */
108 public function getCacheTableReturnsThePreviouslySetTable() {
109 $this->backend->setCacheTable($this->testingCacheTable);
110 $this->assertEquals($this->testingCacheTable, $this->backend->getCacheTable(), 'getCacheTable() did not return the expected value.');
111 }
112
113 /**
114 * @test
115 * @expectedException t3lib_cache_exception_InvalidData
116 * @author Ingo Renner <ingo@typo3.org>
117 */
118 public function setThrowsExceptionIfDataIsNotAString() {
119 $cache = $this->getMock('t3lib_cache_frontend_AbstractFrontend',
120 array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove'),
121 array(),
122 '',
123 FALSE
124 );
125
126 $data = array('Some data');
127 $entryIdentifier = 'BackendDbTest';
128
129 $this->backend->setCache($cache);
130
131 $this->backend->set($entryIdentifier, $data);
132 }
133
134 /**
135 * @test
136 * @author Ingo Renner <ingo@typo3.org>
137 */
138 public function setReallySavesToTheSpecifiedTable() {
139 $cache = $this->getMock('t3lib_cache_frontend_AbstractFrontend',
140 array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove'),
141 array(),
142 '',
143 FALSE
144 );
145
146 $data = 'some data' . microtime();
147 $entryIdentifier = 'BackendDbTest';
148
149 $this->backend->setCache($cache);
150 $this->backend->set($entryIdentifier, $data);
151
152 $entriesFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
153 '*',
154 $this->testingCacheTable,
155 'identifier = \'' . $entryIdentifier . '\''
156 );
157
158 $this->assertEquals(
159 $data,
160 $entriesFound[0]['content'],
161 'The original and the retrieved data don\'t match.'
162 );
163 }
164
165 /**
166 * @test
167 * @author Ingo Renner <ingo@typo3.org>
168 */
169 public function setRemovesAnAlreadyExistingCacheEntryForTheSameIdentifier() {
170 $cache = $this->getMock('t3lib_cache_frontend_AbstractFrontend',
171 array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove'),
172 array(),
173 '',
174 FALSE
175 );
176
177 $data1 = 'some data' . microtime();
178 $data2 = 'some data' . microtime();
179 $entryIdentifier = 'BackendDbRemoveBeforeSetTest';
180
181 $this->backend->setCache($cache);
182 $this->backend->set($entryIdentifier, $data1, array(), 500);
183 // setting a second entry with the same identifier, but different
184 // data, this should _replace_ the existing one we set before
185 $this->backend->set($entryIdentifier, $data2, array(), 200);
186
187 $entriesFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
188 '*',
189 $this->testingCacheTable,
190 'identifier = \'' . $entryIdentifier . '\''
191 );
192
193 $this->assertEquals(1, count($entriesFound), 'There was not exactly one cache entry.');
194 }
195
196 /**
197 * @test
198 * @author Ingo Renner <ingo@typo3.org>
199 */
200 public function setReallySavesSpecifiedTags() {
201 $cache = $this->getMock('t3lib_cache_frontend_AbstractFrontend',
202 array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove'),
203 array(),
204 '',
205 FALSE
206 );
207
208 $data = 'some data' . microtime();
209 $entryIdentifier = 'BackendDbTest';
210
211 $this->backend->setCache($cache);
212 $this->backend->set($entryIdentifier, $data, array('UnitTestTag%tag1', 'UnitTestTag%tag2'));
213
214 $entriesFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
215 '*',
216 $this->testingCacheTable,
217 'identifier = \'' . $entryIdentifier . '\''
218 );
219
220 $tags = explode(',', $entriesFound[0]['tags']);
221
222 $this->assertTrue(is_array($tags) && count($entriesFound) > 0, 'The tags do not exist.');
223 $this->assertTrue(in_array('UnitTestTag%tag1', $tags), 'Tag UnitTestTag%tag1 does not exist.');
224 $this->assertTrue(in_array('UnitTestTag%tag2', $tags), 'Tag UnitTestTag%tag2 does not exist.');
225 }
226
227 /**
228 * @test
229 * @author Ingo Renner <ingo@typo3.org>
230 */
231 public function getReturnsContentOfTheCorrectCacheEntry() {
232 $cache = $this->getMock('t3lib_cache_frontend_AbstractFrontend',
233 array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove'),
234 array(),
235 '',
236 FALSE
237 );
238
239 $data = 'some data' . microtime();
240 $entryIdentifier = 'BackendDbTest';
241
242 $this->backend->setCache($cache);
243 $this->backend->set($entryIdentifier, $data, array(), 500);
244
245 $data = 'some other data' . microtime();
246 $this->backend->set($entryIdentifier, $data, array(), 100);
247
248 $loadedData = $this->backend->get($entryIdentifier);
249
250 $this->assertEquals($data, $loadedData, 'The original and the retrieved data don\'t match.');
251 }
252
253 /**
254 * @test
255 * @author Ingo Renner <ingo@typo3.org>
256 */
257 public function hasReturnsTheCorrectResult() {
258 $cache = $this->getMock('t3lib_cache_frontend_AbstractFrontend',
259 array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove'),
260 array(),
261 '',
262 FALSE
263 );
264
265 $data = 'some data' . microtime();
266 $entryIdentifier = 'BackendDbTest';
267
268 $this->backend->setCache($cache);
269 $this->backend->set($entryIdentifier, $data);
270
271 $this->assertTrue($this->backend->has($entryIdentifier), 'has() did not return TRUE.');
272 $this->assertFalse($this->backend->has($entryIdentifier . 'Not'), 'has() did not return FALSE.');
273 }
274
275 /**
276 * @test
277 * @author Ingo Renner <ingo@typo3.org>
278 */
279 public function removeReallyRemovesACacheEntry() {
280 $cache = $this->getMock('t3lib_cache_frontend_AbstractFrontend',
281 array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove'),
282 array(),
283 '',
284 FALSE
285 );
286
287 $data = 'some data' . microtime();
288 $entryIdentifier = 'BackendDbRemovalTest';
289
290 $this->backend->setCache($cache);
291 $this->backend->set($entryIdentifier, $data);
292
293 $entriesFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
294 '*',
295 $this->testingCacheTable,
296 'identifier = \'' . $entryIdentifier . '\''
297 );
298
299 $this->assertTrue(is_array($entriesFound) && count($entriesFound) > 0, 'The cache entry does not exist.');
300
301 $this->backend->remove($entryIdentifier);
302
303 $entriesFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
304 '*',
305 $this->testingCacheTable,
306 'identifier = \'' . $entryIdentifier . '\''
307 );
308
309 $this->assertTrue(count($entriesFound) == 0, 'The cache entry still exists.');
310 }
311
312 /**
313 * @test
314 * @author Ingo Renner <ingo@typo3.org>
315 */
316 public function collectGarbageReallyRemovesAnExpiredCacheEntry() {
317 $cache = $this->getMock('t3lib_cache_frontend_AbstractFrontend',
318 array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove'),
319 array(),
320 '',
321 FALSE
322 );
323
324 $data = 'some data' . microtime();
325 $entryIdentifier = 'BackendDbRemovalTest';
326
327 $this->backend->setCache($cache);
328 $this->backend->set($entryIdentifier, $data, array(), 1);
329
330 $entriesFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
331 '*',
332 $this->testingCacheTable,
333 'identifier = \'' . $entryIdentifier . '\''
334 );
335
336 $this->assertTrue(is_array($entriesFound) && count($entriesFound) > 0, 'The cache entry does not exist.');
337
338 sleep(2);
339 $this->backend->collectGarbage();
340
341 $entriesFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
342 '*',
343 $this->testingCacheTable,
344 'identifier = \'' . $entryIdentifier . '\''
345 );
346
347 $this->assertTrue(count($entriesFound) == 0, 'The cache entry still exists.');
348 }
349
350 /**
351 * @test
352 * @author Ingo Renner <ingo@typo3.org>
353 */
354 public function collectGarbageReallyRemovesAllExpiredCacheEntries() {
355 $cache = $this->getMock('t3lib_cache_frontend_AbstractFrontend',
356 array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove'),
357 array(),
358 '',
359 FALSE
360 );
361
362 $data = 'some data' . microtime();
363 $entryIdentifier = 'BackendDbRemovalTest';
364
365 $this->backend->setCache($cache);
366
367 $this->backend->set($entryIdentifier . 'A', $data, array(), 1);
368 $this->backend->set($entryIdentifier . 'B', $data, array(), 1);
369 $this->backend->set($entryIdentifier . 'C', $data, array(), 1);
370
371 $entriesFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
372 '*',
373 $this->testingCacheTable,
374 ''
375 );
376
377 $this->assertTrue(is_array($entriesFound) && count($entriesFound) > 0, 'The cache entries do not exist.');
378
379 sleep(2);
380 $this->backend->collectGarbage();
381
382 $entriesFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
383 '*',
384 $this->testingCacheTable,
385 ''
386 );
387
388 $this->assertTrue(count($entriesFound) == 0, 'The cache entries still exist.');
389 }
390
391 /**
392 * @test
393 * @author Ingo Renner <ingo@typo3.org>
394 */
395 public function findIdentifiersByTagFindsCacheEntriesWithSpecifiedTag() {
396 $cache = $this->getMock('t3lib_cache_frontend_AbstractFrontend',
397 array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove'),
398 array(),
399 '',
400 FALSE
401 );
402
403 $this->backend->setCache($cache);
404
405 $data = 'some data' . microtime();
406 $this->backend->set('BackendDbTest1', $data, array('UnitTestTag%test', 'UnitTestTag%boring'));
407 $this->backend->set('BackendDbTest2', $data, array('UnitTestTag%test', 'UnitTestTag%special'));
408 $this->backend->set('BackendDbTest3', $data, array('UnitTestTag%test'));
409
410 $expectedEntry = 'BackendDbTest2';
411
412 $actualEntries = $this->backend->findIdentifiersByTag('UnitTestTag%special');
413 $this->assertTrue(is_array($actualEntries), 'actualEntries is not an array.');
414
415 $this->assertEquals($expectedEntry, array_pop($actualEntries));
416 }
417
418 /**
419 * @test
420 * @author Ingo Renner <ingo@typo3.org>
421 */
422 public function flushRemovesAllCacheEntries() {
423 $cache = $this->getMock('t3lib_cache_frontend_AbstractFrontend',
424 array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove'),
425 array(),
426 '',
427 FALSE
428 );
429
430 $this->backend->setCache($cache);
431
432 $data = 'some data' . microtime();
433 $this->backend->set('BackendDbTest1', $data, array('UnitTestTag%test'));
434 $this->backend->set('BackendDbTest2', $data, array('UnitTestTag%test', 'UnitTestTag%special'));
435 $this->backend->set('BackendDbTest3', $data, array('UnitTestTag%test'));
436
437 $this->backend->flush();
438
439 $entriesFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
440 '*',
441 $this->testingCacheTable,
442 ''
443 );
444
445 $this->assertTrue(count($entriesFound) == 0, 'Still entries in the cache table');
446 }
447
448 /**
449 * @test
450 * @author Ingo Renner <ingo@typo3.org>
451 */
452 public function flushByTagRemovesCacheEntriesWithSpecifiedTag() {
453 $cache = $this->getMock('t3lib_cache_frontend_AbstractFrontend',
454 array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove'),
455 array(),
456 '',
457 FALSE
458 );
459
460 $this->backend->setCache($cache);
461
462 $data = 'some data' . microtime();
463 $this->backend->set('BackendDbTest1', $data, array('UnitTestTag%test', 'UnitTestTag%boring'));
464 $this->backend->set('BackendDbTest2', $data, array('UnitTestTag%test', 'UnitTestTag%special'));
465 $this->backend->set('BackendDbTest3', $data, array('UnitTestTag%test'));
466
467 $this->backend->flushByTag('UnitTestTag%special');
468
469 $this->assertTrue($this->backend->has('BackendDbTest1'), 'BackendDbTest1 does not exist anymore.');
470 $this->assertFalse($this->backend->has('BackendDbTest2'), 'BackendDbTest2 still exists.');
471 $this->assertTrue($this->backend->has('BackendDbTest3'), 'BackendDbTest3 does not exist anymore.');
472 }
473
474
475 /**
476 * @test
477 * @author Ingo Renner <ingo@typo3.org>
478 */
479 public function hasReturnsTheCorrectResultForEntryWithExceededLifetime() {
480 $cache = $this->getMock('t3lib_cache_frontend_AbstractFrontend',
481 array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove'),
482 array(),
483 '',
484 FALSE
485 );
486
487 $data = 'some data' . microtime();
488 $entryIdentifier = 'BackendDbTest';
489
490 $this->backend->setCache($cache);
491 $this->backend->set($entryIdentifier, $data);
492
493 $expiredEntryIdentifier = 'ExpiredBackendDbTest';
494 $expiredData = 'some old data' . microtime();
495 $this->backend->set($expiredEntryIdentifier, $expiredData, array(), 1);
496
497 sleep(2);
498
499 $this->assertFalse($this->backend->has($expiredEntryIdentifier), 'has() did not return FALSE.');
500 }
501
502 /**
503 * @test
504 * @author Ingo Renner <ingo@typo3.org>
505 */
506 public function getReturnsFalseForEntryWithExceededLifetime() {
507 $cache = $this->getMock('t3lib_cache_frontend_AbstractFrontend',
508 array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove'),
509 array(),
510 '',
511 FALSE
512 );
513
514 $data = 'some data' . microtime();
515 $entryIdentifier = 'BackendDbTest';
516
517 $this->backend->setCache($cache);
518 $this->backend->set($entryIdentifier, $data);
519
520 $expiredEntryIdentifier = 'ExpiredBackendDbTest';
521 $expiredData = 'some old data' . microtime();
522 $this->backend->set($expiredEntryIdentifier, $expiredData, array(), 1);
523
524 sleep(2);
525
526 $this->assertEquals($data, $this->backend->get($entryIdentifier), 'The original and the retrieved data don\'t match.');
527 $this->assertFalse($this->backend->get($expiredEntryIdentifier), 'The expired entry could be loaded.');
528 }
529
530 /**
531 * @test
532 * @author Ingo Renner <ingo@typo3.org>
533 */
534 public function findIdentifiersByTagReturnsEmptyArrayForEntryWithExceededLifetime() {
535 $cache = $this->getMock('t3lib_cache_frontend_AbstractFrontend',
536 array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove'),
537 array(),
538 '',
539 FALSE
540 );
541
542 $this->backend->setCache($cache);
543 $this->backend->set('BackendDbTest', 'some data', array('UnitTestTag%special'), 1);
544
545 sleep(2);
546
547 $this->assertEquals(array(), $this->backend->findIdentifiersByTag('UnitTestTag%special'));
548 }
549
550 /**
551 * @test
552 * @author Ingo Renner <ingo@typo3.org>
553 */
554 public function setWithUnlimitedLifetimeWritesCorrectEntry() {
555 $cache = $this->getMock('t3lib_cache_frontend_AbstractFrontend',
556 array('getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove'),
557 array(),
558 '',
559 FALSE
560 );
561
562 $data = 'some data' . microtime();
563 $entryIdentifier = 'BackendFileTest';
564
565 $this->backend->setCache($cache);
566 $this->backend->set($entryIdentifier, $data, array(), 0);
567
568 $entriesFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
569 '*',
570 $this->testingCacheTable,
571 ''
572 );
573
574 $this->assertTrue(is_array($entriesFound), 'entriesFound is not an array.');
575
576 $retrievedData = $entriesFound[0]['content'];
577 $this->assertEquals($data, $retrievedData, 'The original and the retrieved data don\'t match.');
578 }
579
580
581 /**
582 * @test
583 * @author Ingo Renner <ingo@typo3.org>
584 */
585 public function tearDown() {
586 $GLOBALS['TYPO3_DB']->sql_query(
587 'DROP TABLE ' . $this->testingCacheTable . ';'
588 );
589 }
590
591 }
592
593 ?>