[TASK] Functional tests without phpunit process isolation
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Functional / Cache / Backend / MemcachedBackendTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Functional\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\MemcachedBackend;
18 use TYPO3\CMS\Core\Cache\Exception;
19 use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
20 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
21
22 /**
23 * Test case
24 */
25 class MemcachedBackendTest extends FunctionalTestCase
26 {
27 /**
28 * Sets up this test case
29 */
30 protected function setUp()
31 {
32 // Note this functional does NOT call parent::setUp() since it does
33 // not need a full blown instance and database
34 if (!extension_loaded('memcache') && !extension_loaded('memcached')) {
35 $this->markTestSkipped('Neither "memcache" nor "memcached" extension was available');
36 }
37 if (!getenv('typo3TestingMemcachedHost')) {
38 $this->markTestSkipped('environment variable "typo3TestingMemcachedHost" must be set to run this test');
39 }
40 // Note we assume that if that typo3TestingMemcachedHost env is set, we can use that for testing,
41 // there is no test to see if the daemon is actually up and running. Tests will fail if env
42 // is set but daemon is down.
43 }
44
45 /**
46 * Initialize MemcacheBackend ($subject)
47 */
48 protected function initializeSubject(): MemcachedBackend
49 {
50 // We know this env is set, otherwise setUp() would skip the tests
51 $memcachedHost = getenv('typo3TestingMemcachedHost');
52 // If typo3TestingMemcachedPort env is set, use it, otherwise fall back to standard port
53 $env = getenv('typo3TestingMemcachedPort');
54 $memcachedPort = is_string($env) ? (int)$env : 11211;
55
56 $subject = new MemcachedBackend('Testing', [ 'servers' => [$memcachedHost . ':' . $memcachedPort] ]);
57 $subject->initializeObject();
58 return $subject;
59 }
60
61 /**
62 * @test
63 */
64 public function setThrowsExceptionIfNoFrontEndHasBeenSet()
65 {
66 $subject = $this->initializeSubject();
67
68 $this->expectException(Exception::class);
69 $this->expectExceptionCode(1207149215);
70
71 $subject->set($this->getUniqueId('MyIdentifier'), 'some data');
72 }
73
74 /**
75 * @test
76 */
77 public function initializeObjectThrowsExceptionIfNoMemcacheServerIsConfigured()
78 {
79 $subject = new MemcachedBackend('Testing');
80 $this->expectException(Exception::class);
81 $this->expectExceptionCode(1213115903);
82 $subject->initializeObject();
83 }
84
85 /**
86 * @test
87 */
88 public function itIsPossibleToSetAndCheckExistenceInCache()
89 {
90 $frontendProphecy = $this->prophesize(FrontendInterface::class);
91 $frontendProphecy->getIdentifier()->willReturn('cache_pages');
92
93 $subject = $this->initializeSubject();
94 $subject->setCache($frontendProphecy->reveal());
95
96 $identifier = $this->getUniqueId('MyIdentifier');
97 $subject->set($identifier, 'Some data');
98 $this->assertTrue($subject->has($identifier));
99 }
100
101 /**
102 * @test
103 */
104 public function itIsPossibleToSetAndGetEntry()
105 {
106 $frontendProphecy = $this->prophesize(FrontendInterface::class);
107 $frontendProphecy->getIdentifier()->willReturn('cache_pages');
108
109 $subject = $this->initializeSubject();
110 $subject->setCache($frontendProphecy->reveal());
111
112 $data = 'Some data';
113 $identifier = $this->getUniqueId('MyIdentifier');
114 $subject->set($identifier, $data);
115 $this->assertEquals($data, $subject->get($identifier));
116 }
117
118 /**
119 * @test
120 */
121 public function getReturnsPreviouslySetDataWithVariousTypes()
122 {
123 $frontendProphecy = $this->prophesize(FrontendInterface::class);
124 $frontendProphecy->getIdentifier()->willReturn('cache_pages');
125
126 $subject = $this->initializeSubject();
127 $subject->setCache($frontendProphecy->reveal());
128
129 $data = [
130 'string' => 'Serialize a string',
131 'integer' => 0,
132 'anotherIntegerValue' => 123456,
133 'float' => 12.34,
134 'bool' => true,
135 'array' => [
136 0 => 'test',
137 1 => 'another test',
138 ],
139 ];
140
141 $subject->set('myIdentifier', $data);
142 $this->assertSame($data, $subject->get('myIdentifier'));
143 }
144
145 /**
146 * Check if we can store ~5 MB of data.
147 *
148 * @test
149 */
150 public function largeDataIsStored()
151 {
152 $frontendProphecy = $this->prophesize(FrontendInterface::class);
153 $frontendProphecy->getIdentifier()->willReturn('cache_pages');
154
155 $subject = $this->initializeSubject();
156 $subject->setCache($frontendProphecy->reveal());
157
158 $data = str_repeat('abcde', 1024 * 1024);
159 $subject->set('tooLargeData', $data);
160 $this->assertTrue($subject->has('tooLargeData'));
161 $this->assertEquals($subject->get('tooLargeData'), $data);
162 }
163
164 /**
165 * @test
166 */
167 public function itIsPossibleToRemoveEntryFromCache()
168 {
169 $frontendProphecy = $this->prophesize(FrontendInterface::class);
170 $frontendProphecy->getIdentifier()->willReturn('cache_pages');
171
172 $subject = $this->initializeSubject();
173 $subject->setCache($frontendProphecy->reveal());
174
175 $data = 'Some data';
176 $identifier = $this->getUniqueId('MyIdentifier');
177 $subject->set($identifier, $data);
178 $subject->remove($identifier);
179 $this->assertFalse($subject->has($identifier));
180 }
181
182 /**
183 * @test
184 */
185 public function itIsPossibleToOverwriteAnEntryInTheCache()
186 {
187 $frontendProphecy = $this->prophesize(FrontendInterface::class);
188 $frontendProphecy->getIdentifier()->willReturn('cache_pages');
189
190 $subject = $this->initializeSubject();
191 $subject->setCache($frontendProphecy->reveal());
192
193 $data = 'Some data';
194 $identifier = $this->getUniqueId('MyIdentifier');
195 $subject->set($identifier, $data);
196 $otherData = 'some other data';
197 $subject->set($identifier, $otherData);
198 $this->assertEquals($otherData, $subject->get($identifier));
199 }
200
201 /**
202 * @test
203 */
204 public function findIdentifiersByTagFindsCacheEntriesWithSpecifiedTag()
205 {
206 $frontendProphecy = $this->prophesize(FrontendInterface::class);
207 $frontendProphecy->getIdentifier()->willReturn('cache_pages');
208
209 $subject = $this->initializeSubject();
210 $subject->setCache($frontendProphecy->reveal());
211
212 $data = 'Some data';
213 $identifier = $this->getUniqueId('MyIdentifier');
214 $subject->set($identifier, $data, ['UnitTestTag%tag1', 'UnitTestTag%tag2']);
215 $retrieved = $subject->findIdentifiersByTag('UnitTestTag%tag1');
216 $this->assertEquals($identifier, $retrieved[0]);
217 $retrieved = $subject->findIdentifiersByTag('UnitTestTag%tag2');
218 $this->assertEquals($identifier, $retrieved[0]);
219 }
220
221 /**
222 * @test
223 */
224 public function setRemovesTagsFromPreviousSet()
225 {
226 $frontendProphecy = $this->prophesize(FrontendInterface::class);
227 $frontendProphecy->getIdentifier()->willReturn('cache_pages');
228
229 $subject = $this->initializeSubject();
230 $subject->setCache($frontendProphecy->reveal());
231
232 $data = 'Some data';
233 $identifier = $this->getUniqueId('MyIdentifier');
234 $subject->set($identifier, $data, ['UnitTestTag%tag1', 'UnitTestTag%tag2']);
235 $subject->set($identifier, $data, ['UnitTestTag%tag3']);
236 $this->assertEquals([], $subject->findIdentifiersByTag('UnitTestTag%tagX'));
237 }
238
239 /**
240 * @test
241 */
242 public function hasReturnsFalseIfTheEntryDoesntExist()
243 {
244 $frontendProphecy = $this->prophesize(FrontendInterface::class);
245 $frontendProphecy->getIdentifier()->willReturn('cache_pages');
246
247 $subject = $this->initializeSubject();
248 $subject->setCache($frontendProphecy->reveal());
249
250 $identifier = $this->getUniqueId('NonExistingIdentifier');
251 $this->assertFalse($subject->has($identifier));
252 }
253
254 /**
255 * @test
256 */
257 public function removeReturnsFalseIfTheEntryDoesntExist()
258 {
259 $frontendProphecy = $this->prophesize(FrontendInterface::class);
260 $frontendProphecy->getIdentifier()->willReturn('cache_pages');
261
262 $subject = $this->initializeSubject();
263 $subject->setCache($frontendProphecy->reveal());
264
265 $identifier = $this->getUniqueId('NonExistingIdentifier');
266 $this->assertFalse($subject->remove($identifier));
267 }
268
269 /**
270 * @test
271 */
272 public function flushByTagRemovesCacheEntriesWithSpecifiedTag()
273 {
274 $frontendProphecy = $this->prophesize(FrontendInterface::class);
275 $frontendProphecy->getIdentifier()->willReturn('cache_pages');
276
277 $subject = $this->initializeSubject();
278 $subject->setCache($frontendProphecy->reveal());
279
280 $data = 'some data' . microtime();
281 $subject->set('BackendMemcacheTest1', $data, ['UnitTestTag%test', 'UnitTestTag%boring']);
282 $subject->set('BackendMemcacheTest2', $data, ['UnitTestTag%test', 'UnitTestTag%special']);
283 $subject->set('BackendMemcacheTest3', $data, ['UnitTestTag%test']);
284 $subject->flushByTag('UnitTestTag%special');
285 $this->assertTrue($subject->has('BackendMemcacheTest1'));
286 $this->assertFalse($subject->has('BackendMemcacheTest2'));
287 $this->assertTrue($subject->has('BackendMemcacheTest3'));
288 }
289
290 /**
291 * @test
292 */
293 public function flushByTagsRemovesCacheEntriesWithSpecifiedTags()
294 {
295 $frontendProphecy = $this->prophesize(FrontendInterface::class);
296 $frontendProphecy->getIdentifier()->willReturn('cache_pages');
297
298 $subject = $this->initializeSubject();
299 $subject->setCache($frontendProphecy->reveal());
300
301 $data = 'some data' . microtime();
302 $subject->set('BackendMemcacheTest1', $data, ['UnitTestTag%test', 'UnitTestTag%boring']);
303 $subject->set('BackendMemcacheTest2', $data, ['UnitTestTag%test', 'UnitTestTag%special']);
304 $subject->set('BackendMemcacheTest3', $data, ['UnitTestTag%test']);
305 $subject->flushByTags(['UnitTestTag%special', 'UnitTestTag%boring']);
306 $this->assertFalse($subject->has('BackendMemcacheTest1'));
307 $this->assertFalse($subject->has('BackendMemcacheTest2'));
308 $this->assertTrue($subject->has('BackendMemcacheTest3'));
309 }
310
311 /**
312 * @test
313 */
314 public function flushRemovesAllCacheEntries()
315 {
316 $frontendProphecy = $this->prophesize(FrontendInterface::class);
317 $frontendProphecy->getIdentifier()->willReturn('cache_pages');
318
319 $subject = $this->initializeSubject();
320 $subject->setCache($frontendProphecy->reveal());
321
322 $data = 'some data' . microtime();
323 $subject->set('BackendMemcacheTest1', $data);
324 $subject->set('BackendMemcacheTest2', $data);
325 $subject->set('BackendMemcacheTest3', $data);
326 $subject->flush();
327 $this->assertFalse($subject->has('BackendMemcacheTest1'));
328 $this->assertFalse($subject->has('BackendMemcacheTest2'));
329 $this->assertFalse($subject->has('BackendMemcacheTest3'));
330 }
331
332 /**
333 * @test
334 */
335 public function flushRemovesOnlyOwnEntries()
336 {
337 $thisFrontendProphecy = $this->prophesize(FrontendInterface::class);
338 $thisFrontendProphecy->getIdentifier()->willReturn('thisCache');
339 $thisBackend = $this->initializeSubject();
340 $thisBackend->setCache($thisFrontendProphecy->reveal());
341
342 $thatFrontendProphecy = $this->prophesize(FrontendInterface::class);
343 $thatFrontendProphecy->getIdentifier()->willReturn('thatCache');
344 $thatBackend = $this->initializeSubject();
345 $thatBackend->setCache($thatFrontendProphecy->reveal());
346
347 $thisBackend->set('thisEntry', 'Hello');
348 $thatBackend->set('thatEntry', 'World!');
349 $thatBackend->flush();
350
351 $this->assertEquals('Hello', $thisBackend->get('thisEntry'));
352 $this->assertFalse($thatBackend->has('thatEntry'));
353 }
354 }