diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..9866c39
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,11 @@
+# editorconfig.org
+
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+indent_style = space
+indent_size = 4
+trim_trailing_whitespace = true
diff --git a/.gitattributes b/.gitattributes
index bdd4ea2..b7404a3 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1 +1,10 @@
-/tests export-ignore
\ No newline at end of file
+/.github export-ignore
+/.gitattributes export-ignore
+/.gitignore export-ignore
+/phpunit.xml.dist export-ignore
+/tests export-ignore
+/.editorconfig export-ignore
+/.php_cs.dist.php export-ignore
+/psalm.xml export-ignore
+/psalm.xml.dist export-ignore
+/UPGRADING.md export-ignore
diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml
index c592f27..4eabb1b 100644
--- a/.github/workflows/phpunit.yml
+++ b/.github/workflows/phpunit.yml
@@ -1,7 +1,7 @@
on:
push:
branches:
- - master
+ - 1.*
name: phpunit
diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml
index 75c416b..78a4b26 100644
--- a/.github/workflows/psalm.yml
+++ b/.github/workflows/psalm.yml
@@ -1,7 +1,7 @@
on:
push:
branches:
- - master
+ - 1.*
name: static analysis
diff --git a/.gitignore b/.gitignore
index 43c585d..1a6ed30 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,21 +1,11 @@
-# IDEA
-.idea/
-*.iml
-
-# Composer
-composer.phar
-vendor
-composer.lock
-
-# OS
-.DS_Store
-Thumbs.db
-*.exe
-
-# Other
-.phpunit.result.cache
+.idea
+.php_cs
.php_cs.cache
-clover.xml
-.env
-builds
-
+.phpunit.result.cache
+build
+composer.lock
+coverage
+docs
+vendor
+node_modules
+.php-cs-fixer.cache
diff --git a/.styleci.yml b/.styleci.yml
new file mode 100644
index 0000000..6fde134
--- /dev/null
+++ b/.styleci.yml
@@ -0,0 +1,73 @@
+preset: psr12
+risky: true
+
+version: 8
+
+enabled:
+ - alpha_ordered_traits
+ - array_indentation
+ - array_push
+ - combine_consecutive_issets
+ - combine_consecutive_unsets
+ - combine_nested_dirname
+ - declare_strict_types
+ - dir_constant
+ - fully_qualified_strict_types
+ - function_to_constant
+ - is_null
+ - magic_constant_casing
+ - magic_method_casing
+ - method_separation
+ - modernize_types_casting
+ - native_function_casing
+ - native_function_type_declaration_casing
+ - no_alias_functions
+ - no_empty_comment
+ - no_empty_phpdoc
+ - no_empty_statement
+ - no_extra_block_blank_lines
+ - no_short_bool_cast
+ - no_superfluous_elseif
+ - no_unneeded_control_parentheses
+ - no_unneeded_curly_braces
+ - no_unneeded_final_method
+ - no_unset_cast
+ - no_unused_imports
+ - no_unused_lambda_imports
+ - no_useless_else
+ - no_useless_return
+ - normalize_index_brace
+ - php_unit_dedicate_assert
+ - php_unit_dedicate_assert_internal_type
+ - php_unit_expectation
+ - php_unit_mock
+ - php_unit_mock_short_will_return
+ - php_unit_namespaced
+ - php_unit_no_expectation_annotation
+ - phpdoc_no_empty_return
+ - phpdoc_no_useless_inheritdoc
+ - phpdoc_order
+ - phpdoc_property
+ - phpdoc_scalar
+ - phpdoc_separation
+ - phpdoc_singular_inheritdoc
+ - phpdoc_trim
+ - phpdoc_trim_consecutive_blank_line_separation
+ - phpdoc_type_to_var
+ - phpdoc_types
+ - phpdoc_types_order
+ - print_to_echo
+ - regular_callable_call
+ - return_assignment
+ - self_accessor
+ - self_static_accessor
+ - set_type_to_cast
+ - short_array_syntax
+ - short_list_syntax
+ - simplified_if_return
+ - single_quote
+ - standardize_not_equals
+ - ternary_to_null_coalescing
+ - trailing_comma_in_multiline_array
+ - unalign_double_arrow
+ - unalign_equals
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f218000
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 Spiral Scout
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4a39844
--- /dev/null
+++ b/README.md
@@ -0,0 +1,62 @@
+# RoadRunner Lock Integration for Symfony
+
+[![PHP Version Require](https://poser.pugx.org/roadrunner-php/symfony-lock-driver/require/php)](https://packagist.org/packages/roadrunner-php/symfony-lock-driver)
+[![Latest Stable Version](https://poser.pugx.org/roadrunner-php/symfony-lock-driver/v/stable)](https://packagist.org/packages/roadrunner-php/symfony-lock-driver)
+[![phpunit](https://github.com/roadrunner-php/symfony-lock-driver/actions/workflows/phpunit.yml/badge.svg)](https://github.com/roadrunner-php/symfony-lock-driver/actions)
+[![psalm](https://github.com/roadrunner-php/symfony-lock-driver/actions/workflows/psalm.yml/badge.svg)](https://github.com/roadrunner-php/symfony-lock-driver/actions)
+[![Codecov](https://codecov.io/gh/roadrunner-php/symfony-lock-driver/branch/master/graph/badge.svg)](https://codecov.io/gh/roadrunner-php/symfony-lock-driver/)
+[![Total Downloads](https://poser.pugx.org/roadrunner-php/symfony-lock-driver/downloads)](https://packagist.org/roadrunner-php/symfony-lock-driver/phpunit)
+
+
+This package is a bridge that connects the powerful RoadRunner Lock plugin with the Symfony Lock component. It's
+designed to help you easily manage distributed locks in your PHP applications, particularly when you're working with
+high-traffic web applications and microservices.
+
+## Requirements
+
+Make sure that your server is configured with following PHP version and extensions:
+
+- PHP 8.1+
+
+## Installation
+
+You can install the package via composer:
+
+```bash
+composer require roadrunner-php/symfony-lock-driver
+
+```
+
+## Usage
+
+Using the RoadRunner Lock with Symfony is straightforward. Here's a simple example:
+
+```php
+use RoadRunner\Lock\Lock;
+use Spiral\Goridge\RPC\RPC;
+use Spiral\RoadRunner\Symfony\Lock\RoadRunnerStore;
+use Symfony\Component\Lock\LockFactory;
+
+require __DIR__ . '/vendor/autoload.php';
+
+$lock = new Lock(RPC::create('tcp://127.0.0.1:6001'));
+$factory = new LockFactory(
+ new RoadRunnerStore($lock)
+);
+```
+
+Read more about using Symfony Lock component [here](https://symfony.com/doc/current/components/lock.html).
+
+## Contributing
+
+Contributions are welcome! If you find an issue or have a feature request, please open
+an [issue](https://github.com/roadrunner-php/issues) or submit a pull request.
+
+## Credits
+
+- [gam6itko](https://github.com/gam6itko)
+- [butschster](https://github.com/butschster)
+
+## License
+
+The MIT License (MIT). Please see [License File](LICENSE) for more information.
diff --git a/composer.json b/composer.json
index d191c3e..bf1f6b6 100644
--- a/composer.json
+++ b/composer.json
@@ -1,61 +1,68 @@
{
- "name": "roadrunner-php/symfony-lock-driver",
- "type": "library",
- "description": "RoadRunner: symfony/lock bridge",
- "license": "MIT",
- "authors": [
- {
- "name": "Pavel Buchnev (butschster)",
- "email": "pavel.buchnev@spiralscout.com"
+ "name": "roadrunner-php/symfony-lock-driver",
+ "type": "library",
+ "description": "RoadRunner: symfony/lock bridge",
+ "keywords": [
+ "roadrunner-php",
+ "symfony",
+ "roadrunner",
+ "spiral",
+ "lock"
+ ],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Pavel Buchnev (butschster)",
+ "email": "pavel.buchnev@spiralscout.com"
+ },
+ {
+ "name": "Alexander Strizhak",
+ "email": "gam6itko@gmail.com"
+ }
+ ],
+ "homepage": "https://spiral.dev/",
+ "support": {
+ "docs": "https://roadrunner.dev/docs",
+ "issues": "https://github.com/roadrunner-server/roadrunner/issues",
+ "forum": "https://forum.roadrunner.dev/",
+ "chat": "https://discord.gg/V6EK4he"
},
- {
- "name": "Alexander Strizhak",
- "email": "gam6itko@gmail.com"
- }
- ],
- "homepage": "https://spiral.dev/",
- "support": {
- "docs": "https://roadrunner.dev/docs",
- "issues": "https://github.com/roadrunner-server/roadrunner/issues",
- "forum": "https://forum.roadrunner.dev/",
- "chat": "https://discord.gg/V6EK4he"
- },
- "require": {
- "php": ">=8.1",
- "roadrunner-php/lock": "^1.0",
- "symfony/lock": "^6.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.0",
- "vimeo/psalm": "^5.9"
- },
- "autoload": {
- "psr-4": {
- "Spiral\\RoadRunner\\Symfony\\Lock\\": "src"
- }
- },
- "autoload-dev": {
- "psr-4": {
- "Spiral\\RoadRunner\\Symfony\\Lock\\Tests\\": "tests"
- }
- },
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/roadrunner-server"
- }
- ],
- "scripts": {
- "analyze": "psalm"
- },
- "config": {
- "sort-packages": true
- },
- "minimum-stability": "dev",
- "prefer-stable": true,
- "extra": {
- "branch-alias": {
- "dev-main": "1.0-dev"
+ "require": {
+ "php": ">=8.1",
+ "roadrunner-php/lock": "^1.0",
+ "symfony/lock": "^6.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0",
+ "vimeo/psalm": "^5.9"
+ },
+ "autoload": {
+ "psr-4": {
+ "Spiral\\RoadRunner\\Symfony\\Lock\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Spiral\\RoadRunner\\Symfony\\Lock\\Tests\\": "tests"
+ }
+ },
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/roadrunner-server"
+ }
+ ],
+ "scripts": {
+ "analyze": "psalm"
+ },
+ "config": {
+ "sort-packages": true
+ },
+ "minimum-stability": "dev",
+ "prefer-stable": true,
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.0-dev"
+ }
}
- }
}
diff --git a/phpunit.xml b/phpunit.xml
index 6a5626d..d7dc280 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1,23 +1,39 @@
-
+
-
- ./tests/
+
+ tests
-
-
-
- src
-
-
+
+
+ ./src
+
+
+
+
+
+
+
+
+
+
diff --git a/psalm.xml b/psalm.xml
new file mode 100644
index 0000000..dd76fea
--- /dev/null
+++ b/psalm.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/RandomTokenGenerator.php b/src/RandomTokenGenerator.php
new file mode 100644
index 0000000..5e8efb2
--- /dev/null
+++ b/src/RandomTokenGenerator.php
@@ -0,0 +1,21 @@
+ $length
+ */
+ public function __construct(
+ private readonly int $length = 32,
+ ) {
+ }
+
+ public function generate(): string
+ {
+ return \bin2hex(\random_bytes($this->length));
+ }
+}
diff --git a/src/RoadRunnerStore.php b/src/RoadRunnerStore.php
index 89d05ad..85ea9ff 100644
--- a/src/RoadRunnerStore.php
+++ b/src/RoadRunnerStore.php
@@ -6,36 +6,53 @@
use RoadRunner\Lock as RR;
use Spiral\Goridge\RPC\Exception\RPCException;
+use Symfony\Component\Lock\BlockingStoreInterface;
use Symfony\Component\Lock\Exception\LockAcquiringException;
use Symfony\Component\Lock\Exception\LockConflictedException;
use Symfony\Component\Lock\Exception\LockReleasingException;
use Symfony\Component\Lock\Key;
use Symfony\Component\Lock\SharedLockStoreInterface;
+use Symfony\Component\Lock\Store\ExpiringStoreTrait;
-final class RoadRunnerStore implements SharedLockStoreInterface
+final class RoadRunnerStore implements SharedLockStoreInterface, BlockingStoreInterface
{
+ use ExpiringStoreTrait;
+
/**
- * @param RR\LockInterface $rrLock
* @param float $initialTtl The time-to-live of the lock, in seconds. Defaults to 0 (forever).
* @param float $initialWaitTtl How long to wait to acquire lock until returning false.
*/
public function __construct(
- private readonly RR\LockInterface $rrLock,
- private readonly float $initialTtl = 300.0,
- private readonly float $initialWaitTtl = 0,
+ private readonly RR\LockInterface $lock,
+ private readonly TokenGeneratorInterface $tokens = new RandomTokenGenerator(),
+ private readonly float $initialTtl = 300.0,
+ private readonly float $initialWaitTtl = 60,
) {
\assert($this->initialTtl >= 0);
\assert($this->initialWaitTtl >= 0);
}
+ public function withTtl(float $ttl): self
+ {
+ return new self($this->lock, $this->tokens, $ttl, $this->initialWaitTtl);
+ }
+
public function save(Key $key): void
{
\assert(false === $key->hasState(__CLASS__));
+
try {
- $lockId = $this->rrLock->lock((string) $key, null, $this->initialTtl, $this->initialWaitTtl);
- if (false === $lockId) {
+ $lockId = $this->getUniqueToken($key);
+
+ /** @var non-empty-string $resource */
+ $resource = (string)$key;
+
+ $status = $this->lock->lock($resource, $lockId, $this->initialTtl);
+
+ if (false === $status) {
throw new LockConflictedException('RoadRunner. Failed to make lock');
}
+
$key->setState(__CLASS__, $lockId);
} catch (RPCException $e) {
throw new LockAcquiringException(message: 'RoadRunner. RPC call error', previous: $e);
@@ -45,24 +62,42 @@ public function save(Key $key): void
public function saveRead(Key $key): void
{
\assert(false === $key->hasState(__CLASS__));
- $lockId = $this->rrLock->lockRead((string)$key, null, $this->initialTtl, $this->initialWaitTtl);
- if (false === $lockId) {
+ $lockId = $this->getUniqueToken($key);
+
+ /** @var non-empty-string $resource */
+ $resource = (string)$key;
+ $status = $this->lock->lockRead($resource, $lockId, $this->initialTtl);
+
+ if (false === $status) {
throw new LockConflictedException('RoadRunner. Failed to make read lock');
}
+
$key->setState(__CLASS__, $lockId);
}
public function exists(Key $key): bool
{
\assert($key->hasState(__CLASS__));
- return $this->rrLock->exists((string) $key, $key->getState(__CLASS__));
+
+ $lockId = $this->getUniqueToken($key);
+
+ /** @var non-empty-string $resource */
+ $resource = (string)$key;
+
+ return $this->lock->exists($resource, $lockId);
}
public function putOffExpiration(Key $key, float $ttl): void
{
\assert($key->hasState(__CLASS__));
\assert($ttl > 0);
- if (false === $this->rrLock->updateTTL((string) $key, $key->getState(__CLASS__), $ttl)) {
+
+ $lockId = $this->getUniqueToken($key);
+
+ /** @var non-empty-string $resource */
+ $resource = (string)$key;
+
+ if (false === $this->lock->updateTTL($resource, $lockId, $ttl)) {
throw new LockConflictedException('RoadRunner. Failed to update lock ttl');
}
}
@@ -70,8 +105,43 @@ public function putOffExpiration(Key $key, float $ttl): void
public function delete(Key $key): void
{
\assert($key->hasState(__CLASS__));
- if (false === $this->rrLock->release((string) $key, $key->getState(__CLASS__))) {
- throw new LockReleasingException('RoadRunner. Failed to release lock');
+ $lockId = $this->getUniqueToken($key);
+
+ /** @var non-empty-string $resource */
+ $resource = (string)$key;
+ $this->lock->release($resource, $lockId);
+ }
+
+ public function waitAndSave(Key $key): void
+ {
+ $lockId = $this->getUniqueToken($key);
+
+ /** @var non-empty-string $resource */
+ $resource = (string)$key;
+
+ $status = $this->lock->lock($resource, $lockId, $this->initialTtl, $this->initialWaitTtl);
+
+ $key->setState(__CLASS__, $lockId);
+ if (!$status) {
+ throw new LockConflictedException();
}
+
+ $this->checkNotExpired($key);
+ }
+
+ /**
+ * @return non-empty-string
+ */
+ private function getUniqueToken(Key $key): string
+ {
+ if (!$key->hasState(__CLASS__)) {
+ $token = $this->tokens->generate();
+ $key->setState(__CLASS__, $token);
+ }
+
+ /** @var non-empty-string $state */
+ $state = $key->getState(__CLASS__);
+
+ return $state;
}
}
diff --git a/src/TokenGeneratorInterface.php b/src/TokenGeneratorInterface.php
new file mode 100644
index 0000000..61b31c2
--- /dev/null
+++ b/src/TokenGeneratorInterface.php
@@ -0,0 +1,15 @@
+rrLock = $this->createMock(RrLock::class);
+ $this->tokens = $this->createMock(TokenGeneratorInterface::class);
+
+ $this->tokens->method('generate')
+ ->willReturn('random-id');
+ }
+
public function testSaveSuccess(): void
{
- $rrLock = $this->createMock(RrLock::class);
- $rrLock->expects(self::once())
+ $this->rrLock->expects(self::once())
->method('lock')
- ->with('resource-name', null)
+ ->with('resource-name', 'random-id')
->willReturn('lock-id');
- $store = new RoadRunnerStore($rrLock);
+
+ $store = new RoadRunnerStore($this->rrLock, $this->tokens);
$key = new Key('resource-name');
$store->save($key);
- self::assertTrue($key->hasState(RoadRunnerStore::class));
- self::assertSame('lock-id', $key->getState(RoadRunnerStore::class));
+
+ $this->assertTrue($key->hasState(RoadRunnerStore::class));
+ $this->assertSame('random-id', $key->getState(RoadRunnerStore::class));
}
public function testSaveReadSuccess(): void
{
- $rrLock = $this->createMock(RrLock::class);
- $rrLock->expects(self::once())
+ $this->rrLock->expects(self::once())
->method('lockRead')
- ->with('resource-name', null)
+ ->with('resource-name', 'random-id')
->willReturn('lock-id');
- $store = new RoadRunnerStore($rrLock);
+
+ $store = new RoadRunnerStore($this->rrLock, $this->tokens);
$key = new Key('resource-name');
$store->saveRead($key);
}
public function testExistsSuccess(): void
{
- $rrLock = $this->createMock(RrLock::class);
- $rrLock->expects(self::once())
+ $this->rrLock->expects(self::once())
->method('exists')
->with('resource-name')
->willReturn(true);
- $store = new RoadRunnerStore($rrLock);
+
+ $store = new RoadRunnerStore($this->rrLock, $this->tokens);
$key = new Key('resource-name');
$key->setState(RoadRunnerStore::class, 'lock-id');
$store->exists($key);
@@ -54,12 +68,12 @@ public function testExistsSuccess(): void
public function testPutOffExpirationSuccess(): void
{
- $rrLock = $this->createMock(RrLock::class);
- $rrLock->expects(self::once())
+ $this->rrLock->expects(self::once())
->method('updateTTL')
->with('resource-name', 'lock-id', 3600.0)
->willReturn(true);
- $store = new RoadRunnerStore($rrLock);
+
+ $store = new RoadRunnerStore($this->rrLock, $this->tokens);
$key = new Key('resource-name');
$key->setState(RoadRunnerStore::class, 'lock-id');
$store->putOffExpiration($key, 3600.0);
@@ -67,12 +81,12 @@ public function testPutOffExpirationSuccess(): void
public function testDeleteSuccess(): void
{
- $rrLock = $this->createMock(RrLock::class);
- $rrLock->expects(self::once())
+ $this->rrLock->expects(self::once())
->method('release')
->with('resource-name')
->willReturn(true);
- $store = new RoadRunnerStore($rrLock);
+
+ $store = new RoadRunnerStore($this->rrLock, $this->tokens);
$key = new Key('resource-name');
$key->setState(RoadRunnerStore::class, 'lock-id');
$store->delete($key);
@@ -80,56 +94,56 @@ public function testDeleteSuccess(): void
public function testSaveFail(): void
{
- self::expectException(LockConflictedException::class);
- self::expectExceptionMessage('RoadRunner. Failed to make lock');
+ $this->expectException(LockConflictedException::class);
+ $this->expectExceptionMessage('RoadRunner. Failed to make lock');
- $rrLock = $this->createMock(RrLock::class);
- $rrLock->expects(self::once())
+ $this->rrLock->expects(self::once())
->method('lock')
- ->with('resource-name', null)
+ ->with('resource-name', 'random-id')
->willReturn(false);
- $store = new RoadRunnerStore($rrLock);
+
+ $store = new RoadRunnerStore($this->rrLock, $this->tokens);
$store->save(new Key('resource-name'));
}
public function testSaveReadFail(): void
{
- self::expectException(LockConflictedException::class);
- self::expectExceptionMessage('RoadRunner. Failed to make read lock');
+ $this->expectException(LockConflictedException::class);
+ $this->expectExceptionMessage('RoadRunner. Failed to make read lock');
- $rrLock = $this->createMock(RrLock::class);
- $rrLock->expects(self::once())
+ $this->rrLock->expects(self::once())
->method('lockRead')
- ->with('resource-name', null);
- $store = new RoadRunnerStore($rrLock);
+ ->with('resource-name', 'random-id');
+
+ $store = new RoadRunnerStore($this->rrLock, $this->tokens);
$key = new Key('resource-name');
$store->saveRead($key);
}
public function testExistsFail(): void
{
- $rrLock = $this->createMock(RrLock::class);
- $rrLock->expects(self::once())
+ $this->rrLock->expects(self::once())
->method('exists')
->with('resource-name')
->willReturn(false);
- $store = new RoadRunnerStore($rrLock);
+
+ $store = new RoadRunnerStore($this->rrLock, $this->tokens);
$key = new Key('resource-name');
$key->setState(RoadRunnerStore::class, 'lock-id');
- self::assertFalse($store->exists($key));
+ $this->assertFalse($store->exists($key));
}
public function testPutOffExpirationFail(): void
{
- self::expectException(LockConflictedException::class);
- self::expectExceptionMessage('RoadRunner. Failed to update lock ttl');
+ $this->expectException(LockConflictedException::class);
+ $this->expectExceptionMessage('RoadRunner. Failed to update lock ttl');
- $rrLock = $this->createMock(RrLock::class);
- $rrLock->expects(self::once())
+ $this->rrLock->expects(self::once())
->method('updateTTL')
->with('resource-name', 'lock-id', 3600.0)
->willReturn(false);
- $store = new RoadRunnerStore($rrLock);
+
+ $store = new RoadRunnerStore($this->rrLock, $this->tokens);
$key = new Key('resource-name');
$key->setState(RoadRunnerStore::class, 'lock-id');
$store->putOffExpiration($key, 3600.0);
@@ -137,15 +151,12 @@ public function testPutOffExpirationFail(): void
public function testDeleteFail(): void
{
- self::expectException(LockReleasingException::class);
- self::expectExceptionMessage('RoadRunner. Failed to release lock');
-
- $rrLock = $this->createMock(RrLock::class);
- $rrLock->expects(self::once())
+ $this->rrLock->expects(self::once())
->method('release')
->with('resource-name')
->willReturn(false);
- $store = new RoadRunnerStore($rrLock);
+
+ $store = new RoadRunnerStore($this->rrLock, $this->tokens);
$key = new Key('resource-name');
$key->setState(RoadRunnerStore::class, 'lock-id');
$store->delete($key);