bf9b55b2a5bd749d540bbd73fb4125193bf147c9
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Cache / Backend / ApcuBackendTest.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\ApcuBackend;
18 use TYPO3\CMS\Core\Cache\Exception;
19 use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21 use TYPO3\TestingFramework\Core\AccessibleObjectInterface;
22
23 /**
24 * Test case for the APCu cache backend.
25 *
26 * NOTE: If you want to execute these tests you need to enable apc in
27 * cli context (apc.enable_cli = 1) and disable slam defense (apc.slam_defense = 0)
28 */
29 class ApcuBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
30 {
31 /**
32 * Set up
33 */
34 protected function setUp()
35 {
36 // APCu module is called apcu, but options are prefixed with apc
37 if (!extension_loaded('apcu') || !(bool)ini_get('apc.enabled') || !(bool)ini_get('apc.enable_cli')) {
38 $this->markTestSkipped('APCu extension was not available, or it was disabled for CLI.');
39 }
40 if ((bool)ini_get('apc.slam_defense')) {
41 $this->markTestSkipped('This testcase can only be executed with apc.slam_defense = 0');
42 }
43 }
44
45 /**
46 * @test
47 */
48 public function setThrowsExceptionIfNoFrontEndHasBeenSet()
49 {
50 $backend = new ApcuBackend('Testing');
51 $data = 'Some data';
52 $identifier = $this->getUniqueId('MyIdentifier');
53 $this->expectException(Exception::class);
54 $this->expectExceptionCode(1232986118);
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 $this->assertTrue($backend->has($identifier));
68 }
69
70 /**
71 * @test
72 */
73 public function itIsPossibleToSetAndGetEntry()
74 {
75 $backend = $this->setUpBackend();
76 $data = 'Some data';
77 $identifier = $this->getUniqueId('MyIdentifier');
78 $backend->set($identifier, $data);
79 $fetchedData = $backend->get($identifier);
80 $this->assertEquals($data, $fetchedData);
81 }
82
83 /**
84 * @test
85 */
86 public function itIsPossibleToRemoveEntryFromCache()
87 {
88 $backend = $this->setUpBackend();
89 $data = 'Some data';
90 $identifier = $this->getUniqueId('MyIdentifier');
91 $backend->set($identifier, $data);
92 $backend->remove($identifier);
93 $this->assertFalse($backend->has($identifier));
94 }
95
96 /**
97 * @test
98 */
99 public function itIsPossibleToOverwriteAnEntryInTheCache()
100 {
101 $backend = $this->setUpBackend();
102 $data = 'Some data';
103 $identifier = $this->getUniqueId('MyIdentifier');
104 $backend->set($identifier, $data);
105 $otherData = 'some other data';
106 $backend->set($identifier, $otherData);
107 $fetchedData = $backend->get($identifier);
108 $this->assertEquals($otherData, $fetchedData);
109 }
110
111 /**
112 * @test
113 */
114 public function findIdentifiersByTagFindsSetEntries()
115 {
116 $backend = $this->setUpBackend();
117 $data = 'Some data';
118 $identifier = $this->getUniqueId('MyIdentifier');
119 $backend->set($identifier, $data, ['UnitTestTag%tag1', 'UnitTestTag%tag2']);
120 $retrieved = $backend->findIdentifiersByTag('UnitTestTag%tag1');
121 $this->assertEquals($identifier, $retrieved[0]);
122 $retrieved = $backend->findIdentifiersByTag('UnitTestTag%tag2');
123 $this->assertEquals($identifier, $retrieved[0]);
124 }
125
126 /**
127 * @test
128 */
129 public function setRemovesTagsFromPreviousSet()
130 {
131 $backend = $this->setUpBackend();
132 $data = 'Some data';
133 $identifier = $this->getUniqueId('MyIdentifier');
134 $backend->set($identifier, $data, ['UnitTestTag%tag1', 'UnitTestTag%tagX']);
135 $backend->set($identifier, $data, ['UnitTestTag%tag3']);
136 $retrieved = $backend->findIdentifiersByTag('UnitTestTag%tagX');
137 $this->assertEquals([], $retrieved);
138 }
139
140 /**
141 * @test
142 */
143 public function setCacheIsSettingIdentifierPrefixWithCacheIdentifier()
144 {
145 /** @var \PHPUnit_Framework_MockObject_MockObject|FrontendInterface $cacheMock */
146 $cacheMock = $this->createMock(FrontendInterface::class);
147 $cacheMock->expects($this->any())->method('getIdentifier')->will($this->returnValue(
148 'testidentifier'
149 ));
150
151 /** @var $backendMock \PHPUnit_Framework_MockObject_MockObject|ApcuBackend */
152 $backendMock = $this->getMockBuilder(ApcuBackend::class)
153 ->setMethods(['setIdentifierPrefix', 'getCurrentUserData', 'getPathSite'])
154 ->setConstructorArgs(['testcontext'])
155 ->getMock();
156
157 $backendMock->expects($this->once())->method('getCurrentUserData')->will(
158 $this->returnValue(['name' => 'testname'])
159 );
160
161 $backendMock->expects($this->once())->method('getPathSite')->will(
162 $this->returnValue('testpath')
163 );
164
165 $expectedIdentifier = 'TYPO3_' . GeneralUtility::shortMD5('testpath' . 'testname' . 'testcontext' . 'testidentifier', 12);
166 $backendMock->expects($this->once())->method('setIdentifierPrefix')->with($expectedIdentifier);
167 $backendMock->setCache($cacheMock);
168 }
169
170 /**
171 * @test
172 */
173 public function hasReturnsFalseIfTheEntryDoesNotExist()
174 {
175 $backend = $this->setUpBackend();
176 $identifier = $this->getUniqueId('NonExistingIdentifier');
177 $this->assertFalse($backend->has($identifier));
178 }
179
180 /**
181 * @test
182 */
183 public function removeReturnsFalseIfTheEntryDoesntExist()
184 {
185 $backend = $this->setUpBackend();
186 $identifier = $this->getUniqueId('NonExistingIdentifier');
187 $this->assertFalse($backend->remove($identifier));
188 }
189
190 /**
191 * @test
192 */
193 public function flushByTagRemovesCacheEntriesWithSpecifiedTag()
194 {
195 $backend = $this->setUpBackend();
196 $data = 'some data' . microtime();
197 $backend->set('BackendAPCUTest1', $data, ['UnitTestTag%test', 'UnitTestTag%boring']);
198 $backend->set('BackendAPCUTest2', $data, ['UnitTestTag%test', 'UnitTestTag%special']);
199 $backend->set('BackendAPCUTest3', $data, ['UnitTestTag%test']);
200 $backend->flushByTag('UnitTestTag%special');
201 $this->assertTrue($backend->has('BackendAPCUTest1'));
202 $this->assertFalse($backend->has('BackendAPCUTest2'));
203 $this->assertTrue($backend->has('BackendAPCUTest3'));
204 }
205
206 /**
207 * @test
208 */
209 public function flushByTagsRemovesCacheEntriesWithSpecifiedTags()
210 {
211 $backend = $this->setUpBackend();
212 $data = 'some data' . microtime();
213 $backend->set('BackendAPCUTest1', $data, ['UnitTestTag%test', 'UnitTestTag%boring']);
214 $backend->set('BackendAPCUTest2', $data, ['UnitTestTag%test', 'UnitTestTag%special']);
215 $backend->set('BackendAPCUTest3', $data, ['UnitTestTag%test']);
216 $backend->flushByTags(['UnitTestTag%special', 'UnitTestTag%boring']);
217 $this->assertFalse($backend->has('BackendAPCUTest1'), 'BackendAPCTest1');
218 $this->assertFalse($backend->has('BackendAPCUTest2'), 'BackendAPCTest2');
219 $this->assertTrue($backend->has('BackendAPCUTest3'), 'BackendAPCTest3');
220 }
221
222 /**
223 * @test
224 */
225 public function flushRemovesAllCacheEntries()
226 {
227 $backend = $this->setUpBackend();
228 $data = 'some data' . microtime();
229 $backend->set('BackendAPCUTest1', $data);
230 $backend->set('BackendAPCUTest2', $data);
231 $backend->set('BackendAPCUTest3', $data);
232 $backend->flush();
233 $this->assertFalse($backend->has('BackendAPCUTest1'));
234 $this->assertFalse($backend->has('BackendAPCUTest2'));
235 $this->assertFalse($backend->has('BackendAPCUTest3'));
236 }
237
238 /**
239 * @test
240 */
241 public function flushRemovesOnlyOwnEntries()
242 {
243 /** @var \PHPUnit_Framework_MockObject_MockObject|FrontendInterface $thisCache */
244 $thisCache = $this->createMock(FrontendInterface::class);
245 $thisCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('thisCache'));
246 $thisBackend = new ApcuBackend('Testing');
247 $thisBackend->setCache($thisCache);
248
249 /** @var \PHPUnit_Framework_MockObject_MockObject|FrontendInterface $thatCache */
250 $thatCache = $this->createMock(FrontendInterface::class);
251 $thatCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('thatCache'));
252 $thatBackend = new ApcuBackend('Testing');
253 $thatBackend->setCache($thatCache);
254 $thisBackend->set('thisEntry', 'Hello');
255 $thatBackend->set('thatEntry', 'World!');
256 $thatBackend->flush();
257 $this->assertEquals('Hello', $thisBackend->get('thisEntry'));
258 $this->assertFalse($thatBackend->has('thatEntry'));
259 }
260
261 /**
262 * Check if we can store ~5 MB of data
263 *
264 * @test
265 */
266 public function largeDataIsStored()
267 {
268 $backend = $this->setUpBackend();
269 $data = str_repeat('abcde', 1024 * 1024);
270 $identifier = $this->getUniqueId('tooLargeData');
271 $backend->set($identifier, $data);
272 $this->assertTrue($backend->has($identifier));
273 $this->assertEquals($backend->get($identifier), $data);
274 }
275
276 /**
277 * @test
278 */
279 public function setTagsOnlyOnceToIdentifier()
280 {
281 $identifier = $this->getUniqueId('MyIdentifier');
282 $tags = ['UnitTestTag%test', 'UnitTestTag%boring'];
283
284 $backend = $this->setUpBackend(true);
285 $backend->_call('addIdentifierToTags', $identifier, $tags);
286 $this->assertSame(
287 $tags,
288 $backend->_call('findTagsByIdentifier', $identifier)
289 );
290
291 $backend->_call('addIdentifierToTags', $identifier, $tags);
292 $this->assertSame(
293 $tags,
294 $backend->_call('findTagsByIdentifier', $identifier)
295 );
296 }
297
298 /**
299 * Sets up the APCu backend used for testing
300 *
301 * @param bool $accessible TRUE if backend should be encapsulated in accessible proxy otherwise FALSE.
302 * @return AccessibleObjectInterface|ApcuBackend
303 */
304 protected function setUpBackend($accessible = false)
305 {
306 /** @var \PHPUnit_Framework_MockObject_MockObject|FrontendInterface $cache */
307 $cache = $this->createMock(FrontendInterface::class);
308 if ($accessible) {
309 $accessibleClassName = $this->buildAccessibleProxy(ApcuBackend::class);
310 $backend = new $accessibleClassName('Testing');
311 } else {
312 $backend = new ApcuBackend('Testing');
313 }
314 $backend->setCache($cache);
315 return $backend;
316 }
317 }