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