[TASK] Detect APC and APCu correctly
[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 * Copyright notice
6 *
7 * (c) 2009-2013 Ingo Renner <ingo@typo3.org>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26
27 /**
28 * Testcase for the APC cache backend.
29 *
30 * NOTE: If you want to execute these tests you need to enable apc in
31 * cli context (apc.enable_cli = 1)
32 *
33 * This file is a backport from FLOW3
34 *
35 * @author Ingo Renner <ingo@typo3.org>
36 */
37 class ApcBackendTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
38
39 /**
40 * Sets up this testcase
41 *
42 * @return void
43 */
44 public function setUp() {
45 // Currently APCu identifies itself both as "apcu" and "apc" (for compatibility) although it doesn't provide the APC-opcache functionality
46 if (!extension_loaded('apc')) {
47 $this->markTestSkipped('APC/APCu extension was not available');
48 }
49 if (ini_get('apc.slam_defense') == 1) {
50 $this->markTestSkipped('This testcase can only be executed with apc.slam_defense = Off');
51 }
52 }
53
54 /**
55 * @test
56 * @expectedException \TYPO3\CMS\Core\Cache\Exception
57 */
58 public function setThrowsExceptionIfNoFrontEndHasBeenSet() {
59 $backend = new \TYPO3\CMS\Core\Cache\Backend\ApcBackend('Testing');
60 $data = 'Some data';
61 $identifier = 'MyIdentifier' . md5(uniqid(mt_rand(), TRUE));
62 $backend->set($identifier, $data);
63 }
64
65 /**
66 * @test
67 */
68 public function itIsPossibleToSetAndCheckExistenceInCache() {
69 // APC has some slam protection that tries to prevent hammering of cache
70 // entries. This can be disabled, but the option does not work at least
71 // in native PHP 5.3.3 on debian squeeze. While it is no problem with
72 // higher PHP version like the current one on travis-ci.org,
73 // the test is now just skipped on PHP environments that are knows for issues.
74 if (version_compare(phpversion(), '5.3.4', '<')) {
75 $this->markTestSkipped('This test is not reliable with PHP version below 5.3.3');
76 }
77 $backend = $this->setUpBackend();
78 $data = 'Some data';
79 $identifier = 'MyIdentifier' . md5(uniqid(mt_rand(), TRUE));
80 $backend->set($identifier, $data);
81 $inCache = $backend->has($identifier);
82 $this->assertTrue($inCache, 'APC backend failed to set and check entry');
83 }
84
85 /**
86 * @test
87 */
88 public function itIsPossibleToSetAndGetEntry() {
89 // APC has some slam protection that tries to prevent hammering of cache
90 // entries. This can be disabled, but the option does not work at least
91 // in native PHP 5.3.3 on debian squeeze. While it is no problem with
92 // higher PHP version like the current one on travis-ci.org,
93 // the test is now just skipped on PHP environments that are knows for issues.
94 if (version_compare(phpversion(), '5.3.4', '<')) {
95 $this->markTestSkipped('This test is not reliable with PHP version below 5.3.3');
96 }
97 $backend = $this->setUpBackend();
98 $data = 'Some data';
99 $identifier = 'MyIdentifier' . md5(uniqid(mt_rand(), TRUE));
100 $backend->set($identifier, $data);
101 $fetchedData = $backend->get($identifier);
102 $this->assertEquals($data, $fetchedData, 'APC backend failed to set and retrieve data');
103 }
104
105 /**
106 * @test
107 */
108 public function itIsPossibleToRemoveEntryFromCache() {
109 $backend = $this->setUpBackend();
110 $data = 'Some data';
111 $identifier = 'MyIdentifier' . md5(uniqid(mt_rand(), TRUE));
112 $backend->set($identifier, $data);
113 $backend->remove($identifier);
114 $inCache = $backend->has($identifier);
115 $this->assertFalse($inCache, 'Failed to set and remove data from APC backend');
116 }
117
118 /**
119 * @test
120 */
121 public function itIsPossibleToOverwriteAnEntryInTheCache() {
122 $backend = $this->setUpBackend();
123 $data = 'Some data';
124 $identifier = 'MyIdentifier' . md5(uniqid(mt_rand(), TRUE));
125 $backend->set($identifier, $data);
126 $otherData = 'some other data';
127 $backend->set($identifier, $otherData);
128 $fetchedData = $backend->get($identifier);
129 $this->assertEquals($otherData, $fetchedData, 'APC backend failed to overwrite and retrieve data');
130 }
131
132 /**
133 * @test
134 */
135 public function findIdentifiersByTagFindsSetEntries() {
136 $backend = $this->setUpBackend();
137 $data = 'Some data';
138 $identifier = 'MyIdentifier' . md5(uniqid(mt_rand(), TRUE));
139 $backend->set($identifier, $data, array('UnitTestTag%tag1', 'UnitTestTag%tag2'));
140 $retrieved = $backend->findIdentifiersByTag('UnitTestTag%tag1');
141 $this->assertEquals($identifier, $retrieved[0], 'Could not retrieve expected entry by tag.');
142 $retrieved = $backend->findIdentifiersByTag('UnitTestTag%tag2');
143 $this->assertEquals($identifier, $retrieved[0], 'Could not retrieve expected entry by tag.');
144 }
145
146 /**
147 * @test
148 */
149 public function setRemovesTagsFromPreviousSet() {
150 $backend = $this->setUpBackend();
151 $data = 'Some data';
152 $identifier = 'MyIdentifier' . md5(uniqid(mt_rand(), TRUE));
153 $backend->set($identifier, $data, array('UnitTestTag%tag1', 'UnitTestTag%tagX'));
154 $backend->set($identifier, $data, array('UnitTestTag%tag3'));
155 $retrieved = $backend->findIdentifiersByTag('UnitTestTag%tagX');
156 $this->assertEquals(array(), $retrieved, 'Found entry which should no longer exist.');
157 }
158
159 /**
160 * @test
161 */
162 public function setCacheIsSettingIdentifierPrefixWithCacheIdentifier() {
163 $cacheMock = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\FrontendInterface', array(), array(), '', FALSE);
164 $cacheMock->expects($this->any())->method('getIdentifier')->will($this->returnValue(
165 'testidentifier'
166 ));
167
168 /** @var $backendMock \TYPO3\CMS\Core\Cache\Backend\ApcBackend */
169 $backendMock = $this->getMock(
170 'TYPO3\\CMS\\Core\\Cache\\Backend\\ApcBackend',
171 array('setIdentifierPrefix','getCurrentUserData','getPathSite'),
172 array('testcontext')
173 );
174
175 $backendMock->expects($this->once())->method('getCurrentUserData')->will(
176 $this->returnValue(array('name' => 'testname'))
177 );
178
179 $backendMock->expects($this->once())->method('getPathSite')->will(
180 $this->returnValue('testpath')
181 );
182
183 $expectedIdentifier = 'TYPO3_' . \TYPO3\CMS\Core\Utility\GeneralUtility::shortMD5('testpath' . 'testname' . 'testcontext' . 'testidentifier', 12);
184 $backendMock->expects($this->once())->method('setIdentifierPrefix')->with($expectedIdentifier);
185 $backendMock->setCache($cacheMock);
186 }
187
188 /**
189 * @test
190 */
191 public function hasReturnsFalseIfTheEntryDoesntExist() {
192 $backend = $this->setUpBackend();
193 $identifier = 'NonExistingIdentifier' . md5(uniqid(mt_rand(), TRUE));
194 $inCache = $backend->has($identifier);
195 $this->assertFalse($inCache, '"has" did not return FALSE when checking on non existing identifier');
196 }
197
198 /**
199 * @test
200 */
201 public function removeReturnsFalseIfTheEntryDoesntExist() {
202 $backend = $this->setUpBackend();
203 $identifier = 'NonExistingIdentifier' . md5(uniqid(mt_rand(), TRUE));
204 $inCache = $backend->remove($identifier);
205 $this->assertFalse($inCache, '"remove" did not return FALSE when checking on non existing identifier');
206 }
207
208 /**
209 * @test
210 */
211 public function flushByTagRemovesCacheEntriesWithSpecifiedTag() {
212 $backend = $this->setUpBackend();
213 $data = 'some data' . microtime();
214 $backend->set('BackendAPCTest1', $data, array('UnitTestTag%test', 'UnitTestTag%boring'));
215 $backend->set('BackendAPCTest2', $data, array('UnitTestTag%test', 'UnitTestTag%special'));
216 $backend->set('BackendAPCTest3', $data, array('UnitTestTag%test'));
217 $backend->flushByTag('UnitTestTag%special');
218 $this->assertTrue($backend->has('BackendAPCTest1'), 'BackendAPCTest1');
219 $this->assertFalse($backend->has('BackendAPCTest2'), 'BackendAPCTest2');
220 $this->assertTrue($backend->has('BackendAPCTest3'), 'BackendAPCTest3');
221 }
222
223 /**
224 * @test
225 */
226 public function flushRemovesAllCacheEntries() {
227 // APC has some slam protection that tries to prevent hammering of cache
228 // entries. This can be disabled, but the option does not work at least
229 // in native PHP 5.3.3 on debian squeeze. While it is no problem with
230 // higher PHP version like the current one on travis-ci.org,
231 // the test is now just skipped on PHP environments that are knows for issues.
232 if (version_compare(phpversion(), '5.3.4', '<')) {
233 $this->markTestSkipped('This test is not reliable with PHP version below 5.3.3');
234 }
235 $backend = $this->setUpBackend();
236 $data = 'some data' . microtime();
237 $backend->set('BackendAPCTest1', $data);
238 $backend->set('BackendAPCTest2', $data);
239 $backend->set('BackendAPCTest3', $data);
240 $backend->flush();
241 $this->assertFalse($backend->has('BackendAPCTest1'), 'BackendAPCTest1');
242 $this->assertFalse($backend->has('BackendAPCTest2'), 'BackendAPCTest2');
243 $this->assertFalse($backend->has('BackendAPCTest3'), 'BackendAPCTest3');
244 }
245
246 /**
247 * @test
248 */
249 public function flushRemovesOnlyOwnEntries() {
250 $thisCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\FrontendInterface', array(), array(), '', FALSE);
251 $thisCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('thisCache'));
252 $thisBackend = new \TYPO3\CMS\Core\Cache\Backend\ApcBackend('Testing');
253 $thisBackend->setCache($thisCache);
254 $thatCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\FrontendInterface', array(), array(), '', FALSE);
255 $thatCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('thatCache'));
256 $thatBackend = new \TYPO3\CMS\Core\Cache\Backend\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 $backend = $this->setUpBackend();
272 $data = str_repeat('abcde', 1024 * 1024);
273 $identifier = 'tooLargeData' . md5(uniqid(mt_rand(), TRUE));
274 $backend->set($identifier, $data);
275 $this->assertTrue($backend->has($identifier));
276 $this->assertEquals($backend->get($identifier), $data);
277 }
278
279 /**
280 * Sets up the APC backend used for testing
281 *
282 * @return \TYPO3\CMS\Core\Cache\Backend\ApcBackend
283 */
284 protected function setUpBackend() {
285 $cache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\FrontendInterface', array(), array(), '', FALSE);
286 $backend = new \TYPO3\CMS\Core\Cache\Backend\ApcBackend('Testing');
287 $backend->setCache($cache);
288 return $backend;
289 }
290
291 }
292
293 ?>