Skip to content
Snippets Groups Projects
Commit 3e7c4ddd authored by Daniel Hürtgen's avatar Daniel Hürtgen
Browse files

FEATURE: PhpRedisLock implementing the LockExpirationInterface

parent bdf36ed8
Branches
No related merge requests found
Pipeline #362 failed with stages
in 16 seconds
...@@ -25,6 +25,11 @@ ...@@ -25,6 +25,11 @@
"issues": "https://git.higidi.com/higidi/ninja-mutex/issues", "issues": "https://git.higidi.com/higidi/ninja-mutex/issues",
"source": "https://git.higidi.com/higidi/ninja-mutex" "source": "https://git.higidi.com/higidi/ninja-mutex"
}, },
"autoload": {
"psr-4": {
"Higidi\\NinjaMutex\\": "src/"
}
},
"autoload-dev": { "autoload-dev": {
"psr-4": { "psr-4": {
"Higidi\\NinjaMutex\\Tests\\": "tests/" "Higidi\\NinjaMutex\\Tests\\": "tests/"
...@@ -36,6 +41,7 @@ ...@@ -36,6 +41,7 @@
}, },
"require-dev": { "require-dev": {
"squizlabs/php_codesniffer": "^2.9||^3.0", "squizlabs/php_codesniffer": "^2.9||^3.0",
"phpunit/phpunit": "^4.5||^5.0.5" "phpunit/phpunit": "^4.5||^5.0.5",
"ext-redis": "*"
} }
} }
...@@ -10,6 +10,12 @@ ...@@ -10,6 +10,12 @@
syntaxCheck="false" syntaxCheck="false"
bootstrap="tests/bootstrap.php"> bootstrap="tests/bootstrap.php">
<testsuites>
<testsuite name="Unit Tests">
<directory>./tests/Unit/</directory>
</testsuite>
</testsuites>
<filter> <filter>
<whitelist> <whitelist>
<directory>./src/</directory> <directory>./src/</directory>
......
<?php
namespace Higidi\NinjaMutex\Lock;
use NinjaMutex\Lock\LockExpirationInterface;
use NinjaMutex\Lock\PhpRedisLock as BasePhpRedisLock;
/**
* Lock implementation using PHPRedis and allow expiration of locks.
*/
class PhpRedisLock extends BasePhpRedisLock implements LockExpirationInterface
{
/**
* @var int
*/
protected $expiration = 0;
/**
* @param int $expiration
*
* @return mixed
*/
public function setExpiration($expiration)
{
$expiration = (int)$expiration;
if ($expiration < 0) {
return null;
}
$this->expiration = $expiration;
}
/**
* @param string $name
* @param bool $blocking
*
* @return bool
*/
protected function getLock($name, $blocking)
{
$isLocked = parent::getLock($name, $blocking);
if ($isLocked && $this->expiration) {
$this->client->expireAt($name, $this->expiration);
}
return $isLocked;
}
/**
* @param string $name
*
* @return bool
*/
public function clearLock($name)
{
if (!isset($this->locks[$name])) {
return false;
}
unset($this->locks[$name]);
return true;
}
}
<?php
namespace Higidi\NinjaMutex\Tests\Unit\Lock\PhpRedisLock;
use Higidi\NinjaMutex\Lock\PhpRedisLock;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
/**
* Test case for "\Higidi\NinjaMutex\Lock\PhpRedisLock".
*
* @covers \Higidi\NinjaMutex\Lock\PhpRedisLock
*/
class PhpRedisLockTest extends TestCase
{
/**
* @test
*/
public function itImplementsTheLockExpirationInterface()
{
$client = $this->prophesize('\Redis');
$sut = new PhpRedisLock($client->reveal());
$this->assertInstanceOf('\NinjaMutex\Lock\LockExpirationInterface', $sut);
}
/**
* @test
*/
public function itSetsTheKeyExpirationAsExpected()
{
$name = 'blafoo';
$expireAt = time();
$client = $this->prophesize('\Redis');
$client
->setnx($name, Argument::type('string'))
->willReturn(true);
$client
->expireAt($name, $expireAt)
->shouldBeCalled()
->willReturn(true);
$client
->del($name)
->willReturn(true);
$sut = new PhpRedisLock($client->reveal());
$sut->setExpiration($expireAt);
$isLocked = $sut->acquireLock($name);
$this->assertTrue($isLocked);
}
/**
* @test
*/
public function itSetsTheKeyExpirationOnlyIfSet()
{
$name = 'blafoo';
$client = $this->prophesize('\Redis');
$client
->setnx($name, Argument::type('string'))
->willReturn(true);
$client
->expireAt($name, Argument::type('int'))
->shouldNotBeCalled();
$client
->del($name)
->willReturn(true);
$sut = new PhpRedisLock($client->reveal());
$isLocked = $sut->acquireLock($name);
$this->assertTrue($isLocked);
}
/**
* @test
*/
public function itAccecptsOnlyExpirationsGreaterThanOrEqualsZero()
{
$name = 'blafoo';
$expireAt = -1;
$client = $this->prophesize('\Redis');
$client
->setnx($name, Argument::type('string'))
->willReturn(true);
$client
->expireAt($name, Argument::type('int'))
->shouldNotBeCalled();
$client
->del($name)
->willReturn(true);
$sut = new PhpRedisLock($client->reveal());
$sut->setExpiration($expireAt);
$isLocked = $sut->acquireLock($name);
$this->assertTrue($isLocked);
}
/**
* @test
*/
public function itCanClearLocksWithoutReleasingThem()
{
$name = 'blafoo';
$client = $this->prophesize('\Redis');
$client
->setnx($name, Argument::type('string'))
->willReturn(true);
$client
->del($name)
->shouldNotBeCalled();
$sut = new PhpRedisLock($client->reveal());
$isLocked = $sut->acquireLock($name);
$this->assertTrue($isLocked);
$this->assertTrue($sut->clearLock($name));
$this->assertFalse($sut->releaseLock($name));
}
/**
* @test
*/
public function itClearLocksOnlyIfAcquired()
{
$name = 'blafoo';
$client = $this->prophesize('\Redis');
$client
->del($name)
->shouldNotBeCalled();
$sut = new PhpRedisLock($client->reveal());
$this->assertFalse($sut->clearLock($name));
$this->assertFalse($sut->releaseLock($name));
}
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment