* * 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:----hiw34fUiBdqhLR/POph50y7JTjd8wIVj7b9EULpGGt6ddgREs+64qc0Q06wttFlaJ1wptnra7XC7QkGnMXoa14xHoeCyXzlFwGZM903kUOVfrES5i5u8MU/wG6GUV5hAJEN7bvF6QPym+/sGyZuguP1G1zifMpXb1C8TBajL8KX7LKo+YGZYdptqlZkWKz2U7xG5divmPciIQSv7JFZR5rRdF7zDfHdpcQKKh8dphRDGDhddJZ2uVHqL0rYdjYFRpc4rzc6I+F25F4W8WnG0odv+p7HjCYQUNUTenWLK3u4p3U9HxRqQF1K+mqovDU9t4ZIXWYlJJsRVKP5x67DsUWZ6jKsbT8xI8W89Gpa5xm26v6y6BCvQP1vn7dsnpoq9CZ8/bj4peOoqx2MawYP2FTEgUl9iHTg7jZOKjY3olFOzlq1amqsPfvYRhbR+y4eGCV1hAGrXq6XS/s/kDY8PJuBgkW0HrFBU7cxyPu5se6yohzzm/lD+RIHzUMzX+0VqnSNemkh42fVYGQ+DNRk09AzDDf7I601IUOWYCPyiCy5c35cEoE19xOLItXeVsbci+vkxh2aR31CQYlMJv8XNjLrPpQ2lgFloQRdI43FVj3U4/6DaeWGn7Y9a+PFsPn23kowGNZmq3KKNi/Fzo9bidF+S1dUB7AwFvJ48tGWSEoo=----ATTACHMENT:----MTA5MDgyMjY4NjE4MzcyMCA2ODY5NzcxMTEzNzU4NTE2IDEyMDM2NDk2MjAyNjAwMjY=