[BUGFIX] Too many tags by identifier in CacheBackends 18/31518/3
authorAlexander Opitz <opitz.alexander@googlemail.com>
Tue, 17 Jun 2014 07:58:32 +0000 (09:58 +0200)
committerMarkus Klein <klein.t3@mfc-linz.at>
Tue, 8 Jul 2014 20:57:06 +0000 (22:57 +0200)
This applies to Apc/Memcached/Wincache/Xcache backends.

After an array_merge the values aren't unique. This leads to duplicate
tags per identifier. This patch changes that and also moves the
findTagsByIdentifier call out of the foreach loop.

Resolves: #59587
Releases: 6.3, 6.2, 6.1
Change-Id: Id31e16fa4bba11038ba692a483fb9a33808d95fa
Reviewed-on: https://review.typo3.org/31518
Reviewed-by: Markus Klein
Tested-by: Markus Klein
typo3/sysext/core/Classes/Cache/Backend/ApcBackend.php
typo3/sysext/core/Classes/Cache/Backend/MemcachedBackend.php
typo3/sysext/core/Classes/Cache/Backend/WincacheBackend.php
typo3/sysext/core/Classes/Cache/Backend/XcacheBackend.php
typo3/sysext/core/Tests/Unit/Cache/Backend/ApcBackendTest.php
typo3/sysext/core/Tests/Unit/Cache/Backend/MemcachedBackendTest.php
typo3/sysext/core/Tests/Unit/Cache/Backend/WincacheBackendTest.php
typo3/sysext/core/Tests/Unit/Cache/Backend/XcacheBackendTest.php

index 896ca8c..00093ba 100644 (file)
@@ -254,19 +254,28 @@ class ApcBackend extends \TYPO3\CMS\Core\Cache\Backend\AbstractBackend implement
         * @return void
         */
        protected function addIdentifierToTags($entryIdentifier, array $tags) {
+               // Get identifier-to-tag index to look for updates
+               $existingTags = $this->findTagsByIdentifier($entryIdentifier);
+               $existingTagsUpdated = FALSE;
+
                foreach ($tags as $tag) {
                        // Update tag-to-identifier index
                        $identifiers = $this->findIdentifiersByTag($tag);
-                       if (array_search($entryIdentifier, $identifiers) === FALSE) {
+                       if (!in_array($entryIdentifier, $identifiers, TRUE)) {
                                $identifiers[] = $entryIdentifier;
                                apc_store($this->getIdentifierPrefix() . 'tag_' . $tag, $identifiers);
                        }
-                       // Update identifier-to-tag index
-                       $existingTags = $this->findTagsByIdentifier($entryIdentifier);
-                       if (array_search($entryIdentifier, $existingTags) === FALSE) {
-                               apc_store($this->getIdentifierPrefix() . 'ident_' . $entryIdentifier, array_merge($existingTags, $tags));
+                       // Test if identifier-to-tag index needs update
+                       if (!in_array($tag, $existingTags, TRUE)) {
+                               $existingTags[] = $tag;
+                               $existingTagsUpdated = TRUE;
                        }
                }
+
+               // Update identifier-to-tag index if needed
+               if ($existingTagsUpdated) {
+                       apc_store($this->getIdentifierPrefix() . 'ident_' . $entryIdentifier, $existingTags);
+               }
        }
 
        /**
index 2cdaaf0..6fb5d43 100644 (file)
@@ -315,19 +315,28 @@ class MemcachedBackend extends \TYPO3\CMS\Core\Cache\Backend\AbstractBackend imp
         * @return void
         */
        protected function addIdentifierToTags($entryIdentifier, array $tags) {
+               // Get identifier-to-tag index to look for updates
+               $existingTags = $this->findTagsByIdentifier($entryIdentifier);
+               $existingTagsUpdated = FALSE;
+
                foreach ($tags as $tag) {
                        // Update tag-to-identifier index
                        $identifiers = $this->findIdentifiersByTag($tag);
-                       if (array_search($entryIdentifier, $identifiers) === FALSE) {
+                       if (!in_array($entryIdentifier, $identifiers, TRUE)) {
                                $identifiers[] = $entryIdentifier;
                                $this->memcache->set($this->identifierPrefix . 'tag_' . $tag, $identifiers);
                        }
-                       // Update identifier-to-tag index
-                       $existingTags = $this->findTagsByIdentifier($entryIdentifier);
-                       if (array_search($tag, $existingTags) === FALSE) {
-                               $this->memcache->set($this->identifierPrefix . 'ident_' . $entryIdentifier, array_merge($existingTags, $tags));
+                       // Test if identifier-to-tag index needs update
+                       if (!in_array($tag, $existingTags, TRUE)) {
+                               $existingTags[] = $tag;
+                               $existingTagsUpdated = TRUE;
                        }
                }
+
+               // Update identifier-to-tag index if needed
+               if ($existingTagsUpdated) {
+                       $this->memcache->set($this->identifierPrefix . 'ident_' . $entryIdentifier, $existingTags);
+               }
        }
 
        /**
index 89b1bec..08f5bbc 100644 (file)
@@ -38,7 +38,7 @@ namespace TYPO3\CMS\Core\Cache\Backend;
 class WincacheBackend extends \TYPO3\CMS\Core\Cache\Backend\AbstractBackend implements \TYPO3\CMS\Core\Cache\Backend\TaggableBackendInterface {
 
        /**
-        * A prefix to seperate stored data from other data possible stored in the wincache
+        * A prefix to separate stored data from other data possible stored in the wincache
         *
         * @var string
         */
@@ -156,6 +156,7 @@ class WincacheBackend extends \TYPO3\CMS\Core\Cache\Backend\AbstractBackend impl
        /**
         * Removes all cache entries of this cache
         *
+        * @throws \TYPO3\CMS\Core\Cache\Exception
         * @return void
         */
        public function flush() {
@@ -187,19 +188,28 @@ class WincacheBackend extends \TYPO3\CMS\Core\Cache\Backend\AbstractBackend impl
         * @return void
         */
        protected function addIdentifierToTags($entryIdentifier, array $tags) {
+               // Get identifier-to-tag index to look for updates
+               $existingTags = $this->findTagsByIdentifier($entryIdentifier);
+               $existingTagsUpdated = FALSE;
+
                foreach ($tags as $tag) {
                        // Update tag-to-identifier index
                        $identifiers = $this->findIdentifiersByTag($tag);
-                       if (array_search($entryIdentifier, $identifiers) === FALSE) {
+                       if (!in_array($entryIdentifier, $identifiers, TRUE)) {
                                $identifiers[] = $entryIdentifier;
                                wincache_ucache_set($this->identifierPrefix . 'tag_' . $tag, $identifiers);
                        }
-                       // Update identifier-to-tag index
-                       $existingTags = $this->findTagsByIdentifier($entryIdentifier);
-                       if (array_search($entryIdentifier, $existingTags) === FALSE) {
-                               wincache_ucache_set($this->identifierPrefix . 'ident_' . $entryIdentifier, array_merge($existingTags, $tags));
+                       // Test if identifier-to-tag index needs update
+                       if (!in_array($tag, $existingTags, TRUE)) {
+                               $existingTags[] = $tag;
+                               $existingTagsUpdated = TRUE;
                        }
                }
+
+               // Update identifier-to-tag index if needed
+               if ($existingTagsUpdated) {
+                       wincache_ucache_set($this->identifierPrefix . 'ident_' . $entryIdentifier, $existingTags);
+               }
        }
 
        /**
index abed8b9..025494c 100644 (file)
@@ -1,6 +1,5 @@
 <?php
 namespace TYPO3\CMS\Core\Cache\Backend;
-use TYPO3\CMS\Core\Cache\Exception;
 
 /**
  * This file is part of the TYPO3 CMS project.
@@ -221,19 +220,30 @@ class XcacheBackend extends AbstractBackend implements TaggableBackendInterface
                if ($this->runningFromCliOrWrongConfiguration()) {
                        return;
                }
+
+               // Get identifier-to-tag index to look for updates
+               $existingTags = $this->findTagsByIdentifier($entryIdentifier);
+               $existingTagsUpdated = FALSE;
+
+
                foreach ($tags as $tag) {
                        // Update tag-to-identifier index
                        $identifiers = $this->findIdentifiersByTag($tag);
-                       if (array_search($entryIdentifier, $identifiers) === FALSE) {
+                       if (!in_array($entryIdentifier, $identifiers, TRUE)) {
                                $identifiers[] = $entryIdentifier;
                                xcache_set($this->identifierPrefix . 'tag_' . $tag, $identifiers);
                        }
-                       // Update identifier-to-tag index
-                       $existingTags = $this->findTagsByIdentifier($entryIdentifier);
-                       if (array_search($entryIdentifier, $existingTags) === FALSE) {
-                               xcache_set($this->identifierPrefix . 'ident_' . $entryIdentifier, array_merge($existingTags, $tags));
+                       // Test if identifier-to-tag index needs update
+                       if (!in_array($tag, $existingTags, TRUE)) {
+                               $existingTags[] = $tag;
+                               $existingTagsUpdated = TRUE;
                        }
                }
+
+               // Update identifier-to-tag index if needed
+               if ($existingTagsUpdated) {
+                       xcache_set($this->identifierPrefix . 'ident_' . $entryIdentifier, $existingTags);
+               }
        }
 
        /**
index 443e883..5fda3fc 100644 (file)
@@ -14,6 +14,8 @@ namespace TYPO3\CMS\Core\Tests\Unit\Cache\Backend;
  * The TYPO3 project - inspiring people to share!
  */
 
+
+use TYPO3\CMS\Core\Cache\Backend\ApcBackend;
 /**
  * Testcase for the APC cache backend.
  *
@@ -46,7 +48,7 @@ class ApcBackendTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @expectedException \TYPO3\CMS\Core\Cache\Exception
         */
        public function setThrowsExceptionIfNoFrontEndHasBeenSet() {
-               $backend = new \TYPO3\CMS\Core\Cache\Backend\ApcBackend('Testing');
+               $backend = new ApcBackend('Testing');
                $data = 'Some data';
                $identifier = 'MyIdentifier' . md5(uniqid(mt_rand(), TRUE));
                $backend->set($identifier, $data);
@@ -134,12 +136,13 @@ class ApcBackendTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function setCacheIsSettingIdentifierPrefixWithCacheIdentifier() {
+               /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $cacheMock */
                $cacheMock = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\FrontendInterface', array(), array(), '', FALSE);
                $cacheMock->expects($this->any())->method('getIdentifier')->will($this->returnValue(
                        'testidentifier'
                ));
 
-               /** @var $backendMock \TYPO3\CMS\Core\Cache\Backend\ApcBackend */
+               /** @var $backendMock \PHPUnit_Framework_MockObject_MockObject|ApcBackend */
                $backendMock = $this->getMock(
                        'TYPO3\\CMS\\Core\\Cache\\Backend\\ApcBackend',
                        array('setIdentifierPrefix','getCurrentUserData','getPathSite'),
@@ -162,7 +165,7 @@ class ApcBackendTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
        /**
         * @test
         */
-       public function hasReturnsFalseIfTheEntryDoesntExist() {
+       public function hasReturnsFalseIfTheEntryDoesNotExist() {
                $backend = $this->setUpBackend();
                $identifier = 'NonExistingIdentifier' . md5(uniqid(mt_rand(), TRUE));
                $inCache = $backend->has($identifier);
@@ -216,13 +219,16 @@ class ApcBackendTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function flushRemovesOnlyOwnEntries() {
+               /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $thisCache */
                $thisCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\FrontendInterface', array(), array(), '', FALSE);
                $thisCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('thisCache'));
-               $thisBackend = new \TYPO3\CMS\Core\Cache\Backend\ApcBackend('Testing');
+               $thisBackend = new ApcBackend('Testing');
                $thisBackend->setCache($thisCache);
+
+               /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $thatCache */
                $thatCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\FrontendInterface', array(), array(), '', FALSE);
                $thatCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('thatCache'));
-               $thatBackend = new \TYPO3\CMS\Core\Cache\Backend\ApcBackend('Testing');
+               $thatBackend = new ApcBackend('Testing');
                $thatBackend->setCache($thatCache);
                $thisBackend->set('thisEntry', 'Hello');
                $thatBackend->set('thatEntry', 'World!');
@@ -246,13 +252,41 @@ class ApcBackendTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
        }
 
        /**
+        * @test
+        */
+       public function setTagsOnlyOnceToIdentifier() {
+               $identifier = 'MyIdentifier' . md5(uniqid(mt_rand(), TRUE));
+               $tags = array('UnitTestTag%test', 'UnitTestTag%boring');
+
+               $backend = $this->setUpBackend(TRUE);
+               $backend->_call('addIdentifierToTags', $identifier, $tags);
+               $this->assertSame(
+                       $tags,
+                       $backend->_call('findTagsByIdentifier', $identifier)
+               );
+
+               $backend->_call('addIdentifierToTags', $identifier, $tags);
+               $this->assertSame(
+                       $tags,
+                       $backend->_call('findTagsByIdentifier', $identifier)
+               );
+       }
+
+       /**
         * Sets up the APC backend used for testing
         *
-        * @return \TYPO3\CMS\Core\Cache\Backend\ApcBackend
+        * @param bool $accessible TRUE if backend should be encapsulated in accessible proxy otherwise FALSE.
+        * @return \TYPO3\CMS\Core\Tests\AccessibleObjectInterface|ApcBackend
         */
-       protected function setUpBackend() {
+       protected function setUpBackend($accessible = FALSE) {
+               /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $cache */
                $cache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\FrontendInterface', array(), array(), '', FALSE);
-               $backend = new \TYPO3\CMS\Core\Cache\Backend\ApcBackend('Testing');
+               if ($accessible) {
+                       $accessibleClassName = $this->buildAccessibleProxy('\\TYPO3\\CMS\\Core\\Cache\\Backend\\ApcBackend');
+                       $backend = new $accessibleClassName('Testing');
+               } else {
+                       $backend = new ApcBackend('Testing');
+               }
                $backend->setCache($cache);
                return $backend;
        }
index 1f4c8f2..d781012 100644 (file)
@@ -14,6 +14,8 @@ namespace TYPO3\CMS\Core\Tests\Unit\Cache\Backend;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Cache\Backend\MemcachedBackend;
+
 /**
  * Testcase for the cache to memcached backend
  *
@@ -47,7 +49,7 @@ class MemcachedBackendTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         */
        public function setThrowsExceptionIfNoFrontEndHasBeenSet() {
                $backendOptions = array('servers' => array('localhost:11211'));
-               $backend = new \TYPO3\CMS\Core\Cache\Backend\MemcachedBackend('Testing', $backendOptions);
+               $backend = new MemcachedBackend('Testing', $backendOptions);
                $backend->initializeObject();
                $data = 'Some data';
                $identifier = 'MyIdentifier' . md5(uniqid(mt_rand(), TRUE));
@@ -59,7 +61,7 @@ class MemcachedBackendTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @expectedException \TYPO3\CMS\Core\Cache\Exception
         */
        public function initializeObjectThrowsExceptionIfNoMemcacheServerIsConfigured() {
-               $backend = new \TYPO3\CMS\Core\Cache\Backend\MemcachedBackend('Testing');
+               $backend = new MemcachedBackend('Testing');
                $backend->initializeObject();
        }
 
@@ -196,14 +198,17 @@ class MemcachedBackendTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         */
        public function flushRemovesOnlyOwnEntries() {
                $backendOptions = array('servers' => array('localhost:11211'));
+               /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $thisCache */
                $thisCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array(), array(), '', FALSE);
                $thisCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('thisCache'));
-               $thisBackend = new \TYPO3\CMS\Core\Cache\Backend\MemcachedBackend('Testing', $backendOptions);
+               $thisBackend = new MemcachedBackend('Testing', $backendOptions);
                $thisBackend->setCache($thisCache);
                $thisBackend->initializeObject();
+
+               /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $thatCache */
                $thatCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\AbstractFrontend', array(), array(), '', FALSE);
                $thatCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('thatCache'));
-               $thatBackend = new \TYPO3\CMS\Core\Cache\Backend\MemcachedBackend('Testing', $backendOptions);
+               $thatBackend = new MemcachedBackend('Testing', $backendOptions);
                $thatBackend->setCache($thatCache);
                $thatBackend->initializeObject();
                $thisBackend->set('thisEntry', 'Hello');
@@ -228,17 +233,46 @@ class MemcachedBackendTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
        }
 
        /**
+        * @test
+        */
+       public function setTagsOnlyOnceToIdentifier() {
+               $backendOptions = array('servers' => array('localhost:11211'));
+               $identifier = 'MyIdentifier' . md5(uniqid(mt_rand(), TRUE));
+               $tags = array('UnitTestTag%test', 'UnitTestTag%boring');
+
+               $backend = $this->setUpBackend($backendOptions, TRUE);
+               $backend->_call('addIdentifierToTags', $identifier, $tags);
+               $this->assertSame(
+                       $tags,
+                       $backend->_call('findTagsByIdentifier', $identifier)
+               );
+
+               $backend->_call('addIdentifierToTags', $identifier, $tags);
+               $this->assertSame(
+                       $tags,
+                       $backend->_call('findTagsByIdentifier', $identifier)
+               );
+       }
+
+       /**
         * Sets up the memcached backend used for testing
         *
         * @param array $backendOptions Options for the memcache backend
-        * @return \TYPO3\CMS\Core\Cache\Backend\MemcachedBackend
+        * @param bool $accessible TRUE if backend should be encapsulated in accessible proxy otherwise FALSE.
+        * @return \TYPO3\CMS\Core\Tests\AccessibleObjectInterface|MemcachedBackend
         */
-       protected function setUpBackend(array $backendOptions = array()) {
+       protected function setUpBackend(array $backendOptions = array(), $accessible = FALSE) {
+               /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $cache */
                $cache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\FrontendInterface', array(), array(), '', FALSE);
                if ($backendOptions == array()) {
                        $backendOptions = array('servers' => array('localhost:11211'));
                }
-               $backend = new \TYPO3\CMS\Core\Cache\Backend\MemcachedBackend('Testing', $backendOptions);
+               if ($accessible) {
+                       $accessibleClassName = $this->buildAccessibleProxy('\\TYPO3\\CMS\\Core\\Cache\\Backend\\MemcachedBackend');
+                       $backend = new $accessibleClassName('Testing', $backendOptions);
+               } else {
+                       $backend = new MemcachedBackend('Testing', $backendOptions);
+               }
                $backend->setCache($cache);
                $backend->initializeObject();
                return $backend;
index 0409989..5792ae3 100644 (file)
@@ -14,6 +14,8 @@ namespace TYPO3\CMS\Core\Tests\Unit\Cache\Backend;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Cache\Backend\WincacheBackend;
+
 /**
  * Testcase for the WinCache cache backend
  *
@@ -37,7 +39,7 @@ class WincacheBackendTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @expectedException \TYPO3\CMS\Core\Cache\Exception
         */
        public function setThrowsExceptionIfNoFrontEndHasBeenSet() {
-               $backend = new \TYPO3\CMS\Core\Cache\Backend\WincacheBackend('Testing');
+               $backend = new WincacheBackend('Testing');
                $data = 'Some data';
                $identifier = 'MyIdentifier' . md5(uniqid(mt_rand(), TRUE));
                $backend->set($identifier, $data);
@@ -175,13 +177,16 @@ class WincacheBackendTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function flushRemovesOnlyOwnEntries() {
+               /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $thisCache */
                $thisCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\FrontendInterface', array(), array(), '', FALSE);
                $thisCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('thisCache'));
-               $thisBackend = new \TYPO3\CMS\Core\Cache\Backend\WincacheBackend('Testing');
+               $thisBackend = new WincacheBackend('Testing');
                $thisBackend->setCache($thisCache);
+
+               /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $thatCache */
                $thatCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\FrontendInterface', array(), array(), '', FALSE);
                $thatCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('thatCache'));
-               $thatBackend = new \TYPO3\CMS\Core\Cache\Backend\WincacheBackend('Testing');
+               $thatBackend = new WincacheBackend('Testing');
                $thatBackend->setCache($thatCache);
                $thisBackend->set('thisEntry', 'Hello');
                $thatBackend->set('thatEntry', 'World!');
@@ -205,13 +210,41 @@ class WincacheBackendTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
        }
 
        /**
+        * @test
+        */
+       public function setTagsOnlyOnceToIdentifier() {
+               $identifier = 'MyIdentifier' . md5(uniqid(mt_rand(), TRUE));
+               $tags = array('UnitTestTag%test', 'UnitTestTag%boring');
+
+               $backend = $this->setUpBackend(TRUE);
+               $backend->_call('addIdentifierToTags', $identifier, $tags);
+               $this->assertSame(
+                       $tags,
+                       $backend->_call('findTagsByIdentifier', $identifier)
+               );
+
+               $backend->_call('addIdentifierToTags', $identifier, $tags);
+               $this->assertSame(
+                       $tags,
+                       $backend->_call('findTagsByIdentifier', $identifier)
+               );
+       }
+
+       /**
         * Sets up the WinCache backend used for testing
         *
-        * @return \TYPO3\CMS\Core\Cache\Backend\WincacheBackend
+        * @param bool $accessible TRUE if backend should be encapsulated in accessible proxy otherwise FALSE.
+        * @return \TYPO3\CMS\Core\Tests\AccessibleObjectInterface|WincacheBackend
         */
-       protected function setUpBackend() {
+       protected function setUpBackend($accessible = FALSE) {
+               /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $cache */
                $cache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\FrontendInterface', array(), array(), '', FALSE);
-               $backend = new \TYPO3\CMS\Core\Cache\Backend\WincacheBackend('Testing');
+               if ($accessible) {
+                       $accessibleClassName = $this->buildAccessibleProxy('\\TYPO3\\CMS\\Core\\Cache\\Backend\\WincacheBackend');
+                       $backend = new $accessibleClassName('Testing');
+               } else {
+                       $backend = new WincacheBackend('Testing');
+               }
                $backend->setCache($cache);
                return $backend;
        }
index 9a298fd..79fce70 100644 (file)
@@ -14,6 +14,8 @@ namespace TYPO3\CMS\Core\Tests\Unit\Cache\Backend;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Cache\Backend\XcacheBackend;
+
 /**
  * Test case
  *
@@ -40,7 +42,7 @@ class XcacheBackendTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @expectedException \TYPO3\CMS\Core\Cache\Exception
         */
        public function setThrowsExceptionIfNoFrontEndHasBeenSet() {
-               $backend = new \TYPO3\CMS\Core\Cache\Backend\XcacheBackend('Testing');
+               $backend = new XcacheBackend('Testing');
                $data = 'Some data';
                $identifier = 'MyIdentifier' . md5(uniqid(mt_rand(), TRUE));
                $backend->set($identifier, $data);
@@ -178,13 +180,16 @@ class XcacheBackendTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function flushRemovesOnlyOwnEntries() {
+               /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $thisCache */
                $thisCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\FrontendInterface', array(), array(), '', FALSE);
                $thisCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('thisCache'));
-               $thisBackend = new \TYPO3\CMS\Core\Cache\Backend\XcacheBackend('Testing');
+               $thisBackend = new XcacheBackend('Testing');
                $thisBackend->setCache($thisCache);
+
+               /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $thatCache */
                $thatCache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\FrontendInterface', array(), array(), '', FALSE);
                $thatCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('thatCache'));
-               $thatBackend = new \TYPO3\CMS\Core\Cache\Backend\XcacheBackend('Testing');
+               $thatBackend = new XcacheBackend('Testing');
                $thatBackend->setCache($thatCache);
                $thisBackend->set('thisEntry', 'Hello');
                $thatBackend->set('thatEntry', 'World!');
@@ -208,13 +213,41 @@ class XcacheBackendTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
        }
 
        /**
+        * @test
+        */
+       public function setTagsOnlyOnceToIdentifier() {
+               $identifier = 'MyIdentifier' . md5(uniqid(mt_rand(), TRUE));
+               $tags = array('UnitTestTag%test', 'UnitTestTag%boring');
+
+               $backend = $this->setUpBackend(TRUE);
+               $backend->_call('addIdentifierToTags', $identifier, $tags);
+               $this->assertSame(
+                       $tags,
+                       $backend->_call('findTagsByIdentifier', $identifier)
+               );
+
+               $backend->_call('addIdentifierToTags', $identifier, $tags);
+               $this->assertSame(
+                       $tags,
+                       $backend->_call('findTagsByIdentifier', $identifier)
+               );
+       }
+
+       /**
         * Sets up the xcache backend used for testing
         *
-        * @return \TYPO3\CMS\Core\Cache\Backend\XcacheBackend
+        * @param bool $accessible TRUE if backend should be encapsulated in accessible proxy otherwise FALSE.
+        * @return \TYPO3\CMS\Core\Tests\AccessibleObjectInterface|XcacheBackend
         */
-       protected function setUpBackend() {
+       protected function setUpBackend($accessible = FALSE) {
+               /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $cache */
                $cache = $this->getMock('TYPO3\\CMS\\Core\\Cache\\Frontend\\FrontendInterface', array(), array(), '', FALSE);
-               $backend = new \TYPO3\CMS\Core\Cache\Backend\XcacheBackend('Testing');
+               if ($accessible) {
+                       $accessibleClassName = $this->buildAccessibleProxy('\\TYPO3\\CMS\\Core\\Cache\\Backend\\XcacheBackend');
+                       $backend = new $accessibleClassName('Testing');
+               } else {
+                       $backend = new XcacheBackend('Testing');
+               }
                $backend->setCache($cache);
                return $backend;
        }