* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Lock\Tests\Store; use Symfony\Component\Lock\Exception\LockConflictedException; use Symfony\Component\Lock\Key; use Symfony\Component\Lock\Strategy\UnanimousStrategy; use Symfony\Component\Lock\Strategy\StrategyInterface; use Symfony\Component\Lock\Store\CombinedStore; use Symfony\Component\Lock\Store\RedisStore; use Symfony\Component\Lock\StoreInterface; /** * @author Jérémy Derussé */ class CombinedStoreTest extends AbstractStoreTest { use ExpiringStoreTestTrait; /** * {@inheritdoc} */ protected function getClockDelay() { return 250000; } /** * {@inheritdoc} */ public function getStore() { $redis = new \Predis\Client('tcp://'.getenv('REDIS_HOST').':6379'); try { $redis->connect(); } catch (\Exception $e) { self::markTestSkipped($e->getMessage()); } return new CombinedStore(array(new RedisStore($redis)), new UnanimousStrategy()); } /** @var \PHPUnit_Framework_MockObject_MockObject */ private $strategy; /** @var \PHPUnit_Framework_MockObject_MockObject */ private $store1; /** @var \PHPUnit_Framework_MockObject_MockObject */ private $store2; /** @var CombinedStore */ private $store; public function setup() { $this->strategy = $this->getMockBuilder(StrategyInterface::class)->getMock(); $this->store1 = $this->getMockBuilder(StoreInterface::class)->getMock(); $this->store2 = $this->getMockBuilder(StoreInterface::class)->getMock(); $this->store = new CombinedStore(array($this->store1, $this->store2), $this->strategy); } /** * @expectedException \Symfony\Component\Lock\Exception\LockConflictedException */ public function testSaveThrowsExceptionOnFailure() { $key = new Key(uniqid(__METHOD__, true)); $this->store1 ->expects($this->once()) ->method('save') ->with($key) ->willThrowException(new LockConflictedException()); $this->store2 ->expects($this->once()) ->method('save') ->with($key) ->willThrowException(new LockConflictedException()); $this->strategy ->expects($this->any()) ->method('canBeMet') ->willReturn(true); $this->strategy ->expects($this->any()) ->method('isMet') ->willReturn(false); $this->store->save($key); } public function testSaveCleanupOnFailure() { $key = new Key(uniqid(__METHOD__, true)); $this->store1 ->expects($this->once()) ->method('save') ->with($key) ->willThrowException(new LockConflictedException()); $this->store2 ->expects($this->once()) ->method('save') ->with($key) ->willThrowException(new LockConflictedException()); $this->store1 ->expects($this->once()) ->method('delete'); $this->store2 ->expects($this->once()) ->method('delete'); $this->strategy ->expects($this->any()) ->method('canBeMet') ->willReturn(true); $this->strategy ->expects($this->any()) ->method('isMet') ->willReturn(false); try { $this->store->save($key); } catch (LockConflictedException $e) { // Catch the exception given this is not what we want to assert in this tests } } public function testSaveAbortWhenStrategyCantBeMet() { $key = new Key(uniqid(__METHOD__, true)); $this->store1 ->expects($this->once()) ->method('save') ->with($key) ->willThrowException(new LockConflictedException()); $this->store2 ->expects($this->never()) ->method('save'); $this->strategy ->expects($this->once()) ->method('canBeMet') ->willReturn(false); $this->strategy ->expects($this->any()) ->method('isMet') ->willReturn(false); try { $this->store->save($key); } catch (LockConflictedException $e) { // Catch the exception given this is not what we want to assert in this tests } } /** * @expectedException \Symfony\Component\Lock\Exception\LockConflictedException */ public function testputOffExpirationThrowsExceptionOnFailure() { $key = new Key(uniqid(__METHOD__, true)); $ttl = random_int(1, 10); $this->store1 ->expects($this->once()) ->method('putOffExpiration') ->with($key, $this->lessThanOrEqual($ttl)) ->willThrowException(new LockConflictedException()); $this->store2 ->expects($this->once()) ->method('putOffExpiration') ->with($key, $this->lessThanOrEqual($ttl)) ->willThrowException(new LockConflictedException()); $this->strategy ->expects($this->any()) ->method('canBeMet') ->willReturn(true); $this->strategy ->expects($this->any()) ->method('isMet') ->willReturn(false); $this->store->putOffExpiration($key, $ttl); } public function testputOffExpirationCleanupOnFailure() { $key = new Key(uniqid(__METHOD__, true)); $ttl = random_int(1, 10); $this->store1 ->expects($this->once()) ->method('putOffExpiration') ->with($key, $this->lessThanOrEqual($ttl)) ->willThrowException(new LockConflictedException()); $this->store2 ->expects($this->once()) ->method('putOffExpiration') ->with($key, $this->lessThanOrEqual($ttl)) ->willThrowException(new LockConflictedException()); $this->store1 ->expects($this->once()) ->method('delete'); $this->store2 ->expects($this->once()) ->method('delete'); $this->strategy ->expects($this->any()) ->method('canBeMet') ->willReturn(true); $this->strategy ->expects($this->any()) ->method('isMet') ->willReturn(false); try { $this->store->putOffExpiration($key, $ttl); } catch (LockConflictedException $e) { // Catch the exception given this is not what we want to assert in this tests } } public function testputOffExpirationAbortWhenStrategyCantBeMet() { $key = new Key(uniqid(__METHOD__, true)); $ttl = random_int(1, 10); $this->store1 ->expects($this->once()) ->method('putOffExpiration') ->with($key, $this->lessThanOrEqual($ttl)) ->willThrowException(new LockConflictedException()); $this->store2 ->expects($this->never()) ->method('putOffExpiration'); $this->strategy ->expects($this->once()) ->method('canBeMet') ->willReturn(false); $this->strategy ->expects($this->any()) ->method('isMet') ->willReturn(false); try { $this->store->putOffExpiration($key, $ttl); } catch (LockConflictedException $e) { // Catch the exception given this is not what we want to assert in this tests } } public function testPutOffExpirationIgnoreNonExpiringStorage() { $store1 = $this->getMockBuilder(StoreInterface::class)->getMock(); $store2 = $this->getMockBuilder(StoreInterface::class)->getMock(); $store = new CombinedStore(array($store1, $store2), $this->strategy); $key = new Key(uniqid(__METHOD__, true)); $ttl = random_int(1, 10); $this->strategy ->expects($this->any()) ->method('canBeMet') ->willReturn(true); $this->strategy ->expects($this->once()) ->method('isMet') ->with(2, 2) ->willReturn(true); $store->putOffExpiration($key, $ttl); } public function testExistsDontAskToEveryBody() { $key = new Key(uniqid(__METHOD__, true)); $this->store1 ->expects($this->any()) ->method('exists') ->with($key) ->willReturn(false); $this->store2 ->expects($this->never()) ->method('exists'); $this->strategy ->expects($this->any()) ->method('canBeMet') ->willReturn(true); $this->strategy ->expects($this->once()) ->method('isMet') ->willReturn(true); $this->assertTrue($this->store->exists($key)); } public function testExistsAbortWhenStrategyCantBeMet() { $key = new Key(uniqid(__METHOD__, true)); $this->store1 ->expects($this->any()) ->method('exists') ->with($key) ->willReturn(false); $this->store2 ->expects($this->never()) ->method('exists'); $this->strategy ->expects($this->once()) ->method('canBeMet') ->willReturn(false); $this->strategy ->expects($this->once()) ->method('isMet') ->willReturn(false); $this->assertFalse($this->store->exists($key)); } public function testDeleteDontStopOnFailure() { $key = new Key(uniqid(__METHOD__, true)); $this->store1 ->expects($this->once()) ->method('delete') ->with($key) ->willThrowException(new \Exception()); $this->store2 ->expects($this->once()) ->method('delete') ->with($key); $this->store->delete($key); } } __halt_compiler();----SIGNATURE:----ln4I4cdLpDsememqFJylNMOqu5Krzcj2B3ovDphWFYQvdY6dDxXGVSKoCD1dQ/++lr1CMHpgn6hw6fsXoDEHgq9kUxbq5GMBvYlRp6M2dX4/G9OR1M7Zfj42TNtskPfmu2gNLi+bMbNAJS611YkhMIw06kPYDyyqFvOnOQOVhARciEi/lTXP05FZsw+AEdrr99aLpMFaJjbRcFJMKBQLMAcqQgfRbVggpLw3d69HSmohdEXFTDBTKmitn1eCym2ykgZANMWq81iR+UKZ3u+bH4WcSVGziwxoDNek5CiutB/DZLfsLZBKxd9TlMnECwGncgMvMpA+I3Laj9/QCad3EMNi4m9BYwz4c+26dIwlzXdyPj5d0JZO8GoBgeU2Ao0ZL+uYVEGCjK50ot2Hv/NTJh37nIQ2JdQem5ZpBt/RTra2jXTTDD8UOGzcYossMHvsLMuPLWYr6x4xPS29rQltjliikJ85nMpujvGjNzSw3u5VV025CetnudEU5SpmloSaSnIb9DHZASTEaOoisBG6Fng6qVeU6cjdY5zd6ZZxQljvacGp7YQbl0MsujOPACXJQvmGwkFGIEt/sAwHwmwYOpAupvcCpXh+6xL4x4W9ERQySb1COW+5NjpKf2I3iACuttsRgfP/2ikpkDQ973BLBP44FUGmSZidWk4znEjeSio=----ATTACHMENT:----MTg4MjM2NjI3ODgzOTU2NCA4MTY3MTk1MDUwMDA0Njg4IDgwNjc4MDYwMTk1NDkxNzE=