TYPO3 API  SVNRelease
t3lib_cache_backend_redisbackendTest.php
Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003 *  Copyright notice
00004 *
00005 *  (c) 2010-2011 Christian Kuhn <lolli@schwarzbu.ch>
00006 *  All rights reserved
00007 *
00008 *  This script is part of the TYPO3 project. The TYPO3 project is
00009 *  free software; you can redistribute it and/or modify
00010 *  it under the terms of the GNU General Public License as published by
00011 *  the Free Software Foundation; either version 2 of the License, or
00012 *  (at your option) any later version.
00013 *
00014 *  The GNU General Public License can be found at
00015 *  http://www.gnu.org/copyleft/gpl.html.
00016 *
00017 *  This script is distributed in the hope that it will be useful,
00018 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 *  GNU General Public License for more details.
00021 *
00022 *  This copyright notice MUST APPEAR in all copies of the script!
00023 ***************************************************************/
00024 
00025 /**
00026  * Testcase for the cache to redis backend
00027  *
00028  * This class has functional tests as well as implementation tests:
00029  * - The functional tests make API calls to the backend and check expected behaviour
00030  * - The implementation tests make additional calls with an own redis instance to
00031  *   check stored data structures in the redis server, which can not be checked
00032  *   by functional tests alone. Those tests will fail if any changes
00033  *   to the internal data structure are done.
00034  *
00035  * Warning:
00036  * The unit tests use and flush redis database numbers 0 and 1!
00037  *
00038  * @author Christian Kuhn <lolli@schwarzbu.ch>
00039  * @package TYPO3
00040  * @subpackage tests
00041  */
00042 class t3lib_cache_backend_RedisBackendTest extends tx_phpunit_testcase {
00043     /**
00044      * If set, the tearDown() method will flush the cache used by this unit test.
00045      *
00046      * @var t3lib_cache_backend_RedisBackend
00047      */
00048     protected $backend = NULL;
00049 
00050     /**
00051      * Own redis instance used in implementation tests
00052      *
00053      * @var Redis
00054      */
00055     protected $redis = NULL;
00056 
00057     /**
00058      * Set up this testcase
00059      *
00060      * @author Christian Kuhn <lolli@schwarzbu.ch>
00061      */
00062     public function setUp() {
00063         if (!extension_loaded('redis')) {
00064             $this->markTestSkipped('redis extension was not available');
00065         }
00066 
00067         try {
00068             if (!@fsockopen('127.0.0.1', 6379)) {
00069                 $this->markTestSkipped('redis server not reachable');
00070             }
00071         } catch (Exception $e) {
00072             $this->markTestSkipped('redis server not reachable');
00073         }
00074     }
00075 
00076     /**
00077      * Sets up the redis backend used for testing
00078      *
00079      * @param array Options for the redis backend
00080      * @author Christian Kuhn <lolli@schwarzbu.ch>
00081      */
00082     protected function setUpBackend(array $backendOptions = array()) {
00083         $mockCache = $this->getMock('t3lib_cache_frontend_Frontend', array(), array(), '', FALSE);
00084         $mockCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('TestCache'));
00085 
00086         $this->backend = new t3lib_cache_backend_RedisBackend($backendOptions);
00087         $this->backend->setCache($mockCache);
00088     }
00089 
00090     /**
00091      * Sets up an own redis instance for implementation tests
00092      *
00093      * @author Christian Kuhn <lolli@schwarzbu.ch>
00094      */
00095     protected function setUpRedis() {
00096         $this->redis = new Redis();
00097         $this->redis->connect('127.0.0.1', 6379);
00098     }
00099 
00100     /**
00101      * Tear down this testcase
00102      *
00103      * @author Christian Kuhn <lolli@schwarzbu.ch>
00104      */
00105     public function tearDown() {
00106         if ($this->backend instanceof t3lib_cache_backend_RedisBackend) {
00107             $this->backend->flush();
00108         }
00109 
00110         unset($this->redis, $this->backend);
00111     }
00112 
00113     /**
00114      * @test Functional
00115      * @author Christian Kuhn <lolli@schwarzbu.ch>
00116      */
00117     public function constructorThrowsNoExceptionIfPasswordOptionIsSet() {
00118         $this->setUpBackend(array('password' => 'foo'));
00119     }
00120 
00121     /**
00122      * @test Functional
00123      * @author Christian Kuhn <lolli@schwarzbu.ch>
00124      */
00125     public function constructorThrowsNoExceptionIfGivenDatabaseWasSuccessfullySelected() {
00126         $this->setUpBackend(array('database' => 1));
00127     }
00128 
00129     /**
00130      * @test Functional
00131      * @author Christian Kuhn <lolli@schwarzbu.ch>
00132      * @expectedException InvalidArgumentException
00133      */
00134     public function setDatabaseThrowsExceptionIfGivenDatabaseNumberIsNotAnInteger() {
00135         $this->setUpBackend(array('database' => 'foo'));
00136     }
00137 
00138     /**
00139      * @test Functional
00140      * @author Christian Kuhn <lolli@schwarzbu.ch>
00141      * @expectedException InvalidArgumentException
00142      */
00143     public function setDatabaseThrowsExceptionIfGivenDatabaseNumberIsNegative() {
00144         $this->setUpBackend(array('database' => -1));
00145     }
00146 
00147     /**
00148      * @test Functional
00149      * @author Christian Kuhn <lolli@schwarzbu.ch>
00150      * @expectedException InvalidArgumentException
00151      */
00152     public function setCompressionThrowsExceptionIfCompressionParameterIsNotOfTypeBoolean() {
00153         $this->setUpBackend(array('compression' => 'foo'));
00154     }
00155 
00156     /**
00157      * @test Functional
00158      * @author Christian Kuhn <lolli@schwarzbu.ch>
00159      * @expectedException InvalidArgumentException
00160      */
00161     public function setCompressionLevelThrowsExceptionIfCompressionLevelIsNotInteger() {
00162         $this->setUpBackend(array('compressionLevel' => 'foo'));
00163     }
00164 
00165     /**
00166      * @test Functional
00167      * @author Christian Kuhn <lolli@schwarzbu.ch>
00168      * @expectedException InvalidArgumentException
00169      */
00170     public function setCompressionLevelThrowsExceptionIfCompressionLevelIsNotBetweenMinusOneAndNine() {
00171         $this->setUpBackend(array('compressionLevel' => 11));
00172     }
00173 
00174     /**
00175      * @test Functional
00176      * @author Christian Kuhn <lolli@schwarzbu.ch>
00177      * @expectedException InvalidArgumentException
00178      */
00179     public function setThrowsExceptionIfIdentifierIsNotAString() {
00180         $this->setUpBackend();
00181         $this->backend->set(array(), 'data');
00182     }
00183 
00184     /**
00185      * @test Functional
00186      * @author Christian Kuhn <lolli@schwarzbu.ch>
00187      * @expectedException t3lib_cache_Exception_InvalidData
00188      */
00189     public function setThrowsExceptionIfDataIsNotAString() {
00190         $this->setUpBackend();
00191         $this->backend->set('identifier' . uniqid(), array());
00192     }
00193 
00194     /**
00195      * @test Functional
00196      * @author Christian Kuhn <lolli@schwarzbu.ch>
00197      * @expectedException InvalidArgumentException
00198      */
00199     public function setThrowsExceptionIfLifetimeIsNegative() {
00200         $this->setUpBackend();
00201         $this->backend->set('identifier' . uniqid(), 'data', array(), -42);
00202     }
00203 
00204     /**
00205      * @test Functional
00206      * @author Christian Kuhn <lolli@schwarzbu.ch>
00207      * @expectedException InvalidArgumentException
00208      */
00209     public function setThrowsExceptionIfLifetimeIsNotNullOrAnInteger() {
00210         $this->setUpBackend();
00211         $this->backend->set('identifier' . uniqid(), 'data', array(), array());
00212     }
00213 
00214     /**
00215      * @test Implementation
00216      * @author Christian Kuhn <lolli@schwarzbu.ch>
00217      */
00218     public function setStoresEntriesInSelectedDatabase() {
00219         $this->setUpRedis();
00220         $this->redis->select(1);
00221 
00222         $this->setUpBackend(array('database' => 1));
00223         $identifier = 'identifier' . uniqid();
00224         $this->backend->set($identifier, 'data');
00225 
00226         $this->assertTrue($this->redis->exists('identData:' . $identifier));
00227     }
00228 
00229     /**
00230      * @test Implementation
00231      * @author Christian Kuhn <lolli@schwarzbu.ch>
00232      */
00233     public function setSavesStringDataTypeForIdentifierToDataEntry() {
00234         $this->setUpBackend();
00235         $this->setUpRedis();
00236 
00237         $identifier = 'identifier' . uniqid();
00238         $this->backend->set($identifier, 'data');
00239 
00240         $this->assertSame(Redis::REDIS_STRING, $this->redis->type('identData:' . $identifier));
00241     }
00242 
00243     /**
00244      * @test Implementation
00245      * @author Christian Kuhn <lolli@schwarzbu.ch>
00246      */
00247     public function setSavesEntryWithDefaultLifeTime() {
00248         $this->setUpBackend();
00249         $this->setUpRedis();
00250 
00251         $identifier = 'identifier' . uniqid();
00252         $defaultLifetime = 42;
00253         $this->backend->setDefaultLifetime($defaultLifetime);
00254         $this->backend->set($identifier, 'data');
00255 
00256         $lifetimeRegisteredInBackend = $this->redis->ttl('identData:' . $identifier);
00257         $this->assertSame($defaultLifetime, $lifetimeRegisteredInBackend);
00258     }
00259 
00260     /**
00261      * @test Implementation
00262      * @author Christian Kuhn <lolli@schwarzbu.ch>
00263      */
00264     public function setSavesEntryWithSpecifiedLifeTime() {
00265         $this->setUpBackend();
00266         $this->setUpRedis();
00267 
00268         $identifier = 'identifier' . uniqid();
00269         $lifetime = 43;
00270         $this->backend->set($identifier, 'data', array(), $lifetime);
00271 
00272         $lifetimeRegisteredInBackend = $this->redis->ttl('identData:' . $identifier);
00273         $this->assertSame($lifetime, $lifetimeRegisteredInBackend);
00274     }
00275 
00276     /**
00277      * @test Implementation
00278      * @author Christian Kuhn <lolli@schwarzbu.ch>
00279      */
00280     public function setSavesEntryWithUnlimitedLifeTime() {
00281         $this->setUpBackend();
00282         $this->setUpRedis();
00283 
00284         $identifier = 'identifier' . uniqid();
00285         $this->backend->set($identifier, 'data', array(), 0);
00286 
00287         $lifetimeRegisteredInBackend = $this->redis->ttl('identData:' . $identifier);
00288         $this->assertSame(31536000, $lifetimeRegisteredInBackend);
00289     }
00290 
00291     /**
00292      * @test Functional
00293      * @author Christian Jul Jensen <julle@typo3.org>
00294      * @author Christian Kuhn <lolli@schwarzbu.ch>
00295      */
00296     public function setOverwritesExistingEntryWithNewData() {
00297         $this->setUpBackend();
00298         $data = 'data 1';
00299         $identifier = 'identifier' . uniqid();
00300         $this->backend->set($identifier, $data);
00301         $otherData = 'data 2';
00302         $this->backend->set($identifier, $otherData);
00303         $fetchedData = $this->backend->get($identifier);
00304         $this->assertSame($otherData, $fetchedData);
00305     }
00306 
00307     /**
00308      * @test Implementation
00309      * @author Christian Kuhn <lolli@schwarzbu.ch>
00310      */
00311     public function setOverwritesExistingEntryWithSpecifiedLifetime() {
00312         $this->setUpBackend();
00313         $this->setUpRedis();
00314 
00315         $data = 'data';
00316         $identifier = 'identifier' . uniqid();
00317         $this->backend->set($identifier, $data);
00318         $lifetime = 42;
00319         $this->backend->set($identifier, $data, array(), $lifetime);
00320 
00321         $lifetimeRegisteredInBackend = $this->redis->ttl('identData:' . $identifier);
00322         $this->assertSame($lifetime, $lifetimeRegisteredInBackend);
00323     }
00324 
00325     /**
00326      * @test Implementation
00327      * @author Christian Kuhn <lolli@schwarzbu.ch>
00328      */
00329     public function setOverwritesExistingEntryWithNewDefaultLifetime() {
00330         $this->setUpBackend();
00331         $this->setUpRedis();
00332 
00333         $data = 'data';
00334         $identifier = 'identifier' . uniqid();
00335         $lifetime = 42;
00336         $this->backend->set($identifier, $data, array(), $lifetime);
00337         $newDefaultLifetime = 43;
00338         $this->backend->setDefaultLifetime($newDefaultLifetime);
00339         $this->backend->set($identifier, $data, array(), $newDefaultLifetime);
00340 
00341         $lifetimeRegisteredInBackend = $this->redis->ttl('identData:' . $identifier);
00342         $this->assertSame($newDefaultLifetime, $lifetimeRegisteredInBackend);
00343     }
00344 
00345     /**
00346      * @test Implementation
00347      * @author Christian Kuhn <lolli@schwarzbu.ch>
00348      */
00349     public function setOverwritesExistingEntryWithNewUnlimitedLifetime() {
00350         $this->setUpBackend();
00351         $this->setUpRedis();
00352 
00353         $data = 'data';
00354         $identifier = 'identifier' . uniqid();
00355         $lifetime = 42;
00356         $this->backend->set($identifier, $data, array(), $lifetime);
00357         $this->backend->set($identifier, $data, array(), 0);
00358 
00359         $lifetimeRegisteredInBackend = $this->redis->ttl('identData:' . $identifier);
00360         $this->assertSame(31536000, $lifetimeRegisteredInBackend);
00361     }
00362 
00363     /**
00364      * @test Implementation
00365      * @author Christian Kuhn <lolli@schwarzbu.ch>
00366      */
00367     public function setSavesSetDataTypeForIdentifierToTagsSet() {
00368         $this->setUpBackend();
00369         $this->setUpRedis();
00370 
00371         $identifier = 'identifier' . uniqid();
00372         $this->backend->set($identifier, 'data', array('tag'));
00373 
00374         $this->assertSame(Redis::REDIS_SET, $this->redis->type('identTags:' . $identifier));
00375     }
00376 
00377     /**
00378      * @test Implementation
00379      * @author Christian Kuhn <lolli@schwarzbu.ch>
00380      */
00381     public function setSavesSpecifiedTagsInIdentifierToTagsSet() {
00382         $this->setUpBackend();
00383         $this->setUpRedis();
00384 
00385         $identifier = 'identifier' . uniqid();
00386         $tags = array('thatTag', 'thisTag');
00387         $this->backend->set($identifier, 'data', $tags);
00388 
00389         $savedTags = $this->redis->sMembers('identTags:' . $identifier);
00390         sort($savedTags);
00391         $this->assertSame($tags, $savedTags);
00392     }
00393 
00394     /**
00395      * @test Implementation
00396      * @author Christian Kuhn <lolli@schwarzbu.ch>
00397      */
00398     public function setRemovesAllPreviouslySetTagsFromIdentifierToTagsSet() {
00399         $this->setUpBackend();
00400         $this->setUpRedis();
00401 
00402         $identifier = 'identifier' . uniqid();
00403         $tags = array('fooTag', 'barTag');
00404         $this->backend->set($identifier, 'data', $tags);
00405         $this->backend->set($identifier, 'data', array());
00406 
00407         $this->assertSame(array(), $this->redis->sMembers('identTags:' . $identifier));
00408     }
00409 
00410     /**
00411      * @test Implementation
00412      * @author Christian Kuhn <lolli@schwarzbu.ch>
00413      */
00414     public function setRemovesMultiplePreviouslySetTagsFromIdentifierToTagsSet() {
00415         $this->setUpBackend();
00416         $this->setUpRedis();
00417 
00418         $identifier = 'identifier' . uniqid();
00419         $firstTagSet = array('tag1', 'tag2', 'tag3', 'tag4');
00420         $this->backend->set($identifier, 'data', $firstTagSet);
00421         $secondTagSet = array('tag1', 'tag3');
00422         $this->backend->set($identifier, 'data', $secondTagSet);
00423 
00424         $actualTagSet = $this->redis->sMembers('identTags:' . $identifier);
00425         sort($actualTagSet);
00426         $this->assertSame($secondTagSet, $actualTagSet);
00427     }
00428 
00429     /**
00430      * @test Implementation
00431      * @author Christian Kuhn <lolli@schwarzbu.ch>
00432      */
00433     public function setSavesSetDataTypeForTagToIdentifiersSet() {
00434         $this->setUpBackend();
00435         $this->setUpRedis();
00436 
00437         $identifier = 'identifier' . uniqid();
00438         $tag = 'tag';
00439         $this->backend->set($identifier, 'data', array($tag));
00440 
00441         $this->assertSame(Redis::REDIS_SET, $this->redis->type('tagIdents:' . $tag));
00442     }
00443 
00444     /**
00445      * @test Implementation
00446      * @author Christian Kuhn <lolli@schwarzbu.ch>
00447      */
00448     public function setSavesIdentifierInTagToIdentifiersSetOfSpecifiedTag() {
00449         $this->setUpBackend();
00450         $this->setUpRedis();
00451 
00452         $identifier = 'identifier' . uniqid();
00453         $tag = 'thisTag';
00454         $this->backend->set($identifier, 'data', array($tag));
00455 
00456         $savedTagToIdentifiersMemberArray = $this->redis->sMembers('tagIdents:' . $tag);
00457         $this->assertSame(array($identifier), $savedTagToIdentifiersMemberArray);
00458     }
00459 
00460     /**
00461      * @test Implementation
00462      * @author Christian Kuhn <lolli@schwarzbu.ch>
00463      */
00464     public function setAppendsSecondIdentifierInTagToIdentifiersEntry() {
00465         $this->setUpBackend();
00466         $this->setUpRedis();
00467 
00468         $firstIdentifier = 'identifier' . uniqid();
00469         $tag = 'thisTag';
00470         $this->backend->set($firstIdentifier, 'data', array($tag));
00471         $secondIdentifier = 'identifier' . uniqid();
00472         $this->backend->set($secondIdentifier, 'data', array($tag));
00473 
00474         $savedTagToIdentifiersMemberArray = $this->redis->sMembers('tagIdents:' . $tag);
00475         sort($savedTagToIdentifiersMemberArray);
00476         $identifierArray = array($firstIdentifier, $secondIdentifier);
00477         sort($identifierArray);
00478         $this->assertSame(array($firstIdentifier, $secondIdentifier), $savedTagToIdentifiersMemberArray);
00479     }
00480 
00481     /**
00482      * @test Implementation
00483      * @author Christian Kuhn <lolli@schwarzbu.ch>
00484      */
00485     public function setRemovesIdentifierFromTagToIdentifiersEntryIfTagIsOmittedOnConsecutiveSet() {
00486         $this->setUpBackend();
00487         $this->setUpRedis();
00488 
00489         $identifier = 'identifier' . uniqid();
00490         $tag = 'thisTag';
00491         $this->backend->set($identifier, 'data', array($tag));
00492         $this->backend->set($identifier, 'data', array());
00493 
00494         $savedTagToIdentifiersMemberArray = $this->redis->sMembers('tagIdents:' . $tag);
00495         $this->assertSame(array(), $savedTagToIdentifiersMemberArray);
00496     }
00497 
00498     /**
00499      * @test Implementation
00500      * @author Christian Kuhn <lolli@schwarzbu.ch>
00501      */
00502     public function setAddsIdentifierInTagToIdentifiersEntryIfTagIsAddedOnConsecutiveSet() {
00503         $this->setUpBackend();
00504         $this->setUpRedis();
00505 
00506         $identifier = 'identifier' . uniqid();
00507         $this->backend->set($identifier, 'data');
00508         $tag = 'thisTag';
00509         $this->backend->set($identifier, 'data', array($tag));
00510 
00511         $savedTagToIdentifiersMemberArray = $this->redis->sMembers('tagIdents:' . $tag);
00512         $this->assertSame(array($identifier), $savedTagToIdentifiersMemberArray);
00513     }
00514 
00515     /**
00516      * @test Implementation
00517      * @author Christian Kuhn <lolli@schwarzbu.ch>
00518      */
00519     public function setSavesCompressedDataWithEnabledCompression() {
00520         $this->setUpBackend(
00521             array(
00522                 'compression' => TRUE,
00523             )
00524         );
00525         $this->setUpRedis();
00526 
00527         $identifier = 'identifier' . uniqid();
00528         $data = 'some data ' . microtime();
00529         $this->backend->set($identifier, $data);
00530 
00531         $uncompresedStoredData = '';
00532         try {
00533             $uncompresedStoredData = @gzuncompress($this->redis->get('identData:' . $identifier));
00534         } catch (Exception $e) {
00535         }
00536 
00537         $this->assertEquals($data, $uncompresedStoredData, 'Original and compressed data don\'t match');
00538     }
00539 
00540     /**
00541      * @test Implementation
00542      * @author Christian Kuhn <lolli@schwarzbu.ch>
00543      */
00544     public function setSavesPlaintextDataWithEnabledCompressionAndCompressionLevel0() {
00545         $this->setUpBackend(
00546             array(
00547                 'compression' => TRUE,
00548                 'compressionLevel' => 0,
00549             )
00550         );
00551         $this->setUpRedis();
00552 
00553         $identifier = 'identifier' . uniqid();
00554         $data = 'some data ' . microtime();
00555         $this->backend->set($identifier, $data);
00556 
00557         $this->assertGreaterThan(0, substr_count($this->redis->get('identData:' . $identifier), $data), 'Plaintext data not found');
00558     }
00559 
00560     /**
00561      * @test Functional
00562      * @author Christian Kuhn <lolli@schwarzbu.ch>
00563      * @expectedException InvalidArgumentException
00564      */
00565     public function hasThrowsExceptionIfIdentifierIsNotAString() {
00566         $this->setUpBackend();
00567         $this->backend->has(array());
00568     }
00569 
00570     /**
00571      * @test Functional
00572      * @author Christian Kuhn <lolli@schwarzbu.ch>
00573      */
00574     public function hasReturnsFalseForNotExistingEntry() {
00575         $this->setUpBackend();
00576         $identifier = 'identifier' . uniqid();
00577         $this->assertFalse($this->backend->has($identifier));
00578     }
00579 
00580     /**
00581      * @test Functional
00582      * @author Christian Kuhn <lolli@schwarzbu.ch>
00583      */
00584     public function hasReturnsTrueForPreviouslySetEntry() {
00585         $this->setUpBackend();
00586         $identifier = 'identifier' . uniqid();
00587         $this->backend->set($identifier, 'data');
00588         $this->assertTrue($this->backend->has($identifier));
00589     }
00590 
00591     /**
00592      * @test Functional
00593      * @author Christian Kuhn <lolli@schwarzbu.ch>
00594      * @expectedException InvalidArgumentException
00595      */
00596     public function getThrowsExceptionIfIdentifierIsNotAString() {
00597         $this->setUpBackend();
00598         $this->backend->get(array());
00599     }
00600 
00601     /**
00602      * @test Functional
00603      * @author Christian Kuhn <lolli@schwarzbu.ch>
00604      */
00605     public function getReturnsPreviouslyCompressedSetEntry() {
00606         $this->setUpBackend(
00607             array(
00608                 'compression' => TRUE,
00609             )
00610         );
00611         $data = 'data';
00612         $identifier = 'identifier' . uniqid();
00613         $this->backend->set($identifier, $data);
00614         $fetchedData = $this->backend->get($identifier);
00615         $this->assertSame($data, $fetchedData);
00616     }
00617 
00618     /**
00619      * @test Functional
00620      * @author Christian Kuhn <lolli@schwarzbu.ch>
00621      */
00622     public function getReturnsPreviouslySetEntry() {
00623         $this->setUpBackend();
00624         $data = 'data';
00625         $identifier = 'identifier' . uniqid();
00626         $this->backend->set($identifier, $data);
00627         $fetchedData = $this->backend->get($identifier);
00628         $this->assertSame($data, $fetchedData);
00629     }
00630 
00631     /**
00632      * @test Functional
00633      * @author Christian Kuhn <lolli@schwarzbu.ch>
00634      * @expectedException InvalidArgumentException
00635      */
00636     public function removeThrowsExceptionIfIdentifierIsNotAString() {
00637         $this->setUpBackend();
00638         $this->backend->remove(array());
00639     }
00640 
00641     /**
00642      * @test Functional
00643      * @author Christian Kuhn <lolli@schwarzbu.ch>
00644      */
00645     public function removeReturnsFalseIfNoEntryWasDeleted() {
00646         $this->setUpBackend();
00647         $this->assertFalse($this->backend->remove('identifier' . uniqid()));
00648     }
00649 
00650     /**
00651      * @test Functional
00652      * @author Christian Kuhn <lolli@schwarzbu.ch>
00653      */
00654     public function removeReturnsTrueIfAnEntryWasDeleted() {
00655         $this->setUpBackend();
00656         $identifier = 'identifier' . uniqid();
00657         $this->backend->set($identifier, 'data');
00658         $this->assertTrue($this->backend->remove($identifier));
00659     }
00660 
00661     /**
00662      * @test Functional
00663      * @author Christian Jul Jensen <julle@typo3.org>
00664      * @author Christian Kuhn <lolli@schwarzbu.ch>
00665      */
00666     public function removeDeletesEntryFromCache() {
00667         $this->setUpBackend();
00668         $identifier = 'identifier' . uniqid();
00669         $this->backend->set($identifier, 'data');
00670         $this->backend->remove($identifier);
00671         $this->assertFalse($this->backend->has($identifier));
00672     }
00673 
00674     /**
00675      * @test Implementation
00676      * @author Christian Kuhn <lolli@schwarzbu.ch>
00677      */
00678     public function removeDeletesIdentifierToTagEntry() {
00679         $this->setUpBackend();
00680         $this->setUpRedis();
00681 
00682         $identifier = 'identifier' . uniqid();
00683         $tag = 'thisTag';
00684         $this->backend->set($identifier, 'data', array($tag));
00685         $this->backend->remove($identifier);
00686 
00687         $this->assertFalse($this->redis->exists('identTags:' . $identifier));
00688     }
00689 
00690     /**
00691      * @test Implementation
00692      * @author Christian Kuhn <lolli@schwarzbu.ch>
00693      */
00694     public function removeDeletesIdentifierFromTagToIdentifiersSet() {
00695         $this->setUpBackend();
00696         $this->setUpRedis();
00697 
00698         $identifier = 'identifier' . uniqid();
00699         $tag = 'thisTag';
00700         $this->backend->set($identifier, 'data', array($tag));
00701         $this->backend->remove($identifier);
00702 
00703         $tagToIdentifiersMemberArray = $this->redis->sMembers('tagIdents:' . $tag);
00704         $this->assertSame(array(), $tagToIdentifiersMemberArray);
00705     }
00706 
00707     /**
00708      * @test Implementation
00709      * @author Christian Kuhn <lolli@schwarzbu.ch>
00710      */
00711     public function removeDeletesIdentifierFromTagToIdentifiersSetWithMultipleEntries() {
00712         $this->setUpBackend();
00713         $this->setUpRedis();
00714 
00715         $firstIdentifier = 'identifier' . uniqid();
00716         $secondIdentifier = 'identifier' . uniqid();
00717         $tag = 'thisTag';
00718         $this->backend->set($firstIdentifier, 'data', array($tag));
00719         $this->backend->set($secondIdentifier, 'data', array($tag));
00720         $this->backend->remove($firstIdentifier);
00721 
00722         $tagToIdentifiersMemberArray = $this->redis->sMembers('tagIdents:' . $tag);
00723         $this->assertSame(array($secondIdentifier), $tagToIdentifiersMemberArray);
00724     }
00725 
00726     /**
00727      * @test Functional
00728      * @author Christian Kuhn <lolli@schwarzbu.ch>
00729      * @expectedException InvalidArgumentException
00730      */
00731     public function findIdentifiersByTagThrowsExceptionIfTagIsNotAString() {
00732         $this->setUpBackend();
00733         $this->backend->findIdentifiersByTag(array());
00734     }
00735 
00736     /**
00737      * @test Functional
00738      * @author Christian Kuhn <lolli@schwarzbu.ch>
00739      */
00740     public function findIdentifiersByTagReturnsEmptyArrayForNotExistingTag() {
00741         $this->setUpBackend();
00742         $this->assertSame(array(), $this->backend->findIdentifiersByTag('thisTag'));
00743     }
00744 
00745     /**
00746      * @test Functional
00747      * @author Christian Kuhn <lolli@schwarzbu.ch>
00748      */
00749     public function findIdentifiersByTagReturnsAllIdentifiersTagedWithSpecifiedTag() {
00750         $this->setUpBackend();
00751 
00752         $firstIdentifier = 'identifier' . uniqid();
00753         $secondIdentifier = 'identifier' . uniqid();
00754         $thirdIdentifier = 'identifier' . uniqid();
00755         $tagsForFirstIdentifier = array('thisTag');
00756         $tagsForSecondIdentifier = array('thatTag');
00757         $tagsForThirdIdentifier = array('thisTag', 'thatTag');
00758 
00759         $this->backend->set($firstIdentifier, 'data', $tagsForFirstIdentifier);
00760         $this->backend->set($secondIdentifier, 'data', $tagsForSecondIdentifier);
00761         $this->backend->set($thirdIdentifier, 'data', $tagsForThirdIdentifier);
00762 
00763         $expectedResult = array($firstIdentifier, $thirdIdentifier);
00764         $actualResult = $this->backend->findIdentifiersByTag('thisTag');
00765         sort($actualResult);
00766 
00767         $this->assertSame($expectedResult, $actualResult);
00768     }
00769 
00770     /**
00771      * @test Functional
00772      * @author Christian Kuhn <lolli@schwarzbu.ch>
00773      */
00774     public function findIdentifiersByTagsReturnEmptyArrayForNotExistingTag() {
00775         $this->setUpBackend();
00776         $this->assertEquals(array(), $this->backend->findIdentifiersByTags(array('thisTags')));
00777     }
00778 
00779     /**
00780      * @test Functional
00781      * @author Christian Kuhn <lolli@schwarzbu.ch>
00782      */
00783     public function findIdentifiersByTagsReturnsIdentifiersTaggedWithAllSpecifiedTags() {
00784         $this->setUpBackend();
00785 
00786         $identifier = 'identifier' . uniqid();
00787         $this->backend->set($identifier . 'A', 'data', array('tag1'));
00788         $this->backend->set($identifier . 'B', 'data', array('tag2'));
00789         $this->backend->set($identifier . 'C', 'data', array('tag1', 'tag2'));
00790         $this->backend->set($identifier . 'D', 'data', array('tag1', 'tag2', 'tag3'));
00791 
00792         $expectedResult = array($identifier . 'C', $identifier . 'D');
00793         $actualResult = $this->backend->findIdentifiersByTags(array('tag1', 'tag2'));
00794         sort($actualResult);
00795 
00796         $this->assertEquals($expectedResult, $actualResult);
00797     }
00798 
00799 
00800 
00801     /**
00802      * @test Implementation
00803      * @author Christian Kuhn <lolli@schwarzbu.ch>
00804      */
00805     public function flushRemovesAllEntriesFromCache() {
00806         $this->setUpBackend();
00807         $this->setUpRedis();
00808 
00809         $identifier = 'identifier' . uniqid();
00810         $this->backend->set($identifier, 'data');
00811         $this->backend->flush();
00812 
00813         $this->assertSame(array(), $this->redis->getKeys('*'));
00814     }
00815 
00816     /**
00817      * @test Functional
00818      * @author Christian Kuhn <lolli@schwarzbu.ch>
00819      * @expectedException InvalidArgumentException
00820      */
00821     public function flushByTagThrowsExceptionIfTagIsNotAString() {
00822         $this->setUpBackend();
00823         $this->backend->flushByTag(array());
00824     }
00825 
00826     /**
00827      * @test Functional
00828      * @author Christian Kuhn <lolli@schwarzbu.ch>
00829      */
00830     public function flushByTagRemovesEntriesTaggedWithSpecifiedTag() {
00831         $this->setUpBackend();
00832 
00833         $identifier = 'identifier' . uniqid();
00834         $this->backend->set($identifier . 'A', 'data', array('tag1'));
00835         $this->backend->set($identifier . 'B', 'data', array('tag2'));
00836         $this->backend->set($identifier . 'C', 'data', array('tag1', 'tag2'));
00837         $this->backend->flushByTag('tag1');
00838 
00839         $expectedResult = array(FALSE, TRUE, FALSE);
00840         $actualResult = array(
00841             $this->backend->has($identifier . 'A'),
00842             $this->backend->has($identifier . 'B'),
00843             $this->backend->has($identifier . 'C'),
00844         );
00845         $this->assertSame($expectedResult, $actualResult);
00846     }
00847 
00848     /**
00849      * @test Implementation
00850      * @author Christian Kuhn <lolli@schwarzbu.ch>
00851      */
00852     public function flushByTagRemovesTemporarySet() {
00853         $this->setUpBackend();
00854         $this->setUpRedis();
00855 
00856         $identifier = 'identifier' . uniqid();
00857         $this->backend->set($identifier . 'A', 'data', array('tag1'));
00858         $this->backend->set($identifier . 'C', 'data', array('tag1', 'tag2'));
00859         $this->backend->flushByTag('tag1');
00860 
00861         $this->assertSame(array(), $this->redis->getKeys('temp*'));
00862     }
00863 
00864     /**
00865      * @test Implementation
00866      * @author Christian Kuhn <lolli@schwarzbu.ch>
00867      */
00868     public function flushByTagRemovesIdentifierToTagsSetOfEntryTaggedWithGivenTag() {
00869         $this->setUpBackend();
00870         $this->setUpRedis();
00871 
00872         $identifier = 'identifier' . uniqid();
00873         $tag = 'tag1';
00874         $this->backend->set($identifier, 'data', array($tag));
00875         $this->backend->flushByTag($tag);
00876 
00877         $this->assertFalse($this->redis->exists('identTags:' . $identifier));
00878     }
00879 
00880     /**
00881      * @test Implementation
00882      * @author Christian Kuhn <lolli@schwarzbu.ch>
00883      */
00884     public function flushByTagDoesNotRemoveIdentifierToTagsSetOfUnrelatedEntry() {
00885         $this->setUpBackend();
00886         $this->setUpRedis();
00887 
00888         $identifierToBeRemoved = 'identifier' . uniqid();
00889         $tagToRemove = 'tag1';
00890         $this->backend->set($identifierToBeRemoved, 'data', array($tagToRemove));
00891 
00892         $identifierNotToBeRemoved = 'identifier' . uniqid();
00893         $tagNotToRemove = 'tag2';
00894         $this->backend->set($identifierNotToBeRemoved, 'data', array($tagNotToRemove));
00895 
00896         $this->backend->flushByTag($tagToRemove);
00897 
00898         $this->assertSame(array($tagNotToRemove), $this->redis->sMembers('identTags:' . $identifierNotToBeRemoved));
00899     }
00900 
00901     /**
00902      * @test Implementation
00903      * @author Christian Kuhn <lolli@schwarzbu.ch>
00904      */
00905     public function flushByTagRemovesTagToIdentifiersSetOfGivenTag() {
00906         $this->setUpBackend();
00907         $this->setUpRedis();
00908 
00909         $identifier = 'identifier' . uniqid();
00910         $tag = 'tag1';
00911         $this->backend->set($identifier, 'data', array($tag));
00912         $this->backend->flushByTag($tag);
00913 
00914         $this->assertFalse($this->redis->exists('tagIdents:' . $tag));
00915     }
00916 
00917     /**
00918      * @test Implementation
00919      * @author Christian Kuhn <lolli@schwarzbu.ch>
00920      */
00921     public function flushByTagRemovesIdentifiersTaggedWithGivenTagFromTagToIdentifiersSets() {
00922         $this->setUpBackend();
00923         $this->setUpRedis();
00924 
00925         $identifier = 'identifier' . uniqid();
00926         $this->backend->set($identifier . 'A', 'data', array('tag1', 'tag2'));
00927         $this->backend->set($identifier . 'B', 'data', array('tag1', 'tag2'));
00928         $this->backend->set($identifier . 'C', 'data', array('tag2'));
00929 
00930         $this->backend->flushByTag('tag1');
00931 
00932         $this->assertSame(array($identifier . 'C'), $this->redis->sMembers('tagIdents:tag2'));
00933     }
00934 
00935     /**
00936      * @test Implementation
00937      * @author Christian Kuhn <lolli@schwarzbu.ch>
00938      */
00939     public function flushByTagsRemovesEntriesTaggedWithSpecifiedTags() {
00940         $this->setUpBackend();
00941 
00942         $identifier = 'identifier' . uniqid();
00943         $this->backend->set($identifier . 'A', 'data', array('tag1'));
00944         $this->backend->set($identifier . 'B', 'data', array('tag2'));
00945         $this->backend->set($identifier . 'C', 'data', array('tag3'));
00946         $this->backend->set($identifier . 'D', 'data', array('tag1', 'tag2'));
00947         $this->backend->set($identifier . 'E', 'data', array('tag1', 'tag3'));
00948         $this->backend->flushByTags(array('tag1', 'tag2'));
00949 
00950         $expectedResult = array(FALSE, FALSE, TRUE, FALSE, FALSE);
00951         $actualResult = array(
00952             $this->backend->has($identifier . 'A'),
00953             $this->backend->has($identifier . 'B'),
00954             $this->backend->has($identifier . 'C'),
00955             $this->backend->has($identifier . 'D'),
00956             $this->backend->has($identifier . 'E'),
00957         );
00958 
00959         $this->assertEquals($expectedResult, $actualResult);
00960     }
00961 
00962     /**
00963      * @test Implementation
00964      * @author Christian Kuhn <lolli@schwarzbu.ch>
00965      */
00966     public function flushByTagsRemovesIdentifierToTagsSetOfEntriesTaggedWithGivenTags() {
00967         $this->setUpBackend();
00968         $this->setUpRedis();
00969 
00970         $identifier = 'identifier' . uniqid();
00971         $this->backend->set($identifier . 'A', 'data', array('tag1', 'tag2'));
00972         $this->backend->set($identifier . 'B', 'data', array('tag1', 'tag3'));
00973         $this->backend->set($identifier . 'C', 'data', array('tag2', 'tag4'));
00974         $this->backend->set($identifier . 'D', 'data', array('tag3', 'tag4'));
00975 
00976         $this->backend->flushByTags(array('tag1', 'tag2'));
00977 
00978         $expectedResult = array(FALSE, FALSE, FALSE, TRUE);
00979         $actualResult = array(
00980             $this->redis->exists('identTags:' . $identifier . 'A'),
00981             $this->redis->exists('identTags:' . $identifier . 'B'),
00982             $this->redis->exists('identTags:' . $identifier . 'C'),
00983             $this->redis->exists('identTags:' . $identifier . 'D'),
00984         );
00985 
00986         $this->assertEquals($expectedResult, $actualResult);
00987     }
00988 
00989     /**
00990      * @test Implementation
00991      * @author Christian Kuhn <lolli@schwarzbu.ch>
00992      */
00993     public function flushByTagsRemovesTagToIdentifiersSetsOfGivenTags() {
00994         $this->setUpBackend();
00995         $this->setUpRedis();
00996 
00997         $identifier = 'identifier' . uniqid();
00998         $this->backend->set($identifier . 'A', 'data', array('tag1', 'tag2'));
00999         $this->backend->set($identifier . 'B', 'data', array('tag1', 'tag3'));
01000         $this->backend->set($identifier . 'C', 'data', array('tag2', 'tag4'));
01001         $this->backend->set($identifier . 'D', 'data', array('tag3', 'tag4'));
01002 
01003         $this->backend->flushByTags(array('tag1', 'tag2'));
01004 
01005         $expectedResult = array(FALSE, FALSE, TRUE, TRUE);
01006         $actualResult = array(
01007             $this->redis->exists('tagIdents:tag1'),
01008             $this->redis->exists('tagIdents:tag2'),
01009             $this->redis->exists('tagIdents:tag3'),
01010             $this->redis->exists('tagIdents:tag4'),
01011         );
01012 
01013         $this->assertEquals($expectedResult, $actualResult);
01014     }
01015 
01016     /**
01017      * @test Implementation
01018      * @author Christian Kuhn <lolli@schwarzbu.ch>
01019      */
01020     public function flushByTagsRemovesIdentifiersTaggedWithGivenTagsFromTagToIdentifiersSets() {
01021         $this->setUpBackend();
01022         $this->setUpRedis();
01023 
01024         $identifier = 'identifier' . uniqid();
01025         $this->backend->set('A' . $identifier, 'data', array('tag1', 'tag2'));
01026         $this->backend->set('B' . $identifier, 'data', array('tag1', 'tag3'));
01027         $this->backend->set('C' . $identifier, 'data', array('tag3', 'tag4'));
01028         $this->backend->set('D' . $identifier, 'data', array('tag3', 'tag4', 'tag5'));
01029 
01030         $this->backend->flushByTags(array('tag1', 'tag2'));
01031 
01032         $expectedResult = array(
01033             array('C' . $identifier, 'D' . $identifier),
01034             array('C' . $identifier, 'D' . $identifier),
01035             array('D' . $identifier),
01036         );
01037 
01038         $tag3Identifiers = $this->redis->sMembers('tagIdents:tag3');
01039         $tag4Identifiers = $this->redis->sMembers('tagIdents:tag4');
01040         $tag5Identifiers = $this->redis->sMembers('tagIdents:tag5');
01041         sort($tag3Identifiers);
01042         sort($tag4Identifiers);
01043 
01044         $actualResult = array(
01045             $tag3Identifiers,
01046             $tag4Identifiers,
01047             $tag5Identifiers,
01048         );
01049 
01050         $this->assertEquals($expectedResult, $actualResult);
01051     }
01052 
01053     /**
01054      * @test Implementation
01055      * @author Christian Kuhn <lolli@schwarzbu.ch>
01056      */
01057     public function collectGarbageDoesNotRemoveNotExpiredIdentifierToDataEntry() {
01058         $this->setUpBackend();
01059         $this->setUpRedis();
01060 
01061         $identifier = 'identifier' . uniqid();
01062         $this->backend->set($identifier . 'A', 'data', array('tag'));
01063         $this->backend->set($identifier . 'B', 'data', array('tag'));
01064 
01065         $this->redis->delete('identData:' . $identifier . 'A');
01066 
01067         $this->backend->collectGarbage();
01068 
01069         $this->assertTrue($this->redis->exists('identData:' . $identifier . 'B'));
01070     }
01071 
01072     /**
01073      * @test Implementation
01074      * @author Christian Kuhn <lolli@schwarzbu.ch>
01075      */
01076     public function collectGarbageRemovesLeftOverIdentifierToTagsSet() {
01077         $this->setUpBackend();
01078         $this->setUpRedis();
01079 
01080         $identifier = 'identifier' . uniqid();
01081         $this->backend->set($identifier . 'A', 'data', array('tag'));
01082         $this->backend->set($identifier . 'B', 'data', array('tag'));
01083 
01084         $this->redis->delete('identData:' . $identifier . 'A');
01085 
01086         $this->backend->collectGarbage();
01087 
01088         $expectedResult = array(FALSE, TRUE);
01089         $actualResult = array(
01090             $this->redis->exists('identTags:' . $identifier . 'A'),
01091             $this->redis->exists('identTags:' . $identifier . 'B'),
01092         );
01093         $this->assertSame($expectedResult, $actualResult);
01094     }
01095 
01096     /**
01097      * @test Implementation
01098      * @author Christian Kuhn <lolli@schwarzbu.ch>
01099      */
01100     public function collectGarbageRemovesExpiredIdentifierFromTagsToIdentifierSet() {
01101         $this->setUpBackend();
01102         $this->setUpRedis();
01103 
01104         $identifier = 'identifier' . uniqid();
01105         $this->backend->set($identifier . 'A', 'data', array('tag1', 'tag2'));
01106         $this->backend->set($identifier . 'B', 'data', array('tag2'));
01107 
01108         $this->redis->delete('identData:' . $identifier . 'A');
01109 
01110         $this->backend->collectGarbage();
01111 
01112         $expectedResult = array(
01113             array(),
01114             array($identifier . 'B')
01115         );
01116         $actualResult = array(
01117             $this->redis->sMembers('tagIdents:tag1'),
01118             $this->redis->sMembers('tagIdents:tag2'),
01119         );
01120         $this->assertSame($expectedResult, $actualResult);
01121     }
01122 }
01123 ?>