diff --git a/.gitignore b/.gitignore index 87230d1b..bbf0d8c0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,12 @@ +/coverage /vendor /composer.lock +.idea +nbproject +.vscode +.DS_Store + +*.local +*.cache + /phpunit.xml -/.phpunit.result.cache diff --git a/README.md b/README.md index 34d78514..88ffa447 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ **[Requirements](#requirements)** | **[Installation](#installation)** | **[Usage](#usage)** | -**[License and authors](#license-and-authors)** | +**[License](#license)** | # php-lock/lock @@ -119,7 +119,7 @@ $newBalance = $mutex->check(function () use ($bankAccount, $amount): bool { return $balance; }); -if (false === $newBalance) { +if ($newBalance === false) { if ($balance < 0) { throw new \DomainException('You have no credit.'); } @@ -143,11 +143,11 @@ try { throw new \DomainException(); } - return "result"; + return 'result'; }); } catch (LockReleaseException $unlockException) { if ($unlockException->getCodeException() !== null) { - $codeException = $unlockException->getCodeException() + $codeException = $unlockException->getCodeException(); // do something with the code exception } else { $code_result = $unlockException->getCodeResult(); @@ -190,9 +190,9 @@ Example: ```php $mutex = new CASMutex(); $mutex->synchronized(function () use ($memcached, $mutex, $amount): void { - $balance = $memcached->get("balance", null, $casToken); + $balance = $memcached->get('balance', null, $casToken); $balance -= $amount; - if (!$memcached->cas($casToken, "balance", $balance)) { + if (!$memcached->cas($casToken, 'balance', $balance)) { return; } $mutex->notify(); @@ -206,12 +206,12 @@ The **FlockMutex** is a lock implementation based on Example: ```php -$mutex = new FlockMutex(fopen(__FILE__, "r")); +$mutex = new FlockMutex(fopen(__FILE__, 'r')); $mutex->synchronized(function () use ($bankAccount, $amount) { $balance = $bankAccount->getBalance(); $balance -= $amount; if ($balance < 0) { - throw new \DomainException("You have no credit."); + throw new \DomainException('You have no credit.'); } $bankAccount->setBalance($balance); }); @@ -228,14 +228,14 @@ The **MemcachedMutex** is a spinlock implementation which uses the Example: ```php $memcache = new \Memcached(); -$memcache->addServer("localhost", 11211); +$memcache->addServer('localhost', 11211); -$mutex = new MemcachedMutex("balance", $memcache); +$mutex = new MemcachedMutex('balance', $memcache); $mutex->synchronized(function () use ($bankAccount, $amount) { $balance = $bankAccount->getBalance(); $balance -= $amount; if ($balance < 0) { - throw new \DomainException("You have no credit."); + throw new \DomainException('You have no credit.'); } $bankAccount->setBalance($balance); }); @@ -255,14 +255,14 @@ continue to function as long as a majority of the servers still works. Example: ```php $redis = new Redis(); -$redis->connect("localhost"); +$redis->connect('localhost'); -$mutex = new PHPRedisMutex([$redis], "balance"); +$mutex = new PHPRedisMutex([$redis], 'balance'); $mutex->synchronized(function () use ($bankAccount, $amount) { $balance = $bankAccount->getBalance(); $balance -= $amount; if ($balance < 0) { - throw new \DomainException("You have no credit."); + throw new \DomainException('You have no credit.'); } $bankAccount->setBalance($balance); }); @@ -276,14 +276,14 @@ The **PredisMutex** is the distributed lock implementation of Example: ```php -$redis = new Client("redis://localhost"); +$redis = new Client('redis://localhost'); -$mutex = new PredisMutex([$redis], "balance"); +$mutex = new PredisMutex([$redis], 'balance'); $mutex->synchronized(function () use ($bankAccount, $amount) { $balance = $bankAccount->getBalance(); $balance -= $amount; if ($balance < 0) { - throw new \DomainException("You have no credit."); + throw new \DomainException('You have no credit.'); } $bankAccount->setBalance($balance); }); @@ -296,13 +296,13 @@ The **SemaphoreMutex** is a lock implementation based on Example: ```php -$semaphore = sem_get(ftok(__FILE__, "a")); +$semaphore = sem_get(ftok(__FILE__, 'a')); $mutex = new SemaphoreMutex($semaphore); $mutex->synchronized(function () use ($bankAccount, $amount) { $balance = $bankAccount->getBalance(); $balance -= $amount; if ($balance < 0) { - throw new \DomainException("You have no credit."); + throw new \DomainException('You have no credit.'); } $bankAccount->setBalance($balance); }); @@ -324,16 +324,16 @@ Example: $mutex = new TransactionalMutex($pdo); $mutex->synchronized(function () use ($pdo, $accountId, $amount) { $select = $pdo->prepare( - "SELECT balance FROM account WHERE id = ? FOR UPDATE" + 'SELECT balance FROM account WHERE id = ? FOR UPDATE' ); $select->execute([$accountId]); $balance = $select->fetchColumn(); $balance -= $amount; if ($balance < 0) { - throw new \DomainException("You have no credit."); + throw new \DomainException('You have no credit.'); } - $pdo->prepare("UPDATE account SET balance = ? WHERE id = ?") + $pdo->prepare('UPDATE account SET balance = ? WHERE id = ?') ->execute([$balance, $accountId]); }); ``` @@ -355,14 +355,14 @@ Also note that `GET_LOCK` function is server wide and the MySQL manual suggests you to namespace your locks like `dbname.lockname`. ```php -$pdo = new PDO("mysql:host=localhost;dbname=test", "username"); +$pdo = new PDO('mysql:host=localhost;dbname=test', 'username'); -$mutex = new MySQLMutex($pdo, "balance", 15); +$mutex = new MySQLMutex($pdo, 'balance', 15); $mutex->synchronized(function () use ($bankAccount, $amount) { $balance = $bankAccount->getBalance(); $balance -= $amount; if ($balance < 0) { - throw new \DomainException("You have no credit."); + throw new \DomainException('You have no credit.'); } $bankAccount->setBalance($balance); }); @@ -381,24 +381,22 @@ No time outs are supported. If the connection to the database server is lost or interrupted, the lock is automatically released. ```php -$pdo = new PDO("pgsql:host=localhost;dbname=test;", "username"); +$pdo = new PDO('pgsql:host=localhost;dbname=test;', 'username'); -$mutex = new PgAdvisoryLockMutex($pdo, "balance"); +$mutex = new PgAdvisoryLockMutex($pdo, 'balance'); $mutex->synchronized(function () use ($bankAccount, $amount) { $balance = $bankAccount->getBalance(); $balance -= $amount; if ($balance < 0) { - throw new \DomainException("You have no credit."); + throw new \DomainException('You have no credit.'); } $bankAccount->setBalance($balance); }); ``` -## License and authors - -This project is free and under the MIT. +## License -Responsible for this project is Willem Stuursma-Ruwen . +This project is free and is licensed under the MIT. [1]: http://semver.org [2]: https://github.com/nrk/predis diff --git a/composer.json b/composer.json index d0a338ae..d6847780 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,7 @@ "homepage": "https://github.com/malkusch/lock", "require": { "php": ">=7.3 <8.4", - "psr/log": "^1 || ^2 || ^3" + "psr/log": "^1.0 || ^2.0 || ^3.0" }, "require-dev": { "ext-memcached": "*", @@ -44,14 +44,17 @@ "ext-pdo_mysql": "*", "ext-pdo_sqlite": "*", "ext-sysvsem": "*", - "eloquent/liberator": "^2.0", + "eloquent/liberator": "^2.0 || ^3.0", "ergebnis/composer-normalize": "^2.13", "friendsofphp/php-cs-fixer": "^3.0", - "mikey179/vfsstream": "^1.6.7", + "mikey179/vfsstream": "^1.6.11", "php-mock/php-mock-phpunit": "^2.1", - "phpstan/phpstan": "^0.12.58", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", "phpunit/phpunit": "^9.4", - "predis/predis": "^1.1", + "predis/predis": "^1.1.8", "spatie/async": "^1.5" }, "suggest": { diff --git a/phpstan.neon.dist b/phpstan.neon.dist index c31d460e..a5dd35d8 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,9 +1,33 @@ +includes: + - phar://phpstan.phar/conf/bleedingEdge.neon + parameters: - level: 5 + level: 6 + checkMissingOverrideMethodAttribute: true paths: - - ./ - excludes_analyse: - - vendor/ + - . + excludePaths: + - vendor - # TODO review once we drop PHP 7.x support - treatPhpDocTypesAsCertain: false + ignoreErrors: + # TODO + - + path: '*' + identifier: equal.notAllowed + message: '~^Loose comparison via "==" is not allowed\.$~' + count: 4 + - + path: 'src/mutex/RedisMutex.php' + identifier: if.condNotBoolean + message: '~^Only booleans are allowed in an if condition, mixed given\.$~' + count: 1 + - + path: 'src/mutex/TransactionalMutex.php' + identifier: if.condNotBoolean + message: '~^Only booleans are allowed in an if condition, mixed given\.$~' + count: 1 + - + path: 'tests/mutex/*Test.php' + identifier: empty.notAllowed + message: '~^Construct empty\(\) is not allowed\. Use more strict comparison\.$~' + count: 6 diff --git a/src/exception/DeadlineException.php b/src/exception/DeadlineException.php index cc85b012..e81cba6b 100644 --- a/src/exception/DeadlineException.php +++ b/src/exception/DeadlineException.php @@ -4,7 +4,4 @@ namespace malkusch\lock\exception; -/** - * Deadline exception. - */ class DeadlineException extends \RuntimeException implements PhpLockException {} diff --git a/src/exception/MutexException.php b/src/exception/MutexException.php index 9456c7a3..4be564a8 100644 --- a/src/exception/MutexException.php +++ b/src/exception/MutexException.php @@ -12,8 +12,6 @@ */ class MutexException extends \RuntimeException implements PhpLockException { - /** - * @var int not enough redis servers - */ + /** @var int not enough redis servers */ public const REDIS_NOT_ENOUGH_SERVERS = 1; } diff --git a/src/exception/PhpLockException.php b/src/exception/PhpLockException.php index b6b9f04e..a351f046 100644 --- a/src/exception/PhpLockException.php +++ b/src/exception/PhpLockException.php @@ -7,13 +7,13 @@ /** * Common php-lock/lock exception interface. * - * @method string getMessage() - * @method int getCode() - * @method string getFile() - * @method int getLine() - * @method array getTrace() - * @method string getTraceAsString() - * @method \Throwable|null getPrevious() - * @method string __toString() + * @method string getMessage() + * @method int getCode() + * @method string getFile() + * @method int getLine() + * @method list> getTrace() + * @method string getTraceAsString() + * @method \Throwable|null getPrevious() + * @method string __toString() */ interface PhpLockException {} diff --git a/src/mutex/CASMutex.php b/src/mutex/CASMutex.php index 913b06ad..74c4eb09 100644 --- a/src/mutex/CASMutex.php +++ b/src/mutex/CASMutex.php @@ -17,9 +17,7 @@ */ class CASMutex extends Mutex { - /** - * @var Loop the loop - */ + /** @var Loop the loop */ private $loop; /** @@ -63,21 +61,15 @@ public function notify(): void * $balance -= $amount; * if (!$memcached->cas($casToken, 'balance', $balance)) { * return; - * * } * $mutex->notify(); * }); * * - * @template T - * - * @param callable(): T $code the synchronized execution block - * - * @return T the return value of the execution block - * * @throws \Exception the execution block threw an exception * @throws TimeoutException the timeout was reached */ + #[\Override] public function synchronized(callable $code) { return $this->loop->execute($code); diff --git a/src/mutex/FlockMutex.php b/src/mutex/FlockMutex.php index c83d0349..6026e84d 100644 --- a/src/mutex/FlockMutex.php +++ b/src/mutex/FlockMutex.php @@ -33,19 +33,13 @@ class FlockMutex extends LockMutex */ public const STRATEGY_BUSY = 3; - /** - * @var resource the file handle - */ + /** @var resource the file handle */ private $fileHandle; - /** - * @var float - */ + /** @var float */ private $timeout; - /** - * @var self::STRATEGY_* - */ + /** @var self::STRATEGY_* */ private $strategy; /** @@ -115,7 +109,7 @@ function (): void { * @throws TimeoutException * @throws LockAcquireException */ - private function lockBusy() + private function lockBusy(): void { $loop = new Loop($this->timeout); $loop->execute(function () use ($loop): void { @@ -131,7 +125,7 @@ private function lockBusy() private function acquireNonBlockingLock(): bool { if (!flock($this->fileHandle, \LOCK_EX | \LOCK_NB, $wouldBlock)) { - if ($wouldBlock) { + if ($wouldBlock) { // @phpstan-ignore if.condNotBoolean // Another process holds the lock. return false; } @@ -146,6 +140,7 @@ private function acquireNonBlockingLock(): bool * @throws LockAcquireException * @throws TimeoutException */ + #[\Override] protected function lock(): void { switch ($this->strategy) { @@ -163,12 +158,10 @@ protected function lock(): void return; } - throw new \RuntimeException("Unknown strategy '{$this->strategy}'.'"); + throw new \RuntimeException("Unknown strategy '{$this->strategy}'.'"); // @phpstan-ignore deadCode.unreachable } - /** - * @throws LockReleaseException - */ + #[\Override] protected function unlock(): void { if (!flock($this->fileHandle, \LOCK_UN)) { diff --git a/src/mutex/LockMutex.php b/src/mutex/LockMutex.php index 25737394..3804f0c9 100644 --- a/src/mutex/LockMutex.php +++ b/src/mutex/LockMutex.php @@ -30,6 +30,7 @@ abstract protected function lock(): void; */ abstract protected function unlock(): void; + #[\Override] public function synchronized(callable $code) { $this->lock(); diff --git a/src/mutex/MemcachedMutex.php b/src/mutex/MemcachedMutex.php index d38cc749..51042ddb 100644 --- a/src/mutex/MemcachedMutex.php +++ b/src/mutex/MemcachedMutex.php @@ -4,16 +4,12 @@ namespace malkusch\lock\mutex; -use Memcached; - /** * Memcached based spinlock implementation. */ class MemcachedMutex extends SpinlockMutex { - /** - * @var \Memcached the connected Memcached API - */ + /** @var \Memcached the connected Memcached API */ private $memcache; /** @@ -35,6 +31,7 @@ public function __construct(string $name, \Memcached $memcache, float $timeout = $this->memcache = $memcache; } + #[\Override] protected function acquire(string $key, float $expire): bool { // memcached supports only integer expire @@ -44,6 +41,7 @@ protected function acquire(string $key, float $expire): bool return $this->memcache->add($key, true, $expireInt); } + #[\Override] protected function release(string $key): bool { return $this->memcache->delete($key); diff --git a/src/mutex/MySQLMutex.php b/src/mutex/MySQLMutex.php index aea957f3..ee9cdcba 100644 --- a/src/mutex/MySQLMutex.php +++ b/src/mutex/MySQLMutex.php @@ -9,18 +9,12 @@ class MySQLMutex extends LockMutex { - /** - * @var \PDO - */ + /** @var \PDO */ private $pdo; - /** - * @var string - */ + /** @var string */ private $name; - /** - * @var float - */ + /** @var float */ private $timeout; public function __construct(\PDO $PDO, string $name, float $timeout = 0) @@ -35,9 +29,7 @@ public function __construct(\PDO $PDO, string $name, float $timeout = 0) $this->timeout = $timeout; } - /** - * @throws LockAcquireException - */ + #[\Override] public function lock(): void { $statement = $this->pdo->prepare('SELECT GET_LOCK(?,?)'); @@ -69,6 +61,7 @@ public function lock(): void throw TimeoutException::create($this->timeout); } + #[\Override] public function unlock(): void { $statement = $this->pdo->prepare('DO RELEASE_LOCK(?)'); diff --git a/src/mutex/NoMutex.php b/src/mutex/NoMutex.php index a7fdb8a6..b01f4f49 100644 --- a/src/mutex/NoMutex.php +++ b/src/mutex/NoMutex.php @@ -12,6 +12,7 @@ */ class NoMutex extends Mutex { + #[\Override] public function synchronized(callable $code) { return $code(); diff --git a/src/mutex/PHPRedisMutex.php b/src/mutex/PHPRedisMutex.php index 546167ab..eccf5787 100644 --- a/src/mutex/PHPRedisMutex.php +++ b/src/mutex/PHPRedisMutex.php @@ -6,7 +6,6 @@ use malkusch\lock\exception\LockAcquireException; use malkusch\lock\exception\LockReleaseException; -use Redis; /** * Mutex based on the Redlock algorithm using the phpredis extension. @@ -42,6 +41,7 @@ public function __construct(array $redisAPIs, string $name, float $timeout = 3) * * @throws LockAcquireException */ + #[\Override] // @phpstan-ignore method.childParameterType protected function add($redisAPI, string $key, string $value, float $expire): bool { $expireMillis = (int) ceil($expire * 1000); @@ -62,9 +62,8 @@ protected function add($redisAPI, string $key, string $value, float $expire): bo /** * @param \Redis|\RedisCluster $redis the Redis or RedisCluster connection - * - * @throws LockReleaseException */ + #[\Override] // @phpstan-ignore method.childParameterType protected function evalScript($redis, string $script, int $numkeys, array $arguments) { for ($i = $numkeys; $i < count($arguments); ++$i) { diff --git a/src/mutex/PgAdvisoryLockMutex.php b/src/mutex/PgAdvisoryLockMutex.php index 897e863e..6183564c 100644 --- a/src/mutex/PgAdvisoryLockMutex.php +++ b/src/mutex/PgAdvisoryLockMutex.php @@ -6,19 +6,13 @@ class PgAdvisoryLockMutex extends LockMutex { - /** - * @var \PDO - */ + /** @var \PDO */ private $pdo; - /** - * @var int - */ + /** @var int */ private $key1; - /** - * @var int - */ + /** @var int */ private $key2; /** @@ -30,16 +24,13 @@ public function __construct(\PDO $PDO, string $name) $hashed_name = hash('sha256', $name, true); - if ($hashed_name === false) { // @phpstan-ignore-line - throw new \RuntimeException('Unable to hash the key, sha256 algorithm is not supported.'); - } - [$bytes1, $bytes2] = str_split($hashed_name, 4); $this->key1 = unpack('i', $bytes1)[1]; $this->key2 = unpack('i', $bytes2)[1]; } + #[\Override] public function lock(): void { $statement = $this->pdo->prepare('SELECT pg_advisory_lock(?,?)'); @@ -50,6 +41,7 @@ public function lock(): void ]); } + #[\Override] public function unlock(): void { $statement = $this->pdo->prepare('SELECT pg_advisory_unlock(?,?)'); diff --git a/src/mutex/PredisMutex.php b/src/mutex/PredisMutex.php index 05604556..c085e8a4 100644 --- a/src/mutex/PredisMutex.php +++ b/src/mutex/PredisMutex.php @@ -33,6 +33,7 @@ public function __construct(array $clients, string $name, float $timeout = 3) /** * @throws LockAcquireException */ + #[\Override] protected function add($redisAPI, string $key, string $value, float $expire): bool { $expireMillis = (int) ceil($expire * 1000); @@ -50,9 +51,7 @@ protected function add($redisAPI, string $key, string $value, float $expire): bo } } - /** - * @throws LockReleaseException - */ + #[\Override] protected function evalScript($client, string $script, int $numkeys, array $arguments) { /** @var ClientInterface $client */ diff --git a/src/mutex/RedisMutex.php b/src/mutex/RedisMutex.php index 86de1425..dd41ef0c 100644 --- a/src/mutex/RedisMutex.php +++ b/src/mutex/RedisMutex.php @@ -19,22 +19,18 @@ abstract class RedisMutex extends SpinlockMutex implements LoggerAwareInterface { use LoggerAwareTrait; - /** - * @var string the random value token for key identification - */ + /** @var string the random value token for key identification */ private $token; - /** - * @var array the Redis APIs - */ + /** @var array the Redis APIs */ private $redisAPIs; /** * Sets the Redis APIs. * - * @param array $redisAPIs the Redis APIs - * @param string $name the lock name - * @param float $timeout the time in seconds a lock expires, default is 3 + * @param array $redisAPIs the Redis APIs + * @param string $name the lock name + * @param float $timeout the time in seconds a lock expires, default is 3 * * @throws \LengthException the timeout must be greater than 0 */ @@ -46,6 +42,7 @@ public function __construct(array $redisAPIs, string $name, float $timeout = 3) $this->logger = new NullLogger(); } + #[\Override] protected function acquire(string $key, float $expire): bool { // 1. This differs from the specification to avoid an overflow on 32-Bit systems. @@ -101,6 +98,7 @@ protected function acquire(string $key, float $expire): bool return false; } + #[\Override] protected function release(string $key): bool { /* @@ -161,10 +159,10 @@ private function isMajority(int $count): bool abstract protected function add($redisAPI, string $key, string $value, float $expire): bool; /** - * @param mixed $redisAPI the connected Redis API - * @param string $script the Lua script - * @param int $numkeys the number of values in $arguments that represent Redis key names - * @param array $arguments keys and values + * @param mixed $redisAPI the connected Redis API + * @param string $script the Lua script + * @param int $numkeys the number of values in $arguments that represent Redis key names + * @param list $arguments keys and values * * @return mixed the script result, or false if executing failed * diff --git a/src/mutex/SemaphoreMutex.php b/src/mutex/SemaphoreMutex.php index 7fd180de..f33a4828 100644 --- a/src/mutex/SemaphoreMutex.php +++ b/src/mutex/SemaphoreMutex.php @@ -12,9 +12,7 @@ */ class SemaphoreMutex extends LockMutex { - /** - * @var \SysvSemaphore|resource the semaphore id - */ + /** @var \SysvSemaphore|resource the semaphore id */ private $semaphore; /** @@ -24,8 +22,8 @@ class SemaphoreMutex extends LockMutex * * Example: * - * $semaphore = sem_get(ftok(__FILE__, "a")); - * $mutex = new SemaphoreMutex($semaphore); + * $semaphore = sem_get(ftok(__FILE__, 'a')); + * $mutex = new SemaphoreMutex($semaphore); * * * @param \SysvSemaphore|resource $semaphore the semaphore id @@ -43,6 +41,7 @@ public function __construct($semaphore) /** * @internal */ + #[\Override] protected function lock(): void { if (!sem_acquire($this->semaphore)) { @@ -53,6 +52,7 @@ protected function lock(): void /** * @internal */ + #[\Override] protected function unlock(): void { if (!sem_release($this->semaphore)) { diff --git a/src/mutex/SpinlockMutex.php b/src/mutex/SpinlockMutex.php index cd825e62..5d8915bb 100644 --- a/src/mutex/SpinlockMutex.php +++ b/src/mutex/SpinlockMutex.php @@ -16,29 +16,19 @@ */ abstract class SpinlockMutex extends LockMutex { - /** - * The prefix for the lock key. - */ + /** The prefix for the lock key. */ private const PREFIX = 'lock_'; - /** - * @var float the timeout in seconds a lock may live - */ + /** @var float the timeout in seconds a lock may live */ private $timeout; - /** - * @var Loop the loop - */ + /** @var Loop the loop */ private $loop; - /** - * @var string the lock key - */ + /** @var string the lock key */ private $key; - /** - * @var float the timestamp when the lock was acquired - */ + /** @var float the timestamp when the lock was acquired */ private $acquired; /** @@ -55,6 +45,7 @@ public function __construct(string $name, float $timeout = 3) $this->key = self::PREFIX . $name; } + #[\Override] protected function lock(): void { $this->loop->execute(function (): void { @@ -73,6 +64,7 @@ protected function lock(): void }); } + #[\Override] protected function unlock(): void { $elapsed_time = microtime(true) - $this->acquired; diff --git a/src/mutex/TransactionalMutex.php b/src/mutex/TransactionalMutex.php index d277b2aa..865c2407 100644 --- a/src/mutex/TransactionalMutex.php +++ b/src/mutex/TransactionalMutex.php @@ -4,11 +4,8 @@ namespace malkusch\lock\mutex; -use Exception; use malkusch\lock\exception\LockAcquireException; use malkusch\lock\util\Loop; -use PDO; -use PDOException; /** * Serialization is delegated to the DBS. @@ -20,14 +17,10 @@ */ class TransactionalMutex extends Mutex { - /** - * @var \PDO the PDO - */ + /** @var \PDO the PDO */ private $pdo; - /** - * @var Loop the loop - */ + /** @var Loop the loop */ private $loop; /** @@ -95,16 +88,8 @@ private static function checkAutocommit(\PDO $pdo): void * * If the code throws any other exception, the transaction is rolled back * and won't be replayed. - * - * @template T - * - * @param callable(): T $code the synchronized execution block - * - * @return T the return value of the execution block - * - * @throws \Exception the execution block threw an exception - * @throws LockAcquireException the transaction was not commited */ + #[\Override] public function synchronized(callable $code) { return $this->loop->execute(function () use ($code) { @@ -160,7 +145,7 @@ private static function hasPDOException(\Throwable $exception) * * @throws LockAcquireException the roll back failed */ - private function rollBack(\Exception $exception) + private function rollBack(\Exception $exception): void { try { $this->pdo->rollBack(); diff --git a/src/util/DoubleCheckedLocking.php b/src/util/DoubleCheckedLocking.php index 9fc76cab..c086bcb1 100644 --- a/src/util/DoubleCheckedLocking.php +++ b/src/util/DoubleCheckedLocking.php @@ -17,14 +17,10 @@ */ class DoubleCheckedLocking { - /** - * @var Mutex the mutex - */ + /** @var Mutex the mutex */ private $mutex; - /** - * @var callable(): bool the check - */ + /** @var callable(): bool the check */ private $check; /** diff --git a/src/util/Loop.php b/src/util/Loop.php index 10629e36..e3a7a086 100644 --- a/src/util/Loop.php +++ b/src/util/Loop.php @@ -27,14 +27,10 @@ class Loop */ private const MAXIMUM_WAIT_US = 5e5; // 0.50 seconds - /** - * @var float the timeout in seconds - */ + /** @var float the timeout in seconds */ private $timeout; - /** - * @var bool true while code execution is repeating - */ + /** @var bool true while code execution is repeating */ private $looping = false; /** @@ -91,9 +87,9 @@ public function execute(callable $code) $deadline = microtime(true) + $this->timeout; $result = null; - for ($i = 0; $this->looping && microtime(true) < $deadline; ++$i) { // @phpstan-ignore-line + for ($i = 0; $this->looping && microtime(true) < $deadline; ++$i) { // @phpstan-ignore booleanAnd.leftAlwaysTrue $result = $code(); - if (!$this->looping) { // @phpstan-ignore-line + if (!$this->looping) { // @phpstan-ignore booleanNot.alwaysFalse // The $code callback has called $this->end() and the lock has been acquired. return $result; diff --git a/src/util/PcntlTimeout.php b/src/util/PcntlTimeout.php index 4f8864c3..97d57846 100644 --- a/src/util/PcntlTimeout.php +++ b/src/util/PcntlTimeout.php @@ -18,9 +18,7 @@ */ final class PcntlTimeout { - /** - * @var int Timeout in seconds - */ + /** @var int Timeout in seconds */ private $timeout; /** @@ -80,7 +78,7 @@ public function timeBoxed(callable $code) } $oldAlarm = pcntl_alarm($this->timeout); - if ($oldAlarm != 0) { + if ($oldAlarm !== 0) { throw new LockAcquireException('Existing alarm was not expected'); } diff --git a/tests/mutex/CASMutexTest.php b/tests/mutex/CASMutexTest.php index 4f528257..839df769 100644 --- a/tests/mutex/CASMutexTest.php +++ b/tests/mutex/CASMutexTest.php @@ -7,13 +7,11 @@ use phpmock\phpunit\PHPMock; use PHPUnit\Framework\TestCase; -/** - * Tests for CASMutex. - */ class CASMutexTest extends TestCase { use PHPMock; + #[\Override] protected function setUp(): void { parent::setUp(); @@ -30,7 +28,7 @@ protected function setUp(): void /** * Tests exceeding the execution timeout. */ - public function testExceedTimeout() + public function testExceedTimeout(): void { $this->expectException(LockAcquireException::class); @@ -43,7 +41,7 @@ public function testExceedTimeout() /** * Tests that an exception would stop any further iteration. */ - public function testExceptionStopsIteration() + public function testExceptionStopsIteration(): void { $this->expectException(\DomainException::class); @@ -56,7 +54,7 @@ public function testExceptionStopsIteration() /** * Tests notify() will stop the iteration and return the result. */ - public function testNotify() + public function testNotify(): void { $i = 0; $mutex = new CASMutex(); @@ -70,7 +68,7 @@ public function testNotify() /** * Tests that the code is executed more times. */ - public function testIteration() + public function testIteration(): void { $i = 0; $mutex = new CASMutex(); diff --git a/tests/mutex/FlockMutexTest.php b/tests/mutex/FlockMutexTest.php index 4e5a61ca..283e1ce1 100644 --- a/tests/mutex/FlockMutexTest.php +++ b/tests/mutex/FlockMutexTest.php @@ -10,24 +10,22 @@ class FlockMutexTest extends TestCase { - /** - * @var FlockMutex - */ + /** @var FlockMutex */ private $mutex; - /** - * @var string - */ + /** @var string */ private $file; + #[\Override] protected function setUp(): void { parent::setUp(); $this->file = tempnam(sys_get_temp_dir(), 'flock-'); - $this->mutex = Liberator::liberate(new FlockMutex(fopen($this->file, 'r'), 1)); // @phpstan-ignore-line + $this->mutex = Liberator::liberate(new FlockMutex(fopen($this->file, 'r'), 1)); // @phpstan-ignore assign.propertyType } + #[\Override] protected function tearDown(): void { unlink($this->file); @@ -36,13 +34,15 @@ protected function tearDown(): void } /** - * @dataProvider dpTimeoutableStrategiesCases + * @param FlockMutex::STRATEGY_* $strategy + * + * @dataProvider provideTimeoutableStrategiesCases */ - public function testCodeExecutedOutsideLockIsNotThrown(int $strategy) + public function testCodeExecutedOutsideLockIsNotThrown(int $strategy): void { - $this->mutex->strategy = $strategy; // @phpstan-ignore-line + $this->mutex->strategy = $strategy; // @phpstan-ignore property.private - self::assertTrue($this->mutex->synchronized(static function (): bool { + self::assertTrue($this->mutex->synchronized(static function (): bool { // @phpstan-ignore staticMethod.alreadyNarrowedType usleep(1100 * 1000); return true; @@ -50,9 +50,11 @@ public function testCodeExecutedOutsideLockIsNotThrown(int $strategy) } /** - * @dataProvider dpTimeoutableStrategiesCases + * @param FlockMutex::STRATEGY_* $strategy + * + * @dataProvider provideTimeoutableStrategiesCases */ - public function testTimeoutOccurs(int $strategy) + public function testTimeoutOccurs(int $strategy): void { $this->expectException(TimeoutException::class); $this->expectExceptionMessage('Timeout of 1.0 seconds exceeded.'); @@ -60,7 +62,7 @@ public function testTimeoutOccurs(int $strategy) $another_resource = fopen($this->file, 'r'); flock($another_resource, \LOCK_EX); - $this->mutex->strategy = $strategy; // @phpstan-ignore-line + $this->mutex->strategy = $strategy; // @phpstan-ignore property.private try { $this->mutex->synchronized( @@ -73,7 +75,10 @@ static function () { } } - public static function dpTimeoutableStrategiesCases(): iterable + /** + * @return iterable> + */ + public static function provideTimeoutableStrategiesCases(): iterable { return [ [FlockMutex::STRATEGY_PCNTL], @@ -81,14 +86,14 @@ public static function dpTimeoutableStrategiesCases(): iterable ]; } - public function testNoTimeoutWaitsForever() + public function testNoTimeoutWaitsForever(): void { $this->expectException(DeadlineException::class); $another_resource = fopen($this->file, 'r'); flock($another_resource, \LOCK_EX); - $this->mutex->strategy = FlockMutex::STRATEGY_BLOCK; // @phpstan-ignore-line + $this->mutex->strategy = FlockMutex::STRATEGY_BLOCK; // @phpstan-ignore property.private $timebox = new PcntlTimeout(1); $timebox->timeBoxed(function () { diff --git a/tests/mutex/LockMutexTest.php b/tests/mutex/LockMutexTest.php index b93df070..cd06bfd0 100644 --- a/tests/mutex/LockMutexTest.php +++ b/tests/mutex/LockMutexTest.php @@ -7,16 +7,12 @@ use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -/** - * Tests for LockMutex. - */ class LockMutexTest extends TestCase { - /** - * @var MockObject|LockMutex The SUT - */ + /** @var MockObject|LockMutex The SUT */ private $mutex; + #[\Override] protected function setUp(): void { parent::setUp(); @@ -27,7 +23,7 @@ protected function setUp(): void /** * Tests lock() fails and the code is not executed. */ - public function testLockFails() + public function testLockFails(): void { $this->expectException(LockAcquireException::class); @@ -43,7 +39,7 @@ public function testLockFails() /** * Tests unlock() is called after the code was executed. */ - public function testUnlockAfterCode() + public function testUnlockAfterCode(): void { $this->mutex->expects(self::once()) ->method('unlock'); @@ -54,7 +50,7 @@ public function testUnlockAfterCode() /** * Tests unlock() is called after an exception. */ - public function testUnlockAfterException() + public function testUnlockAfterException(): void { $this->mutex->expects(self::once()) ->method('unlock'); @@ -68,7 +64,7 @@ public function testUnlockAfterException() /** * Tests unlock() fails after the code was executed. */ - public function testUnlockFailsAfterCode() + public function testUnlockFailsAfterCode(): void { $this->expectException(LockReleaseException::class); @@ -82,7 +78,7 @@ public function testUnlockFailsAfterCode() /** * Tests unlock() fails after the code threw an exception. */ - public function testUnlockFailsAfterException() + public function testUnlockFailsAfterException(): void { $this->expectException(LockReleaseException::class); @@ -98,7 +94,7 @@ public function testUnlockFailsAfterException() /** * Tests the code result is available in LockReleaseException. */ - public function testCodeResultAvailableAfterFailedUnlock() + public function testCodeResultAvailableAfterFailedUnlock(): void { $this->mutex->expects(self::once()) ->method('unlock') @@ -117,7 +113,7 @@ public function testCodeResultAvailableAfterFailedUnlock() /** * Tests the code exception is available in LockReleaseException. */ - public function testCodeExceptionAvailableAfterFailedUnlock() + public function testCodeExceptionAvailableAfterFailedUnlock(): void { $this->mutex->expects(self::once()) ->method('unlock') diff --git a/tests/mutex/MemcachedMutexTest.php b/tests/mutex/MemcachedMutexTest.php index 094e7f5d..48eae889 100644 --- a/tests/mutex/MemcachedMutexTest.php +++ b/tests/mutex/MemcachedMutexTest.php @@ -16,16 +16,13 @@ */ class MemcachedMutexTest extends TestCase { - /** - * @var \Memcached|MockObject - */ + /** @var \Memcached|MockObject */ protected $memcached; - /** - * @var MemcachedMutex - */ + /** @var MemcachedMutex */ private $mutex; + #[\Override] protected function setUp(): void { $this->memcached = $this->createMock(\Memcached::class); @@ -35,7 +32,7 @@ protected function setUp(): void /** * Tests failing to acquire the lock within the timeout. */ - public function testFailAcquireLock() + public function testFailAcquireLock(): void { $this->expectException(TimeoutException::class); @@ -52,7 +49,7 @@ public function testFailAcquireLock() /** * Tests failing to release a lock. */ - public function testFailReleasingLock() + public function testFailReleasingLock(): void { $this->expectException(LockReleaseException::class); diff --git a/tests/mutex/MutexConcurrencyTest.php b/tests/mutex/MutexConcurrencyTest.php index d499a6fc..65ffeec9 100644 --- a/tests/mutex/MutexConcurrencyTest.php +++ b/tests/mutex/MutexConcurrencyTest.php @@ -6,7 +6,6 @@ use PHPUnit\Framework\Constraint\IsType; use PHPUnit\Framework\TestCase; use Predis\Client; -use Redis; use Spatie\Async\Pool; /** @@ -21,20 +20,18 @@ */ class MutexConcurrencyTest extends TestCase { - /** - * @var array - */ - private static $temporaryFiles = []; - /** - * @var \PDO|null the pdo instance - */ + /** @var list */ + protected static $temporaryFiles = []; + /** @var \PDO|null the pdo instance */ private $pdo; + #[\Override] public static function tearDownAfterClass(): void { foreach (self::$temporaryFiles as $temporaryFile) { unlink($temporaryFile); } + self::$temporaryFiles = []; parent::tearDownAfterClass(); } @@ -64,7 +61,7 @@ private function getPDO(string $dsn, string $user, string $password): \PDO * @param int $concurrency the amount of forks * @param callable $code the code for the fork */ - private function fork(int $concurrency, callable $code) + private function fork(int $concurrency, callable $code): void { $pool = Pool::create(); @@ -85,7 +82,7 @@ private function fork(int $concurrency, callable $code) * * @slowThreshold 1000 */ - public function testHighContention(callable $code, callable $mutexFactory) + public function testHighContention(callable $code, callable $mutexFactory): void { $concurrency = 10; $iterations = 1000 / $concurrency; @@ -107,6 +104,8 @@ public function testHighContention(callable $code, callable $mutexFactory) /** * Returns test cases for testHighContention(). + * + * @return iterable> */ public function provideHighContentionCases(): iterable { @@ -198,7 +197,7 @@ function ($timeout = 3) use ($dsn, $user, $password) { * * @slowThreshold 2000 */ - public function testExecutionIsSerializedWhenLocked(callable $mutexFactory) + public function testExecutionIsSerializedWhenLocked(callable $mutexFactory): void { $time = \microtime(true); @@ -235,7 +234,7 @@ public static function provideExecutionIsSerializedWhenLockedCases(): iterable 'flockWithTimoutPcntl' => [static function ($timeout = 3) use ($filename): Mutex { $file = fopen($filename, 'w'); $lock = Liberator::liberate(new FlockMutex($file, $timeout)); - $lock->strategy = FlockMutex::STRATEGY_PCNTL; // @phpstan-ignore-line + $lock->strategy = FlockMutex::STRATEGY_PCNTL; // @phpstan-ignore property.notFound return $lock->popsValue(); }], @@ -243,7 +242,7 @@ public static function provideExecutionIsSerializedWhenLockedCases(): iterable 'flockWithTimoutBusy' => [static function ($timeout = 3) use ($filename): Mutex { $file = fopen($filename, 'w'); $lock = Liberator::liberate(new FlockMutex($file, $timeout)); - $lock->strategy = FlockMutex::STRATEGY_BUSY; // @phpstan-ignore-line + $lock->strategy = FlockMutex::STRATEGY_BUSY; // @phpstan-ignore property.notFound return $lock->popsValue(); }], diff --git a/tests/mutex/MutexTest.php b/tests/mutex/MutexTest.php index 9633f4ee..f80c5d8e 100644 --- a/tests/mutex/MutexTest.php +++ b/tests/mutex/MutexTest.php @@ -6,7 +6,6 @@ use org\bovigo\vfs\vfsStream; use PHPUnit\Framework\TestCase; use Predis\Client; -use Redis; /** * Tests for Mutex. @@ -20,6 +19,7 @@ class MutexTest extends TestCase { protected const TIMEOUT = 4; + #[\Override] public static function setUpBeforeClass(): void { vfsStream::setup('test'); @@ -53,7 +53,7 @@ public function provideMutexFactoriesCases(): iterable 'flockWithTimoutPcntl' => [static function (): Mutex { $file = fopen(vfsStream::url('test/lock'), 'w'); $lock = Liberator::liberate(new FlockMutex($file, 3)); - $lock->strategy = FlockMutex::STRATEGY_PCNTL; // @phpstan-ignore-line + $lock->strategy = FlockMutex::STRATEGY_PCNTL; // @phpstan-ignore property.notFound return $lock->popsValue(); }], @@ -61,7 +61,7 @@ public function provideMutexFactoriesCases(): iterable 'flockWithTimoutBusy' => [static function ($timeout = 3): Mutex { $file = fopen(vfsStream::url('test/lock'), 'w'); $lock = Liberator::liberate(new FlockMutex($file, 3)); - $lock->strategy = FlockMutex::STRATEGY_BUSY; // @phpstan-ignore-line + $lock->strategy = FlockMutex::STRATEGY_BUSY; // @phpstan-ignore property.notFound return $lock->popsValue(); }], @@ -175,7 +175,7 @@ static function ($uri) { * * @dataProvider provideMutexFactoriesCases */ - public function testSynchronizedDelegates(callable $mutexFactory) + public function testSynchronizedDelegates(callable $mutexFactory): void { /** @var Mutex $mutex */ $mutex = $mutexFactory(); @@ -192,7 +192,7 @@ public function testSynchronizedDelegates(callable $mutexFactory) * * @dataProvider provideMutexFactoriesCases */ - public function testRelease(callable $mutexFactory) + public function testRelease(callable $mutexFactory): void { $mutex = call_user_func($mutexFactory); $mutex->synchronized(static function () {}); @@ -208,7 +208,7 @@ public function testRelease(callable $mutexFactory) * * @dataProvider provideMutexFactoriesCases */ - public function testSynchronizedPassesExceptionThrough(callable $mutexFactory) + public function testSynchronizedPassesExceptionThrough(callable $mutexFactory): void { $this->expectException(\DomainException::class); diff --git a/tests/mutex/PHPRedisMutexTest.php b/tests/mutex/PHPRedisMutexTest.php index 2a72c999..4aa7bb0b 100644 --- a/tests/mutex/PHPRedisMutexTest.php +++ b/tests/mutex/PHPRedisMutexTest.php @@ -6,19 +6,24 @@ use malkusch\lock\exception\LockReleaseException; use malkusch\lock\exception\MutexException; use PHPUnit\Framework\TestCase; -use Redis; if (\PHP_MAJOR_VERSION >= 8) { trait RedisTestTrait { - #[\Override] + /** + * @param list $args + */ + #[\Override] // @phpstan-ignore method.childParameterType public function eval($script, $args = [], $numKeys = 0): mixed { return $this->_eval($script, $args, $numKeys); } + /** + * @param mixed $options + */ #[\Override] - public function set($key, $value, $options = null): /* Redis|string| */ bool + public function set($key, $value, $options = null): /* \Redis|string| */ bool { return $this->_set($key, $value, $options); } @@ -59,21 +64,18 @@ public function set($key, $value, $options = null) */ class PHPRedisMutexTest extends TestCase { - /** - * @var \Redis[] - */ + /** @var \Redis[] */ private $connections = []; - /** - * @var PHPRedisMutex the SUT - */ + /** @var PHPRedisMutex the SUT */ private $mutex; + #[\Override] protected function setUp(): void { parent::setUp(); - $uris = explode(',', getenv('REDIS_URIS') ?: 'redis://localhost'); + $uris = explode(',', getenv('REDIS_URIS') ?: 'redis://localhost'); // @phpstan-ignore ternary.shortNotAllowed foreach ($uris as $redisUri) { $uri = parse_url($redisUri); @@ -82,8 +84,10 @@ protected function setUp(): void $connection = new class extends \Redis { use RedisTestTrait; + /** @var bool */ private $is_closed = false; + #[\Override] public function close(): bool { $res = parent::close(); @@ -92,7 +96,13 @@ public function close(): bool return $res; } - private function _set($key, $value, $timeout = 0) + /** + * @param mixed $value + * @param mixed $timeout + * + * @return \Redis|string|bool + */ + private function _set(string $key, $value, $timeout = 0) { if ($this->is_closed) { throw new \RedisException('Connection is closed'); @@ -101,7 +111,12 @@ private function _set($key, $value, $timeout = 0) return parent::set($key, $value, $timeout); } - private function _eval($script, $args = [], $numKeys = 0) + /** + * @param list $args + * + * @return mixed + */ + private function _eval(string $script, array $args = [], int $numKeys = 0) { if ($this->is_closed) { throw new \RedisException('Connection is closed'); @@ -128,7 +143,7 @@ private function _eval($script, $args = [], $numKeys = 0) $this->mutex = new PHPRedisMutex($this->connections, 'test'); } - private function closeMajorityConnections() + private function closeMajorityConnections(): void { $numberToClose = (int) ceil(count($this->connections) / 2); @@ -137,7 +152,7 @@ private function closeMajorityConnections() } } - private function closeMinorityConnections() + private function closeMinorityConnections(): void { if (count($this->connections) === 1) { self::markTestSkipped('Cannot test this with only a single Redis server'); @@ -153,7 +168,7 @@ private function closeMinorityConnections() } } - public function testAddFails() + public function testAddFails(): void { $this->expectException(LockAcquireException::class); $this->expectExceptionCode(MutexException::REDIS_NOT_ENOUGH_SERVERS); @@ -168,7 +183,7 @@ public function testAddFails() /** * Tests evalScript() fails. */ - public function testEvalScriptFails() + public function testEvalScriptFails(): void { $this->expectException(LockReleaseException::class); @@ -178,9 +193,12 @@ public function testEvalScriptFails() } /** + * @param \Redis::SERIALIZER_* $serializer + * @param \Redis::COMPRESSION_* $compressor + * * @dataProvider provideSerializersAndCompressorsCases */ - public function testSerializersAndCompressors($serializer, $compressor) + public function testSerializersAndCompressors($serializer, $compressor): void { foreach ($this->connections as $connection) { $connection->setOption(\Redis::OPT_SERIALIZER, $serializer); @@ -192,7 +210,7 @@ public function testSerializersAndCompressors($serializer, $compressor) })); } - public function testResistantToPartialClusterFailuresForAcquiringLock() + public function testResistantToPartialClusterFailuresForAcquiringLock(): void { $this->closeMinorityConnections(); @@ -201,15 +219,18 @@ public function testResistantToPartialClusterFailuresForAcquiringLock() })); } - public function testResistantToPartialClusterFailuresForReleasingLock() + public function testResistantToPartialClusterFailuresForReleasingLock(): void { - self::assertNull($this->mutex->synchronized(function () { + self::assertNull($this->mutex->synchronized(function () { // @phpstan-ignore staticMethod.alreadyNarrowedType $this->closeMinorityConnections(); return null; })); } + /** + * @return iterable> + */ public static function provideSerializersAndCompressorsCases(): iterable { if (!class_exists(\Redis::class)) { diff --git a/tests/mutex/PgAdvisoryLockMutexTest.php b/tests/mutex/PgAdvisoryLockMutexTest.php index 1b8e6842..e4ec39f0 100644 --- a/tests/mutex/PgAdvisoryLockMutexTest.php +++ b/tests/mutex/PgAdvisoryLockMutexTest.php @@ -7,16 +7,13 @@ class PgAdvisoryLockMutexTest extends TestCase { - /** - * @var \PDO|MockObject - */ + /** @var \PDO|MockObject */ private $pdo; - /** - * @var PgAdvisoryLockMutex - */ + /** @var PgAdvisoryLockMutex */ private $mutex; + #[\Override] protected function setUp(): void { parent::setUp(); @@ -26,7 +23,7 @@ protected function setUp(): void $this->mutex = new PgAdvisoryLockMutex($this->pdo, 'test' . uniqid()); } - public function testAcquireLock() + public function testAcquireLock(): void { $statement = $this->createMock(\PDOStatement::class); @@ -56,7 +53,7 @@ public function testAcquireLock() $this->mutex->lock(); } - public function testReleaseLock() + public function testReleaseLock(): void { $statement = $this->createMock(\PDOStatement::class); diff --git a/tests/mutex/PredisMutexTest.php b/tests/mutex/PredisMutexTest.php index 588092ac..6580a403 100644 --- a/tests/mutex/PredisMutexTest.php +++ b/tests/mutex/PredisMutexTest.php @@ -13,30 +13,25 @@ /** * Tests for PredisMutex. * - * @group redis + * @group redis */ class PredisMutexTest extends TestCase { - /** - * @var ClientInterface|MockObject - */ + /** @var ClientInterface|MockObject */ private $client; - /** - * @var PredisMutex - */ + /** @var PredisMutex */ private $mutex; - /** - * @var LoggerInterface|MockObject - */ + /** @var LoggerInterface|MockObject */ private $logger; + #[\Override] protected function setUp(): void { parent::setUp(); - $this->client = $this->getMockBuilder(ClientInterface::class) + $this->client = $this->getMockBuilder(ClientInterface::class) // @phpstan-ignore method.deprecated ->setMethods(array_merge(get_class_methods(ClientInterface::class), ['set', 'eval'])) ->getMock(); @@ -49,7 +44,7 @@ protected function setUp(): void /** * Tests add() fails. */ - public function testAddFailsToSetKey() + public function testAddFailsToSetKey(): void { $this->client->expects(self::atLeastOnce()) ->method('set') @@ -71,7 +66,7 @@ static function (): void { /** * Tests add() errors. */ - public function testAddErrors() + public function testAddErrors(): void { $this->client->expects(self::atLeastOnce()) ->method('set') @@ -91,7 +86,7 @@ static function () { ); } - public function testWorksNormally() + public function testWorksNormally(): void { $this->client->expects(self::atLeastOnce()) ->method('set') @@ -115,7 +110,7 @@ public function testWorksNormally() /** * Tests evalScript() fails. */ - public function testEvalScriptFails() + public function testEvalScriptFails(): void { $this->client->expects(self::atLeastOnce()) ->method('set') diff --git a/tests/mutex/RedisMutexTest.php b/tests/mutex/RedisMutexTest.php index 9f8069fc..100dbc31 100644 --- a/tests/mutex/RedisMutexTest.php +++ b/tests/mutex/RedisMutexTest.php @@ -20,6 +20,7 @@ class RedisMutexTest extends TestCase { use PHPMock; + #[\Override] protected function setUp(): void { parent::setUp(); @@ -61,7 +62,7 @@ static function ($id): array { * * @dataProvider provideMinorityCases */ - public function testTooFewServerToAcquire(int $count, int $available) + public function testTooFewServerToAcquire(int $count, int $available): void { $this->expectException(LockAcquireException::class); $this->expectExceptionCode(MutexException::REDIS_NOT_ENOUGH_SERVERS); @@ -96,7 +97,7 @@ static function () use (&$i, $available): bool { * * @dataProvider provideMajorityCases */ - public function testFaultTolerance(int $count, int $available) + public function testFaultTolerance(int $count, int $available): void { $mutex = $this->buildRedisMutex($count); $mutex->expects(self::exactly($count)) @@ -129,7 +130,7 @@ static function () use (&$i, $available): bool { * * @dataProvider provideMinorityCases */ - public function testAcquireTooFewKeys($count, $available) + public function testAcquireTooFewKeys($count, $available): void { $this->expectException(TimeoutException::class); $this->expectExceptionMessage('Timeout of 1.0 seconds exceeded.'); @@ -161,7 +162,7 @@ static function () use (&$i, $available): bool { * * @dataProvider provideTimingOutCases */ - public function testTimingOut(int $count, float $timeout, float $delay) + public function testTimingOut(int $count, float $timeout, float $delay): void { $timeoutStr = (string) round($timeout, 6); if (strpos($timeoutStr, '.') === false) { @@ -189,7 +190,7 @@ public function testTimingOut(int $count, float $timeout, float $delay) /** * Returns test cases for testTimingOut(). * - * @return array test cases + * @return iterable> */ public static function provideTimingOutCases(): iterable { @@ -208,7 +209,7 @@ public static function provideTimingOutCases(): iterable * * @dataProvider provideMajorityCases */ - public function testAcquireWithMajority(int $count, int $available) + public function testAcquireWithMajority(int $count, int $available): void { $mutex = $this->buildRedisMutex($count); $mutex->expects(self::exactly($count)) @@ -237,7 +238,7 @@ static function () use (&$i, $available): bool { * * @dataProvider provideMinorityCases */ - public function testTooFewServersToRelease(int $count, int $available) + public function testTooFewServersToRelease(int $count, int $available): void { $mutex = $this->buildRedisMutex($count); $mutex->expects(self::exactly($count)) diff --git a/tests/mutex/SpinlockMutexTest.php b/tests/mutex/SpinlockMutexTest.php index 29c71b79..e78f8a2b 100644 --- a/tests/mutex/SpinlockMutexTest.php +++ b/tests/mutex/SpinlockMutexTest.php @@ -11,13 +11,11 @@ use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -/** - * Tests for SpinlockMutex. - */ class SpinlockMutexTest extends TestCase { use PHPMock; + #[\Override] protected function setUp(): void { parent::setUp(); @@ -34,7 +32,7 @@ protected function setUp(): void /** * Tests failing to acquire the lock. */ - public function testFailAcquireLock() + public function testFailAcquireLock(): void { $this->expectException(LockAcquireException::class); @@ -51,7 +49,7 @@ public function testFailAcquireLock() /** * Tests failing to acquire the lock due to a timeout. */ - public function testAcquireTimesOut() + public function testAcquireTimesOut(): void { $this->expectException(TimeoutException::class); $this->expectExceptionMessage('Timeout of 3.0 seconds exceeded.'); @@ -69,10 +67,10 @@ public function testAcquireTimesOut() /** * Tests executing code which exceeds the timeout fails. */ - public function testExecuteTooLong() + public function testExecuteTooLong(): void { /** @var SpinlockMutex|MockObject $mutex */ - $mutex = $this->getMockForAbstractClass(SpinlockMutex::class, ['test', 0.5]); + $mutex = $this->getMockForAbstractClass(SpinlockMutex::class, ['test', 0.5]); // @phpstan-ignore varTag.nativeType $mutex->expects(self::any()) ->method('acquire') ->willReturn(true); @@ -95,7 +93,7 @@ public function testExecuteTooLong() /** * Tests executing code which barely doesn't hit the timeout. */ - public function testExecuteBarelySucceeds() + public function testExecuteBarelySucceeds(): void { $mutex = $this->getMockForAbstractClass(SpinlockMutex::class, ['test', 0.5]); $mutex->expects(self::any())->method('acquire')->willReturn(true); @@ -109,7 +107,7 @@ public function testExecuteBarelySucceeds() /** * Tests failing to release a lock. */ - public function testFailReleasingLock() + public function testFailReleasingLock(): void { $this->expectException(LockReleaseException::class); @@ -123,7 +121,7 @@ public function testFailReleasingLock() /** * Tests executing exactly until the timeout will leave the key one more second. */ - public function testExecuteTimeoutLeavesOneSecondForKeyToExpire() + public function testExecuteTimeoutLeavesOneSecondForKeyToExpire(): void { $mutex = $this->getMockForAbstractClass(SpinlockMutex::class, ['test', 0.2]); $mutex->expects(self::once()) diff --git a/tests/mutex/TransactionalMutexTest.php b/tests/mutex/TransactionalMutexTest.php index 08fde681..b4f7463a 100644 --- a/tests/mutex/TransactionalMutexTest.php +++ b/tests/mutex/TransactionalMutexTest.php @@ -19,7 +19,7 @@ class TransactionalMutexTest extends TestCase * * @dataProvider provideInvalidErrorModeCases */ - public function testInvalidErrorMode(int $mode) + public function testInvalidErrorMode(int $mode): void { $this->expectException(\InvalidArgumentException::class); @@ -30,6 +30,8 @@ public function testInvalidErrorMode(int $mode) /** * Returns test cases for testInvalidErrorMode(). + * + * @return iterable> */ public static function provideInvalidErrorModeCases(): iterable { @@ -42,7 +44,7 @@ public static function provideInvalidErrorModeCases(): iterable /** * Tests BEGIN fails. */ - public function testBeginFails() + public function testBeginFails(): void { $this->expectException(LockAcquireException::class); $this->expectExceptionMessage('Could not begin transaction.'); @@ -60,7 +62,7 @@ public function testBeginFails() /** * Tests that an exception in the critical code causes a ROLLBACK. */ - public function testExceptionRollsback() + public function testExceptionRollsback(): void { $pdo = $this->buildMySqlPdo(); $mutex = new TransactionalMutex($pdo); @@ -88,7 +90,7 @@ public function testExceptionRollsback() /** * Tests that a ROLLBACK caused by an exception fails. */ - public function testFailExceptionRollsback() + public function testFailExceptionRollsback(): void { $pdo = $this->buildMySqlPdo(); $mutex = new TransactionalMutex($pdo); @@ -110,7 +112,7 @@ public function testFailExceptionRollsback() * * @dataProvider provideReplayTransactionCases */ - public function testReplayTransaction(\Exception $exception) + public function testReplayTransaction(\Exception $exception): void { $pdo = $this->buildMySqlPdo(); $mutex = new TransactionalMutex($pdo); @@ -158,7 +160,7 @@ public static function provideReplayTransactionCases(): iterable /** * Tests failing a ROLLBACK after the failed COMMIT. */ - public function testRollbackAfterFailedCommitFails() + public function testRollbackAfterFailedCommitFails(): void { $this->expectException(LockAcquireException::class); $this->expectExceptionMessage('Could not roll back transaction:'); diff --git a/tests/util/DoubleCheckedLockingTest.php b/tests/util/DoubleCheckedLockingTest.php index 19aa537e..3df4b0fd 100644 --- a/tests/util/DoubleCheckedLockingTest.php +++ b/tests/util/DoubleCheckedLockingTest.php @@ -6,16 +6,12 @@ use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -/** - * Tests for DoubleCheckedLocking. - */ class DoubleCheckedLockingTest extends TestCase { - /** - * @var Mutex|MockObject the Mutex mock - */ + /** @var Mutex|MockObject the Mutex mock */ private $mutex; + #[\Override] protected function setUp(): void { parent::setUp(); @@ -26,7 +22,7 @@ protected function setUp(): void /** * Tests that the lock will not be acquired for a failing test. */ - public function testCheckFailsAcquiresNoLock() + public function testCheckFailsAcquiresNoLock(): void { $this->mutex->expects(self::never())->method('synchronized'); @@ -39,13 +35,13 @@ public function testCheckFailsAcquiresNoLock() }); // Failed check should return false. - self::assertFalse($result); + self::assertFalse($result); // @phpstan-ignore staticMethod.impossibleType } /** * Tests that the check and execution are in the same lock. */ - public function testLockedCheckAndExecution() + public function testLockedCheckAndExecution(): void { $lock = 0; $check = 0; @@ -88,7 +84,7 @@ public function testLockedCheckAndExecution() * * @dataProvider provideCodeNotExecutedCases */ - public function testCodeNotExecuted(callable $check) + public function testCodeNotExecuted(callable $check): void { $this->mutex->expects(self::any()) ->method('synchronized') @@ -102,7 +98,7 @@ public function testCodeNotExecuted(callable $check) }); // Each failed check should return false. - self::assertFalse($result); + self::assertFalse($result); // @phpstan-ignore staticMethod.impossibleType } /** @@ -131,7 +127,7 @@ public static function provideCodeNotExecutedCases(): iterable /** * Tests that the code executed if the checks are true. */ - public function testCodeExecuted() + public function testCodeExecuted(): void { $this->mutex->expects(self::once()) ->method('synchronized') diff --git a/tests/util/LoopTest.php b/tests/util/LoopTest.php index 606f1f67..2c54dbf0 100644 --- a/tests/util/LoopTest.php +++ b/tests/util/LoopTest.php @@ -7,13 +7,11 @@ use phpmock\phpunit\PHPMock; use PHPUnit\Framework\TestCase; -/** - * Tests for Loop. - */ class LoopTest extends TestCase { use PHPMock; + #[\Override] protected function setUp(): void { parent::setUp(); @@ -29,7 +27,7 @@ protected function setUp(): void /** * Test an invalid timeout. */ - public function testInvalidTimeout() + public function testInvalidTimeout(): void { $this->expectException(\LengthException::class); @@ -39,7 +37,7 @@ public function testInvalidTimeout() /** * Tests execution within the timeout. */ - public function testExecutionWithinTimeout() + public function testExecutionWithinTimeout(): void { $this->expectNotToPerformAssertions(); @@ -53,7 +51,7 @@ public function testExecutionWithinTimeout() /** * Tests execution within the timeout without calling end(). */ - public function testExecutionWithinTimeoutWithoutExplicitEnd() + public function testExecutionWithinTimeoutWithoutExplicitEnd(): void { $this->expectException(TimeoutException::class); $this->expectExceptionMessage('Timeout of 0.5 seconds exceeded.'); @@ -67,7 +65,7 @@ public function testExecutionWithinTimeoutWithoutExplicitEnd() /** * Tests exceeding the execution timeout. */ - public function testExceedTimeoutIsAcceptableIfEndWasCalled() + public function testExceedTimeoutIsAcceptableIfEndWasCalled(): void { $this->expectNotToPerformAssertions(); @@ -81,7 +79,7 @@ public function testExceedTimeoutIsAcceptableIfEndWasCalled() /** * Tests exceeding the execution timeout without calling end(). */ - public function testExceedTimeoutWithoutExplicitEnd() + public function testExceedTimeoutWithoutExplicitEnd(): void { $this->expectException(TimeoutException::class); $this->expectExceptionMessage('Timeout of 0.5 seconds exceeded.'); @@ -95,7 +93,7 @@ public function testExceedTimeoutWithoutExplicitEnd() /** * Tests that an exception would stop any further iteration. */ - public function testExceptionStopsIteration() + public function testExceptionStopsIteration(): void { $this->expectException(\DomainException::class); @@ -108,7 +106,7 @@ public function testExceptionStopsIteration() /** * Tests end() will stop the iteration and return the result. */ - public function testEnd() + public function testEnd(): void { $i = 0; $loop = new Loop(); @@ -122,7 +120,7 @@ public function testEnd() /** * Tests that the code is executed more times. */ - public function testIteration() + public function testIteration(): void { $i = 0; $loop = new Loop(); diff --git a/tests/util/PcntlTimeoutTest.php b/tests/util/PcntlTimeoutTest.php index 44b4ed42..c76ea36c 100644 --- a/tests/util/PcntlTimeoutTest.php +++ b/tests/util/PcntlTimeoutTest.php @@ -16,7 +16,7 @@ class PcntlTimeoutTest extends TestCase /** * A long running system call should be interrupted. */ - public function testShouldTimeout() + public function testShouldTimeout(): void { $this->expectException(DeadlineException::class); @@ -30,7 +30,7 @@ public function testShouldTimeout() /** * A short running system call should complete its execution. */ - public function testShouldNotTimeout() + public function testShouldNotTimeout(): void { $timeout = new PcntlTimeout(1); @@ -44,7 +44,7 @@ public function testShouldNotTimeout() /** * When a previous scheduled alarm exists, it should fail. */ - public function testShouldFailOnExistingAlarm() + public function testShouldFailOnExistingAlarm(): void { $this->expectException(LockAcquireException::class); @@ -63,7 +63,7 @@ public function testShouldFailOnExistingAlarm() /** * After not timing out, there should be no alarm scheduled. */ - public function testShouldResetAlarmWhenNotTimeout() + public function testShouldResetAlarmWhenNotTimeout(): void { $timeout = new PcntlTimeout(3);