[BUGFIX] Add missing namespace parts
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Cache / Backend / ApcBackendTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Unit\Cache\Backend;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Cache\Backend\ApcBackend;
18
19 /**
20 * Testcase for the APC cache backend.
21 *
22 * NOTE: If you want to execute these tests you need to enable apc in
23 * cli context (apc.enable_cli = 1)
24 *
25 * This file is a backport from FLOW3
26 */
27 class ApcBackendTest extends \TYPO3\Components\TestingFramework\Core\Unit\UnitTestCase
28 {
29 /**
30 * Sets up this testcase
31 *
32 * @return void
33 */
34 protected function setUp()
35 {
36 // Currently APCu identifies itself both as "apcu" and "apc" (for compatibility) although it doesn't provide the APC-opcache functionality
37 if (!extension_loaded('apc') || ini_get('apc.enabled') == 0 || ini_get('apc.enable_cli') == 0) {
38 $this->markTestSkipped('APC/APCu extension was not available, or it was disabled for CLI.');
39 }
40 if (ini_get('apc.slam_defense') == 1) {
41 $this->markTestSkipped('This testcase can only be executed with apc.slam_defense = Off');
42 }
43 }
44
45 /**
46 * @test
47 */
48 public function setThrowsExceptionIfNoFrontEndHasBeenSet()
49 {
50 $backend = new ApcBackend('Testing');
51 $data = 'Some data';
52 $identifier = $this->getUniqueId('MyIdentifier');
53 $this->expectException(\TYPO3\CMS\Core\Cache\Exception::class);
54 $this->expectExceptionCode(1232986818);
55 $backend->set($identifier, $data);
56 }
57
58 /**
59 * @test
60 */
61 public function itIsPossibleToSetAndCheckExistenceInCache()
62 {
63 $backend = $this->setUpBackend();
64 $data = 'Some data';
65 $identifier = $this->getUniqueId('MyIdentifier');
66 $backend->set($identifier, $data);
67 $inCache = $backend->has($identifier);
68 $this->assertTrue($inCache, 'APC backend failed to set and check entry');
69 }
70
71 /**
72 * @test
73 */
74 public function itIsPossibleToSetAndGetEntry()
75 {
76 $backend = $this->setUpBackend();
77 $data = 'Some data';
78 $identifier = $this->getUniqueId('MyIdentifier');
79 $backend->set($identifier, $data);
80 $fetchedData = $backend->get($identifier);
81 $this->assertEquals($data, $fetchedData, 'APC backend failed to set and retrieve data');
82 }
83
84 /**
85 * @test
86 */
87 public function itIsPossibleToRemoveEntryFromCache()
88 {
89 $backend = $this->setUpBackend();
90 $data = 'Some data';
91 $identifier = $this->getUniqueId('MyIdentifier');
92 $backend->set($identifier, $data);
93 $backend->remove($identifier);
94 $inCache = $backend->has($identifier);
95 $this->assertFalse($inCache, 'Failed to set and remove data from APC backend');
96 }
97
98 /**
99 * @test
100 */
101 public function itIsPossibleToOverwriteAnEntryInTheCache()
102 {
103 $backend = $this->setUpBackend();
104 $data = 'Some data';
105 $identifier = $this->getUniqueId('MyIdentifier');
106 $backend->set($identifier, $data);
107 $otherData = 'some other data';
108 $backend->set($identifier, $otherData);
109 $fetchedData = $backend->get($identifier);
110 $this->assertEquals($otherData, $fetchedData, 'APC backend failed to overwrite and retrieve data');
111 }
112
113 /**
114 * @test
115 */
116 public function findIdentifiersByTagFindsSetEntries()
117 {
118 $backend = $this->setUpBackend();
119 $data = 'Some data';
120 $identifier = $this->getUniqueId('MyIdentifier');
121 $backend->set($identifier, $data, ['UnitTestTag%tag1', 'UnitTestTag%tag2']);
122 $retrieved = $backend->findIdentifiersByTag('UnitTestTag%tag1');
123 $this->assertEquals($identifier, $retrieved[0], 'Could not retrieve expected entry by tag.');
124 $retrieved = $backend->findIdentifiersByTag('UnitTestTag%tag2');
125 $this->assertEquals($identifier, $retrieved[0], 'Could not retrieve expected entry by tag.');
126 }
127
128 /**
129 * @test
130 */
131 public function setRemovesTagsFromPreviousSet()
132 {
133 $backend = $this->setUpBackend();
134 $data = 'Some data';
135 $identifier = $this->getUniqueId('MyIdentifier');
136 $backend->set($identifier, $data, ['UnitTestTag%tag1', 'UnitTestTag%tagX']);
137 $backend->set($identifier, $data, ['UnitTestTag%tag3']);
138 $retrieved = $backend->findIdentifiersByTag('UnitTestTag%tagX');
139 $this->assertEquals([], $retrieved, 'Found entry which should no longer exist.');
140 }
141
142 /**
143 * @test
144 */
145 public function setCacheIsSettingIdentifierPrefixWithCacheIdentifier()
146 {
147 /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $cacheMock */
148 $cacheMock = $this->createMock(\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface::class);
149 $cacheMock->expects($this->any())->method('getIdentifier')->will($this->returnValue(
150 'testidentifier'
151 ));
152
153 /** @var $backendMock \PHPUnit_Framework_MockObject_MockObject|ApcBackend */
154 $backendMock = $this->getMockBuilder(ApcBackend::class)
155 ->setMethods(['setIdentifierPrefix', 'getCurrentUserData', 'getPathSite'])
156 ->setConstructorArgs(['testcontext'])
157 ->getMock();
158
159 $backendMock->expects($this->once())->method('getCurrentUserData')->will(
160 $this->returnValue(['name' => 'testname'])
161 );
162
163 $backendMock->expects($this->once())->method('getPathSite')->will(
164 $this->returnValue('testpath')
165 );
166
167 $expectedIdentifier = 'TYPO3_' . \TYPO3\CMS\Core\Utility\GeneralUtility::shortMD5('testpath' . 'testname' . 'testcontext' . 'testidentifier', 12);
168 $backendMock->expects($this->once())->method('setIdentifierPrefix')->with($expectedIdentifier);
169 $backendMock->setCache($cacheMock);
170 }
171
172 /**
173 * @test
174 */
175 public function hasReturnsFalseIfTheEntryDoesNotExist()
176 {
177 $backend = $this->setUpBackend();
178 $identifier = $this->getUniqueId('NonExistingIdentifier');
179 $inCache = $backend->has($identifier);
180 $this->assertFalse($inCache, '"has" did not return FALSE when checking on non existing identifier');
181 }
182
183 /**
184 * @test
185 */
186 public function removeReturnsFalseIfTheEntryDoesntExist()
187 {
188 $backend = $this->setUpBackend();
189 $identifier = $this->getUniqueId('NonExistingIdentifier');
190 $inCache = $backend->remove($identifier);
191 $this->assertFalse($inCache, '"remove" did not return FALSE when checking on non existing identifier');
192 }
193
194 /**
195 * @test
196 */
197 public function flushByTagRemovesCacheEntriesWithSpecifiedTag()
198 {
199 $backend = $this->setUpBackend();
200 $data = 'some data' . microtime();
201 $backend->set('BackendAPCTest1', $data, ['UnitTestTag%test', 'UnitTestTag%boring']);
202 $backend->set('BackendAPCTest2', $data, ['UnitTestTag%test', 'UnitTestTag%special']);
203 $backend->set('BackendAPCTest3', $data, ['UnitTestTag%test']);
204 $backend->flushByTag('UnitTestTag%special');
205 $this->assertTrue($backend->has('BackendAPCTest1'), 'BackendAPCTest1');
206 $this->assertFalse($backend->has('BackendAPCTest2'), 'BackendAPCTest2');
207 $this->assertTrue($backend->has('BackendAPCTest3'), 'BackendAPCTest3');
208 }
209
210 /**
211 * @test
212 */
213 public function flushByTagsRemovesCacheEntriesWithSpecifiedTags()
214 {
215 $backend = $this->setUpBackend();
216 $data = 'some data' . microtime();
217 $backend->set('BackendAPCTest1', $data, ['UnitTestTag%test', 'UnitTestTag%boring']);
218 $backend->set('BackendAPCTest2', $data, ['UnitTestTag%test', 'UnitTestTag%special']);
219 $backend->set('BackendAPCTest3', $data, ['UnitTestTag%test']);
220 $backend->flushByTags(['UnitTestTag%special', 'UnitTestTag%boring']);
221 $this->assertFalse($backend->has('BackendAPCTest1'), 'BackendAPCTest1');
222 $this->assertFalse($backend->has('BackendAPCTest2'), 'BackendAPCTest2');
223 $this->assertTrue($backend->has('BackendAPCTest3'), 'BackendAPCTest3');
224 }
225
226 /**
227 * @test
228 */
229 public function flushRemovesAllCacheEntries()
230 {
231 $backend = $this->setUpBackend();
232 $data = 'some data' . microtime();
233 $backend->set('BackendAPCTest1', $data);
234 $backend->set('BackendAPCTest2', $data);
235 $backend->set('BackendAPCTest3', $data);
236 $backend->flush();
237 $this->assertFalse($backend->has('BackendAPCTest1'), 'BackendAPCTest1');
238 $this->assertFalse($backend->has('BackendAPCTest2'), 'BackendAPCTest2');
239 $this->assertFalse($backend->has('BackendAPCTest3'), 'BackendAPCTest3');
240 }
241
242 /**
243 * @test
244 */
245 public function flushRemovesOnlyOwnEntries()
246 {
247 /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $thisCache */
248 $thisCache = $this->createMock(\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface::class);
249 $thisCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('thisCache'));
250 $thisBackend = new ApcBackend('Testing');
251 $thisBackend->setCache($thisCache);
252
253 /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $thatCache */
254 $thatCache = $this->createMock(\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface::class);
255 $thatCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('thatCache'));
256 $thatBackend = new ApcBackend('Testing');
257 $thatBackend->setCache($thatCache);
258 $thisBackend->set('thisEntry', 'Hello');
259 $thatBackend->set('thatEntry', 'World!');
260 $thatBackend->flush();
261 $this->assertEquals('Hello', $thisBackend->get('thisEntry'));
262 $this->assertFalse($thatBackend->has('thatEntry'));
263 }
264
265 /**
266 * Check if we can store ~5 MB of data
267 *
268 * @test
269 */
270 public function largeDataIsStored()
271 {
272 $backend = $this->setUpBackend();
273 $data = str_repeat('abcde', 1024 * 1024);
274 $identifier = $this->getUniqueId('tooLargeData');
275 $backend->set($identifier, $data);
276 $this->assertTrue($backend->has($identifier));
277 $this->assertEquals($backend->get($identifier), $data);
278 }
279
280 /**
281 * @test
282 */
283 public function setTagsOnlyOnceToIdentifier()
284 {
285 $identifier = $this->getUniqueId('MyIdentifier');
286 $tags = ['UnitTestTag%test', 'UnitTestTag%boring'];
287
288 $backend = $this->setUpBackend(true);
289 $backend->_call('addIdentifierToTags', $identifier, $tags);
290 $this->assertSame(
291 $tags,
292 $backend->_call('findTagsByIdentifier', $identifier)
293 );
294
295 $backend->_call('addIdentifierToTags', $identifier, $tags);
296 $this->assertSame(
297 $tags,
298 $backend->_call('findTagsByIdentifier', $identifier)
299 );
300 }
301
302 /**
303 * Sets up the APC backend used for testing
304 *
305 * @param bool $accessible TRUE if backend should be encapsulated in accessible proxy otherwise FALSE.
306 * @return \TYPO3\Components\TestingFramework\Core\AccessibleObjectInterface|ApcBackend
307 */
308 protected function setUpBackend($accessible = false)
309 {
310 /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $cache */
311 $cache = $this->createMock(\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface::class);
312 if ($accessible) {
313 $accessibleClassName = $this->buildAccessibleProxy(ApcBackend::class);
314 $backend = new $accessibleClassName('Testing');
315 } else {
316 $backend = new ApcBackend('Testing');
317 }
318 $backend->setCache($cache);
319 return $backend;
320 }
321 }