[BUGFIX] Ensure manually updated slug is saved correctly
[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\TestingFramework\Core\AccessibleObjectInterface;
21 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
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 UnitTestCase
30 {
31 protected $resetSingletonInstances = true;
32
33 /**
34 * Set up
35 */
36 protected function setUp(): void
37 {
38 // APCu module is called apcu, but options are prefixed with apc
39 if (!extension_loaded('apcu') || !(bool)ini_get('apc.enabled') || !(bool)ini_get('apc.enable_cli')) {
40 $this->markTestSkipped('APCu extension was not available, or it was disabled for CLI.');
41 }
42 if ((bool)ini_get('apc.slam_defense')) {
43 $this->markTestSkipped('This testcase can only be executed with apc.slam_defense = 0');
44 }
45 }
46
47 /**
48 * @test
49 */
50 public function setThrowsExceptionIfNoFrontEndHasBeenSet()
51 {
52 $backend = new ApcuBackend('Testing');
53 $data = 'Some data';
54 $identifier = $this->getUniqueId('MyIdentifier');
55 $this->expectException(Exception::class);
56 $this->expectExceptionCode(1232986118);
57 $backend->set($identifier, $data);
58 }
59
60 /**
61 * @test
62 */
63 public function itIsPossibleToSetAndCheckExistenceInCache()
64 {
65 $backend = $this->setUpBackend();
66 $data = 'Some data';
67 $identifier = $this->getUniqueId('MyIdentifier');
68 $backend->set($identifier, $data);
69 $this->assertTrue($backend->has($identifier));
70 }
71
72 /**
73 * @test
74 */
75 public function itIsPossibleToSetAndGetEntry()
76 {
77 $backend = $this->setUpBackend();
78 $data = 'Some data';
79 $identifier = $this->getUniqueId('MyIdentifier');
80 $backend->set($identifier, $data);
81 $fetchedData = $backend->get($identifier);
82 $this->assertEquals($data, $fetchedData);
83 }
84
85 /**
86 * @test
87 */
88 public function itIsPossibleToRemoveEntryFromCache()
89 {
90 $backend = $this->setUpBackend();
91 $data = 'Some data';
92 $identifier = $this->getUniqueId('MyIdentifier');
93 $backend->set($identifier, $data);
94 $backend->remove($identifier);
95 $this->assertFalse($backend->has($identifier));
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);
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]);
124 $retrieved = $backend->findIdentifiersByTag('UnitTestTag%tag2');
125 $this->assertEquals($identifier, $retrieved[0]);
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);
140 }
141
142 /**
143 * @test
144 */
145 public function hasReturnsFalseIfTheEntryDoesNotExist()
146 {
147 $backend = $this->setUpBackend();
148 $identifier = $this->getUniqueId('NonExistingIdentifier');
149 $this->assertFalse($backend->has($identifier));
150 }
151
152 /**
153 * @test
154 */
155 public function removeReturnsFalseIfTheEntryDoesntExist()
156 {
157 $backend = $this->setUpBackend();
158 $identifier = $this->getUniqueId('NonExistingIdentifier');
159 $this->assertFalse($backend->remove($identifier));
160 }
161
162 /**
163 * @test
164 */
165 public function flushByTagRemovesCacheEntriesWithSpecifiedTag()
166 {
167 $backend = $this->setUpBackend();
168 $data = 'some data' . microtime();
169 $backend->set('BackendAPCUTest1', $data, ['UnitTestTag%test', 'UnitTestTag%boring']);
170 $backend->set('BackendAPCUTest2', $data, ['UnitTestTag%test', 'UnitTestTag%special']);
171 $backend->set('BackendAPCUTest3', $data, ['UnitTestTag%test']);
172 $backend->flushByTag('UnitTestTag%special');
173 $this->assertTrue($backend->has('BackendAPCUTest1'));
174 $this->assertFalse($backend->has('BackendAPCUTest2'));
175 $this->assertTrue($backend->has('BackendAPCUTest3'));
176 }
177
178 /**
179 * @test
180 */
181 public function flushByTagsRemovesCacheEntriesWithSpecifiedTags()
182 {
183 $backend = $this->setUpBackend();
184 $data = 'some data' . microtime();
185 $backend->set('BackendAPCUTest1', $data, ['UnitTestTag%test', 'UnitTestTag%boring']);
186 $backend->set('BackendAPCUTest2', $data, ['UnitTestTag%test', 'UnitTestTag%special']);
187 $backend->set('BackendAPCUTest3', $data, ['UnitTestTag%test']);
188 $backend->flushByTags(['UnitTestTag%special', 'UnitTestTag%boring']);
189 $this->assertFalse($backend->has('BackendAPCUTest1'), 'BackendAPCTest1');
190 $this->assertFalse($backend->has('BackendAPCUTest2'), 'BackendAPCTest2');
191 $this->assertTrue($backend->has('BackendAPCUTest3'), 'BackendAPCTest3');
192 }
193
194 /**
195 * @test
196 */
197 public function flushRemovesAllCacheEntries()
198 {
199 $backend = $this->setUpBackend();
200 $data = 'some data' . microtime();
201 $backend->set('BackendAPCUTest1', $data);
202 $backend->set('BackendAPCUTest2', $data);
203 $backend->set('BackendAPCUTest3', $data);
204 $backend->flush();
205 $this->assertFalse($backend->has('BackendAPCUTest1'));
206 $this->assertFalse($backend->has('BackendAPCUTest2'));
207 $this->assertFalse($backend->has('BackendAPCUTest3'));
208 }
209
210 /**
211 * @test
212 */
213 public function flushRemovesOnlyOwnEntries()
214 {
215 /** @var \PHPUnit_Framework_MockObject_MockObject|FrontendInterface $thisCache */
216 $thisCache = $this->createMock(FrontendInterface::class);
217 $thisCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('thisCache'));
218 $thisBackend = new ApcuBackend('Testing');
219 $thisBackend->setCache($thisCache);
220
221 /** @var \PHPUnit_Framework_MockObject_MockObject|FrontendInterface $thatCache */
222 $thatCache = $this->createMock(FrontendInterface::class);
223 $thatCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('thatCache'));
224 $thatBackend = new ApcuBackend('Testing');
225 $thatBackend->setCache($thatCache);
226 $thisBackend->set('thisEntry', 'Hello');
227 $thatBackend->set('thatEntry', 'World!');
228 $thatBackend->flush();
229 $this->assertEquals('Hello', $thisBackend->get('thisEntry'));
230 $this->assertFalse($thatBackend->has('thatEntry'));
231 }
232
233 /**
234 * Check if we can store ~5 MB of data
235 *
236 * @test
237 */
238 public function largeDataIsStored()
239 {
240 $backend = $this->setUpBackend();
241 $data = str_repeat('abcde', 1024 * 1024);
242 $identifier = $this->getUniqueId('tooLargeData');
243 $backend->set($identifier, $data);
244 $this->assertTrue($backend->has($identifier));
245 $this->assertEquals($backend->get($identifier), $data);
246 }
247
248 /**
249 * @test
250 */
251 public function setTagsOnlyOnceToIdentifier()
252 {
253 $identifier = $this->getUniqueId('MyIdentifier');
254 $tags = ['UnitTestTag%test', 'UnitTestTag%boring'];
255
256 $backend = $this->setUpBackend(true);
257 $backend->_call('addIdentifierToTags', $identifier, $tags);
258 $this->assertSame(
259 $tags,
260 $backend->_call('findTagsByIdentifier', $identifier)
261 );
262
263 $backend->_call('addIdentifierToTags', $identifier, $tags);
264 $this->assertSame(
265 $tags,
266 $backend->_call('findTagsByIdentifier', $identifier)
267 );
268 }
269
270 /**
271 * Sets up the APCu backend used for testing
272 *
273 * @param bool $accessible TRUE if backend should be encapsulated in accessible proxy otherwise FALSE.
274 * @return AccessibleObjectInterface|ApcuBackend
275 */
276 protected function setUpBackend($accessible = false)
277 {
278 /** @var \PHPUnit_Framework_MockObject_MockObject|FrontendInterface $cache */
279 $cache = $this->createMock(FrontendInterface::class);
280 if ($accessible) {
281 $accessibleClassName = $this->buildAccessibleProxy(ApcuBackend::class);
282 $backend = new $accessibleClassName('Testing');
283 } else {
284 $backend = new ApcuBackend('Testing');
285 }
286 $backend->setCache($cache);
287 return $backend;
288 }
289 }