Added feature #14666: Caching framework: Backport PhpFrontend from FLOW3 and refactor...
[Packages/TYPO3.CMS.git] / tests / t3lib / cache / backend / t3lib_cache_backend_filebackendtestcase.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2009-2010 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_filebackend.php');
47
48 /**
49 * Testcase for the File cache backend
50 *
51 * This file is a backport from FLOW3
52 *
53 * @author Ingo Renner <ingo@typo3.org>
54 * @author Christian Kuhn <lolli@schwarzbu.ch>
55 * @package TYPO3
56 * @subpackage tests
57 * @version $Id$
58 */
59 class t3lib_cache_backend_FileBackendTestCase extends tx_phpunit_testcase {
60 /**
61 * Backup of global variable EXEC_TIME
62 *
63 * @var array
64 */
65 protected $backupGlobalVariables;
66
67 /**
68 * If set, the tearDown() method will clean up the cache subdirectory used by this unit test.
69 *
70 * @var t3lib_cache_backend_FileBackend
71 */
72 protected $backend;
73
74 /**
75 * @var string Directory for testing data, relative to PATH_site
76 */
77 protected $testingCacheDirectory;
78
79 /**
80 * Sets up this testcase
81 *
82 * @return void
83 */
84 public function setUp() {
85 $this->backupGlobalVariables = array(
86 'EXEC_TIME' => $GLOBALS['EXEC_TIME'],
87 );
88
89 $this->testingCacheDirectory = 'typo3temp/cache/testing/';
90
91 $this->backend = t3lib_div::makeInstance(
92 't3lib_cache_backend_FileBackend',
93 array('cacheDirectory' => $this->testingCacheDirectory)
94 );
95 }
96
97 /**
98 * @test
99 * @author Robert Lemke <robert@typo3.org>
100 * @author Ingo Renner <ingo@typo3.org>
101 */
102 public function defaultCacheDirectoryIsWritable() {
103 $cacheDirectory = $this->backend->getCacheDirectory();
104
105 $this->assertTrue(is_writable($cacheDirectory), 'The default cache directory "' . $cacheDirectory . '" is not writable.');
106 }
107
108 /**
109 * @test
110 * @author Robert Lemke <robert@typo3.org>
111 * @expectedException t3lib_cache_Exception
112 */
113 public function setCacheDirectoryThrowsExceptionOnNonWritableDirectory() {
114 if (DIRECTORY_SEPARATOR == '\\') {
115 $this->markTestSkipped('test not reliable in Windows environment');
116 }
117 $directoryName = '/sbin';
118
119 $this->backend->setCacheDirectory($directoryName);
120 }
121
122 /**
123 * @test
124 * @author Robert Lemke <robert@typo3.org>
125 * @author Ingo Renner <ingo@typo3.org>
126 */
127 public function getCacheDirectoryReturnsTheCurrentCacheDirectory() {
128 $directory = $this->testingCacheDirectory;
129 $fullPathToDirectory = t3lib_div::getIndpEnv('TYPO3_DOCUMENT_ROOT') . '/' . $directory;
130
131 $this->backend->setCacheDirectory($directory);
132 $this->assertEquals($fullPathToDirectory, $this->backend->getCacheDirectory(), 'getCacheDirectory() did not return the expected value.');
133 }
134
135 /**
136 * @test
137 * @author Robert Lemke <robert@typo3.org>
138 * @author Ingo Renner <ingo@typo3.org>
139 * @expectedException t3lib_cache_exception_InvalidData
140 */
141 public function setThrowsExceptionIfDataIsNotAString() {
142 $mockCache = $this->getMock('t3lib_cache_frontend_AbstractFrontend', array(), array(), '', FALSE);
143 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
144
145 $this->backend->setCache($mockCache);
146 $data = array('Some data');
147 $entryIdentifier = 'BackendFileTest';
148
149 $this->backend->set($entryIdentifier, $data);
150 }
151
152 /**
153 * @test
154 * @author Robert Lemke <robert@typo3.org>
155 * @author Ingo Renner <ingo@typo3.org>
156 */
157 public function setReallySavesToTheSpecifiedDirectory() {
158 $mockCache = $this->getMock('t3lib_cache_frontend_AbstractFrontend', array(), array(), '', FALSE);
159 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
160
161 $data = 'some data' . microtime();
162 $entryIdentifier = 'BackendFileTest';
163 $this->backend->setCache($mockCache);
164 $pathAndFilename = $this->backend->getCacheDirectory() . $entryIdentifier;
165
166 $this->backend->set($entryIdentifier, $data, array(), 10);
167
168 $this->assertFileExists($pathAndFilename);
169 $retrievedData = file_get_contents($pathAndFilename, NULL, NULL, 0, strlen($data));
170 $this->assertEquals($data, $retrievedData);
171 }
172
173 /**
174 * @test
175 * @author Robert Lemke <robert@typo3.org>
176 * @author Ingo Renner <ingo@typo3.org>
177 */
178 public function setOverwritesAnAlreadyExistingCacheEntryForTheSameIdentifier() {
179 $mockCache = $this->getMock('t3lib_cache_frontend_AbstractFrontend', array(), array(), '', FALSE);
180 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
181
182 $data1 = 'some data' . microtime();
183 $data2 = 'some data' . microtime();
184 $entryIdentifier = 'BackendFileRemoveBeforeSetTest';
185
186 $this->backend->setCache($mockCache);
187 $this->backend->set($entryIdentifier, $data1, array(), 500);
188 // Setting a second entry with the same identifier, but different
189 // data, this should _replace_ the existing one we set before
190 $this->backend->set($entryIdentifier, $data2, array(), 200);
191
192 $pathAndFilename = $this->backend->getCacheDirectory() . $entryIdentifier;
193
194 $this->assertFileExists($pathAndFilename);
195 $retrievedData = file_get_contents($pathAndFilename, NULL, NULL, 0, strlen($data2));
196 $this->assertEquals($data2, $retrievedData);
197 }
198
199 /**
200 * @test
201 * @author Robert Lemke <robert@typo3.org>
202 * @author Ingo Renner <ingo@typo3.org>
203 */
204 public function setAlsoSavesSpecifiedTags() {
205 $mockCache = $this->getMock('t3lib_cache_frontend_AbstractFrontend', array(), array(), '', FALSE);
206 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
207
208 $data = 'some data' . microtime();
209 $entryIdentifier = 'BackendFileTest';
210
211 $this->backend->setCache($mockCache);
212 $this->backend->set($entryIdentifier, $data, array('Tag1', 'Tag2'));
213
214 $pathAndFilename = $this->backend->getCacheDirectory() . $entryIdentifier;
215 $this->assertFileExists($pathAndFilename);
216 $retrievedData = file_get_contents($pathAndFilename, NULL, NULL, (strlen($data) + t3lib_cache_backend_FileBackend::EXPIRYTIME_LENGTH), 9);
217 $this->assertEquals('Tag1 Tag2', $retrievedData);
218 }
219
220 /**
221 * @test
222 * @author Robert Lemke <robert@typo3.org>
223 * @author Karsten Dambekalns <karsten@typo3.org>
224 * @author Ingo Renner <ingo@typo3.org>
225 */
226 public function setWithUnlimitedLifetimeWritesCorrectEntry() {
227 $mockCache = $this->getMock('t3lib_cache_frontend_AbstractFrontend', array(), array(), '', FALSE);
228 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
229
230 $data = 'some data' . microtime();
231 $entryIdentifier = 'BackendFileTest';
232
233 $this->backend->setCache($mockCache);
234 $pathAndFilename = $this->backend->getCacheDirectory() . $entryIdentifier;
235
236 $this->backend->set($entryIdentifier, $data, array(), 0);
237
238 $this->assertFileExists($pathAndFilename);
239
240 $dataSize = (integer)file_get_contents($pathAndFilename, NULL, NULL, filesize($pathAndFilename) - t3lib_cache_backend_FileBackend::DATASIZE_DIGITS, t3lib_cache_backend_FileBackend::DATASIZE_DIGITS);
241 $retrievedData = file_get_contents($pathAndFilename, NULL, NULL, 0, $dataSize);
242
243 $this->assertEquals($data, $retrievedData, 'The original and the retrieved data don\'t match.');
244 }
245
246 /**
247 * @test
248 * @author Robert Lemke <robert@typo3.org>
249 */
250 public function getReturnsFalseForExpiredEntries() {
251 $mockCache = $this->getMock('t3lib_cache_frontend_AbstractFrontend', array(), array(), '', FALSE);
252 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
253
254 $backend = $this->getMock('t3lib_cache_backend_FileBackend', array('isCacheFileExpired'), array(), '', FALSE);
255 $fullPathToCacheFile = t3lib_div::getIndpEnv('TYPO3_DOCUMENT_ROOT') . '/typo3temp/cache/UnitTestCache/ExpiredEntry';
256 $backend->expects($this->once())->method('isCacheFileExpired')->with($fullPathToCacheFile)->will($this->returnValue(TRUE));
257 $backend->setCache($mockCache);
258
259 $this->assertFalse($backend->get('ExpiredEntry'));
260 }
261
262 /**
263 * @test
264 * @author Robert Lemke <robert@typo3.org>
265 * @author Ingo Renner <ingo@typo3.org>
266 */
267 public function hasReturnsTrueIfAnEntryExists() {
268 $mockCache = $this->getMock('t3lib_cache_frontend_AbstractFrontend', array(), array(), '', FALSE);
269 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
270
271 $this->backend->setCache($mockCache);
272
273 $entryIdentifier = 'BackendFileTest';
274 $data = 'some data' . microtime();
275 $this->backend->set($entryIdentifier, $data);
276
277 $this->assertTrue($this->backend->has($entryIdentifier), 'has() did not return TRUE.');
278 $this->assertFalse($this->backend->has($entryIdentifier . 'Not'), 'has() did not return FALSE.');
279 }
280
281 /**
282 * @test
283 * @author Robert Lemke <robert@typo3.org>
284 */
285 public function hasReturnsFalseForExpiredEntries() {
286 $backend = $this->getMock('t3lib_cache_backend_FileBackend', array('isCacheFileExpired'), array(), '', FALSE);
287 $backend->expects($this->exactly(2))->method('isCacheFileExpired')->will($this->onConsecutiveCalls(TRUE, FALSE));
288
289 $this->assertFalse($backend->has('foo'));
290 $this->assertTrue($backend->has('bar'));
291 }
292
293 /**
294 * @test
295 * @author Robert Lemke <robert@typo3.org>
296 * @author Ingo Renner <ingo@typo3.org>
297 */
298 public function removeReallyRemovesACacheEntry() {
299 $mockCache = $this->getMock('t3lib_cache_frontend_AbstractFrontend', array(), array(), '', FALSE);
300 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
301
302 $data = 'some data' . microtime();
303 $entryIdentifier = 'BackendFileTest';
304
305 $this->backend->setCache($mockCache);
306 $pathAndFilename = $this->backend->getCacheDirectory() . $entryIdentifier;
307 $this->backend->set($entryIdentifier, $data);
308
309 $this->assertFileExists($pathAndFilename);
310 $this->backend->remove($entryIdentifier);
311 $this->assertFileNotExists($pathAndFilename);
312 }
313
314 /**
315 * @test
316 * @author Robert Lemke <robert@typo3.org>
317 * @author Karsten Dambekalns <karsten@typo3.org>
318 * @author Ingo Renner <ingo@typo3.org>
319 */
320 public function collectGarbageReallyRemovesAnExpiredCacheEntry() {
321 $mockCache = $this->getMock('t3lib_cache_frontend_AbstractFrontend', array(), array(), '', FALSE);
322 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
323
324 $data = 'some data' . microtime();
325 $entryIdentifier = 'BackendFileRemovalTest';
326
327 $this->backend->setCache($mockCache);
328 $pathAndFilename = $this->backend->getCacheDirectory() . $entryIdentifier;
329 $this->backend->set($entryIdentifier, $data, array(), 1);
330
331 $this->assertFileExists($pathAndFilename);
332
333 $GLOBALS['EXEC_TIME'] += 2;
334 $this->backend->collectGarbage();
335
336 $this->assertFileNotExists($pathAndFilename);
337 }
338
339 /**
340 * @test
341 * @author Robert Lemke <robert@typo3.org>
342 * @author Karsten Dambekalns <karsten@typo3.org>
343 * @author Ingo Renner <ingo@typo3.org>
344 */
345 public function collectGarbageReallyRemovesAllExpiredCacheEntries() {
346 $mockCache = $this->getMock('t3lib_cache_frontend_AbstractFrontend', array(), array(), '', FALSE);
347 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
348
349 $data = 'some data' . microtime();
350 $entryIdentifier = 'BackendFileRemovalTest';
351
352 $this->backend->setCache($mockCache);
353 $pathAndFilename = $this->backend->getCacheDirectory() . $entryIdentifier;
354
355 $this->backend->set($entryIdentifier . 'A', $data, array(), NULL);
356 $this->backend->set($entryIdentifier . 'B', $data, array(), 10);
357 $this->backend->set($entryIdentifier . 'C', $data, array(), 1);
358 $this->backend->set($entryIdentifier . 'D', $data, array(), 1);
359
360 $this->assertFileExists($pathAndFilename . 'A');
361 $this->assertFileExists($pathAndFilename . 'B');
362 $this->assertFileExists($pathAndFilename . 'C');
363 $this->assertFileExists($pathAndFilename . 'D');
364
365 $GLOBALS['EXEC_TIME'] += 2;
366 $this->backend->collectGarbage();
367
368 $this->assertFileExists($pathAndFilename . 'A');
369 $this->assertFileExists($pathAndFilename . 'B');
370 $this->assertFileNotExists($pathAndFilename . 'C');
371 $this->assertFileNotExists($pathAndFilename . 'D');
372 }
373
374 /**
375 * @test
376 * @author Robert Lemke <robert@typo3.org>
377 * @author Ingo Renner <ingo@typo3.org>
378 */
379 public function findIdentifiersByTagFindsCacheEntriesWithSpecifiedTag() {
380 $mockCache = $this->getMock('t3lib_cache_frontend_AbstractFrontend', array(), array(), '', FALSE);
381 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
382
383 $this->backend->setCache($mockCache);
384
385 $data = 'some data' . microtime();
386 $this->backend->set('BackendFileTest1', $data, array('UnitTestTag%test', 'UnitTestTag%boring'));
387 $this->backend->set('BackendFileTest2', $data, array('UnitTestTag%test', 'UnitTestTag%special'));
388 $this->backend->set('BackendFileTest3', $data, array('UnitTestTag%test'));
389
390 $expectedEntry = 'BackendFileTest2';
391
392 $actualEntries = $this->backend->findIdentifiersByTag('UnitTestTag%special');
393
394 $this->assertTrue(is_array($actualEntries), 'actualEntries is not an array.');
395 $this->assertEquals($expectedEntry, array_pop($actualEntries));
396 }
397
398 /**
399 * @test
400 * @author Ingo Renner <ingo@typo3.org>
401 */
402 public function findIdentifiersByTagDoesNotReturnExpiredEntries() {
403 $mockCache = $this->getMock('t3lib_cache_frontend_AbstractFrontend', array(), array(), '', FALSE);
404 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
405
406 $this->backend->setCache($mockCache);
407
408 $data = 'some data';
409 $this->backend->set('BackendFileTest1', $data, array('UnitTestTag%test', 'UnitTestTag%boring'));
410 $this->backend->set('BackendFileTest2', $data, array('UnitTestTag%test', 'UnitTestTag%special'), -100);
411 $this->backend->set('BackendFileTest3', $data, array('UnitTestTag%test'));
412
413 $this->assertSame(array(), $this->backend->findIdentifiersByTag('UnitTestTag%special'));
414 $foundIdentifiers = $this->backend->findIdentifiersByTag('UnitTestTag%test');
415 sort($foundIdentifiers);
416 $this->assertSame(array('BackendFileTest1', 'BackendFileTest3'), $foundIdentifiers);
417 }
418
419 /**
420 * @test
421 * @author Robert Lemke <robert@typo3.org>
422 * @author Ingo Renner <ingo@typo3.org>
423 */
424 public function flushRemovesAllCacheEntries() {
425 $mockCache = $this->getMock('t3lib_cache_frontend_AbstractFrontend', array(), array(), '', FALSE);
426 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
427
428 $this->backend->setCache($mockCache);
429
430 $data = 'some data' . microtime();
431 $this->backend->set('BackendFileTest1', $data, array('UnitTestTag%test'));
432 $this->backend->set('BackendFileTest2', $data, array('UnitTestTag%test', 'UnitTestTag%special'));
433 $this->backend->set('BackendFileTest3', $data, array('UnitTestTag%test'));
434
435 $this->backend->flush();
436
437 $pattern = $this->backend->getCacheDirectory() . '*';
438 $filesFound = is_array(glob($pattern)) ? glob($pattern) : array();
439 $this->assertTrue(count($filesFound) === 0, 'Still files in the cache directory');
440 }
441
442 /**
443 * @test
444 * @author Robert Lemke <robert@typo3.org>
445 * @author Ingo Renner <ingo@typo3.org>
446 */
447 public function flushByTagRemovesCacheEntriesWithSpecifiedTag() {
448 $mockCache = $this->getMock('t3lib_cache_frontend_AbstractFrontend', array(), array(), '', FALSE);
449 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
450
451 $this->backend->setCache($mockCache);
452
453 $data = 'some data' . microtime();
454 $this->backend->set('BackendFileTest1', $data, array('UnitTestTag%test', 'UnitTestTag%boring'));
455 $this->backend->set('BackendFileTest2', $data, array('UnitTestTag%test', 'UnitTestTag%special'));
456 $this->backend->set('BackendFileTest3', $data, array('UnitTestTag%test'));
457
458 $this->backend->flushByTag('UnitTestTag%special');
459
460 $this->assertTrue($this->backend->has('BackendFileTest1'), 'BackendFileTest1');
461 $this->assertFalse($this->backend->has('BackendFileTest2'), 'BackendFileTest2');
462 $this->assertTrue($this->backend->has('BackendFileTest3'), 'BackendFileTest3');
463 }
464
465 /**
466 * @author Robert Lemke <robert@typo3.org>
467 * @author Ingo Renner <ingo@typo3.org>
468 */
469 public function tearDown() {
470 if (is_object($this->backend)) {
471 $directory = $this->backend->getCacheDirectory();
472 if (is_dir($directory)) {
473 t3lib_div::rmdir($directory, TRUE);
474 }
475 }
476 foreach ($this->backupGlobalVariables as $key => $data) {
477 $GLOBALS[$key] = $data;
478 }
479 }
480 }
481
482 ?>