[TASK] Use Environment API instead of PATH_site for Cache Backends
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Cache / Backend / FileBackendTest.php
1 <?php
2 declare(strict_types = 1);
3
4 namespace TYPO3\CMS\Core\Tests\Unit\Cache\Backend;
5
6 /*
7 * This file is part of the TYPO3 CMS project.
8 *
9 * It is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License, either version 2
11 * of the License, or any later version.
12 *
13 * For the full copyright and license information, please read the
14 * LICENSE.txt file that was distributed with this source code.
15 *
16 * The TYPO3 project - inspiring people to share!
17 */
18
19 use org\bovigo\vfs\vfsStreamDirectory;
20 use org\bovigo\vfs\vfsStreamWrapper;
21 use TYPO3\CMS\Core\Cache\Backend\FileBackend;
22 use TYPO3\CMS\Core\Cache\Exception;
23 use TYPO3\CMS\Core\Cache\Exception\InvalidDataException;
24 use TYPO3\CMS\Core\Cache\Frontend\AbstractFrontend;
25 use TYPO3\CMS\Core\Cache\Frontend\PhpFrontend;
26 use TYPO3\CMS\Core\Core\Environment;
27 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
28
29 /**
30 * Testcase for the File cache backend
31 */
32 class FileBackendTest extends UnitTestCase
33 {
34 /**
35 * Sets up this testcase
36 * @throws \org\bovigo\vfs\vfsStreamException
37 */
38 protected function setUp(): void
39 {
40 if (!class_exists(vfsStreamWrapper::class)) {
41 $this->markTestSkipped('File backend tests are not available with this phpunit version.');
42 }
43
44 vfsStreamWrapper::register();
45 vfsStreamWrapper::setRoot(new vfsStreamDirectory('Foo'));
46 }
47
48 /**
49 * @test
50 * @throws Exception
51 */
52 public function setCacheDirectoryThrowsExceptionOnNonWritableDirectory(): void
53 {
54 $this->expectException(Exception::class);
55 $this->expectExceptionCode(1303669848);
56
57 $mockCache = $this->createMock(AbstractFrontend::class);
58
59 $backend = $this->getMockBuilder(FileBackend::class)
60 ->setMethods(['dummy'])
61 ->disableOriginalConstructor()
62 ->getMock();
63 $backend->setCacheDirectory('http://localhost/');
64
65 $backend->setCache($mockCache);
66 }
67
68 /**
69 * @test
70 */
71 public function setCacheDirectoryAllowsAbsolutePathWithoutTrailingSlash(): void
72 {
73 $backend = $this->getAccessibleMock(FileBackend::class, ['dummy'], [], '', false);
74 $backend->_set('cacheIdentifier', 'test');
75 $backend->setCacheDirectory('/tmp/foo');
76 $this->assertEquals('/tmp/foo/test/', $backend->_get('temporaryCacheDirectory'));
77 }
78
79 /**
80 * @test
81 */
82 public function setCacheDirectoryAllowsAbsolutePathWithTrailingSlash(): void
83 {
84 $backend = $this->getAccessibleMock(FileBackend::class, ['dummy'], [], '', false);
85 $backend->_set('cacheIdentifier', 'test');
86 $backend->setCacheDirectory('/tmp/foo/');
87 $this->assertEquals('/tmp/foo/test/', $backend->_get('temporaryCacheDirectory'));
88 }
89
90 /**
91 * @test
92 */
93 public function setCacheDirectoryAllowsRelativePathWithoutTrailingSlash(): void
94 {
95 $backend = $this->getAccessibleMock(FileBackend::class, ['dummy'], [], '', false);
96 $backend->_set('cacheIdentifier', 'test');
97 $backend->setCacheDirectory('tmp/foo');
98 $path = Environment::getProjectPath();
99 $this->assertEquals($path . '/tmp/foo/test/', $backend->_get('temporaryCacheDirectory'));
100 }
101
102 /**
103 * @test
104 */
105 public function setCacheDirectoryAllowsRelativePathWithTrailingSlash(): void
106 {
107 $backend = $this->getAccessibleMock(FileBackend::class, ['dummy'], [], '', false);
108 $backend->_set('cacheIdentifier', 'test');
109 $backend->setCacheDirectory('tmp/foo/');
110 $path = Environment::getProjectPath();
111 $this->assertEquals($path . '/tmp/foo/test/', $backend->_get('temporaryCacheDirectory'));
112 }
113
114 /**
115 * @test
116 */
117 public function setCacheDirectoryAllowsRelativeDottedPathWithoutTrailingSlash(): void
118 {
119 $backend = $this->getAccessibleMock(FileBackend::class, ['dummy'], [], '', false);
120 $backend->_set('cacheIdentifier', 'test');
121 $backend->setCacheDirectory('../tmp/foo');
122 $path = Environment::getProjectPath();
123 $this->assertEquals($path . '/../tmp/foo/test/', $backend->_get('temporaryCacheDirectory'));
124 }
125
126 /**
127 * @test
128 */
129 public function setCacheDirectoryAllowsRelativeDottedPathWithTrailingSlash(): void
130 {
131 $backend = $this->getAccessibleMock(FileBackend::class, ['dummy'], [], '', false);
132 $backend->_set('cacheIdentifier', 'test');
133 $backend->setCacheDirectory('../tmp/foo/');
134 $path = Environment::getProjectPath();
135 $this->assertEquals($path . '/../tmp/foo/test/', $backend->_get('temporaryCacheDirectory'));
136 }
137
138 /**
139 * @test
140 */
141 public function setCacheDirectoryAllowsAbsoluteDottedPathWithoutTrailingSlash(): void
142 {
143 $backend = $this->getAccessibleMock(FileBackend::class, ['dummy'], [], '', false);
144 $backend->_set('cacheIdentifier', 'test');
145 $backend->setCacheDirectory('/tmp/../foo');
146 $this->assertEquals('/tmp/../foo/test/', $backend->_get('temporaryCacheDirectory'));
147 }
148
149 /**
150 * @test
151 */
152 public function setCacheDirectoryAllowsAbsoluteDottedPathWithTrailingSlash(): void
153 {
154 $backend = $this->getAccessibleMock(FileBackend::class, ['dummy'], [], '', false);
155 $backend->_set('cacheIdentifier', 'test');
156 $backend->setCacheDirectory('/tmp/../foo/');
157 $this->assertEquals('/tmp/../foo/test/', $backend->_get('temporaryCacheDirectory'));
158 }
159
160 /**
161 * @test
162 * @throws Exception
163 */
164 public function getCacheDirectoryReturnsTheCurrentCacheDirectory(): void
165 {
166 $mockCache = $this->createMock(AbstractFrontend::class);
167 $mockCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('SomeCache'));
168
169 $backend = $this->getMockBuilder(FileBackend::class)
170 ->setMethods(['dummy'])
171 ->disableOriginalConstructor()
172 ->getMock();
173 $backend->setCacheDirectory('vfs://Foo/');
174 $backend->setCache($mockCache);
175
176 $this->assertEquals('vfs://Foo/cache/data/SomeCache/', $backend->getCacheDirectory());
177 }
178
179 /**
180 * @test
181 * @throws Exception
182 */
183 public function aDedicatedCacheDirectoryIsUsedForCodeCaches(): void
184 {
185 $mockCache = $this->createMock(PhpFrontend::class);
186 $mockCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('SomeCache'));
187
188 $backend = $this->getMockBuilder(FileBackend::class)
189 ->setMethods(['dummy'])
190 ->disableOriginalConstructor()
191 ->getMock();
192 $backend->setCacheDirectory('vfs://Foo/');
193 $backend->setCache($mockCache);
194
195 $this->assertEquals('vfs://Foo/cache/code/SomeCache/', $backend->getCacheDirectory());
196 }
197
198 /**
199 * @test
200 * @throws Exception
201 */
202 public function setThrowsExceptionIfDataIsNotAString(): void
203 {
204 $this->expectException(InvalidDataException::class);
205 $this->expectExceptionCode(1204481674);
206
207 $mockCache = $this->createMock(AbstractFrontend::class);
208
209 $backend = $this->getMockBuilder(FileBackend::class)
210 ->setMethods(['dummy'])
211 ->disableOriginalConstructor()
212 ->getMock();
213 $backend->setCacheDirectory('vfs://Foo/');
214 $backend->setCache($mockCache);
215
216 $backend->set('some identifier', ['not a string']);
217 }
218
219 /**
220 * @test
221 * @throws Exception
222 */
223 public function setReallySavesToTheSpecifiedDirectory(): void
224 {
225 $mockCache = $this->createMock(AbstractFrontend::class);
226 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
227
228 $data = 'some data' . microtime();
229 $entryIdentifier = 'BackendFileTest';
230 $pathAndFilename = 'vfs://Foo/cache/data/UnitTestCache/' . $entryIdentifier;
231
232 $backend = $this->getMockBuilder(FileBackend::class)
233 ->setMethods(['dummy'])
234 ->disableOriginalConstructor()
235 ->getMock();
236 $backend->setCacheDirectory('vfs://Foo/');
237 $backend->setCache($mockCache);
238
239 $backend->set($entryIdentifier, $data);
240
241 $this->assertFileExists($pathAndFilename);
242 $retrievedData = file_get_contents($pathAndFilename, false, null, 0, \strlen($data));
243 $this->assertEquals($data, $retrievedData);
244 }
245
246 /**
247 * @test
248 * @throws Exception
249 */
250 public function setOverwritesAnAlreadyExistingCacheEntryForTheSameIdentifier(): void
251 {
252 $mockCache = $this->createMock(AbstractFrontend::class);
253 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
254
255 $data1 = 'some data' . microtime();
256 $data2 = 'some data' . microtime();
257 $entryIdentifier = 'BackendFileRemoveBeforeSetTest';
258
259 $backend = $this->getMockBuilder(FileBackend::class)
260 ->setMethods(['dummy'])
261 ->disableOriginalConstructor()
262 ->getMock();
263 $backend->setCacheDirectory('vfs://Foo/');
264 $backend->setCache($mockCache);
265
266 $backend->set($entryIdentifier, $data1, [], 500);
267 $backend->set($entryIdentifier, $data2, [], 200);
268
269 $pathAndFilename = 'vfs://Foo/cache/data/UnitTestCache/' . $entryIdentifier;
270 $this->assertFileExists($pathAndFilename);
271 $retrievedData = file_get_contents($pathAndFilename, false, null, 0, \strlen($data2));
272 $this->assertEquals($data2, $retrievedData);
273 }
274
275 /**
276 * @test
277 * @throws Exception
278 */
279 public function setAlsoSavesSpecifiedTags(): void
280 {
281 $mockCache = $this->createMock(AbstractFrontend::class);
282 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
283
284 $data = 'some data' . microtime();
285 $entryIdentifier = 'BackendFileRemoveBeforeSetTest';
286
287 $backend = $this->getMockBuilder(FileBackend::class)
288 ->setMethods(['dummy'])
289 ->disableOriginalConstructor()
290 ->getMock();
291 $backend->setCacheDirectory('vfs://Foo/');
292 $backend->setCache($mockCache);
293
294 $backend->set($entryIdentifier, $data, ['Tag1', 'Tag2']);
295
296 $pathAndFilename = 'vfs://Foo/cache/data/UnitTestCache/' . $entryIdentifier;
297 $this->assertFileExists($pathAndFilename);
298 $retrievedData = file_get_contents(
299 $pathAndFilename,
300 false,
301 null,
302 \strlen($data) + FileBackend::EXPIRYTIME_LENGTH,
303 9
304 );
305 $this->assertEquals('Tag1 Tag2', $retrievedData);
306 }
307
308 /**
309 * @test
310 * @throws Exception
311 */
312 public function setCacheDetectsAndLoadsAFrozenCache(): void
313 {
314 $mockCache = $this->createMock(AbstractFrontend::class);
315 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
316
317 $data = 'some data' . microtime();
318 $entryIdentifier = 'BackendFileTest';
319
320 $backend = $this->getMockBuilder(FileBackend::class)
321 ->setMethods(['dummy'])
322 ->disableOriginalConstructor()
323 ->getMock();
324 $backend->setCacheDirectory('vfs://Foo/');
325 $backend->setCache($mockCache);
326
327 $backend->set($entryIdentifier, $data, ['Tag1', 'Tag2']);
328
329 $backend->freeze();
330
331 unset($backend);
332
333 $backend = $this->getMockBuilder(FileBackend::class)
334 ->setMethods(['dummy'])
335 ->disableOriginalConstructor()
336 ->getMock();
337 $backend->setCacheDirectory('vfs://Foo/');
338 $backend->setCache($mockCache);
339
340 $this->assertTrue($backend->isFrozen());
341 $this->assertEquals($data, $backend->get($entryIdentifier));
342 }
343
344 /**
345 * @test
346 * @throws Exception
347 */
348 public function getReturnsContentOfTheCorrectCacheFile(): void
349 {
350 $mockCache = $this->createMock(AbstractFrontend::class);
351 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
352
353 $backend = $this->getMockBuilder(FileBackend::class)
354 ->setMethods(['setTag'])
355 ->disableOriginalConstructor()
356 ->getMock();
357 $backend->setCacheDirectory('vfs://Foo/');
358 $backend->setCache($mockCache);
359
360 $entryIdentifier = 'BackendFileTest';
361
362 $data = 'some data' . microtime();
363 $backend->set($entryIdentifier, $data, [], 500);
364
365 $data = 'some other data' . microtime();
366 $backend->set($entryIdentifier, $data, [], 100);
367
368 $loadedData = $backend->get($entryIdentifier);
369 $this->assertEquals($data, $loadedData);
370 }
371
372 /**
373 * @test
374 * @throws Exception
375 */
376 public function getReturnsFalseForExpiredEntries(): void
377 {
378 $mockCache = $this->createMock(AbstractFrontend::class);
379 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
380
381 $backend = $this->getMockBuilder(FileBackend::class)
382 ->setMethods(['isCacheFileExpired'])
383 ->disableOriginalConstructor()
384 ->getMock();
385 $backend->expects($this->once())->method('isCacheFileExpired')->with('vfs://Foo/cache/data/UnitTestCache/ExpiredEntry')->will($this->returnValue(true));
386 $backend->setCacheDirectory('vfs://Foo/');
387 $backend->setCache($mockCache);
388
389 $this->assertFalse($backend->get('ExpiredEntry'));
390 }
391
392 /**
393 * @test
394 * @throws Exception
395 */
396 public function getDoesNotCheckIfAnEntryIsExpiredIfTheCacheIsFrozen(): void
397 {
398 $mockCache = $this->createMock(AbstractFrontend::class);
399 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
400
401 $backend = $this->getMockBuilder(FileBackend::class)
402 ->setMethods(['isCacheFileExpired'])
403 ->disableOriginalConstructor()
404 ->getMock();
405 $backend->setCacheDirectory('vfs://Foo/');
406 $backend->setCache($mockCache);
407
408 $backend->expects($this->once())->method('isCacheFileExpired');
409
410 $backend->set('foo', 'some data');
411 $backend->freeze();
412 $this->assertEquals('some data', $backend->get('foo'));
413 $this->assertFalse($backend->get('bar'));
414 }
415
416 /**
417 * @test
418 * @throws Exception
419 */
420 public function hasReturnsTrueIfAnEntryExists(): void
421 {
422 $mockCache = $this->createMock(AbstractFrontend::class);
423 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
424
425 $backend = $this->getMockBuilder(FileBackend::class)
426 ->setMethods(['dummy'])
427 ->disableOriginalConstructor()
428 ->getMock();
429 $backend->setCacheDirectory('vfs://Foo/');
430 $backend->setCache($mockCache);
431
432 $entryIdentifier = 'BackendFileTest';
433
434 $data = 'some data' . microtime();
435 $backend->set($entryIdentifier, $data);
436
437 $this->assertTrue($backend->has($entryIdentifier), 'has() did not return TRUE.');
438 $this->assertFalse($backend->has($entryIdentifier . 'Not'), 'has() did not return FALSE.');
439 }
440
441 /**
442 * @test
443 */
444 public function hasReturnsFalseForExpiredEntries(): void
445 {
446 $backend = $this->getMockBuilder(FileBackend::class)
447 ->setMethods(['isCacheFileExpired'])
448 ->disableOriginalConstructor()
449 ->getMock();
450 $backend->expects($this->exactly(2))->method('isCacheFileExpired')->will($this->onConsecutiveCalls(
451 true,
452 false
453 ));
454
455 $this->assertFalse($backend->has('foo'));
456 $this->assertTrue($backend->has('bar'));
457 }
458
459 /**
460 * @test
461 * @throws Exception
462 */
463 public function hasDoesNotCheckIfAnEntryIsExpiredIfTheCacheIsFrozen(): void
464 {
465 $mockCache = $this->createMock(AbstractFrontend::class);
466 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
467
468 $backend = $this->getMockBuilder(FileBackend::class)
469 ->setMethods(['isCacheFileExpired'])
470 ->disableOriginalConstructor()
471 ->getMock();
472 $backend->setCacheDirectory('vfs://Foo/');
473 $backend->setCache($mockCache);
474
475 $backend->expects($this->once())->method('isCacheFileExpired'); // Indirectly called by freeze() -> get()
476
477 $backend->set('foo', 'some data');
478 $backend->freeze();
479 $this->assertTrue($backend->has('foo'));
480 $this->assertFalse($backend->has('bar'));
481 }
482
483 /**
484 * @test
485 * @throws Exception
486 */
487 public function removeReallyRemovesACacheEntry(): void
488 {
489 $mockCache = $this->createMock(AbstractFrontend::class);
490 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
491
492 $data = 'some data' . microtime();
493 $entryIdentifier = 'BackendFileTest';
494 $pathAndFilename = 'vfs://Foo/cache/data/UnitTestCache/' . $entryIdentifier;
495
496 $backend = $this->getMockBuilder(FileBackend::class)
497 ->setMethods(['dummy'])
498 ->disableOriginalConstructor()
499 ->getMock();
500 $backend->setCacheDirectory('vfs://Foo/');
501 $backend->setCache($mockCache);
502
503 $backend->set($entryIdentifier, $data);
504 $this->assertFileExists($pathAndFilename);
505
506 $backend->remove($entryIdentifier);
507 $this->assertFileNotExists($pathAndFilename);
508 }
509
510 /**
511 */
512 public function invalidEntryIdentifiers(): array
513 {
514 return [
515 'trailing slash' => ['/myIdentifer'],
516 'trailing dot and slash' => ['./myIdentifer'],
517 'trailing two dots and slash' => ['../myIdentifier'],
518 'trailing with multiple dots and slashes' => ['.././../myIdentifier'],
519 'slash in middle part' => ['my/Identifier'],
520 'dot and slash in middle part' => ['my./Identifier'],
521 'two dots and slash in middle part' => ['my../Identifier'],
522 'multiple dots and slashes in middle part' => ['my.././../Identifier'],
523 'pending slash' => ['myIdentifier/'],
524 'pending dot and slash' => ['myIdentifier./'],
525 'pending dots and slash' => ['myIdentifier../'],
526 'pending multiple dots and slashes' => ['myIdentifier.././../'],
527 ];
528 }
529
530 /**
531 * @test
532 * @dataProvider invalidEntryIdentifiers
533 * @param string $identifier
534 * @throws Exception
535 * @throws InvalidDataException
536 */
537 public function setThrowsExceptionForInvalidIdentifier(string $identifier): void
538 {
539 $this->expectException(\InvalidArgumentException::class);
540 $this->expectExceptionCode(1282073032);
541
542 $mockCache = $this->createMock(AbstractFrontend::class);
543 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
544
545 $backend = $this->getMockBuilder(FileBackend::class)
546 ->setMethods(['dummy'])
547 ->setConstructorArgs(['test'])
548 ->getMock();
549 $backend->setCacheDirectory('vfs://Foo/');
550 $backend->setCache($mockCache);
551
552 $backend->set($identifier, 'cache data', []);
553 }
554
555 /**
556 * @test
557 * @dataProvider invalidEntryIdentifiers
558 * @param string $identifier
559 * @throws Exception
560 */
561 public function getThrowsExceptionForInvalidIdentifier(string $identifier): void
562 {
563 $this->expectException(\InvalidArgumentException::class);
564 $this->expectExceptionCode(1282073033);
565
566 $mockCache = $this->createMock(AbstractFrontend::class);
567 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
568
569 $backend = $this->getMockBuilder(FileBackend::class)
570 ->setMethods(['dummy'])
571 ->disableOriginalConstructor()
572 ->getMock();
573 $backend->setCacheDirectory('vfs://Foo/');
574 $backend->setCache($mockCache);
575
576 $backend->get($identifier);
577 }
578
579 /**
580 * @test
581 * @dataProvider invalidEntryIdentifiers
582 * @param string $identifier
583 */
584 public function hasThrowsExceptionForInvalidIdentifier(string $identifier): void
585 {
586 $this->expectException(\InvalidArgumentException::class);
587 $this->expectExceptionCode(1282073034);
588
589 $backend = $this->getMockBuilder(FileBackend::class)
590 ->setMethods(['dummy'])
591 ->disableOriginalConstructor()
592 ->getMock();
593
594 $backend->has($identifier);
595 }
596
597 /**
598 * @test
599 * @dataProvider invalidEntryIdentifiers
600 * @param string $identifier
601 * @throws Exception
602 */
603 public function removeThrowsExceptionForInvalidIdentifier(string $identifier): void
604 {
605 $this->expectException(\InvalidArgumentException::class);
606 $this->expectExceptionCode(1282073035);
607
608 $mockCache = $this->createMock(AbstractFrontend::class);
609 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
610
611 $backend = $this->getMockBuilder(FileBackend::class)
612 ->setMethods(['dummy'])
613 ->disableOriginalConstructor()
614 ->getMock();
615 $backend->setCacheDirectory('vfs://Foo/');
616 $backend->setCache($mockCache);
617
618 $backend->remove($identifier);
619 }
620
621 /**
622 * @test
623 * @dataProvider invalidEntryIdentifiers
624 * @param string $identifier
625 * @throws Exception
626 */
627 public function requireOnceThrowsExceptionForInvalidIdentifier(string $identifier): void
628 {
629 $this->expectException(\InvalidArgumentException::class);
630 $this->expectExceptionCode(1282073036);
631
632 $mockCache = $this->createMock(AbstractFrontend::class);
633 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
634
635 $backend = $this->getMockBuilder(FileBackend::class)
636 ->setMethods(['dummy'])
637 ->disableOriginalConstructor()
638 ->getMock();
639 $backend->setCacheDirectory('vfs://Foo/');
640 $backend->setCache($mockCache);
641
642 $backend->requireOnce($identifier);
643 }
644
645 /**
646 * @test
647 * @throws Exception
648 */
649 public function requireOnceIncludesAndReturnsResultOfIncludedPhpFile(): void
650 {
651 $mockCache = $this->createMock(AbstractFrontend::class);
652 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
653
654 $backend = $this->getMockBuilder(FileBackend::class)
655 ->setMethods(['dummy'])
656 ->disableOriginalConstructor()
657 ->getMock();
658 $backend->setCacheDirectory('vfs://Foo/');
659 $backend->setCache($mockCache);
660
661 $entryIdentifier = 'SomePhpEntry';
662
663 $data = '<?php return "foo"; ?>';
664 $backend->set($entryIdentifier, $data);
665
666 $loadedData = $backend->requireOnce($entryIdentifier);
667 $this->assertEquals('foo', $loadedData);
668 }
669
670 /**
671 * @test
672 * @throws Exception
673 */
674 public function requireOnceDoesNotCheckExpiryTimeIfBackendIsFrozen(): void
675 {
676 $mockCache = $this->createMock(AbstractFrontend::class);
677 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
678
679 $backend = $this->getMockBuilder(FileBackend::class)
680 ->setMethods(['isCacheFileExpired'])
681 ->disableOriginalConstructor()
682 ->getMock();
683 $backend->setCacheDirectory('vfs://Foo/');
684 $backend->setCache($mockCache);
685
686 $backend->expects($this->once())->method('isCacheFileExpired'); // Indirectly called by freeze() -> get()
687
688 $data = '<?php return "foo"; ?>';
689 $backend->set('FooEntry', $data);
690
691 $backend->freeze();
692
693 $loadedData = $backend->requireOnce('FooEntry');
694 $this->assertEquals('foo', $loadedData);
695 }
696
697 /**
698 * @test
699 * @throws Exception
700 */
701 public function findIdentifiersByTagFindsCacheEntriesWithSpecifiedTag(): void
702 {
703 $mockCache = $this->createMock(AbstractFrontend::class);
704 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
705
706 $backend = $this->getMockBuilder(FileBackend::class)
707 ->setMethods(['dummy'])
708 ->disableOriginalConstructor()
709 ->getMock();
710 $backend->setCacheDirectory('vfs://Foo/');
711 $backend->setCache($mockCache);
712
713 $data = 'some data' . microtime();
714 $backend->set('BackendFileTest1', $data, ['UnitTestTag%test', 'UnitTestTag%boring']);
715 $backend->set('BackendFileTest2', $data, ['UnitTestTag%test', 'UnitTestTag%special']);
716 $backend->set('BackendFileTest3', $data, ['UnitTestTag%test']);
717
718 $expectedEntry = 'BackendFileTest2';
719
720 $actualEntries = $backend->findIdentifiersByTag('UnitTestTag%special');
721 $this->assertInternalType('array', $actualEntries);
722 $this->assertEquals($expectedEntry, array_pop($actualEntries));
723 }
724
725 /**
726 * @test
727 * @throws Exception
728 */
729 public function findIdentifiersByTagDoesNotReturnExpiredEntries(): void
730 {
731 $mockCache = $this->createMock(AbstractFrontend::class);
732 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
733
734 $backend = $this->getMockBuilder(FileBackend::class)
735 ->setMethods(['dummy'])
736 ->disableOriginalConstructor()
737 ->getMock();
738 $backend->setCacheDirectory('vfs://Foo/');
739 $backend->setCache($mockCache);
740
741 $data = 'some data';
742 $backend->set('BackendFileTest1', $data, ['UnitTestTag%test', 'UnitTestTag%boring']);
743 $backend->set('BackendFileTest2', $data, ['UnitTestTag%test', 'UnitTestTag%special'], -100);
744 $backend->set('BackendFileTest3', $data, ['UnitTestTag%test']);
745
746 $this->assertSame([], $backend->findIdentifiersByTag('UnitTestTag%special'));
747 $this->assertSame(['BackendFileTest1', 'BackendFileTest3'], $backend->findIdentifiersByTag('UnitTestTag%test'));
748 }
749
750 /**
751 * @test
752 * @throws Exception
753 */
754 public function flushRemovesAllCacheEntries(): void
755 {
756 $mockCache = $this->createMock(AbstractFrontend::class);
757 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
758
759 $backend = $this->getMockBuilder(FileBackend::class)
760 ->setMethods(['dummy'])
761 ->disableOriginalConstructor()
762 ->getMock();
763 $backend->setCacheDirectory('vfs://Foo/');
764 $backend->setCache($mockCache);
765
766 $data = 'some data';
767 $backend->set('BackendFileTest1', $data);
768 $backend->set('BackendFileTest2', $data);
769
770 $this->assertFileExists('vfs://Foo/cache/data/UnitTestCache/BackendFileTest1');
771 $this->assertFileExists('vfs://Foo/cache/data/UnitTestCache/BackendFileTest2');
772
773 $backend->flush();
774
775 $this->assertFileNotExists('vfs://Foo/cache/data/UnitTestCache/BackendFileTest1');
776 $this->assertFileNotExists('vfs://Foo/cache/data/UnitTestCache/BackendFileTest2');
777 }
778
779 /**
780 * @test
781 * @throws Exception
782 */
783 public function flushCreatesCacheDirectoryAgain(): void
784 {
785 $mockCache = $this->createMock(AbstractFrontend::class);
786 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
787
788 $backend = $this->getMockBuilder(FileBackend::class)
789 ->setMethods(['dummy'])
790 ->disableOriginalConstructor()
791 ->getMock();
792 $backend->setCacheDirectory('vfs://Foo/');
793 $backend->setCache($mockCache);
794
795 $backend->flush();
796 $this->assertFileExists('vfs://Foo/cache/data/UnitTestCache/');
797 }
798
799 /**
800 * @test
801 */
802 public function flushByTagRemovesCacheEntriesWithSpecifiedTag(): void
803 {
804 $backend = $this->getMockBuilder(FileBackend::class)
805 ->setMethods(['findIdentifiersByTag', 'remove'])
806 ->disableOriginalConstructor()
807 ->getMock();
808
809 $backend->expects($this->once())->method('findIdentifiersByTag')->with('UnitTestTag%special')->will($this->returnValue([
810 'foo',
811 'bar',
812 'baz'
813 ]));
814 $backend->expects($this->at(1))->method('remove')->with('foo');
815 $backend->expects($this->at(2))->method('remove')->with('bar');
816 $backend->expects($this->at(3))->method('remove')->with('baz');
817
818 $backend->flushByTag('UnitTestTag%special');
819 }
820
821 /**
822 * @test
823 * @throws Exception
824 */
825 public function collectGarbageRemovesExpiredCacheEntries(): void
826 {
827 $mockCache = $this->createMock(AbstractFrontend::class);
828 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
829
830 $backend = $this->getMockBuilder(FileBackend::class)
831 ->setMethods(['isCacheFileExpired'])
832 ->disableOriginalConstructor()
833 ->getMock();
834 $backend->expects($this->exactly(2))->method('isCacheFileExpired')->will($this->onConsecutiveCalls(
835 true,
836 false
837 ));
838 $backend->setCacheDirectory('vfs://Foo/');
839 $backend->setCache($mockCache);
840
841 $data = 'some data';
842 $backend->set('BackendFileTest1', $data);
843 $backend->set('BackendFileTest2', $data);
844
845 $this->assertFileExists('vfs://Foo/cache/data/UnitTestCache/BackendFileTest1');
846 $this->assertFileExists('vfs://Foo/cache/data/UnitTestCache/BackendFileTest2');
847
848 $backend->collectGarbage();
849 $this->assertFileNotExists('vfs://Foo/cache/data/UnitTestCache/BackendFileTest1');
850 $this->assertFileExists('vfs://Foo/cache/data/UnitTestCache/BackendFileTest2');
851 }
852
853 /**
854 * @test
855 * @throws Exception
856 */
857 public function flushUnfreezesTheCache(): void
858 {
859 $mockCache = $this->createMock(AbstractFrontend::class);
860 $mockCache->expects($this->atLeastOnce())->method('getIdentifier')->will($this->returnValue('UnitTestCache'));
861
862 $backend = $this->getMockBuilder(FileBackend::class)
863 ->setMethods(['dummy'])
864 ->disableOriginalConstructor()
865 ->getMock();
866 $backend->setCacheDirectory('vfs://Foo/');
867 $backend->setCache($mockCache);
868
869 $backend->freeze();
870
871 $this->assertTrue($backend->isFrozen());
872 $backend->flush();
873 $this->assertFalse($backend->isFrozen());
874 }
875 }