2 /***************************************************************
5 * (c) 2009-2011 Ingo Renner <ingo@typo3.org>
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.
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
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.
22 * This copyright notice MUST APPEAR in all copies of the script!
23 ***************************************************************/
26 * Testcase for the DB cache backend
28 * @author Ingo Renner <ingo@typo3.org>
32 class t3lib_cache_backend_DbBackendTest
extends tx_phpunit_testcase
{
35 * Enable backup of global and system variables
39 protected $backupGlobals = TRUE;
42 * Exclude TYPO3_DB from backup/ restore of $GLOBALS
43 * because resource types cannot be handled during serializing
47 protected $backupGlobalsBlacklist = array('TYPO3_DB');
50 * @var t3lib_DB Backup of original TYPO3_DB instance
52 protected $typo3DbBackup;
55 * @var string Name of the testing data table
57 protected $testingCacheTable = 'cachingframework_Testing';
60 * @var string Name of the testing tags table
62 protected $testingTagsTable = 'cachingframework_Testing_tags';
67 public function setUp() {
68 $this->typo3DbBackup
= $GLOBALS['TYPO3_DB'];
72 * Sets up the backend used for testing
75 * @author Ingo Renner <ingo@typo3.org>
76 * @author Christian Kuhn <lolli@schwarzbu.ch>
78 protected function setUpBackend(array $backendOptions = array()) {
79 $GLOBALS['TYPO3_DB']->sql_query('CREATE TABLE ' . $this->testingCacheTable
. ' (
80 id int(11) unsigned NOT NULL auto_increment,
81 identifier varchar(250) DEFAULT \'\' NOT NULL,
82 crdate int(11) unsigned DEFAULT \'0\' NOT NULL,
84 lifetime int(11) unsigned DEFAULT \'0\' NOT NULL,
86 KEY cache_id (identifier)
90 $GLOBALS['TYPO3_DB']->sql_query('CREATE TABLE ' . $this->testingTagsTable
. ' (
91 id int(11) unsigned NOT NULL auto_increment,
92 identifier varchar(250) DEFAULT \'\' NOT NULL,
93 tag varchar(250) DEFAULT \'\' NOT NULL,
95 KEY cache_id (identifier),
100 $backend = t3lib_div
::makeInstance(
101 't3lib_cache_backend_DbBackend',
110 * Helper method to inject a mock frontend to backend instance
112 * @param t3lib_cache_backend_DbBackend $backend Current backend instance
115 protected function setUpMockFrontendOfBackend(t3lib_cache_backend_DbBackend
$backend) {
116 $mockCache = $this->getMock('t3lib_cache_frontend_AbstractFrontend', array(), array(), '', FALSE);
117 $mockCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('Testing'));
118 $backend->setCache($mockCache);
122 * @author Ingo Renner <ingo@typo3.org>
124 public function tearDown() {
125 $GLOBALS['TYPO3_DB']->sql_query(
126 'DROP TABLE IF EXISTS ' . $this->testingCacheTable
. ';'
129 $GLOBALS['TYPO3_DB']->sql_query(
130 'DROP TABLE IF EXISTS ' . $this->testingTagsTable
. ';'
133 $GLOBALS['TYPO3_DB'] = $this->typo3DbBackup
;
138 * @author Ingo Renner <ingo@typo3.org>
140 public function setCacheCalculatesCacheTableName() {
141 $backend = $this->setUpBackend();
142 $this->setUpMockFrontendOfBackend($backend);
143 $this->assertEquals($this->testingCacheTable
, $backend->getCacheTable());
149 public function setCacheCalculatesTagsTableName() {
150 $backend = $this->setUpBackend();
151 $this->setUpMockFrontendOfBackend($backend);
153 $this->assertEquals($this->testingTagsTable
, $backend->getTagsTable());
158 * @expectedException t3lib_cache_Exception
160 public function setThrowsExceptionIfFrontendWasNotSet() {
161 $backend = $this->setUpBackend();
162 $backend->set('identifier', 'data');
167 * @expectedException t3lib_cache_exception_InvalidData
168 * @author Ingo Renner <ingo@typo3.org>
170 public function setThrowsExceptionIfDataIsNotAString() {
171 $backend = $this->setUpBackend();
172 $this->setUpMockFrontendOfBackend($backend);
174 $data = array('Some data');
175 $entryIdentifier = 'BackendDbTest';
177 $backend->set($entryIdentifier, $data);
182 * @author Ingo Renner <ingo@typo3.org>
184 public function setInsertsEntryInTable() {
185 $backend = $this->setUpBackend();
186 $this->setUpMockFrontendOfBackend($backend);
188 $data = 'some data' . microtime();
189 $entryIdentifier = 'BackendDbTest';
191 $backend->set($entryIdentifier, $data);
193 $entryFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
195 $this->testingCacheTable
,
196 'identifier = \'' . $entryIdentifier . '\''
199 $this->assertEquals($data, $entryFound['content']);
204 * @author Ingo Renner <ingo@typo3.org>
206 public function setRemovesAnAlreadyExistingCacheEntryForTheSameIdentifier() {
207 $backend = $this->setUpBackend();
208 $this->setUpMockFrontendOfBackend($backend);
210 $data1 = 'some data' . microtime();
211 $data2 = $data1 . '_different';
212 $entryIdentifier = 'BackendDbRemoveBeforeSetTest';
214 $backend->set($entryIdentifier, $data1, array(), 500);
215 $backend->set($entryIdentifier, $data2, array(), 200);
217 $entriesFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
219 $this->testingCacheTable
,
220 'identifier = \'' . $entryIdentifier . '\''
223 $this->assertEquals(1, count($entriesFound));
228 * @author Ingo Renner <ingo@typo3.org>
230 public function setReallySavesSpecifiedTags() {
231 $backend = $this->setUpBackend();
232 $this->setUpMockFrontendOfBackend($backend);
234 $data = 'some data' . microtime();
235 $entryIdentifier = 'BackendDbTest';
237 $backend->set($entryIdentifier, $data, array('UnitTestTag%tag1', 'UnitTestTag%tag2'));
239 $entriesFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
241 $this->testingTagsTable
,
242 'identifier = \'' . $entryIdentifier . '\''
247 foreach ($entriesFound as $entry) {
248 $tags[] = $entry['tag'];
251 $this->assertTrue(count($tags) > 0);
252 $this->assertTrue(in_array('UnitTestTag%tag1', $tags));
253 $this->assertTrue(in_array('UnitTestTag%tag2', $tags));
258 * @author Christian Kuhn <lolli@schwarzbu.ch>
260 public function setSavesCompressedDataWithEnabledCompression() {
261 $backend = $this->setUpBackend(
263 'compression' => TRUE,
266 $this->setUpMockFrontendOfBackend($backend);
268 $data = 'some data ' . microtime();
269 $entryIdentifier = 'BackendDbTest';
271 $backend->set($entryIdentifier, $data);
273 $entry = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
275 $this->testingCacheTable
,
276 'identifier = \'' . $entryIdentifier . '\''
279 $this->assertEquals($data, @gzuncompress
($entry['content']));
284 * @author Christian Kuhn <lolli@schwarzbu.ch>
286 public function setSavesPlaintextDataWithEnabledCompressionAndCompressionLevel0() {
287 $backend = $this->setUpBackend(
289 'compression' => TRUE,
290 'compressionLevel' => 0,
293 $this->setUpMockFrontendOfBackend($backend);
295 $data = 'some data ' . microtime();
296 $entryIdentifier = 'BackendDbTest';
298 $backend->set($entryIdentifier, $data);
300 $entry = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
302 $this->testingCacheTable
,
303 'identifier = \'' . $entryIdentifier . '\''
306 $this->assertGreaterThan(0, substr_count($entry['content'], $data));
311 * @expectedException t3lib_cache_Exception
313 public function getThrowsExceptionIfFrontendWasNotSet() {
314 $backend = $this->setUpBackend();
315 $backend->get('identifier');
320 * @author Ingo Renner <ingo@typo3.org>
322 public function getReturnsContentOfTheCorrectCacheEntry() {
323 $backend = $this->setUpBackend();
324 $this->setUpMockFrontendOfBackend($backend);
326 $data = 'some data' . microtime();
327 $entryIdentifier = 'BackendDbTest';
329 $backend->set($entryIdentifier, $data, array(), 500);
331 $data = 'some other data' . microtime();
332 $backend->set($entryIdentifier, $data, array(), 100);
334 $loadedData = $backend->get($entryIdentifier);
336 $this->assertEquals($data, $loadedData);
341 * @expectedException t3lib_cache_Exception
343 public function hasThrowsExceptionIfFrontendWasNotSet() {
344 $backend = $this->setUpBackend();
345 $backend->has('identifier');
350 * @author Ingo Renner <ingo@typo3.org>
352 public function hasReturnsTheCorrectResult() {
353 $backend = $this->setUpBackend();
354 $this->setUpMockFrontendOfBackend($backend);
356 $data = 'some data' . microtime();
357 $entryIdentifier = 'BackendDbTest';
359 $backend->set($entryIdentifier, $data);
361 $this->assertTrue($backend->has($entryIdentifier));
362 $this->assertFalse($backend->has($entryIdentifier . 'Not'));
367 * @expectedException t3lib_cache_Exception
369 public function removeThrowsExceptionIfFrontendWasNotSet() {
370 $backend = $this->setUpBackend();
371 $backend->remove('identifier');
376 * @author Ingo Renner <ingo@typo3.org>
378 public function removeReallyRemovesACacheEntry() {
379 $backend = $this->setUpBackend();
380 $this->setUpMockFrontendOfBackend($backend);
382 $data = 'some data' . microtime();
383 $entryIdentifier = 'BackendDbRemovalTest';
385 $backend->set($entryIdentifier, $data);
387 $backend->remove($entryIdentifier);
389 $entriesFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
391 $this->testingCacheTable
,
392 'identifier = \'' . $entryIdentifier . '\''
395 $this->assertTrue(count($entriesFound) == 0);
400 * @expectedException t3lib_cache_Exception
402 public function collectGarbageThrowsExceptionIfFrontendWasNotSet() {
403 $backend = $this->setUpBackend();
404 $backend->collectGarbage();
409 * @author Ingo Renner <ingo@typo3.org>
411 public function collectGarbageReallyRemovesAnExpiredCacheEntry() {
412 $backend = $this->setUpBackend();
413 $this->setUpMockFrontendOfBackend($backend);
415 $data = 'some data' . microtime();
416 $entryIdentifier = 'BackendDbRemovalTest';
418 $backend->set($entryIdentifier, $data, array(), 1);
420 $GLOBALS['EXEC_TIME'] +
= 2;
421 $backend->collectGarbage();
423 $entriesFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
425 $this->testingCacheTable
,
426 'identifier = \'' . $entryIdentifier . '\''
429 $this->assertTrue(count($entriesFound) == 0);
434 * @author Ingo Renner <ingo@typo3.org>
436 public function collectGarbageReallyRemovesAllExpiredCacheEntries() {
437 $backend = $this->setUpBackend();
438 $this->setUpMockFrontendOfBackend($backend);
440 $data = 'some data' . microtime();
441 $entryIdentifier = 'BackendDbRemovalTest';
443 $backend->set($entryIdentifier . 'A', $data, array(), 1);
444 $backend->set($entryIdentifier . 'B', $data, array(), 1);
445 $backend->set($entryIdentifier . 'C', $data, array(), 1);
447 $GLOBALS['EXEC_TIME'] +
= 2;
448 $backend->collectGarbage();
450 $entriesFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
452 $this->testingCacheTable
,
456 $this->assertTrue(count($entriesFound) == 0);
461 * @author Ingo Renner <ingo@typo3.org>
463 public function findIdentifiersByTagFindsCacheEntriesWithSpecifiedTag() {
464 $backend = $this->setUpBackend();
465 $this->setUpMockFrontendOfBackend($backend);
467 $data = 'some data' . microtime();
468 $backend->set('BackendDbTest1', $data, array('UnitTestTag%test', 'UnitTestTag%boring'));
469 $backend->set('BackendDbTest2', $data, array('UnitTestTag%test', 'UnitTestTag%special'));
470 $backend->set('BackendDbTest3', $data, array('UnitTestTag%test'));
472 $expectedEntry = 'BackendDbTest2';
474 $actualEntries = $backend->findIdentifiersByTag('UnitTestTag%special');
475 $this->assertTrue(is_array($actualEntries));
476 $this->assertEquals($expectedEntry, array_pop($actualEntries));
481 * @expectedException t3lib_cache_Exception
483 public function flushThrowsExceptionIfFrontendWasNotSet() {
484 $backend = $this->setUpBackend();
490 * @author Ingo Renner <ingo@typo3.org>
492 public function flushRemovesAllCacheEntries() {
493 $backend = $this->setUpBackend();
494 $this->setUpMockFrontendOfBackend($backend);
496 $data = 'some data' . microtime();
497 $backend->set('BackendDbTest1', $data, array('UnitTestTag%test'));
498 $backend->set('BackendDbTest2', $data, array('UnitTestTag%test', 'UnitTestTag%special'));
499 $backend->set('BackendDbTest3', $data, array('UnitTestTag%test'));
503 $entriesFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
505 $this->testingCacheTable
,
509 $this->assertTrue(count($entriesFound) == 0);
515 public function flushDropsDataTable() {
516 $backend = $this->setUpBackend();
517 $this->setUpMockFrontendOfBackend($backend);
519 $GLOBALS['TYPO3_DB'] = $this->getMock('t3lib_DB', array('admin_query'));
520 $GLOBALS['TYPO3_DB']->expects($this->at(0))
521 ->method('admin_query')
522 ->with('DROP TABLE IF EXISTS cachingframework_Testing');
530 public function flushDropsTagsTable() {
531 $backend = $this->setUpBackend();
532 $this->setUpMockFrontendOfBackend($backend);
534 $GLOBALS['TYPO3_DB'] = $this->getMock('t3lib_DB', array('admin_query'));
535 $GLOBALS['TYPO3_DB']->expects($this->at(1))
536 ->method('admin_query')
537 ->with('DROP TABLE IF EXISTS cachingframework_Testing_tags');
545 public function flushCreatesDataTable() {
546 $backend = $this->setUpBackend();
547 $this->setUpMockFrontendOfBackend($backend);
549 $GLOBALS['TYPO3_DB'] = $this->getMock('t3lib_DB', array('admin_query'));
550 $GLOBALS['TYPO3_DB']->expects($this->at(2))
551 ->method('admin_query')
552 ->will($this->returnCallback(array($this, flushCreatesDataTableCallback
)));
558 * Callback of flushCreatesDataTable to check if data table is created
560 * @param string $sql SQL of admin_query
563 public function flushCreatesDataTableCallback($sql) {
564 $startOfStatement = 'CREATE TABLE cachingframework_Testing (';
565 $this->assertEquals($startOfStatement, substr($sql, 0, strlen($startOfStatement)));
571 public function flushCreatesTagsTable() {
572 $backend = $this->setUpBackend();
573 $this->setUpMockFrontendOfBackend($backend);
575 $GLOBALS['TYPO3_DB'] = $this->getMock('t3lib_DB', array('admin_query'));
576 $GLOBALS['TYPO3_DB']->expects($this->at(3))
577 ->method('admin_query')
578 ->will($this->returnCallback(array($this, flushCreatesTagsTableCallback
)));
584 * Callback of flushCreatesTagsTable to check if tags table is created
586 * @param string $sql SQL of admin_query
589 public function flushCreatesTagsTableCallback($sql) {
590 $startOfStatement = 'CREATE TABLE cachingframework_Testing_tags (';
591 $this->assertEquals($startOfStatement, substr($sql, 0, strlen($startOfStatement)));
596 * @expectedException t3lib_cache_Exception
598 public function flushByTagThrowsExceptionIfFrontendWasNotSet() {
599 $backend = $this->setUpBackend();
600 $backend->flushByTag(array());
605 * @author Ingo Renner <ingo@typo3.org>
607 public function flushByTagRemovesCacheEntriesWithSpecifiedTag() {
608 $backend = $this->setUpBackend();
609 $this->setUpMockFrontendOfBackend($backend);
611 $data = 'some data' . microtime();
612 $backend->set('BackendDbTest1', $data, array('UnitTestTag%test', 'UnitTestTag%boring'));
613 $backend->set('BackendDbTest2', $data, array('UnitTestTag%test', 'UnitTestTag%special'));
614 $backend->set('BackendDbTest3', $data, array('UnitTestTag%test'));
616 $backend->flushByTag('UnitTestTag%special');
618 $this->assertTrue($backend->has('BackendDbTest1'), 'BackendDbTest1 does not exist anymore.');
619 $this->assertFalse($backend->has('BackendDbTest2'), 'BackendDbTest2 still exists.');
620 $this->assertTrue($backend->has('BackendDbTest3'), 'BackendDbTest3 does not exist anymore.');
622 $tagEntriesFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
624 $this->testingTagsTable
,
625 'tag = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr('UnitTestTag%special', $this->testingTagsTable
)
627 $this->assertEquals(0, count($tagEntriesFound));
633 * @author Ingo Renner <ingo@typo3.org>
635 public function hasReturnsTheCorrectResultForEntryWithExceededLifetime() {
636 $backend = $this->setUpBackend();
637 $this->setUpMockFrontendOfBackend($backend);
639 $data = 'some data' . microtime();
640 $entryIdentifier = 'BackendDbTest';
642 $backend->set($entryIdentifier, $data);
644 $expiredEntryIdentifier = 'ExpiredBackendDbTest';
645 $expiredData = 'some old data' . microtime();
646 $backend->set($expiredEntryIdentifier, $expiredData, array(), 1);
648 $GLOBALS['EXEC_TIME'] +
= 2;
650 $this->assertFalse($backend->has($expiredEntryIdentifier));
655 * @author Christian Kuhn <lolli@schwarzbu.ch>
657 public function hasReturnsTrueForEntryWithUnlimitedLifetime() {
658 $backend = $this->setUpBackend();
659 $this->setUpMockFrontendOfBackend($backend);
661 $entryIdentifier = 'BackendDbTest';
663 $backend->set($entryIdentifier, 'data', array(), 0);
665 $GLOBALS['EXEC_TIME'] +
= 1;
666 $this->assertTrue($backend->has($entryIdentifier));
671 * @author Ingo Renner <ingo@typo3.org>
673 public function getReturnsFalseForEntryWithExceededLifetime() {
674 $backend = $this->setUpBackend();
675 $this->setUpMockFrontendOfBackend($backend);
677 $data = 'some data' . microtime();
678 $entryIdentifier = 'BackendDbTest';
680 $backend->set($entryIdentifier, $data);
682 $expiredEntryIdentifier = 'ExpiredBackendDbTest';
683 $expiredData = 'some old data' . microtime();
684 $backend->set($expiredEntryIdentifier, $expiredData, array(), 1);
686 $GLOBALS['EXEC_TIME'] +
= 2;
688 $this->assertEquals($data, $backend->get($entryIdentifier));
689 $this->assertFalse($backend->get($expiredEntryIdentifier));
694 * @expectedException t3lib_cache_Exception
696 public function findIdentifiersByTagThrowsExceptionIfFrontendWasNotSet() {
697 $backend = $this->setUpBackend();
698 $backend->findIdentifiersByTag('identifier');
703 * @author Ingo Renner <ingo@typo3.org>
705 public function findIdentifiersByTagReturnsEmptyArrayForEntryWithExceededLifetime() {
706 $backend = $this->setUpBackend();
707 $mockCache = $this->getMock('t3lib_cache_frontend_AbstractFrontend', array(), array(), '', FALSE);
708 $mockCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('Testing'));
709 $backend->setCache($mockCache);
711 $backend->set('BackendDbTest', 'some data', array('UnitTestTag%special'), 1);
713 $GLOBALS['EXEC_TIME'] +
= 2;
714 // Not required, but used to update the pre-calculated queries:
715 $backend->setCache($mockCache);
717 $this->assertEquals(array(), $backend->findIdentifiersByTag('UnitTestTag%special'));
722 * @author Ingo Renner <ingo@typo3.org>
724 public function setWithUnlimitedLifetimeWritesCorrectEntry() {
725 $backend = $this->setUpBackend();
726 $this->setUpMockFrontendOfBackend($backend);
728 $data = 'some data' . microtime();
729 $entryIdentifier = 'BackendFileTest';
731 $backend->set($entryIdentifier, $data, array(), 0);
733 $entryFound = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
735 $this->testingCacheTable
,
739 $this->assertTrue(is_array($entryFound));
741 $retrievedData = $entryFound['content'];
742 $this->assertEquals($data, $retrievedData);