Re-implement CLIENT command as container command (#1337)

This commit is contained in:
Vladyslav Vildanov
2023-07-19 10:23:28 +03:00
committed by GitHub
parent e8daf1abaf
commit 00e87640a7
5 changed files with 245 additions and 53 deletions
+12 -11
View File
@@ -38,11 +38,12 @@ use Predis\Command\Argument\TimeSeries\MGetArguments;
use Predis\Command\Argument\TimeSeries\MRangeArguments;
use Predis\Command\Argument\TimeSeries\RangeArguments;
use Predis\Command\CommandInterface;
use Predis\Command\Redis\Container\ACL;
use Predis\Command\Redis\Container\FunctionContainer;
use Predis\Command\Redis\Container\Json\JSONDEBUG;
use Predis\Command\Redis\Container\Search\FTCONFIG;
use Predis\Command\Redis\Container\Search\FTCURSOR;
use Predis\Command\Container\ACL;
use Predis\Command\Container\CLIENT;
use Predis\Command\Container\FUNCTIONS;
use Predis\Command\Container\Json\JSONDEBUG;
use Predis\Command\Container\Search\FTCONFIG;
use Predis\Command\Container\Search\FTCURSOR;
/**
* Interface defining a client-side context such as a pipeline or transaction.
@@ -316,7 +317,6 @@ use Predis\Command\Redis\Container\Search\FTCURSOR;
* @method $this select($database)
* @method $this bgrewriteaof()
* @method $this bgsave()
* @method $this client($subcommand, $argument = null)
* @method $this config($subcommand, $argument = null)
* @method $this dbsize()
* @method $this flushall()
@@ -338,11 +338,12 @@ use Predis\Command\Redis\Container\Search\FTCURSOR;
* @method $this geosearchstore(string $destination, string $source, FromInterface $from, ByInterface $by, ?string $sorting = null, int $count = -1, bool $any = false, bool $storeDist = false)
*
* Container commands
* @property FunctionContainer $function
* @property FTCONFIG $ftconfig
* @property FTCURSOR $ftcursor
* @property JSONDEBUG $jsondebug
* @property ACL $acl
* @property CLIENT $client
* @property FUNCTIONS $function
* @property FTCONFIG $ftconfig
* @property FTCURSOR $ftcursor
* @property JSONDEBUG $jsondebug
* @property ACL $acl
*/
interface ClientContextInterface
{
+12 -11
View File
@@ -38,12 +38,13 @@ use Predis\Command\Argument\TimeSeries\MGetArguments;
use Predis\Command\Argument\TimeSeries\MRangeArguments;
use Predis\Command\Argument\TimeSeries\RangeArguments;
use Predis\Command\CommandInterface;
use Predis\Command\Container\ACL;
use Predis\Command\Container\CLIENT;
use Predis\Command\Container\FUNCTIONS;
use Predis\Command\Container\Json\JSONDEBUG;
use Predis\Command\Container\Search\FTCONFIG;
use Predis\Command\Container\Search\FTCURSOR;
use Predis\Command\FactoryInterface;
use Predis\Command\Redis\Container\ACL;
use Predis\Command\Redis\Container\FunctionContainer;
use Predis\Command\Redis\Container\Json\JSONDEBUG;
use Predis\Command\Redis\Container\Search\FTCONFIG;
use Predis\Command\Redis\Container\Search\FTCURSOR;
use Predis\Configuration\OptionsInterface;
use Predis\Connection\ConnectionInterface;
use Predis\Response\Status;
@@ -334,7 +335,6 @@ use Predis\Response\Status;
* @method mixed select(int $database)
* @method mixed bgrewriteaof()
* @method mixed bgsave()
* @method mixed client($subcommand, $argument = null)
* @method mixed config($subcommand, $argument = null)
* @method int dbsize()
* @method mixed flushall()
@@ -356,11 +356,12 @@ use Predis\Response\Status;
* @method int geosearchstore(string $destination, string $source, FromInterface $from, ByInterface $by, ?string $sorting = null, int $count = -1, bool $any = false, bool $storeDist = false)
*
* Container commands
* @property FunctionContainer $function
* @property FTCONFIG $ftconfig
* @property FTCURSOR $ftcursor
* @property JSONDEBUG $jsondebug
* @property ACL $acl
* @property CLIENT $client
* @property FUNCTIONS $function
* @property FTCONFIG $ftconfig
* @property FTCURSOR $ftcursor
* @property JSONDEBUG $jsondebug
* @property ACL $acl
*/
interface ClientInterface
{
+31
View File
@@ -0,0 +1,31 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) 2009-2020 Daniele Alessandri
* (c) 2021-2023 Till Krüss
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Command\Container;
use Predis\Response\Status;
/**
* @method string getName()
* @method Status kill(...$arguments)
* @method string list(string $type = null, int ...$clientId)
* @method Status noTouch(bool $enable = null)
* @method Status setInfo(string $modifier = null, string $value = null)
* @method Status setName(string $connectionName)
*/
class CLIENT extends AbstractContainer
{
public function getContainerCommandId(): string
{
return 'CLIENT';
}
}
+67
View File
@@ -30,6 +30,73 @@ class CLIENT extends RedisCommand
return 'CLIENT';
}
public function setArguments(array $arguments)
{
switch ($arguments[0]) {
case 'LIST':
$this->setListArguments($arguments);
break;
case 'NOTOUCH':
$arguments[0] = 'NO-TOUCH';
$this->setNoTouchArguments($arguments);
break;
case 'SETINFO':
$this->setSetInfoArguments($arguments);
break;
default:
parent::setArguments($arguments);
}
}
private function setListArguments(array $arguments): void
{
$processedArguments = [$arguments[0]];
if (array_key_exists(1, $arguments) && null !== $arguments[1]) {
array_push($processedArguments, 'TYPE', strtoupper($arguments[1]));
}
if (array_key_exists(2, $arguments)) {
array_push($processedArguments, 'ID', $arguments[2]);
}
if (count($arguments) > 3) {
for ($i = 3, $iMax = count($arguments); $i < $iMax; $i++) {
$processedArguments[] = $arguments[$i];
}
}
parent::setArguments($processedArguments);
}
private function setNoTouchArguments(array $arguments): void
{
$processedArguments = [$arguments[0]];
if (array_key_exists(1, $arguments) && null !== $arguments[1]) {
$modifier = ($arguments[1]) ? 'ON' : 'OFF';
$processedArguments[] = $modifier;
}
parent::setArguments($processedArguments);
}
private function setSetInfoArguments(array $arguments): void
{
$processedArguments = [$arguments[0]];
if (
array_key_exists(1, $arguments)
&& null !== $arguments[1]
&& array_key_exists(2, $arguments)
&& null !== $arguments[2]
) {
array_push($processedArguments, strtoupper($arguments[1]), $arguments[2]);
}
parent::setArguments($processedArguments);
}
/**
* {@inheritdoc}
*/
+123 -31
View File
@@ -39,8 +39,8 @@ class CLIENT_Test extends PredisCommandTestCase
*/
public function testFilterArgumentsOfClientKill(): void
{
$arguments = ['kill', '127.0.0.1:45393'];
$expected = ['kill', '127.0.0.1:45393'];
$arguments = ['KILL', '127.0.0.1:45393'];
$expected = ['KILL', '127.0.0.1:45393'];
$command = $this->getCommand();
$command->setArguments($arguments);
@@ -49,17 +49,15 @@ class CLIENT_Test extends PredisCommandTestCase
}
/**
* @dataProvider listArgumentsProvider
* @group disconnected
*/
public function testFilterArgumentsOfClientList(): void
public function testFilterArgumentsOfClientList(array $actualArguments, array $expectedArguments): void
{
$arguments = ['list'];
$expected = ['list'];
$command = $this->getCommand();
$command->setArguments($arguments);
$command->setArguments($actualArguments);
$this->assertSame($expected, $command->getArguments());
$this->assertSame($expectedArguments, $command->getArguments());
}
/**
@@ -67,7 +65,7 @@ class CLIENT_Test extends PredisCommandTestCase
*/
public function testFilterArgumentsOfClientGetname(): void
{
$arguments = $expected = ['getname'];
$arguments = $expected = ['GETNAME'];
$command = $this->getCommand();
$command->setArguments($arguments);
@@ -80,7 +78,7 @@ class CLIENT_Test extends PredisCommandTestCase
*/
public function testFilterArgumentsOfClientSetname(): void
{
$arguments = $expected = ['setname', 'connection-a'];
$arguments = $expected = ['SETNAME', 'connection-a'];
$command = $this->getCommand();
$command->setArguments($arguments);
@@ -88,6 +86,30 @@ class CLIENT_Test extends PredisCommandTestCase
$this->assertSame($expected, $command->getArguments());
}
/**
* @dataProvider noTouchArgumentsProvider
* @group disconnected
*/
public function testFilterArgumentsNoTouch(array $actualArguments, array $expectedArguments): void
{
$command = $this->getCommand();
$command->setArguments($actualArguments);
$this->assertSame($expectedArguments, $command->getArguments());
}
/**
* @dataProvider setInfoArgumentsProvider
* @group disconnected
*/
public function testFilterArgumentsSetInfo(array $actualArguments, array $expectedArguments): void
{
$command = $this->getCommand();
$command->setArguments($actualArguments);
$this->assertSame($expectedArguments, $command->getArguments());
}
/**
* @group disconnected
*/
@@ -131,7 +153,7 @@ BUFFER;
{
$redis = $this->getClient();
$this->assertIsArray($clients = $redis->client('LIST'));
$this->assertIsArray($clients = $redis->client->list());
$this->assertGreaterThanOrEqual(1, count($clients));
$this->assertIsArray($clients[0]);
$this->assertArrayHasKey('addr', $clients[0]);
@@ -151,12 +173,12 @@ BUFFER;
public function testGetsNameOfConnection(): void
{
$redis = $this->getClient();
$clientName = $redis->client('GETNAME');
$clientName = $redis->client->getName();
$this->assertNull($clientName);
$expectedConnectionName = 'foo-bar';
$this->assertEquals('OK', $redis->client('SETNAME', $expectedConnectionName));
$this->assertEquals($expectedConnectionName, $redis->client('GETNAME'));
$this->assertEquals('OK', $redis->client->setName($expectedConnectionName));
$this->assertEquals($expectedConnectionName, $redis->client->getName());
}
/**
@@ -168,8 +190,33 @@ BUFFER;
$redis = $this->getClient();
$expectedConnectionName = 'foo-baz';
$this->assertEquals('OK', $redis->client('SETNAME', $expectedConnectionName));
$this->assertEquals($expectedConnectionName, $redis->client('GETNAME'));
$this->assertEquals('OK', $redis->client->setName($expectedConnectionName));
$this->assertEquals($expectedConnectionName, $redis->client->getName());
}
/**
* @group connected
* @requiresRedisVersion >= 7.2.0
*/
public function testNoTouchTurnOnControlOnKeys(): void
{
$redis = $this->getClient();
$this->assertEquals('OK', $redis->client->noTouch(true));
}
/**
* @group connected
* @requiresRedisVersion >= 7.2.0
*/
public function testSetInfoToCurrentClientConnection(): void
{
$redis = $this->getClient();
$this->assertEquals('OK', $redis->client->setInfo('LIB-NAME', 'lib'));
$this->assertEquals('OK', $redis->client->setInfo('LIB-VER', '1.0.0'));
$this->assertSame('lib', $redis->client->list()[0]['lib-name']);
$this->assertSame('1.0.0', $redis->client->list()[0]['lib-ver']);
}
/**
@@ -196,20 +243,7 @@ BUFFER;
$this->expectException('Predis\Response\ServerException');
$redis = $this->getClient();
$redis->client('SETNAME', $invalidConnectionName);
}
/**
* @group connected
* @requiresRedisVersion >= 2.4.0
*/
public function testThrowsExceptioOnWrongModifier(): void
{
$this->expectException('Predis\Response\ServerException');
$redis = $this->getClient();
$redis->client('FOO');
$redis->client->setName($invalidConnectionName);
}
/**
@@ -223,6 +257,64 @@ BUFFER;
$redis = $this->getClient();
$redis->client('KILL', '127.0.0.1:65535');
$redis->client->kill('127.0.0.1:65535');
}
public function listArgumentsProvider(): array
{
return [
'with default arguments' => [
['LIST'],
['LIST'],
],
'with TYPE modifier' => [
['LIST', 'MASTER'],
['LIST', 'TYPE', 'MASTER'],
],
'with ID modifier' => [
['LIST', null, 1, 2, 3],
['LIST', 'ID', 1, 2, 3],
],
];
}
public function noTouchArgumentsProvider(): array
{
return [
'with default arguments' => [
['NOTOUCH'],
['NO-TOUCH'],
],
'with enabled modifier' => [
['NOTOUCH', true],
['NO-TOUCH', 'ON'],
],
'with disabled modifier' => [
['NOTOUCH', false],
['NO-TOUCH', 'OFF'],
],
];
}
public function setInfoArgumentsProvider(): array
{
return [
'with default arguments' => [
['SETINFO'],
['SETINFO'],
],
'with LIB-NAME modifier' => [
['SETINFO', 'LIB-NAME', 'lib'],
['SETINFO', 'LIB-NAME', 'lib'],
],
'with LIB-VER modifier' => [
['SETINFO', 'LIB-VER', '1.0.0'],
['SETINFO', 'LIB-VER', '1.0.0'],
],
'with only modifier given' => [
['SETINFO', 'LIB-VER'],
['SETINFO'],
],
];
}
}