diff --git a/.gitignore b/.gitignore index 8a7575c5..cc9b4e00 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ phpunit.xml experiments/ -test/enable.tests diff --git a/.travis.yml b/.travis.yml index c28c4bad..0fc69047 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,7 @@ language: php php: - 5.3 - 5.4 -before_script: touch test/enable.tests branches: only: - master - - version-0.6 + - v0.7 diff --git a/README.md b/README.md index 8b3f60bd..43b21fc4 100644 --- a/README.md +++ b/README.md @@ -148,27 +148,40 @@ $redis->newcmd(); ``` -## Development ## +## Test suite ## -Predis is fully backed up by a test suite which tries to cover all the aspects of the -client library and the interaction of every single command with a Redis server. If you -want to work on Predis, it is highly recommended that you first run the test suite to -be sure that everything is OK, and report strange behaviours or bugs. +__ATTENTION__: Do not run the test suite shipped with Predis against instances of +Redis running in production environments or containing data you are interested in! -When modifying Predis please be sure that no warnings or notices are emitted by PHP +Predis has a comprehensive test suite covering every aspect of the library. The suite +performs integration tests against a running instance of Redis (>= 2.4.0 is required) +to verify the correct behaviour of the implementation of each command and automatically +skips commands that are not defined in the selected version of Redis. If you do not have +Redis up and running, integration tests can be disabled. By default, the test suite is +configured to execute integration tests using the server profile for Redis v2.4 (which +is the current stable version of Redis). You can optionally run the suite against a +Redis instance built from the `unstable` branch with the development profile by changing +the `TEST_SERVER_VERSION` to `dev` in the `phpunit.xml` file. More details about testing +Predis are available in `tests/README.md`. + +## Contributing ## + +If you want to work on Predis, it is highly recommended that you first run the test +suite in order to check that everything is OK, and report strange behaviours or bugs. + +When modifying Predis please make sure that no warnings or notices are emitted by PHP by running the interpreter in your development environment with the `error_reporting` variable set to `E_ALL | E_STRICT`. The recommended way to contribute to Predis is to fork the project on GitHub, create new topic branches on your newly created repository to fix or add features and then -open a new pull request with a description of the applied changes. Obviously, you can -use any other Git hosting provider of your preference. Diff patches will be accepted -too, even though they are not the preferred way to contribute to Predis. +open a new pull request with a description of the applied changes. Obviously, you +can use any other Git hosting provider of your preference. ## Dependencies ## -- PHP >= 5.3.0 +- PHP >= 5.3.2 - PHPUnit >= 3.5.0 (needed to run the test suite) ## Links ## diff --git a/TODO b/TODO index 97e7ce6a..3ea86486 100644 --- a/TODO +++ b/TODO @@ -2,13 +2,5 @@ * Implement smart and transparent support for redis-cluster. -* Switch to smaller test units and add more granular tests that try to cover - every single class. - * Documentation! The README is obviously not enought to show how to use Predis as it does not cover all of its features. - -* Missing tests for commands: - PUBLISH, SUBSCRIBE, UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, DEBUG, OBJECT, - CLIENT, CONFIG GET, CONFIG SET, CONFIG RESETSTAT, SLOWLOG, SCRIPT, PTTL, - PSETEX, PEXPIRE, PEXPIREAT, INCRBYFLOAT, HINCRBYFLOAT diff --git a/bin/generate-command-test.php b/bin/generate-command-test.php new file mode 100755 index 00000000..dca47c9c --- /dev/null +++ b/bin/generate-command-test.php @@ -0,0 +1,237 @@ +#!/usr/bin/env php + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Predis\Commands\ICommand; +use Predis\Commands\IPrefixable; + +class CommandTestCaseGenerator +{ + private $options; + + public function __construct(Array $options) + { + if (!isset($options['class'])) { + throw new RuntimeException("Missing 'class' option."); + } + $this->options = $options; + } + + public static function fromCommandLine() + { + $parameters = array( + 'c:' => 'class:', + 'r::' => 'realm::', + 'o::' => 'output::', + 'x::' => 'overwrite::' + ); + + $getops = getopt(implode(array_keys($parameters)), $parameters); + + $options = array( + 'overwrite' => false, + 'tests' => __DIR__.'/../tests', + ); + + foreach ($getops as $option => $value) { + switch ($option) { + case 'c': + case 'class': + $options['class'] = $value; + break; + + case 'r': + case 'realm': + $options['realm'] = $value; + break; + + case 'o': + case 'output': + $options['output'] = $value; + break; + + case 'x': + case 'overwrite': + $options['overwrite'] = true; + break; + } + } + + if (!isset($options['class'])) { + throw new RuntimeException("Missing 'class' option."); + } + + $options['fqn'] = "Predis\\Commands\\{$options['class']}"; + $options['path'] = "Predis/Commands/{$options['class']}.php"; + + $source = __DIR__.'/../lib/'.$options['path']; + if (!file_exists($source)) { + throw new RuntimeException("Cannot find class file for {$options['fqn']} in $source."); + } + + if (!isset($options['output'])) { + $options['output'] = sprintf("%s/%s", $options['tests'], str_replace('.php', 'Test.php', $options['path'])); + } + + return new self($options); + } + + protected function getTestRealm() + { + if (isset($this->options['realm'])) { + if (!$this->options['realm']) { + throw new RuntimeException('Invalid value for realm has been sepcified (empty).'); + } + return $this->options['realm']; + } + + $class = array_pop(explode('\\', $this->options['fqn'])); + list($realm,) = preg_split('/([[:upper:]][[:lower:]]+)/', $class, 2, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + + return strtolower($realm); + } + + public function generate() + { + $reflection = new ReflectionClass($class = $this->options['fqn']); + + if (!$reflection->isInstantiable()) { + throw new RuntimeException("Class $class must be instantiable, abstract classes or interfaces are not allowed."); + } + if (!$reflection->implementsInterface('Predis\Commands\ICommand')) { + throw new RuntimeException("Class $class must implement the Predis\Commands\ICommand interface."); + } + + $instance = $reflection->newInstance(); + $buffer = $this->getTestCaseBuffer($instance); + + return $buffer; + } + + public function save() + { + $options = $this->options; + if (file_exists($options['output']) && !$options['overwrite']) { + throw new RuntimeException("File {$options['output']} already exist. Specify the --overwrite option to overwrite the existing file."); + } + file_put_contents($options['output'], $this->generate()); + } + + protected function getTestCaseBuffer(ICommand $instance) + { + $id = $instance->getId(); + $fqn = get_class($instance); + $class = array_pop(explode('\\', $fqn)) . "Test"; + $realm = $this->getTestRealm(); + + $buffer =<< + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-$realm + */ +class $class extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return '$fqn'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return '$id'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + \$this->markTestIncomplete('This test has not been implemented yet.'); + + \$arguments = array(/* add arguments */); + \$expected = array(/* add arguments */); + + \$command = \$this->getCommand(); + \$command->setArguments(\$arguments); + + \$this->assertSame(\$expected, \$command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + \$this->markTestIncomplete('This test has not been implemented yet.'); + + \$raw = null; + \$expected = null; + + \$command = \$this->getCommand(); + + \$this->assertSame(\$expected, \$command->parseResponse(\$raw)); + } + +PHP; + + if ($instance instanceof IPrefixable) { + $buffer .=<<markTestIncomplete('This test has not been implemented yet.'); + + \$arguments = array(/* add arguments */); + \$expected = array(/* add arguments */); + + \$command = \$this->getCommandWithArgumentsArray(\$arguments); + \$command->prefixKeys('prefix:'); + + \$this->assertSame(\$expected, \$command->getArguments()); + } + +PHP; + } + + return "$buffer}\n"; + } +} + +// ------------------------------------------------------------------------- // + +require __DIR__.'/../autoload.php'; + +$generator = CommandTestCaseGenerator::fromCommandLine(); +$generator->save(); diff --git a/examples/ServerSideScripting.php b/examples/ServerSideScripting.php index 5087d3c0..e87cde5f 100644 --- a/examples/ServerSideScripting.php +++ b/examples/ServerSideScripting.php @@ -20,7 +20,7 @@ use Predis\Commands\ScriptedCommand; class IncrementExistingKey extends ScriptedCommand { - protected function keysCount() + public function getKeysCount() { return 1; } diff --git a/lib/Predis/Autoloader.php b/lib/Predis/Autoloader.php index 6dc6be74..3d59e09b 100644 --- a/lib/Predis/Autoloader.php +++ b/lib/Predis/Autoloader.php @@ -52,11 +52,6 @@ class Autoloader $relativeClassName = substr($className, strlen($this->prefix)); $classNameParts = explode('\\', $relativeClassName); - $path = $this->baseDir . - DIRECTORY_SEPARATOR . - implode(DIRECTORY_SEPARATOR, $classNameParts) . - '.php'; - - require_once $path; + require_once $this->baseDir.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $classNameParts).'.php'; } } diff --git a/lib/Predis/Client.php b/lib/Predis/Client.php index e98d109e..06e27751 100644 --- a/lib/Predis/Client.php +++ b/lib/Predis/Client.php @@ -191,11 +191,9 @@ class Client { if (isset($id)) { if (!Helpers::isCluster($this->connection)) { - throw new ClientException( - 'Retrieving connections by alias is supported only with clustered connections' - ); + $message = 'Retrieving connections by alias is supported only with clustered connections'; + throw new NotSupportedException($message); } - return $this->connection->getConnectionById($id); } diff --git a/lib/Predis/Commands/HashDelete.php b/lib/Predis/Commands/HashDelete.php index fbdf35a7..aa9724af 100644 --- a/lib/Predis/Commands/HashDelete.php +++ b/lib/Predis/Commands/HashDelete.php @@ -34,12 +34,4 @@ class HashDelete extends PrefixableCommand { return Helpers::filterVariadicValues($arguments); } - - /** - * {@inheritdoc} - */ - public function parseResponse($data) - { - return (bool) $data; - } } diff --git a/lib/Predis/Commands/KeyKeysV12x.php b/lib/Predis/Commands/KeyKeysV12x.php index 262cc3b5..1eccae93 100644 --- a/lib/Predis/Commands/KeyKeysV12x.php +++ b/lib/Predis/Commands/KeyKeysV12x.php @@ -14,6 +14,7 @@ namespace Predis\Commands; /** * @link http://redis.io/commands/keys * @author Daniele Alessandri + * @deprecated */ class KeyKeysV12x extends KeyKeys { diff --git a/lib/Predis/Commands/KeyRandom.php b/lib/Predis/Commands/KeyRandom.php index 0102a75b..51c34f61 100644 --- a/lib/Predis/Commands/KeyRandom.php +++ b/lib/Predis/Commands/KeyRandom.php @@ -15,7 +15,7 @@ namespace Predis\Commands; * @link http://redis.io/commands/randomkey * @author Daniele Alessandri */ -class KeyRandom extends PrefixableCommand +class KeyRandom extends Command { /** * {@inheritdoc} diff --git a/lib/Predis/Commands/ListPopFirstBlocking.php b/lib/Predis/Commands/ListPopFirstBlocking.php index bf5db0d3..5a348be9 100644 --- a/lib/Predis/Commands/ListPopFirstBlocking.php +++ b/lib/Predis/Commands/ListPopFirstBlocking.php @@ -25,6 +25,18 @@ class ListPopFirstBlocking extends Command implements IPrefixable return 'BLPOP'; } + /** + * {@inheritdoc} + */ + protected function filterArguments(Array $arguments) + { + if (count($arguments) === 2 && is_array($arguments[0])) { + list($arguments, $timeout) = $arguments; + array_push($arguments, $timeout); + } + return $arguments; + } + /** * {@inheritdoc} */ diff --git a/lib/Predis/Commands/PrefixHelpers.php b/lib/Predis/Commands/PrefixHelpers.php index e69d75e4..f344eed5 100644 --- a/lib/Predis/Commands/PrefixHelpers.php +++ b/lib/Predis/Commands/PrefixHelpers.php @@ -24,12 +24,12 @@ class PrefixHelpers * @param ICommand $command Command instance. * @param string $prefix Prefix string. */ - public function first(ICommand $command, $prefix) { - $arguments = $command->getArguments(); - - $arguments[0] = "$prefix{$arguments[0]}"; - - $command->setRawArguments($arguments); + public function first(ICommand $command, $prefix) + { + if ($arguments = $command->getArguments()) { + $arguments[0] = "$prefix{$arguments[0]}"; + $command->setRawArguments($arguments); + } } /** diff --git a/lib/Predis/Commands/PrefixableCommand.php b/lib/Predis/Commands/PrefixableCommand.php index 2d8347f6..21289d88 100644 --- a/lib/Predis/Commands/PrefixableCommand.php +++ b/lib/Predis/Commands/PrefixableCommand.php @@ -23,8 +23,9 @@ abstract class PrefixableCommand extends Command implements IPrefixable */ public function prefixKeys($prefix) { - $arguments = $this->getArguments(); - $arguments[0] = "$prefix{$arguments[0]}"; - $this->setRawArguments($arguments); + if ($arguments = $this->getArguments()) { + $arguments[0] = "$prefix{$arguments[0]}"; + $this->setRawArguments($arguments); + } } } diff --git a/lib/Predis/Commands/Processors/ProcessorChain.php b/lib/Predis/Commands/Processors/ProcessorChain.php index 6018000f..867cc6b3 100644 --- a/lib/Predis/Commands/Processors/ProcessorChain.php +++ b/lib/Predis/Commands/Processors/ProcessorChain.php @@ -20,7 +20,7 @@ use Predis\Commands\ICommand; */ class ProcessorChain implements ICommandProcessorChain, \ArrayAccess { - private $processors; + private $processors = array(); /** * @param array $processors List of instances of ICommandProcessor. @@ -127,5 +127,6 @@ class ProcessorChain implements ICommandProcessorChain, \ArrayAccess public function offsetUnset($index) { unset($this->processors[$index]); + $this->processors = array_values($this->processors); } } diff --git a/lib/Predis/Commands/PubSubUnsubscribe.php b/lib/Predis/Commands/PubSubUnsubscribe.php index 0f65ecb0..e17c553c 100644 --- a/lib/Predis/Commands/PubSubUnsubscribe.php +++ b/lib/Predis/Commands/PubSubUnsubscribe.php @@ -11,6 +11,8 @@ namespace Predis\Commands; +use Predis\Helpers; + /** * @link http://redis.io/commands/unsubscribe * @author Daniele Alessandri @@ -25,6 +27,14 @@ class PubSubUnsubscribe extends Command implements IPrefixable return 'UNSUBSCRIBE'; } + /** + * {@inheritdoc} + */ + protected function filterArguments(Array $arguments) + { + return Helpers::filterArrayArguments($arguments); + } + /** * {@inheritdoc} */ diff --git a/lib/Predis/Commands/ScriptedCommand.php b/lib/Predis/Commands/ScriptedCommand.php index 769457a1..c3319638 100644 --- a/lib/Predis/Commands/ScriptedCommand.php +++ b/lib/Predis/Commands/ScriptedCommand.php @@ -27,12 +27,16 @@ abstract class ScriptedCommand extends ServerEval */ public abstract function getScript(); - /* + /** * Gets the number of arguments that should be considered as keys. * + * @todo Should we make a scripted command act by default as a variadic + * command where the first argument is the key (KEYS[1]) and the + * rest is the list of values (ARGV)? + * * @return int */ - protected function keysCount() + public function getKeysCount() { // The default behaviour for the base class is to use all the arguments // passed to a scripted command to populate the KEYS table in Lua. @@ -40,18 +44,20 @@ abstract class ScriptedCommand extends ServerEval } /** - * {@inheritdoc} + * Returns the elements from the arguments that are identified as keys. + * + * @return array */ - protected function filterArguments(Array $arguments) + public function getKeys() { - return array_merge(array($this->getScript(), $this->keysCount()), $arguments); + return array_slice($this->getArguments(), 2, $this->getKeysCount()); } /** * {@inheritdoc} */ - protected function getKeys() + protected function filterArguments(Array $arguments) { - return array_slice($this->getArguments(), 2, $this->keysCount()); + return array_merge(array($this->getScript(), $this->getKeysCount()), $arguments); } } diff --git a/lib/Predis/Commands/ServerEval.php b/lib/Predis/Commands/ServerEval.php index 0095686d..4b3ed4f3 100644 --- a/lib/Predis/Commands/ServerEval.php +++ b/lib/Predis/Commands/ServerEval.php @@ -36,7 +36,7 @@ class ServerEval extends Command implements IPrefixable $arguments[$i] = "$prefix{$arguments[$i]}"; } - return $arguments; + $this->setRawArguments($arguments); } /** diff --git a/lib/Predis/Commands/ServerInfo.php b/lib/Predis/Commands/ServerInfo.php index 347c1aec..a4edc20f 100644 --- a/lib/Predis/Commands/ServerInfo.php +++ b/lib/Predis/Commands/ServerInfo.php @@ -39,7 +39,7 @@ class ServerInfo extends Command public function parseResponse($data) { $info = array(); - $infoLines = explode("\r\n", $data, -1); + $infoLines = preg_split('/\r?\n/', $data); foreach ($infoLines as $row) { @list($k, $v) = explode(':', $row); diff --git a/lib/Predis/Commands/ServerInfoV26x.php b/lib/Predis/Commands/ServerInfoV26x.php index cc58c0ee..d6fb619a 100644 --- a/lib/Predis/Commands/ServerInfoV26x.php +++ b/lib/Predis/Commands/ServerInfoV26x.php @@ -24,7 +24,11 @@ class ServerInfoV26x extends ServerInfo { $info = array(); $current = null; - $infoLines = explode("\r\n", $data, -1); + $infoLines = preg_split('/\r?\n/', $data); + + if (isset($infoLines[0]) && $infoLines[0][0] !== '#') { + return parent::parseResponse($data); + } foreach ($infoLines as $row) { if ($row === '') { diff --git a/lib/Predis/Commands/SetAdd.php b/lib/Predis/Commands/SetAdd.php index 112cbb96..6738e04a 100644 --- a/lib/Predis/Commands/SetAdd.php +++ b/lib/Predis/Commands/SetAdd.php @@ -34,12 +34,4 @@ class SetAdd extends PrefixableCommand { return Helpers::filterVariadicValues($arguments); } - - /** - * {@inheritdoc} - */ - public function parseResponse($data) - { - return (bool) $data; - } } diff --git a/lib/Predis/Commands/SetRemove.php b/lib/Predis/Commands/SetRemove.php index 78aa3020..2e9ba3a9 100644 --- a/lib/Predis/Commands/SetRemove.php +++ b/lib/Predis/Commands/SetRemove.php @@ -34,12 +34,4 @@ class SetRemove extends PrefixableCommand { return Helpers::filterVariadicValues($arguments); } - - /** - * {@inheritdoc} - */ - public function parseResponse($data) - { - return (bool) $data; - } } diff --git a/lib/Predis/Commands/ZSetAdd.php b/lib/Predis/Commands/ZSetAdd.php index 2df5b31c..e369bc58 100644 --- a/lib/Predis/Commands/ZSetAdd.php +++ b/lib/Predis/Commands/ZSetAdd.php @@ -32,14 +32,16 @@ class ZSetAdd extends PrefixableCommand */ protected function filterArguments(Array $arguments) { - return Helpers::filterVariadicValues($arguments); - } + if (count($arguments) === 2 && is_array($arguments[1])) { + $flattened = array($arguments[0]); + foreach($arguments[1] as $member => $score) { + $flattened[] = $score; + $flattened[] = $member; + } - /** - * {@inheritdoc} - */ - public function parseResponse($data) - { - return (bool) $data; + return $flattened; + } + + return $arguments; } } diff --git a/lib/Predis/Commands/ZSetRemove.php b/lib/Predis/Commands/ZSetRemove.php index 6d7ee626..2ebb71bd 100644 --- a/lib/Predis/Commands/ZSetRemove.php +++ b/lib/Predis/Commands/ZSetRemove.php @@ -34,12 +34,4 @@ class ZSetRemove extends PrefixableCommand { return Helpers::filterVariadicValues($arguments); } - - /** - * {@inheritdoc} - */ - public function parseResponse($data) - { - return (bool) $data; - } } diff --git a/lib/Predis/Iterators/MultiBulkResponseSimple.php b/lib/Predis/Iterators/MultiBulkResponseSimple.php index 943c8e44..4f37307c 100644 --- a/lib/Predis/Iterators/MultiBulkResponseSimple.php +++ b/lib/Predis/Iterators/MultiBulkResponseSimple.php @@ -42,7 +42,7 @@ class MultiBulkResponseSimple extends MultiBulkResponse */ public function __destruct() { - $this->sync(); + $this->sync(true); } /** diff --git a/lib/Predis/Iterators/MultiBulkResponseTuple.php b/lib/Predis/Iterators/MultiBulkResponseTuple.php index a84fdba1..163669e9 100644 --- a/lib/Predis/Iterators/MultiBulkResponseTuple.php +++ b/lib/Predis/Iterators/MultiBulkResponseTuple.php @@ -17,7 +17,7 @@ namespace Predis\Iterators; * * @author Daniele Alessandri */ -class MultiBulkResponseTuple extends MultiBulkResponse +class MultiBulkResponseTuple extends MultiBulkResponse implements \OuterIterator { private $iterator; @@ -33,12 +33,20 @@ class MultiBulkResponseTuple extends MultiBulkResponse $this->replySize = $virtualSize; } + /** + * {@inheritdoc} + */ + public function getInnerIterator() + { + return $this->iterator; + } + /** * {@inheritdoc} */ public function __destruct() { - $this->iterator->sync(); + $this->iterator->sync(true); } /** diff --git a/lib/Predis/MonitorContext.php b/lib/Predis/MonitorContext.php index eb3fdc91..82af112e 100644 --- a/lib/Predis/MonitorContext.php +++ b/lib/Predis/MonitorContext.php @@ -49,15 +49,11 @@ class MonitorContext implements \Iterator private function checkCapabilities(Client $client) { if (Helpers::isCluster($client->getConnection())) { - throw new ClientException( - 'Cannot initialize a monitor context over a cluster of connections' - ); + throw new NotSupportedException('Cannot initialize a monitor context over a cluster of connections'); } if ($client->getProfile()->supportsCommand('monitor') === false) { - throw new ClientException( - 'The current profile does not support the MONITOR command' - ); + throw new NotSupportedException('The current profile does not support the MONITOR command'); } } diff --git a/lib/Predis/Network/ConnectionBase.php b/lib/Predis/Network/ConnectionBase.php index a175793d..70d40e96 100644 --- a/lib/Predis/Network/ConnectionBase.php +++ b/lib/Predis/Network/ConnectionBase.php @@ -11,7 +11,6 @@ namespace Predis\Network; -use \InvalidArgumentException; use Predis\Helpers; use Predis\IReplyObject; use Predis\IConnectionParameters; @@ -61,14 +60,14 @@ abstract class ConnectionBase implements IConnectionSingle switch ($parameters->scheme) { case 'unix': if (!isset($parameters->path)) { - throw new InvalidArgumentException('Missing UNIX domain socket path'); + throw new \InvalidArgumentException('Missing UNIX domain socket path'); } case 'tcp': return $parameters; default: - throw new InvalidArgumentException("Invalid scheme: {$parameters->scheme}"); + throw new \InvalidArgumentException("Invalid scheme: {$parameters->scheme}"); } } @@ -182,7 +181,7 @@ abstract class ConnectionBase implements IConnectionSingle $message .= " [$parameters]"; } - throw new InvalidArgumentException($message); + throw new \InvalidArgumentException($message); } /** diff --git a/lib/Predis/Network/PhpiredisConnection.php b/lib/Predis/Network/PhpiredisConnection.php index 75982271..990386d5 100644 --- a/lib/Predis/Network/PhpiredisConnection.php +++ b/lib/Predis/Network/PhpiredisConnection.php @@ -11,12 +11,13 @@ namespace Predis\Network; +use Predis\Commands\ICommand; +use Predis\IConnectionParameters; use Predis\ResponseError; use Predis\ResponseQueued; use Predis\ClientException; use Predis\ServerException; -use Predis\IConnectionParameters; -use Predis\Commands\ICommand; +use Predis\NotSupportedException; /** * This class provides the implementation of a Predis connection that uses the @@ -47,7 +48,7 @@ class PhpiredisConnection extends ConnectionBase public function __construct(IConnectionParameters $parameters) { if (!function_exists('socket_create')) { - throw new ClientException( + throw new NotSupportedException( 'The socket extension must be loaded in order to be able to ' . 'use this connection class' ); @@ -90,7 +91,7 @@ class PhpiredisConnection extends ConnectionBase private function initializeReader($throw_errors = true) { if (!function_exists('phpiredis_reader_create')) { - throw new ClientException( + throw new NotSupportedException( 'The phpiredis extension must be loaded in order to be able to ' . 'use this connection class' ); diff --git a/lib/Predis/Network/PredisCluster.php b/lib/Predis/Network/PredisCluster.php index 14e250fd..b8c517a4 100644 --- a/lib/Predis/Network/PredisCluster.php +++ b/lib/Predis/Network/PredisCluster.php @@ -11,10 +11,11 @@ namespace Predis\Network; -use Predis\Helpers; -use Predis\ClientException; use Predis\Commands\ICommand; use Predis\Distribution\IDistributionStrategy; +use Predis\Helpers; +use Predis\ClientException; +use Predis\NotSupportedException; use Predis\Distribution\HashRing; /** @@ -22,6 +23,7 @@ use Predis\Distribution\HashRing; * implementing client-side sharding based on pluggable distribution strategies. * * @author Daniele Alessandri + * @todo Add the ability to remove connections from pool. */ class PredisCluster implements IConnectionCluster, \IteratorAggregate { @@ -85,7 +87,8 @@ class PredisCluster implements IConnectionCluster, \IteratorAggregate $this->pool[] = $connection; } - $this->distributor->add($connection, $parameters->weight); + $weight = isset($parameters->weight) ? $parameters->weight : null; + $this->distributor->add($connection, $weight); } /** @@ -99,9 +102,8 @@ class PredisCluster implements IConnectionCluster, \IteratorAggregate return $this->distributor->get($cmdHash); } - throw new ClientException( - sprintf("Cannot send '%s' commands to a cluster of connections", $command->getId()) - ); + $message = sprintf("Cannot send '%s' commands to a cluster of connections", $command->getId()); + throw new NotSupportedException($message); } /** diff --git a/lib/Predis/Network/StreamConnection.php b/lib/Predis/Network/StreamConnection.php index 8e803688..7c207691 100644 --- a/lib/Predis/Network/StreamConnection.php +++ b/lib/Predis/Network/StreamConnection.php @@ -14,6 +14,7 @@ namespace Predis\Network; use Predis\ResponseError; use Predis\ResponseQueued; use Predis\ServerException; +use Predis\NotSupportedException; use Predis\IConnectionParameters; use Predis\Commands\ICommand; use Predis\Iterators\MultiBulkResponseSimple; diff --git a/lib/Predis/Network/WebdisConnection.php b/lib/Predis/Network/WebdisConnection.php index ec071850..bdac4c72 100644 --- a/lib/Predis/Network/WebdisConnection.php +++ b/lib/Predis/Network/WebdisConnection.php @@ -11,12 +11,13 @@ namespace Predis\Network; +use Predis\Commands\ICommand; use Predis\IConnectionParameters; use Predis\ResponseError; -use Predis\ClientException; use Predis\ServerException; -use Predis\Commands\ICommand; +use Predis\NotSupportedException; use Predis\Protocol\ProtocolException; +use Predis\Network\ConnectionException; const ERR_MSG_EXTENSION = 'The %s extension must be loaded in order to be able to use this connection class'; @@ -74,7 +75,7 @@ class WebdisConnection implements IConnectionSingle private function throwNotSupportedException($function) { $class = __CLASS__; - throw new \RuntimeException("The method $class::$function() is not supported"); + throw new NotSupportedException("The method $class::$function() is not supported"); } /** @@ -83,10 +84,10 @@ class WebdisConnection implements IConnectionSingle private function checkExtensions() { if (!function_exists('curl_init')) { - throw new ClientException(sprintf(ERR_MSG_EXTENSION, 'curl')); + throw new NotSupportedException(sprintf(ERR_MSG_EXTENSION, 'curl')); } if (!function_exists('phpiredis_reader_create')) { - throw new ClientException(sprintf(ERR_MSG_EXTENSION, 'phpiredis')); + throw new NotSupportedException(sprintf(ERR_MSG_EXTENSION, 'phpiredis')); } } @@ -138,7 +139,7 @@ class WebdisConnection implements IConnectionSingle * * @return \Closure */ - private function getStatusHandler() + protected function getStatusHandler() { return function($payload) { return $payload === 'OK' ? true : $payload; @@ -151,7 +152,7 @@ class WebdisConnection implements IConnectionSingle * @param Boolean $throwErrors Specify if Redis errors throw exceptions. * @return \Closure */ - private function getErrorHandler($throwErrors) + protected function getErrorHandler($throwErrors) { if ($throwErrors) { return function($errorMessage) { @@ -218,7 +219,8 @@ class WebdisConnection implements IConnectionSingle case 'WATCH': case 'UNWATCH': case 'DISCARD': - throw new \InvalidArgumentException("Disabled command: {$command->getId()}"); + case 'MONITOR': + throw new NotSupportedException("Disabled command: {$command->getId()}"); default: return $commandId; diff --git a/lib/Predis/NotSupportedException.php b/lib/Predis/NotSupportedException.php new file mode 100644 index 00000000..631b820a --- /dev/null +++ b/lib/Predis/NotSupportedException.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis; + +/** + * Exception class generated when trying to use features not + * supported by certain classes or abstractions. + * + * @author Daniele Alessandri + */ +class NotSupportedException extends PredisException +{ +} diff --git a/lib/Predis/Options/ClientCluster.php b/lib/Predis/Options/ClientCluster.php index 6f8ee530..920a04e0 100644 --- a/lib/Predis/Options/ClientCluster.php +++ b/lib/Predis/Options/ClientCluster.php @@ -30,9 +30,7 @@ class ClientCluster extends Option protected function checkInstance($cluster) { if (!$cluster instanceof IConnectionCluster) { - throw new \InvalidArgumentException( - 'Instance of Predis\Network\IConnectionCluster expected' - ); + throw new \InvalidArgumentException('Instance of Predis\Network\IConnectionCluster expected'); } return $cluster; @@ -44,7 +42,7 @@ class ClientCluster extends Option public function validate(IClientOptions $options, $value) { if (is_callable($value)) { - return $this->checkInstance(call_user_func($value)); + return $this->checkInstance(call_user_func($value, $options)); } $initializer = $this->getInitializer($options, $value); @@ -54,7 +52,7 @@ class ClientCluster extends Option /** * Returns an initializer for the specified FQN or type. * - * @param string $fqnOrType Type of cluster of FQN of a class implementing IConnectionCluster. + * @param string $fqnOrType Type of cluster or FQN of a class implementing IConnectionCluster. * @param IClientOptions $options Instance of the client options. * @return \Closure */ @@ -65,6 +63,10 @@ class ClientCluster extends Option return function() { return new PredisCluster(); }; default: + // TODO: we should not even allow non-string values here. + if (is_string($fqnOrType) && !class_exists($fqnOrType)) { + throw new \InvalidArgumentException('Class $fqnOrType does not exist'); + } return function() use($fqnOrType) { return new $fqnOrType(); }; diff --git a/lib/Predis/Options/ClientConnectionFactory.php b/lib/Predis/Options/ClientConnectionFactory.php index 934bb56b..21f396da 100644 --- a/lib/Predis/Options/ClientConnectionFactory.php +++ b/lib/Predis/Options/ClientConnectionFactory.php @@ -36,6 +36,14 @@ class ClientConnectionFactory extends Option } return $factory; } + if (is_string($value) && class_exists($value)) { + if (!($factory = new $value()) && !$factory instanceof IConnectionFactory) { + throw new \InvalidArgumentException("Class $value must be an instance of Predis\IConnectionFactory"); + } + return $factory; + } + + throw new \InvalidArgumentException('Invalid value for the connections option'); } /** diff --git a/lib/Predis/Options/CustomOption.php b/lib/Predis/Options/CustomOption.php index 5a8e2fe9..7775d401 100644 --- a/lib/Predis/Options/CustomOption.php +++ b/lib/Predis/Options/CustomOption.php @@ -24,7 +24,7 @@ class CustomOption implements IOption /** * @param array $options List of options */ - public function __construct(Array $options) + public function __construct(Array $options = array()) { $this->validate = $this->filterCallable($options, 'validate'); $this->default = $this->filterCallable($options, 'default'); diff --git a/lib/Predis/Pipeline/PipelineContext.php b/lib/Predis/Pipeline/PipelineContext.php index 6151ce64..bc5c91b4 100644 --- a/lib/Predis/Pipeline/PipelineContext.php +++ b/lib/Predis/Pipeline/PipelineContext.php @@ -38,7 +38,7 @@ class PipelineContext public function __construct(Client $client, Array $options = null) { $this->client = $client; - $this->executor = $this->getExecutor($client, $options ?: array()); + $this->executor = $this->createExecutor($client, $options ?: array()); } /** @@ -49,7 +49,7 @@ class PipelineContext * @param array Options for the context initialization. * @return IPipelineExecutor */ - protected function getExecutor(Client $client, Array $options) + protected function createExecutor(Client $client, Array $options) { if (!$options) { return new StandardExecutor(); @@ -160,7 +160,7 @@ class PipelineContext try { if ($callable !== null) { - $callable($this); + call_user_func($callable, $this); } $this->flushPipeline(); } @@ -186,4 +186,14 @@ class PipelineContext { return $this->client; } + + /** + * Returns the underlying pipeline executor used by the pipeline object. + * + * @return IPipelineExecutor + */ + public function getExecutor() + { + return $this->executor; + } } diff --git a/lib/Predis/Profiles/ServerProfile.php b/lib/Predis/Profiles/ServerProfile.php index a4f43564..eb73abd5 100644 --- a/lib/Predis/Profiles/ServerProfile.php +++ b/lib/Predis/Profiles/ServerProfile.php @@ -96,9 +96,7 @@ abstract class ServerProfile implements IServerProfile, IProcessingSupport $profileReflection = new \ReflectionClass($profileClass); if (!$profileReflection->isSubclassOf('Predis\Profiles\IServerProfile')) { - throw new ClientException( - "Cannot register '$profileClass' as it is not a valid profile class" - ); + throw new \InvalidArgumentException("Cannot register '$profileClass' as it is not a valid profile class"); } self::$profiles[$alias] = $profileClass; @@ -146,6 +144,20 @@ abstract class ServerProfile implements IServerProfile, IProcessingSupport return isset($this->commands[strtolower($command)]); } + /** + * Returns the FQN of the class that represent the specified command ID + * registered in the current server profile. + * + * @param string $command Command ID. + * @return string + */ + public function getCommandClass($command) + { + if (isset($this->commands[$command = strtolower($command)])) { + return $this->commands[$command]; + } + } + /** * {@inheritdoc} */ @@ -189,7 +201,7 @@ abstract class ServerProfile implements IServerProfile, IProcessingSupport { $commandReflection = new \ReflectionClass($command); if (!$commandReflection->isSubclassOf('Predis\Commands\ICommand')) { - throw new ClientException("Cannot register '$command' as it is not a valid Redis command"); + throw new \InvalidArgumentException("Cannot register '$command' as it is not a valid Redis command"); } $this->commands[strtolower($alias)] = $command; } @@ -197,12 +209,8 @@ abstract class ServerProfile implements IServerProfile, IProcessingSupport /** * {@inheritdoc} */ - public function setProcessor(ICommandProcessor $processor) + public function setProcessor(ICommandProcessor $processor = null) { - if (!isset($processor)) { - unset($this->processor); - return; - } $this->processor = $processor; } diff --git a/lib/Predis/Profiles/ServerVersion12.php b/lib/Predis/Profiles/ServerVersion12.php index d89caebb..3aa94f25 100644 --- a/lib/Predis/Profiles/ServerVersion12.php +++ b/lib/Predis/Profiles/ServerVersion12.php @@ -35,91 +35,91 @@ class ServerVersion12 extends ServerProfile /* ---------------- Redis 1.2 ---------------- */ /* commands operating on the key space */ - 'exists' => '\Predis\Commands\KeyExists', - 'del' => '\Predis\Commands\KeyDelete', - 'type' => '\Predis\Commands\KeyType', - 'keys' => '\Predis\Commands\KeyKeysV12x', - 'randomkey' => '\Predis\Commands\KeyRandom', - 'rename' => '\Predis\Commands\KeyRename', - 'renamenx' => '\Predis\Commands\KeyRenamePreserve', - 'expire' => '\Predis\Commands\KeyExpire', - 'expireat' => '\Predis\Commands\KeyExpireAt', - 'ttl' => '\Predis\Commands\KeyTimeToLive', - 'move' => '\Predis\Commands\KeyMove', - 'sort' => '\Predis\Commands\KeySort', + 'exists' => 'Predis\Commands\KeyExists', + 'del' => 'Predis\Commands\KeyDelete', + 'type' => 'Predis\Commands\KeyType', + 'keys' => 'Predis\Commands\KeyKeysV12x', + 'randomkey' => 'Predis\Commands\KeyRandom', + 'rename' => 'Predis\Commands\KeyRename', + 'renamenx' => 'Predis\Commands\KeyRenamePreserve', + 'expire' => 'Predis\Commands\KeyExpire', + 'expireat' => 'Predis\Commands\KeyExpireAt', + 'ttl' => 'Predis\Commands\KeyTimeToLive', + 'move' => 'Predis\Commands\KeyMove', + 'sort' => 'Predis\Commands\KeySort', /* commands operating on string values */ - 'set' => '\Predis\Commands\StringSet', - 'setnx' => '\Predis\Commands\StringSetPreserve', - 'mset' => '\Predis\Commands\StringSetMultiple', - 'msetnx' => '\Predis\Commands\StringSetMultiplePreserve', - 'get' => '\Predis\Commands\StringGet', - 'mget' => '\Predis\Commands\StringGetMultiple', - 'getset' => '\Predis\Commands\StringGetSet', - 'incr' => '\Predis\Commands\StringIncrement', - 'incrby' => '\Predis\Commands\StringIncrementBy', - 'decr' => '\Predis\Commands\StringDecrement', - 'decrby' => '\Predis\Commands\StringDecrementBy', + 'set' => 'Predis\Commands\StringSet', + 'setnx' => 'Predis\Commands\StringSetPreserve', + 'mset' => 'Predis\Commands\StringSetMultiple', + 'msetnx' => 'Predis\Commands\StringSetMultiplePreserve', + 'get' => 'Predis\Commands\StringGet', + 'mget' => 'Predis\Commands\StringGetMultiple', + 'getset' => 'Predis\Commands\StringGetSet', + 'incr' => 'Predis\Commands\StringIncrement', + 'incrby' => 'Predis\Commands\StringIncrementBy', + 'decr' => 'Predis\Commands\StringDecrement', + 'decrby' => 'Predis\Commands\StringDecrementBy', /* commands operating on lists */ - 'rpush' => '\Predis\Commands\ListPushTail', - 'lpush' => '\Predis\Commands\ListPushHead', - 'llen' => '\Predis\Commands\ListLength', - 'lrange' => '\Predis\Commands\ListRange', - 'ltrim' => '\Predis\Commands\ListTrim', - 'lindex' => '\Predis\Commands\ListIndex', - 'lset' => '\Predis\Commands\ListSet', - 'lrem' => '\Predis\Commands\ListRemove', - 'lpop' => '\Predis\Commands\ListPopFirst', - 'rpop' => '\Predis\Commands\ListPopLast', - 'rpoplpush' => '\Predis\Commands\ListPopLastPushHead', + 'rpush' => 'Predis\Commands\ListPushTail', + 'lpush' => 'Predis\Commands\ListPushHead', + 'llen' => 'Predis\Commands\ListLength', + 'lrange' => 'Predis\Commands\ListRange', + 'ltrim' => 'Predis\Commands\ListTrim', + 'lindex' => 'Predis\Commands\ListIndex', + 'lset' => 'Predis\Commands\ListSet', + 'lrem' => 'Predis\Commands\ListRemove', + 'lpop' => 'Predis\Commands\ListPopFirst', + 'rpop' => 'Predis\Commands\ListPopLast', + 'rpoplpush' => 'Predis\Commands\ListPopLastPushHead', /* commands operating on sets */ - 'sadd' => '\Predis\Commands\SetAdd', - 'srem' => '\Predis\Commands\SetRemove', - 'spop' => '\Predis\Commands\SetPop', - 'smove' => '\Predis\Commands\SetMove', - 'scard' => '\Predis\Commands\SetCardinality', - 'sismember' => '\Predis\Commands\SetIsMember', - 'sinter' => '\Predis\Commands\SetIntersection', - 'sinterstore' => '\Predis\Commands\SetIntersectionStore', - 'sunion' => '\Predis\Commands\SetUnion', - 'sunionstore' => '\Predis\Commands\SetUnionStore', - 'sdiff' => '\Predis\Commands\SetDifference', - 'sdiffstore' => '\Predis\Commands\SetDifferenceStore', - 'smembers' => '\Predis\Commands\SetMembers', - 'srandmember' => '\Predis\Commands\SetRandomMember', + 'sadd' => 'Predis\Commands\SetAdd', + 'srem' => 'Predis\Commands\SetRemove', + 'spop' => 'Predis\Commands\SetPop', + 'smove' => 'Predis\Commands\SetMove', + 'scard' => 'Predis\Commands\SetCardinality', + 'sismember' => 'Predis\Commands\SetIsMember', + 'sinter' => 'Predis\Commands\SetIntersection', + 'sinterstore' => 'Predis\Commands\SetIntersectionStore', + 'sunion' => 'Predis\Commands\SetUnion', + 'sunionstore' => 'Predis\Commands\SetUnionStore', + 'sdiff' => 'Predis\Commands\SetDifference', + 'sdiffstore' => 'Predis\Commands\SetDifferenceStore', + 'smembers' => 'Predis\Commands\SetMembers', + 'srandmember' => 'Predis\Commands\SetRandomMember', /* commands operating on sorted sets */ - 'zadd' => '\Predis\Commands\ZSetAdd', - 'zincrby' => '\Predis\Commands\ZSetIncrementBy', - 'zrem' => '\Predis\Commands\ZSetRemove', - 'zrange' => '\Predis\Commands\ZSetRange', - 'zrevrange' => '\Predis\Commands\ZSetReverseRange', - 'zrangebyscore' => '\Predis\Commands\ZSetRangeByScore', - 'zcard' => '\Predis\Commands\ZSetCardinality', - 'zscore' => '\Predis\Commands\ZSetScore', - 'zremrangebyscore' => '\Predis\Commands\ZSetRemoveRangeByScore', + 'zadd' => 'Predis\Commands\ZSetAdd', + 'zincrby' => 'Predis\Commands\ZSetIncrementBy', + 'zrem' => 'Predis\Commands\ZSetRemove', + 'zrange' => 'Predis\Commands\ZSetRange', + 'zrevrange' => 'Predis\Commands\ZSetReverseRange', + 'zrangebyscore' => 'Predis\Commands\ZSetRangeByScore', + 'zcard' => 'Predis\Commands\ZSetCardinality', + 'zscore' => 'Predis\Commands\ZSetScore', + 'zremrangebyscore' => 'Predis\Commands\ZSetRemoveRangeByScore', /* connection related commands */ - 'ping' => '\Predis\Commands\ConnectionPing', - 'auth' => '\Predis\Commands\ConnectionAuth', - 'select' => '\Predis\Commands\ConnectionSelect', - 'echo' => '\Predis\Commands\ConnectionEcho', - 'quit' => '\Predis\Commands\ConnectionQuit', + 'ping' => 'Predis\Commands\ConnectionPing', + 'auth' => 'Predis\Commands\ConnectionAuth', + 'select' => 'Predis\Commands\ConnectionSelect', + 'echo' => 'Predis\Commands\ConnectionEcho', + 'quit' => 'Predis\Commands\ConnectionQuit', /* remote server control commands */ - 'info' => '\Predis\Commands\ServerInfo', - 'slaveof' => '\Predis\Commands\ServerSlaveOf', - 'monitor' => '\Predis\Commands\ServerMonitor', - 'dbsize' => '\Predis\Commands\ServerDatabaseSize', - 'flushdb' => '\Predis\Commands\ServerFlushDatabase', - 'flushall' => '\Predis\Commands\ServerFlushAll', - 'save' => '\Predis\Commands\ServerSave', - 'bgsave' => '\Predis\Commands\ServerBackgroundSave', - 'lastsave' => '\Predis\Commands\ServerLastSave', - 'shutdown' => '\Predis\Commands\ServerShutdown', - 'bgrewriteaof' => '\Predis\Commands\ServerBackgroundRewriteAOF', + 'info' => 'Predis\Commands\ServerInfo', + 'slaveof' => 'Predis\Commands\ServerSlaveOf', + 'monitor' => 'Predis\Commands\ServerMonitor', + 'dbsize' => 'Predis\Commands\ServerDatabaseSize', + 'flushdb' => 'Predis\Commands\ServerFlushDatabase', + 'flushall' => 'Predis\Commands\ServerFlushAll', + 'save' => 'Predis\Commands\ServerSave', + 'bgsave' => 'Predis\Commands\ServerBackgroundSave', + 'lastsave' => 'Predis\Commands\ServerLastSave', + 'shutdown' => 'Predis\Commands\ServerShutdown', + 'bgrewriteaof' => 'Predis\Commands\ServerBackgroundRewriteAOF', ); } } diff --git a/lib/Predis/Profiles/ServerVersion20.php b/lib/Predis/Profiles/ServerVersion20.php index 8c64a597..002254a1 100644 --- a/lib/Predis/Profiles/ServerVersion20.php +++ b/lib/Predis/Profiles/ServerVersion20.php @@ -35,140 +35,140 @@ class ServerVersion20 extends ServerProfile /* ---------------- Redis 1.2 ---------------- */ /* commands operating on the key space */ - 'exists' => '\Predis\Commands\KeyExists', - 'del' => '\Predis\Commands\KeyDelete', - 'type' => '\Predis\Commands\KeyType', - 'keys' => '\Predis\Commands\KeyKeys', - 'randomkey' => '\Predis\Commands\KeyRandom', - 'rename' => '\Predis\Commands\KeyRename', - 'renamenx' => '\Predis\Commands\KeyRenamePreserve', - 'expire' => '\Predis\Commands\KeyExpire', - 'expireat' => '\Predis\Commands\KeyExpireAt', - 'ttl' => '\Predis\Commands\KeyTimeToLive', - 'move' => '\Predis\Commands\KeyMove', - 'sort' => '\Predis\Commands\KeySort', + 'exists' => 'Predis\Commands\KeyExists', + 'del' => 'Predis\Commands\KeyDelete', + 'type' => 'Predis\Commands\KeyType', + 'keys' => 'Predis\Commands\KeyKeys', + 'randomkey' => 'Predis\Commands\KeyRandom', + 'rename' => 'Predis\Commands\KeyRename', + 'renamenx' => 'Predis\Commands\KeyRenamePreserve', + 'expire' => 'Predis\Commands\KeyExpire', + 'expireat' => 'Predis\Commands\KeyExpireAt', + 'ttl' => 'Predis\Commands\KeyTimeToLive', + 'move' => 'Predis\Commands\KeyMove', + 'sort' => 'Predis\Commands\KeySort', /* commands operating on string values */ - 'set' => '\Predis\Commands\StringSet', - 'setnx' => '\Predis\Commands\StringSetPreserve', - 'mset' => '\Predis\Commands\StringSetMultiple', - 'msetnx' => '\Predis\Commands\StringSetMultiplePreserve', - 'get' => '\Predis\Commands\StringGet', - 'mget' => '\Predis\Commands\StringGetMultiple', - 'getset' => '\Predis\Commands\StringGetSet', - 'incr' => '\Predis\Commands\StringIncrement', - 'incrby' => '\Predis\Commands\StringIncrementBy', - 'decr' => '\Predis\Commands\StringDecrement', - 'decrby' => '\Predis\Commands\StringDecrementBy', + 'set' => 'Predis\Commands\StringSet', + 'setnx' => 'Predis\Commands\StringSetPreserve', + 'mset' => 'Predis\Commands\StringSetMultiple', + 'msetnx' => 'Predis\Commands\StringSetMultiplePreserve', + 'get' => 'Predis\Commands\StringGet', + 'mget' => 'Predis\Commands\StringGetMultiple', + 'getset' => 'Predis\Commands\StringGetSet', + 'incr' => 'Predis\Commands\StringIncrement', + 'incrby' => 'Predis\Commands\StringIncrementBy', + 'decr' => 'Predis\Commands\StringDecrement', + 'decrby' => 'Predis\Commands\StringDecrementBy', /* commands operating on lists */ - 'rpush' => '\Predis\Commands\ListPushTail', - 'lpush' => '\Predis\Commands\ListPushHead', - 'llen' => '\Predis\Commands\ListLength', - 'lrange' => '\Predis\Commands\ListRange', - 'ltrim' => '\Predis\Commands\ListTrim', - 'lindex' => '\Predis\Commands\ListIndex', - 'lset' => '\Predis\Commands\ListSet', - 'lrem' => '\Predis\Commands\ListRemove', - 'lpop' => '\Predis\Commands\ListPopFirst', - 'rpop' => '\Predis\Commands\ListPopLast', - 'rpoplpush' => '\Predis\Commands\ListPopLastPushHead', + 'rpush' => 'Predis\Commands\ListPushTail', + 'lpush' => 'Predis\Commands\ListPushHead', + 'llen' => 'Predis\Commands\ListLength', + 'lrange' => 'Predis\Commands\ListRange', + 'ltrim' => 'Predis\Commands\ListTrim', + 'lindex' => 'Predis\Commands\ListIndex', + 'lset' => 'Predis\Commands\ListSet', + 'lrem' => 'Predis\Commands\ListRemove', + 'lpop' => 'Predis\Commands\ListPopFirst', + 'rpop' => 'Predis\Commands\ListPopLast', + 'rpoplpush' => 'Predis\Commands\ListPopLastPushHead', /* commands operating on sets */ - 'sadd' => '\Predis\Commands\SetAdd', - 'srem' => '\Predis\Commands\SetRemove', - 'spop' => '\Predis\Commands\SetPop', - 'smove' => '\Predis\Commands\SetMove', - 'scard' => '\Predis\Commands\SetCardinality', - 'sismember' => '\Predis\Commands\SetIsMember', - 'sinter' => '\Predis\Commands\SetIntersection', - 'sinterstore' => '\Predis\Commands\SetIntersectionStore', - 'sunion' => '\Predis\Commands\SetUnion', - 'sunionstore' => '\Predis\Commands\SetUnionStore', - 'sdiff' => '\Predis\Commands\SetDifference', - 'sdiffstore' => '\Predis\Commands\SetDifferenceStore', - 'smembers' => '\Predis\Commands\SetMembers', - 'srandmember' => '\Predis\Commands\SetRandomMember', + 'sadd' => 'Predis\Commands\SetAdd', + 'srem' => 'Predis\Commands\SetRemove', + 'spop' => 'Predis\Commands\SetPop', + 'smove' => 'Predis\Commands\SetMove', + 'scard' => 'Predis\Commands\SetCardinality', + 'sismember' => 'Predis\Commands\SetIsMember', + 'sinter' => 'Predis\Commands\SetIntersection', + 'sinterstore' => 'Predis\Commands\SetIntersectionStore', + 'sunion' => 'Predis\Commands\SetUnion', + 'sunionstore' => 'Predis\Commands\SetUnionStore', + 'sdiff' => 'Predis\Commands\SetDifference', + 'sdiffstore' => 'Predis\Commands\SetDifferenceStore', + 'smembers' => 'Predis\Commands\SetMembers', + 'srandmember' => 'Predis\Commands\SetRandomMember', /* commands operating on sorted sets */ - 'zadd' => '\Predis\Commands\ZSetAdd', - 'zincrby' => '\Predis\Commands\ZSetIncrementBy', - 'zrem' => '\Predis\Commands\ZSetRemove', - 'zrange' => '\Predis\Commands\ZSetRange', - 'zrevrange' => '\Predis\Commands\ZSetReverseRange', - 'zrangebyscore' => '\Predis\Commands\ZSetRangeByScore', - 'zcard' => '\Predis\Commands\ZSetCardinality', - 'zscore' => '\Predis\Commands\ZSetScore', - 'zremrangebyscore' => '\Predis\Commands\ZSetRemoveRangeByScore', + 'zadd' => 'Predis\Commands\ZSetAdd', + 'zincrby' => 'Predis\Commands\ZSetIncrementBy', + 'zrem' => 'Predis\Commands\ZSetRemove', + 'zrange' => 'Predis\Commands\ZSetRange', + 'zrevrange' => 'Predis\Commands\ZSetReverseRange', + 'zrangebyscore' => 'Predis\Commands\ZSetRangeByScore', + 'zcard' => 'Predis\Commands\ZSetCardinality', + 'zscore' => 'Predis\Commands\ZSetScore', + 'zremrangebyscore' => 'Predis\Commands\ZSetRemoveRangeByScore', /* connection related commands */ - 'ping' => '\Predis\Commands\ConnectionPing', - 'auth' => '\Predis\Commands\ConnectionAuth', - 'select' => '\Predis\Commands\ConnectionSelect', - 'echo' => '\Predis\Commands\ConnectionEcho', - 'quit' => '\Predis\Commands\ConnectionQuit', + 'ping' => 'Predis\Commands\ConnectionPing', + 'auth' => 'Predis\Commands\ConnectionAuth', + 'select' => 'Predis\Commands\ConnectionSelect', + 'echo' => 'Predis\Commands\ConnectionEcho', + 'quit' => 'Predis\Commands\ConnectionQuit', /* remote server control commands */ - 'info' => '\Predis\Commands\ServerInfo', - 'slaveof' => '\Predis\Commands\ServerSlaveOf', - 'monitor' => '\Predis\Commands\ServerMonitor', - 'dbsize' => '\Predis\Commands\ServerDatabaseSize', - 'flushdb' => '\Predis\Commands\ServerFlushDatabase', - 'flushall' => '\Predis\Commands\ServerFlushAll', - 'save' => '\Predis\Commands\ServerSave', - 'bgsave' => '\Predis\Commands\ServerBackgroundSave', - 'lastsave' => '\Predis\Commands\ServerLastSave', - 'shutdown' => '\Predis\Commands\ServerShutdown', - 'bgrewriteaof' => '\Predis\Commands\ServerBackgroundRewriteAOF', + 'info' => 'Predis\Commands\ServerInfo', + 'slaveof' => 'Predis\Commands\ServerSlaveOf', + 'monitor' => 'Predis\Commands\ServerMonitor', + 'dbsize' => 'Predis\Commands\ServerDatabaseSize', + 'flushdb' => 'Predis\Commands\ServerFlushDatabase', + 'flushall' => 'Predis\Commands\ServerFlushAll', + 'save' => 'Predis\Commands\ServerSave', + 'bgsave' => 'Predis\Commands\ServerBackgroundSave', + 'lastsave' => 'Predis\Commands\ServerLastSave', + 'shutdown' => 'Predis\Commands\ServerShutdown', + 'bgrewriteaof' => 'Predis\Commands\ServerBackgroundRewriteAOF', /* ---------------- Redis 2.0 ---------------- */ /* commands operating on string values */ - 'setex' => '\Predis\Commands\StringSetExpire', - 'append' => '\Predis\Commands\StringAppend', - 'substr' => '\Predis\Commands\StringSubstr', + 'setex' => 'Predis\Commands\StringSetExpire', + 'append' => 'Predis\Commands\StringAppend', + 'substr' => 'Predis\Commands\StringSubstr', /* commands operating on lists */ - 'blpop' => '\Predis\Commands\ListPopFirstBlocking', - 'brpop' => '\Predis\Commands\ListPopLastBlocking', + 'blpop' => 'Predis\Commands\ListPopFirstBlocking', + 'brpop' => 'Predis\Commands\ListPopLastBlocking', /* commands operating on sorted sets */ - 'zunionstore' => '\Predis\Commands\ZSetUnionStore', - 'zinterstore' => '\Predis\Commands\ZSetIntersectionStore', - 'zcount' => '\Predis\Commands\ZSetCount', - 'zrank' => '\Predis\Commands\ZSetRank', - 'zrevrank' => '\Predis\Commands\ZSetReverseRank', - 'zremrangebyrank' => '\Predis\Commands\ZSetRemoveRangeByRank', + 'zunionstore' => 'Predis\Commands\ZSetUnionStore', + 'zinterstore' => 'Predis\Commands\ZSetIntersectionStore', + 'zcount' => 'Predis\Commands\ZSetCount', + 'zrank' => 'Predis\Commands\ZSetRank', + 'zrevrank' => 'Predis\Commands\ZSetReverseRank', + 'zremrangebyrank' => 'Predis\Commands\ZSetRemoveRangeByRank', /* commands operating on hashes */ - 'hset' => '\Predis\Commands\HashSet', - 'hsetnx' => '\Predis\Commands\HashSetPreserve', - 'hmset' => '\Predis\Commands\HashSetMultiple', - 'hincrby' => '\Predis\Commands\HashIncrementBy', - 'hget' => '\Predis\Commands\HashGet', - 'hmget' => '\Predis\Commands\HashGetMultiple', - 'hdel' => '\Predis\Commands\HashDelete', - 'hexists' => '\Predis\Commands\HashExists', - 'hlen' => '\Predis\Commands\HashLength', - 'hkeys' => '\Predis\Commands\HashKeys', - 'hvals' => '\Predis\Commands\HashValues', - 'hgetall' => '\Predis\Commands\HashGetAll', + 'hset' => 'Predis\Commands\HashSet', + 'hsetnx' => 'Predis\Commands\HashSetPreserve', + 'hmset' => 'Predis\Commands\HashSetMultiple', + 'hincrby' => 'Predis\Commands\HashIncrementBy', + 'hget' => 'Predis\Commands\HashGet', + 'hmget' => 'Predis\Commands\HashGetMultiple', + 'hdel' => 'Predis\Commands\HashDelete', + 'hexists' => 'Predis\Commands\HashExists', + 'hlen' => 'Predis\Commands\HashLength', + 'hkeys' => 'Predis\Commands\HashKeys', + 'hvals' => 'Predis\Commands\HashValues', + 'hgetall' => 'Predis\Commands\HashGetAll', /* transactions */ - 'multi' => '\Predis\Commands\TransactionMulti', - 'exec' => '\Predis\Commands\TransactionExec', - 'discard' => '\Predis\Commands\TransactionDiscard', + 'multi' => 'Predis\Commands\TransactionMulti', + 'exec' => 'Predis\Commands\TransactionExec', + 'discard' => 'Predis\Commands\TransactionDiscard', /* publish - subscribe */ - 'subscribe' => '\Predis\Commands\PubSubSubscribe', - 'unsubscribe' => '\Predis\Commands\PubSubUnsubscribe', - 'psubscribe' => '\Predis\Commands\PubSubSubscribeByPattern', - 'punsubscribe' => '\Predis\Commands\PubSubUnsubscribeByPattern', - 'publish' => '\Predis\Commands\PubSubPublish', + 'subscribe' => 'Predis\Commands\PubSubSubscribe', + 'unsubscribe' => 'Predis\Commands\PubSubUnsubscribe', + 'psubscribe' => 'Predis\Commands\PubSubSubscribeByPattern', + 'punsubscribe' => 'Predis\Commands\PubSubUnsubscribeByPattern', + 'publish' => 'Predis\Commands\PubSubPublish', /* remote server control commands */ - 'config' => '\Predis\Commands\ServerConfig', + 'config' => 'Predis\Commands\ServerConfig', ); } } diff --git a/lib/Predis/Profiles/ServerVersion22.php b/lib/Predis/Profiles/ServerVersion22.php index 34b8fd01..e49af0a9 100644 --- a/lib/Predis/Profiles/ServerVersion22.php +++ b/lib/Predis/Profiles/ServerVersion22.php @@ -35,170 +35,170 @@ class ServerVersion22 extends ServerProfile /* ---------------- Redis 1.2 ---------------- */ /* commands operating on the key space */ - 'exists' => '\Predis\Commands\KeyExists', - 'del' => '\Predis\Commands\KeyDelete', - 'type' => '\Predis\Commands\KeyType', - 'keys' => '\Predis\Commands\KeyKeys', - 'randomkey' => '\Predis\Commands\KeyRandom', - 'rename' => '\Predis\Commands\KeyRename', - 'renamenx' => '\Predis\Commands\KeyRenamePreserve', - 'expire' => '\Predis\Commands\KeyExpire', - 'expireat' => '\Predis\Commands\KeyExpireAt', - 'ttl' => '\Predis\Commands\KeyTimeToLive', - 'move' => '\Predis\Commands\KeyMove', - 'sort' => '\Predis\Commands\KeySort', + 'exists' => 'Predis\Commands\KeyExists', + 'del' => 'Predis\Commands\KeyDelete', + 'type' => 'Predis\Commands\KeyType', + 'keys' => 'Predis\Commands\KeyKeys', + 'randomkey' => 'Predis\Commands\KeyRandom', + 'rename' => 'Predis\Commands\KeyRename', + 'renamenx' => 'Predis\Commands\KeyRenamePreserve', + 'expire' => 'Predis\Commands\KeyExpire', + 'expireat' => 'Predis\Commands\KeyExpireAt', + 'ttl' => 'Predis\Commands\KeyTimeToLive', + 'move' => 'Predis\Commands\KeyMove', + 'sort' => 'Predis\Commands\KeySort', /* commands operating on string values */ - 'set' => '\Predis\Commands\StringSet', - 'setnx' => '\Predis\Commands\StringSetPreserve', - 'mset' => '\Predis\Commands\StringSetMultiple', - 'msetnx' => '\Predis\Commands\StringSetMultiplePreserve', - 'get' => '\Predis\Commands\StringGet', - 'mget' => '\Predis\Commands\StringGetMultiple', - 'getset' => '\Predis\Commands\StringGetSet', - 'incr' => '\Predis\Commands\StringIncrement', - 'incrby' => '\Predis\Commands\StringIncrementBy', - 'decr' => '\Predis\Commands\StringDecrement', - 'decrby' => '\Predis\Commands\StringDecrementBy', + 'set' => 'Predis\Commands\StringSet', + 'setnx' => 'Predis\Commands\StringSetPreserve', + 'mset' => 'Predis\Commands\StringSetMultiple', + 'msetnx' => 'Predis\Commands\StringSetMultiplePreserve', + 'get' => 'Predis\Commands\StringGet', + 'mget' => 'Predis\Commands\StringGetMultiple', + 'getset' => 'Predis\Commands\StringGetSet', + 'incr' => 'Predis\Commands\StringIncrement', + 'incrby' => 'Predis\Commands\StringIncrementBy', + 'decr' => 'Predis\Commands\StringDecrement', + 'decrby' => 'Predis\Commands\StringDecrementBy', /* commands operating on lists */ - 'rpush' => '\Predis\Commands\ListPushTail', - 'lpush' => '\Predis\Commands\ListPushHead', - 'llen' => '\Predis\Commands\ListLength', - 'lrange' => '\Predis\Commands\ListRange', - 'ltrim' => '\Predis\Commands\ListTrim', - 'lindex' => '\Predis\Commands\ListIndex', - 'lset' => '\Predis\Commands\ListSet', - 'lrem' => '\Predis\Commands\ListRemove', - 'lpop' => '\Predis\Commands\ListPopFirst', - 'rpop' => '\Predis\Commands\ListPopLast', - 'rpoplpush' => '\Predis\Commands\ListPopLastPushHead', + 'rpush' => 'Predis\Commands\ListPushTail', + 'lpush' => 'Predis\Commands\ListPushHead', + 'llen' => 'Predis\Commands\ListLength', + 'lrange' => 'Predis\Commands\ListRange', + 'ltrim' => 'Predis\Commands\ListTrim', + 'lindex' => 'Predis\Commands\ListIndex', + 'lset' => 'Predis\Commands\ListSet', + 'lrem' => 'Predis\Commands\ListRemove', + 'lpop' => 'Predis\Commands\ListPopFirst', + 'rpop' => 'Predis\Commands\ListPopLast', + 'rpoplpush' => 'Predis\Commands\ListPopLastPushHead', /* commands operating on sets */ - 'sadd' => '\Predis\Commands\SetAdd', - 'srem' => '\Predis\Commands\SetRemove', - 'spop' => '\Predis\Commands\SetPop', - 'smove' => '\Predis\Commands\SetMove', - 'scard' => '\Predis\Commands\SetCardinality', - 'sismember' => '\Predis\Commands\SetIsMember', - 'sinter' => '\Predis\Commands\SetIntersection', - 'sinterstore' => '\Predis\Commands\SetIntersectionStore', - 'sunion' => '\Predis\Commands\SetUnion', - 'sunionstore' => '\Predis\Commands\SetUnionStore', - 'sdiff' => '\Predis\Commands\SetDifference', - 'sdiffstore' => '\Predis\Commands\SetDifferenceStore', - 'smembers' => '\Predis\Commands\SetMembers', - 'srandmember' => '\Predis\Commands\SetRandomMember', + 'sadd' => 'Predis\Commands\SetAdd', + 'srem' => 'Predis\Commands\SetRemove', + 'spop' => 'Predis\Commands\SetPop', + 'smove' => 'Predis\Commands\SetMove', + 'scard' => 'Predis\Commands\SetCardinality', + 'sismember' => 'Predis\Commands\SetIsMember', + 'sinter' => 'Predis\Commands\SetIntersection', + 'sinterstore' => 'Predis\Commands\SetIntersectionStore', + 'sunion' => 'Predis\Commands\SetUnion', + 'sunionstore' => 'Predis\Commands\SetUnionStore', + 'sdiff' => 'Predis\Commands\SetDifference', + 'sdiffstore' => 'Predis\Commands\SetDifferenceStore', + 'smembers' => 'Predis\Commands\SetMembers', + 'srandmember' => 'Predis\Commands\SetRandomMember', /* commands operating on sorted sets */ - 'zadd' => '\Predis\Commands\ZSetAdd', - 'zincrby' => '\Predis\Commands\ZSetIncrementBy', - 'zrem' => '\Predis\Commands\ZSetRemove', - 'zrange' => '\Predis\Commands\ZSetRange', - 'zrevrange' => '\Predis\Commands\ZSetReverseRange', - 'zrangebyscore' => '\Predis\Commands\ZSetRangeByScore', - 'zcard' => '\Predis\Commands\ZSetCardinality', - 'zscore' => '\Predis\Commands\ZSetScore', - 'zremrangebyscore' => '\Predis\Commands\ZSetRemoveRangeByScore', + 'zadd' => 'Predis\Commands\ZSetAdd', + 'zincrby' => 'Predis\Commands\ZSetIncrementBy', + 'zrem' => 'Predis\Commands\ZSetRemove', + 'zrange' => 'Predis\Commands\ZSetRange', + 'zrevrange' => 'Predis\Commands\ZSetReverseRange', + 'zrangebyscore' => 'Predis\Commands\ZSetRangeByScore', + 'zcard' => 'Predis\Commands\ZSetCardinality', + 'zscore' => 'Predis\Commands\ZSetScore', + 'zremrangebyscore' => 'Predis\Commands\ZSetRemoveRangeByScore', /* connection related commands */ - 'ping' => '\Predis\Commands\ConnectionPing', - 'auth' => '\Predis\Commands\ConnectionAuth', - 'select' => '\Predis\Commands\ConnectionSelect', - 'echo' => '\Predis\Commands\ConnectionEcho', - 'quit' => '\Predis\Commands\ConnectionQuit', + 'ping' => 'Predis\Commands\ConnectionPing', + 'auth' => 'Predis\Commands\ConnectionAuth', + 'select' => 'Predis\Commands\ConnectionSelect', + 'echo' => 'Predis\Commands\ConnectionEcho', + 'quit' => 'Predis\Commands\ConnectionQuit', /* remote server control commands */ - 'info' => '\Predis\Commands\ServerInfo', - 'slaveof' => '\Predis\Commands\ServerSlaveOf', - 'monitor' => '\Predis\Commands\ServerMonitor', - 'dbsize' => '\Predis\Commands\ServerDatabaseSize', - 'flushdb' => '\Predis\Commands\ServerFlushDatabase', - 'flushall' => '\Predis\Commands\ServerFlushAll', - 'save' => '\Predis\Commands\ServerSave', - 'bgsave' => '\Predis\Commands\ServerBackgroundSave', - 'lastsave' => '\Predis\Commands\ServerLastSave', - 'shutdown' => '\Predis\Commands\ServerShutdown', - 'bgrewriteaof' => '\Predis\Commands\ServerBackgroundRewriteAOF', + 'info' => 'Predis\Commands\ServerInfo', + 'slaveof' => 'Predis\Commands\ServerSlaveOf', + 'monitor' => 'Predis\Commands\ServerMonitor', + 'dbsize' => 'Predis\Commands\ServerDatabaseSize', + 'flushdb' => 'Predis\Commands\ServerFlushDatabase', + 'flushall' => 'Predis\Commands\ServerFlushAll', + 'save' => 'Predis\Commands\ServerSave', + 'bgsave' => 'Predis\Commands\ServerBackgroundSave', + 'lastsave' => 'Predis\Commands\ServerLastSave', + 'shutdown' => 'Predis\Commands\ServerShutdown', + 'bgrewriteaof' => 'Predis\Commands\ServerBackgroundRewriteAOF', /* ---------------- Redis 2.0 ---------------- */ /* commands operating on string values */ - 'setex' => '\Predis\Commands\StringSetExpire', - 'append' => '\Predis\Commands\StringAppend', - 'substr' => '\Predis\Commands\StringSubstr', + 'setex' => 'Predis\Commands\StringSetExpire', + 'append' => 'Predis\Commands\StringAppend', + 'substr' => 'Predis\Commands\StringSubstr', /* commands operating on lists */ - 'blpop' => '\Predis\Commands\ListPopFirstBlocking', - 'brpop' => '\Predis\Commands\ListPopLastBlocking', + 'blpop' => 'Predis\Commands\ListPopFirstBlocking', + 'brpop' => 'Predis\Commands\ListPopLastBlocking', /* commands operating on sorted sets */ - 'zunionstore' => '\Predis\Commands\ZSetUnionStore', - 'zinterstore' => '\Predis\Commands\ZSetIntersectionStore', - 'zcount' => '\Predis\Commands\ZSetCount', - 'zrank' => '\Predis\Commands\ZSetRank', - 'zrevrank' => '\Predis\Commands\ZSetReverseRank', - 'zremrangebyrank' => '\Predis\Commands\ZSetRemoveRangeByRank', + 'zunionstore' => 'Predis\Commands\ZSetUnionStore', + 'zinterstore' => 'Predis\Commands\ZSetIntersectionStore', + 'zcount' => 'Predis\Commands\ZSetCount', + 'zrank' => 'Predis\Commands\ZSetRank', + 'zrevrank' => 'Predis\Commands\ZSetReverseRank', + 'zremrangebyrank' => 'Predis\Commands\ZSetRemoveRangeByRank', /* commands operating on hashes */ - 'hset' => '\Predis\Commands\HashSet', - 'hsetnx' => '\Predis\Commands\HashSetPreserve', - 'hmset' => '\Predis\Commands\HashSetMultiple', - 'hincrby' => '\Predis\Commands\HashIncrementBy', - 'hget' => '\Predis\Commands\HashGet', - 'hmget' => '\Predis\Commands\HashGetMultiple', - 'hdel' => '\Predis\Commands\HashDelete', - 'hexists' => '\Predis\Commands\HashExists', - 'hlen' => '\Predis\Commands\HashLength', - 'hkeys' => '\Predis\Commands\HashKeys', - 'hvals' => '\Predis\Commands\HashValues', - 'hgetall' => '\Predis\Commands\HashGetAll', + 'hset' => 'Predis\Commands\HashSet', + 'hsetnx' => 'Predis\Commands\HashSetPreserve', + 'hmset' => 'Predis\Commands\HashSetMultiple', + 'hincrby' => 'Predis\Commands\HashIncrementBy', + 'hget' => 'Predis\Commands\HashGet', + 'hmget' => 'Predis\Commands\HashGetMultiple', + 'hdel' => 'Predis\Commands\HashDelete', + 'hexists' => 'Predis\Commands\HashExists', + 'hlen' => 'Predis\Commands\HashLength', + 'hkeys' => 'Predis\Commands\HashKeys', + 'hvals' => 'Predis\Commands\HashValues', + 'hgetall' => 'Predis\Commands\HashGetAll', /* transactions */ - 'multi' => '\Predis\Commands\TransactionMulti', - 'exec' => '\Predis\Commands\TransactionExec', - 'discard' => '\Predis\Commands\TransactionDiscard', + 'multi' => 'Predis\Commands\TransactionMulti', + 'exec' => 'Predis\Commands\TransactionExec', + 'discard' => 'Predis\Commands\TransactionDiscard', /* publish - subscribe */ - 'subscribe' => '\Predis\Commands\PubSubSubscribe', - 'unsubscribe' => '\Predis\Commands\PubSubUnsubscribe', - 'psubscribe' => '\Predis\Commands\PubSubSubscribeByPattern', - 'punsubscribe' => '\Predis\Commands\PubSubUnsubscribeByPattern', - 'publish' => '\Predis\Commands\PubSubPublish', + 'subscribe' => 'Predis\Commands\PubSubSubscribe', + 'unsubscribe' => 'Predis\Commands\PubSubUnsubscribe', + 'psubscribe' => 'Predis\Commands\PubSubSubscribeByPattern', + 'punsubscribe' => 'Predis\Commands\PubSubUnsubscribeByPattern', + 'publish' => 'Predis\Commands\PubSubPublish', /* remote server control commands */ - 'config' => '\Predis\Commands\ServerConfig', + 'config' => 'Predis\Commands\ServerConfig', /* ---------------- Redis 2.2 ---------------- */ /* commands operating on the key space */ - 'persist' => '\Predis\Commands\KeyPersist', + 'persist' => 'Predis\Commands\KeyPersist', /* commands operating on string values */ - 'strlen' => '\Predis\Commands\StringStrlen', - 'setrange' => '\Predis\Commands\StringSetRange', - 'getrange' => '\Predis\Commands\StringGetRange', - 'setbit' => '\Predis\Commands\StringSetBit', - 'getbit' => '\Predis\Commands\StringGetBit', + 'strlen' => 'Predis\Commands\StringStrlen', + 'setrange' => 'Predis\Commands\StringSetRange', + 'getrange' => 'Predis\Commands\StringGetRange', + 'setbit' => 'Predis\Commands\StringSetBit', + 'getbit' => 'Predis\Commands\StringGetBit', /* commands operating on lists */ - 'rpushx' => '\Predis\Commands\ListPushTailX', - 'lpushx' => '\Predis\Commands\ListPushHeadX', - 'linsert' => '\Predis\Commands\ListInsert', - 'brpoplpush' => '\Predis\Commands\ListPopLastPushHeadBlocking', + 'rpushx' => 'Predis\Commands\ListPushTailX', + 'lpushx' => 'Predis\Commands\ListPushHeadX', + 'linsert' => 'Predis\Commands\ListInsert', + 'brpoplpush' => 'Predis\Commands\ListPopLastPushHeadBlocking', /* commands operating on sorted sets */ - 'zrevrangebyscore' => '\Predis\Commands\ZSetReverseRangeByScore', + 'zrevrangebyscore' => 'Predis\Commands\ZSetReverseRangeByScore', /* transactions */ - 'watch' => '\Predis\Commands\TransactionWatch', - 'unwatch' => '\Predis\Commands\TransactionUnwatch', + 'watch' => 'Predis\Commands\TransactionWatch', + 'unwatch' => 'Predis\Commands\TransactionUnwatch', /* remote server control commands */ - 'object' => '\Predis\Commands\ServerObject', - 'slowlog' => '\Predis\Commands\ServerSlowlog', + 'object' => 'Predis\Commands\ServerObject', + 'slowlog' => 'Predis\Commands\ServerSlowlog', ); } } diff --git a/lib/Predis/Profiles/ServerVersion24.php b/lib/Predis/Profiles/ServerVersion24.php index 173d1ad5..2617945e 100644 --- a/lib/Predis/Profiles/ServerVersion24.php +++ b/lib/Predis/Profiles/ServerVersion24.php @@ -35,176 +35,176 @@ class ServerVersion24 extends ServerProfile /* ---------------- Redis 1.2 ---------------- */ /* commands operating on the key space */ - 'exists' => '\Predis\Commands\KeyExists', - 'del' => '\Predis\Commands\KeyDelete', - 'type' => '\Predis\Commands\KeyType', - 'keys' => '\Predis\Commands\KeyKeys', - 'randomkey' => '\Predis\Commands\KeyRandom', - 'rename' => '\Predis\Commands\KeyRename', - 'renamenx' => '\Predis\Commands\KeyRenamePreserve', - 'expire' => '\Predis\Commands\KeyExpire', - 'expireat' => '\Predis\Commands\KeyExpireAt', - 'ttl' => '\Predis\Commands\KeyTimeToLive', - 'move' => '\Predis\Commands\KeyMove', - 'sort' => '\Predis\Commands\KeySort', + 'exists' => 'Predis\Commands\KeyExists', + 'del' => 'Predis\Commands\KeyDelete', + 'type' => 'Predis\Commands\KeyType', + 'keys' => 'Predis\Commands\KeyKeys', + 'randomkey' => 'Predis\Commands\KeyRandom', + 'rename' => 'Predis\Commands\KeyRename', + 'renamenx' => 'Predis\Commands\KeyRenamePreserve', + 'expire' => 'Predis\Commands\KeyExpire', + 'expireat' => 'Predis\Commands\KeyExpireAt', + 'ttl' => 'Predis\Commands\KeyTimeToLive', + 'move' => 'Predis\Commands\KeyMove', + 'sort' => 'Predis\Commands\KeySort', /* commands operating on string values */ - 'set' => '\Predis\Commands\StringSet', - 'setnx' => '\Predis\Commands\StringSetPreserve', - 'mset' => '\Predis\Commands\StringSetMultiple', - 'msetnx' => '\Predis\Commands\StringSetMultiplePreserve', - 'get' => '\Predis\Commands\StringGet', - 'mget' => '\Predis\Commands\StringGetMultiple', - 'getset' => '\Predis\Commands\StringGetSet', - 'incr' => '\Predis\Commands\StringIncrement', - 'incrby' => '\Predis\Commands\StringIncrementBy', - 'decr' => '\Predis\Commands\StringDecrement', - 'decrby' => '\Predis\Commands\StringDecrementBy', + 'set' => 'Predis\Commands\StringSet', + 'setnx' => 'Predis\Commands\StringSetPreserve', + 'mset' => 'Predis\Commands\StringSetMultiple', + 'msetnx' => 'Predis\Commands\StringSetMultiplePreserve', + 'get' => 'Predis\Commands\StringGet', + 'mget' => 'Predis\Commands\StringGetMultiple', + 'getset' => 'Predis\Commands\StringGetSet', + 'incr' => 'Predis\Commands\StringIncrement', + 'incrby' => 'Predis\Commands\StringIncrementBy', + 'decr' => 'Predis\Commands\StringDecrement', + 'decrby' => 'Predis\Commands\StringDecrementBy', /* commands operating on lists */ - 'rpush' => '\Predis\Commands\ListPushTail', - 'lpush' => '\Predis\Commands\ListPushHead', - 'llen' => '\Predis\Commands\ListLength', - 'lrange' => '\Predis\Commands\ListRange', - 'ltrim' => '\Predis\Commands\ListTrim', - 'lindex' => '\Predis\Commands\ListIndex', - 'lset' => '\Predis\Commands\ListSet', - 'lrem' => '\Predis\Commands\ListRemove', - 'lpop' => '\Predis\Commands\ListPopFirst', - 'rpop' => '\Predis\Commands\ListPopLast', - 'rpoplpush' => '\Predis\Commands\ListPopLastPushHead', + 'rpush' => 'Predis\Commands\ListPushTail', + 'lpush' => 'Predis\Commands\ListPushHead', + 'llen' => 'Predis\Commands\ListLength', + 'lrange' => 'Predis\Commands\ListRange', + 'ltrim' => 'Predis\Commands\ListTrim', + 'lindex' => 'Predis\Commands\ListIndex', + 'lset' => 'Predis\Commands\ListSet', + 'lrem' => 'Predis\Commands\ListRemove', + 'lpop' => 'Predis\Commands\ListPopFirst', + 'rpop' => 'Predis\Commands\ListPopLast', + 'rpoplpush' => 'Predis\Commands\ListPopLastPushHead', /* commands operating on sets */ - 'sadd' => '\Predis\Commands\SetAdd', - 'srem' => '\Predis\Commands\SetRemove', - 'spop' => '\Predis\Commands\SetPop', - 'smove' => '\Predis\Commands\SetMove', - 'scard' => '\Predis\Commands\SetCardinality', - 'sismember' => '\Predis\Commands\SetIsMember', - 'sinter' => '\Predis\Commands\SetIntersection', - 'sinterstore' => '\Predis\Commands\SetIntersectionStore', - 'sunion' => '\Predis\Commands\SetUnion', - 'sunionstore' => '\Predis\Commands\SetUnionStore', - 'sdiff' => '\Predis\Commands\SetDifference', - 'sdiffstore' => '\Predis\Commands\SetDifferenceStore', - 'smembers' => '\Predis\Commands\SetMembers', - 'srandmember' => '\Predis\Commands\SetRandomMember', + 'sadd' => 'Predis\Commands\SetAdd', + 'srem' => 'Predis\Commands\SetRemove', + 'spop' => 'Predis\Commands\SetPop', + 'smove' => 'Predis\Commands\SetMove', + 'scard' => 'Predis\Commands\SetCardinality', + 'sismember' => 'Predis\Commands\SetIsMember', + 'sinter' => 'Predis\Commands\SetIntersection', + 'sinterstore' => 'Predis\Commands\SetIntersectionStore', + 'sunion' => 'Predis\Commands\SetUnion', + 'sunionstore' => 'Predis\Commands\SetUnionStore', + 'sdiff' => 'Predis\Commands\SetDifference', + 'sdiffstore' => 'Predis\Commands\SetDifferenceStore', + 'smembers' => 'Predis\Commands\SetMembers', + 'srandmember' => 'Predis\Commands\SetRandomMember', /* commands operating on sorted sets */ - 'zadd' => '\Predis\Commands\ZSetAdd', - 'zincrby' => '\Predis\Commands\ZSetIncrementBy', - 'zrem' => '\Predis\Commands\ZSetRemove', - 'zrange' => '\Predis\Commands\ZSetRange', - 'zrevrange' => '\Predis\Commands\ZSetReverseRange', - 'zrangebyscore' => '\Predis\Commands\ZSetRangeByScore', - 'zcard' => '\Predis\Commands\ZSetCardinality', - 'zscore' => '\Predis\Commands\ZSetScore', - 'zremrangebyscore' => '\Predis\Commands\ZSetRemoveRangeByScore', + 'zadd' => 'Predis\Commands\ZSetAdd', + 'zincrby' => 'Predis\Commands\ZSetIncrementBy', + 'zrem' => 'Predis\Commands\ZSetRemove', + 'zrange' => 'Predis\Commands\ZSetRange', + 'zrevrange' => 'Predis\Commands\ZSetReverseRange', + 'zrangebyscore' => 'Predis\Commands\ZSetRangeByScore', + 'zcard' => 'Predis\Commands\ZSetCardinality', + 'zscore' => 'Predis\Commands\ZSetScore', + 'zremrangebyscore' => 'Predis\Commands\ZSetRemoveRangeByScore', /* connection related commands */ - 'ping' => '\Predis\Commands\ConnectionPing', - 'auth' => '\Predis\Commands\ConnectionAuth', - 'select' => '\Predis\Commands\ConnectionSelect', - 'echo' => '\Predis\Commands\ConnectionEcho', - 'quit' => '\Predis\Commands\ConnectionQuit', + 'ping' => 'Predis\Commands\ConnectionPing', + 'auth' => 'Predis\Commands\ConnectionAuth', + 'select' => 'Predis\Commands\ConnectionSelect', + 'echo' => 'Predis\Commands\ConnectionEcho', + 'quit' => 'Predis\Commands\ConnectionQuit', /* remote server control commands */ - 'info' => '\Predis\Commands\ServerInfo', - 'slaveof' => '\Predis\Commands\ServerSlaveOf', - 'monitor' => '\Predis\Commands\ServerMonitor', - 'dbsize' => '\Predis\Commands\ServerDatabaseSize', - 'flushdb' => '\Predis\Commands\ServerFlushDatabase', - 'flushall' => '\Predis\Commands\ServerFlushAll', - 'save' => '\Predis\Commands\ServerSave', - 'bgsave' => '\Predis\Commands\ServerBackgroundSave', - 'lastsave' => '\Predis\Commands\ServerLastSave', - 'shutdown' => '\Predis\Commands\ServerShutdown', - 'bgrewriteaof' => '\Predis\Commands\ServerBackgroundRewriteAOF', + 'info' => 'Predis\Commands\ServerInfo', + 'slaveof' => 'Predis\Commands\ServerSlaveOf', + 'monitor' => 'Predis\Commands\ServerMonitor', + 'dbsize' => 'Predis\Commands\ServerDatabaseSize', + 'flushdb' => 'Predis\Commands\ServerFlushDatabase', + 'flushall' => 'Predis\Commands\ServerFlushAll', + 'save' => 'Predis\Commands\ServerSave', + 'bgsave' => 'Predis\Commands\ServerBackgroundSave', + 'lastsave' => 'Predis\Commands\ServerLastSave', + 'shutdown' => 'Predis\Commands\ServerShutdown', + 'bgrewriteaof' => 'Predis\Commands\ServerBackgroundRewriteAOF', /* ---------------- Redis 2.0 ---------------- */ /* commands operating on string values */ - 'setex' => '\Predis\Commands\StringSetExpire', - 'append' => '\Predis\Commands\StringAppend', - 'substr' => '\Predis\Commands\StringSubstr', + 'setex' => 'Predis\Commands\StringSetExpire', + 'append' => 'Predis\Commands\StringAppend', + 'substr' => 'Predis\Commands\StringSubstr', /* commands operating on lists */ - 'blpop' => '\Predis\Commands\ListPopFirstBlocking', - 'brpop' => '\Predis\Commands\ListPopLastBlocking', + 'blpop' => 'Predis\Commands\ListPopFirstBlocking', + 'brpop' => 'Predis\Commands\ListPopLastBlocking', /* commands operating on sorted sets */ - 'zunionstore' => '\Predis\Commands\ZSetUnionStore', - 'zinterstore' => '\Predis\Commands\ZSetIntersectionStore', - 'zcount' => '\Predis\Commands\ZSetCount', - 'zrank' => '\Predis\Commands\ZSetRank', - 'zrevrank' => '\Predis\Commands\ZSetReverseRank', - 'zremrangebyrank' => '\Predis\Commands\ZSetRemoveRangeByRank', + 'zunionstore' => 'Predis\Commands\ZSetUnionStore', + 'zinterstore' => 'Predis\Commands\ZSetIntersectionStore', + 'zcount' => 'Predis\Commands\ZSetCount', + 'zrank' => 'Predis\Commands\ZSetRank', + 'zrevrank' => 'Predis\Commands\ZSetReverseRank', + 'zremrangebyrank' => 'Predis\Commands\ZSetRemoveRangeByRank', /* commands operating on hashes */ - 'hset' => '\Predis\Commands\HashSet', - 'hsetnx' => '\Predis\Commands\HashSetPreserve', - 'hmset' => '\Predis\Commands\HashSetMultiple', - 'hincrby' => '\Predis\Commands\HashIncrementBy', - 'hget' => '\Predis\Commands\HashGet', - 'hmget' => '\Predis\Commands\HashGetMultiple', - 'hdel' => '\Predis\Commands\HashDelete', - 'hexists' => '\Predis\Commands\HashExists', - 'hlen' => '\Predis\Commands\HashLength', - 'hkeys' => '\Predis\Commands\HashKeys', - 'hvals' => '\Predis\Commands\HashValues', - 'hgetall' => '\Predis\Commands\HashGetAll', + 'hset' => 'Predis\Commands\HashSet', + 'hsetnx' => 'Predis\Commands\HashSetPreserve', + 'hmset' => 'Predis\Commands\HashSetMultiple', + 'hincrby' => 'Predis\Commands\HashIncrementBy', + 'hget' => 'Predis\Commands\HashGet', + 'hmget' => 'Predis\Commands\HashGetMultiple', + 'hdel' => 'Predis\Commands\HashDelete', + 'hexists' => 'Predis\Commands\HashExists', + 'hlen' => 'Predis\Commands\HashLength', + 'hkeys' => 'Predis\Commands\HashKeys', + 'hvals' => 'Predis\Commands\HashValues', + 'hgetall' => 'Predis\Commands\HashGetAll', /* transactions */ - 'multi' => '\Predis\Commands\TransactionMulti', - 'exec' => '\Predis\Commands\TransactionExec', - 'discard' => '\Predis\Commands\TransactionDiscard', + 'multi' => 'Predis\Commands\TransactionMulti', + 'exec' => 'Predis\Commands\TransactionExec', + 'discard' => 'Predis\Commands\TransactionDiscard', /* publish - subscribe */ - 'subscribe' => '\Predis\Commands\PubSubSubscribe', - 'unsubscribe' => '\Predis\Commands\PubSubUnsubscribe', - 'psubscribe' => '\Predis\Commands\PubSubSubscribeByPattern', - 'punsubscribe' => '\Predis\Commands\PubSubUnsubscribeByPattern', - 'publish' => '\Predis\Commands\PubSubPublish', + 'subscribe' => 'Predis\Commands\PubSubSubscribe', + 'unsubscribe' => 'Predis\Commands\PubSubUnsubscribe', + 'psubscribe' => 'Predis\Commands\PubSubSubscribeByPattern', + 'punsubscribe' => 'Predis\Commands\PubSubUnsubscribeByPattern', + 'publish' => 'Predis\Commands\PubSubPublish', /* remote server control commands */ - 'config' => '\Predis\Commands\ServerConfig', + 'config' => 'Predis\Commands\ServerConfig', /* ---------------- Redis 2.2 ---------------- */ /* commands operating on the key space */ - 'persist' => '\Predis\Commands\KeyPersist', + 'persist' => 'Predis\Commands\KeyPersist', /* commands operating on string values */ - 'strlen' => '\Predis\Commands\StringStrlen', - 'setrange' => '\Predis\Commands\StringSetRange', - 'getrange' => '\Predis\Commands\StringGetRange', - 'setbit' => '\Predis\Commands\StringSetBit', - 'getbit' => '\Predis\Commands\StringGetBit', + 'strlen' => 'Predis\Commands\StringStrlen', + 'setrange' => 'Predis\Commands\StringSetRange', + 'getrange' => 'Predis\Commands\StringGetRange', + 'setbit' => 'Predis\Commands\StringSetBit', + 'getbit' => 'Predis\Commands\StringGetBit', /* commands operating on lists */ - 'rpushx' => '\Predis\Commands\ListPushTailX', - 'lpushx' => '\Predis\Commands\ListPushHeadX', - 'linsert' => '\Predis\Commands\ListInsert', - 'brpoplpush' => '\Predis\Commands\ListPopLastPushHeadBlocking', + 'rpushx' => 'Predis\Commands\ListPushTailX', + 'lpushx' => 'Predis\Commands\ListPushHeadX', + 'linsert' => 'Predis\Commands\ListInsert', + 'brpoplpush' => 'Predis\Commands\ListPopLastPushHeadBlocking', /* commands operating on sorted sets */ - 'zrevrangebyscore' => '\Predis\Commands\ZSetReverseRangeByScore', + 'zrevrangebyscore' => 'Predis\Commands\ZSetReverseRangeByScore', /* transactions */ - 'watch' => '\Predis\Commands\TransactionWatch', - 'unwatch' => '\Predis\Commands\TransactionUnwatch', + 'watch' => 'Predis\Commands\TransactionWatch', + 'unwatch' => 'Predis\Commands\TransactionUnwatch', /* remote server control commands */ - 'object' => '\Predis\Commands\ServerObject', - 'slowlog' => '\Predis\Commands\ServerSlowlog', + 'object' => 'Predis\Commands\ServerObject', + 'slowlog' => 'Predis\Commands\ServerSlowlog', /* ---------------- Redis 2.4 ---------------- */ /* remote server control commands */ - 'client' => '\Predis\Commands\ServerClient', + 'client' => 'Predis\Commands\ServerClient', ); } } diff --git a/lib/Predis/Profiles/ServerVersionNext.php b/lib/Predis/Profiles/ServerVersionNext.php index 8c890843..cec4547c 100644 --- a/lib/Predis/Profiles/ServerVersionNext.php +++ b/lib/Predis/Profiles/ServerVersionNext.php @@ -33,24 +33,24 @@ class ServerVersionNext extends ServerVersion24 { return array_merge(parent::getSupportedCommands(), array( /* commands operating on the key space */ - 'pttl' => '\Predis\Commands\KeyPreciseTimeToLive', - 'pexpire' => '\Predis\Commands\KeyPreciseExpire', - 'pexpireat' => '\Predis\Commands\KeyPreciseExpireAt', + 'pttl' => 'Predis\Commands\KeyPreciseTimeToLive', + 'pexpire' => 'Predis\Commands\KeyPreciseExpire', + 'pexpireat' => 'Predis\Commands\KeyPreciseExpireAt', /* commands operating on string values */ - 'psetex' => '\Predis\Commands\StringPreciseSetExpire', - 'incrbyfloat' => '\Predis\Commands\StringIncrementByFloat', + 'psetex' => 'Predis\Commands\StringPreciseSetExpire', + 'incrbyfloat' => 'Predis\Commands\StringIncrementByFloat', /* commands operating on hashes */ - 'hincrbyfloat' => '\Predis\Commands\HashIncrementByFloat', + 'hincrbyfloat' => 'Predis\Commands\HashIncrementByFloat', /* scripting */ - 'eval' => '\Predis\Commands\ServerEval', - 'evalsha' => '\Predis\Commands\ServerEvalSHA', - 'script' => '\Predis\Commands\ServerScript', + 'eval' => 'Predis\Commands\ServerEval', + 'evalsha' => 'Predis\Commands\ServerEvalSHA', + 'script' => 'Predis\Commands\ServerScript', /* remote server control commands */ - 'info' => '\Predis\Commands\ServerInfoV26x', + 'info' => 'Predis\Commands\ServerInfoV26x', )); } } diff --git a/lib/Predis/PubSub/DispatcherLoop.php b/lib/Predis/PubSub/DispatcherLoop.php index c7fab965..7bdd10cf 100644 --- a/lib/Predis/PubSub/DispatcherLoop.php +++ b/lib/Predis/PubSub/DispatcherLoop.php @@ -12,7 +12,6 @@ namespace Predis\PubSub; use Predis\Client; -use Predis\ClientException; /** * Method-dispatcher loop built around the client-side abstraction of a Redis @@ -46,7 +45,7 @@ class DispatcherLoop protected function validateCallback($callable) { if (!is_callable($callable)) { - throw new ClientException("A valid callable object must be provided"); + throw new \InvalidArgumentException("A valid callable object must be provided"); } } diff --git a/lib/Predis/PubSub/PubSubContext.php b/lib/Predis/PubSub/PubSubContext.php index 168634ee..03c95432 100644 --- a/lib/Predis/PubSub/PubSubContext.php +++ b/lib/Predis/PubSub/PubSubContext.php @@ -14,6 +14,7 @@ namespace Predis\PubSub; use Predis\Client; use Predis\Helpers; use Predis\ClientException; +use Predis\NotSupportedException; /** * Client-side abstraction of a Publish / Subscribe context. @@ -57,7 +58,7 @@ class PubSubContext implements \Iterator */ public function __destruct() { - $this->closeContext(); + $this->closeContext(true); } /** @@ -69,17 +70,12 @@ class PubSubContext implements \Iterator private function checkCapabilities(Client $client) { if (Helpers::isCluster($client->getConnection())) { - throw new ClientException( - 'Cannot initialize a PUB/SUB context over a cluster of connections' - ); + throw new NotSupportedException('Cannot initialize a PUB/SUB context over a cluster of connections'); } $commands = array('publish', 'subscribe', 'unsubscribe', 'psubscribe', 'punsubscribe'); - if ($client->getProfile()->supportsCommands($commands) === false) { - throw new ClientException( - 'The current profile does not support PUB/SUB related commands' - ); + throw new NotSupportedException('The current profile does not support PUB/SUB related commands'); } } @@ -150,10 +146,23 @@ class PubSubContext implements \Iterator /** * Closes the context by unsubscribing from all the subscribed channels. + * Optionally, the context can be forcefully closed by dropping the + * underlying connection. + * + * @param Boolean $force Forcefully close the context by closing the connection. + * @return Boolean Returns false if there are no pending messages. */ - public function closeContext() + public function closeContext($force = false) { - if ($this->valid()) { + if (!$this->valid()) { + return false; + } + + if ($force) { + $this->invalidate(); + $this->client->disconnect(); + } + else { if ($this->isFlagSet(self::STATUS_SUBSCRIBED)) { $this->unsubscribe(); } @@ -161,6 +170,8 @@ class PubSubContext implements \Iterator $this->punsubscribe(); } } + + return !$force; } /** @@ -208,7 +219,7 @@ class PubSubContext implements \Iterator */ public function next() { - if ($this->isFlagSet(self::STATUS_VALID)) { + if ($this->valid()) { $this->position++; } @@ -272,9 +283,8 @@ class PubSubContext implements \Iterator ); default: - throw new ClientException( - "Received an unknown message type {$response[0]} inside of a pubsub context" - ); + $message = "Received an unknown message type {$response[0]} inside of a pubsub context"; + throw new ClientException($message); } } } diff --git a/lib/Predis/Transaction/MultiExecContext.php b/lib/Predis/Transaction/MultiExecContext.php index 077e468e..f9020074 100644 --- a/lib/Predis/Transaction/MultiExecContext.php +++ b/lib/Predis/Transaction/MultiExecContext.php @@ -16,6 +16,7 @@ use Predis\Helpers; use Predis\ResponseQueued; use Predis\ClientException; use Predis\ServerException; +use Predis\NotSupportedException; use Predis\CommunicationException; use Predis\Protocol\ProtocolException; @@ -112,17 +113,12 @@ class MultiExecContext private function checkCapabilities(Client $client) { if (Helpers::isCluster($client->getConnection())) { - throw new ClientException( - 'Cannot initialize a MULTI/EXEC context over a cluster of connections' - ); + throw new NotSupportedException('Cannot initialize a MULTI/EXEC context over a cluster of connections'); } $profile = $client->getProfile(); - if ($profile->supportsCommands(array('multi', 'exec', 'discard')) === false) { - throw new ClientException( - 'The current profile does not support MULTI, EXEC and DISCARD' - ); + throw new NotSupportedException('The current profile does not support MULTI, EXEC and DISCARD'); } $this->canWatch = $profile->supportsCommands(array('watch', 'unwatch')); @@ -134,9 +130,7 @@ class MultiExecContext private function isWatchSupported() { if ($this->canWatch === false) { - throw new ClientException( - 'The current profile does not support WATCH and UNWATCH' - ); + throw new NotSupportedException('The current profile does not support WATCH and UNWATCH'); } } @@ -256,7 +250,7 @@ class MultiExecContext { $this->isWatchSupported(); $this->unflagState(self::STATE_WATCH); - $this->client->unwatch(); + $this->__call('unwatch', array()); return $this; } @@ -297,31 +291,23 @@ class MultiExecContext private function checkBeforeExecution($callable) { if ($this->checkState(self::STATE_INSIDEBLOCK)) { - throw new ClientException( - "Cannot invoke 'execute' or 'exec' inside an active client transaction block" - ); + throw new ClientException("Cannot invoke 'execute' or 'exec' inside an active client transaction block"); } if ($callable) { if (!is_callable($callable)) { - throw new \InvalidArgumentException( - 'Argument passed must be a callable object' - ); + throw new \InvalidArgumentException('Argument passed must be a callable object'); } if (count($this->commands) > 0) { $this->discard(); - throw new ClientException( - 'Cannot execute a transaction block after using fluent interface' - ); + throw new ClientException('Cannot execute a transaction block after using fluent interface'); } } if (isset($this->options['retry']) && !isset($callable)) { $this->discard(); - throw new \InvalidArgumentException( - 'Automatic retries can be used only when a transaction block is provided' - ); + throw new \InvalidArgumentException('Automatic retries can be used only when a transaction block is provided'); } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 3ab76c14..781b6e84 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,12 +1,24 @@ - + - test/ + tests/Predis/ + + + ext-phpiredis + ext-curl + realm-network-webdis + + + + + + + lib/Predis/ @@ -14,9 +26,14 @@ - - - - + + + + + + + + + diff --git a/test/ClientFeaturesTest.php b/test/ClientFeaturesTest.php deleted file mode 100644 index c275fb97..00000000 --- a/test/ClientFeaturesTest.php +++ /dev/null @@ -1,830 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -class ClientFeaturesTestSuite extends PHPUnit_Framework_TestCase -{ - public $redis; - - protected function setUp() - { - $this->redis = RC::getConnection(); - $this->redis->flushdb(); - } - - protected function tearDown() - { - } - - protected function onNotSuccessfulTest(Exception $exception) - { - // drops and reconnect to a redis server on uncaught exceptions - RC::resetConnection(); - - parent::onNotSuccessfulTest($exception); - } - - /* Predis\ConnectionParameters */ - - function testConnectionParametersDefaultValues() - { - $params = new Predis\ConnectionParameters(); - - $this->assertEquals('127.0.0.1', $params->host); - $this->assertEquals(6379, $params->port); - $this->assertEquals(5, $params->connection_timeout); - $this->assertNull($params->read_write_timeout); - $this->assertNull($params->database); - $this->assertNull($params->password); - $this->assertNull($params->alias); - } - - function testConnectionParametersSetupValuesArray() - { - $paramsArray = RC::getConnectionParametersArgumentsArray(); - $params = new Predis\ConnectionParameters($paramsArray); - - $this->assertEquals($paramsArray['host'], $params->host); - $this->assertEquals($paramsArray['port'], $params->port); - $this->assertEquals($paramsArray['connection_timeout'], $params->connection_timeout); - $this->assertEquals($paramsArray['read_write_timeout'], $params->read_write_timeout); - $this->assertEquals($paramsArray['database'], $params->database); - $this->assertEquals($paramsArray['password'], $params->password); - $this->assertEquals($paramsArray['alias'], $params->alias); - } - - function testConnectionParametersSetupValuesString() - { - $paramsArray = RC::getConnectionParametersArgumentsArray(); - $paramsString = RC::getConnectionParametersArgumentsString($paramsArray); - $params = new Predis\ConnectionParameters($paramsArray); - - $this->assertEquals($paramsArray['host'], $params->host); - $this->assertEquals($paramsArray['port'], $params->port); - $this->assertEquals($paramsArray['connection_timeout'], $params->connection_timeout); - $this->assertEquals($paramsArray['read_write_timeout'], $params->read_write_timeout); - $this->assertEquals($paramsArray['database'], $params->database); - $this->assertEquals($paramsArray['password'], $params->password); - $this->assertEquals($paramsArray['alias'], $params->alias); - } - - /* Predis\Commands\Command and derivates */ - - function testCommand_TestArguments() - { - $cmdArgs = array('key1', 'key2', 'key3'); - - $cmd = new Predis\Commands\StringGetMultiple(); - $cmd->setArguments($cmdArgs); - $this->assertEquals($cmdArgs[0], $cmd->getArgument(0)); - $this->assertEquals($cmdArgs[1], $cmd->getArgument(1)); - $this->assertEquals($cmdArgs[2], $cmd->getArgument(2)); - - $cmd = new Predis\Commands\ConnectionPing(); - $this->assertNull($cmd->getArgument(0)); - } - - function testCommand_ParseResponse() - { - // default parser - $cmd = new Predis\Commands\StringGet(); - $this->assertEquals('test', $cmd->parseResponse('test')); - - // overridden parser (boolean) - $cmd = new Predis\Commands\KeyExists(); - $this->assertTrue($cmd->parseResponse('1')); - $this->assertFalse($cmd->parseResponse('0')); - - // overridden parser (boolean) - $cmd = new Predis\Commands\ConnectionPing(); - $this->assertTrue($cmd->parseResponse('PONG')); - - // overridden parser (complex) - // TODO: emulate a respons to INFO - } - - - /* Predis\Profiles\ServerProfile and derivates */ - - function testServerProfile_GetSpecificVersions() - { - $this->assertInstanceOf('\Predis\Profiles\ServerVersion12', Predis\Profiles\ServerProfile::get('1.2')); - $this->assertInstanceOf('\Predis\Profiles\ServerVersion20', Predis\Profiles\ServerProfile::get('2.0')); - $this->assertInstanceOf('\Predis\Profiles\ServerVersion22', Predis\Profiles\ServerProfile::get('2.2')); - $this->assertInstanceOf('\Predis\Profiles\ServerVersionNext', Predis\Profiles\ServerProfile::get('dev')); - $this->assertInstanceOf('\Predis\Profiles\ServerProfile', Predis\Profiles\ServerProfile::get('default')); - $this->assertEquals(Predis\Profiles\ServerProfile::get('default'), Predis\Profiles\ServerProfile::getDefault()); - } - - function testServerProfile_SupportedCommands() - { - $profile_12 = Predis\Profiles\ServerProfile::get('1.2'); - $profile_20 = Predis\Profiles\ServerProfile::get('2.0'); - - $this->assertTrue($profile_12->supportsCommand('info')); - $this->assertTrue($profile_20->supportsCommand('info')); - - $this->assertFalse($profile_12->supportsCommand('multi')); - $this->assertTrue($profile_20->supportsCommand('multi')); - - $this->assertFalse($profile_12->supportsCommand('watch')); - $this->assertFalse($profile_20->supportsCommand('watch')); - } - - function testServerProfile_CommandsCreation() - { - $profile = Predis\Profiles\ServerProfile::get('2.0'); - - $cmdNoArgs = $profile->createCommand('info'); - $this->assertInstanceOf('\Predis\Commands\ServerInfo', $cmdNoArgs); - $this->assertNull($cmdNoArgs->getArgument()); - - $args = array('key1', 'key2'); - $cmdWithArgs = $profile->createCommand('mget', $args); - - $this->assertInstanceOf('\Predis\Commands\StringGetMultiple', $cmdWithArgs); - $this->assertEquals($args[0], $cmdWithArgs->getArgument()); // TODO: why? - $this->assertEquals($args[0], $cmdWithArgs->getArgument(0)); - $this->assertEquals($args[1], $cmdWithArgs->getArgument(1)); - - $bogusCommand = 'not_existing_command'; - $expectedMessage = "'$bogusCommand' is not a registered Redis command"; - RC::testForClientException($this, $expectedMessage, function() - use($profile, $bogusCommand) { - - $profile->createCommand($bogusCommand); - }); - } - - function testServerProfile_CommandsRegistration() - { - $profile = Predis\Profiles\ServerProfile::get('1.2'); - $cmdId = 'multi'; - $cmdClass = '\Predis\Commands\TransactionMulti'; - - $this->assertFalse($profile->supportsCommand($cmdId)); - $profile->defineCommand($cmdId, new $cmdClass()); - $this->assertTrue($profile->supportsCommand($cmdId)); - $this->assertInstanceOf($cmdClass, $profile->createCommand($cmdId)); - } - - function testServerProfile_CaseInsensitiveCommandsNames() { - $profile = $this->redis->getProfile(); - - $uppercase = $profile->supportsCommand('INFO'); - $lowercase = $profile->supportsCommand('info'); - $this->assertEquals($uppercase, $lowercase); - - $uppercase = $profile->createCommand('INFO'); - $lowercase = $profile->createCommand('info'); - $this->assertEquals($uppercase, $lowercase); - } - - /* Predis\ResponseQueued */ - - function testResponseQueued() - { - $response = new Predis\ResponseQueued(); - $this->assertInstanceOf('\Predis\IReplyObject', $response); - $this->assertEquals(\Predis\Protocol\Text\TextProtocol::QUEUED, (string)$response); - } - - /* Predis\ResponseError */ - - function testResponseError() - { - $errorMessage = 'ERROR MESSAGE'; - $response = new Predis\ResponseError($errorMessage); - - $this->assertInstanceOf('\Predis\IReplyObject', $response); - $this->assertInstanceOf('\Predis\IRedisServerError', $response); - - $this->assertEquals($errorMessage, $response->getMessage()); - $this->assertEquals($errorMessage, (string)$response); - } - - /* Predis\Network\StreamConnection */ - - function testStreamConnection_StringCastReturnsIPAndPort() - { - $connection = new Predis\Network\StreamConnection(RC::getConnectionParameters()); - $this->assertEquals(RC::SERVER_HOST . ':' . RC::SERVER_PORT, (string) $connection); - } - - function testStreamConnection_ConnectDisconnect() - { - $connection = new Predis\Network\StreamConnection(RC::getConnectionParameters()); - - $this->assertFalse($connection->isConnected()); - $connection->connect(); - $this->assertTrue($connection->isConnected()); - $connection->disconnect(); - $this->assertFalse($connection->isConnected()); - } - - function testStreamConnection_WriteAndReadCommand() - { - $cmd = Predis\Profiles\ServerProfile::getDefault()->createCommand('ping'); - $connection = new Predis\Network\StreamConnection(RC::getConnectionParameters()); - $connection->connect(); - - $connection->writeCommand($cmd); - $this->assertTrue($connection->readResponse($cmd)); - } - - function testStreamConnection_WriteCommandAndCloseConnection() - { - $cmd = Predis\Profiles\ServerProfile::getDefault()->createCommand('quit'); - $connection = new Predis\Network\StreamConnection(new Predis\ConnectionParameters( - RC::getConnectionArguments() + array('read_write_timeout' => 0.5) - )); - - $connection->connect(); - - $this->assertTrue($connection->isConnected()); - - $connection->writeCommand($cmd); - $connection->disconnect(); - - $exceptionMessage = 'Error while reading line from the server'; - RC::testForCommunicationException($this, $exceptionMessage, function() use($connection, $cmd) { - $connection->readResponse($cmd); - }); - } - - function testStreamConnection_GetSocketOpensConnection() - { - $connection = new Predis\Network\StreamConnection(RC::getConnectionParameters()); - - $this->assertFalse($connection->isConnected()); - $this->assertInternalType('resource', $connection->getResource()); - $this->assertTrue($connection->isConnected()); - } - - function testStreamConnection_LazyConnect() - { - $cmd = Predis\Profiles\ServerProfile::getDefault()->createCommand('ping'); - $connection = new Predis\Network\StreamConnection(RC::getConnectionParameters()); - - $this->assertFalse($connection->isConnected()); - - $connection->writeCommand($cmd); - - $this->assertTrue($connection->isConnected()); - $this->assertTrue($connection->readResponse($cmd)); - } - - function testStreamConnection_Alias() - { - $connection1 = new Predis\Network\StreamConnection(RC::getConnectionParameters()); - $this->assertNull($connection1->getParameters()->alias); - - $args = array_merge(RC::getConnectionArguments(), array('alias' => 'servername')); - $connection2 = new Predis\Network\StreamConnection(new Predis\ConnectionParameters($args)); - - $this->assertEquals('servername', $connection2->getParameters()->alias); - } - - function testStreamConnection_ConnectionTimeout() - { - $timeout = 3; - $args = array('host' => '1.0.0.1', 'connection_timeout' => $timeout); - $connection = new Predis\Network\StreamConnection(new Predis\ConnectionParameters($args)); - - $start = time(); - RC::testForCommunicationException($this, null, function() use($connection) { - $connection->connect(); - }); - - $this->assertEquals((float)(time() - $start), $timeout, '', 1); - } - - function testStreamConnection_ReadTimeout() - { - $timeout = 1; - $args = array_merge(RC::getConnectionArguments(), array('read_write_timeout' => $timeout)); - $cmdFake = Predis\Profiles\ServerProfile::getDefault()->createCommand('ping'); - $connection = new Predis\Network\StreamConnection(new Predis\ConnectionParameters($args)); - - $expectedMessage = 'Error while reading line from the server'; - $start = time(); - RC::testForCommunicationException($this, $expectedMessage, function() use($connection, $cmdFake) { - $connection->readResponse($cmdFake); - }); - $this->assertEquals((float)(time() - $start), $timeout, '', 1); - } - - /* Predis\Protocol\TextResponseReader */ - - function testResponseReader_OptionIterableMultiBulkReplies() - { - $protocol = new Predis\Protocol\Text\ComposableTextProtocol(); - $reader = $protocol->getReader(); - $connection = new Predis\Network\ComposableStreamConnection(RC::getConnectionParameters(), $protocol); - - $reader->setHandler( - Predis\Protocol\Text\TextProtocol::PREFIX_MULTI_BULK, - new Predis\Protocol\Text\ResponseMultiBulkHandler() - ); - $connection->writeBytes("KEYS *\r\n"); - $this->assertInternalType('array', $reader->read($connection)); - - $reader->setHandler( - Predis\Protocol\Text\TextProtocol::PREFIX_MULTI_BULK, - new Predis\Protocol\Text\ResponseMultiBulkStreamHandler() - ); - $connection->writeBytes("KEYS *\r\n"); - $this->assertInstanceOf('\Iterator', $reader->read($connection)); - } - - function testResponseReader_OptionExceptionOnError() - { - $protocol = new Predis\Protocol\Text\ComposableTextProtocol(); - $reader = $protocol->getReader(); - $connection = new Predis\Network\ComposableStreamConnection(RC::getConnectionParameters(), $protocol); - - $rawCmdUnexpected = "*3\r\n$5\r\nLPUSH\r\n$3\r\nkey\r\n$5\r\nvalue\r\n"; - $connection->writeBytes("*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n"); - $reader->read($connection); - - $reader->setHandler( - Predis\Protocol\Text\TextProtocol::PREFIX_ERROR, - new Predis\Protocol\Text\ResponseErrorSilentHandler() - ); - $connection->writeBytes($rawCmdUnexpected); - $errorReply = $reader->read($connection); - $this->assertInstanceOf('\Predis\ResponseError', $errorReply); - $this->assertEquals(RC::EXCEPTION_WRONG_TYPE, $errorReply->getMessage()); - - $reader->setHandler( - Predis\Protocol\Text\TextProtocol::PREFIX_ERROR, - new Predis\Protocol\Text\ResponseErrorHandler() - ); - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function() - use ($connection, $rawCmdUnexpected) { - - $connection->writeBytes($rawCmdUnexpected); - $connection->getProtocol()->read($connection); - }); - } - - function testResponseReader_EmptyBulkResponse() - { - $protocol = new Predis\Protocol\Text\ComposableTextProtocol(); - $connection = new Predis\Network\ComposableStreamConnection(RC::getConnectionParameters(), $protocol); - $client = new Predis\Client($connection); - - $this->assertTrue($client->set('foo', '')); - $this->assertEquals('', $client->get('foo')); - $this->assertEquals('', $client->get('foo')); - } - - /* Client initialization */ - - function testClientInitialization_SingleConnectionParameters() - { - $params1 = array_merge(RC::getConnectionArguments(), array( - 'connection_timeout' => 10, - 'read_write_timeout' => 30, - 'alias' => 'connection_alias', - )); - $params2 = RC::getConnectionParametersArgumentsString($params1); - $params3 = new Predis\ConnectionParameters($params1); - $params4 = new Predis\Network\StreamConnection($params3); - - foreach (array($params1, $params2, $params3, $params4) as $params) { - $client = new Predis\Client($params); - $parameters = $client->getConnection()->getParameters(); - $this->assertEquals($params1['host'], $parameters->host); - $this->assertEquals($params1['port'], $parameters->port); - $this->assertEquals($params1['connection_timeout'], $parameters->connection_timeout); - $this->assertEquals($params1['read_write_timeout'], $parameters->read_write_timeout); - $this->assertEquals($params1['alias'], $parameters->alias); - $this->assertNull($parameters->password); - } - } - - function testClientInitialization_ClusterConnectionParameters() - { - $params1 = array_merge(RC::getConnectionArguments(), array( - 'connection_timeout' => 10, - 'read_write_timeout' => 30, - )); - $params2 = RC::getConnectionParametersArgumentsString($params1); - $params3 = new Predis\ConnectionParameters($params1); - $params4 = new Predis\Network\StreamConnection($params3); - - $client1 = new Predis\Client(array($params1, $params2, $params3, $params4)); - - foreach ($client1->getConnection() as $connection) { - $parameters = $connection->getParameters(); - $this->assertEquals($params1['host'], $parameters->host); - $this->assertEquals($params1['port'], $parameters->port); - $this->assertEquals($params1['connection_timeout'], $parameters->connection_timeout); - $this->assertEquals($params1['read_write_timeout'], $parameters->read_write_timeout); - $this->assertNull($parameters->password); - } - - $connectionCluster = $client1->getConnection(); - $client2 = new Predis\Client($connectionCluster); - $this->assertSame($connectionCluster, $client2->getConnection()); - } - - /* Client + PipelineContext */ - - function testPipelineContext_Simple() - { - $client = RC::getConnection(); - $client->flushdb(); - - $pipe = $client->pipeline(); - $pipelineClass = '\Predis\Pipeline\PipelineContext'; - - $this->assertInstanceOf($pipelineClass, $pipe); - $this->assertInstanceOf($pipelineClass, $pipe->set('foo', 'bar')); - $this->assertInstanceOf($pipelineClass, $pipe->set('hoge', 'piyo')); - $this->assertInstanceOf($pipelineClass, $pipe->mset(array( - 'foofoo' => 'barbar', 'hogehoge' => 'piyopiyo' - ))); - $this->assertInstanceOf($pipelineClass, $pipe->mget(array( - 'foo', 'hoge', 'foofoo', 'hogehoge' - ))); - - $replies = $pipe->execute(); - $this->assertInternalType('array', $replies); - $this->assertEquals(4, count($replies)); - $this->assertEquals(4, count($replies[3])); - $this->assertEquals('barbar', $replies[3][2]); - } - - function testPipelineContext_FluentInterface() - { - $client = RC::getConnection(); - $client->flushdb(); - - $replies = $client->pipeline()->ping()->set('foo', 'bar')->get('foo')->execute(); - $this->assertInternalType('array', $replies); - $this->assertEquals('bar', $replies[2]); - } - - function testPipelineContext_CallableAnonymousBlock() - { - $client = RC::getConnection(); - $client->flushdb(); - - $replies = $client->pipeline(function($pipe) { - $pipe->ping(); - $pipe->set('foo', 'bar'); - $pipe->get('foo'); - }); - - $this->assertInternalType('array', $replies); - $this->assertEquals('bar', $replies[2]); - } - - function testPipelineContext_ClientExceptionInCallableBlock() - { - $client = RC::getConnection(); - $client->flushdb(); - - RC::testForClientException($this, 'TEST', function() use($client) { - $client->pipeline(function($pipe) { - $pipe->ping(); - $pipe->set('foo', 'bar'); - throw new Predis\ClientException("TEST"); - }); - }); - - $this->assertFalse($client->exists('foo')); - } - - function testPipelineContext_ServerExceptionInCallableBlock() - { - $client = RC::createConnection(array('throw_errors' => false)); - $client->flushdb(); - - $replies = $client->pipeline(function($pipe) { - $pipe->set('foo', 'bar'); - $pipe->lpush('foo', 'piyo'); // LIST operation on STRING type returns an ERROR - $pipe->set('hoge', 'piyo'); - }); - - $this->assertInternalType('array', $replies); - $this->assertInstanceOf('\Predis\ResponseError', $replies[1]); - $this->assertTrue($client->exists('foo')); - $this->assertTrue($client->exists('hoge')); - } - - function testPipelineContext_Flush() - { - $client = RC::getConnection(); - $client->flushdb(); - - $pipe = $client->pipeline(); - $pipe->set('foo', 'bar')->set('hoge', 'piyo'); - $pipe->flushPipeline(); - $pipe->ping()->mget(array('foo', 'hoge')); - $replies = $pipe->execute(); - - $this->assertInternalType('array', $replies); - $this->assertEquals(4, count($replies)); - $this->assertEquals('bar', $replies[3][0]); - $this->assertEquals('piyo', $replies[3][1]); - } - - /* Predis\Client + Predis\MultiExecContext */ - - function testMultiExecContext_Simple() - { - $client = RC::getConnection(); - $client->flushdb(); - - $multi = $client->multiExec(); - $transactionClass = '\Predis\Transaction\MultiExecContext'; - - $this->assertInstanceOf($transactionClass, $multi); - $this->assertInstanceOf($transactionClass, $multi->set('foo', 'bar')); - $this->assertInstanceOf($transactionClass, $multi->set('hoge', 'piyo')); - $this->assertInstanceOf($transactionClass, $multi->mset(array( - 'foofoo' => 'barbar', 'hogehoge' => 'piyopiyo' - ))); - $this->assertInstanceOf($transactionClass, $multi->mget(array( - 'foo', 'hoge', 'foofoo', 'hogehoge' - ))); - - $replies = $multi->execute(); - $this->assertInternalType('array', $replies); - $this->assertEquals(4, count($replies)); - $this->assertEquals(4, count($replies[3])); - $this->assertEquals('barbar', $replies[3][2]); - } - - function testMultiExecContext_FluentInterface() - { - $client = RC::getConnection(); - $client->flushdb(); - - $replies = $client->multiExec()->ping()->set('foo', 'bar')->get('foo')->execute(); - $this->assertInternalType('array', $replies); - $this->assertEquals('bar', $replies[2]); - } - - function testMultiExecContext_CallableAnonymousBlock() - { - $client = RC::getConnection(); - $client->flushdb(); - - $replies = $client->multiExec(function($multi) { - $multi->ping(); - $multi->set('foo', 'bar'); - $multi->get('foo'); - }); - - $this->assertInternalType('array', $replies); - $this->assertEquals('bar', $replies[2]); - } - - /** - * @expectedException Predis\ClientException - */ - function testMultiExecContext_CannotMixFluentInterfaceAndAnonymousBlock() - { - $emptyBlock = function($tx) { }; - $tx = RC::getConnection()->multiExec()->get('foo')->execute($emptyBlock); - } - - function testMultiExecContext_EmptyCallableBlock() - { - $client = RC::getConnection(); - $client->flushdb(); - - $replies = $client->multiExec(function($multi) { }); - $this->assertEquals(0, count($replies)); - - $options = array('cas' => true); - $replies = $client->multiExec($options, function($multi) { }); - $this->assertEquals(0, count($replies)); - - $options = array('cas' => true); - $replies = $client->multiExec($options, function($multi) { - $multi->multi(); - }); - $this->assertEquals(0, count($replies)); - } - - function testMultiExecContext_ClientExceptionInCallableBlock() - { - $client = RC::getConnection(); - $client->flushdb(); - - RC::testForClientException($this, 'TEST', function() use($client) { - $client->multiExec(function($multi) { - $multi->ping(); - $multi->set('foo', 'bar'); - throw new Predis\ClientException("TEST"); - }); - }); - - $this->assertFalse($client->exists('foo')); - } - - function testMultiExecContext_ServerExceptionInCallableBlock() - { - $client = RC::createConnection(array('throw_errors' => false)); - $client->flushdb(); - - $replies = $client->multiExec(function($multi) { - $multi->set('foo', 'bar'); - $multi->lpush('foo', 'piyo'); // LIST operation on STRING type returns an ERROR - $multi->set('hoge', 'piyo'); - }); - - $this->assertInternalType('array', $replies); - $this->assertInstanceOf('\Predis\ResponseError', $replies[1]); - $this->assertTrue($client->exists('foo')); - $this->assertTrue($client->exists('hoge')); - } - - function testMultiExecContext_Discard() - { - $client = RC::getConnection(); - $client->flushdb(); - - $replies = $client->multiExec(function($multi) { - $multi->set('foo', 'bar'); - $multi->discard(); - $multi->set('hoge', 'piyo'); - }); - - $this->assertEquals(1, count($replies)); - $this->assertFalse($client->exists('foo')); - $this->assertTrue($client->exists('hoge')); - } - - function testMultiExecContext_DiscardEmpty() - { - $client = RC::getConnection(); - $client->flushdb(); - - $replies = $client->multiExec(function($multi) { - $multi->discard(); - }); - - $this->assertEquals(0, count($replies)); - } - - function testMultiExecContext_Watch() - { - $client1 = RC::getConnection(); - $client2 = RC::getConnection(true); - $client1->flushdb(); - - RC::testForAbortedMultiExecException($this, function() - use($client1, $client2) { - - $client1->multiExec(array('watch' => 'sentinel'), function($multi) - use ($client2) { - - $multi->set('sentinel', 'client1'); - $multi->get('sentinel'); - $client2->set('sentinel', 'client2'); - }); - }); - - $this->assertEquals('client2', $client1->get('sentinel')); - } - - function testMultiExecContext_CheckAndSet() - { - $client = RC::getConnection(); - $client->flushdb(); - $client->set('foo', 'bar'); - - $options = array('watch' => 'foo', 'cas' => true); - $replies = $client->multiExec($options, function($tx) { - $tx->watch('foobar'); - $foo = $tx->get('foo'); - $tx->multi(); - $tx->set('foobar', $foo); - $tx->mget('foo', 'foobar'); - }); - $this->assertInternalType('array', $replies); - $this->assertEquals(array(true, array('bar', 'bar')), $replies); - - $tx = $client->multiExec($options); - $tx->watch('foobar'); - $foo = $tx->get('foo'); - $replies = $tx->multi() - ->set('foobar', $foo) - ->mget('foo', 'foobar') - ->execute(); - $this->assertInternalType('array', $replies); - $this->assertEquals(array(true, array('bar', 'bar')), $replies); - } - - function testMultiExecContext_RetryOnServerAbort() - { - $client1 = RC::getConnection(); - $client2 = RC::getConnection(true); - $client1->flushdb(); - - $retry = 3; - $attempts = 0; - RC::testForAbortedMultiExecException($this, function() - use($client1, $client2, $retry, &$attempts) { - - $options = array('watch' => 'sentinel', 'retry' => $retry); - $client1->multiExec($options, function($tx) - use ($client2, &$attempts) { - - $attempts++; - $tx->set('sentinel', 'client1'); - $tx->get('sentinel'); - $client2->set('sentinel', 'client2'); - }); - }); - $this->assertEquals('client2', $client1->get('sentinel')); - $this->assertEquals($retry + 1, $attempts); - - $retry = 3; - $attempts = 0; - RC::testForAbortedMultiExecException($this, function() - use($client1, $client2, $retry, &$attempts) { - - $options = array( - 'watch' => 'sentinel', - 'cas' => true, - 'retry' => $retry - ); - $client1->multiExec($options, function($tx) - use ($client2, &$attempts) { - - $attempts++; - $tx->incr('attempts'); - $tx->multi(); - $tx->set('sentinel', 'client1'); - $tx->get('sentinel'); - $client2->set('sentinel', 'client2'); - }); - }); - $this->assertEquals('client2', $client1->get('sentinel')); - $this->assertEquals($retry + 1, $attempts); - $this->assertEquals($attempts, $client1->get('attempts')); - } - - /** - * @expectedException InvalidArgumentException - */ - function testMultiExecContext_RetryNotAvailableWithoutBlock() - { - $options = array('watch' => 'foo', 'retry' => 1); - $tx = RC::getConnection()->multiExec($options); - $tx->multi()->get('foo')->exec(); - } - - function testMultiExecContext_CheckAndSet_Discard() - { - $client = RC::getConnection(); - $client->flushdb(); - - $client->set('foo', 'bar'); - $options = array('watch' => 'foo', 'cas' => true); - $replies = $client->multiExec($options, function($tx) { - $tx->watch('foobar'); - $foo = $tx->get('foo'); - $tx->multi(); - $tx->set('foobar', $foo); - $tx->discard(); - $tx->mget('foo', 'foobar'); - }); - $this->assertInternalType('array', $replies); - $this->assertEquals(array(array('bar', null)), $replies); - - $hijack = true; - $client->set('foo', 'bar'); - $client2 = RC::getConnection(true); - $options = array('watch' => 'foo', 'cas' => true, 'retry' => 1); - $replies = $client->multiExec($options, function($tx) - use ($client2, &$hijack) { - - $foo = $tx->get('foo'); - $tx->multi(); - $tx->set('foobar', $foo); - $tx->discard(); - if ($hijack) { - $hijack = false; - $client2->set('foo', 'hijacked!'); - } - $tx->mget('foo', 'foobar'); - }); - $this->assertInternalType('array', $replies); - $this->assertEquals(array(array('hijacked!', null)), $replies); - } -} diff --git a/test/PredisShared.php b/test/PredisShared.php deleted file mode 100644 index 1647a788..00000000 --- a/test/PredisShared.php +++ /dev/null @@ -1,283 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -if (!file_exists(__DIR__.'/enable.tests')) { - exit( - "Please create an empty file named 'enable.tests' inside the test directory ". - "in order to proceed.\n\n*** DO NOT *** run this test suite against servers in ". - "a production environment or containing data you are interested in!\n" - ); -} - -if (!function_exists('array_union')) { - function array_union(Array $a, Array $b) - { - return array_merge($a, array_diff($b, $a)); - } -} - -class RC -{ - const SERVER_VERSION = TEST_SERVER_VERSION; - const SERVER_HOST = TEST_SERVER_HOST; - const SERVER_PORT = TEST_SERVER_PORT; - const DEFAULT_DATABASE = TEST_SERVER_DBNUM; - - const WIPE_OUT = 1; - const EXCEPTION_WRONG_TYPE = 'ERR Operation against a key holding the wrong kind of value'; - const EXCEPTION_NO_SUCH_KEY = 'ERR no such key'; - const EXCEPTION_OUT_OF_RANGE = 'ERR index out of range'; - const EXCEPTION_OFFSET_RANGE = 'ERR offset is out of range'; - const EXCEPTION_INVALID_DB_IDX = 'ERR invalid DB index'; - const EXCEPTION_VALUE_NOT_INT = 'ERR value is not an integer'; - const EXCEPTION_EXEC_NO_MULTI = 'ERR EXEC without MULTI'; - const EXCEPTION_SETEX_TTL = 'ERR invalid expire time in SETEX'; - const EXCEPTION_HASH_VALNOTINT = 'ERR hash value is not an integer'; - const EXCEPTION_BIT_VALUE = 'ERR bit is not an integer or out of range'; - const EXCEPTION_BIT_OFFSET = 'ERR bit offset is not an integer or out of range'; - - private static $connection; - - public static function getConnectionArguments(Array $additional = array()) - { - return array_merge(array('host' => RC::SERVER_HOST, 'port' => RC::SERVER_PORT), $additional); - } - - public static function getConnectionParameters(Array $additional = array()) - { - return new Predis\ConnectionParameters(self::getConnectionArguments($additional)); - } - - public static function createConnection(Array $additional = array()) - { - $serverProfile = Predis\Profiles\ServerProfile::get(self::SERVER_VERSION); - - $connection = new Predis\Client(RC::getConnectionArguments($additional), $serverProfile); - $connection->connect(); - $connection->select(RC::DEFAULT_DATABASE); - - return $connection; - } - - public static function getConnection($new = false) - { - if ($new == true) { - return self::createConnection(); - } - - if (self::$connection === null || !self::$connection->isConnected()) { - self::$connection = self::createConnection(); - } - - return self::$connection; - } - - public static function resetConnection() - { - if (self::$connection !== null && self::$connection->isConnected()) { - self::$connection->disconnect(); - self::$connection = self::createConnection(); - } - } - - public static function helperForBlockingPops($op) - { - // TODO: I admit that this helper is kinda lame and it does not run - // in a separate process to properly test BLPOP/BRPOP - $redisUri = sprintf('tcp://%s:%d/?database=%d', RC::SERVER_HOST, RC::SERVER_PORT, RC::DEFAULT_DATABASE); - $handle = popen('php', 'w'); - - fwrite($handle, "rpush('{$op}1', 'a'); - \$redis->rpush('{$op}2', 'b'); - \$redis->rpush('{$op}3', 'c'); - \$redis->rpush('{$op}1', 'd'); - ?>"); - - pclose($handle); - } - - public static function getArrayOfNumbers() - { - return array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); - } - - public static function getKeyValueArray() - { - return array( - 'foo' => 'bar', - 'hoge' => 'piyo', - 'foofoo' => 'barbar', - ); - } - - public static function getNamespacedKeyValueArray() - { - return array( - 'metavar:foo' => 'bar', - 'metavar:hoge' => 'piyo', - 'metavar:foofoo' => 'barbar', - ); - } - - public static function getZSetArray() - { - return array('a' => -10, 'b' => 0, 'c' => 10, 'd' => 20, 'e' => 20, 'f' => 30); - } - - public static function sameValuesInArrays($arrayA, $arrayB) - { - if (count($arrayA) != count($arrayB)) { - return false; - } - - return count(array_diff($arrayA, $arrayB)) == 0; - } - - public static function testForServerException($testcaseInstance, $expectedMessage, $wrapFunction) - { - $thrownException = null; - - try { - $wrapFunction($testcaseInstance); - } - catch (Predis\ServerException $exception) { - $thrownException = $exception; - } - - $testcaseInstance->assertInstanceOf('Predis\ServerException', $thrownException); - - if (isset($expectedMessage)) { - $testcaseInstance->assertEquals($expectedMessage, $thrownException->getMessage()); - } - } - - public static function testForClientException($testcaseInstance, $expectedMessage, $wrapFunction) - { - $thrownException = null; - - try { - $wrapFunction($testcaseInstance); - } - catch (Predis\ClientException $exception) { - $thrownException = $exception; - } - - $testcaseInstance->assertInstanceOf('Predis\ClientException', $thrownException); - - if (isset($expectedMessage)) { - $testcaseInstance->assertEquals($expectedMessage, $thrownException->getMessage()); - } - } - - public static function testForCommunicationException($testcaseInstance, $expectedMessage, $wrapFunction) - { - $thrownException = null; - - try { - $wrapFunction($testcaseInstance); - } - catch (Predis\CommunicationException $exception) { - $thrownException = $exception; - } - - $testcaseInstance->assertInstanceOf('Predis\CommunicationException', $thrownException); - - if (isset($expectedMessage)) { - $testcaseInstance->assertEquals($expectedMessage, $thrownException->getMessage()); - } - } - - public static function testForAbortedMultiExecException($testcaseInstance, $wrapFunction) - { - $thrownException = null; - - try { - $wrapFunction($testcaseInstance); - } - catch (Predis\Transaction\AbortedMultiExecException $exception) { - $thrownException = $exception; - } - - $testcaseInstance->assertInstanceOf('Predis\Transaction\AbortedMultiExecException', $thrownException); - } - - public static function pushTailAndReturn(Predis\Client $client, $keyName, Array $values, $wipeOut = 0) - { - if ($wipeOut == true) { - $client->del($keyName); - } - - foreach ($values as $value) { - $client->rpush($keyName, $value); - } - - return $values; - } - - public static function setAddAndReturn(Predis\Client $client, $keyName, Array $values, $wipeOut = 0) - { - if ($wipeOut == true) { - $client->del($keyName); - } - - foreach ($values as $value) { - $client->sadd($keyName, $value); - } - - return $values; - } - - public static function zsetAddAndReturn(Predis\Client $client, $keyName, Array $values, $wipeOut = 0) - { - // $values: array(SCORE => VALUE, ...); - if ($wipeOut == true) { - $client->del($keyName); - } - - foreach ($values as $value => $score) { - $client->zadd($keyName, $score, $value); - } - - return $values; - } - - public static function getConnectionParametersArgumentsArray() - { - return array( - 'host' => '10.0.0.1', - 'port' => 6380, - 'connection_timeout' => 10, - 'read_write_timeout' => 30, - 'database' => 5, - 'password' => 'dbpassword', - 'alias' => 'connection_alias', - ); - } - - public static function getConnectionParametersArgumentsString($arguments = null) - { - // TODO: must be improved - $args = $arguments ?: RC::getConnectionParametersArgumentsArray(); - $paramsString = "tcp://{$args['host']}:{$args['port']}/?"; - - unset($args['host']); - unset($args['port']); - - foreach($args as $k => $v) { - $paramsString .= "$k=$v&"; - } - - return $paramsString; - } -} diff --git a/test/RedisCommandsTest.php b/test/RedisCommandsTest.php deleted file mode 100644 index b4c24f94..00000000 --- a/test/RedisCommandsTest.php +++ /dev/null @@ -1,2181 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -class RedisCommandTestSuite extends PHPUnit_Framework_TestCase -{ - public $redis; - - // TODO: instead of an boolean assertion against the return value - // of RC::sameValuesInArrays, we should extend PHPUnit with - // a new assertion, e.g. $this->assertSameValues(); - // TODO: an option to skip certain tests such as testflushdbs - // should be provided. - // TODO: missing test with float values for a few commands - - protected function setUp() - { - $this->redis = RC::getConnection(); - $this->redis->flushdb(); - } - - protected function tearDown() - { - } - - protected function onNotSuccessfulTest(Exception $exception) - { - // drops and reconnect to a redis server on uncaught exceptions - RC::resetConnection(); - - parent::onNotSuccessfulTest($exception); - } - - /* miscellaneous commands */ - - function testPing() - { - $this->assertTrue($this->redis->ping()); - } - - function testEcho() - { - $string = 'This is an echo test!'; - $this->assertEquals($string, $this->redis->echo($string)); - } - - function testQuit() - { - $this->redis->quit(); - $this->assertFalse($this->redis->isConnected()); - } - - function testMultiExec() - { - // NOTE: due to a limitation in the current implementation of Predis\Client, - // the replies returned by Predis\Commands\Exec are not parsed by their - // respective Predis\Commands\Command::parseResponse methods. If you - // need that kind of behaviour, you should use an instance of - // Predis\MultiExecBlock. - - $this->assertTrue($this->redis->multi()); - $this->assertInstanceOf('Predis\ResponseQueued', $this->redis->ping()); - $this->assertInstanceOf('Predis\ResponseQueued', $this->redis->echo('hello')); - $this->assertInstanceOf('Predis\ResponseQueued', $this->redis->echo('redis')); - $this->assertEquals(array('PONG', 'hello', 'redis'), $this->redis->exec()); - - $this->assertTrue($this->redis->multi()); - $this->assertEquals(array(), $this->redis->exec()); - - // should throw an exception when trying to EXEC without having previously issued MULTI - RC::testForServerException($this, RC::EXCEPTION_EXEC_NO_MULTI, function($test) { - $test->redis->exec(); - }); - } - - function testDiscard() - { - $this->assertTrue($this->redis->multi()); - $this->assertInstanceOf('Predis\ResponseQueued', $this->redis->set('foo', 'bar')); - $this->assertInstanceOf('Predis\ResponseQueued', $this->redis->set('hoge', 'piyo')); - $this->assertEquals(true, $this->redis->discard()); - - // should throw an exception when trying to EXEC after a DISCARD - RC::testForServerException($this, RC::EXCEPTION_EXEC_NO_MULTI, function($test) { - $test->redis->exec(); - }); - - $this->assertFalse($this->redis->exists('foo')); - $this->assertFalse($this->redis->exists('hoge')); - } - - /* commands operating on string values */ - - function testSet() - { - $this->assertTrue($this->redis->set('foo', 'bar')); - $this->assertEquals('bar', $this->redis->get('foo')); - } - - function testGet() - { - $this->redis->set('foo', 'bar'); - $this->assertEquals('bar', $this->redis->get('foo')); - - $this->assertTrue($this->redis->set('foo', '')); - $this->assertEquals('', $this->redis->get('foo')); - - $this->assertNull($this->redis->get('fooDoesNotExist')); - - // should throw an exception when trying to do a GET on non-string types - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->rpush('metavars', 'foo'); - $test->redis->get('metavars'); - }); - } - - function testExists() - { - $this->redis->set('foo', 'bar'); - - $this->assertTrue($this->redis->exists('foo')); - $this->assertFalse($this->redis->exists('key_does_not_exist')); - } - - function testSetPreserve() - { - $multi = RC::getKeyValueArray(); - - $this->assertTrue($this->redis->setnx('foo', 'bar')); - $this->assertFalse($this->redis->setnx('foo', 'rab')); - $this->assertEquals('bar', $this->redis->get('foo')); - } - - function testMultipleSetAndGet() - { - $multi = RC::getKeyValueArray(); - - // key=>value pairs via array instance - $this->assertTrue($this->redis->mset($multi)); - $multiRet = $this->redis->mget(array_keys($multi)); - $this->assertEquals($multi, array_combine(array_keys($multi), array_values($multiRet))); - - // key=>value pairs via function arguments - $this->assertTrue($this->redis->mset('a', 1, 'b', 2, 'c', 3)); - $this->assertEquals(array(1, 2, 3), $this->redis->mget('a', 'b', 'c')); - } - - function testSetMultiplePreserve() - { - $multi = RC::getKeyValueArray(); - $newpair = array('hogehoge' => 'piyopiyo'); - $hijacked = array('foo' => 'baz', 'hoge' => 'fuga'); - - // successful set - $expectedResult = array_merge($multi, $newpair); - $this->redis->mset($multi); - $this->assertTrue($this->redis->msetnx($newpair)); - $this->assertEquals( - array_values($expectedResult), - $this->redis->mget(array_keys($expectedResult)) - ); - - $this->redis->flushdb(); - - // unsuccessful set - $expectedResult = array_merge($multi, array('hogehoge' => null)); - $this->redis->mset($multi); - $this->assertFalse($this->redis->msetnx(array_merge($newpair, $hijacked))); - $this->assertEquals( - array_values($expectedResult), - $this->redis->mget(array_keys($expectedResult)) - ); - } - - function testGetSet() - { - $this->assertNull($this->redis->getset('foo', 'bar')); - $this->assertEquals('bar', $this->redis->getset('foo', 'barbar')); - $this->assertEquals('barbar', $this->redis->getset('foo', 'baz')); - } - - function testIncrementAndIncrementBy() - { - // test subsequent increment commands - $this->assertEquals(1, $this->redis->incr('foo')); - $this->assertEquals(2, $this->redis->incr('foo')); - - // test subsequent incrementBy commands - $this->assertEquals(22, $this->redis->incrby('foo', 20)); - $this->assertEquals(10, $this->redis->incrby('foo', -12)); - $this->assertEquals(-100, $this->redis->incrby('foo', -110)); - } - - function testDecrementAndDecrementBy() - { - // test subsequent decrement commands - $this->assertEquals(-1, $this->redis->decr('foo')); - $this->assertEquals(-2, $this->redis->decr('foo')); - - // test subsequent decrementBy commands - $this->assertEquals(-22, $this->redis->decrby('foo', 20)); - $this->assertEquals(-10, $this->redis->decrby('foo', -12)); - $this->assertEquals(100, $this->redis->decrby('foo', -110)); - } - - function testDelete() - { - $this->redis->set('foo', 'bar'); - $this->assertEquals(1, $this->redis->del('foo')); - $this->assertFalse($this->redis->exists('foo')); - $this->assertEquals(0, $this->redis->del('foo')); - } - - function testType() - { - $this->assertEquals('none', $this->redis->type('fooDoesNotExist')); - - $this->redis->set('fooString', 'bar'); - $this->assertEquals('string', $this->redis->type('fooString')); - - $this->redis->rpush('fooList', 'bar'); - $this->assertEquals('list', $this->redis->type('fooList')); - - $this->redis->sadd('fooSet', 'bar'); - $this->assertEquals('set', $this->redis->type('fooSet')); - - $this->redis->zadd('fooZSet', 0, 'bar'); - $this->assertEquals('zset', $this->redis->type('fooZSet')); - - $this->redis->hset('fooHash', 'value', 'bar'); - $this->assertEquals('hash', $this->redis->type('fooHash')); - } - - function testAppend() - { - $this->redis->set('foo', 'bar'); - $this->assertEquals(5, $this->redis->append('foo', '__')); - $this->assertEquals(8, $this->redis->append('foo', 'bar')); - $this->assertEquals('bar__bar', $this->redis->get('foo')); - - $this->assertEquals(4, $this->redis->append('hoge', 'piyo')); - $this->assertEquals('piyo', $this->redis->get('hoge')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->rpush('metavars', 'foo'); - $test->redis->append('metavars', 'bar'); - }); - } - - function testSetRange() - { - $this->assertEquals(6, $this->redis->setrange('var', 0, 'foobar')); - $this->assertEquals('foobar', $this->redis->get('var')); - $this->assertEquals(6, $this->redis->setrange('var', 3, 'foo')); - $this->assertEquals('foofoo', $this->redis->get('var')); - $this->assertEquals(16, $this->redis->setrange('var', 10, 'barbar')); - $this->assertEquals("foofoo\x00\x00\x00\x00barbar", $this->redis->get('var')); - - $this->assertEquals(4, $this->redis->setrange('binary', 0, pack('l', -2147483648))); - list($unpacked) = array_values(unpack('l', $this->redis->get('binary'))); - $this->assertEquals(-2147483648, $unpacked); - - RC::testForServerException($this, RC::EXCEPTION_OFFSET_RANGE, function($test) { - $test->redis->setrange('var', -1, 'bogus'); - }); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->rpush('metavars', 'foo'); - $test->redis->setrange('metavars', 0, 'hoge'); - }); - } - - function testSubstr() - { - $this->redis->set('var', 'foobar'); - $this->assertEquals('foo', $this->redis->substr('var', 0, 2)); - $this->assertEquals('bar', $this->redis->substr('var', 3, 5)); - $this->assertEquals('bar', $this->redis->substr('var', -3, -1)); - - $this->assertEquals('', $this->redis->substr('var', 5, 0)); - - $this->redis->set('numeric', 123456789); - $this->assertEquals(12345, $this->redis->substr('numeric', 0, 4)); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->rpush('metavars', 'foo'); - $test->redis->substr('metavars', 0, 3); - }); - } - - function testStrlen() - { - $this->redis->set('var', 'foobar'); - $this->assertEquals(6, $this->redis->strlen('var')); - $this->assertEquals(9, $this->redis->append('var', '___')); - $this->assertEquals(9, $this->redis->strlen('var')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->rpush('metavars', 'foo'); - $test->redis->strlen('metavars'); - }); - } - - function testSetBit() - { - $this->assertEquals(0, $this->redis->setbit('binary', 31, 1)); - $this->assertEquals(0, $this->redis->setbit('binary', 0, 1)); - $this->assertEquals(4, $this->redis->strlen('binary')); - $this->assertEquals("\x80\x00\00\x01", $this->redis->get('binary')); - - $this->assertEquals(1, $this->redis->setbit('binary', 0, 0)); - $this->assertEquals(0, $this->redis->setbit('binary', 0, 0)); - $this->assertEquals("\x00\x00\00\x01", $this->redis->get('binary')); - - RC::testForServerException($this, RC::EXCEPTION_BIT_OFFSET, function($test) { - $test->redis->setbit('binary', -1, 1); - }); - - RC::testForServerException($this, RC::EXCEPTION_BIT_OFFSET, function($test) { - $test->redis->setbit('binary', 'invalid', 1); - }); - - RC::testForServerException($this, RC::EXCEPTION_BIT_VALUE, function($test) { - $test->redis->setbit('binary', 15, 255); - }); - - RC::testForServerException($this, RC::EXCEPTION_BIT_VALUE, function($test) { - $test->redis->setbit('binary', 15, 'invalid'); - }); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->rpush('metavars', 'foo'); - $test->redis->setbit('metavars', 0, 1); - }); - } - - function testGetBit() - { - $this->redis->set('binary', "\x80\x00\00\x01"); - - $this->assertEquals(1, $this->redis->getbit('binary', 0)); - $this->assertEquals(0, $this->redis->getbit('binary', 15)); - $this->assertEquals(1, $this->redis->getbit('binary', 31)); - $this->assertEquals(0, $this->redis->getbit('binary', 63)); - - RC::testForServerException($this, RC::EXCEPTION_BIT_OFFSET, function($test) { - $test->redis->getbit('binary', -1); - }); - - RC::testForServerException($this, RC::EXCEPTION_BIT_OFFSET, function($test) { - $test->redis->getbit('binary', 'invalid'); - }); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->rpush('metavars', 'foo'); - $test->redis->getbit('metavars', 0); - }); - } - - /* commands operating on the key space */ - - function testKeys() - { - $keyValsNs = RC::getNamespacedKeyValueArray(); - $keyValsOthers = array('aaa' => 1, 'aba' => 2, 'aca' => 3); - $allKeyVals = array_merge($keyValsNs, $keyValsOthers); - - $this->redis->mset($allKeyVals); - - $this->assertEquals(array(), $this->redis->keys('nokeys:*')); - - $keysFromRedis = $this->redis->keys('metavar:*'); - $this->assertEquals(array(), array_diff(array_keys($keyValsNs), $keysFromRedis)); - - $keysFromRedis = $this->redis->keys('*'); - $this->assertEquals(array(), array_diff(array_keys($allKeyVals), $keysFromRedis)); - - $keysFromRedis = $this->redis->keys('a?a'); - $this->assertEquals(array(), array_diff(array_keys($keyValsOthers), $keysFromRedis)); - } - - function testRandomKey() - { - $keyvals = RC::getKeyValueArray(); - - $this->assertNull($this->redis->randomkey()); - - $this->redis->mset($keyvals); - $this->assertTrue(in_array($this->redis->randomkey(), array_keys($keyvals))); - } - - function testRename() - { - $this->redis->mset(array('foo' => 'bar', 'foofoo' => 'barbar')); - - // rename existing keys - $this->assertTrue($this->redis->rename('foo', 'foofoo')); - $this->assertFalse($this->redis->exists('foo')); - $this->assertEquals('bar', $this->redis->get('foofoo')); - - // should throw an excepion then trying to rename non-existing keys - RC::testForServerException($this, RC::EXCEPTION_NO_SUCH_KEY, function($test) { - $test->redis->rename('hoge', 'hogehoge'); - }); - } - - function testRenamePreserve() - { - $this->redis->mset(array('foo' => 'bar', 'hoge' => 'piyo', 'hogehoge' => 'piyopiyo')); - - $this->assertTrue($this->redis->renamenx('foo', 'foofoo')); - $this->assertFalse($this->redis->exists('foo')); - $this->assertEquals('bar', $this->redis->get('foofoo')); - - $this->assertFalse($this->redis->renamenx('hoge', 'hogehoge')); - $this->assertTrue($this->redis->exists('hoge')); - - // should throw an excepion then trying to rename non-existing keys - RC::testForServerException($this, RC::EXCEPTION_NO_SUCH_KEY, function($test) { - $test->redis->renamenx('fuga', 'baz'); - }); - } - - function testExpirationAndTTL() - { - $this->redis->set('foo', 'bar'); - - // check for key expiration - $this->assertTrue($this->redis->expire('foo', 1)); - $this->assertEquals(1, $this->redis->ttl('foo')); - $this->assertTrue($this->redis->exists('foo')); - sleep(2); - $this->assertFalse($this->redis->exists('foo')); - $this->assertEquals(-1, $this->redis->ttl('foo')); - - // check for consistent TTL values - $this->redis->set('foo', 'bar'); - $this->assertTrue($this->redis->expire('foo', 100)); - sleep(3); - $this->assertEquals(97, $this->redis->ttl('foo')); - - // delete key on negative TTL - $this->redis->set('foo', 'bar'); - $this->assertTrue($this->redis->expire('foo', -100)); - $this->assertFalse($this->redis->exists('foo')); - $this->assertEquals(-1, $this->redis->ttl('foo')); - } - - function testPersist() - { - $this->redis->set('foo', 'bar'); - - $this->assertTrue($this->redis->expire('foo', 1)); - $this->assertEquals(1, $this->redis->ttl('foo')); - $this->assertTrue($this->redis->persist('foo')); - $this->assertEquals(-1, $this->redis->ttl('foo')); - - $this->assertFalse($this->redis->persist('foo')); - $this->assertFalse($this->redis->persist('foobar')); - } - - function testSetExpire() - { - $this->assertTrue($this->redis->setex('foo', 10, 'bar')); - $this->assertTrue($this->redis->exists('foo')); - $this->assertEquals(10, $this->redis->ttl('foo')); - - $this->assertTrue($this->redis->setex('hoge', 1, 'piyo')); - sleep(2); - $this->assertFalse($this->redis->exists('hoge')); - - // TODO: do not check the error message RC::EXCEPTION_VALUE_NOT_INT for now - RC::testForServerException($this, null, function($test) { - $test->redis->setex('hoge', 2.5, 'piyo'); - }); - RC::testForServerException($this, RC::EXCEPTION_SETEX_TTL, function($test) { - $test->redis->setex('hoge', 0, 'piyo'); - }); - RC::testForServerException($this, RC::EXCEPTION_SETEX_TTL, function($test) { - $test->redis->setex('hoge', -10, 'piyo'); - }); - } - - function testDatabaseSize() - { - // TODO: is this really OK? - $this->assertEquals(0, $this->redis->dbsize()); - $this->redis->mset(RC::getKeyValueArray()); - $this->assertGreaterThan(0, $this->redis->dbsize()); - } - - /* commands operating on lists */ - - function testPushTail() - { - // NOTE: List push operations return the list length since Redis commit 520b5a3 - $this->assertEquals(1, $this->redis->rpush('metavars', 'foo')); - $this->assertTrue($this->redis->exists('metavars')); - $this->assertEquals(2, $this->redis->rpush('metavars', 'hoge')); - - // should throw an exception when trying to do a RPUSH on non-list types - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->rpush('foo', 'bar'); - }); - } - - function testPushTailX() - { - $this->assertEquals(0, $this->redis->rpushx('numbers', 1)); - $this->assertEquals(1, $this->redis->rpush('numbers', 2)); - $this->assertEquals(2, $this->redis->rpushx('numbers', 3)); - - $this->assertEquals(2, $this->redis->llen('numbers')); - $this->assertEquals(array(2, 3), $this->redis->lrange('numbers', 0, -1)); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->rpushx('foo', 'bar'); - }); - } - - function testPushHead() - { - // NOTE: List push operations return the list length since Redis commit 520b5a3 - $this->assertEquals(1, $this->redis->lpush('metavars', 'foo')); - $this->assertTrue($this->redis->exists('metavars')); - $this->assertEquals(2, $this->redis->lpush('metavars', 'hoge')); - - // should throw an exception when trying to do a LPUSH on non-list types - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->lpush('foo', 'bar'); - }); - } - - function testPushHeadX() - { - $this->assertEquals(0, $this->redis->lpushx('numbers', 1)); - $this->assertEquals(1, $this->redis->lpush('numbers', 2)); - $this->assertEquals(2, $this->redis->lpushx('numbers', 3)); - - $this->assertEquals(2, $this->redis->llen('numbers')); - $this->assertEquals(array(3, 2), $this->redis->lrange('numbers', 0, -1)); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->lpushx('foo', 'bar'); - }); - } - - function testListLength() - { - $this->assertEquals(1, $this->redis->rpush('metavars', 'foo')); - $this->assertEquals(2, $this->redis->rpush('metavars', 'hoge')); - $this->assertEquals(2, $this->redis->llen('metavars')); - - $this->assertEquals(0, $this->redis->llen('doesnotexist')); - - // should throw an exception when trying to do a LLEN on non-list types - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->llen('foo'); - }); - } - - function testListRange() - { - $numbers = RC::pushTailAndReturn($this->redis, 'numbers', RC::getArrayOfNumbers()); - - $this->assertEquals( - array_slice($numbers, 0, 4), - $this->redis->lrange('numbers', 0, 3) - ); - $this->assertEquals( - array_slice($numbers, 4, 5), - $this->redis->lrange('numbers', 4, 8) - ); - $this->assertEquals( - array_slice($numbers, 0, 1), - $this->redis->lrange('numbers', 0, 0) - ); - $this->assertEquals( - array(), - $this->redis->lrange('numbers', 1, 0) - ); - $this->assertEquals( - $numbers, - $this->redis->lrange('numbers', 0, -1) - ); - $this->assertEquals( - array(5), - $this->redis->lrange('numbers', 5, -5) - ); - $this->assertEquals( - array(), - $this->redis->lrange('numbers', 7, -5) - ); - $this->assertEquals( - array_slice($numbers, -5, -1), - $this->redis->lrange('numbers', -5, -2) - ); - $this->assertEquals( - $numbers, - $this->redis->lrange('numbers', -100, 100) - ); - - $this->assertEquals( - array(), - $this->redis->lrange('keyDoesNotExist', 0, 1) - ); - - // should throw an exception when trying to do a LRANGE on non-list types - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->lrange('foo', 0, -1); - }); - } - - function testListTrim() - { - $numbers = RC::pushTailAndReturn($this->redis, 'numbers', RC::getArrayOfNumbers()); - $this->assertTrue($this->redis->ltrim('numbers', 0, 2)); - $this->assertEquals( - array_slice($numbers, 0, 3), - $this->redis->lrange('numbers', 0, -1) - ); - - $numbers = RC::pushTailAndReturn($this->redis, 'numbers', RC::getArrayOfNumbers(), RC::WIPE_OUT); - $this->assertTrue($this->redis->ltrim('numbers', 5, 9)); - $this->assertEquals( - array_slice($numbers, 5, 5), - $this->redis->lrange('numbers', 0, -1) - ); - - $numbers = RC::pushTailAndReturn($this->redis, 'numbers', RC::getArrayOfNumbers(), RC::WIPE_OUT); - $this->assertTrue($this->redis->ltrim('numbers', 0, -6)); - $this->assertEquals( - array_slice($numbers, 0, -5), - $this->redis->lrange('numbers', 0, -1) - ); - - $numbers = RC::pushTailAndReturn($this->redis, 'numbers', RC::getArrayOfNumbers(), RC::WIPE_OUT); - $this->assertTrue($this->redis->ltrim('numbers', -5, -3)); - $this->assertEquals( - array_slice($numbers, 5, 3), - $this->redis->lrange('numbers', 0, -1) - ); - - $numbers = RC::pushTailAndReturn($this->redis, 'numbers', RC::getArrayOfNumbers(), RC::WIPE_OUT); - $this->assertTrue($this->redis->ltrim('numbers', -100, 100)); - $this->assertEquals( - $numbers, - $this->redis->lrange('numbers', 0, -1) - ); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->ltrim('foo', 0, 1); - }); - } - - function testListIndex() - { - $numbers = RC::pushTailAndReturn($this->redis, 'numbers', RC::getArrayOfNumbers()); - - $this->assertEquals(0, $this->redis->lindex('numbers', 0)); - $this->assertEquals(5, $this->redis->lindex('numbers', 5)); - $this->assertEquals(9, $this->redis->lindex('numbers', 9)); - $this->assertNull($this->redis->lindex('numbers', 100)); - - $this->assertEquals(0, $this->redis->lindex('numbers', -0)); - $this->assertEquals(9, $this->redis->lindex('numbers', -1)); - $this->assertEquals(7, $this->redis->lindex('numbers', -3)); - $this->assertNull($this->redis->lindex('numbers', -100)); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->lindex('foo', 0); - }); - } - - function testListSet() - { - $numbers = RC::pushTailAndReturn($this->redis, 'numbers', RC::getArrayOfNumbers()); - - $this->assertTrue($this->redis->lset('numbers', 5, -5)); - $this->assertEquals(-5, $this->redis->lindex('numbers', 5)); - - RC::testForServerException($this, RC::EXCEPTION_OUT_OF_RANGE, function($test) { - $test->redis->lset('numbers', 99, 99); - }); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->lset('foo', 0, 0); - }); - } - - function testListRemove() - { - $mixed = array(0, '_', 2, '_', 4, '_', 6, '_'); - - RC::pushTailAndReturn($this->redis, 'mixed', $mixed); - $this->assertEquals(2, $this->redis->lrem('mixed', 2, '_')); - $this->assertEquals(array(0, 2, 4, '_', 6, '_'), $this->redis->lrange('mixed', 0, -1)); - - RC::pushTailAndReturn($this->redis, 'mixed', $mixed, RC::WIPE_OUT); - $this->assertEquals(4, $this->redis->lrem('mixed', 0, '_')); - $this->assertEquals(array(0, 2, 4, 6), $this->redis->lrange('mixed', 0, -1)); - - RC::pushTailAndReturn($this->redis, 'mixed', $mixed, RC::WIPE_OUT); - $this->assertEquals(2, $this->redis->lrem('mixed', -2, '_')); - $this->assertEquals(array(0, '_', 2, '_', 4, 6), $this->redis->lrange('mixed', 0, -1)); - - RC::pushTailAndReturn($this->redis, 'mixed', $mixed, RC::WIPE_OUT); - $this->assertEquals(0, $this->redis->lrem('mixed', 2, '|')); - $this->assertEquals($mixed, $this->redis->lrange('mixed', 0, -1)); - - $this->assertEquals(0, $this->redis->lrem('listDoesNotExist', 2, '_')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->lrem('foo', 0, 0); - }); - } - - function testListPopFirst() - { - $numbers = RC::pushTailAndReturn($this->redis, 'numbers', array(0, 1, 2, 3, 4)); - - $this->assertEquals(0, $this->redis->lpop('numbers')); - $this->assertEquals(1, $this->redis->lpop('numbers')); - $this->assertEquals(2, $this->redis->lpop('numbers')); - - $this->assertEquals(array(3, 4), $this->redis->lrange('numbers', 0, -1)); - - $this->redis->lpop('numbers'); - $this->redis->lpop('numbers'); - $this->assertNull($this->redis->lpop('numbers')); - - $this->assertNull($this->redis->lpop('numbers')); - - $this->assertNull($this->redis->lpop('listDoesNotExist')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->lpop('foo'); - }); - } - - function testListPopLast() - { - $numbers = RC::pushTailAndReturn($this->redis, 'numbers', array(0, 1, 2, 3, 4)); - - $this->assertEquals(4, $this->redis->rpop('numbers')); - $this->assertEquals(3, $this->redis->rpop('numbers')); - $this->assertEquals(2, $this->redis->rpop('numbers')); - - $this->assertEquals(array(0, 1), $this->redis->lrange('numbers', 0, -1)); - - $this->redis->rpop('numbers'); - $this->redis->rpop('numbers'); - $this->assertNull($this->redis->rpop('numbers')); - - $this->assertNull($this->redis->rpop('numbers')); - - $this->assertNull($this->redis->rpop('listDoesNotExist')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->rpop('foo'); - }); - } - - function testListPopLastPushHead() - { - $numbers = RC::pushTailAndReturn($this->redis, 'numbers', array(0, 1, 2)); - $this->assertEquals(0, $this->redis->llen('temporary')); - $this->assertEquals(2, $this->redis->rpoplpush('numbers', 'temporary')); - $this->assertEquals(1, $this->redis->rpoplpush('numbers', 'temporary')); - $this->assertEquals(0, $this->redis->rpoplpush('numbers', 'temporary')); - $this->assertEquals(0, $this->redis->llen('numbers')); - $this->assertEquals(3, $this->redis->llen('temporary')); - $this->assertEquals(array(), $this->redis->lrange('numbers', 0, -1)); - $this->assertEquals($numbers, $this->redis->lrange('temporary', 0, -1)); - - $numbers = RC::pushTailAndReturn($this->redis, 'numbers', array(0, 1, 2)); - $this->redis->rpoplpush('numbers', 'numbers'); - $this->redis->rpoplpush('numbers', 'numbers'); - $this->redis->rpoplpush('numbers', 'numbers'); - $this->assertEquals($numbers, $this->redis->lrange('numbers', 0, -1)); - - $this->assertNull($this->redis->rpoplpush('listDoesNotExist1', 'listDoesNotExist2')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->rpoplpush('foo', 'hoge'); - }); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->rpoplpush('temporary', 'foo'); - }); - } - - function testListBlockingPopFirst() - { - // TODO: this test does not cover all the aspects of BLPOP/BRPOP as it - // does not run with a concurrent client pushing items on lists. - RC::helperForBlockingPops('blpop'); - - // BLPOP on one key - $start = time(); - $item = $this->redis->blpop('blpop3', 5); - $this->assertEquals((float)(time() - $start), 0, '', 1); - $this->assertEquals($item, array('blpop3', 'c')); - - // BLPOP on more than one key - $poppedItems = array(); - while ($item = $this->redis->blpop('blpop1', 'blpop2', 1)) { - $poppedItems[] = $item; - } - $this->assertEquals( - array(array('blpop1', 'a'), array('blpop1', 'd'), array('blpop2', 'b')), - $poppedItems - ); - - // check if BLPOP timeouts as expected on empty lists - $start = time(); - $this->redis->blpop('blpop4', 2); - $this->assertEquals((float)(time() - $start), 2, '', 1); - } - - function testListBlockingPopLast() - { - // TODO: this test does not cover all the aspects of BLPOP/BRPOP as it - // does not run with a concurrent client pushing items on lists. - RC::helperForBlockingPops('brpop'); - - // BRPOP on one key - $start = time(); - $item = $this->redis->brpop('brpop3', 5); - $this->assertEquals((float)(time() - $start), 0, '', 1); - $this->assertEquals($item, array('brpop3', 'c')); - - // BRPOP on more than one key - $poppedItems = array(); - while ($item = $this->redis->brpop('brpop1', 'brpop2', 1)) { - $poppedItems[] = $item; - } - $this->assertEquals( - array(array('brpop1', 'd'), array('brpop1', 'a'), array('brpop2', 'b')), - $poppedItems - ); - - // check if BRPOP timeouts as expected on empty lists - $start = time(); - $this->redis->brpop('brpop4', 2); - $this->assertEquals((float)(time() - $start), 2, '', 1); - } - - function testListBlockingPopLastPushHead() - { - // TODO: this test does not cover all the aspects of BLPOP/BRPOP as it - // does not run with a concurrent client pushing items on lists. - $numbers = RC::pushTailAndReturn($this->redis, 'numbers', array(1, 2, 3)); - $src_count = count($numbers); - $dst_count = 0; - - while ($item = $this->redis->brpoplpush('numbers', 'temporary', 1)) { - $this->assertEquals(--$src_count, $this->redis->llen('numbers')); - $this->assertEquals(++$dst_count, $this->redis->llen('temporary')); - $this->assertEquals(array_pop($numbers), $this->redis->lindex('temporary', 0)); - } - - $start = time(); - $this->assertNull($this->redis->brpoplpush('numbers', 'temporary', 2)); - $this->assertEquals(2, (float)(time() - $start), '', 1); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->del('numbers'); - $test->redis->del('temporary'); - $test->redis->set('numbers', 'foobar'); - $test->redis->brpoplpush('numbers', 'temporary', 1); - }); - } - - function testListInsert() - { - $numbers = RC::pushTailAndReturn($this->redis, 'numbers', RC::getArrayOfNumbers()); - - $this->assertEquals(11, $this->redis->linsert('numbers', 'before', 0, -2)); - $this->assertEquals(12, $this->redis->linsert('numbers', 'after', -2, -1)); - $this->assertEquals(array(-2, -1, 0, 1), $this->redis->lrange('numbers', 0, 3)); - - $this->assertEquals(-1, $this->redis->linsert('numbers', 'after', 100, 200)); - $this->assertEquals(-1, $this->redis->linsert('numbers', 'before', 100, 50)); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->linsert('foo', 'before', 0, 0); - }); - } - - /* commands operating on sets */ - - function testSetAdd() - { - $this->assertTrue($this->redis->sadd('set', 0)); - $this->assertTrue($this->redis->sadd('set', 1)); - $this->assertFalse($this->redis->sadd('set', 0)); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->sadd('foo', 0); - }); - } - - function testSetRemove() - { - $set = RC::setAddAndReturn($this->redis, 'set', array(0, 1, 2, 3, 4)); - - $this->assertTrue($this->redis->srem('set', 0)); - $this->assertTrue($this->redis->srem('set', 4)); - $this->assertFalse($this->redis->srem('set', 10)); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->srem('foo', 0); - }); - } - - function testSetPop() - { - $set = RC::setAddAndReturn($this->redis, 'set', array(0, 1, 2, 3, 4)); - - $this->assertTrue(in_array($this->redis->spop('set'), $set)); - - $this->assertNull($this->redis->spop('setDoesNotExist')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->spop('foo'); - }); - } - - function testSetMove() - { - $setA = RC::setAddAndReturn($this->redis, 'setA', array(0, 1, 2, 3, 4, 5)); - $setB = RC::setAddAndReturn($this->redis, 'setB', array(5, 6, 7, 8, 9, 10)); - - $this->assertTrue($this->redis->smove('setA', 'setB', 0)); - $this->assertFalse($this->redis->srem('setA', 0)); - $this->assertTrue($this->redis->srem('setB', 0)); - - $this->assertTrue($this->redis->smove('setA', 'setB', 5)); - $this->assertFalse($this->redis->smove('setA', 'setB', 100)); - - // wrong type - $this->redis->set('foo', 'bar'); - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->smove('foo', 'setB', 5); - }); - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->smove('setA', 'foo', 5); - }); - } - - function testSetCardinality() - { - RC::setAddAndReturn($this->redis, 'setA', array(0, 1, 2, 3, 4, 5)); - - $this->assertEquals(6, $this->redis->scard('setA')); - - // empty set - $this->redis->sadd('setB', 0); - $this->redis->spop('setB'); - $this->assertEquals(0, $this->redis->scard('setB')); - - // non-existing set - $this->assertEquals(0, $this->redis->scard('setDoesNotExist')); - - // wrong type - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->scard('foo'); - }); - } - - function testSetIsMember() - { - RC::setAddAndReturn($this->redis, 'set', array(0, 1, 2, 3, 4, 5)); - - $this->assertTrue($this->redis->sismember('set', 3)); - $this->assertFalse($this->redis->sismember('set', 100)); - - $this->assertFalse($this->redis->sismember('setDoesNotExist', 0)); - - // wrong type - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->sismember('foo', 0); - }); - } - - function testSetMembers() - { - $set = RC::setAddAndReturn($this->redis, 'set', array(0, 1, 2, 3, 4, 5, 6)); - - $this->assertTrue(RC::sameValuesInArrays($set, $this->redis->smembers('set'))); - - $this->assertEquals(array(), $this->redis->smembers('setDoesNotExist')); - - // wrong type - $this->redis->set('foo', 'bar'); - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->smembers('foo'); - }); - } - - function testSetIntersection() - { - $setA = RC::setAddAndReturn($this->redis, 'setA', array(0, 1, 2, 3, 4, 5, 6)); - $setB = RC::setAddAndReturn($this->redis, 'setB', array(1, 3, 4, 6, 9, 10)); - - $this->assertTrue(RC::sameValuesInArrays( - $setA, - $this->redis->sinter('setA') - )); - - $this->assertTrue(RC::sameValuesInArrays( - array_intersect($setA, $setB), - $this->redis->sinter('setA', 'setB') - )); - - $this->assertEquals(array(), $this->redis->sinter('setA', 'setDoesNotExist')); - - // wrong type - $this->redis->set('foo', 'bar'); - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->sinter('foo'); - }); - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->sinter('setA', 'foo'); - }); - } - - function testSetIntersectionStore() - { - $setA = RC::setAddAndReturn($this->redis, 'setA', array(0, 1, 2, 3, 4, 5, 6)); - $setB = RC::setAddAndReturn($this->redis, 'setB', array(1, 3, 4, 6, 9, 10)); - - $this->assertEquals(count($setA), $this->redis->sinterstore('setC', 'setA')); - $this->assertTrue(RC::sameValuesInArrays( - $setA, - $this->redis->smembers('setC') - )); - - $this->redis->del('setC'); - $this->assertEquals(4, $this->redis->sinterstore('setC', 'setA', 'setB')); - $this->assertTrue(RC::sameValuesInArrays( - array(1, 3, 4, 6), - $this->redis->smembers('setC') - )); - - $this->redis->del('setC'); - $this->assertEquals(array(), $this->redis->sinter('setC', 'setDoesNotExist')); - $this->assertFalse($this->redis->exists('setC')); - - // existing keys are replaced by SINTERSTORE - $this->redis->set('foo', 'bar'); - $this->assertEquals(count($setA), $this->redis->sinterstore('foo', 'setA')); - - // accepts an array for the list of source keys - $this->assertEquals(4, $this->redis->sinterstore('setC', array('setA', 'setB'))); - - // wrong type - $this->redis->set('foo', 'bar'); - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->sinterstore('setA', 'foo'); - }); - } - - function testSetUnion() - { - $setA = RC::setAddAndReturn($this->redis, 'setA', array(0, 1, 2, 3, 4, 5, 6)); - $setB = RC::setAddAndReturn($this->redis, 'setB', array(1, 3, 4, 6, 9, 10)); - - $this->assertTrue(RC::sameValuesInArrays( - $setA, - $this->redis->sunion('setA') - )); - - $this->assertTrue(RC::sameValuesInArrays( - array_union($setA, $setB), - $this->redis->sunion('setA', 'setB') - )); - - $this->assertTrue(RC::sameValuesInArrays( - $setA, - $this->redis->sunion('setA', 'setDoesNotExist') - )); - - // wrong type - $this->redis->set('foo', 'bar'); - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->sunion('foo'); - }); - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->sunion('setA', 'foo'); - }); - } - - function testSetUnionStore() - { - $setA = RC::setAddAndReturn($this->redis, 'setA', array(0, 1, 2, 3, 4, 5, 6)); - $setB = RC::setAddAndReturn($this->redis, 'setB', array(1, 3, 4, 6, 9, 10)); - - $this->assertEquals(count($setA), $this->redis->sunionstore('setC', 'setA')); - $this->assertTrue(RC::sameValuesInArrays( - $setA, - $this->redis->smembers('setC') - )); - - $this->redis->del('setC'); - $this->assertEquals(9, $this->redis->sunionstore('setC', 'setA', 'setB')); - $this->assertTrue(RC::sameValuesInArrays( - array_union($setA, $setB), - $this->redis->smembers('setC') - )); - - // non-existing keys are considered empty sets - $this->redis->del('setC'); - $this->assertEquals(0, $this->redis->sunionstore('setC', 'setDoesNotExist')); - $this->assertFalse($this->redis->exists('setC')); - $this->assertEquals(0, $this->redis->scard('setC')); - - // existing keys are replaced by SUNIONSTORE - $this->redis->set('foo', 'bar'); - $this->assertEquals(count($setA), $this->redis->sunionstore('foo', 'setA')); - - // accepts an array for the list of source keys - $this->assertEquals(9, $this->redis->sunionstore('setC', array('setA', 'setB'))); - - // wrong type - $this->redis->set('foo', 'bar'); - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->sunionstore('setA', 'foo'); - }); - } - - function testSetDifference() - { - $setA = RC::setAddAndReturn($this->redis, 'setA', array(0, 1, 2, 3, 4, 5, 6)); - $setB = RC::setAddAndReturn($this->redis, 'setB', array(1, 3, 4, 6, 9, 10)); - - $this->assertTrue(RC::sameValuesInArrays( - $setA, - $this->redis->sdiff('setA') - )); - - $this->assertTrue(RC::sameValuesInArrays( - array_diff($setA, $setB), - $this->redis->sdiff('setA', 'setB') - )); - - $this->assertTrue(RC::sameValuesInArrays( - $setA, - $this->redis->sdiff('setA', 'setDoesNotExist') - )); - - // wrong type - $this->redis->set('foo', 'bar'); - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->sdiff('foo'); - }); - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->sdiff('setA', 'foo'); - }); - } - - function testSetDifferenceStore() - { - $setA = RC::setAddAndReturn($this->redis, 'setA', array(0, 1, 2, 3, 4, 5, 6)); - $setB = RC::setAddAndReturn($this->redis, 'setB', array(1, 3, 4, 6, 9, 10)); - - $this->assertEquals(count($setA), $this->redis->sdiffstore('setC', 'setA')); - $this->assertTrue(RC::sameValuesInArrays( - $setA, - $this->redis->smembers('setC') - )); - - $this->redis->del('setC'); - $this->assertEquals(3, $this->redis->sdiffstore('setC', 'setA', 'setB')); - $this->assertTrue(RC::sameValuesInArrays( - array_diff($setA, $setB), - $this->redis->smembers('setC') - )); - - // non-existing keys are considered empty sets - $this->redis->del('setC'); - $this->assertEquals(0, $this->redis->sdiffstore('setC', 'setDoesNotExist')); - $this->assertFalse($this->redis->exists('setC')); - $this->assertEquals(0, $this->redis->scard('setC')); - - // existing keys are replaced by SDIFFSTORE - $this->redis->set('foo', 'bar'); - $this->assertEquals(count($setA), $this->redis->sdiffstore('foo', 'setA')); - - // wrong type - $this->redis->set('foo', 'bar'); - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->sdiffstore('setA', 'foo'); - }); - } - - function testRandomMember() - { - $set = RC::setAddAndReturn($this->redis, 'set', array(0, 1, 2, 3, 4, 5, 6)); - - $this->assertTrue(in_array($this->redis->srandmember('set'), $set)); - - $this->assertNull($this->redis->srandmember('setDoesNotExist')); - - // wrong type - $this->redis->set('foo', 'bar'); - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->srandmember('foo'); - }); - } - - /* commands operating on sorted sets */ - - function testZsetAdd() - { - $this->assertTrue($this->redis->zadd('zset', 0, 'a')); - $this->assertTrue($this->redis->zadd('zset', 1, 'b')); - - $this->assertTrue($this->redis->zadd('zset', -1, 'c')); - - // TODO: floats? - //$this->assertTrue($this->redis->zadd('zset', -1.0, 'c')); - //$this->assertTrue($this->redis->zadd('zset', -1.0, 'c')); - - $this->assertFalse($this->redis->zadd('zset', 2, 'b')); - $this->assertFalse($this->redis->zadd('zset', -2, 'b')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->zadd('foo', 0, 'a'); - }); - } - - function testZsetIncrementBy() - { - $this->assertEquals(1, $this->redis->zincrby('zsetDoesNotExist', 1, 'foo')); - $this->assertEquals('zset', $this->redis->type('zsetDoesNotExist')); - - RC::zsetAddAndReturn($this->redis, 'zset', RC::getZSetArray()); - $this->assertEquals(-5, $this->redis->zincrby('zset', 5, 'a')); - $this->assertEquals(1, $this->redis->zincrby('zset', 1, 'b')); - $this->assertEquals(10, $this->redis->zincrby('zset', 0, 'c')); - $this->assertEquals(0, $this->redis->zincrby('zset', -20, 'd')); - $this->assertEquals(2, $this->redis->zincrby('zset', 2, 'd')); - $this->assertEquals(-10, $this->redis->zincrby('zset', -30, 'e')); - $this->assertEquals(1, $this->redis->zincrby('zset', 1, 'x')); - - // wrong type - $this->redis->set('foo', 'bar'); - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->zincrby('foo', 1, 'a'); - }); - } - - function testZsetRemove() - { - RC::zsetAddAndReturn($this->redis, 'zset', RC::getZSetArray()); - - $this->assertTrue($this->redis->zrem('zset', 'a')); - $this->assertFalse($this->redis->zrem('zset', 'x')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->zrem('foo', 'bar'); - }); - } - - function testZsetRange() - { - $zset = RC::zsetAddAndReturn($this->redis, 'zset', RC::getZSetArray()); - - $this->assertEquals( - array_slice(array_keys($zset), 0, 4), - $this->redis->zrange('zset', 0, 3) - ); - - $this->assertEquals( - array_slice(array_keys($zset), 0, 1), - $this->redis->zrange('zset', 0, 0) - ); - - $this->assertEquals( - array(), - $this->redis->zrange('zset', 1, 0) - ); - - $this->assertEquals( - array_values(array_keys($zset)), - $this->redis->zrange('zset', 0, -1) - ); - - $this->assertEquals( - array_slice(array_keys($zset), 3, 1), - $this->redis->zrange('zset', 3, -3) - ); - - $this->assertEquals( - array(), - $this->redis->zrange('zset', 5, -3) - ); - - $this->assertEquals( - array_slice(array_keys($zset), -5, -1), - $this->redis->zrange('zset', -5, -2) - ); - - $this->assertEquals( - array_values(array_keys($zset)), - $this->redis->zrange('zset', -100, 100) - ); - - $this->assertEquals( - array_values(array_keys($zset)), - $this->redis->zrange('zset', -100, 100) - ); - - $this->assertEquals( - array(array('a', -10), array('b', 0), array('c', 10)), - $this->redis->zrange('zset', 0, 2, 'withscores') - ); - - $this->assertEquals( - array(array('a', -10), array('b', 0), array('c', 10)), - $this->redis->zrange('zset', 0, 2, array('withscores' => true)) - ); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->zrange('foo', 0, -1); - }); - } - - function testZsetReverseRange() - { - $zset = RC::zsetAddAndReturn($this->redis, 'zset', RC::getZSetArray()); - - $this->assertEquals( - array_slice(array_reverse(array_keys($zset)), 0, 4), - $this->redis->zrevrange('zset', 0, 3) - ); - - $this->assertEquals( - array_slice(array_reverse(array_keys($zset)), 0, 1), - $this->redis->zrevrange('zset', 0, 0) - ); - - $this->assertEquals( - array(), - $this->redis->zrevrange('zset', 1, 0) - ); - - $this->assertEquals( - array_values(array_reverse(array_keys($zset))), - $this->redis->zrevrange('zset', 0, -1) - ); - - $this->assertEquals( - array_slice(array_reverse(array_keys($zset)), 3, 1), - $this->redis->zrevrange('zset', 3, -3) - ); - - $this->assertEquals( - array(), - $this->redis->zrevrange('zset', 5, -3) - ); - - $this->assertEquals( - array_slice(array_reverse(array_keys($zset)), -5, -1), - $this->redis->zrevrange('zset', -5, -2) - ); - - $this->assertEquals( - array_values(array_reverse(array_keys($zset))), - $this->redis->zrevrange('zset', -100, 100) - ); - - $this->assertEquals( - array(array('f', 30), array('e', 20), array('d', 20)), - $this->redis->zrevrange('zset', 0, 2, 'withscores') - ); - - $this->assertEquals( - array(array('f', 30), array('e', 20), array('d', 20)), - $this->redis->zrevrange('zset', 0, 2, array('withscores' => true)) - ); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->zrevrange('foo', 0, -1); - }); - } - - function testZsetRangeByScore() - { - $zset = RC::zsetAddAndReturn($this->redis, 'zset', RC::getZSetArray()); - - $this->assertEquals( - array('a'), - $this->redis->zrangebyscore('zset', -10, -10) - ); - - $this->assertEquals( - array('c', 'd', 'e', 'f'), - $this->redis->zrangebyscore('zset', 10, 30) - ); - - $this->assertEquals( - array('d', 'e'), - $this->redis->zrangebyscore('zset', 20, 20) - ); - - $this->assertEquals( - array(), - $this->redis->zrangebyscore('zset', 30, 0) - ); - - $this->assertEquals( - array(array('c', 10), array('d', 20), array('e', 20)), - $this->redis->zrangebyscore('zset', 10, 20, 'withscores') - ); - - $this->assertEquals( - array(array('c', 10), array('d', 20), array('e', 20)), - $this->redis->zrangebyscore('zset', 10, 20, array('withscores' => true)) - ); - - $this->assertEquals( - array('d', 'e'), - $this->redis->zrangebyscore('zset', 10, 20, array('limit' => array(1, 2))) - ); - - $this->assertEquals( - array('d', 'e'), - $this->redis->zrangebyscore('zset', 10, 20, array( - 'limit' => array('offset' => 1, 'count' => 2) - )) - ); - - $this->assertEquals( - array(array('d', 20), array('e', 20)), - $this->redis->zrangebyscore('zset', 10, 20, array( - 'limit' => array(1, 2), - 'withscores' => true, - )) - ); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->zrangebyscore('foo', 0, 0); - }); - } - - function testZsetReverseRangeByScore() - { - $zset = RC::zsetAddAndReturn($this->redis, 'zset', RC::getZSetArray()); - - $this->assertEquals( - array('a'), - $this->redis->zrevrangebyscore('zset', -10, -10) - ); - - $this->assertEquals( - array('b', 'a'), - $this->redis->zrevrangebyscore('zset', 0, -10) - ); - - $this->assertEquals( - array('e', 'd'), - $this->redis->zrevrangebyscore('zset', 20, 20) - ); - - $this->assertEquals( - array('f', 'e', 'd', 'c', 'b'), - $this->redis->zrevrangebyscore('zset', 30, 0) - ); - - $this->assertEquals( - array(array('e', 20), array('d', 20), array('c', 10)), - $this->redis->zrevrangebyscore('zset', 20, 10, 'withscores') - ); - - $this->assertEquals( - array(array('e', 20), array('d', 20), array('c', 10)), - $this->redis->zrevrangebyscore('zset', 20, 10, array('withscores' => true)) - ); - - $this->assertEquals( - array('d', 'c'), - $this->redis->zrevrangebyscore('zset', 20, 10, array('limit' => array(1, 2))) - ); - - $this->assertEquals( - array('d', 'c'), - $this->redis->zrevrangebyscore('zset', 20, 10, array( - 'limit' => array('offset' => 1, 'count' => 2) - )) - ); - - $this->assertEquals( - array(array('d', 20), array('c', 10)), - $this->redis->zrevrangebyscore('zset', 20, 10, array( - 'limit' => array(1, 2), - 'withscores' => true, - )) - ); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->zrevrangebyscore('foo', 0, 0); - }); - } - - function testZsetUnionStore() - { - $zsetA = RC::zsetAddAndReturn($this->redis, 'zseta', array('a' => 1, 'b' => 2, 'c' => 3)); - $zsetB = RC::zsetAddAndReturn($this->redis, 'zsetb', array('b' => 1, 'c' => 2, 'd' => 3)); - - // basic ZUNIONSTORE - $this->assertEquals(4, $this->redis->zunionstore('zsetc', 2, 'zseta', 'zsetb')); - $this->assertEquals( - array(array('a', 1), array('b', 3), array('d', 3), array('c', 5)), - $this->redis->zrange('zsetc', 0, -1, 'withscores') - ); - - $this->assertEquals(3, $this->redis->zunionstore('zsetc', 2, 'zseta', 'zsetbNull')); - $this->assertEquals( - array(array('a', 1), array('b', 2), array('c', 3)), - $this->redis->zrange('zsetc', 0, -1, 'withscores') - ); - - $this->assertEquals(3, $this->redis->zunionstore('zsetc', 2, 'zsetaNull', 'zsetb')); - $this->assertEquals( - array(array('b', 1), array('c', 2), array('d', 3)), - $this->redis->zrange('zsetc', 0, -1, 'withscores') - ); - - $this->assertEquals(0, $this->redis->zunionstore('zsetc', 2, 'zsetaNull', 'zsetbNull')); - - // with WEIGHTS - $options = array('weights' => array(2, 3)); - $this->assertEquals(4, $this->redis->zunionstore('zsetc', 2, 'zseta', 'zsetb', $options)); - $this->assertEquals( - array(array('a', 2), array('b', 7), array('d', 9), array('c', 12)), - $this->redis->zrange('zsetc', 0, -1, 'withscores') - ); - - // with AGGREGATE (min) - $options = array('aggregate' => 'min'); - $this->assertEquals(4, $this->redis->zunionstore('zsetc', 2, 'zseta', 'zsetb', $options)); - $this->assertEquals( - array(array('a', 1), array('b', 1), array('c', 2), array('d', 3)), - $this->redis->zrange('zsetc', 0, -1, 'withscores') - ); - - // with AGGREGATE (max) - $options = array('aggregate' => 'max'); - $this->assertEquals(4, $this->redis->zunionstore('zsetc', 2, 'zseta', 'zsetb', $options)); - $this->assertEquals( - array(array('a', 1), array('b', 2), array('c', 3), array('d', 3)), - $this->redis->zrange('zsetc', 0, -1, 'withscores') - ); - - // using an array to pass the list of source keys - $sourceKeys = array('zseta', 'zsetb'); - - $this->assertEquals(4, $this->redis->zunionstore('zsetc', $sourceKeys)); - $this->assertEquals( - array(array('a', 1), array('b', 3), array('d', 3), array('c', 5)), - $this->redis->zrange('zsetc', 0, -1, 'withscores') - ); - - // using an array to pass the list of source keys + options array - $options = array('weights' => array(2, 3)); - $this->assertEquals(4, $this->redis->zunionstore('zsetc', $sourceKeys, $options)); - $this->assertEquals( - array(array('a', 2), array('b', 7), array('d', 9), array('c', 12)), - $this->redis->zrange('zsetc', 0, -1, 'withscores') - ); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('zsetFake', 'fake'); - $test->redis->zunionstore('zsetc', 2, 'zseta', 'zsetFake'); - }); - } - - function testZsetIntersectionStore() - { - $zsetA = RC::zsetAddAndReturn($this->redis, 'zseta', array('a' => 1, 'b' => 2, 'c' => 3)); - $zsetB = RC::zsetAddAndReturn($this->redis, 'zsetb', array('b' => 1, 'c' => 2, 'd' => 3)); - - // basic ZINTERSTORE - $this->assertEquals(2, $this->redis->zinterstore('zsetc', 2, 'zseta', 'zsetb')); - $this->assertEquals( - array(array('b', 3), array('c', 5)), - $this->redis->zrange('zsetc', 0, -1, 'withscores') - ); - - $this->assertEquals(0, $this->redis->zinterstore('zsetc', 2, 'zseta', 'zsetbNull')); - $this->assertEquals(0, $this->redis->zinterstore('zsetc', 2, 'zsetaNull', 'zsetb')); - $this->assertEquals(0, $this->redis->zinterstore('zsetc', 2, 'zsetaNull', 'zsetbNull')); - - // with WEIGHTS - $options = array('weights' => array(2, 3)); - $this->assertEquals(2, $this->redis->zinterstore('zsetc', 2, 'zseta', 'zsetb', $options)); - $this->assertEquals( - array(array('b', 7), array('c', 12)), - $this->redis->zrange('zsetc', 0, -1, 'withscores') - ); - - // with AGGREGATE (min) - $options = array('aggregate' => 'min'); - $this->assertEquals(2, $this->redis->zinterstore('zsetc', 2, 'zseta', 'zsetb', $options)); - $this->assertEquals( - array(array('b', 1), array('c', 2)), - $this->redis->zrange('zsetc', 0, -1, 'withscores') - ); - - // with AGGREGATE (max) - $options = array('aggregate' => 'max'); - $this->assertEquals(2, $this->redis->zinterstore('zsetc', 2, 'zseta', 'zsetb', $options)); - $this->assertEquals( - array(array('b', 2), array('c', 3)), - $this->redis->zrange('zsetc', 0, -1, 'withscores') - ); - - // using an array to pass the list of source keys - $sourceKeys = array('zseta', 'zsetb'); - - $this->assertEquals(2, $this->redis->zinterstore('zsetc', $sourceKeys)); - $this->assertEquals( - array(array('b', 3), array('c', 5)), - $this->redis->zrange('zsetc', 0, -1, 'withscores') - ); - - // using an array to pass the list of source keys + options array - $options = array('weights' => array(2, 3)); - $this->assertEquals(2, $this->redis->zinterstore('zsetc', $sourceKeys, $options)); - $this->assertEquals( - array(array('b', 7), array('c', 12)), - $this->redis->zrange('zsetc', 0, -1, 'withscores') - ); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('zsetFake', 'fake'); - $test->redis->zinterstore('zsetc', 2, 'zseta', 'zsetFake'); - }); - } - - function testZsetCount() - { - $zset = RC::zsetAddAndReturn($this->redis, 'zset', RC::getZSetArray()); - - $this->assertEquals(0, $this->redis->zcount('zset', 50, 100)); - $this->assertEquals(6, $this->redis->zcount('zset', -100, 100)); - $this->assertEquals(3, $this->redis->zcount('zset', 10, 20)); - $this->assertEquals(2, $this->redis->zcount('zset', "(10", 20)); - $this->assertEquals(1, $this->redis->zcount('zset', 10, "(20")); - $this->assertEquals(0, $this->redis->zcount('zset', "(10", "(20")); - $this->assertEquals(3, $this->redis->zcount('zset', "(0", "(30")); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->zcount('foo', 0, 0); - }); - } - - function testZsetCardinality() - { - $zset = RC::zsetAddAndReturn($this->redis, 'zset', RC::getZSetArray()); - - $this->assertEquals(count($zset), $this->redis->zcard('zset')); - - $this->redis->zrem('zset', 'a'); - $this->assertEquals(count($zset) - 1, $this->redis->zcard('zset')); - - // empty zset - $this->redis->zadd('zsetB', 0, 'a'); - $this->redis->zrem('zsetB', 'a'); - $this->assertEquals(0, $this->redis->zcard('setB')); - - // non-existing zset - $this->assertEquals(0, $this->redis->zcard('zsetDoesNotExist')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->zcard('foo'); - }); - } - - function testZsetScore() - { - $zset = RC::zsetAddAndReturn($this->redis, 'zset', RC::getZSetArray()); - - $this->assertEquals(-10, $this->redis->zscore('zset', 'a')); - $this->assertEquals(10, $this->redis->zscore('zset', 'c')); - $this->assertEquals(20, $this->redis->zscore('zset', 'e')); - - $this->assertNull($this->redis->zscore('zset', 'x')); - $this->assertNull($this->redis->zscore('zsetDoesNotExist', 'a')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->zscore('foo', 'bar'); - }); - } - - function testZsetRemoveRangeByScore() - { - $zset = RC::zsetAddAndReturn($this->redis, 'zset', RC::getZSetArray()); - - $this->assertEquals(2, $this->redis->zremrangebyscore('zset', -10, 0)); - $this->assertEquals( - array('c', 'd', 'e', 'f'), - $this->redis->zrange('zset', 0, -1) - ); - - $this->assertEquals(1, $this->redis->zremrangebyscore('zset', 10, 10)); - $this->assertEquals( - array('d', 'e', 'f'), - $this->redis->zrange('zset', 0, -1) - ); - - $this->assertEquals(0, $this->redis->zremrangebyscore('zset', 100, 100)); - - $this->assertEquals(3, $this->redis->zremrangebyscore('zset', 0, 100)); - $this->assertEquals(0, $this->redis->zremrangebyscore('zset', 0, 100)); - - $this->assertEquals(0, $this->redis->zremrangebyscore('zsetDoesNotExist', 0, 100)); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->zremrangebyscore('foo', 0, 0); - }); - } - - function testZsetRank() - { - $zset = RC::zsetAddAndReturn($this->redis, 'zset', RC::getZSetArray()); - - $this->assertEquals(0, $this->redis->zrank('zset', 'a')); - $this->assertEquals(1, $this->redis->zrank('zset', 'b')); - $this->assertEquals(4, $this->redis->zrank('zset', 'e')); - - $this->redis->zrem('zset', 'd'); - $this->assertEquals(3, $this->redis->zrank('zset', 'e')); - - $this->assertNull($this->redis->zrank('zset', 'x')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->zrank('foo', 'a'); - }); - } - - function testZsetReverseRank() - { - $zset = RC::zsetAddAndReturn($this->redis, 'zset', RC::getZSetArray()); - - $this->assertEquals(5, $this->redis->zrevrank('zset', 'a')); - $this->assertEquals(4, $this->redis->zrevrank('zset', 'b')); - $this->assertEquals(1, $this->redis->zrevrank('zset', 'e')); - - $this->redis->zrem('zset', 'e'); - $this->assertEquals(1, $this->redis->zrevrank('zset', 'd')); - - $this->assertNull($this->redis->zrevrank('zset', 'x')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->zrevrank('foo', 'a'); - }); - } - - function testZsetRemoveRangeByRank() - { - RC::zsetAddAndReturn($this->redis, 'zseta', RC::getZSetArray()); - - $this->assertEquals(3, $this->redis->zremrangebyrank('zseta', 0, 2)); - $this->assertEquals( - array('d', 'e', 'f'), - $this->redis->zrange('zseta', 0, -1) - ); - - $this->assertEquals(1, $this->redis->zremrangebyrank('zseta', 0, 0)); - $this->assertEquals( - array('e', 'f'), - $this->redis->zrange('zseta', 0, -1) - ); - - RC::zsetAddAndReturn($this->redis, 'zsetb', RC::getZSetArray()); - $this->assertEquals(3, $this->redis->zremrangebyrank('zsetb', -3, -1)); - $this->assertEquals( - array('a', 'b', 'c'), - $this->redis->zrange('zsetb', 0, -1) - ); - - $this->assertEquals(1, $this->redis->zremrangebyrank('zsetb', -1, -1)); - $this->assertEquals( - array('a', 'b'), - $this->redis->zrange('zsetb', 0, -1) - ); - - $this->assertEquals(2, $this->redis->zremrangebyrank('zsetb', -2, 1)); - $this->assertEquals( - array(), - $this->redis->zrange('zsetb', 0, -1) - ); - $this->assertFalse($this->redis->exists('zsetb')); - - $this->assertEquals(0, $this->redis->zremrangebyrank('zsetc', 0, 0)); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->zremrangebyrank('foo', 0, 1); - }); - } - - /* commands operating on hashes */ - - function testHashSet() - { - $this->assertTrue($this->redis->hset('metavars', 'foo', 'bar')); - $this->assertTrue($this->redis->hset('metavars', 'hoge', 'piyo')); - $this->assertEquals('bar', $this->redis->hget('metavars', 'foo')); - $this->assertEquals('piyo', $this->redis->hget('metavars', 'hoge')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('test', 'foobar'); - $test->redis->hset('test', 'hoge', 'piyo'); - }); - } - - function testHashGet() - { - $this->assertTrue($this->redis->hset('metavars', 'foo', 'bar')); - $this->assertEquals('bar', $this->redis->hget('metavars', 'foo')); - - $this->assertEquals('bar', $this->redis->hget('metavars', 'foo')); - $this->assertNull($this->redis->hget('metavars', 'hoge')); - $this->assertNull($this->redis->hget('hashDoesNotExist', 'field')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->rpush('metavars', 'foo'); - $test->redis->hget('metavars', 'foo'); - }); - } - - function testHashExists() - { - $this->assertTrue($this->redis->hset('metavars', 'foo', 'bar')); - $this->assertTrue($this->redis->hexists('metavars', 'foo')); - $this->assertFalse($this->redis->hexists('metavars', 'hoge')); - $this->assertFalse($this->redis->hexists('hashDoesNotExist', 'field')); - } - - function testHashDelete() - { - $this->assertTrue($this->redis->hset('metavars', 'foo', 'bar')); - $this->assertTrue($this->redis->hexists('metavars', 'foo')); - $this->assertTrue($this->redis->hdel('metavars', 'foo')); - $this->assertFalse($this->redis->hexists('metavars', 'foo')); - - $this->assertFalse($this->redis->hdel('metavars', 'hoge')); - $this->assertFalse($this->redis->hdel('hashDoesNotExist', 'field')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->hdel('foo', 'field'); - }); - } - - function testHashLength() - { - $this->assertTrue($this->redis->hset('metavars', 'foo', 'bar')); - $this->assertTrue($this->redis->hset('metavars', 'hoge', 'piyo')); - $this->assertTrue($this->redis->hset('metavars', 'foofoo', 'barbar')); - $this->assertTrue($this->redis->hset('metavars', 'hogehoge', 'piyopiyo')); - - $this->assertEquals(4, $this->redis->hlen('metavars')); - $this->assertEquals(0, $this->redis->hlen('hashDoesNotExist')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->hlen('foo'); - }); - } - - function testHashSetPreserve() - { - $this->assertTrue($this->redis->hsetnx('metavars', 'foo', 'bar')); - $this->assertFalse($this->redis->hsetnx('metavars', 'foo', 'barbar')); - $this->assertEquals('bar', $this->redis->hget('metavars', 'foo')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('test', 'foobar'); - $test->redis->hsetnx('test', 'hoge', 'piyo'); - }); - } - - function testHashSetAndGetMultiple() - { - $hashKVs = array('foo' => 'bar', 'hoge' => 'piyo'); - - // key=>value pairs via array instance - $this->assertTrue($this->redis->hmset('metavars', $hashKVs)); - $multiRet = $this->redis->hmget('metavars', array_keys($hashKVs)); - $this->assertEquals($hashKVs, array_combine(array_keys($hashKVs), array_values($multiRet))); - - // key=>value pairs via function arguments - $this->redis->del('metavars'); - $this->assertTrue($this->redis->hmset('metavars', 'foo', 'bar', 'hoge', 'piyo')); - $this->assertEquals(array('bar', 'piyo'), $this->redis->hmget('metavars', 'foo', 'hoge')); - } - - function testHashIncrementBy() - { - // test subsequent increment commands - $this->assertEquals(10, $this->redis->hincrby('hash', 'counter', 10)); - $this->assertEquals(20, $this->redis->hincrby('hash', 'counter', 10)); - $this->assertEquals(0, $this->redis->hincrby('hash', 'counter', -20)); - - RC::testForServerException($this, RC::EXCEPTION_HASH_VALNOTINT, function($test) { - $test->redis->hset('hash', 'field', 'stringvalue'); - $test->redis->hincrby('hash', 'field', 10); - }); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->hincrby('foo', 'bar', 1); - }); - } - - function testHashKeys() - { - $hashKVs = array('foo' => 'bar', 'hoge' => 'piyo'); - $this->assertTrue($this->redis->hmset('metavars', $hashKVs)); - - $this->assertEquals(array_keys($hashKVs), $this->redis->hkeys('metavars')); - $this->assertEquals(array(), $this->redis->hkeys('hashDoesNotExist')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->hkeys('foo'); - }); - } - - function testHashValues() - { - $hashKVs = array('foo' => 'bar', 'hoge' => 'piyo'); - $this->assertTrue($this->redis->hmset('metavars', $hashKVs)); - - $this->assertEquals(array_values($hashKVs), $this->redis->hvals('metavars')); - $this->assertEquals(array(), $this->redis->hvals('hashDoesNotExist')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->hvals('foo'); - }); - } - - function testHashGetAll() - { - $hashKVs = array('foo' => 'bar', 'hoge' => 'piyo'); - $this->assertTrue($this->redis->hmset('metavars', $hashKVs)); - - $this->assertEquals($hashKVs, $this->redis->hgetall('metavars')); - $this->assertEquals(array(), $this->redis->hgetall('hashDoesNotExist')); - - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->hgetall('foo'); - }); - } - - /* multiple databases handling commands */ - - function testSelectDatabase() - { - $this->assertTrue($this->redis->select(0)); - $this->assertTrue($this->redis->select(RC::DEFAULT_DATABASE)); - - RC::testForServerException($this, RC::EXCEPTION_INVALID_DB_IDX, function($test) { - $test->redis->select(32); - }); - - RC::testForServerException($this, RC::EXCEPTION_INVALID_DB_IDX, function($test) { - $test->redis->select(-1); - }); - } - - function testMove() - { - // TODO: This test sucks big time. Period. - $otherDb = 5; - $this->redis->set('foo', 'bar'); - - $this->redis->select($otherDb); - $this->redis->flushdb(); - $this->redis->select(RC::DEFAULT_DATABASE); - - $this->assertTrue($this->redis->move('foo', $otherDb)); - $this->assertFalse($this->redis->move('foo', $otherDb)); - $this->assertFalse($this->redis->move('keyDoesNotExist', $otherDb)); - - $this->redis->set('hoge', 'piyo'); - // TODO: shouldn't Redis send an EXCEPTION_INVALID_DB_IDX instead of EXCEPTION_OUT_OF_RANGE? - RC::testForServerException($this, RC::EXCEPTION_OUT_OF_RANGE, function($test) { - $test->redis->move('hoge', 32); - }); - } - - function testFlushdb() - { - $this->assertTrue($this->redis->flushdb()); - } - - /* sorting */ - - function testSort() - { - $unorderedList = RC::pushTailAndReturn($this->redis, 'unordered', array(2, 100, 3, 1, 30, 10)); - - // without parameters - $this->assertEquals(array(1, 2, 3, 10, 30, 100), $this->redis->sort('unordered')); - - // with parameter ASC/DESC - $this->assertEquals( - array(100, 30, 10, 3, 2, 1), - $this->redis->sort('unordered', array( - 'sort' => 'desc' - )) - ); - - // with parameter LIMIT - $this->assertEquals( - array(1, 2, 3), - $this->redis->sort('unordered', array( - 'limit' => array(0, 3) - )) - ); - $this->assertEquals( - array(10, 30), - $this->redis->sort('unordered', array( - 'limit' => array(3, 2) - )) - ); - - // with parameter ALPHA - $this->assertEquals( - array(1, 10, 100, 2, 3, 30), - $this->redis->sort('unordered', array( - 'alpha' => true - )) - ); - - // with combined parameters - $this->assertEquals( - array(30, 10, 3, 2), - $this->redis->sort('unordered', array( - 'alpha' => false, - 'sort' => 'desc', - 'limit' => array(1, 4) - )) - ); - - // with parameter ALPHA - $this->assertEquals( - array(1, 10, 100, 2, 3, 30), - $this->redis->sort('unordered', array( - 'alpha' => true - )) - ); - - // with parameter STORE - $this->assertEquals( - count($unorderedList), - $this->redis->sort('unordered', array( - 'store' => 'ordered' - )) - ); - $this->assertEquals(array(1, 2, 3, 10, 30, 100), $this->redis->lrange('ordered', 0, -1)); - - // with parameter GET - $this->redis->rpush('uids', 1003); - $this->redis->rpush('uids', 1001); - $this->redis->rpush('uids', 1002); - $this->redis->rpush('uids', 1000); - $sortget = array( - 'uid:1000' => 'foo', 'uid:1001' => 'bar', - 'uid:1002' => 'hoge', 'uid:1003' => 'piyo' - ); - $this->redis->mset($sortget); - $this->assertEquals( - array_values($sortget), - $this->redis->sort('uids', array('get' => 'uid:*')) - ); - - // wrong type - RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function($test) { - $test->redis->set('foo', 'bar'); - $test->redis->sort('foo'); - }); - } - - /* remote server control commands */ - - function testInfo() - { - $serverInfo = $this->redis->info(); - - $this->assertInternalType('array', $serverInfo); - $this->assertNotNull($serverInfo['redis_version']); - $this->assertGreaterThan(0, $serverInfo['uptime_in_seconds']); - $this->assertGreaterThan(0, $serverInfo['total_connections_received']); - } - - function testSlaveOf() - { - $masterHost = 'www.google.com'; - $masterPort = 80; - - $this->assertTrue($this->redis->slaveof($masterHost, $masterPort)); - - // slave of NO ONE, the implicit way - $this->assertTrue($this->redis->slaveof()); - - // slave of NO ONE, the explicit way - $this->assertTrue($this->redis->slaveof('NO ONE')); - } - - /* persistence control commands */ - - function testSave() - { - $this->assertTrue($this->redis->save()); - } - - function testBackgroundSave() - { - $this->assertTrue($this->redis->bgsave()); - sleep(1); - } - - function testBackgroundRewriteAppendOnlyFile() - { - $this->assertTrue($this->redis->bgrewriteaof()); - } - - function testLastSave() - { - $this->assertGreaterThan(0, $this->redis->lastsave()); - } -} diff --git a/tests/PHPUnit/ArrayHasSameValuesConstraint.php b/tests/PHPUnit/ArrayHasSameValuesConstraint.php new file mode 100644 index 00000000..8fa3d3e7 --- /dev/null +++ b/tests/PHPUnit/ArrayHasSameValuesConstraint.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use \PHPUnit_Framework_Constraint; +use \PHPUnit_Framework_ExpectationFailedException; + +/** + * Constraint that accepts arrays with the same elements but different order. + */ +class ArrayHasSameValuesConstraint extends PHPUnit_Framework_Constraint +{ + protected $array; + + /** + * @param array $array + */ + public function __construct($array) + { + $this->array = $array; + } + + /** + * {@inheritdoc} + */ + public function evaluate($other) + { + if (count($this->array) !== count($other)) { + throw new PHPUnit_Framework_ExpectationFailedException('Failed asserting that two arrays have the same elements.'); + } + if (array_diff($this->array, $other)) { + throw new PHPUnit_Framework_ExpectationFailedException('Failed asserting that two arrays have the same elements.'); + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function toString() + { + return 'two arrays have the same elements.'; + } +} \ No newline at end of file diff --git a/tests/PHPUnit/CommandTestCase.php b/tests/PHPUnit/CommandTestCase.php new file mode 100644 index 00000000..0a144910 --- /dev/null +++ b/tests/PHPUnit/CommandTestCase.php @@ -0,0 +1,174 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +use Predis\Client; +use Predis\Profiles\ServerProfile; +use Predis\Profiles\IServerProfile; + +/** + * + */ +abstract class CommandTestCase extends StandardTestCase +{ + /** + * Returns the expected command. + * + * @return ICommand|string Instance or FQN of the expected command. + */ + protected abstract function getExpectedCommand(); + + /** + * Returns the expected command ID. + * + * @return string + */ + protected abstract function getExpectedId(); + + /** + * Returns a new command instance. + * + * @return ICommand + */ + protected function getCommand() + { + $command = $this->getExpectedCommand(); + + return $command instanceof ICommand ? $command : new $command(); + } + + /** + * Return the server profile used during the tests. + * + * @return IServerProfile + */ + protected function getProfile() + { + return ServerProfile::get(REDIS_SERVER_VERSION); + } + + /** + * Returns a new client instance. + * + * @param Boolean $connect Flush selected database before returning the client. + * @return Client + */ + protected function getClient($flushdb = true) + { + $profile = $this->getProfile(); + + if (!$profile->supportsCommand($id = $this->getExpectedId())) { + $this->markTestSkipped("The profile {$profile->getVersion()} does not support command {$id}"); + } + + $parameters = array( + 'host' => REDIS_SERVER_HOST, + 'port' => REDIS_SERVER_PORT, + ); + + $options = array( + 'profile' => $profile + ); + + $client = new Client($parameters, $options); + $client->connect(); + $client->select(REDIS_SERVER_DBNUM); + + if ($flushdb) { + $client->flushdb(); + } + + return $client; + } + + /** + * Returns wether the command is prefixable or not. + * + * @return Boolean + */ + protected function isPrefixable() + { + return $this->getCommand() instanceof IPrefixable; + } + + /** + * Returns a new command instance with the specified arguments. + * + * @param ... List of arguments for the command. + * @return ICommand + */ + protected function getCommandWithArguments(/* arguments */) + { + return $this->getCommandWithArgumentsArray(func_get_args()); + } + + /** + * Returns a new command instance with the specified arguments. + * + * @param array $arguments Arguments for the command. + * @return ICommand + */ + protected function getCommandWithArgumentsArray(Array $arguments) + { + $command = $this->getCommand(); + $command->setArguments($arguments); + + return $command; + } + + /** + * Sleep the test case with microseconds resolution. + * + * @param float $seconds Seconds to sleep. + */ + protected function sleep($seconds) + { + usleep($seconds * 1000000); + } + + /** + * Asserts that two arrays have the same values, even if with different order. + * + * @param Array $expected Expected array. + * @param Array $actual Actual array. + */ + protected function assertSameValues(Array $expected, Array $actual) + { + $this->assertThat($expected, new \ArrayHasSameValuesConstraint($actual)); + } + + /** + * @group disconnected + */ + public function testCommandId() + { + $command = $this->getCommand(); + + $this->assertInstanceOf('Predis\Commands\ICommand', $command); + $this->assertEquals($this->getExpectedId(), $command->getId()); + } + + /** + * @group disconnected + */ + public function testRawArguments() + { + $expected = array('1st', '2nd', '3rd', '4th'); + + $command = $this->getCommand(); + $command->setRawArguments($expected); + + $this->assertSame($expected, $command->getArguments()); + } +} diff --git a/tests/PHPUnit/ConnectionTestCase.php b/tests/PHPUnit/ConnectionTestCase.php new file mode 100644 index 00000000..fa83edc3 --- /dev/null +++ b/tests/PHPUnit/ConnectionTestCase.php @@ -0,0 +1,387 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Network; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +use Predis\ConnectionParameters; +use Predis\Profiles\ServerProfile; + +/** + * @group realm-network + */ +abstract class ConnectionTestCase extends StandardTestCase +{ + /** + * @group disconnected + * @group slow + * @expectedException Predis\Network\ConnectionException + */ + public function testThrowExceptionWhenUnableToConnect() + { + $parameters = array('host' => '169.254.10.10', 'connection_timeout' => 0.5); + $connection = $this->getConnection($profile, false, $parameters); + $connection->executeCommand($this->getProfile()->createCommand('ping')); + } + + // ******************************************************************** // + // ---- INTEGRATION TESTS --------------------------------------------- // + // ******************************************************************** // + + /** + * @group connected + */ + public function testConnectForcesConnection() + { + $connection = $this->getConnection(); + + $this->assertFalse($connection->isConnected()); + $connection->connect(); + $this->assertTrue($connection->isConnected()); + } + + /** + * @group connected + * @expectedException Predis\ClientException + * @expectedExceptionMessage Connection already estabilished + */ + public function testThrowsExceptionOnConnectWhenAlreadyConnected() + { + $connection = $this->getConnection(); + + $connection->connect(); + $connection->connect(); + } + + /** + * @group connected + */ + public function testDisconnectForcesDisconnection() + { + $connection = $this->getConnection(); + + $connection->connect(); + $this->assertTrue($connection->isConnected()); + + $connection->disconnect(); + $this->assertFalse($connection->isConnected()); + } + + /** + * @group disconnected + */ + public function testDoesNotThrowExceptionOnDisconnectWhenAlreadyDisconnected() + { + $connection = $this->getConnection(); + + $this->assertFalse($connection->isConnected()); + $connection->disconnect(); + $this->assertFalse($connection->isConnected()); + } + + /** + * @group connected + */ + public function testGetResourceForcesConnection() + { + $connection = $this->getConnection(); + + $this->assertFalse($connection->isConnected()); + $this->assertInternalType('resource', $connection->getResource()); + $this->assertTrue($connection->isConnected()); + } + + /** + * @group connected + */ + public function testSendingCommandForcesConnection() + { + $connection = $this->getConnection($profile); + $cmdPing = $profile->createCommand('ping'); + + $this->assertTrue($connection->executeCommand($cmdPing)); + $this->assertTrue($connection->isConnected()); + } + + /** + * @group connected + */ + public function testExecutesCommandOnServer() + { + $connection = $this->getConnection($profile); + + $cmdPing = $this->getMock($profile->getCommandClass('ping'), array('parseResponse')); + $cmdPing->expects($this->once()) + ->method('parseResponse') + ->with('PONG') + ->will($this->returnValue(true)); + + $this->assertTrue($connection->executeCommand($cmdPing)); + } + + /** + * @group connected + */ + public function testWritesCommandToServer() + { + $connection = $this->getConnection($profile); + + $cmdPing = $this->getMock($profile->getCommandClass('ping'), array('parseResponse')); + $cmdPing->expects($this->never()) + ->method('parseResponse'); + + $connection->writeCommand($cmdPing); + $connection->disconnect(); + } + + /** + * @group connected + */ + public function testReadsCommandFromServer() + { + $connection = $this->getConnection($profile); + + $cmdPing = $this->getMock($profile->getCommandClass('ping'), array('parseResponse')); + $cmdPing->expects($this->once()) + ->method('parseResponse') + ->with('PONG') + ->will($this->returnValue(true)); + + $connection->writeCommand($cmdPing); + $this->assertTrue($connection->readResponse($cmdPing)); + } + + /** + * @group connected + */ + public function testIsAbleToWriteMultipleCommandsAndReadThemBackForPipelining() + { + $connection = $this->getConnection($profile); + + $cmdPing = $this->getMock($profile->getCommandClass('ping'), array('parseResponse')); + $cmdPing->expects($this->once()) + ->method('parseResponse') + ->with('PONG') + ->will($this->returnValue(true)); + + $cmdEcho = $this->getMock($profile->getCommandClass('echo'), array('parseResponse')); + $cmdEcho->setArguments(array('ECHOED')); + $cmdEcho->expects($this->once()) + ->method('parseResponse') + ->with('ECHOED') + ->will($this->returnValue('ECHOED')); + + $connection = $this->getConnection(); + + $connection->writeCommand($cmdPing); + $connection->writeCommand($cmdEcho); + + $this->assertTrue($connection->readResponse($cmdPing)); + $this->assertSame('ECHOED', $connection->readResponse($cmdEcho)); + } + + /** + * @group connected + */ + public function testSendsInitializationCommandsOnConnection() + { + $connection = $this->getConnection($profile, true); + + $cmdPing = $this->getMock($profile->getCommandClass('ping'), array('parseResponse')); + $cmdPing->expects($this->once()) + ->method('parseResponse') + ->with('PONG') + ->will($this->returnValue(true)); + + $cmdEcho = $this->getMock($profile->getCommandClass('echo'), array('parseResponse')); + $cmdEcho->setArguments(array('ECHOED')); + $cmdEcho->expects($this->once()) + ->method('parseResponse') + ->with('ECHOED') + ->will($this->returnValue('ECHOED')); + + $connection->pushInitCommand($cmdPing); + $connection->pushInitCommand($cmdEcho); + + $connection->connect(); + } + + /** + * @group connected + */ + public function testReadsStatusReplies() + { + $connection = $this->getConnection($profile, true); + + $connection->writeCommand($profile->createCommand('set', array('foo', 'bar'))); + $this->assertTrue($connection->read()); + + $connection->writeCommand($profile->createCommand('ping')); + $this->assertSame('PONG', $connection->read()); + + $connection->writeCommand($profile->createCommand('multi')); + $connection->writeCommand($profile->createCommand('ping')); + $this->assertTrue($connection->read()); + $this->assertInstanceOf('Predis\ResponseQueued', $connection->read()); + } + + /** + * @group connected + */ + public function testReadsBulkReplies() + { + $connection = $this->getConnection($profile, true); + + $connection->executeCommand($profile->createCommand('set', array('foo', 'bar'))); + + $connection->writeCommand($profile->createCommand('get', array('foo'))); + $this->assertSame('bar', $connection->read()); + + $connection->writeCommand($profile->createCommand('get', array('hoge'))); + $this->assertNull($connection->read()); + } + + /** + * @group connected + */ + public function testReadsIntegerReplies() + { + $connection = $this->getConnection($profile, true); + + $connection->executeCommand($profile->createCommand('rpush', array('metavars', 'foo', 'hoge', 'lol'))); + $connection->writeCommand($profile->createCommand('llen', array('metavars'))); + + $this->assertSame(3, $connection->read()); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testReadsErrorRepliesAsExceptions() + { + $connection = $this->getConnection($profile, true, array('throw_errors' => true)); + + $connection->executeCommand($profile->createCommand('set', array('foo', 'bar'))); + $connection->writeCommand($profile->createCommand('rpush', array('foo', 'baz'))); + + $connection->read(); + } + + /** + * @group connected + */ + public function testReadsErrorRepliesAsResponseErrorObjects() + { + $connection = $this->getConnection($profile, true, array('throw_errors' => false)); + + $connection->executeCommand($profile->createCommand('set', array('foo', 'bar'))); + $connection->writeCommand($profile->createCommand('rpush', array('foo', 'baz'))); + + $this->assertInstanceOf('Predis\ResponseError', $error = $connection->read()); + $this->assertSame('ERR Operation against a key holding the wrong kind of value', $error->getMessage()); + } + + /** + * @group connected + */ + public function testReadsMultibulkRepliesAsArrays() + { + $connection = $this->getConnection($profile, true); + + $connection->executeCommand($profile->createCommand('rpush', array('metavars', 'foo', 'hoge', 'lol'))); + $connection->writeCommand($profile->createCommand('lrange', array('metavars', 0, -1))); + + $this->assertSame(array('foo', 'hoge', 'lol'), $connection->read()); + } + + /** + * @group connected + * @group slow + * @expectedException Predis\Network\ConnectionException + * @expectedExceptionMessage Connection timed out + */ + public function testThrowsExceptionOnConnectionTimeout() + { + $connection = $this->getConnection($_, false, array('host' => '169.254.10.10', 'connection_timeout' => 0.5)); + + $connection->connect(); + } + + /** + * @group connected + * @group slow + * @expectedException Predis\Network\ConnectionException + */ + public function testThrowsExceptionOnReadWriteTimeout() + { + $connection = $this->getConnection($profile, true, array('read_write_timeout' => 0.5)); + + $connection->executeCommand($profile->createCommand('brpop', array('foo', 3))); + } + + // ******************************************************************** // + // ---- HELPER METHODS ------------------------------------------------ // + // ******************************************************************** // + + /** + * Returns a named array with the default connection parameters and their values. + * + * @return Array Default connection parameters. + */ + protected function getDefaultParametersArray() + { + return array( + 'scheme' => 'tcp', + 'host' => REDIS_SERVER_HOST, + 'port' => REDIS_SERVER_PORT, + 'database' => REDIS_SERVER_DBNUM, + 'read_write_timeout' => 2, + ); + } + + /** + * Returns a new instance of connection parameters. + * + * @param array $additional Additional connection parameters. + * @return ConnectionParameters Default connection parameters. + */ + protected function getParameters($additional = array()) + { + $parameters = array_merge($this->getDefaultParametersArray(), $additional); + $parameters = new ConnectionParameters($parameters); + + return $parameters; + } + + /** + * Returns a new instance of server profile. + * + * @param array $additional Additional connection parameters. + * @return ServerProfile + */ + protected function getProfile($version = null) + { + return ServerProfile::get($version ?: REDIS_SERVER_VERSION); + } + + /** + * Returns a new instance of a connection instance. + * + * @param ServerProfile $profile Reference to the server profile instance. + * @param Boolean $initialize Push default initialization commands (SELECT and FLUSHDB). + * @param array $parameters Additional connection parameters. + * @return StreamConnection + */ + protected abstract function getConnection(&$profile = null, $initialize = false, Array $parameters = array()); +} diff --git a/tests/PHPUnit/DistributionStrategyTestCase.php b/tests/PHPUnit/DistributionStrategyTestCase.php new file mode 100644 index 00000000..3cd1623c --- /dev/null +++ b/tests/PHPUnit/DistributionStrategyTestCase.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Distribution; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * + */ +abstract class DistributionStrategyTestCase extends StandardTestCase +{ + /** + * Returns a new instance of the tested distributor. + * + * @return Predis\Distribution\IDistributionStrategy + */ + protected abstract function getDistributorInstance(); + + /** + * Returns a list of nodes from the hashring. + * + * @param IDistributionStrategy $ring Hashring instance. + * @param int $iterations Number of nodes to fetch. + * @return array Nodes from the hashring. + */ + protected function getNodes(IDistributionStrategy $ring, $iterations = 10) + { + $nodes = array(); + + for ($i = 0; $i < $iterations; $i++) { + $key = $ring->generateKey($i * $i); + $nodes[] = $ring->get($key); + } + + return $nodes; + } + + /** + * @group disconnected + */ + public function testEmptyRingThrowsException() + { + $this->setExpectedException('Predis\Distribution\EmptyRingException'); + + $ring = $this->getDistributorInstance(); + $ring->get('nodekey'); + } + + /** + * @group disconnected + */ + public function testRemoveOnEmptyRingDoesNotThrowException() + { + $ring = $this->getDistributorInstance(); + + $this->assertNull($ring->remove('node')); + } +} diff --git a/tests/PHPUnit/ServerVersionTestCase.php b/tests/PHPUnit/ServerVersionTestCase.php new file mode 100644 index 00000000..5e19bad7 --- /dev/null +++ b/tests/PHPUnit/ServerVersionTestCase.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Profiles; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * + */ +abstract class ServerVersionTestCase extends StandardTestCase +{ + /** + * Returns a new instance of the tested profile. + * + * @return Predis\Profiles\IServerProfile + */ + protected abstract function getProfileInstance(); + + /** + * Returns the expected version string for the tested profile. + * + * @return string Version string. + */ + protected abstract function getExpectedVersion(); + + /** + * Returns the expected list of commands supported by the tested profile. + * + * @return array List of supported commands. + */ + protected abstract function getExpectedCommands(); + + /** + * Returns the list of commands supported by the current + * server profile. + * + * @param IServerProfile $profile Server profile instance. + * @return array + */ + protected function getCommands(IServerProfile $profile) + { + $commands = $profile->getSupportedCommands(); + + return array_keys($commands); + } + + /** + * @group disconnected + */ + public function testGetVersion() + { + $profile = $this->getProfileInstance(); + + $this->assertEquals($this->getExpectedVersion(), $profile->getVersion()); + } + + /** + * @group disconnected + */ + public function testSupportedCommands() + { + $profile = $this->getProfileInstance(); + $expected = $this->getExpectedCommands(); + $commands = $this->getCommands($profile); + + $this->assertSame($expected, $commands); + } +} diff --git a/tests/Predis/ClientExceptionTest.php b/tests/Predis/ClientExceptionTest.php new file mode 100644 index 00000000..13e6c94e --- /dev/null +++ b/tests/Predis/ClientExceptionTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * + */ +class ClientExceptionTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testExceptionMessage() + { + $message = 'This is a client exception.'; + + $this->setExpectedException('Predis\ClientException', $message); + + throw new ClientException($message); + } + + /** + * @group disconnected + */ + public function testExceptionClass() + { + $exception = new ClientException(); + + $this->assertInstanceOf('Predis\ClientException', $exception); + $this->assertInstanceOf('Predis\PredisException', $exception); + } +} diff --git a/tests/Predis/ClientTest.php b/tests/Predis/ClientTest.php new file mode 100644 index 00000000..6628e715 --- /dev/null +++ b/tests/Predis/ClientTest.php @@ -0,0 +1,647 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +use Predis\Profiles\ServerProfile; +use Predis\Network\PredisCluster; + +/** + * + */ +class ClientTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testConstructorWithoutArguments() + { + $client = new Client(); + + $connection = $client->getConnection(); + $this->assertInstanceOf('Predis\Network\IConnectionSingle', $connection); + + $parameters = $connection->getParameters(); + $this->assertSame($parameters->host, '127.0.0.1'); + $this->assertSame($parameters->port, 6379); + + $options = $client->getOptions(); + $this->assertSame($options->profile->getVersion(), ServerProfile::getDefault()->getVersion()); + + $this->assertFalse($client->isConnected()); + } + + /** + * @group disconnected + */ + public function testConstructorWithNullArgument() + { + $client = new Client(null); + + $connection = $client->getConnection(); + $this->assertInstanceOf('Predis\Network\IConnectionSingle', $connection); + + $parameters = $connection->getParameters(); + $this->assertSame($parameters->host, '127.0.0.1'); + $this->assertSame($parameters->port, 6379); + + $options = $client->getOptions(); + $this->assertSame($options->profile->getVersion(), ServerProfile::getDefault()->getVersion()); + + $this->assertFalse($client->isConnected()); + } + + /** + * @group disconnected + */ + public function testConstructorWithNullAndNullArguments() + { + $client = new Client(null, null); + + $connection = $client->getConnection(); + $this->assertInstanceOf('Predis\Network\IConnectionSingle', $connection); + + $parameters = $connection->getParameters(); + $this->assertSame($parameters->host, '127.0.0.1'); + $this->assertSame($parameters->port, 6379); + + $options = $client->getOptions(); + $this->assertSame($options->profile->getVersion(), ServerProfile::getDefault()->getVersion()); + + $this->assertFalse($client->isConnected()); + } + + /** + * @group disconnected + */ + public function testConstructorWithArrayArgument() + { + $client = new Client($arg1 = array('host' => 'localhost', 'port' => 7000)); + + $parameters = $client->getConnection()->getParameters(); + $this->assertSame($parameters->host, $arg1['host']); + $this->assertSame($parameters->port, $arg1['port']); + } + + /** + * @group disconnected + */ + public function testConstructorWithArrayOfArrayArgument() + { + $arg1 = array( + array('host' => 'localhost', 'port' => 7000), + array('host' => 'localhost', 'port' => 7001), + ); + + $client = new Client($arg1); + + $this->assertInstanceOf('Predis\Network\IConnectionCluster', $client->getConnection()); + } + + /** + * @group disconnected + */ + public function testConstructorWithStringArgument() + { + $client = new Client('tcp://localhost:7000'); + + $parameters = $client->getConnection()->getParameters(); + $this->assertSame($parameters->host, 'localhost'); + $this->assertSame($parameters->port, 7000); + } + + /** + * @group disconnected + */ + public function testConstructorWithArrayOfStringArgument() + { + $client = new Client($arg1 = array('tcp://localhost:7000', 'tcp://localhost:7001')); + + $this->assertInstanceOf('Predis\Network\IConnectionCluster', $client->getConnection()); + } + + /** + * @group disconnected + */ + public function testConstructorWithArrayOfConnectionsArgument() + { + $connection1 = $this->getMock('Predis\Network\IConnectionSingle'); + $connection2 = $this->getMock('Predis\Network\IConnectionSingle'); + + $client = new Client(array($connection1, $connection2)); + + $this->assertInstanceOf('Predis\Network\IConnectionCluster', $cluster = $client->getConnection()); + $this->assertSame($connection1, $cluster->getConnectionById(0)); + $this->assertSame($connection2, $cluster->getConnectionById(1)); + } + + /** + * @group disconnected + */ + public function testConstructorWithConnectionArgument() + { + $factory = new ConnectionFactory(); + $connection = $factory->create('tcp://localhost:7000'); + + $client = new Client($connection); + + $this->assertInstanceOf('Predis\Network\IConnectionSingle', $client->getConnection()); + $this->assertSame($connection, $client->getConnection()); + + $parameters = $client->getConnection()->getParameters(); + $this->assertSame($parameters->host, 'localhost'); + $this->assertSame($parameters->port, 7000); + } + + /** + * @group disconnected + */ + public function testConstructorWithClusterArgument() + { + $cluster = new PredisCluster(); + + $factory = new ConnectionFactory(); + $factory->createCluster($cluster, array('tcp://localhost:7000', 'tcp://localhost:7001')); + + $client = new Client($cluster); + + $this->assertInstanceOf('Predis\Network\IConnectionCluster', $client->getConnection()); + $this->assertSame($cluster, $client->getConnection()); + } + + /** + * @group disconnected + */ + public function testConstructorWithNullAndStringArgument() + { + $client = new Client(null, '2.0'); + + $this->assertSame($client->getProfile()->getVersion(), ServerProfile::get('2.0')->getVersion()); + } + + /** + * @group disconnected + */ + public function testConstructorWithNullAndProfileArgument() + { + $client = new Client(null, $arg2 = ServerProfile::get('2.0')); + + $this->assertSame($client->getProfile(), $arg2); + } + + /** + * @group disconnected + */ + public function testConstructorWithNullAndArrayArgument() + { + $factory = $this->getMock('Predis\IConnectionFactory'); + + $arg2 = array('profile' => '2.0', 'prefix' => 'prefix:', 'connections' => $factory); + $client = new Client(null, $arg2); + + $profile = $client->getProfile(); + $this->assertSame($profile->getVersion(), ServerProfile::get('2.0')->getVersion()); + $this->assertInstanceOf('Predis\Commands\Processors\KeyPrefixProcessor', $profile->getProcessor()); + $this->assertSame('prefix:', $profile->getProcessor()->getPrefix()); + + $this->assertSame($factory, $client->getConnectionFactory()); + } + + /** + * @group disconnected + */ + public function testConnectAndDisconnect() + { + $connection = $this->getMock('Predis\Network\IConnection'); + $connection->expects($this->once())->method('connect'); + $connection->expects($this->once())->method('disconnect'); + + $client = new Client($connection); + $client->connect(); + $client->disconnect(); + } + + /** + * @group disconnected + */ + public function testIsConnectedChecksConnectionState() + { + $connection = $this->getMock('Predis\Network\IConnection'); + $connection->expects($this->once())->method('isConnected'); + + $client = new Client($connection); + $client->isConnected(); + } + + /** + * @group disconnected + */ + public function testQuitIsAliasForDisconnect() + { + $connection = $this->getMock('Predis\Network\IConnection'); + $connection->expects($this->once())->method('disconnect'); + + $client = new Client($connection); + $client->quit(); + } + + /** + * @group disconnected + */ + public function testCreatesNewCommandUsingSpecifiedProfile() + { + $ping = ServerProfile::getDefault()->createCommand('ping', array()); + + $profile = $this->getMock('Predis\Profiles\IServerProfile'); + $profile->expects($this->once()) + ->method('createCommand') + ->with('ping', array()) + ->will($this->returnValue($ping)); + + $client = new Client(null, $profile); + $this->assertSame($ping, $client->createCommand('ping', array())); + } + + /** + * @group disconnected + */ + public function testExecuteCommand() + { + $ping = ServerProfile::getDefault()->createCommand('ping', array()); + + $connection= $this->getMock('Predis\Network\IConnection'); + $connection->expects($this->once()) + ->method('executeCommand') + ->with($ping) + ->will($this->returnValue(true)); + + $client = new Client($connection); + + $this->assertTrue($client->executeCommand($ping)); + } + + /** + * @group disconnected + */ + public function testExecuteCommandOnEachNode() + { + $ping = ServerProfile::getDefault()->createCommand('ping', array()); + + $connection1 = $this->getMock('Predis\Network\IConnectionSingle'); + $connection1->expects($this->once()) + ->method('executeCommand') + ->with($ping) + ->will($this->returnValue(true)); + + $connection2 = $this->getMock('Predis\Network\IConnectionSingle'); + $connection2->expects($this->once()) + ->method('executeCommand') + ->with($ping) + ->will($this->returnValue(false)); + + $client = new Client(array($connection1, $connection2)); + + $this->assertSame(array(true, false), $client->executeCommandOnShards($ping)); + } + + /** + * @group disconnected + */ + public function testExecuteCommandOnEachNodeButConnectionSingle() + { + $ping = ServerProfile::getDefault()->createCommand('ping', array()); + + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $connection->expects($this->once()) + ->method('executeCommand') + ->with($ping) + ->will($this->returnValue(true)); + + $client = new Client($connection); + + $this->assertSame(array(true), $client->executeCommandOnShards($ping)); + } + + /** + * @group disconnected + */ + public function testCallingRedisCommandExecutesInstanceOfCommand() + { + $ping = ServerProfile::getDefault()->createCommand('ping', array()); + + $connection = $this->getMock('Predis\Network\IConnection'); + $connection->expects($this->once()) + ->method('executeCommand') + ->with($this->isInstanceOf('Predis\Commands\ConnectionPing')) + ->will($this->returnValue(true)); + + $profile = $this->getMock('Predis\Profiles\IServerProfile'); + $profile->expects($this->once()) + ->method('createCommand') + ->with('ping', array()) + ->will($this->returnValue($ping)); + + $client = $this->getMock('Predis\Client', array('createCommand'), array($connection, $profile)); + + $this->assertTrue($client->ping()); + } + + /** + * @group disconnected + * @expectedException Predis\ClientException + * @expectedExceptionMessage 'invalidcommand' is not a registered Redis command + */ + public function testThrowsExceptionOnNonRegisteredRedisCommand() + { + $client = new Client(); + $client->invalidCommand(); + } + + /** + * @group disconnected + */ + public function testGetConnectionFromClusterWithAlias() + { + $client = new Client(array('tcp://host1?alias=node01', 'tcp://host2?alias=node02')); + + $this->assertInstanceOf('Predis\Network\IConnectionCluster', $cluster = $client->getConnection()); + $this->assertInstanceOf('Predis\Network\IConnectionSingle', $node01 = $client->getConnection('node01')); + $this->assertInstanceOf('Predis\Network\IConnectionSingle', $node02 = $client->getConnection('node02')); + + $this->assertSame('host1', $node01->getParameters()->host); + $this->assertSame('host2', $node02->getParameters()->host); + } + + /** + * @group disconnected + * @expectedException Predis\NotSupportedException + * @expectedExceptionMessage Retrieving connections by alias is supported only with clustered connections + */ + public function testGetConnectionWithAliasWorksOnlyWithCluster() + { + $client = new Client(); + + $client->getConnection('node01'); + } + + /** + * @group disconnected + */ + public function testPipelineWithoutArgumentsReturnsPipelineContext() + { + $client = new Client(); + + $this->assertInstanceOf('Predis\Pipeline\PipelineContext', $pipeline = $client->pipeline()); + } + + /** + * @group disconnected + */ + public function testPipelineWithArrayReturnsPipelineContextWithOptions() + { + $client = new Client(); + + $executor = $this->getMock('Predis\Pipeline\IPipelineExecutor'); + $options = array('executor' => $executor); + + $this->assertInstanceOf('Predis\Pipeline\PipelineContext', $pipeline = $client->pipeline($options)); + + $reflection = new \ReflectionProperty($pipeline, 'executor'); + $reflection->setAccessible(true); + + $this->assertSame($executor, $reflection->getValue($pipeline)); + } + + /** + * @group disconnected + */ + public function testPipelineWithCallableExecutesPipeline() + { + $callable = $this->getMock('stdClass', array('__invoke')); + $callable->expects($this->once()) + ->method('__invoke') + ->with($this->isInstanceOf('Predis\Pipeline\PipelineContext')); + + $client = new Client(); + $client->pipeline($callable); + } + + /** + * @group disconnected + */ + public function testPipelineWithArrayAndCallableExecutesPipelineWithOptions() + { + $executor = $this->getMock('Predis\Pipeline\IPipelineExecutor'); + $options = array('executor' => $executor); + + $test = $this; + $mockCallback = function($pipeline) use($executor, $test) { + $reflection = new \ReflectionProperty($pipeline, 'executor'); + $reflection->setAccessible(true); + + $test->assertSame($executor, $reflection->getValue($pipeline)); + }; + + $callable = $this->getMock('stdClass', array('__invoke')); + $callable->expects($this->once()) + ->method('__invoke') + ->with($this->isInstanceOf('Predis\Pipeline\PipelineContext')) + ->will($this->returnCallback($mockCallback)); + + $client = new Client(); + $client->pipeline($options, $callable); + } + + /** + * @group disconnected + */ + public function testPubSubWithoutArgumentsReturnsPubSubContext() + { + $client = new Client(); + + $this->assertInstanceOf('Predis\PubSub\PubSubContext', $pubsub = $client->pubSub()); + } + + /** + * @group disconnected + */ + public function testPubSubWithArrayReturnsPubSubContextWithOptions() + { + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $options = array('subscribe' => 'channel'); + + $client = new Client($connection); + + $this->assertInstanceOf('Predis\PubSub\PubSubContext', $pubsub = $client->pubSub($options)); + + $reflection = new \ReflectionProperty($pubsub, 'options'); + $reflection->setAccessible(true); + + $this->assertSame($options, $reflection->getValue($pubsub)); + } + + /** + * @group disconnected + */ + public function testPubSubWithArrayAndCallableExecutesPubSub() + { + // NOTE: we use a subscribe count of 0 in the fake message to trick + // the context and to make it think that it can be closed + // since there are no more subscriptions active. + + $message = array('subscribe', 'channel', 0); + $options = array('subscribe' => 'channel'); + + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $connection->expects($this->once()) + ->method('read') + ->will($this->returnValue($message)); + + $callable = $this->getMock('stdClass', array('__invoke')); + $callable->expects($this->once()) + ->method('__invoke'); + + $client = new Client($connection); + $client->pubSub($options, $callable); + } + + /** + * @group disconnected + */ + public function testMultiExecWithoutArgumentsReturnsMultiExecContext() + { + $client = new Client(); + + $this->assertInstanceOf('Predis\Transaction\MultiExecContext', $pubsub = $client->multiExec()); + } + + /** + * @group disconnected + */ + public function testMultiExecWithArrayReturnsMultiExecContextWithOptions() + { + $options = array('cas' => true, 'retry' => 3); + + $client = new Client(); + + $this->assertInstanceOf('Predis\Transaction\MultiExecContext', $tx = $client->multiExec($options)); + + $reflection = new \ReflectionProperty($tx, 'options'); + $reflection->setAccessible(true); + + $this->assertSame($options, $reflection->getValue($tx)); + } + + /** + * @group disconnected + */ + public function testMultiExecWithArrayAndCallableExecutesMultiExec() + { + // NOTE: we use CAS since testing the actual MULTI/EXEC context + // here is not the point. + $options = array('cas' => true, 'retry' => 3); + + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $connection->expects($this->once()) + ->method('executeCommand') + ->will($this->returnValue(new ResponseQueued())); + + $txCallback = function($tx) { $tx->ping(); }; + + $callable = $this->getMock('stdClass', array('__invoke')); + $callable->expects($this->once()) + ->method('__invoke') + ->will($this->returnCallback($txCallback)); + + $client = new Client($connection); + $client->multiExec($options, $callable); + } + + /** + * @group disconnected + */ + public function testMonitorReturnsMonitorContext() + { + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $client = new Client($connection); + + $this->assertInstanceOf('Predis\MonitorContext', $monitor = $client->monitor()); + } + + // ******************************************************************** // + // ---- HELPER METHODS ------------------------------------------------ // + // ******************************************************************** // + + /** + * Returns a named array with the default connection parameters and their values. + * + * @return Array Default connection parameters. + */ + protected function getDefaultParametersArray() + { + return array( + 'scheme' => 'tcp', + 'host' => REDIS_SERVER_HOST, + 'port' => REDIS_SERVER_PORT, + 'database' => REDIS_SERVER_DBNUM, + ); + } + + /** + * Returns a named array with the default client options and their values. + * + * @return Array Default connection parameters. + */ + protected function getDefaultOptionsArray() + { + return array( + 'profile' => REDIS_SERVER_VERSION, + ); + } + + /** + * Returns a named array with the default connection parameters merged with + * the specified additional parameters. + * + * @param Array $additional Additional connection parameters. + * @return Array Connection parameters. + */ + protected function getParametersArray(Array $additional) + { + return array_merge($this->getDefaultParametersArray(), $additional); + } + + /** + * Returns an URI string representation of the specified connection parameters. + * + * @param Array $parameters Array of connection parameters. + * @return String URI string. + */ + protected function getParametersString(Array $parameters) + { + $defaults = $this->getDefaultParametersArray(); + + $scheme = isset($parameters['scheme']) ? $parameters['scheme'] : $defaults['scheme']; + $host = isset($parameters['host']) ? $parameters['host'] : $defaults['host']; + $port = isset($parameters['port']) ? $parameters['port'] : $defaults['port']; + + unset($parameters['scheme'], $parameters['host'], $parameters['port']); + $uriString = "$scheme://$host:$port/?"; + + foreach ($parameters as $k => $v) { + $uriString .= "$k=$v&"; + } + + return $uriString; + } +} diff --git a/tests/Predis/Commands/CommandTest.php b/tests/Predis/Commands/CommandTest.php new file mode 100644 index 00000000..bc141ac6 --- /dev/null +++ b/tests/Predis/Commands/CommandTest.php @@ -0,0 +1,216 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * + */ +class CommandTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testImplementsCorrectInterface() + { + $command = $this->getMockForAbstractClass('Predis\Commands\Command'); + + $this->assertInstanceOf('Predis\Commands\ICommand', $command); + } + + /** + * @group disconnected + */ + public function testGetEmptyArguments() + { + $command = $this->getMockForAbstractClass('Predis\Commands\Command'); + + $this->assertEmpty($command->getArguments()); + } + + /** + * @group disconnected + */ + public function testSetRawArguments() + { + $arguments = array('1st', '2nd', '3rd'); + + $command = $this->getMockForAbstractClass('Predis\Commands\Command'); + $command->setRawArguments($arguments); + + $this->assertEquals($arguments, $command->getArguments()); + } + + /** + * @group disconnected + * + * @todo Since Command::filterArguments is protected we cannot set an expectation + * for it when Command::setArguments() is invoked. I wonder how we can do that. + */ + public function testSetArguments() + { + $arguments = array('1st', '2nd', '3rd'); + + $command = $this->getMockForAbstractClass('Predis\Commands\Command'); + $command->setArguments($arguments); + + $this->assertEquals($arguments, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testGetArgumentAtIndex() + { + $arguments = array('1st', '2nd', '3rd'); + + $command = $this->getMockForAbstractClass('Predis\Commands\Command'); + $command->setArguments($arguments); + + $this->assertEquals($arguments[0], $command->getArgument(0)); + $this->assertEquals($arguments[2], $command->getArgument(2)); + $this->assertNull($command->getArgument(10)); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $response = 'response-buffer'; + $command = $this->getMockForAbstractClass('Predis\Commands\Command'); + + $this->assertEquals($response, $command->parseResponse($response)); + } + + /** + * @group disconnected + * @protected + */ + public function testCheckSameHashForKeys() + { + $command = $this->getMockForAbstractClass('Predis\Commands\Command'); + + $checkSameHashForKeys = new \ReflectionMethod($command, 'checkSameHashForKeys'); + $checkSameHashForKeys->setAccessible(true); + + $this->assertTrue($checkSameHashForKeys->invoke($command, array('foo', '{foo}:bar'))); + $this->assertFalse($checkSameHashForKeys->invoke($command, array('foo', '{foo}:bar', 'foo:bar'))); + } + + /** + * @group disconnected + * @protected + */ + public function testCanBeHashed() + { + $command = $this->getMockForAbstractClass('Predis\Commands\Command'); + + $canBeHashed = new \ReflectionMethod($command, 'canBeHashed'); + $canBeHashed->setAccessible(true); + + $this->assertFalse($canBeHashed->invoke($command)); + + $command->setRawArguments(array('key')); + $this->assertTrue($canBeHashed->invoke($command)); + } + + /** + * @group disconnected + */ + public function testDoesNotReturnAnHashByDefault() + { + $distributor = $this->getMock('Predis\Distribution\INodeKeyGenerator'); + $distributor->expects($this->never())->method('generateKey'); + + $command = $this->getMockForAbstractClass('Predis\Commands\Command'); + + $command->getHash($distributor); + } + + /** + * @group disconnected + */ + public function testReturnAnHashWhenCanBeHashedAndCachesIt() + { + $key = 'key'; + $hash = "$key-hash"; + + $distributor = $this->getMock('Predis\Distribution\INodeKeyGenerator'); + $distributor->expects($this->once()) + ->method('generateKey') + ->with($key) + ->will($this->returnValue($hash)); + + $command = $this->getMockForAbstractClass('Predis\Commands\Command'); + $command->setRawArguments(array($key)); + + $this->assertEquals($hash, $command->getHash($distributor)); + + $this->assertEquals($hash, $command->getHash($distributor)); + $this->assertEquals($hash, $command->getHash($distributor)); + } + + /** + * @group disconnected + */ + public function testExtractsKeyTagsBeforeHashing() + { + $tag = 'key'; + $key = "{{$tag}}:ignore"; + $hash = "$tag-hash"; + + $distributor = $this->getMock('Predis\Distribution\INodeKeyGenerator'); + $distributor->expects($this->once()) + ->method('generateKey') + ->with($tag) + ->will($this->returnValue($hash)); + + $command = $this->getMockForAbstractClass('Predis\Commands\Command'); + $command->setRawArguments(array($key)); + + $this->assertEquals($hash, $command->getHash($distributor)); + } + + /** + * @group disconnected + */ + public function testToString() + { + $expected = 'SET key value'; + $arguments = array('key', 'value'); + + $command = $this->getMockForAbstractClass('Predis\Commands\Command'); + $command->expects($this->once())->method('getId')->will($this->returnValue('SET')); + + $command->setRawArguments($arguments); + + $this->assertEquals($expected, (string) $command); + } + + /** + * @group disconnected + */ + public function testToStringWithLongArguments() + { + $expected = 'SET key abcdefghijklmnopqrstuvwxyz012345[...]'; + $arguments = array('key', 'abcdefghijklmnopqrstuvwxyz0123456789'); + + $command = $this->getMockForAbstractClass('Predis\Commands\Command'); + $command->expects($this->once())->method('getId')->will($this->returnValue('SET')); + + $command->setRawArguments($arguments); + + $this->assertEquals($expected, (string) $command); + } +} diff --git a/tests/Predis/Commands/ConnectionAuthTest.php b/tests/Predis/Commands/ConnectionAuthTest.php new file mode 100644 index 00000000..fdc10f7e --- /dev/null +++ b/tests/Predis/Commands/ConnectionAuthTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-connection + */ +class ConnectionAuthTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ConnectionAuth'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'AUTH'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('password'); + $expected = array('password'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = null; + $expected = null; + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } +} diff --git a/tests/Predis/Commands/ConnectionEchoTest.php b/tests/Predis/Commands/ConnectionEchoTest.php new file mode 100644 index 00000000..8a61949f --- /dev/null +++ b/tests/Predis/Commands/ConnectionEchoTest.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-connection + */ +class ConnectionEchoTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ConnectionEcho'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'ECHO'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('message'); + $expected = array('message'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = 'message'; + $expected = 'message'; + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group connected + */ + public function testAlwaysReturnsThePassedMessage() + { + $redis = $this->getClient(); + + $message = 'Can you hear me?'; + + $this->assertSame($message, $redis->echo($message)); + } +} diff --git a/tests/Predis/Commands/ConnectionPingTest.php b/tests/Predis/Commands/ConnectionPingTest.php new file mode 100644 index 00000000..6f2f0462 --- /dev/null +++ b/tests/Predis/Commands/ConnectionPingTest.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-connection + */ +class ConnectionPingTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ConnectionPing'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'PING'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array(); + $expected = array(); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertTrue($command->parseResponse('PONG')); + } + + /** + * @group connected + */ + public function testAlwaysReturnsTrue() + { + $redis = $this->getClient(); + + $this->assertTrue($redis->ping()); + } +} diff --git a/tests/Predis/Commands/ConnectionQuitTest.php b/tests/Predis/Commands/ConnectionQuitTest.php new file mode 100644 index 00000000..90a0032e --- /dev/null +++ b/tests/Predis/Commands/ConnectionQuitTest.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-connection + */ +class ConnectionQuitTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ConnectionQuit'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'QUIT'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array(); + $expected = array(); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertTrue($command->parseResponse(true)); + } + + /** + * @group connected + */ + public function testReturnsTrueWhenClosingConnection() + { + $redis = $this->getClient(); + $command = $this->getCommand(); + + $this->assertTrue($redis->executeCommand($command)); + } +} diff --git a/tests/Predis/Commands/ConnectionSelectTest.php b/tests/Predis/Commands/ConnectionSelectTest.php new file mode 100644 index 00000000..da3a5254 --- /dev/null +++ b/tests/Predis/Commands/ConnectionSelectTest.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-connection + */ +class ConnectionSelectTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ConnectionSelect'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SELECT'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array(10); + $expected = array(10); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertTrue($command->parseResponse(true)); + } + + /** + * @group connected + */ + public function testCanSelectDifferentDatabase() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + + $this->assertTrue($redis->select(REDIS_SERVER_DBNUM - 1)); + $this->assertFalse($redis->exists('foo')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR invalid DB index + */ + public function testThrowsExceptionOnUnexpectedDatabase() + { + $redis = $this->getClient(); + + $redis->select(100000000); + } +} diff --git a/tests/Predis/Commands/HashDeleteTest.php b/tests/Predis/Commands/HashDeleteTest.php new file mode 100644 index 00000000..ba713e5a --- /dev/null +++ b/tests/Predis/Commands/HashDeleteTest.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-hash + */ +class HashDeleteTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\HashDelete'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'HDEL'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'field1', 'field2', 'field3'); + $expected = array('key', 'field1', 'field2', 'field3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsFieldsAsSingleArray() + { + $arguments = array('key', array('field1', 'field2', 'field3')); + $expected = array('key', 'field1', 'field2', 'field3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'field1', 'field2', 'field3'); + $expected = array('prefix:key', 'field1', 'field2', 'field3'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testDeletesSpecifiedFieldsFromHash() + { + $redis = $this->getClient(); + + $redis->hmset('metavars', 'foo', 'bar', 'hoge', 'piyo', 'lol', 'wut'); + + $this->assertSame(2, $redis->hdel('metavars', 'foo', 'hoge')); + $this->assertSame(0, $redis->hdel('metavars', 'foofoo')); + $this->assertSame(0, $redis->hdel('unknown', 'foo')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->hdel('foo', 'bar'); + } +} diff --git a/tests/Predis/Commands/HashExistsTest.php b/tests/Predis/Commands/HashExistsTest.php new file mode 100644 index 00000000..011811ae --- /dev/null +++ b/tests/Predis/Commands/HashExistsTest.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-hash + */ +class HashExistsTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\HashExists'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'HEXISTS'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'field'); + $expected = array('key', 'field'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertFalse($command->parseResponse(0)); + $this->assertTrue($command->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'field'); + $expected = array('prefix:key', 'field'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsExistenceOfSpecifiedField() + { + $redis = $this->getClient(); + + $redis->hmset('metavars', 'foo', 'bar', 'hoge', 'piyo'); + + $this->assertTrue($redis->hexists('metavars', 'foo')); + $this->assertFalse($redis->hexists('metavars', 'lol')); + $this->assertFalse($redis->hexists('unknown', 'foo')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->hexists('foo', 'bar'); + } +} diff --git a/tests/Predis/Commands/HashGetAllTest.php b/tests/Predis/Commands/HashGetAllTest.php new file mode 100644 index 00000000..5c4ad294 --- /dev/null +++ b/tests/Predis/Commands/HashGetAllTest.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-hash + */ +class HashGetAllTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\HashGetAll'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'HGETALL'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key'); + $expected = array('key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('foo', 'bar', 'hoge', 'piyo', 'lol', 'wut'); + $expected = array('foo' => 'bar', 'hoge' => 'piyo', 'lol' => 'wut'); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsAllTheFieldsAndTheirValues() + { + $redis = $this->getClient(); + + $redis->hmset('metavars', 'foo', 'bar', 'hoge', 'piyo', 'lol', 'wut'); + + $this->assertSame(array('foo' => 'bar', 'hoge' => 'piyo', 'lol' => 'wut'), $redis->hgetall('metavars')); + $this->assertSame(array(), $redis->hgetall('unknown')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->hgetall('foo'); + } +} diff --git a/tests/Predis/Commands/HashGetMultipleTest.php b/tests/Predis/Commands/HashGetMultipleTest.php new file mode 100644 index 00000000..6a8b848b --- /dev/null +++ b/tests/Predis/Commands/HashGetMultipleTest.php @@ -0,0 +1,120 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-hash + */ +class HashGetMultipleTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\HashGetMultiple'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'HMGET'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'field1', 'field2', 'field3'); + $expected = array('key', 'field1', 'field2', 'field3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsFieldsAsSingleArray() + { + $arguments = array('key', array('field1', 'field2', 'field3')); + $expected = array('key', 'field1', 'field2', 'field3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('bar', 'piyo', 'wut'); + $expected = array('bar', 'piyo', 'wut'); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'field1', 'field2', 'field3'); + $expected = array('prefix:key', 'field1', 'field2', 'field3'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsValuesOfSpecifiedFields() + { + $redis = $this->getClient(); + + $redis->hmset('metavars', 'foo', 'bar', 'hoge', 'piyo', 'lol', 'wut'); + + $this->assertSame(array('bar', 'piyo', null), $redis->hmget('metavars', 'foo', 'hoge', 'unknown')); + $this->assertSame(array('bar', 'bar'), $redis->hmget('metavars', 'foo', 'foo')); + $this->assertSame(array(null, null), $redis->hmget('metavars', 'unknown', 'unknown')); + $this->assertSame(array(null, null), $redis->hmget('unknown', 'foo', 'hoge')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->hmget('foo', 'bar'); + } +} diff --git a/tests/Predis/Commands/HashGetTest.php b/tests/Predis/Commands/HashGetTest.php new file mode 100644 index 00000000..9abc8587 --- /dev/null +++ b/tests/Predis/Commands/HashGetTest.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-hash + */ +class HashGetTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\HashGet'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'HGET'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'field'); + $expected = array('key', 'field'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame('value', $this->getCommand()->parseResponse('value')); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'field'); + $expected = array('prefix:key', 'field'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsValueOfSpecifiedField() + { + $redis = $this->getClient(); + + $redis->hmset('metavars', 'foo', 'bar', 'hoge', 'piyo'); + + $this->assertSame('bar', $redis->hget('metavars', 'foo')); + $this->assertNull($redis->hget('metavars', 'lol')); + $this->assertNull($redis->hget('unknown', 'foo')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->hget('foo', 'bar'); + } +} diff --git a/tests/Predis/Commands/HashIncrementByFloatTest.php b/tests/Predis/Commands/HashIncrementByFloatTest.php new file mode 100644 index 00000000..36659953 --- /dev/null +++ b/tests/Predis/Commands/HashIncrementByFloatTest.php @@ -0,0 +1,125 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-hash + */ +class HashIncrementByFloatTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\HashIncrementByFloat'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'HINCRBYFLOAT'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'field', 10.5); + $expected = array('key', 'field', 10.5); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(10.5, $this->getCommand()->parseResponse(10.5)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'field', 10.5); + $expected = array('prefix:key', 'field', 10.5); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testIncrementsValueOfFieldByFloat() + { + $redis = $this->getClient(); + + $this->assertSame('10.5', $redis->hincrbyfloat('metavars', 'foo', 10.5)); + $this->assertSame('10.001', $redis->hincrbyfloat('metavars', 'hoge', 10.001)); + $this->assertSame('11', $redis->hincrbyfloat('metavars', 'hoge', 0.999)); + $this->assertSame(array('foo' => '10.5', 'hoge' => '11'), $redis->hgetall('metavars')); + } + + /** + * @group connected + */ + public function testDecrementsValueOfFieldByFloat() + { + $redis = $this->getClient(); + + $this->assertSame('-10.5', $redis->hincrbyfloat('metavars', 'foo', -10.5)); + $this->assertSame('-10.001', $redis->hincrbyfloat('metavars', 'hoge', -10.001)); + $this->assertSame('-11', $redis->hincrbyfloat('metavars', 'hoge', -0.999)); + $this->assertSame(array('foo' => '-10.5', 'hoge' => '-11'), $redis->hgetall('metavars')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR hash value is not a valid float + */ + public function testThrowsExceptionOnStringField() + { + $redis = $this->getClient(); + + $redis->hset('metavars', 'foo', 'bar'); + $redis->hincrbyfloat('metavars', 'foo', 10.0); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->hincrbyfloat('foo', 'bar', 10.5); + } +} diff --git a/tests/Predis/Commands/HashIncrementByTest.php b/tests/Predis/Commands/HashIncrementByTest.php new file mode 100644 index 00000000..327fa3eb --- /dev/null +++ b/tests/Predis/Commands/HashIncrementByTest.php @@ -0,0 +1,125 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-hash + */ +class HashIncrementByTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\HashIncrementBy'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'HINCRBY'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'field', 10); + $expected = array('key', 'field', 10); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(10, $this->getCommand()->parseResponse(10)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'field', 10); + $expected = array('prefix:key', 'field', 10); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testIncrementsValueOfFieldByInteger() + { + $redis = $this->getClient(); + + $this->assertSame(10, $redis->hincrby('metavars', 'foo', 10)); + $this->assertSame(5, $redis->hincrby('metavars', 'hoge', 5)); + $this->assertSame(15, $redis->hincrby('metavars', 'hoge', 10)); + $this->assertSame(array('foo' => '10', 'hoge' => '15'), $redis->hgetall('metavars')); + } + + /** + * @group connected + */ + public function testDecrementsValueOfFieldByInteger() + { + $redis = $this->getClient(); + + $this->assertSame(-10, $redis->hincrby('metavars', 'foo', -10)); + $this->assertSame(-5, $redis->hincrby('metavars', 'hoge', -5)); + $this->assertSame(-15, $redis->hincrby('metavars', 'hoge', -10)); + $this->assertSame(array('foo' => '-10', 'hoge' => '-15'), $redis->hgetall('metavars')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR hash value is not an integer + */ + public function testThrowsExceptionOnStringField() + { + $redis = $this->getClient(); + + $redis->hset('metavars', 'foo', 'bar'); + $redis->hincrby('metavars', 'foo', 10); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->hincrby('foo', 'bar', 10); + } +} diff --git a/tests/Predis/Commands/HashKeysTest.php b/tests/Predis/Commands/HashKeysTest.php new file mode 100644 index 00000000..46d58b1f --- /dev/null +++ b/tests/Predis/Commands/HashKeysTest.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-hash + */ +class HashKeysTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\HashKeys'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'HKEYS'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key'); + $expected = array('key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('foo', 'hoge', 'lol'); + $expected = array('foo', 'hoge', 'lol'); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsKeysOfHash() + { + $redis = $this->getClient(); + + $redis->hmset('metavars', 'foo', 'bar', 'hoge', 'piyo', 'lol', 'wut'); + + $this->assertSame(array('foo', 'hoge', 'lol'), $redis->hkeys('metavars')); + $this->assertSame(array(), $redis->hkeys('unknown')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->hkeys('foo'); + } +} diff --git a/tests/Predis/Commands/HashLengthTest.php b/tests/Predis/Commands/HashLengthTest.php new file mode 100644 index 00000000..444ecf94 --- /dev/null +++ b/tests/Predis/Commands/HashLengthTest.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-hash + */ +class HashLengthTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\HashLength'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'HLEN'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key'); + $expected = array('key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsLengthOfHash() + { + $redis = $this->getClient(); + + $redis->hmset('metavars', 'foo', 'bar', 'hoge', 'piyo', 'lol', 'wut'); + + $this->assertSame(3, $redis->hlen('metavars')); + $this->assertSame(0, $redis->hlen('unknown')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->hlen('foo'); + } +} diff --git a/tests/Predis/Commands/HashSetMultipleTest.php b/tests/Predis/Commands/HashSetMultipleTest.php new file mode 100644 index 00000000..14fcb19c --- /dev/null +++ b/tests/Predis/Commands/HashSetMultipleTest.php @@ -0,0 +1,126 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-hash + */ +class HashSetMultipleTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\HashSetMultiple'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'HMSET'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'field1', 'value1', 'field2', 'value2'); + $expected = array('key', 'field1', 'value1', 'field2', 'value2'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsFieldsValuesAsSingleArray() + { + $arguments = array('key', array('field1' => 'value1', 'field2' => 'value2')); + $expected = array('key', 'field1', 'value1', 'field2', 'value2'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'field1', 'value1', 'field2', 'value2'); + $expected = array('prefix:key', 'field1', 'value1', 'field2', 'value2'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testSetsSpecifiedFieldsOfHash() + { + $redis = $this->getClient(); + + $this->assertTrue($redis->hmset('metavars', 'foo', 'bar', 'hoge', 'piyo')); + $this->assertSame(array('foo' => 'bar', 'hoge' => 'piyo'), $redis->hgetall('metavars')); + + $this->assertTrue($redis->hmset('metavars', 'foo', 'barbar', 'lol', 'wut')); + $this->assertSame(array('foo' => 'barbar', 'hoge' => 'piyo', 'lol' => 'wut'), $redis->hgetall('metavars')); + } + + /** + * @group connected + */ + public function testSetsTheSpecifiedFie() + { + $redis = $this->getClient(); + + $redis->hmset('metavars', 'foo', 'bar', 'hoge', 'piyo', 'lol', 'wut'); + + $this->assertSame(array('foo' => 'bar', 'hoge' => 'piyo', 'lol' => 'wut'), $redis->hgetall('metavars')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('metavars', 'bar'); + $redis->hmset('metavars', 'foo', 'bar'); + } +} diff --git a/tests/Predis/Commands/HashSetPreserveTest.php b/tests/Predis/Commands/HashSetPreserveTest.php new file mode 100644 index 00000000..a6a51a05 --- /dev/null +++ b/tests/Predis/Commands/HashSetPreserveTest.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-hash + */ +class HashSetPreserveTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\HashSetPreserve'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'HSETNX'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'field', 'value'); + $expected = array('key', 'field', 'value'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertTrue($command->parseResponse(1)); + $this->assertFalse($command->parseResponse(0)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'field', 'value'); + $expected = array('prefix:key', 'field', 'value'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testSetsNewFieldsAndPreserversExistingOnes() + { + $redis = $this->getClient(); + + $this->assertTrue($redis->hsetnx('metavars', 'foo', 'bar')); + $this->assertTrue($redis->hsetnx('metavars', 'hoge', 'piyo')); + $this->assertFalse($redis->hsetnx('metavars', 'foo', 'barbar')); + + $this->assertSame(array('bar', 'piyo'), $redis->hmget('metavars', 'foo', 'hoge')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('metavars', 'foo'); + $redis->hsetnx('metavars', 'foo', 'bar'); + } +} diff --git a/tests/Predis/Commands/HashSetTest.php b/tests/Predis/Commands/HashSetTest.php new file mode 100644 index 00000000..a2448a10 --- /dev/null +++ b/tests/Predis/Commands/HashSetTest.php @@ -0,0 +1,102 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-hash + */ +class HashSetTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\HashSet'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'HSET'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'field', 'value'); + $expected = array('key', 'field', 'value'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertTrue($command->parseResponse(1)); + $this->assertFalse($command->parseResponse(0)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'field', 'value'); + $expected = array('prefix:key', 'field', 'value'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testSetsValueOfSpecifiedField() + { + $redis = $this->getClient(); + + $this->assertTrue($redis->hset('metavars', 'foo', 'bar')); + $this->assertTrue($redis->hset('metavars', 'hoge', 'piyo')); + + $this->assertSame(array('bar', 'piyo'), $redis->hmget('metavars', 'foo', 'hoge')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('metavars', 'foo'); + $redis->hset('metavars', 'foo', 'bar'); + } +} diff --git a/tests/Predis/Commands/HashValuesTest.php b/tests/Predis/Commands/HashValuesTest.php new file mode 100644 index 00000000..853993e1 --- /dev/null +++ b/tests/Predis/Commands/HashValuesTest.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-hash + */ +class HashValuesTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\HashValues'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'HVALS'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key'); + $expected = array('key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('foo', 'hoge', 'lol'); + $expected = array('foo', 'hoge', 'lol'); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsValuesOfHash() + { + $redis = $this->getClient(); + + $redis->hmset('metavars', 'foo', 'bar', 'hoge', 'piyo', 'lol', 'wut'); + + $this->assertSame(array('bar', 'piyo', 'wut'), $redis->hvals('metavars')); + $this->assertSame(array(), $redis->hvals('unknown')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->hvals('foo'); + } +} diff --git a/tests/Predis/Commands/KeyDeleteTest.php b/tests/Predis/Commands/KeyDeleteTest.php new file mode 100644 index 00000000..d33663a6 --- /dev/null +++ b/tests/Predis/Commands/KeyDeleteTest.php @@ -0,0 +1,108 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-key + */ +class KeyDeleteTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\KeyDelete'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'DEL'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key1', 'key2', 'key3'); + $expected = array('key1', 'key2', 'key3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsAsSingleArray() + { + $arguments = array(array('key1', 'key2', 'key3')); + $expected = array('key1', 'key2', 'key3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertSame(10, $command->parseResponse(10)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key1', 'key2', 'key3'); + $expected = array('prefix:key1', 'prefix:key2', 'prefix:key3'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsNumberOfDeletedKeys() + { + $redis = $this->getClient(); + + $this->assertSame(0, $redis->del('foo')); + + $redis->set('foo', 'bar'); + $this->assertSame(1, $redis->del('foo')); + + $redis->set('foo', 'bar'); + $this->assertSame(1, $redis->del('foo', 'hoge')); + + $redis->set('foo', 'bar'); + $redis->set('hoge', 'piyo'); + $this->assertSame(2, $redis->del('foo', 'hoge')); + } +} diff --git a/tests/Predis/Commands/KeyExistsTest.php b/tests/Predis/Commands/KeyExistsTest.php new file mode 100644 index 00000000..21cb68bc --- /dev/null +++ b/tests/Predis/Commands/KeyExistsTest.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-key + */ +class KeyExistsTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\KeyExists'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'EXISTS'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key'); + $expected = array('key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertTrue($command->parseResponse(1)); + $this->assertFalse($command->parseResponse(0)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsTrueIfKeyExists() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $this->assertTrue($redis->exists('foo')); + } + + /** + * @group connected + */ + public function testReturnsFalseIfKeyDoesNotExist() + { + $redis = $this->getClient(); + + $this->assertFalse($redis->exists('foo')); + } +} diff --git a/tests/Predis/Commands/KeyExpireAtTest.php b/tests/Predis/Commands/KeyExpireAtTest.php new file mode 100644 index 00000000..9a93a884 --- /dev/null +++ b/tests/Predis/Commands/KeyExpireAtTest.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-key + */ +class KeyExpireAtTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\KeyExpireAt'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'EXPIREAT'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'ttl'); + $expected = array('key', 'ttl'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertTrue($command->parseResponse(1)); + $this->assertFalse($command->parseResponse(0)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'value'); + $expected = array('prefix:key', 'value'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsFalseOnNonExistingKeys() + { + $redis = $this->getClient(); + + $this->assertFalse($redis->expireat('foo', 2)); + } + + /** + * @group connected + * @group slow + */ + public function testCanExpireKeys() + { + $redis = $this->getClient(); + + $now = time(); + $redis->set('foo', 'bar'); + + $this->assertTrue($redis->expireat('foo', $now + 1)); + $this->assertLessThanOrEqual(1, $redis->ttl('foo')); + + $this->sleep(2); + + $this->assertFalse($redis->exists('foo')); + } + + /** + * @group connected + */ + public function testDeletesKeysOnPastUnixTime() + { + $redis = $this->getClient(); + + $now = time(); + $redis->set('foo', 'bar'); + + $this->assertTrue($redis->expireat('foo', $now - 100)); + $this->assertFalse($redis->exists('foo')); + } +} diff --git a/tests/Predis/Commands/KeyExpireTest.php b/tests/Predis/Commands/KeyExpireTest.php new file mode 100644 index 00000000..6b472282 --- /dev/null +++ b/tests/Predis/Commands/KeyExpireTest.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-key + */ +class KeyExpireTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\KeyExpire'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'EXPIRE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'ttl'); + $expected = array('key', 'ttl'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertTrue($command->parseResponse(1)); + $this->assertFalse($command->parseResponse(0)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'value'); + $expected = array('prefix:key', 'value'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsFalseOnNonExistingKeys() + { + $redis = $this->getClient(); + + $this->assertFalse($redis->expire('foo', 2)); + } + + /** + * @group connected + * @group slow + */ + public function testCanExpireKeys() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + + $this->assertTrue($redis->expire('foo', 1)); + $this->assertSame(1, $redis->ttl('foo')); + + $this->sleep(2.0); + + $this->assertFalse($redis->exists('foo')); + } + + /** + * @group connected + * @group slow + */ + public function testConsistencyWithTTL() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + + $this->assertTrue($redis->expire('foo', 10)); + $this->sleep(1.5); + $this->assertLessThan(10, $redis->ttl('foo')); + } + + /** + * @group connected + */ + public function testDeletesKeysOnNegativeTTL() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + + $this->assertTrue($redis->expire('foo', -10)); + $this->assertFalse($redis->exists('foo')); + } +} diff --git a/tests/Predis/Commands/KeyKeysTest.php b/tests/Predis/Commands/KeyKeysTest.php new file mode 100644 index 00000000..0ce1c49d --- /dev/null +++ b/tests/Predis/Commands/KeyKeysTest.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-key + */ +class KeyKeysTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\KeyKeys'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'KEYS'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('pattern:*'); + $expected = array('pattern:*'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('key1', 'key2', 'key3'); + $parsed = array('key1', 'key2', 'key3'); + + $this->assertSame($parsed, $this->getCommand()->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('pattern'); + $expected = array('prefix:pattern'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsArrayOfMatchingKeys() + { + $keys = array('aaa' => 1, 'aba' => 2, 'aca' => 3); + $keysNS = array('metavar:foo' => 'bar', 'metavar:hoge' => 'piyo'); + $keysAll = array_merge($keys, $keysNS); + + $redis = $this->getClient(); + $redis->mset($keysAll); + + $this->assertSame(array(), $redis->keys('nomatch:*')); + $this->assertSameValues(array_keys($keysNS), $redis->keys('metavar:*')); + $this->assertSameValues(array_keys($keysAll), $redis->keys('*')); + $this->assertSameValues(array_keys($keys), $redis->keys('a?a')); + } +} diff --git a/tests/Predis/Commands/KeyKeysV12xTest.php b/tests/Predis/Commands/KeyKeysV12xTest.php new file mode 100644 index 00000000..b29deded --- /dev/null +++ b/tests/Predis/Commands/KeyKeysV12xTest.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * We only perform disconnected tests for this commands because + * it is too old (Redis v1.2) and expects a different response + * format. + * + * @group commands + * @group realm-key + */ +class KeyKeysV12xTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\KeyKeysV12x'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'KEYS'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('pattern:*'); + $expected = array('pattern:*'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = 'key1 key2 key3'; + $parsed = array('key1', 'key2', 'key3'); + + $this->assertSame($parsed, $this->getCommand()->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('pattern'); + $expected = array('prefix:pattern'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } +} diff --git a/tests/Predis/Commands/KeyMoveTest.php b/tests/Predis/Commands/KeyMoveTest.php new file mode 100644 index 00000000..8e6700b0 --- /dev/null +++ b/tests/Predis/Commands/KeyMoveTest.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-key + */ +class KeyMoveTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\KeyMove'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'MOVE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 10); + $expected = array('key', 10); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertTrue($command->parseResponse(1)); + $this->assertFalse($command->parseResponse(0)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'db'); + $expected = array('prefix:key', 'db'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + * @todo This test fails if REDIS_SERVER_DBNUM is 0. + */ + public function testMovesKeysToDifferentDatabases() + { + $db = REDIS_SERVER_DBNUM - 1; + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + + $this->assertTrue($redis->move('foo', $db)); + $this->assertFalse($redis->exists('foo')); + + $redis->select($db); + $this->assertTrue($redis->exists('foo')); + + $redis->del('foo'); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR index out of range + */ + public function testThrowsExceptionOnInvalidDatabases() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + + $redis->move('foo', 100000000); + } +} diff --git a/tests/Predis/Commands/KeyPersistTest.php b/tests/Predis/Commands/KeyPersistTest.php new file mode 100644 index 00000000..2da3c82d --- /dev/null +++ b/tests/Predis/Commands/KeyPersistTest.php @@ -0,0 +1,112 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-key + */ +class KeyPersistTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\KeyPersist'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'PERSIST'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key'); + $expected = array('key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertTrue($command->parseResponse(1)); + $this->assertFalse($command->parseResponse(0)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testRemovesExpireFromKey() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->expire('foo', 10); + + $this->assertTrue($redis->persist('foo')); + $this->assertSame(-1, $redis->ttl('foo')); + } + + /** + * @group connected + */ + public function testReturnsFalseOnNonExpiringKeys() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + + $this->assertFalse($redis->persist('foo')); + } + + /** + * @group connected + */ + public function testReturnsFalseOnNonExistentKeys() + { + $redis = $this->getClient(); + + $this->assertFalse($redis->persist('foo')); + } +} diff --git a/tests/Predis/Commands/KeyPreciseExpireAtTest.php b/tests/Predis/Commands/KeyPreciseExpireAtTest.php new file mode 100644 index 00000000..81b093d3 --- /dev/null +++ b/tests/Predis/Commands/KeyPreciseExpireAtTest.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-key + */ +class KeyPreciseExpireAtTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\KeyPreciseExpireAt'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'PEXPIREAT'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 100); + $expected = array('key', 100); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertTrue($command->parseResponse(1)); + $this->assertFalse($command->parseResponse(0)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'value'); + $expected = array('prefix:key', 'value'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + * @group slow + */ + public function testCanExpireKeys() + { + $ttl = 1.5; + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + + $this->assertTrue($redis->pexpireat('foo', time() + $ttl * 1000)); + $this->assertLessThan($ttl * 1000, $redis->pttl('foo')); + + $this->sleep($ttl + 0.5); + + $this->assertFalse($redis->exists('foo')); + } + + /** + * @group connected + */ + public function testDeletesKeysOnPastUnixTime() + { + $redis = $this->getClient(); + + $now = time(); + $redis->set('foo', 'bar'); + + $this->assertTrue($redis->expireat('foo', time() - 100000)); + $this->assertFalse($redis->exists('foo')); + } +} diff --git a/tests/Predis/Commands/KeyPreciseExpireTest.php b/tests/Predis/Commands/KeyPreciseExpireTest.php new file mode 100644 index 00000000..0e3ab3cc --- /dev/null +++ b/tests/Predis/Commands/KeyPreciseExpireTest.php @@ -0,0 +1,134 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-key + */ +class KeyPreciseExpireTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\KeyPreciseExpire'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'PEXPIRE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 100); + $expected = array('key', 100); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertTrue($command->parseResponse(1)); + $this->assertFalse($command->parseResponse(0)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'value'); + $expected = array('prefix:key', 'value'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsFalseOnNonExistingKeys() + { + $redis = $this->getClient(); + + $this->assertFalse($redis->pexpire('foo', 20000)); + } + + /** + * @group connected + * @group slow + */ + public function testCanExpireKeys() + { + $ttl = 1 * 1000; + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + + $this->assertTrue($redis->pexpire('foo', $ttl)); + + $this->sleep(1.2); + $this->assertFalse($redis->exists('foo')); + } + + /** + * @group connected + * @group slow + */ + public function testConsistencyWithTTL() + { + $ttl = 1 * 1000; + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + + $this->assertTrue($redis->pexpire('foo', $ttl)); + + $this->sleep(0.5); + $this->assertLessThanOrEqual($ttl, $redis->pttl('foo')); + $this->assertGreaterThan($ttl - 800, $redis->pttl('foo')); + } + + /** + * @group connected + */ + public function testDeletesKeysOnNegativeTTL() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + + $this->assertTrue($redis->pexpire('foo', -10000)); + $this->assertFalse($redis->exists('foo')); + } +} diff --git a/tests/Predis/Commands/KeyPreciseTimeToLiveTest.php b/tests/Predis/Commands/KeyPreciseTimeToLiveTest.php new file mode 100644 index 00000000..4610fb8c --- /dev/null +++ b/tests/Predis/Commands/KeyPreciseTimeToLiveTest.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-key + */ +class KeyPreciseTimeToLiveTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\KeyPreciseTimeToLive'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'PTTL'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 10); + $expected = array('key', 10); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertSame(100, $command->parseResponse(100)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 10); + $expected = array('prefix:key', 10); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsTTL() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->expire('foo', 10); + + $this->assertLessThanOrEqual(10000, $redis->pttl('foo')); + } + + /** + * @group connected + */ + public function testReturnsLessThanZeroOnNonExistingKeys() + { + $redis = $this->getClient(); + + $this->assertSame(-1, $redis->pttl('foo')); + } + + /** + * @group connected + */ + public function testReturnsLessThanZeroOnNonExpiringKeys() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $this->assertSame(-1, $redis->pttl('foo')); + } +} diff --git a/tests/Predis/Commands/KeyRandomTest.php b/tests/Predis/Commands/KeyRandomTest.php new file mode 100644 index 00000000..43ebe387 --- /dev/null +++ b/tests/Predis/Commands/KeyRandomTest.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-key + */ +class KeyRandomTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\KeyRandom'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'RANDOMKEY'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array(); + $expected = array(); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = 'key'; + $expected = 'key'; + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group connected + */ + public function testReturnsFalseOnNonExpiringKeys() + { + $keys = array('key:1' => 1, 'key:2' => 2, 'key:3' => 3); + + $redis = $this->getClient(); + $redis->mset($keys); + + $this->assertContains($redis->randomkey(), array_keys($keys)); + } + + /** + * @group connected + */ + public function testReturnsNullOnEmptyDatabase() + { + $redis = $this->getClient(); + + $this->assertNull($redis->randomkey()); + } +} diff --git a/tests/Predis/Commands/KeyRenamePreserveTest.php b/tests/Predis/Commands/KeyRenamePreserveTest.php new file mode 100644 index 00000000..4f526de6 --- /dev/null +++ b/tests/Predis/Commands/KeyRenamePreserveTest.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-key + */ +class KeyRenamePreserveTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\KeyRenamePreserve'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'RENAMENX'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'newkey'); + $expected = array('key', 'newkey'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(1)); + $this->assertFalse($this->getCommand()->parseResponse(0)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'newkey'); + $expected = array('prefix:key', 'prefix:newkey'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testRenamesKeys() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + + $this->assertTrue($redis->renamenx('foo', 'foofoo')); + $this->assertFalse($redis->exists('foo')); + $this->assertTrue($redis->exists('foofoo')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR no such key + */ + public function testReturnsFalseOnNonExistingKeys() + { + $redis = $this->getClient(); + + $this->assertFalse($redis->renamenx('foo', 'foobar')); + } +} diff --git a/tests/Predis/Commands/KeyRenameTest.php b/tests/Predis/Commands/KeyRenameTest.php new file mode 100644 index 00000000..6875f1af --- /dev/null +++ b/tests/Predis/Commands/KeyRenameTest.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-key + */ +class KeyRenameTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\KeyRename'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'RENAME'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'newkey'); + $expected = array('key', 'newkey'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'newkey'); + $expected = array('prefix:key', 'prefix:newkey'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testRenamesKeys() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + + $this->assertTrue($redis->rename('foo', 'foofoo')); + $this->assertFalse($redis->exists('foo')); + $this->assertTrue($redis->exists('foofoo')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR no such key + */ + public function testThrowsExceptionOnNonExistingKeys() + { + $redis = $this->getClient(); + + $redis->rename('foo', 'foobar'); + } +} diff --git a/tests/Predis/Commands/KeySortTest.php b/tests/Predis/Commands/KeySortTest.php new file mode 100644 index 00000000..69f9c9e1 --- /dev/null +++ b/tests/Predis/Commands/KeySortTest.php @@ -0,0 +1,270 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-key + */ +class KeySortTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\KeySort'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SORT'; + } + + /** + * Utility method to to an LPUSH of some unordered values on a key. + * + * @param Predis\Client $redis Redis client instance. + * @param string $key Target key + * @return array + */ + protected function lpushUnorderedList(Predis\Client $redis, $key) + { + $list = array(2, 100, 3, 1, 30, 10); + $redis->lpush($key, $list); + + return $list; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $modifiers = array( + 'by' => 'by_key_*', + 'limit' => array(1, 4), + 'get' => array('object_*', '#'), + 'sort' => 'asc', + 'alpha' => true, + 'store' => 'destination_key', + ); + $arguments = array('key', $modifiers); + + $expected = array( + 'key', 'BY', 'by_key_*', 'GET', 'object_*', 'GET', '#', + 'LIMIT', 1, 4, 'ASC', 'ALPHA', 'STORE', 'destination_key' + ); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertEquals($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testGetModifierCanBeString() + { + $arguments = array('key', array('get' => '#')); + $expected = array('key', 'GET', '#'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('value1', 'value2', 'value3'); + $expected = array('value1', 'value2', 'value3'); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $modifiers = array( + 'by' => 'by_key_*', + 'limit' => array(1, 4), + 'get' => array('object_*', '#'), + 'sort' => 'asc', + 'alpha' => true, + 'store' => 'destination_key', + ); + $arguments = array('key', $modifiers); + + $expected = array( + 'prefix:key', 'BY', 'prefix:by_key_*', 'GET', 'prefix:object_*', 'GET', '#', + 'LIMIT', 1, 4, 'ASC', 'ALPHA', 'STORE', 'prefix:destination_key' + ); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testBasicSort() + { + $redis = $this->getClient(); + $redis->lpush('list:unordered', $unordered = array(2, 100, 3, 1, 30, 10)); + + $this->assertEquals(array(1, 2, 3, 10, 30, 100), $redis->sort('list:unordered')); + } + + /** + * @group connected + */ + public function testSortWithAscOrDescModifier() + { + $redis = $this->getClient(); + $redis->lpush('list:unordered', $unordered = array(2, 100, 3, 1, 30, 10)); + + $this->assertEquals( + array(100, 30, 10, 3, 2, 1), + $redis->sort('list:unordered', array( + 'sort' => 'desc', + )) + ); + + $this->assertEquals( + array(1, 2, 3, 10, 30, 100), + $redis->sort('list:unordered', array( + 'sort' => 'asc', + )) + ); + } + + /** + * @group connected + */ + public function testSortWithLimitModifier() + { + $redis = $this->getClient(); + $redis->lpush('list:unordered', $unordered = array(2, 100, 3, 1, 30, 10)); + + $this->assertEquals( + array(1, 2, 3), + $redis->sort('list:unordered', array( + 'limit' => array(0, 3), + )) + ); + + $this->assertEquals( + array(10, 30), + $redis->sort('list:unordered', array( + 'limit' => array(3, 2) + )) + ); + } + + /** + * @group connected + */ + public function testSortWithAlphaModifier() + { + $redis = $this->getClient(); + $redis->lpush('list:unordered', $unordered = array(2, 100, 3, 1, 30, 10)); + + $this->assertEquals( + array(1, 10, 100, 2, 3, 30), + $redis->sort('list:unordered', array( + 'alpha' => true + )) + ); + } + + /** + * @group connected + */ + public function testSortWithStoreModifier() + { + $redis = $this->getClient(); + $redis->lpush('list:unordered', $unordered = array(2, 100, 3, 1, 30, 10)); + + $this->assertEquals( + count($unordered), + $redis->sort('list:unordered', array( + 'store' => 'list:ordered' + )) + ); + + $this->assertEquals(array(1, 2, 3, 10, 30, 100), $redis->lrange('list:ordered', 0, -1)); + } + + /** + * @group connected + */ + public function testSortWithCombinedModifiers() + { + $redis = $this->getClient(); + $redis->lpush('list:unordered', $unordered = array(2, 100, 3, 1, 30, 10)); + + $this->assertEquals( + array(30, 10, 3, 2), + $redis->sort('list:unordered', array( + 'alpha' => false, + 'sort' => 'desc', + 'limit' => array(1, 4) + )) + ); + } + + /** + * @group connected + */ + public function testSortWithGetModifiers() + { + $redis = $this->getClient(); + $redis->lpush('list:unordered', $unordered = array(2, 100, 3, 1, 30, 10)); + + $redis->rpush('list:uids', $uids = array(1003, 1001, 1002, 1000)); + $redis->mset($sortget = array( + 'uid:1000' => 'foo', 'uid:1001' => 'bar', + 'uid:1002' => 'hoge', 'uid:1003' => 'piyo', + )); + + $this->assertEquals(array_values($sortget), $redis->sort('list:uids', array('get' => 'uid:*'))); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->sort('foo'); + } +} diff --git a/tests/Predis/Commands/KeyTimeToLiveTest.php b/tests/Predis/Commands/KeyTimeToLiveTest.php new file mode 100644 index 00000000..2aec9a91 --- /dev/null +++ b/tests/Predis/Commands/KeyTimeToLiveTest.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-key + */ +class KeyTimeToLiveTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\KeyTimeToLive'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'TTL'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 10); + $expected = array('key', 10); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertSame(100, $command->parseResponse(100)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 10); + $expected = array('prefix:key', 10); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsTTL() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->expire('foo', 10); + + $this->assertSame(10, $redis->ttl('foo')); + } + + /** + * @group connected + */ + public function testReturnsLessThanZeroOnNonExistingKeys() + { + $redis = $this->getClient(); + + $this->assertSame(-1, $redis->ttl('foo')); + } + + /** + * @group connected + */ + public function testReturnsLessThanZeroOnNonExpiringKeys() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $this->assertSame(-1, $redis->ttl('foo')); + } +} diff --git a/tests/Predis/Commands/KeyTypeTest.php b/tests/Predis/Commands/KeyTypeTest.php new file mode 100644 index 00000000..983a1f51 --- /dev/null +++ b/tests/Predis/Commands/KeyTypeTest.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-key + */ +class KeyTypeTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\KeyType'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'TYPE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key'); + $expected = array('key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame('type', $this->getCommand()->parseResponse('type')); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsTypeOfKey() + { + $redis = $this->getClient(); + + $this->assertSame('none', $redis->type('type:keydoesnotexist')); + + $redis->set('type:string', 'foobar'); + $this->assertSame('string', $redis->type('type:string')); + + $redis->lpush('type:list', 'foobar'); + $this->assertSame('list', $redis->type('type:list')); + + $redis->sadd('type:set', 'foobar'); + $this->assertSame('set', $redis->type('type:set')); + + $redis->zadd('type:zset', 0, 'foobar'); + $this->assertSame('zset', $redis->type('type:zset')); + + $redis->hset('type:hash', 'foo', 'bar'); + $this->assertSame('hash', $redis->type('type:hash')); + } +} diff --git a/tests/Predis/Commands/ListIndexTest.php b/tests/Predis/Commands/ListIndexTest.php new file mode 100644 index 00000000..47fe7993 --- /dev/null +++ b/tests/Predis/Commands/ListIndexTest.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-list + */ +class ListIndexTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ListIndex'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'LINDEX'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 1); + $expected = array('key', 1); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(0, $this->getCommand()->parseResponse(0)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 1); + $expected = array('prefix:key', 1); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsElementAtIndex() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', 'b', 'c', 'd', 'e'); + + $this->assertSame('a', $redis->lindex('letters', 0)); + $this->assertSame('c', $redis->lindex('letters', 2)); + $this->assertNull($redis->lindex('letters', 100)); + } + + /** + * @group connected + */ + public function testReturnsElementAtNegativeIndex() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', 'b', 'c', 'd', 'e'); + + $this->assertSame('a', $redis->lindex('letters', -0)); + $this->assertSame('c', $redis->lindex('letters', -3)); + $this->assertSame('e', $redis->lindex('letters', -1)); + $this->assertNull($redis->lindex('letters', -100)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->lindex('foo', 0); + } +} diff --git a/tests/Predis/Commands/ListInsertTest.php b/tests/Predis/Commands/ListInsertTest.php new file mode 100644 index 00000000..2b561b9d --- /dev/null +++ b/tests/Predis/Commands/ListInsertTest.php @@ -0,0 +1,123 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-list + */ +class ListInsertTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ListInsert'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'LINSERT'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'before', 'value1', 'value2'); + $expected = array('key', 'before', 'value1', 'value2'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'before', 'value1', 'value2'); + $expected = array('prefix:key', 'before', 'value1', 'value2'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsLengthOfListAfterInser() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', 'c', 'e'); + + $this->assertSame(4, $redis->linsert('letters', 'before', 'c', 'b')); + $this->assertSame(5, $redis->linsert('letters', 'after', 'c', 'd')); + $this->assertSame(array('a', 'b', 'c', 'd', 'e'), $redis->lrange('letters', 0, -1)); + } + + /** + * @group connected + */ + public function testReturnsNegativeLengthOnFailedInsert() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', 'c', 'e'); + + $this->assertSame(-1, $redis->linsert('letters', 'before', 'n', 'm')); + $this->assertSame(-1, $redis->linsert('letters', 'after', 'o', 'p')); + } + + /** + * @group connected + */ + public function testReturnsZeroLengthOnNonExistingList() + { + $redis = $this->getClient(); + + $this->assertSame(0, $redis->linsert('letters', 'after', 'a', 'b')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->linsert('foo', 'BEFORE', 'bar', 'baz'); + } +} diff --git a/tests/Predis/Commands/ListLengthTest.php b/tests/Predis/Commands/ListLengthTest.php new file mode 100644 index 00000000..ab29d1c2 --- /dev/null +++ b/tests/Predis/Commands/ListLengthTest.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-list + */ +class ListLengthTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ListLength'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'LLEN'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key'); + $expected = array('key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsLengthOfList() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', 'b', 'c'); + $this->assertSame(3, $redis->llen('letters')); + + $redis->rpush('letters', 'd', 'e', 'f'); + $this->assertSame(6, $redis->llen('letters')); + } + + /** + * @group connected + */ + public function testReturnsZeroLengthOnNonExistingList() + { + $redis = $this->getClient(); + + $this->assertSame(0, $redis->llen('letters')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->llen('foo'); + } +} diff --git a/tests/Predis/Commands/ListPopFirstBlockingTest.php b/tests/Predis/Commands/ListPopFirstBlockingTest.php new file mode 100644 index 00000000..2bdb0f19 --- /dev/null +++ b/tests/Predis/Commands/ListPopFirstBlockingTest.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-list + * @todo Testing blocking pop operations against Redis using PHP is + * tricky, so we will skip these kind of tests for now. + */ +class ListPopFirstBlockingTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ListPopFirstBlocking'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'BLPOP'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key1', 'key2', 'key3', 10); + $expected = array('key1', 'key2', 'key3', 10); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsKeysAsSingleArray() + { + $arguments = array(array('key1', 'key2', 'key3'), 10); + $expected = array('key1', 'key2', 'key3', 10); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('key', 'value'); + $expected = array('key', 'value'); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key1', 'key2', 'key3', 10); + $expected = array('prefix:key1', 'prefix:key2', 'prefix:key3', 10); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } +} diff --git a/tests/Predis/Commands/ListPopFirstTest.php b/tests/Predis/Commands/ListPopFirstTest.php new file mode 100644 index 00000000..64d3c38a --- /dev/null +++ b/tests/Predis/Commands/ListPopFirstTest.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-list + */ +class ListPopFirstTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ListPopFirst'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'LPOP'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key'); + $expected = array('key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame('element', $this->getCommand()->parseResponse('element')); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testPopsTheFirstElementFromList() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', 'b', 'c', 'd'); + + $this->assertSame('a', $redis->lpop('letters')); + $this->assertSame('b', $redis->lpop('letters')); + $this->assertSame(array('c', 'd'), $redis->lrange('letters', 0, -1)); + } + + /** + * @group connected + */ + public function testReturnsNullOnEmptyList() + { + $redis = $this->getClient(); + + $this->assertNull($redis->lpop('letters')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->lpop('foo'); + } +} diff --git a/tests/Predis/Commands/ListPopLastBlockingTest.php b/tests/Predis/Commands/ListPopLastBlockingTest.php new file mode 100644 index 00000000..d7bd6093 --- /dev/null +++ b/tests/Predis/Commands/ListPopLastBlockingTest.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-list + * @todo Testing blocking pop operations against Redis using PHP is + * tricky, so we will skip these kind of tests for now. + */ +class ListPopLastBlockingTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ListPopLastBlocking'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'BRPOP'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key1', 'key2', 'key3', 10); + $expected = array('key1', 'key2', 'key3', 10); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsKeysAsSingleArray() + { + $arguments = array(array('key1', 'key2', 'key3'), 10); + $expected = array('key1', 'key2', 'key3', 10); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('key', 'value'); + $expected = array('key', 'value'); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key1', 'key2', 'key3', 10); + $expected = array('prefix:key1', 'prefix:key2', 'prefix:key3', 10); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } +} diff --git a/tests/Predis/Commands/ListPopLastPushHeadBlockingTest.php b/tests/Predis/Commands/ListPopLastPushHeadBlockingTest.php new file mode 100644 index 00000000..d009ae9b --- /dev/null +++ b/tests/Predis/Commands/ListPopLastPushHeadBlockingTest.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-list + * @todo Testing blocking pop operations against Redis using PHP is + * tricky, so we will skip these kind of tests for now. + */ +class ListPopLastPushHeadBlockingTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ListPopLastPushHeadBlocking'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'BRPOPLPUSH'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key:source', 'key:destination', 10); + $expected = array('key:source', 'key:destination', 10); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame('element', $this->getCommand()->parseResponse('element')); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key:source', 'key:destination', 10); + $expected = array('prefix:key:source', 'prefix:key:destination', 10); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } +} diff --git a/tests/Predis/Commands/ListPopLastPushHeadTest.php b/tests/Predis/Commands/ListPopLastPushHeadTest.php new file mode 100644 index 00000000..3b0df6b0 --- /dev/null +++ b/tests/Predis/Commands/ListPopLastPushHeadTest.php @@ -0,0 +1,144 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-list + */ +class ListPopLastPushHeadTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ListPopLastPushHead'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'RPOPLPUSH'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key:source', 'key:destination'); + $expected = array('key:source', 'key:destination'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame('element', $this->getCommand()->parseResponse('element')); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key:source', 'key:destination'); + $expected = array('prefix:key:source', 'prefix:key:destination'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsElementPoppedFromSourceAndPushesToDestination() + { + $redis = $this->getClient(); + + $redis->rpush('letters:source', 'a', 'b', 'c'); + + $this->assertSame('c', $redis->rpoplpush('letters:source', 'letters:destination')); + $this->assertSame('b', $redis->rpoplpush('letters:source', 'letters:destination')); + $this->assertSame('a', $redis->rpoplpush('letters:source', 'letters:destination')); + + $this->assertSame(array(), $redis->lrange('letters:source', 0, -1)); + $this->assertSame(array('a', 'b', 'c'), $redis->lrange('letters:destination', 0, -1)); + } + + /** + * @group connected + */ + public function testReturnsElementPoppedFromSourceAndPushesToSelf() + { + $redis = $this->getClient(); + + $redis->rpush('letters:source', 'a', 'b', 'c'); + + $this->assertSame('c', $redis->rpoplpush('letters:source', 'letters:source')); + $this->assertSame('b', $redis->rpoplpush('letters:source', 'letters:source')); + $this->assertSame('a', $redis->rpoplpush('letters:source', 'letters:source')); + + $this->assertSame(array('a', 'b', 'c'), $redis->lrange('letters:source', 0, -1)); + } + + /** + * @group connected + */ + public function testReturnsNullOnEmptySource() + { + $redis = $this->getClient(); + + $this->assertNull($redis->rpoplpush('key:source', 'key:destination')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongTypeOfSourceKey() + { + $redis = $this->getClient(); + + $redis->set('key:source', 'foo'); + $redis->rpoplpush('key:source', 'key:destination'); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongTypeOfDestinationKey() + { + $redis = $this->getClient(); + + $redis->rpush('key:source', 'foo'); + $redis->set('key:destination', 'bar'); + + $redis->rpoplpush('key:source', 'key:destination'); + } +} diff --git a/tests/Predis/Commands/ListPopLastTest.php b/tests/Predis/Commands/ListPopLastTest.php new file mode 100644 index 00000000..79e9252c --- /dev/null +++ b/tests/Predis/Commands/ListPopLastTest.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-list + */ +class ListPopLastTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ListPopLast'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'RPOP'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key'); + $expected = array('key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame('element', $this->getCommand()->parseResponse('element')); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testPopsTheLastElementFromList() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', 'b', 'c', 'd'); + + $this->assertSame('d', $redis->rpop('letters')); + $this->assertSame('c', $redis->rpop('letters')); + $this->assertSame(array('a', 'b'), $redis->lrange('letters', 0, -1)); + } + + /** + * @group connected + */ + public function testReturnsNullOnEmptyList() + { + $redis = $this->getClient(); + + $this->assertNull($redis->rpop('letters')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->rpop('foo'); + } +} diff --git a/tests/Predis/Commands/ListPushHeadTest.php b/tests/Predis/Commands/ListPushHeadTest.php new file mode 100644 index 00000000..95dc5c2c --- /dev/null +++ b/tests/Predis/Commands/ListPushHeadTest.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-list + */ +class ListPushHeadTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ListPushHead'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'LPUSH'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'value1', 'value2', 'value3'); + $expected = array('key', 'value1', 'value2', 'value3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsValuesAsSingleArray() + { + $arguments = array('key', array('value1', 'value2', 'value3')); + $expected = array('key', 'value1', 'value2', 'value3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'value1', 'value2', 'value3'); + $expected = array('prefix:key', 'value1', 'value2', 'value3'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testPushesElementsToHeadOfList() + { + $redis = $this->getClient(); + + // NOTE: List push operations return the list length since Redis commit 520b5a3 + $this->assertSame(1, $redis->lpush('metavars', 'foo')); + $this->assertSame(2, $redis->lpush('metavars', 'hoge')); + $this->assertSame(array('hoge', 'foo'), $redis->lrange('metavars', 0, -1)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('metavars', 'foo'); + $redis->lpush('metavars', 'hoge'); + } +} diff --git a/tests/Predis/Commands/ListPushHeadXTest.php b/tests/Predis/Commands/ListPushHeadXTest.php new file mode 100644 index 00000000..af1db985 --- /dev/null +++ b/tests/Predis/Commands/ListPushHeadXTest.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-list + */ +class ListPushHeadXTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ListPushHeadX'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'LPUSHX'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'value'); + $expected = array('key', 'value'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'value'); + $expected = array('prefix:key', 'value'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testPushesElementsToHeadOfExistingList() + { + $redis = $this->getClient(); + + $redis->lpush('metavars', 'foo'); + + $this->assertSame(2, $redis->lpushx('metavars', 'hoge')); + $this->assertSame(array('hoge', 'foo'), $redis->lrange('metavars', 0, -1)); + } + + /** + * @group connected + */ + public function testDoesNotPushElementOnNonExistingKey() + { + $redis = $this->getClient(); + + $this->assertSame(0, $redis->lpushx('metavars', 'foo')); + $this->assertSame(0, $redis->lpushx('metavars', 'hoge')); + $this->assertFalse($redis->exists('metavars')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('metavars', 'foo'); + $redis->lpushx('metavars', 'hoge'); + } +} diff --git a/tests/Predis/Commands/ListPushTailTest.php b/tests/Predis/Commands/ListPushTailTest.php new file mode 100644 index 00000000..7011f8cc --- /dev/null +++ b/tests/Predis/Commands/ListPushTailTest.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-list + */ +class ListPushTailTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ListPushTail'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'RPUSH'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'value1', 'value2', 'value3'); + $expected = array('key', 'value1', 'value2', 'value3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsValuesAsSingleArray() + { + $arguments = array('key', array('value1', 'value2', 'value3')); + $expected = array('key', 'value1', 'value2', 'value3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'value1', 'value2', 'value3'); + $expected = array('prefix:key', 'value1', 'value2', 'value3'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testPushesElementsToHeadOfList() + { + $redis = $this->getClient(); + + // NOTE: List push operations return the list length since Redis commit 520b5a3 + $this->assertSame(1, $redis->rpush('metavars', 'foo')); + $this->assertSame(2, $redis->rpush('metavars', 'hoge')); + $this->assertSame(array('foo', 'hoge'), $redis->lrange('metavars', 0, -1)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('metavars', 'foo'); + $redis->rpush('metavars', 'hoge'); + } +} diff --git a/tests/Predis/Commands/ListPushTailXTest.php b/tests/Predis/Commands/ListPushTailXTest.php new file mode 100644 index 00000000..fa8b5f8d --- /dev/null +++ b/tests/Predis/Commands/ListPushTailXTest.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-list + */ +class ListPushTailXTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ListPushTailX'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'RPUSHX'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'value'); + $expected = array('key', 'value'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'value'); + $expected = array('prefix:key', 'value'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testPushesElementsToHeadOfExistingList() + { + $redis = $this->getClient(); + + $redis->rpush('metavars', 'foo'); + + $this->assertSame(2, $redis->rpushx('metavars', 'hoge')); + $this->assertSame(array('foo', 'hoge'), $redis->lrange('metavars', 0, -1)); + } + + /** + * @group connected + */ + public function testDoesNotPushElementOnNonExistingKey() + { + $redis = $this->getClient(); + + $this->assertSame(0, $redis->rpushx('metavars', 'foo')); + $this->assertSame(0, $redis->rpushx('metavars', 'hoge')); + $this->assertFalse($redis->exists('metavars')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('metavars', 'foo'); + $redis->rpushx('metavars', 'hoge'); + } +} diff --git a/tests/Predis/Commands/ListRangeTest.php b/tests/Predis/Commands/ListRangeTest.php new file mode 100644 index 00000000..2309af83 --- /dev/null +++ b/tests/Predis/Commands/ListRangeTest.php @@ -0,0 +1,154 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-list + */ +class ListRangeTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ListRange'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'LRANGE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 0, -1); + $expected = array('key', 0, -1); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('value1', 'value2', 'value3'); + $expected = array('value1', 'value2', 'value3'); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 0, -1); + $expected = array('prefix:key', 0, -1); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsListSliceWithPositiveStartAndStop() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'l'); + + $this->assertSame(array('a', 'b', 'c', 'd'), $redis->lrange('letters', 0, 3)); + $this->assertSame(array('e', 'f', 'g', 'h'), $redis->lrange('letters', 4, 7)); + $this->assertSame(array('a', 'b'), $redis->lrange('letters', 0, 1)); + $this->assertSame(array('a'), $redis->lrange('letters', 0, 0)); + } + + /** + * @group connected + */ + public function testReturnsListSliceWithPositiveStartAndNegativeStop() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'l'); + + $this->assertSame(array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'l'), $redis->lrange('letters', 0, -1)); + $this->assertSame(array('f'), $redis->lrange('letters', 5, -5)); + $this->assertSame(array(), $redis->lrange('letters', 7, -5)); + } + + /** + * @group connected + */ + public function testReturnsListSliceWithNegativeStartAndStop() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'l'); + + $this->assertSame(array('f'), $redis->lrange('letters', -5, -5)); + } + + /** + * @group connected + */ + public function testHandlesStartAndStopOverflow() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'l'); + + $this->assertSame(array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'l'), $redis->lrange('letters', -100, 100)); + } + + /** + * @group connected + */ + public function testReturnsEmptyArrayOnNonExistingList() + { + $redis = $this->getClient(); + + $this->assertSame(array(), $redis->lrange('letters', 0, -1)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('metavars', 'foo'); + $redis->lrange('metavars', 0, -1); + } +} diff --git a/tests/Predis/Commands/ListRemoveTest.php b/tests/Predis/Commands/ListRemoveTest.php new file mode 100644 index 00000000..e0304983 --- /dev/null +++ b/tests/Predis/Commands/ListRemoveTest.php @@ -0,0 +1,138 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-list + */ +class ListRemoveTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ListRemove'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'LREM'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 1, 'value'); + $expected = array('key', 1, 'value'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 1, 'value'); + $expected = array('prefix:key', 1, 'value'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testRemovesMatchingElementsFromHeadToTail() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', '_', 'b', '_', 'c', '_', 'd', '_'); + + $this->assertSame(2, $redis->lrem('letters', 2, '_')); + $this->assertSame(array('a', 'b', 'c', '_', 'd', '_'), $redis->lrange('letters', 0, -1)); + } + + /** + * @group connected + */ + public function testRemovesMatchingElementsFromTailToHead() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', '_', 'b', '_', 'c', '_', 'd', '_'); + + $this->assertSame(2, $redis->lrem('letters', -2, '_')); + $this->assertSame(array('a', '_', 'b', '_', 'c', 'd'), $redis->lrange('letters', 0, -1)); + } + + /** + * @group connected + */ + public function testRemovesAllMatchingElements() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', '_', 'b', '_', 'c', '_', 'd', '_'); + + $this->assertSame(4, $redis->lrem('letters', 0, '_')); + $this->assertSame(array('a', 'b', 'c', 'd'), $redis->lrange('letters', 0, -1)); + } + + /** + * @group connected + */ + public function testReturnsZeroOnNonMatchingElementsOrEmptyList() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', 'b', 'c', 'd'); + + $this->assertSame(0, $redis->lrem('letters', 0, 'z')); + $this->assertSame(0, $redis->lrem('digits', 0, 100)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('metavars', 'foo'); + $redis->lrem('metavars', 0, 0); + } +} diff --git a/tests/Predis/Commands/ListSetTest.php b/tests/Predis/Commands/ListSetTest.php new file mode 100644 index 00000000..0f0fa2cc --- /dev/null +++ b/tests/Predis/Commands/ListSetTest.php @@ -0,0 +1,112 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-list + */ +class ListSetTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ListSet'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'LSET'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 0, 'value'); + $expected = array('key', 0, 'value'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 0, 'value'); + $expected = array('prefix:key', 0, 'value'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testSetsElementAtSpecifiedIndex() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', 'b', 'c'); + + $this->assertTrue($redis->lset('letters', 1, 'B')); + $this->assertSame(array('a', 'B', 'c'), $redis->lrange('letters', 0, -1)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR index out of range + */ + public function testThrowsExceptionOnIndexOutOfRange() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', 'b', 'c'); + $redis->lset('letters', 21, 'z'); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('metavars', 'foo'); + $redis->lset('metavars', 0, 'hoge'); + } +} diff --git a/tests/Predis/Commands/ListTrimTest.php b/tests/Predis/Commands/ListTrimTest.php new file mode 100644 index 00000000..d523d214 --- /dev/null +++ b/tests/Predis/Commands/ListTrimTest.php @@ -0,0 +1,144 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-list + */ +class ListTrimTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ListTrim'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'LTRIM'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 0, 1); + $expected = array('key', 0, 1); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 0, 1); + $expected = array('prefix:key', 0, 1); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testTrimsListWithPositiveStartAndStop() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'l'); + + $this->assertTrue($redis->ltrim('letters', 0, 2)); + $this->assertSame(array('a', 'b', 'c'), $redis->lrange('letters', 0, -1)); + + $redis->flushdb(); + $redis->rpush('letters', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'l'); + + $this->assertTrue($redis->ltrim('letters', 5, 9)); + $this->assertSame(array('f', 'g', 'h', 'i', 'l'), $redis->lrange('letters', 0, -1)); + } + + /** + * @group connected + */ + public function testTrimsListWithPositiveStartAndNegativeStop() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'l'); + + $this->assertTrue($redis->ltrim('letters', 0, -6)); + $this->assertSame(array('a', 'b', 'c', 'd', 'e'), $redis->lrange('letters', 0, -1)); + } + + /** + * @group connected + */ + public function testTrimsListWithNegativeStartAndStop() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'l'); + + $this->assertTrue($redis->ltrim('letters', -5, -5)); + $this->assertSame(array('f'), $redis->lrange('letters', 0, -1)); + } + + /** + * @group connected + */ + public function testHandlesStartAndStopOverflow() + { + $redis = $this->getClient(); + + $redis->rpush('letters', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'l'); + + $this->assertTrue($redis->ltrim('letters', -100, 100)); + $this->assertSame(array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'l'), $redis->lrange('letters', -100, 100)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('metavars', 'foo'); + $redis->ltrim('metavars', 0, 1); + } +} diff --git a/tests/Predis/Commands/PrefixHelpersTest.php b/tests/Predis/Commands/PrefixHelpersTest.php new file mode 100644 index 00000000..f5d672a4 --- /dev/null +++ b/tests/Predis/Commands/PrefixHelpersTest.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * + */ +class PrefixHelpersTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testPrefixFirst() + { + $arguments = array('1st', '2nd', '3rd', '4th'); + $expected = array('prefix:1st', '2nd', '3rd', '4th'); + + $command = $this->getMockForAbstractClass('Predis\Commands\Command'); + $command->setRawArguments($arguments); + + PrefixHelpers::first($command, 'prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testPrefixAll() + { + $arguments = array('1st', '2nd', '3rd', '4th'); + $expected = array('prefix:1st', 'prefix:2nd', 'prefix:3rd', 'prefix:4th'); + + $command = $this->getMockForAbstractClass('Predis\Commands\Command'); + $command->setRawArguments($arguments); + + PrefixHelpers::all($command, 'prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testPrefixInterleaved() + { + $arguments = array('1st', '2nd', '3rd', '4th'); + $expected = array('prefix:1st', '2nd', 'prefix:3rd', '4th'); + + $command = $this->getMockForAbstractClass('Predis\Commands\Command'); + $command->setRawArguments($arguments); + + PrefixHelpers::interleaved($command, 'prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testPrefixSkipLast() + { + $arguments = array('1st', '2nd', '3rd', '4th'); + $expected = array('prefix:1st', 'prefix:2nd', 'prefix:3rd', '4th'); + + $command = $this->getMockForAbstractClass('Predis\Commands\Command'); + $command->setRawArguments($arguments); + + PrefixHelpers::skipLast($command, 'prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } +} diff --git a/tests/Predis/Commands/PrefixableCommandTest.php b/tests/Predis/Commands/PrefixableCommandTest.php new file mode 100644 index 00000000..8c391a9a --- /dev/null +++ b/tests/Predis/Commands/PrefixableCommandTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * + */ +class PrefixableCommandTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testImplementsCorrectInterface() + { + $command = $this->getMockForAbstractClass('Predis\Commands\PrefixableCommand'); + + $this->assertInstanceOf('Predis\Commands\IPrefixable', $command); + $this->assertInstanceOf('Predis\Commands\ICommand', $command); + } + + /** + * @group disconnected + */ + public function testAddPrefixToFirstArgument() + { + $command = $this->getMockForAbstractClass('Predis\Commands\PrefixableCommand'); + $command->setRawArguments(array('key', 'value')); + $command->prefixKeys('prefix:'); + + $this->assertSame(array('prefix:key', 'value'), $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testDoesNotBreakOnEmptyArguments() + { + $command = $this->getMockForAbstractClass('Predis\Commands\PrefixableCommand'); + $command->prefixKeys('prefix:'); + + $this->assertEmpty($command->getArguments()); + } +} diff --git a/tests/Predis/Commands/Processors/KeyPrefixProcessorTest.php b/tests/Predis/Commands/Processors/KeyPrefixProcessorTest.php new file mode 100644 index 00000000..b197500e --- /dev/null +++ b/tests/Predis/Commands/Processors/KeyPrefixProcessorTest.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands\Processors; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * + */ +class KeyPrefixProcessorTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testConstructorWithPrefix() + { + $prefix = 'prefix:'; + $processor = new KeyPrefixProcessor($prefix); + + $this->assertInstanceOf('Predis\Commands\Processors\ICommandProcessor', $processor); + $this->assertEquals($prefix, $processor->getPrefix()); + } + + /** + * @group disconnected + */ + public function testChangePrefix() + { + $prefix1 = 'prefix:'; + $prefix2 = 'prefix:new:'; + + $processor = new KeyPrefixProcessor($prefix1); + $this->assertEquals($prefix1, $processor->getPrefix()); + + $processor->setPrefix($prefix2); + $this->assertEquals($prefix2, $processor->getPrefix()); + } + + /** + * @group disconnected + */ + public function testProcessPrefixableCommands() + { + $prefix = 'prefix:'; + $unprefixed = 'key'; + $expected = "$prefix$unprefixed"; + + $command = $this->getMock('Predis\Commands\PrefixableCommand'); + $command->expects($this->once()) + ->method('prefixKeys') + ->with($prefix); + + $processor = new KeyPrefixProcessor($prefix); + + $processor->process($command); + } + + /** + * @group disconnected + */ + public function testProcessNotPrefixableCommands() + { + $prefix = 'prefix:'; + $unprefixed = 'key'; + $expected = "$prefix$unprefixed"; + + $command = $this->getMock('Predis\Commands\ICommand'); + $command->expects($this->never())->method('prefixKeys'); + + $processor = new KeyPrefixProcessor($prefix); + + $processor->process($command); + } +} diff --git a/tests/Predis/Commands/Processors/ProcessorChainTest.php b/tests/Predis/Commands/Processors/ProcessorChainTest.php new file mode 100644 index 00000000..39be7dad --- /dev/null +++ b/tests/Predis/Commands/Processors/ProcessorChainTest.php @@ -0,0 +1,170 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands\Processors; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * + */ +class ProcessorChainTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testConstructor() + { + $chain = new ProcessorChain(); + + $this->assertInstanceOf('Predis\Commands\Processors\ICommandProcessor', $chain); + $this->assertInstanceOf('Predis\Commands\Processors\ICommandProcessorChain', $chain); + $this->assertEmpty($chain->getProcessors()); + } + + /** + * @group disconnected + */ + public function testConstructorWithProcessorsArray() + { + $processors = array( + $this->getMock('Predis\Commands\Processors\ICommandProcessor'), + $this->getMock('Predis\Commands\Processors\ICommandProcessor'), + ); + + $chain = new ProcessorChain($processors); + + $this->assertSame($processors, $chain->getProcessors()); + } + + /** + * @group disconnected + */ + public function testCountProcessors() + { + $processors = array( + $this->getMock('Predis\Commands\Processors\ICommandProcessor'), + $this->getMock('Predis\Commands\Processors\ICommandProcessor'), + ); + + $chain = new ProcessorChain($processors); + + $this->assertEquals(2, $chain->count()); + } + + /** + * @group disconnected + */ + public function testAddProcessors() + { + $processors = array( + $this->getMock('Predis\Commands\Processors\ICommandProcessor'), + $this->getMock('Predis\Commands\Processors\ICommandProcessor'), + ); + + $chain = new ProcessorChain(); + $chain->add($processors[0]); + $chain->add($processors[1]); + + $this->assertSame($processors, $chain->getProcessors()); + } + + /** + * @group disconnected + */ + public function testAddMoreProcessors() + { + $processors1 = array( + $this->getMock('Predis\Commands\Processors\ICommandProcessor'), + $this->getMock('Predis\Commands\Processors\ICommandProcessor'), + ); + + $processors2 = array( + $this->getMock('Predis\Commands\Processors\ICommandProcessor'), + $this->getMock('Predis\Commands\Processors\ICommandProcessor'), + ); + + $chain = new ProcessorChain($processors1); + $chain->add($processors2[0]); + $chain->add($processors2[1]); + + $this->assertSame(array_merge($processors1, $processors2), $chain->getProcessors()); + } + + /** + * @group disconnected + */ + public function testRemoveProcessors() + { + $processors = array( + $this->getMock('Predis\Commands\Processors\ICommandProcessor'), + $this->getMock('Predis\Commands\Processors\ICommandProcessor'), + ); + + $chain = new ProcessorChain($processors); + + $chain->remove($processors[0]); + $this->assertSame(array($processors[1]), $chain->getProcessors()); + + $chain->remove($processors[1]); + $this->assertEmpty($chain->getProcessors()); + } + + /** + * @group disconnected + */ + public function testRemoveProcessorNotInChain() + { + $processor = $this->getMock('Predis\Commands\Processors\ICommandProcessor'); + $processors = array( + $this->getMock('Predis\Commands\Processors\ICommandProcessor'), + $this->getMock('Predis\Commands\Processors\ICommandProcessor'), + ); + + $chain = new ProcessorChain($processors); + $chain->remove($processor); + + $this->assertSame($processors, $chain->getProcessors()); + } + + /** + * @group disconnected + */ + public function testRemoveProcessorFromEmptyChain() + { + $processor = $this->getMock('Predis\Commands\Processors\ICommandProcessor'); + + $chain = new ProcessorChain(); + $this->assertEmpty($chain->getProcessors()); + + $chain->remove($processor); + $this->assertEmpty($chain->getProcessors()); + } + + /** + * @group disconnected + */ + public function testProcessChain() + { + $command = $this->getMock('Predis\Commands\ICommand'); + + $processor1 = $this->getMock('Predis\Commands\Processors\ICommandProcessor'); + $processor1->expects($this->once())->method('process')->with($command); + + $processor2 = $this->getMock('Predis\Commands\Processors\ICommandProcessor'); + $processor2->expects($this->once())->method('process')->with($command); + + $processors = array($processor1, $processor2); + + $chain = new ProcessorChain($processors); + $chain->process($command); + } +} diff --git a/tests/Predis/Commands/PubSubPublishTest.php b/tests/Predis/Commands/PubSubPublishTest.php new file mode 100644 index 00000000..5d1b02ba --- /dev/null +++ b/tests/Predis/Commands/PubSubPublishTest.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-pubsub + */ +class PubSubPublishTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\PubSubPublish'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'PUBLISH'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('channel', 'message'); + $expected = array('channel', 'message'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('channel', 'message'); + $expected = array('prefix:channel', 'message'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testPublishesMessagesToChannel() + { + $redis1 = $this->getClient(); + $redis2 = $this->getClient(); + + $redis1->subscribe('channel:foo'); + + $this->assertSame(1, $redis2->publish('channel:foo', 'bar')); + $this->assertSame(0, $redis2->publish('channel:hoge', 'piyo')); + } +} diff --git a/tests/Predis/Commands/PubSubSubscribeByPatternTest.php b/tests/Predis/Commands/PubSubSubscribeByPatternTest.php new file mode 100644 index 00000000..ad3b6a8f --- /dev/null +++ b/tests/Predis/Commands/PubSubSubscribeByPatternTest.php @@ -0,0 +1,173 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-pubsub + */ +class PubSubSubscribeByPatternTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\PubSubSubscribeByPattern'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'PSUBSCRIBE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('channel:foo:*', 'channel:hoge:*'); + $expected = array('channel:foo:*', 'channel:hoge:*'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsAsSingleArray() + { + $arguments = array(array('channel:foo:*', 'channel:hoge:*')); + $expected = array('channel:foo:*', 'channel:hoge:*'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('psubscribe', 'channel:*', 1); + $expected = array('psubscribe', 'channel:*', 1); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('channel:foo:*', 'channel:hoge:*'); + $expected = array('prefix:channel:foo:*', 'prefix:channel:hoge:*'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsTheFirstPsubscribedChannelDetails() + { + $redis = $this->getClient(); + + $this->assertSame(array('psubscribe', 'channel:*', 1), $redis->psubscribe('channel:*')); + } + + /** + * @group connected + */ + public function testCanSendPsubscribeAfterPsubscribe() + { + $redis = $this->getClient(); + + $this->assertSame(array('psubscribe', 'channel:foo:*', 1), $redis->psubscribe('channel:foo:*')); + $this->assertSame(array('psubscribe', 'channel:hoge:*', 2), $redis->psubscribe('channel:hoge:*')); + } + + /** + * @group connected + */ + public function testCanSendSubscribeAfterPsubscribe() + { + $redis = $this->getClient(); + + $this->assertSame(array('psubscribe', 'channel:foo:*', 1), $redis->psubscribe('channel:foo:*')); + $this->assertSame(array('subscribe', 'channel:foo:bar', 2), $redis->subscribe('channel:foo:bar')); + } + + /** + * @group connected + */ + public function testCanSendUnsubscribeAfterPsubscribe() + { + $redis = $this->getClient(); + + $this->assertSame(array('psubscribe', 'channel:foo:*', 1), $redis->psubscribe('channel:foo:*')); + $this->assertSame(array('psubscribe', 'channel:hoge:*', 2), $redis->psubscribe('channel:hoge:*')); + $this->assertSame(array('unsubscribe', 'channel:foo:bar', 2), $redis->unsubscribe('channel:foo:bar')); + } + + /** + * @group connected + */ + public function testCanSendPunsubscribeAfterPsubscribe() + { + $redis = $this->getClient(); + + $this->assertSame(array('psubscribe', 'channel:foo:*', 1), $redis->psubscribe('channel:foo:*')); + $this->assertSame(array('psubscribe', 'channel:hoge:*', 2), $redis->psubscribe('channel:hoge:*')); + $this->assertSame(array('punsubscribe', 'channel:*:*', 2), $redis->punsubscribe('channel:*:*')); + } + + /** + * @group connected + */ + public function testCanSendQuitAfterPsubscribe() + { + $redis = $this->getClient(); + $quit = $this->getProfile()->createCommand('quit'); + + $this->assertSame(array('subscribe', 'channel1', 1), $redis->subscribe('channel1')); + $this->assertTrue($redis->executeCommand($quit)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in this context + */ + public function testCannotSendOtherCommandsAfterPsubscribe() + { + $redis = $this->getClient(); + + $redis->psubscribe('channel:*'); + $redis->set('foo', 'bar'); + } +} diff --git a/tests/Predis/Commands/PubSubSubscribeTest.php b/tests/Predis/Commands/PubSubSubscribeTest.php new file mode 100644 index 00000000..c725165f --- /dev/null +++ b/tests/Predis/Commands/PubSubSubscribeTest.php @@ -0,0 +1,173 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-pubsub + */ +class PubSubSubscribeTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\PubSubSubscribe'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SUBSCRIBE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('channel:foo', 'channel:bar'); + $expected = array('channel:foo', 'channel:bar'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsAsSingleArray() + { + $arguments = array(array('channel:foo', 'channel:bar')); + $expected = array('channel:foo', 'channel:bar'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('subscribe', 'channel', 1); + $expected = array('subscribe', 'channel', 1); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array(array('channel:foo', 'channel:bar')); + $expected = array('prefix:channel:foo', 'prefix:channel:bar'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsTheFirstSubscribedChannelDetails() + { + $redis = $this->getClient(); + + $this->assertSame(array('subscribe', 'channel', 1), $redis->subscribe('channel')); + } + + /** + * @group connected + */ + public function testCanSendSubscribeAfterSubscribe() + { + $redis = $this->getClient(); + + $this->assertSame(array('subscribe', 'channel:foo', 1), $redis->subscribe('channel:foo')); + $this->assertSame(array('subscribe', 'channel:bar', 2), $redis->subscribe('channel:bar')); + } + + /** + * @group connected + */ + public function testCanSendPsubscribeAfterSubscribe() + { + $redis = $this->getClient(); + + $this->assertSame(array('subscribe', 'channel:foo', 1), $redis->subscribe('channel:foo')); + $this->assertSame(array('psubscribe', 'channel:*', 2), $redis->psubscribe('channel:*')); + } + + /** + * @group connected + */ + public function testCanSendUnsubscribeAfterSubscribe() + { + $redis = $this->getClient(); + + $this->assertSame(array('subscribe', 'channel:foo', 1), $redis->subscribe('channel:foo')); + $this->assertSame(array('subscribe', 'channel:bar', 2), $redis->subscribe('channel:bar')); + $this->assertSame(array('unsubscribe', 'channel:foo', 1), $redis->unsubscribe('channel:foo')); + } + + /** + * @group connected + */ + public function testCanSendPunsubscribeAfterSubscribe() + { + $redis = $this->getClient(); + + $this->assertSame(array('subscribe', 'channel:foo', 1), $redis->subscribe('channel:foo')); + $this->assertSame(array('subscribe', 'channel:bar', 2), $redis->subscribe('channel:bar')); + $this->assertSame(array('punsubscribe', 'channel:*', 2), $redis->punsubscribe('channel:*')); + } + + /** + * @group connected + */ + public function testCanSendQuitAfterSubscribe() + { + $redis = $this->getClient(); + $quit = $this->getProfile()->createCommand('quit'); + + $this->assertSame(array('subscribe', 'channel:foo', 1), $redis->subscribe('channel:foo')); + $this->assertTrue($redis->executeCommand($quit)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in this context + */ + public function testCannotSendOtherCommandsAfterSubscribe() + { + $redis = $this->getClient(); + + $redis->subscribe('channel:foo'); + $redis->set('foo', 'bar'); + } +} diff --git a/tests/Predis/Commands/PubSubUnsubscribeByPatternTest.php b/tests/Predis/Commands/PubSubUnsubscribeByPatternTest.php new file mode 100644 index 00000000..5531fcc9 --- /dev/null +++ b/tests/Predis/Commands/PubSubUnsubscribeByPatternTest.php @@ -0,0 +1,141 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-pubsub + */ +class PubSubUnsubscribeByPatternTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\PubSubUnsubscribeByPattern'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'PUNSUBSCRIBE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('channel:foo:*', 'channel:bar:*'); + $expected = array('channel:foo:*', 'channel:bar:*'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsAsSingleArray() + { + $arguments = array(array('channel:foo:*', 'channel:bar:*')); + $expected = array('channel:foo:*', 'channel:bar:*'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('punsubscribe', 'channel:*', 1); + $expected = array('punsubscribe', 'channel:*', 1); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array(array('channel:foo:*', 'channel:bar:*')); + $expected = array('prefix:channel:foo:*', 'prefix:channel:bar:*'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testDoesNotSwitchToSubscribeMode() + { + $redis = $this->getClient(); + + $this->assertSame(array('punsubscribe', 'channel:*', 0), $redis->punsubscribe('channel:*')); + $this->assertSame('echoed', $redis->echo('echoed')); + } + + /** + * @group connected + */ + public function testUnsubscribesFromNotSubscribedChannels() + { + $redis = $this->getClient(); + + $this->assertSame(array('punsubscribe', 'channel:*', 0), $redis->punsubscribe('channel:*')); + } + + /** + * @group connected + */ + public function testUnsubscribesFromSubscribedChannels() + { + $redis = $this->getClient(); + + $this->assertSame(array('subscribe', 'channel:foo', 1), $redis->subscribe('channel:foo')); + $this->assertSame(array('subscribe', 'channel:bar', 2), $redis->subscribe('channel:bar')); + $this->assertSame(array('punsubscribe', 'channel:*', 2), $redis->punsubscribe('channel:*')); + } + + /** + * @group connected + * @todo Disabled for now, must investigate why this test hangs on PUNSUBSCRIBE. + */ + public function __testUnsubscribesFromAllSubscribedChannels() + { + $redis = $this->getClient(); + + $this->assertSame(array('subscribe', 'channel:foo', 1), $redis->subscribe('channel:foo')); + $this->assertSame(array('subscribe', 'channel:bar', 2), $redis->subscribe('channel:bar')); + + $this->assertSame(array('punsubscribe', 'channel:foo', 1), $redis->punsubscribe()); + $this->assertSame(array('punsubscribe', 'channel:bar', 0), $redis->getConnection()->read()); + $this->assertSame('echoed', $redis->echo('echoed')); + } +} diff --git a/tests/Predis/Commands/PubSubUnsubscribeTest.php b/tests/Predis/Commands/PubSubUnsubscribeTest.php new file mode 100644 index 00000000..34f07b5a --- /dev/null +++ b/tests/Predis/Commands/PubSubUnsubscribeTest.php @@ -0,0 +1,139 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-pubsub + */ +class PubSubUnsubscribeTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\PubSubUnsubscribe'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'UNSUBSCRIBE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('channel1', 'channel2', 'channel3'); + $expected = array('channel1', 'channel2', 'channel3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsAsSingleArray() + { + $arguments = array(array('channel1', 'channel2', 'channel3')); + $expected = array('channel1', 'channel2', 'channel3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('unsubscribe', 'channel', 1); + $expected = array('unsubscribe', 'channel', 1); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array(array('channel1', 'channel2', 'channel3')); + $expected = array('prefix:channel1', 'prefix:channel2', 'prefix:channel3'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testDoesNotSwitchToSubscribeMode() + { + $redis = $this->getClient(); + + $this->assertSame(array('unsubscribe', 'channel', 0), $redis->unsubscribe('channel')); + $this->assertSame('echoed', $redis->echo('echoed')); + } + + /** + * @group connected + */ + public function testUnsubscribesFromNotSubscribedChannels() + { + $redis = $this->getClient(); + + $this->assertSame(array('unsubscribe', 'channel', 0), $redis->unsubscribe('channel')); + } + + /** + * @group connected + */ + public function testUnsubscribesFromSubscribedChannels() + { + $redis = $this->getClient(); + + $this->assertSame(array('subscribe', 'channel', 1), $redis->subscribe('channel')); + $this->assertSame(array('unsubscribe', 'channel', 0), $redis->unsubscribe('channel')); + } + + /** + * @group connected + */ + public function testUnsubscribesFromAllSubscribedChannels() + { + $redis = $this->getClient(); + + $this->assertSame(array('subscribe', 'channel:foo', 1), $redis->subscribe('channel:foo')); + $this->assertSame(array('subscribe', 'channel:bar', 2), $redis->subscribe('channel:bar')); + + $this->assertSame(array('unsubscribe', 'channel:foo', 1), $redis->unsubscribe()); + $this->assertSame(array('unsubscribe', 'channel:bar', 0), $redis->getConnection()->read()); + $this->assertSame('echoed', $redis->echo('echoed')); + } +} diff --git a/tests/Predis/Commands/ScriptedCommandTest.php b/tests/Predis/Commands/ScriptedCommandTest.php new file mode 100644 index 00000000..48331eaa --- /dev/null +++ b/tests/Predis/Commands/ScriptedCommandTest.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group realm-scripting + */ +class ScriptedCommandTest extends StandardTestCase +{ + const LUA_SCRIPT = 'return { KEYS[1], KEYS[2], ARGV[1], ARGV[2] }'; + + /** + * @group disconnected + */ + public function testGetArguments() + { + $arguments = array('key1', 'key2', 'value1', 'value2'); + + $command = $this->getMock('Predis\Commands\ScriptedCommand', array('getScript', 'getKeysCount')); + $command->expects($this->once()) + ->method('getScript') + ->will($this->returnValue(self::LUA_SCRIPT)); + $command->expects($this->once()) + ->method('getKeysCount') + ->will($this->returnValue(2)); + $command->setArguments($arguments); + + $this->assertSame(array_merge(array(self::LUA_SCRIPT, 2), $arguments), $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testGetKeys() + { + $arguments = array('key1', 'key2', 'value1', 'value2'); + + $command = $this->getMock('Predis\Commands\ScriptedCommand', array('getScript', 'getKeysCount')); + $command->expects($this->once()) + ->method('getScript') + ->will($this->returnValue(self::LUA_SCRIPT)); + $command->expects($this->exactly(2)) + ->method('getKeysCount') + ->will($this->returnValue(2)); + $command->setArguments($arguments); + + $this->assertSame(array('key1', 'key2'), $command->getKeys()); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('foo', 'hoge', 'bar', 'piyo'); + $expected = array('prefix:foo', 'prefix:hoge'); + + $command = $this->getMock('Predis\Commands\ScriptedCommand', array('getScript', 'getKeysCount')); + $command->expects($this->once()) + ->method('getScript') + ->will($this->returnValue(self::LUA_SCRIPT)); + $command->expects($this->exactly(2)) + ->method('getKeysCount') + ->will($this->returnValue(2)); + $command->setArguments($arguments); + + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getKeys()); + } + + /** + * @group disconnected + */ + public function testGetScriptHash() + { + $arguments = array('key1', 'key2', 'value1', 'value2'); + + $command = $this->getMock('Predis\Commands\ScriptedCommand', array('getScript', 'getKeysCount')); + $command->expects($this->once()) + ->method('getScript') + ->will($this->returnValue(self::LUA_SCRIPT)); + $command->expects($this->once()) + ->method('getKeysCount') + ->will($this->returnValue(2)); + $command->setArguments($arguments); + + $this->assertSame(sha1(self::LUA_SCRIPT), $command->getScriptHash()); + } +} diff --git a/tests/Predis/Commands/ServerBackgroundRewriteAOFTest.php b/tests/Predis/Commands/ServerBackgroundRewriteAOFTest.php new file mode 100644 index 00000000..d0c32f2d --- /dev/null +++ b/tests/Predis/Commands/ServerBackgroundRewriteAOFTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-server + */ +class ServerBackgroundRewriteAOFTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerBackgroundRewriteAOF'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'BGREWRITEAOF'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $command = $this->getCommand(); + $command->setArguments(array()); + + $this->assertSame(array(), $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } +} diff --git a/tests/Predis/Commands/ServerBackgroundSaveTest.php b/tests/Predis/Commands/ServerBackgroundSaveTest.php new file mode 100644 index 00000000..5f46da6f --- /dev/null +++ b/tests/Predis/Commands/ServerBackgroundSaveTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-server + */ +class ServerBackgroundSaveTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerBackgroundSave'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'BGSAVE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $command = $this->getCommand(); + $command->setArguments(array()); + + $this->assertSame(array(), $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } +} diff --git a/tests/Predis/Commands/ServerClientTest.php b/tests/Predis/Commands/ServerClientTest.php new file mode 100644 index 00000000..0e360dad --- /dev/null +++ b/tests/Predis/Commands/ServerClientTest.php @@ -0,0 +1,142 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-server + */ +class ServerClientTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerClient'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'CLIENT'; + } + + /** + * @group disconnected + */ + public function testFilterArgumentsOfClientKill() + { + $arguments = array('kill', '127.0.0.1:45393'); + $expected = array('kill', '127.0.0.1:45393'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsOfClientList() + { + $arguments = array('list'); + $expected = array('list'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponseOfClientKill() + { + $command = $this->getCommand(); + $command->setArguments(array('kill')); + + $this->assertSame(true, $command->parseResponse(true)); + } + + /** + * @group disconnected + */ + public function testParseResponseOfClientList() + { + $command = $this->getCommand(); + $command->setArguments(array('list')); + + $raw =<<'127.0.0.1:45393','fd'=>'6','idle'=>'0','flags'=>'N','db'=>'0','sub'=>'0','psub'=>'0'), + array('addr'=>'127.0.0.1:45394','fd'=>'7','idle'=>'0','flags'=>'N','db'=>'0','sub'=>'0','psub'=>'0'), + array('addr'=>'127.0.0.1:45395','fd'=>'8','idle'=>'0','flags'=>'N','db'=>'0','sub'=>'0','psub'=>'0'), + ); + + $this->assertSame($parsed, $command->parseResponse($raw)); + } + + /** + * @group connected + */ + public function testReturnsListOfConnectedClients() + { + $redis = $this->getClient(); + + $this->assertInternalType('array', $clients = $redis->client('LIST')); + $this->assertGreaterThanOrEqual(1, count($clients)); + $this->assertInternalType('array', $clients[0]); + $this->assertArrayHasKey('addr', $clients[0]); + $this->assertArrayHasKey('fd', $clients[0]); + $this->assertArrayHasKey('idle', $clients[0]); + $this->assertArrayHasKey('flags', $clients[0]); + $this->assertArrayHasKey('db', $clients[0]); + $this->assertArrayHasKey('sub', $clients[0]); + $this->assertArrayHasKey('psub', $clients[0]); + } + + /** + * @group connected + * @expectedException Predis\ServerException + */ + public function testThrowsExceptioOnWrongModifier() + { + $redis = $this->getClient(); + + $this->assertTrue($redis->client('FOO')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR No such client + */ + public function testThrowsExceptionWhenKillingUnknownClient() + { + $redis = $this->getClient(); + + $this->assertTrue($redis->client('KILL', '127.0.0.1:65535')); + } +} diff --git a/tests/Predis/Commands/ServerConfigTest.php b/tests/Predis/Commands/ServerConfigTest.php new file mode 100644 index 00000000..259d9067 --- /dev/null +++ b/tests/Predis/Commands/ServerConfigTest.php @@ -0,0 +1,173 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-server + */ +class ServerConfigTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerConfig'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'CONFIG'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('GET', 'slowlog'); + $expected = array('GET', 'slowlog'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponseOfConfigGet() + { + $raw = array('slowlog-log-slower-than','10000','slowlog-max-len','64','loglevel','verbose'); + $expected = array( + 'slowlog-log-slower-than' => '10000', + 'slowlog-max-len' => '64', + 'loglevel' => 'verbose', + ); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testParseResponseOfConfigSet() + { + $command = $this->getCommand(); + + $this->assertTrue($command->parseResponse(true)); + } + + /** + * @group disconnected + */ + public function testParseResponseOfConfigResetstat() + { + $command = $this->getCommand(); + + $this->assertTrue($command->parseResponse(true)); + } + + /** + * @group connected + */ + public function testReturnsListOfConfigurationValues() + { + $redis = $this->getClient(); + + $this->assertInternalType('array', $configs = $redis->config('GET', '*')); + $this->assertGreaterThan(1, count($configs)); + $this->assertArrayHasKey('loglevel', $configs); + $this->assertArrayHasKey('appendonly', $configs); + $this->assertArrayHasKey('dbfilename', $configs); + } + + /** + * @group connected + */ + public function testReturnsListOfOneConfigurationEntry() + { + $redis = $this->getClient(); + + $this->assertInternalType('array', $configs = $redis->config('GET', 'dbfilename')); + $this->assertEquals(1, count($configs)); + $this->assertArrayHasKey('dbfilename', $configs); + } + + /** + * @group connected + */ + public function testReturnsEmptyListOnUnknownConfigurationEntry() + { + $redis = $this->getClient(); + + $this->assertSame(array(), $redis->config('GET', 'foobar')); + } + + /** + * @group connected + */ + public function testReturnsTrueOnSuccessfulConfiguration() + { + $redis = $this->getClient(); + + $previous = $redis->config('GET', 'loglevel'); + + $this->assertTrue($redis->config('SET', 'loglevel', 'notice')); + $this->assertSame(array('loglevel' => 'notice'), $redis->config('GET', 'loglevel')); + + // We set the loglevel configuration to the previous value. + $redis->config('SET', 'loglevel', $previous['loglevel']); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Unsupported CONFIG parameter: foo + */ + public function testThrowsExceptionWhenSettingUnknownConfiguration() + { + $redis = $this->getClient(); + + $this->assertFalse($redis->config('SET', 'foo', 'bar')); + } + + /** + * @group connected + */ + public function testReturnsTrueOnResetstat() + { + $redis = $this->getClient(); + + $this->assertTrue($redis->config('RESETSTAT')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + */ + public function testThrowsExceptionOnUnknownSubcommand() + { + $redis = $this->getClient(); + + $this->assertFalse($redis->config('FOO')); + } +} diff --git a/tests/Predis/Commands/ServerDatabaseSizeTest.php b/tests/Predis/Commands/ServerDatabaseSizeTest.php new file mode 100644 index 00000000..61b874c3 --- /dev/null +++ b/tests/Predis/Commands/ServerDatabaseSizeTest.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-server + */ +class ServerDatabaseSizeTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerDatabaseSize'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'DBSIZE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $command = $this->getCommand(); + $command->setArguments(array()); + + $this->assertSame(array(), $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(100, $this->getCommand()->parseResponse(100)); + } + + /** + * @group connected + */ + public function testReturnsCurrentSizeOfDatabase() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $this->assertGreaterThan(0, $redis->dbsize()); + } +} diff --git a/tests/Predis/Commands/ServerEvalSHATest.php b/tests/Predis/Commands/ServerEvalSHATest.php new file mode 100644 index 00000000..fdc2080d --- /dev/null +++ b/tests/Predis/Commands/ServerEvalSHATest.php @@ -0,0 +1,118 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-scripting + */ +class ServerEvalSHATest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerEvalSHA'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'EVALSHA'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('9d0c0826bde023cc39eebaaf832c32a890f3b088', 1, 'foo', 'bar'); + $expected = array('9d0c0826bde023cc39eebaaf832c32a890f3b088', 1, 'foo', 'bar'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertSame('bar', $this->getCommand()->parseResponse('bar')); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $sha1 = 'a42059b356c875f0717db19a51f6aaca9ae659ea'; + + $arguments = array($sha1, 2, 'foo', 'hoge', 'bar', 'piyo'); + $expected = array($sha1, 2, 'prefix:foo', 'prefix:hoge', 'bar', 'piyo'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testExecutesSpecifiedLuaScript() + { + $redis = $this->getClient(); + + $lua = 'return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}'; + $sha1 = sha1($lua); + $result = array('foo', 'hoge', 'bar', 'piyo'); + + $this->assertSame($result, $redis->eval($lua, 2, 'foo', 'hoge', 'bar', 'piyo')); + $this->assertSame($result, $redis->evalsha($sha1, 2, 'foo', 'hoge', 'bar', 'piyo')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + */ + public function testThrowsExceptionOnWrongNumberOfKeys() + { + $redis = $this->getClient(); + + $lua = 'return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}'; + $sha1 = sha1($lua); + + $redis->eval($lua, 2, 'foo', 'hoge', 'bar', 'piyo'); + $redis->evalsha($sha1, 3, 'foo', 'hoge'); + } + + /** + * @group connected + * @expectedException Predis\ServerException + */ + public function testThrowsExceptionOnInvalidScript() + { + $redis = $this->getClient(); + + $redis->evalsha('ffffffffffffffffffffffffffffffffffffffff', 0); + } +} diff --git a/tests/Predis/Commands/ServerEvalTest.php b/tests/Predis/Commands/ServerEvalTest.php new file mode 100644 index 00000000..0c3ea54a --- /dev/null +++ b/tests/Predis/Commands/ServerEvalTest.php @@ -0,0 +1,122 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-scripting + */ +class ServerEvalTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerEval'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'EVAL'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('return redis.call("SET", KEYS[1], ARGV[1])', 1, 'foo', 'bar'); + $expected = array('return redis.call("SET", KEYS[1], ARGV[1])', 1, 'foo', 'bar'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertSame('bar', $this->getCommand()->parseResponse('bar')); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $lua = 'return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}'; + + $arguments = array($lua, 2, 'foo', 'hoge', 'bar', 'piyo'); + $expected = array($lua, 2, 'prefix:foo', 'prefix:hoge', 'bar', 'piyo'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testGetScriptHash() + { + $command = $this->getCommandWithArgumentsArray(array($lua = 'return true', 0)); + $this->assertSame(sha1($lua), $command->getScriptHash()); + } + + /** + * @group connected + */ + public function testExecutesSpecifiedLuaScript() + { + $redis = $this->getClient(); + + $lua = 'return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}'; + $result = array('foo', 'hoge', 'bar', 'piyo'); + + $this->assertSame($result, $redis->eval($lua, 2, 'foo', 'hoge', 'bar', 'piyo')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + */ + public function testThrowsExceptionOnWrongNumberOfKeys() + { + $redis = $this->getClient(); + $lua = 'return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}'; + + $redis->eval($lua, 3, 'foo', 'hoge'); + } + + /** + * @group connected + * @expectedException Predis\ServerException + */ + public function testThrowsExceptionOnInvalidScript() + { + $redis = $this->getClient(); + + $redis->eval('invalid', 0); + } +} diff --git a/tests/Predis/Commands/ServerFlushAllTest.php b/tests/Predis/Commands/ServerFlushAllTest.php new file mode 100644 index 00000000..6d1303bc --- /dev/null +++ b/tests/Predis/Commands/ServerFlushAllTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-server + */ +class ServerFlushAllTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerFlushAll'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'FLUSHALL'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $command = $this->getCommand(); + $command->setArguments(array()); + + $this->assertSame(array(), $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } +} diff --git a/tests/Predis/Commands/ServerFlushDatabaseTest.php b/tests/Predis/Commands/ServerFlushDatabaseTest.php new file mode 100644 index 00000000..c1af9433 --- /dev/null +++ b/tests/Predis/Commands/ServerFlushDatabaseTest.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-server + */ +class ServerFlushDatabaseTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerFlushDatabase'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'FLUSHDB'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $command = $this->getCommand(); + $command->setArguments(array()); + + $this->assertSame(array(), $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } + + /** + * @group connected + */ + public function testFlushesTheEntireLogicalDatabase() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + + $this->assertTrue($redis->flushdb()); + $this->assertFalse($redis->exists('foo')); + } +} diff --git a/tests/Predis/Commands/ServerInfoTest.php b/tests/Predis/Commands/ServerInfoTest.php new file mode 100644 index 00000000..7fc12809 --- /dev/null +++ b/tests/Predis/Commands/ServerInfoTest.php @@ -0,0 +1,289 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-server + */ +class ServerInfoTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerInfo'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'INFO'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $command = $this->getCommand(); + $command->setArguments(array()); + + $this->assertSame(array(), $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw =<< '2.4.4', + 'redis_git_sha1' => 'bc62bc5e', + 'redis_git_dirty' => '0', + 'arch_bits' => '32', + 'multiplexing_api' => 'epoll', + 'process_id' => '15640', + 'uptime_in_seconds' => '792', + 'uptime_in_days' => '0', + 'lru_clock' => '197890', + 'used_cpu_sys' => '0.08', + 'used_cpu_user' => '0.10', + 'used_cpu_sys_children' => '0.00', + 'used_cpu_user_children' => '0.00', + 'connected_clients' => '1', + 'connected_slaves' => '0', + 'client_longest_output_list' => '0', + 'client_biggest_input_buf' => '0', + 'blocked_clients' => '0', + 'used_memory' => '556156', + 'used_memory_human' => '543.12K', + 'used_memory_rss' => '1396736', + 'used_memory_peak' => '547688', + 'used_memory_peak_human' => '534.85K', + 'mem_fragmentation_ratio' => '2.51', + 'mem_allocator' => 'jemalloc-2.2.1', + 'loading' => '0', + 'aof_enabled' => '0', + 'changes_since_last_save' => '0', + 'bgsave_in_progress' => '0', + 'last_save_time' => '1323183872', + 'bgrewriteaof_in_progress' => '0', + 'total_connections_received' => '2', + 'total_commands_processed' => '1', + 'expired_keys' => '0', + 'evicted_keys' => '0', + 'keyspace_hits' => '0', + 'keyspace_misses' => '0', + 'pubsub_channels' => '0', + 'pubsub_patterns' => '0', + 'latest_fork_usec' => '0', + 'vm_enabled' => '0', + 'role' => 'master', + 'db0' => array('keys' => '2', 'expires' => '0'), + 'db5' => array('keys' => '1', 'expires' => '0'), + ); + + $this->assertSame($expected, $this->getCommand()->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testCanParseResponsesFromRedis30() + { + $raw =<< '2.9.0', + 'redis_git_sha1' => '237194b7', + 'redis_git_dirty' => '0', + 'arch_bits' => '32', + 'multiplexing_api' => 'epoll', + 'process_id' => '16620', + 'tcp_port' => '6379', + 'uptime_in_seconds' => '444', + 'uptime_in_days' => '0', + 'lru_clock' => '198040', + 'connected_clients' => '1', + 'client_longest_output_list' => '0', + 'client_biggest_input_buf' => '0', + 'blocked_clients' => '0', + 'used_memory' => '628076', + 'used_memory_human' => '613.36K', + 'used_memory_rss' => '1568768', + 'used_memory_peak' => '570056', + 'used_memory_peak_human' => '556.70K', + 'used_memory_lua' => '14336', + 'mem_fragmentation_ratio' => '2.50', + 'mem_allocator' => 'jemalloc-2.2.1', + 'loading' => '0', + 'aof_enabled' => '0', + 'changes_since_last_save' => '0', + 'bgsave_in_progress' => '0', + 'last_save_time' => '1323185719', + 'bgrewriteaof_in_progress' => '0', + 'total_connections_received' => '4', + 'total_commands_processed' => '3', + 'rejected_connections' => '0', + 'expired_keys' => '0', + 'evicted_keys' => '0', + 'keyspace_hits' => '0', + 'keyspace_misses' => '0', + 'pubsub_channels' => '0', + 'pubsub_patterns' => '0', + 'latest_fork_usec' => '0', + 'role' => 'master', + 'connected_slaves' => '0', + 'used_cpu_sys' => '0.06', + 'used_cpu_user' => '0.06', + 'used_cpu_sys_children' => '0.00', + 'used_cpu_user_children' => '0.00', + 'cluster_enabled' => '0', + 'db0' => array('keys' => '2', 'expires' => '0'), + 'db5' => array('keys' => '1','expires' => '0'), + ); + + $this->assertSame($expected, $this->getCommand()->parseResponse($raw)); + } + + /** + * @group connected + */ + public function testReturnsAnArrayOfInfo() + { + $redis = $this->getClient(); + $command = $this->getCommand(); + + $this->assertInternalType('array', $info = $redis->executeCommand($command)); + $this->assertArrayHasKey('redis_version', $info); + } +} diff --git a/tests/Predis/Commands/ServerInfoV26xTest.php b/tests/Predis/Commands/ServerInfoV26xTest.php new file mode 100644 index 00000000..6fd79f4a --- /dev/null +++ b/tests/Predis/Commands/ServerInfoV26xTest.php @@ -0,0 +1,307 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-server + */ +class ServerInfoV26xTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerInfoV26x'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'INFO'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $command = $this->getCommand(); + $command->setArguments(array()); + + $this->assertSame(array(), $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw =<< array( + 'redis_version' => '2.9.0', + 'redis_git_sha1' => '237194b7', + 'redis_git_dirty' => '0', + 'arch_bits' => '32', + 'multiplexing_api' => 'epoll', + 'process_id' => '16620', + 'tcp_port' => '6379', + 'uptime_in_seconds' => '444', + 'uptime_in_days' => '0', + 'lru_clock' => '198040', + ), + 'Clients' => array( + 'connected_clients' => '1', + 'client_longest_output_list' => '0', + 'client_biggest_input_buf' => '0', + 'blocked_clients' => '0', + ), + 'Memory' => array( + 'used_memory' => '628076', + 'used_memory_human' => '613.36K', + 'used_memory_rss' => '1568768', + 'used_memory_peak' => '570056', + 'used_memory_peak_human' => '556.70K', + 'used_memory_lua' => '14336', + 'mem_fragmentation_ratio' => '2.50', + 'mem_allocator' => 'jemalloc-2.2.1', + ), + 'Persistence' => array( + 'loading' => '0', + 'aof_enabled' => '0', + 'changes_since_last_save' => '0', + 'bgsave_in_progress' => '0', + 'last_save_time' => '1323185719', + 'bgrewriteaof_in_progress' => '0', + ), + 'Stats' => array( + 'total_connections_received' => '4', + 'total_commands_processed' => '3', + 'rejected_connections' => '0', + 'expired_keys' => '0', + 'evicted_keys' => '0', + 'keyspace_hits' => '0', + 'keyspace_misses' => '0', + 'pubsub_channels' => '0', + 'pubsub_patterns' => '0', + 'latest_fork_usec' => '0', + ), + 'Replication' => array( + 'role' => 'master', + 'connected_slaves' => '0', + ), + 'CPU' => array( + 'used_cpu_sys' => '0.06', + 'used_cpu_user' => '0.06', + 'used_cpu_sys_children' => '0.00', + 'used_cpu_user_children' => '0.00', + ), + 'Cluster' => array( + 'cluster_enabled' => '0', + ), + 'Keyspace' => array( + 'db0' => array('keys' => '2', 'expires' => '0'), + 'db5' => array('keys' => '1', 'expires' => '0') + ), + ); + + $this->assertSame($expected, $this->getCommand()->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testCanParseResponsesFromOlderRedisVersions() + { + $raw =<< '2.4.4', + 'redis_git_sha1' => 'bc62bc5e', + 'redis_git_dirty' => '0', + 'arch_bits' => '32', + 'multiplexing_api' => 'epoll', + 'process_id' => '15640', + 'uptime_in_seconds' => '792', + 'uptime_in_days' => '0', + 'lru_clock' => '197890', + 'used_cpu_sys' => '0.08', + 'used_cpu_user' => '0.10', + 'used_cpu_sys_children' => '0.00', + 'used_cpu_user_children' => '0.00', + 'connected_clients' => '1', + 'connected_slaves' => '0', + 'client_longest_output_list' => '0', + 'client_biggest_input_buf' => '0', + 'blocked_clients' => '0', + 'used_memory' => '556156', + 'used_memory_human' => '543.12K', + 'used_memory_rss' => '1396736', + 'used_memory_peak' => '547688', + 'used_memory_peak_human' => '534.85K', + 'mem_fragmentation_ratio' => '2.51', + 'mem_allocator' => 'jemalloc-2.2.1', + 'loading' => '0', + 'aof_enabled' => '0', + 'changes_since_last_save' => '0', + 'bgsave_in_progress' => '0', + 'last_save_time' => '1323183872', + 'bgrewriteaof_in_progress' => '0', + 'total_connections_received' => '2', + 'total_commands_processed' => '1', + 'expired_keys' => '0', + 'evicted_keys' => '0', + 'keyspace_hits' => '0', + 'keyspace_misses' => '0', + 'pubsub_channels' => '0', + 'pubsub_patterns' => '0', + 'latest_fork_usec' => '0', + 'vm_enabled' => '0', + 'role' => 'master', + 'db0' => array('keys' => '2', 'expires' => '0'), + 'db5' => array('keys' => '1', 'expires' => '0'), + ); + + $this->assertSame($expected, $this->getCommand()->parseResponse($raw)); + } + + /** + * @group connected + */ + public function testReturnsAnArrayOfInfo() + { + $redis = $this->getClient(); + $command = $this->getCommand(); + + $this->assertInternalType('array', $info = $redis->executeCommand($command)); + $this->assertArrayHasKey('redis_version', isset($info['Server']) ? $info['Server'] : $info); + } +} diff --git a/tests/Predis/Commands/ServerLastSaveTest.php b/tests/Predis/Commands/ServerLastSaveTest.php new file mode 100644 index 00000000..e74581b2 --- /dev/null +++ b/tests/Predis/Commands/ServerLastSaveTest.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-server + */ +class ServerLastSaveTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerLastSave'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'LASTSAVE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $command = $this->getCommand(); + $command->setArguments(array()); + + $this->assertSame(array(), $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(100, $this->getCommand()->parseResponse(100)); + } + + /** + * @group connected + */ + public function testReturnsIntegerValue() + { + $redis = $this->getClient(); + + $this->assertInternalType('integer', $redis->lastsave()); + } +} diff --git a/tests/Predis/Commands/ServerMonitorTest.php b/tests/Predis/Commands/ServerMonitorTest.php new file mode 100644 index 00000000..b1df9714 --- /dev/null +++ b/tests/Predis/Commands/ServerMonitorTest.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-server + * @group realm-monitor + */ +class ServerMonitorTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerMonitor'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'MONITOR'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $command = $this->getCommand(); + $command->setArguments(array()); + + $this->assertSame(array(), $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } + + /** + * @group connected + */ + public function testReturnsTrueAndReadsEventsFromTheConnection() + { + $connection = $this->getClient()->getConnection(); + $command = $this->getCommand(); + + $this->assertTrue($connection->executeCommand($command)); + $this->assertRegExp('/\d+.\d+(\s?\(db \d+\))? "MONITOR"/', $connection->read()); + } +} diff --git a/tests/Predis/Commands/ServerObjectTest.php b/tests/Predis/Commands/ServerObjectTest.php new file mode 100644 index 00000000..03b8c6ac --- /dev/null +++ b/tests/Predis/Commands/ServerObjectTest.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-server + */ +class ServerObjectTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerObject'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'OBJECT'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('REFCOUNT', 'key'); + $expected = array('REFCOUNT', 'key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame('ziplist', $this->getCommand()->parseResponse('ziplist')); + } + + /** + * @group connected + */ + public function testObjectRefcount() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $this->assertInternalType('integer', $redis->object('REFCOUNT', 'foo')); + } + + /** + * @group connected + */ + public function testObjectIdletime() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $this->assertInternalType('integer', $redis->object('IDLETIME', 'foo')); + } + + /** + * @group connected + */ + public function testObjectEncoding() + { + $redis = $this->getClient(); + + $redis->lpush('list:metavars', 'foo', 'bar'); + $this->assertSame('ziplist', $redis->object('ENCODING', 'list:metavars')); + } + + /** + * @group connected + */ + public function testReturnsNullOnNonExistingKey() + { + $redis = $this->getClient(); + + $this->assertNull($redis->object('REFCOUNT', 'foo')); + $this->assertNull($redis->object('IDLETIME', 'foo')); + $this->assertNull($redis->object('ENCODING', 'foo')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + */ + public function testThrowsExceptionOnInvalidSubcommand() + { + $redis = $this->getClient(); + + $redis->object('INVALID', 'foo'); + } +} diff --git a/tests/Predis/Commands/ServerSaveTest.php b/tests/Predis/Commands/ServerSaveTest.php new file mode 100644 index 00000000..7101699d --- /dev/null +++ b/tests/Predis/Commands/ServerSaveTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-server + */ +class ServerSaveTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerSave'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SAVE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $command = $this->getCommand(); + $command->setArguments(array()); + + $this->assertSame(array(), $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } +} diff --git a/tests/Predis/Commands/ServerScriptTest.php b/tests/Predis/Commands/ServerScriptTest.php new file mode 100644 index 00000000..cb9e3847 --- /dev/null +++ b/tests/Predis/Commands/ServerScriptTest.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-scripting + */ +class ServerScriptTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerScript'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SCRIPT'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('EXISTS', '9d0c0826bde023cc39eebaaf832c32a890f3b088', 'ffffffffffffffffffffffffffffffffffffffff'); + $expected = array('EXISTS', '9d0c0826bde023cc39eebaaf832c32a890f3b088', 'ffffffffffffffffffffffffffffffffffffffff'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } + + /** + * @group connected + * @todo We should probably convert integers to booleans. + */ + public function testExistsReturnAnArrayOfValues() + { + $redis = $this->getClient(); + + $redis->eval($lua = 'return true', 0); + $sha1 = sha1($lua); + + $this->assertSame(array(1, 0), $redis->script('EXISTS', $sha1, 'ffffffffffffffffffffffffffffffffffffffff')); + } + + /** + * @group connected + */ + public function testLoadReturnsHashOfScripts() + { + $redis = $this->getClient(); + + $lua = 'return true'; + $sha1 = sha1($lua); + + $this->assertSame($sha1, $redis->script('LOAD', $lua)); + } + + /** + * @group connected + */ + public function testFlushesExistingScripts() + { + $redis = $this->getClient(); + + $sha1 = $redis->script('LOAD', 'return true'); + + $this->assertTrue($redis->script('FLUSH')); + $this->assertSame(array(0), $redis->script('EXISTS', $sha1)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + */ + public function testThrowsExceptionOnInvalidSubcommand() + { + $redis = $this->getClient(); + + $redis->script('INVALID'); + } +} diff --git a/tests/Predis/Commands/ServerShutdownTest.php b/tests/Predis/Commands/ServerShutdownTest.php new file mode 100644 index 00000000..5402c761 --- /dev/null +++ b/tests/Predis/Commands/ServerShutdownTest.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-server + */ +class ServerShutdownTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerShutdown'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SHUTDOWN'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $command = $this->getCommand(); + $command->setArguments(array()); + + $this->assertSame(array(), $command->getArguments()); + } +} diff --git a/tests/Predis/Commands/ServerSlaveOfTest.php b/tests/Predis/Commands/ServerSlaveOfTest.php new file mode 100644 index 00000000..ad77dbe0 --- /dev/null +++ b/tests/Predis/Commands/ServerSlaveOfTest.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-server + */ +class ServerSlaveOfTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerSlaveOf'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SLAVEOF'; + } + + /** + * @group disconnected + */ + public function testFilterArgumentsHostPortArray() + { + $arguments = array('127.0.0.1', '80'); + $expected = array('127.0.0.1', '80'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsNoOneArray() + { + $arguments = array('NO', 'ONE'); + $expected = array('NO', 'ONE'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsNoOneString() + { + $arguments = array('NO ONE'); + $expected = array('NO', 'ONE'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } +} diff --git a/tests/Predis/Commands/ServerSlowlogTest.php b/tests/Predis/Commands/ServerSlowlogTest.php new file mode 100644 index 00000000..92f579cc --- /dev/null +++ b/tests/Predis/Commands/ServerSlowlogTest.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * In order to support the output of SLOWLOG, the backend connection + * must be able to parse nested multibulk replies deeper than 2 levels. + * + * @group commands + * @group realm-server + */ +class ServerSlowlogTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ServerSlowlog'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SLOWLOG'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('GET', '2'); + $expected = array('GET', '2'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array(array(0, 1323163469, 12451, array('SORT', 'list:unordered'))); + $expected = array( + array( + 'id' => 0, + 'timestamp' => 1323163469, + 'duration' => 12451, + 'command' => array('SORT', 'list:unordered'), + ), + ); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group connected + */ + public function testReturnsAnArrayOfLoggedCommands() + { + $redis = $this->getClient(); + + $threshold = array_pop($redis->config('get', 'slowlog-log-slower-than')); + + $redis->config('set', 'slowlog-log-slower-than', 0); + $redis->set('foo', 'bar'); + + $this->assertInternalType('array', $slowlog = $redis->slowlog('GET')); + $this->assertGreaterThan(0, count($slowlog)); + + $this->assertInternalType('array', $slowlog[0]); + $this->assertGreaterThan(0, $slowlog[0]['id']); + $this->assertGreaterThan(0, $slowlog[0]['timestamp']); + $this->assertGreaterThan(0, $slowlog[0]['duration']); + $this->assertInternalType('array', $slowlog[0]['command']); + + $redis->config('set', 'slowlog-log-slower-than', $threshold); + } + + /** + * @group connected + */ + public function testCanResetTheLog() + { + $redis = $this->getClient(); + + $this->assertTrue($redis->slowlog('RESET')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + */ + public function testThrowsExceptionOnInvalidSubcommand() + { + $redis = $this->getClient(); + + $redis->slowlog('INVALID'); + } +} diff --git a/tests/Predis/Commands/SetAddTest.php b/tests/Predis/Commands/SetAddTest.php new file mode 100644 index 00000000..a15c4bc9 --- /dev/null +++ b/tests/Predis/Commands/SetAddTest.php @@ -0,0 +1,112 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-set + */ +class SetAddTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\SetAdd'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SADD'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'member1', 'member2', 'member3'); + $expected = array('key', 'member1', 'member2', 'member3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsValuesAsSingleArray() + { + $arguments = array('key', array('member1', 'member2', 'member3')); + $expected = array('key', 'member1', 'member2', 'member3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'member1', 'member2', 'member3'); + $expected = array('prefix:key', 'member1', 'member2', 'member3'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testAddsMembersToSet() + { + $redis = $this->getClient(); + + $this->assertSame(1, $redis->sadd('letters', 'a')); + $this->assertSame(2, $redis->sadd('letters', 'b', 'c')); + $this->assertSame(0, $redis->sadd('letters', 'b')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('metavars', 'foo'); + $redis->sadd('metavars', 'hoge'); + } +} diff --git a/tests/Predis/Commands/SetCardinalityTest.php b/tests/Predis/Commands/SetCardinalityTest.php new file mode 100644 index 00000000..49ce7502 --- /dev/null +++ b/tests/Predis/Commands/SetCardinalityTest.php @@ -0,0 +1,108 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-set + */ +class SetCardinalityTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\SetCardinality'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SCARD'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key'); + $expected = array('key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsNumberOfMembers() + { + $redis = $this->getClient(); + + $redis->sadd('letters', 'a', 'b', 'c', 'd'); + + $this->assertSame(4, $redis->scard('letters')); + } + + /** + * @group connected + */ + public function testReturnsZeroOnEmptySet() + { + $redis = $this->getClient(); + + $this->assertSame(0, $redis->scard('letters')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('metavars', 'foo'); + $redis->scard('metavars'); + } +} diff --git a/tests/Predis/Commands/SetDifferenceStoreTest.php b/tests/Predis/Commands/SetDifferenceStoreTest.php new file mode 100644 index 00000000..010f1593 --- /dev/null +++ b/tests/Predis/Commands/SetDifferenceStoreTest.php @@ -0,0 +1,131 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-set + */ +class SetDifferenceStoreTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\SetDifferenceStore'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SDIFFSTORE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key:destination', 'key:source1', 'key:source:2'); + $expected = array('key:destination', 'key:source1', 'key:source:2'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsSourceKeysAsSingleArray() + { + $arguments = array('key:destination', array('key:source1', 'key:source:2')); + $expected = array('key:destination', 'key:source1', 'key:source:2'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key:destination', 'key:source1', 'key:source:2'); + $expected = array('prefix:key:destination', 'prefix:key:source1', 'prefix:key:source:2'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testStoresMembersOfSetOnSingleSet() + { + $redis = $this->getClient(); + + $redis->sadd('letters:1st', 'a', 'b', 'c', 'd', 'e', 'f', 'g'); + + $this->assertSame(7, $redis->sdiffstore('letters:destination', 'letters:1st')); + $this->assertSameValues(array( 'a', 'b', 'c', 'd', 'e', 'f', 'g'), $redis->smembers('letters:destination')); + } + + /** + * @group connected + */ + public function testStoresDifferenceOfMultipleSets() + { + $redis = $this->getClient(); + + $redis->sadd('letters:1st', 'a', 'b', 'c', 'd', 'e', 'f', 'g'); + $redis->sadd('letters:2nd', 'a', 'c', 'f', 'g'); + $redis->sadd('letters:3rd', 'a', 'b', 'e', 'f'); + + $this->assertSame(3, $redis->sdiffstore('letters:destination', 'letters:1st', 'letters:2nd')); + $this->assertSameValues(array('b', 'd', 'e'), $redis->smembers('letters:destination')); + + $this->assertSame(1, $redis->sdiffstore('letters:destination', 'letters:1st', 'letters:2nd', 'letters:3rd')); + $this->assertSameValues(array('d'), $redis->smembers('letters:destination')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongTypeOfSourceKey() + { + $redis = $this->getClient(); + + $redis->set('set:source', 'foo'); + $redis->sdiffstore('set:destination', 'set:source'); + } +} diff --git a/tests/Predis/Commands/SetDifferenceTest.php b/tests/Predis/Commands/SetDifferenceTest.php new file mode 100644 index 00000000..6da34cfe --- /dev/null +++ b/tests/Predis/Commands/SetDifferenceTest.php @@ -0,0 +1,133 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-set + */ +class SetDifferenceTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\SetDifference'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SDIFF'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key1', 'key2', 'key3'); + $expected = array('key1', 'key2', 'key3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsAsSingleArray() + { + $arguments = array(array('key1', 'key2', 'key3')); + $expected = array('key1', 'key2', 'key3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('member1', 'member2', 'member3'); + $expected = array('member1', 'member2', 'member3'); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key1', 'key2', 'key3'); + $expected = array('prefix:key1', 'prefix:key2', 'prefix:key3'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsMembersOnSingleKeyOrNonExistingSetForDifference() + { + $redis = $this->getClient(); + + $redis->sadd('letters:1st', 'a', 'b', 'c', 'd', 'e', 'f', 'g'); + + $this->assertSameValues(array( 'a', 'b', 'c', 'd', 'e', 'f', 'g'), $redis->sdiff('letters:1st')); + $this->assertSameValues(array( 'a', 'b', 'c', 'd', 'e', 'f', 'g'), $redis->sdiff('letters:1st', 'letters:2nd')); + } + + /** + * @group connected + */ + public function testReturnsMembersFromDifferenceAmongSets() + { + $redis = $this->getClient(); + + $redis->sadd('letters:1st', 'a', 'b', 'c', 'd', 'e', 'f', 'g'); + $redis->sadd('letters:2nd', 'a', 'c', 'f', 'g'); + $redis->sadd('letters:3rd', 'a', 'b', 'e', 'f'); + + $this->assertSameValues(array('b', 'd', 'e'), $redis->sdiff('letters:1st', 'letters:2nd')); + $this->assertSameValues(array('d'), $redis->sdiff('letters:1st', 'letters:2nd', 'letters:3rd')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('set:foo', 'a'); + $redis->sdiff('set:foo'); + } +} diff --git a/tests/Predis/Commands/SetIntersectionStoreTest.php b/tests/Predis/Commands/SetIntersectionStoreTest.php new file mode 100644 index 00000000..06c3a875 --- /dev/null +++ b/tests/Predis/Commands/SetIntersectionStoreTest.php @@ -0,0 +1,144 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-set + */ +class SetIntersectionStoreTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\SetIntersectionStore'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SINTERSTORE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key:destination', 'key:source1', 'key:source:2'); + $expected = array('key:destination', 'key:source1', 'key:source:2'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsSourceKeysAsSingleArray() + { + $arguments = array('key:destination', array('key:source1', 'key:source:2')); + $expected = array('key:destination', 'key:source1', 'key:source:2'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key:destination', 'key:source1', 'key:source:2'); + $expected = array('prefix:key:destination', 'prefix:key:source1', 'prefix:key:source:2'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testStoresMembersOfSetOnSingleKey() + { + $redis = $this->getClient(); + + $redis->sadd('letters:1st', 'a', 'b', 'c', 'd', 'e', 'f', 'g'); + + $this->assertSame(7, $redis->sinterstore('letters:destination', 'letters:1st')); + $this->assertSameValues(array( 'a', 'b', 'c', 'd', 'e', 'f', 'g'), $redis->smembers('letters:destination')); + } + + /** + * @group connected + */ + public function testDoesNotStoreOnNonExistingSetForIntersection() + { + $redis = $this->getClient(); + + $redis->sadd('letters:1st', 'a', 'b', 'c', 'd', 'e', 'f', 'g'); + + $this->assertSame(0, $redis->sinterstore('letters:destination', 'letters:1st', 'letters:2nd')); + $this->assertFalse($redis->exists('letters:destination')); + } + + /** + * @group connected + */ + public function testStoresIntersectionOfMultipleSets() + { + $redis = $this->getClient(); + + $redis->sadd('letters:1st', 'a', 'b', 'c', 'd', 'e', 'f', 'g'); + $redis->sadd('letters:2nd', 'a', 'c', 'f', 'g'); + $redis->sadd('letters:3rd', 'a', 'b', 'e', 'f'); + + $this->assertSame(4, $redis->sinterstore('letters:destination', 'letters:1st', 'letters:2nd')); + $this->assertSameValues(array('a', 'c', 'f', 'g'), $redis->smembers('letters:destination')); + + $this->assertSame(2, $redis->sinterstore('letters:destination', 'letters:1st', 'letters:2nd', 'letters:3rd')); + $this->assertSameValues(array('a', 'f'), $redis->smembers('letters:destination')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongTypeOfSourceKey() + { + $redis = $this->getClient(); + + $redis->set('set:source', 'foo'); + $redis->sinterstore('set:destination', 'set:source'); + } +} diff --git a/tests/Predis/Commands/SetIntersectionTest.php b/tests/Predis/Commands/SetIntersectionTest.php new file mode 100644 index 00000000..bd9edcc1 --- /dev/null +++ b/tests/Predis/Commands/SetIntersectionTest.php @@ -0,0 +1,144 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-set + */ +class SetIntersectionTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\SetIntersection'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SINTER'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key1', 'key2', 'key3'); + $expected = array('key1', 'key2', 'key3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsAsSingleArray() + { + $arguments = array(array('key1', 'key2', 'key3')); + $expected = array('key1', 'key2', 'key3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('member1', 'member2', 'member3'); + $expected = array('member1', 'member2', 'member3'); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key1', 'key2', 'key3'); + $expected = array('prefix:key1', 'prefix:key2', 'prefix:key3'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsMembersOfSetOnSingleKey() + { + $redis = $this->getClient(); + + $redis->sadd('letters:1st', 'a', 'b', 'c', 'd', 'e', 'f', 'g'); + + $this->assertSameValues(array('a', 'b', 'c', 'd', 'e', 'f', 'g'), $redis->sinter('letters:1st')); + } + + /** + * @group connected + */ + public function testReturnsEmptyArrayOnNonExistingSetForIntersection() + { + $redis = $this->getClient(); + + $redis->sadd('letters:1st', 'a', 'b', 'c', 'd', 'e', 'f', 'g'); + + $this->assertSameValues(array(), $redis->sinter('letters:1st', 'letters:2nd')); + } + + /** + * @group connected + */ + public function testReturnsMembersFromIntersectionAmongSets() + { + $redis = $this->getClient(); + + $redis->sadd('letters:1st', 'a', 'b', 'c', 'd', 'e', 'f', 'g'); + $redis->sadd('letters:2nd', 'a', 'c', 'f', 'g'); + $redis->sadd('letters:3rd', 'a', 'b', 'e', 'f'); + + $this->assertSameValues(array('a', 'c', 'f', 'g'), $redis->sinter('letters:1st', 'letters:2nd')); + $this->assertSameValues(array('a', 'f'), $redis->sinter('letters:1st', 'letters:2nd', 'letters:3rd')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('set:foo', 'a'); + $redis->sinter('set:foo'); + } +} diff --git a/tests/Predis/Commands/SetIsMemberTest.php b/tests/Predis/Commands/SetIsMemberTest.php new file mode 100644 index 00000000..b07a5d9e --- /dev/null +++ b/tests/Predis/Commands/SetIsMemberTest.php @@ -0,0 +1,112 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-set + */ +class SetIsMemberTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\SetIsMember'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SISMEMBER'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'member'); + $expected = array('key', 'member'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertTrue($command->parseResponse(1)); + $this->assertFalse($command->parseResponse(0)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'member'); + $expected = array('prefix:key', 'member'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsMemberExistenceInSet() + { + $redis = $this->getClient(); + + $redis->sadd('letters', 'a', 'b', 'c'); + + $this->assertTrue($redis->sismember('letters', 'a')); + $this->assertFalse($redis->sismember('letters', 'z')); + } + + /** + * @group connected + */ + public function testReturnsFalseOnNonExistingSet() + { + $redis = $this->getClient(); + + $this->assertFalse($redis->sismember('letters', 'a')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->sismember('foo', 'bar'); + } +} diff --git a/tests/Predis/Commands/SetMembersTest.php b/tests/Predis/Commands/SetMembersTest.php new file mode 100644 index 00000000..618155e2 --- /dev/null +++ b/tests/Predis/Commands/SetMembersTest.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-set + */ +class SetMembersTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\SetMembers'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SMEMBERS'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key'); + $expected = array('key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('member1', 'member2', 'member3'); + $expected = array('member1', 'member2', 'member3'); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsFalseOnNonExistingSet() + { + $redis = $this->getClient(); + + $redis->sadd('letters', 'a', 'b', 'c', 'd', 'e'); + + $this->assertSameValues(array('a', 'b', 'c', 'd', 'e'), $redis->smembers('letters')); + $this->assertSame(array(), $redis->smembers('digits')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->smembers('foo'); + } +} diff --git a/tests/Predis/Commands/SetMoveTest.php b/tests/Predis/Commands/SetMoveTest.php new file mode 100644 index 00000000..5114905b --- /dev/null +++ b/tests/Predis/Commands/SetMoveTest.php @@ -0,0 +1,120 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-set + */ +class SetMoveTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\SetMove'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SMOVE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key:source', 'key:destination', 'member'); + $expected = array('key:source', 'key:destination', 'member'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + + $this->assertTrue($command->parseResponse(1)); + $this->assertFalse($command->parseResponse(0)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key:source', 'key:destination', 'member'); + $expected = array('prefix:key:source', 'prefix:key:destination', 'member'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsMemberExistenceInSet() + { + $redis = $this->getClient(); + + $redis->sadd('letters:source', 'a', 'b', 'c'); + + $this->assertTrue($redis->smove('letters:source', 'letters:destination', 'b')); + $this->assertFalse($redis->smove('letters:source', 'letters:destination', 'z')); + + $this->assertSameValues(array('a', 'c'), $redis->smembers('letters:source')); + $this->assertSameValues(array('b'), $redis->smembers('letters:destination')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongTypeOfSourceKey() + { + $redis = $this->getClient(); + + $redis->set('set:source', 'foo'); + $redis->sadd('set:destination', 'bar'); + $redis->smove('set:destination', 'set:source', 'foo'); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongTypeOfDestinationKey() + { + $redis = $this->getClient(); + + $redis->sadd('set:source', 'foo'); + $redis->set('set:destination', 'bar'); + $redis->smove('set:destination', 'set:source', 'foo'); + } +} diff --git a/tests/Predis/Commands/SetPopTest.php b/tests/Predis/Commands/SetPopTest.php new file mode 100644 index 00000000..b39426f1 --- /dev/null +++ b/tests/Predis/Commands/SetPopTest.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-set + */ +class SetPopTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\SetPop'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SPOP'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key'); + $expected = array('key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame('member', $this->getCommand()->parseResponse('member')); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testPopsRandomMemberFromSet() + { + $redis = $this->getClient(); + + $redis->sadd('letters', 'a', 'b'); + + $this->assertContains($redis->spop('letters'), array('a', 'b')); + $this->assertContains($redis->spop('letters'), array('a', 'b')); + + $this->assertNull($redis->spop('letters')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->spop('foo'); + } +} diff --git a/tests/Predis/Commands/SetRandomMemberTest.php b/tests/Predis/Commands/SetRandomMemberTest.php new file mode 100644 index 00000000..a9e3320c --- /dev/null +++ b/tests/Predis/Commands/SetRandomMemberTest.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-set + */ +class SetRandomMemberTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\SetRandomMember'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SRANDMEMBER'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key'); + $expected = array('key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame('member', $this->getCommand()->parseResponse('member')); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsRandomMemberFromSet() + { + $redis = $this->getClient(); + + $redis->sadd('letters', 'a', 'b'); + + $this->assertContains($redis->srandmember('letters'), array('a', 'b')); + $this->assertContains($redis->srandmember('letters'), array('a', 'b')); + + $this->assertSame(2, $redis->scard('letters')); + } + + /** + * @group connected + */ + public function testReturnsNullOnNonExistingSet() + { + $this->assertNull($this->getClient()->srandmember('letters')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->srandmember('foo'); + } +} diff --git a/tests/Predis/Commands/SetRemoveTest.php b/tests/Predis/Commands/SetRemoveTest.php new file mode 100644 index 00000000..b8d5e55b --- /dev/null +++ b/tests/Predis/Commands/SetRemoveTest.php @@ -0,0 +1,116 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-set + */ +class SetRemoveTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\SetRemove'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SREM'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'member1', 'member2', 'member3'); + $expected = array('key', 'member1', 'member2', 'member3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsMembersAsSingleArray() + { + $arguments = array('key', array('member1', 'member2', 'member3')); + $expected = array('key', 'member1', 'member2', 'member3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'member1', 'member2', 'member3'); + $expected = array('prefix:key', 'member1', 'member2', 'member3'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testRemovesMembersFromSet() + { + $redis = $this->getClient(); + + $redis->sadd('letters', 'a', 'b', 'c', 'd'); + + $this->assertSame(1, $redis->srem('letters', 'b')); + $this->assertSame(1, $redis->srem('letters', 'd', 'z')); + $this->assertSameValues(array('a', 'c'), $redis->smembers('letters')); + + $this->assertSame(0, $redis->srem('digits', 1)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->srem('foo', 'bar'); + } +} diff --git a/tests/Predis/Commands/SetUnionStoreTest.php b/tests/Predis/Commands/SetUnionStoreTest.php new file mode 100644 index 00000000..e83cb982 --- /dev/null +++ b/tests/Predis/Commands/SetUnionStoreTest.php @@ -0,0 +1,131 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-set + */ +class SetUnionStoreTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\SetUnionStore'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SUNIONSTORE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key:destination', 'key:source1', 'key:source:2'); + $expected = array('key:destination', 'key:source1', 'key:source:2'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsSourceKeysAsSingleArray() + { + $arguments = array('key:destination', array('key:source1', 'key:source:2')); + $expected = array('key:destination', 'key:source1', 'key:source:2'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key:destination', 'key:source1', 'key:source:2'); + $expected = array('prefix:key:destination', 'prefix:key:source1', 'prefix:key:source:2'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testStoresMembersOfSetOnSingleSet() + { + $redis = $this->getClient(); + + $redis->sadd('letters:1st', 'a', 'b', 'c', 'd', 'e', 'f', 'g'); + + $this->assertSame(7, $redis->sunionstore('letters:destination', 'letters:1st')); + $this->assertSameValues(array( 'a', 'b', 'c', 'd', 'e', 'f', 'g'), $redis->smembers('letters:destination')); + } + + /** + * @group connected + */ + public function testStoresUnionOfMultipleSets() + { + $redis = $this->getClient(); + + $redis->sadd('letters:1st', 'b', 'd', 'f'); + $redis->sadd('letters:2nd', 'a', 'c', 'g'); + $redis->sadd('letters:3rd', 'a', 'e', 'f'); + + $this->assertSame(5, $redis->sunionstore('letters:destination', 'letters:2nd', 'letters:3rd')); + $this->assertSameValues(array('a', 'c', 'e', 'f', 'g'), $redis->smembers('letters:destination')); + + $this->assertSame(7, $redis->sunionstore('letters:destination', 'letters:1st', 'letters:2nd', 'letters:3rd')); + $this->assertSameValues(array( 'a', 'b', 'c', 'd', 'e', 'f', 'g'), $redis->smembers('letters:destination')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongTypeOfSourceKey() + { + $redis = $this->getClient(); + + $redis->set('set:source', 'foo'); + $redis->sunionstore('set:destination', 'set:source'); + } +} diff --git a/tests/Predis/Commands/SetUnionTest.php b/tests/Predis/Commands/SetUnionTest.php new file mode 100644 index 00000000..cf638597 --- /dev/null +++ b/tests/Predis/Commands/SetUnionTest.php @@ -0,0 +1,133 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-set + */ +class SetUnionTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\SetUnion'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SUNION'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key1', 'key2', 'key3'); + $expected = array('key1', 'key2', 'key3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsAsSingleArray() + { + $arguments = array(array('key1', 'key2', 'key3')); + $expected = array('key1', 'key2', 'key3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('member1', 'member2', 'member3'); + $expected = array('member1', 'member2', 'member3'); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key1', 'key2', 'key3'); + $expected = array('prefix:key1', 'prefix:key2', 'prefix:key3'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsMembersOnSingleKeyOrNonExistingSetForUnion() + { + $redis = $this->getClient(); + + $redis->sadd('letters:1st', 'a', 'b', 'c', 'd', 'e', 'f', 'g'); + + $this->assertSameValues(array( 'a', 'b', 'c', 'd', 'e', 'f', 'g'), $redis->sunion('letters:1st')); + $this->assertSameValues(array( 'a', 'b', 'c', 'd', 'e', 'f', 'g'), $redis->sunion('letters:1st', 'letters:2nd')); + } + + /** + * @group connected + */ + public function testReturnsMembersFromDifferenceAmongSets() + { + $redis = $this->getClient(); + + $redis->sadd('letters:1st', 'b', 'd', 'f'); + $redis->sadd('letters:2nd', 'a', 'c', 'g'); + $redis->sadd('letters:3rd', 'a', 'e', 'f'); + + $this->assertSameValues(array('a', 'c', 'e', 'f', 'g'), $redis->sunion('letters:2nd', 'letters:3rd')); + $this->assertSameValues(array( 'a', 'b', 'c', 'd', 'e', 'f', 'g'), $redis->sunion('letters:1st', 'letters:2nd', 'letters:3rd')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('set:foo', 'a'); + $redis->sunion('set:foo'); + } +} diff --git a/tests/Predis/Commands/StringAppendTest.php b/tests/Predis/Commands/StringAppendTest.php new file mode 100644 index 00000000..ae4e2069 --- /dev/null +++ b/tests/Predis/Commands/StringAppendTest.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringAppendTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringAppend'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'APPEND'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'value'); + $expected = array('key', 'value'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(10, $this->getCommand()->parseResponse(10)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'value'); + $expected = array('prefix:key', 'value'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testCreatesNewKeyOnNonExistingKey() + { + $redis = $this->getClient(); + + $this->assertSame(3, $redis->append('foo', 'bar')); + $this->assertSame('bar', $redis->get('foo')); + } + + /** + * @group connected + */ + public function testReturnsTheLenghtOfTheStringAfterAppend() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + + $this->assertSame(5, $redis->append('foo', '__')); + $this->assertSame(8, $redis->append('foo', 'bar')); + $this->assertSame('bar__bar', $redis->get('foo')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->lpush('metavars', 'foo'); + $redis->append('metavars', 'bar'); + } +} diff --git a/tests/Predis/Commands/StringDecrementByTest.php b/tests/Predis/Commands/StringDecrementByTest.php new file mode 100644 index 00000000..8cdbbd49 --- /dev/null +++ b/tests/Predis/Commands/StringDecrementByTest.php @@ -0,0 +1,136 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringDecrementByTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringDecrementBy'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'DECRBY'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 5); + $expected = array('key', 5); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(5, $this->getCommand()->parseResponse(5)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 5); + $expected = array('prefix:key', 5); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testCreatesNewKeyOnNonExistingKey() + { + $redis = $this->getClient(); + + $this->assertSame(-10, $redis->decrby('foo', 10)); + $this->assertEquals(-10, $redis->get('foo')); + } + + /** + * @group connected + */ + public function testReturnsTheValueOfTheKeyAfterDecrement() + { + $redis = $this->getClient(); + + $redis->set('foo', 10); + + $this->assertSame(6, $redis->decrby('foo', 4)); + $this->assertSame(0, $redis->decrby('foo', 6)); + $this->assertSame(-25, $redis->decrby('foo', 25)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR value is not an integer or out of range + */ + public function testThrowsExceptionOnDecrementValueNotInteger() + { + $redis = $this->getClient(); + + $redis->decrby('foo', 'bar'); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR value is not an integer or out of range + */ + public function testThrowsExceptionOnKeyValueNotInteger() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->decrby('foo', 5); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->lpush('metavars', 'foo'); + $redis->decrby('metavars', 10); + } +} diff --git a/tests/Predis/Commands/StringDecrementTest.php b/tests/Predis/Commands/StringDecrementTest.php new file mode 100644 index 00000000..9dfbc213 --- /dev/null +++ b/tests/Predis/Commands/StringDecrementTest.php @@ -0,0 +1,123 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringDecrementTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringDecrement'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'DECR'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key'); + $expected = array('key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(5, $this->getCommand()->parseResponse(5)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testCreatesNewKeyOnNonExistingKey() + { + $redis = $this->getClient(); + + $this->assertSame(-1, $redis->decr('foo')); + $this->assertEquals(-1, $redis->get('foo')); + } + + /** + * @group connected + */ + public function testReturnsTheValueOfTheKeyAfterDecrement() + { + $redis = $this->getClient(); + + $redis->set('foo', 1); + + $this->assertSame(0, $redis->decr('foo')); + $this->assertSame(-1, $redis->decr('foo')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR value is not an integer or out of range + */ + public function testThrowsExceptionOnKeyValueNotInteger() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->decr('foo'); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->lpush('metavars', 'foo'); + $redis->decr('metavars'); + } +} diff --git a/tests/Predis/Commands/StringGetBitTest.php b/tests/Predis/Commands/StringGetBitTest.php new file mode 100644 index 00000000..8acfac2f --- /dev/null +++ b/tests/Predis/Commands/StringGetBitTest.php @@ -0,0 +1,129 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringGetBitTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringGetBit'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'GETBIT'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 100); + $expected = array('key', 100); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + $this->assertSame(0, $command->parseResponse(0)); + $this->assertSame(1, $command->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 100); + $expected = array('prefix:key', 100); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testCanGetBitsFromString() + { + $redis = $this->getClient(); + + $redis->set('key:binary', "\x80\x00\00\x01"); + + $this->assertSame(1, $redis->getbit('key:binary', 0)); + $this->assertSame(0, $redis->getbit('key:binary', 15)); + $this->assertSame(1, $redis->getbit('key:binary', 31)); + $this->assertSame(0, $redis->getbit('key:binary', 63)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR bit offset is not an integer or out of range + */ + public function testThrowsExceptionOnNegativeOffset() + { + $redis = $this->getClient(); + + $redis->set('key:binary', "\x80\x00\00\x01"); + $redis->getbit('key:binary', -1); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR bit offset is not an integer or out of range + */ + public function testThrowsExceptionOnInvalidOffset() + { + $redis = $this->getClient(); + + $redis->set('key:binary', "\x80\x00\00\x01"); + $redis->getbit('key:binary', 'invalid'); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->lpush('metavars', 'foo'); + $redis->getbit('metavars', '1'); + } +} diff --git a/tests/Predis/Commands/StringGetMultipleTest.php b/tests/Predis/Commands/StringGetMultipleTest.php new file mode 100644 index 00000000..2a6f47df --- /dev/null +++ b/tests/Predis/Commands/StringGetMultipleTest.php @@ -0,0 +1,127 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringGetMultipleTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringGetMultiple'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'MGET'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key1', 'key2', 'key3'); + $expected = array('key1', 'key2', 'key3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsAsSingleArray() + { + $arguments = array(array('key1', 'key2', 'key3')); + $expected = array('key1', 'key2', 'key3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('value1', 'value2', 'value3'); + $expected = array('value1', 'value2', 'value3'); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key1', 'key2', 'key3'); + $expected = array('prefix:key1', 'prefix:key2', 'prefix:key3'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + + /** + * @group connected + */ + public function testReturnsArrayOfValues() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->set('hoge', 'piyo'); + + $this->assertSame(array('bar', 'piyo'), $redis->mget('foo', 'hoge')); + } + + /** + * @group connected + */ + public function testReturnsArrayWithNullValuesOnNonExistingKeys() + { + $redis = $this->getClient(); + + $this->assertSame(array(null, null), $redis->mget('foo', 'hoge')); + } + + /** + * @group connected + */ + public function testDoesNotThrowExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->lpush('metavars', 'foo'); + $this->assertSame(array(null), $redis->mget('metavars')); + } +} diff --git a/tests/Predis/Commands/StringGetRangeTest.php b/tests/Predis/Commands/StringGetRangeTest.php new file mode 100644 index 00000000..425a7e6e --- /dev/null +++ b/tests/Predis/Commands/StringGetRangeTest.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringGetRangeTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringGetRange'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'GETRANGE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 5, 10); + $expected = array('key', 5, 10); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame('substring',$this->getCommand()->parseResponse('substring')); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 5, 10); + $expected = array('prefix:key', 5, 10); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsSubstring() + { + $redis = $this->getClient(); + + $redis->set('string', 'this is a string'); + + $this->assertSame('this', $redis->getrange('string', 0, 3)); + $this->assertSame('ing', $redis->getrange('string', -3, -1)); + $this->assertSame('this is a string', $redis->getrange('string', 0, -1)); + $this->assertSame('string', $redis->getrange('string', 10, 100)); + + $this->assertSame('t', $redis->getrange('string', 0, 0)); + $this->assertSame('', $redis->getrange('string', -1, 0)); + } + + /** + * @group connected + */ + public function testReturnsEmptyStringOnNonExistingKey() + { + $redis = $this->getClient(); + + $this->assertSame('', $redis->getrange('string', 0, 3)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->lpush('metavars', 'foo'); + $redis->getrange('metavars', 0, 5); + } +} diff --git a/tests/Predis/Commands/StringGetSetTest.php b/tests/Predis/Commands/StringGetSetTest.php new file mode 100644 index 00000000..e03ce1b4 --- /dev/null +++ b/tests/Predis/Commands/StringGetSetTest.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringGetSetTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringGetSet'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'GETSET'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'value'); + $expected = array('key', 'value'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame('value', $this->getCommand()->parseResponse('value')); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'value'); + $expected = array('prefix:key', 'value'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsPreviousValueOfKey() + { + $redis = $this->getClient(); + + $this->assertNull($redis->getset('foo', 'bar')); + $this->assertSame('bar', $redis->getset('foo', 'barbar')); + + $redis->set('hoge', 'piyo'); + $this->assertSame('piyo', $redis->getset('hoge', 'piyopiyo')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->lpush('metavars', 'foo'); + $redis->getset('metavars', 'foo'); + } +} diff --git a/tests/Predis/Commands/StringGetTest.php b/tests/Predis/Commands/StringGetTest.php new file mode 100644 index 00000000..d9762907 --- /dev/null +++ b/tests/Predis/Commands/StringGetTest.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringGetTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringGet'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'GET'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('foo'); + $expected = array('foo'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame('bar', $this->getCommand()->parseResponse('bar')); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsStringValue() + { + $redis = $this->getClient(); + + $this->assertTrue($redis->set('foo', 'bar')); + $this->assertEquals('bar', $redis->get('foo')); + } + + /** + * @group connected + */ + public function testReturnsEmptyStringOnEmptyStrings() + { + $redis = $this->getClient(); + + $redis->set('foo', ''); + + $this->assertTrue($redis->exists('foo')); + $this->assertSame('', $redis->get('foo')); + } + + /** + * @group connected + */ + public function testReturnsNullOnNonExistingKeys() + { + $redis = $this->getClient(); + + $this->assertFalse($redis->exists('foo')); + $this->assertNull($redis->get('foo')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->rpush('metavars', 'foo'); + $redis->get('metavars'); + } +} diff --git a/tests/Predis/Commands/StringIncrementByFloatTest.php b/tests/Predis/Commands/StringIncrementByFloatTest.php new file mode 100644 index 00000000..e1d7d876 --- /dev/null +++ b/tests/Predis/Commands/StringIncrementByFloatTest.php @@ -0,0 +1,136 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringIncrementByFloatTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringIncrementByFloat'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'INCRBYFLOAT'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 5.0); + $expected = array('key', 5.0); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(5.0, $this->getCommand()->parseResponse(5.0)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 5.0); + $expected = array('prefix:key', 5.0); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testCreatesNewKeyOnNonExistingKey() + { + $redis = $this->getClient(); + + $this->assertEquals(10.5, $redis->incrbyfloat('foo', 10.5)); + $this->assertEquals(10.5, $redis->get('foo')); + } + + /** + * @group connected + */ + public function testReturnsTheValueOfTheKeyAfterIncrement() + { + $redis = $this->getClient(); + + $redis->set('foo', 2); + + $this->assertEquals(22.123, $redis->incrbyfloat('foo', 20.123)); + $this->assertEquals(10, $redis->incrbyfloat('foo', -12.123)); + $this->assertEquals(-100.01, $redis->incrbyfloat('foo', -110.01)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR value is not a valid float + */ + public function testThrowsExceptionOnDecrementValueNotFloat() + { + $redis = $this->getClient(); + + $redis->incrbyfloat('foo', 'bar'); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR value is not a valid float + */ + public function testThrowsExceptionOnKeyValueNotFloat() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->incrbyfloat('foo', 10.0); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->lpush('metavars', 'foo'); + $redis->incrbyfloat('metavars', 10.0); + } +} diff --git a/tests/Predis/Commands/StringIncrementByTest.php b/tests/Predis/Commands/StringIncrementByTest.php new file mode 100644 index 00000000..1e03f4d7 --- /dev/null +++ b/tests/Predis/Commands/StringIncrementByTest.php @@ -0,0 +1,136 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringIncrementByTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringIncrementBy'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'INCRBY'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 5); + $expected = array('key', 5); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(5, $this->getCommand()->parseResponse(5)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 5); + $expected = array('prefix:key', 5); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testCreatesNewKeyOnNonExistingKey() + { + $redis = $this->getClient(); + + $this->assertSame(10, $redis->incrby('foo', 10)); + $this->assertEquals(10, $redis->get('foo')); + } + + /** + * @group connected + */ + public function testReturnsTheValueOfTheKeyAfterIncrement() + { + $redis = $this->getClient(); + + $redis->set('foo', 2); + + $this->assertSame(22, $redis->incrby('foo', 20)); + $this->assertSame(10, $redis->incrby('foo', -12)); + $this->assertSame(-100, $redis->incrby('foo', -110)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR value is not an integer or out of range + */ + public function testThrowsExceptionOnDecrementValueNotInteger() + { + $redis = $this->getClient(); + + $redis->incrby('foo', 'bar'); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR value is not an integer or out of range + */ + public function testThrowsExceptionOnKeyValueNotInteger() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->incrby('foo', 10); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->lpush('metavars', 'foo'); + $redis->incrby('metavars', 10); + } +} diff --git a/tests/Predis/Commands/StringIncrementTest.php b/tests/Predis/Commands/StringIncrementTest.php new file mode 100644 index 00000000..d8644f81 --- /dev/null +++ b/tests/Predis/Commands/StringIncrementTest.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringIncrementTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringIncrement'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'INCR'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key'); + $expected = array('key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(5, $this->getCommand()->parseResponse(5)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testCreatesNewKeyOnNonExistingKey() + { + $redis = $this->getClient(); + + $this->assertSame(1, $redis->incr('foo')); + $this->assertEquals(1, $redis->get('foo')); + } + + /** + * @group connected + */ + public function testReturnsTheValueOfTheKeyAfterIncrement() + { + $redis = $this->getClient(); + + $redis->set('foo', 2); + + $this->assertSame(3, $redis->incr('foo')); + $this->assertSame(4, $redis->incr('foo')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->lpush('metavars', 'foo'); + $redis->incr('metavars'); + } +} diff --git a/tests/Predis/Commands/StringPreciseSetExpireTest.php b/tests/Predis/Commands/StringPreciseSetExpireTest.php new file mode 100644 index 00000000..c464038a --- /dev/null +++ b/tests/Predis/Commands/StringPreciseSetExpireTest.php @@ -0,0 +1,130 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringPreciseSetExpireTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringPreciseSetExpire'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'PSETEX'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 10, 'hello'); + $expected = array('key', 10, 'hello'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 10, 'hello'); + $expected = array('prefix:key', 10, 'hello'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testCreatesNewKeyAndSetsTTL() + { + $redis = $this->getClient(); + + $this->assertTrue($redis->psetex('foo', 10000, 'bar')); + $this->assertTrue($redis->exists('foo')); + $this->assertEquals(10, $redis->ttl('foo')); + } + + /** + * @group connected + * @group slow + */ + public function testKeyExpiresAfterTTL() + { + $redis = $this->getClient(); + + $redis->psetex('foo', 50, 'bar'); + $this->sleep(0.5); + $this->assertFalse($redis->exists('foo'));; + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR value is not an integer or out of range + */ + public function testThrowsExceptionOnNonIntegerTTL() + { + $this->getClient()->psetex('foo', 2.5, 'bar'); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR invalid expire time in SETEX + * @todo Should not Redis return PSETEX instead of SETEX here? + */ + public function testThrowsExceptionOnZeroTTL() + { + $this->getClient()->psetex('foo', 0, 'bar'); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR invalid expire time in SETEX + * @todo Should not Redis return PSETEX instead of SETEX here? + */ + public function testThrowsExceptionOnNegativeTTL() + { + $this->getClient()->psetex('foo', -10000, 'bar'); + } +} diff --git a/tests/Predis/Commands/StringSetBitTest.php b/tests/Predis/Commands/StringSetBitTest.php new file mode 100644 index 00000000..6dfdaa57 --- /dev/null +++ b/tests/Predis/Commands/StringSetBitTest.php @@ -0,0 +1,145 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringSetBitTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringSetBit'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SETBIT'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 7, 1); + $expected = array('key', 7, 1); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $command = $this->getCommand(); + $this->assertSame(0, $command->parseResponse(0)); + $this->assertSame(1, $command->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 7, 1); + $expected = array('prefix:key', 7, 1); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testCanSetBitsOfStrings() + { + $redis = $this->getClient(); + + $redis->set('key:binary', "\x80\x00\00\x01"); + + $this->assertEquals(1, $redis->setbit('key:binary', 0, 0)); + $this->assertEquals(0, $redis->setbit('key:binary', 0, 0)); + $this->assertEquals("\x00\x00\00\x01", $redis->get('key:binary')); + } + + /** + * @group connected + */ + public function testCreatesNewKeyOnNonExistingKey() + { + $redis = $this->getClient(); + + $this->assertSame(0, $redis->setbit('key:binary', 31, 1)); + $this->assertSame(0, $redis->setbit('key:binary', 0, 1)); + $this->assertSame(4, $redis->strlen('key:binary')); + $this->assertSame("\x80\x00\00\x01", $redis->get('key:binary')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR bit is not an integer or out of range + */ + public function testThrowsExceptionOnInvalidBitValue() + { + $redis = $this->getClient()->setbit('key:binary', 10, 255); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR bit offset is not an integer or out of range + */ + public function testThrowsExceptionOnNegativeOffset() + { + $redis = $this->getClient()->setbit('key:binary', -1, 1); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR bit offset is not an integer or out of range + */ + public function testThrowsExceptionOnInvalidOffset() + { + $redis = $this->getClient()->setbit('key:binary', 'invalid', 1); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->lpush('metavars', 'foo'); + $redis->setbit('metavars', 0, 1); + } +} diff --git a/tests/Predis/Commands/StringSetExpireTest.php b/tests/Predis/Commands/StringSetExpireTest.php new file mode 100644 index 00000000..3fae15aa --- /dev/null +++ b/tests/Predis/Commands/StringSetExpireTest.php @@ -0,0 +1,128 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringSetExpireTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringSetExpire'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SETEX'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 10, 'hello'); + $expected = array('key', 10, 'hello'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 10, 'hello'); + $expected = array('prefix:key', 10, 'hello'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testCreatesNewKeyAndSetsTTL() + { + $redis = $this->getClient(); + + $this->assertTrue($redis->setex('foo', 10, 'bar')); + $this->assertTrue($redis->exists('foo')); + $this->assertEquals(10, $redis->ttl('foo')); + } + + /** + * @group connected + * @group slow + */ + public function testKeyExpiresAfterTTL() + { + $redis = $this->getClient(); + + $redis->setex('foo', 1, 'bar'); + $this->sleep(2.0); + $this->assertFalse($redis->exists('foo'));; + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR value is not an integer or out of range + */ + public function testThrowsExceptionOnNonIntegerTTL() + { + $this->getClient()->setex('foo', 2.5, 'bar'); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR invalid expire time in SETEX + */ + public function testThrowsExceptionOnZeroTTL() + { + $this->getClient()->setex('foo', 0, 'bar'); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR invalid expire time in SETEX + */ + public function testThrowsExceptionOnNegativeTTL() + { + $this->getClient()->setex('foo', -10, 'bar'); + } +} diff --git a/tests/Predis/Commands/StringSetMultiplePreserveTest.php b/tests/Predis/Commands/StringSetMultiplePreserveTest.php new file mode 100644 index 00000000..b2fee1c4 --- /dev/null +++ b/tests/Predis/Commands/StringSetMultiplePreserveTest.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringSetMultiplePreserveTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringSetMultiplePreserve'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'MSETNX'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('foo', 'bar', 'hoge', 'piyo'); + $expected = array('foo', 'bar', 'hoge', 'piyo'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsAsSingleNamedArray() + { + $arguments = array(array('foo' => 'bar', 'hoge' => 'piyo')); + $expected = array('foo', 'bar', 'hoge', 'piyo'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(true, $this->getCommand()->parseResponse(true)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('foo', 'bar', 'hoge', 'piyo'); + $expected = array('prefix:foo', 'bar', 'prefix:hoge', 'piyo'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testCreatesMultipleKeys() + { + $redis = $this->getClient(); + + $this->assertTrue($redis->msetnx('foo', 'bar', 'hoge', 'piyo')); + $this->assertSame('bar', $redis->get('foo')); + $this->assertSame('piyo', $redis->get('hoge')); + } + + /** + * @group connected + */ + public function testCreatesMultipleKeysAndPreservesExistingOnes() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + + $this->assertFalse($redis->msetnx('foo', 'barbar', 'hoge', 'piyo')); + $this->assertSame('bar', $redis->get('foo')); + $this->assertFalse($redis->exists('hoge')); + } +} diff --git a/tests/Predis/Commands/StringSetMultipleTest.php b/tests/Predis/Commands/StringSetMultipleTest.php new file mode 100644 index 00000000..4893aa0e --- /dev/null +++ b/tests/Predis/Commands/StringSetMultipleTest.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringSetMultipleTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringSetMultiple'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'MSET'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('foo', 'bar', 'hoge', 'piyo'); + $expected = array('foo', 'bar', 'hoge', 'piyo'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsAsSingleNamedArray() + { + $arguments = array(array('foo' => 'bar', 'hoge' => 'piyo')); + $expected = array('foo', 'bar', 'hoge', 'piyo'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(true, $this->getCommand()->parseResponse(true)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('foo', 'bar', 'hoge', 'piyo'); + $expected = array('prefix:foo', 'bar', 'prefix:hoge', 'piyo'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testCreatesMultipleKeys() + { + $redis = $this->getClient(); + + $this->assertTrue($redis->mset('foo', 'bar', 'hoge', 'piyo')); + $this->assertSame('bar', $redis->get('foo')); + $this->assertSame('piyo', $redis->get('hoge')); + } +} diff --git a/tests/Predis/Commands/StringSetRangeTest.php b/tests/Predis/Commands/StringSetRangeTest.php new file mode 100644 index 00000000..e07c4766 --- /dev/null +++ b/tests/Predis/Commands/StringSetRangeTest.php @@ -0,0 +1,139 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringSetRangeTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringSetRange'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SETRANGE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 5, 'range'); + $expected = array('key', 5, 'range'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(10, $this->getCommand()->parseResponse(10)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 5, 'range'); + $expected = array('prefix:key', 5, 'range'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testCreatesNewKeyOnNonExistingKey() + { + $redis = $this->getClient(); + + $this->assertSame(3, $redis->setrange('foo', 0, 'bar')); + $this->assertSame('bar', $redis->get('foo')); + + $this->assertSame(8, $redis->setrange('hoge', 4, 'piyo')); + $this->assertSame("\x00\x00\x00\x00piyo", $redis->get('hoge')); + } + + /** + * @group connected + */ + public function testOverwritesOrAppendBytesInKeys() + { + $redis = $this->getClient(); + + $redis->set('foo', 'barbar'); + + $this->assertSame(6, $redis->setrange('foo', 3, 'baz')); + $this->assertSame('barbaz', $redis->get('foo')); + + $this->assertEquals(16, $redis->setrange('foo', 10, 'foofoo')); + $this->assertEquals("barbaz\x00\x00\x00\x00foofoo", $redis->get('foo')); + } + + /** + * @group connected + */ + public function testHandlesBinaryData() + { + $redis = $this->getClient(); + + $this->assertSame(4, $redis->setrange('key:binary', 0, pack('i', -2147483648))); + + list($unpacked) = array_values(unpack('i', $redis->get('key:binary'))); + $this->assertEquals(-2147483648, $unpacked); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR offset is out of range + */ + public function testThrowsExceptionOnInvalidOffset() + { + $this->getClient()->setrange('var', -1, 'bogus'); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->lpush('metavars', 'foo'); + $redis->setrange('metavars', 3, 'bar'); + } +} diff --git a/tests/Predis/Commands/StringSetTest.php b/tests/Predis/Commands/StringSetTest.php new file mode 100644 index 00000000..70c70293 --- /dev/null +++ b/tests/Predis/Commands/StringSetTest.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringSetTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringSet'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SET'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('foo', 'bar'); + $expected = array('foo', 'bar'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'value'); + $expected = array('prefix:key', 'value'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testSetStringValue() + { + $redis = $this->getClient(); + + $this->assertTrue($redis->set('foo', 'bar')); + $this->assertTrue($redis->exists('foo')); + $this->assertEquals('bar', $redis->get('foo')); + } +} diff --git a/tests/Predis/Commands/StringStrlenTest.php b/tests/Predis/Commands/StringStrlenTest.php new file mode 100644 index 00000000..032563f7 --- /dev/null +++ b/tests/Predis/Commands/StringStrlenTest.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-string + */ +class StringStrlenTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringStrlen'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'STRLEN'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key'); + $expected = array('key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(4, $this->getCommand()->parseResponse(4)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsTheLengthOfString() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $this->assertSame(3, $redis->strlen('foo')); + + $redis->append('foo', 'bar'); + $this->assertSame(6, $redis->strlen('foo')); + } + + /** + * @group connected + */ + public function testReturnsZeroOnNonExistingKeys() + { + $redis = $this->getClient(); + + $this->assertSame(0, $redis->strlen('foo')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->lpush('metavars', 'foo'); + $redis->strlen('metavars'); + } +} diff --git a/tests/Predis/Commands/StringSubstrTest.php b/tests/Predis/Commands/StringSubstrTest.php new file mode 100644 index 00000000..4831dcbb --- /dev/null +++ b/tests/Predis/Commands/StringSubstrTest.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * SUBSTR is actually the old name of GETRANGE in version of Redis <= 2.0. + * This command should be considered obsolete and we will perform any kind + * of tests against a Redis server for this one. + * + * @group commands + * @group realm-string + */ +class StringSubstrTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\StringSubstr'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'SUBSTR'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 5, 10); + $expected = array('key', 5, 10); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame('substring',$this->getCommand()->parseResponse('substring')); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 5, 10); + $expected = array('prefix:key', 5, 10); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } +} diff --git a/tests/Predis/Commands/TransactionDiscardTest.php b/tests/Predis/Commands/TransactionDiscardTest.php new file mode 100644 index 00000000..84bd8590 --- /dev/null +++ b/tests/Predis/Commands/TransactionDiscardTest.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-transaction + */ +class TransactionDiscardTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\TransactionDiscard'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'DISCARD'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $command = $this->getCommand(); + $command->setArguments(array()); + + $this->assertSame(array(), $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } + + /** + * @group connected + */ + public function testAbortsTransactionAndRestoresNormalFlow() + { + $redis = $this->getClient(); + + $redis->multi(); + + $this->assertInstanceOf('Predis\ResponseQueued', $redis->set('foo', 'bar')); + $this->assertTrue($redis->discard()); + $this->assertFalse($redis->exists('foo')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR DISCARD without MULTI + */ + public function testThrowsExceptionWhenCallingOutsideTransaction() + { + $redis = $this->getClient(); + + $redis->discard(); + } +} diff --git a/tests/Predis/Commands/TransactionExecTest.php b/tests/Predis/Commands/TransactionExecTest.php new file mode 100644 index 00000000..75e8c46e --- /dev/null +++ b/tests/Predis/Commands/TransactionExecTest.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-transaction + */ +class TransactionExecTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\TransactionExec'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'EXEC'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $command = $this->getCommand(); + $command->setArguments(array()); + + $this->assertSame(array(), $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('tx1', 'tx2'); + $expected = array('tx1', 'tx2'); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group connected + */ + public function testExecutesTransactionAndReturnsArrayOfReplies() + { + $redis = $this->getClient(); + + $redis->multi(); + $redis->echo('tx1'); + $redis->echo('tx2'); + + $this->assertSame(array('tx1', 'tx2'), $redis->exec()); + } + + /** + * @group connected + */ + public function testReturnsEmptyArrayOnEmptyTransactions() + { + $redis = $this->getClient(); + + $redis->multi(); + + $this->assertSame(array(), $redis->exec()); + } + + /** + * @group connected + */ + public function testRepliesOfTransactionsAreNotParsed() + { + $redis = $this->getClient(); + + $redis->multi(); + $redis->ping(); + $redis->set('foo', 'bar'); + $redis->exists('foo'); + + $this->assertSame(array('PONG', true, 1), $redis->exec()); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR EXEC without MULTI + */ + public function testThrowsExceptionWhenCallingOutsideTransaction() + { + $redis = $this->getClient(); + + $redis->exec(); + } +} diff --git a/tests/Predis/Commands/TransactionMultiTest.php b/tests/Predis/Commands/TransactionMultiTest.php new file mode 100644 index 00000000..ad818f48 --- /dev/null +++ b/tests/Predis/Commands/TransactionMultiTest.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-transaction + */ +class TransactionMultiTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\TransactionMulti'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'MULTI'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $command = $this->getCommand(); + $command->setArguments(array()); + + $this->assertSame(array(), $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } + + /** + * @group connected + */ + public function testInitializesNewTransaction() + { + $redis = $this->getClient(); + + $this->assertTrue($redis->multi()); + $this->assertSame('QUEUED', (string) $redis->echo('tx1')); + $this->assertSame('QUEUED', (string) $redis->echo('tx2')); + } + + /** + * @group connected + */ + public function testActuallyReturnsReplyObjectAbstraction() + { + $redis = $this->getClient(); + + $this->assertTrue($redis->multi()); + $this->assertInstanceOf('Predis\IReplyObject', $redis->echo('tx1')); + $this->assertInstanceOf('Predis\ResponseQueued', $redis->echo('tx2')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR MULTI calls can not be nested + */ + public function testThrowsExceptionWhenCallingMultiInsideTransaction() + { + $redis = $this->getClient(); + + $redis->multi(); + $redis->multi(); + } +} diff --git a/tests/Predis/Commands/TransactionUnwatchTest.php b/tests/Predis/Commands/TransactionUnwatchTest.php new file mode 100644 index 00000000..85393caa --- /dev/null +++ b/tests/Predis/Commands/TransactionUnwatchTest.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-transaction + */ +class TransactionUnwatchTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\TransactionUnwatch'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'UNWATCH'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $command = $this->getCommand(); + $command->setArguments(array()); + + $this->assertSame(array(), $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } + + /** + * @group connected + */ + public function testUnwatchWatchedKeys() + { + $redis1 = $this->getClient(); + $redis2 = $this->getClient(); + + $redis1->set('foo', 'bar'); + $redis1->watch('foo'); + $this->assertTrue($redis1->unwatch()); + $redis1->multi(); + $redis1->get('foo'); + + $redis2->set('foo', 'hijacked'); + + $this->assertSame(array('hijacked'), $redis1->exec()); + } + + /** + * @group connected + */ + public function testCanBeCalledInsideTransaction() + { + $redis = $this->getClient(); + + $redis->multi(); + $this->assertInstanceOf('Predis\ResponseQueued', $redis->unwatch()); + } +} diff --git a/tests/Predis/Commands/TransactionWatchTest.php b/tests/Predis/Commands/TransactionWatchTest.php new file mode 100644 index 00000000..33f6f1f1 --- /dev/null +++ b/tests/Predis/Commands/TransactionWatchTest.php @@ -0,0 +1,134 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-transaction + */ +class TransactionWatchTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\TransactionWatch'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'WATCH'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key1', 'key2', 'key3'); + $expected = array('key1', 'key2', 'key3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsAsSingleArray() + { + $arguments = array(array('key1', 'key2', 'key3')); + $expected = array('key1', 'key2', 'key3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertTrue($this->getCommand()->parseResponse(true)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key1', 'key2', 'key3'); + $expected = array('prefix:key1', 'prefix:key2', 'prefix:key3'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testAbortsTransactionOnExternalWriteOperations() + { + $redis1 = $this->getClient(); + $redis2 = $this->getClient(); + + $redis1->mset('foo', 'bar', 'hoge', 'piyo'); + + $this->assertTrue($redis1->watch('foo', 'hoge')); + $this->assertTrue($redis1->multi()); + $this->assertInstanceOf('Predis\ResponseQueued', $redis1->get('foo')); + $this->assertTrue($redis2->set('foo', 'hijacked')); + $this->assertNull($redis1->exec()); + $this->assertSame('hijacked', $redis1->get('foo')); + } + + /** + * @group connected + */ + public function testCanWatchNotYetExistingKeys() + { + $redis1 = $this->getClient(); + $redis2 = $this->getClient(); + + $this->assertTrue($redis1->watch('foo')); + $this->assertTrue($redis1->multi()); + $this->assertInstanceOf('Predis\ResponseQueued', $redis1->set('foo', 'bar')); + $this->assertTrue($redis2->set('foo', 'hijacked')); + $this->assertNull($redis1->exec()); + $this->assertSame('hijacked', $redis1->get('foo')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR WATCH inside MULTI is not allowed + */ + public function testThrowsExceptionWhenCallingInsideTransaction() + { + $redis = $this->getClient(); + + $redis->multi(); + $redis->watch('foo'); + } +} diff --git a/tests/Predis/Commands/ZSetAddTest.php b/tests/Predis/Commands/ZSetAddTest.php new file mode 100644 index 00000000..c94ceb29 --- /dev/null +++ b/tests/Predis/Commands/ZSetAddTest.php @@ -0,0 +1,125 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-zset + */ +class ZSetAddTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ZSetAdd'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'ZADD'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 1, 'member1', 2, 'member2'); + $expected = array('key', 1, 'member1', 2, 'member2'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsMembersScoresAsSingleArray() + { + $arguments = array('key', array('member1' => 1, 'member2' => 2)); + $expected = array('key', 1, 'member1', 2, 'member2'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'score1', 'member1', 'score2', 'member2'); + $expected = array('prefix:key', 'score1', 'member1', 'score2', 'member2'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testAddsOrUpdatesMembersOrderingByScore() + { + $redis = $this->getClient(); + + $this->assertSame(5, $redis->zadd('letters', 1, 'a', 2, 'b', 3, 'c', 4, 'd', 5, 'e')); + $this->assertSame(array('a', 'b', 'c', 'd', 'e'), $redis->zrange('letters', 0, -1)); + + $this->assertSame(1, $redis->zadd('letters', 1, 'e', 8, 'c', 6, 'f')); + $this->assertSame(array('a', 'e', 'b', 'd', 'f', 'c'), $redis->zrange('letters', 0, -1)); + } + + /** + * @group connected + */ + public function testAcceptsFloatValuesAsScore() + { + $redis = $this->getClient(); + + $redis->zadd('letters', 0.2, 'b', 0.3, 'a', 0.1, 'c'); + $this->assertSame(array('c', 'b', 'a'), $redis->zrange('letters', 0, -1)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->zadd('foo', 10, 'bar'); + } +} diff --git a/tests/Predis/Commands/ZSetCardinalityTest.php b/tests/Predis/Commands/ZSetCardinalityTest.php new file mode 100644 index 00000000..40bb8f2e --- /dev/null +++ b/tests/Predis/Commands/ZSetCardinalityTest.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-zset + */ +class ZSetCardinalityTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ZSetCardinality'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'ZCARD'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key'); + $expected = array('key'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key'); + $expected = array('prefix:key'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsSizeOfSortedSet() + { + $redis = $this->getClient(); + + $redis->zadd('letters', 1, 'a', 2, 'b', 3, 'c'); + $this->assertSame(3, $redis->zcard('letters')); + + $this->assertSame(0, $redis->zcard('unknown')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->zcard('foo'); + } +} diff --git a/tests/Predis/Commands/ZSetCountTest.php b/tests/Predis/Commands/ZSetCountTest.php new file mode 100644 index 00000000..db548696 --- /dev/null +++ b/tests/Predis/Commands/ZSetCountTest.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-zset + */ +class ZSetCountTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ZSetCount'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'ZCOUNT'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 0, 10); + $expected = array('key', 0, 10); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 0, 10); + $expected = array('prefix:key', 0, 10); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsNumberOfElementsInGivenScoreRange() + { + $redis = $this->getClient(); + + $redis->zadd('letters', 10, 'a', 20, 'b', 30, 'c', 40, 'd', 50, 'e'); + + $this->assertSame(5, $redis->zcount('letters', 0, 100)); + $this->assertSame(5, $redis->zcount('letters', -100, 100)); + $this->assertSame(2, $redis->zcount('letters', 25, 45)); + $this->assertSame(1, $redis->zcount('letters', 20, 20)); + $this->assertSame(0, $redis->zcount('letters', 0, 0)); + + $this->assertSame(0, $redis->zcount('unknown', 0, 100)); + } + + /** + * @group connected + */ + public function testInfinityScoreIntervals() + { + $redis = $this->getClient(); + + $redis->zadd('letters', 10, 'a', 20, 'b', 30, 'c', 40, 'd', 50, 'e'); + + $this->assertSame(3, $redis->zcount('letters', '-inf', 30)); + $this->assertSame(3, $redis->zcount('letters', 30, '+inf')); + $this->assertSame(5, $redis->zcount('letters', '-inf', '+inf')); + } + + /** + * @group connected + */ + public function testExclusiveScoreIntervals() + { + $redis = $this->getClient(); + + $redis->zadd('letters', 10, 'a', 20, 'b', 30, 'c', 40, 'd', 50, 'e'); + + $this->assertSame(2, $redis->zcount('letters', 10, '(30')); + $this->assertSame(2, $redis->zcount('letters', '(10', 30)); + $this->assertSame(1, $redis->zcount('letters', '(10', '(30')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->zcount('foo', 0, 10); + } +} diff --git a/tests/Predis/Commands/ZSetIncrementByTest.php b/tests/Predis/Commands/ZSetIncrementByTest.php new file mode 100644 index 00000000..1994a23d --- /dev/null +++ b/tests/Predis/Commands/ZSetIncrementByTest.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-zset + */ +class ZSetIncrementByTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ZSetIncrementBy'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'ZINCRBY'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 1.0, 'member'); + $expected = array('key', 1.0, 'member'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame('1', $this->getCommand()->parseResponse('1')); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 1.0, 'member'); + $expected = array('prefix:key', 1.0, 'member'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testIncrementsScoreOfMemberByFloat() + { + $redis = $this->getClient(); + + $this->assertSame('1', $redis->zincrby('letters', 1, 'member')); + $this->assertSame('0', $redis->zincrby('letters', -1, 'member')); + $this->assertSame('0.5', $redis->zincrby('letters', 0.5, 'member')); + $this->assertSame('-10', $redis->zincrby('letters', -10.5, 'member')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->zincrby('foo', 1, 'bar'); + } +} diff --git a/tests/Predis/Commands/ZSetIntersectionStoreTest.php b/tests/Predis/Commands/ZSetIntersectionStoreTest.php new file mode 100644 index 00000000..3d6c4c07 --- /dev/null +++ b/tests/Predis/Commands/ZSetIntersectionStoreTest.php @@ -0,0 +1,193 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-zset + */ +class ZSetIntersectionStoreTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ZSetIntersectionStore'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'ZINTERSTORE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $modifiers = array( + 'aggregate' => 'sum', + 'weights' => array(10, 100), + ); + $arguments = array('zset:destination', 2, 'zset1', 'zset2', $modifiers); + + $expected = array( + 'zset:destination', 2, 'zset1', 'zset2', 'WEIGHTS', 10, 100, 'AGGREGATE', 'sum' + ); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsSourceKeysAsSingleArray() + { + $modifiers = array( + 'aggregate' => 'sum', + 'weights' => array(10, 100), + ); + $arguments = array('zset:destination', array('zset1', 'zset2'), $modifiers); + + $expected = array( + 'zset:destination', 2, 'zset1', 'zset2', 'WEIGHTS', 10, 100, 'AGGREGATE', 'sum' + ); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $modifiers = array( + 'aggregate' => 'sum', + 'weights' => array(10, 100), + ); + $arguments = array('zset:destination', 2, 'zset1', 'zset2', $modifiers); + + $expected = array( + 'prefix:zset:destination', 2, 'prefix:zset1', 'prefix:zset2', 'WEIGHTS', 10, 100, 'AGGREGATE', 'sum' + ); + + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testStoresIntersectionInNewSortedSet() + { + $redis = $this->getClient(); + + $redis->zadd('letters:1st', 1, 'a', 2, 'b', 3, 'c'); + $redis->zadd('letters:2nd', 1, 'b', 2, 'c', 3, 'd'); + + $this->assertSame(2, $redis->zinterstore('letters:out', 2, 'letters:1st', 'letters:2nd')); + $this->assertSame(array(array('b', '3'), array('c', '5')), $redis->zrange('letters:out', 0, -1, 'withscores')); + + $this->assertSame(0, $redis->zinterstore('letters:out', 2, 'letters:1st', 'letters:void')); + $this->assertSame(0, $redis->zinterstore('letters:out', 2, 'letters:void', 'letters:2nd')); + $this->assertSame(0, $redis->zinterstore('letters:out', 2, 'letters:void', 'letters:void')); + } + + /** + * @group connected + */ + public function testStoresIntersectionWithAggregateModifier() + { + $redis = $this->getClient(); + + $redis->zadd('letters:1st', 1, 'a', 2, 'b', 3, 'c'); + $redis->zadd('letters:2nd', 1, 'b', 2, 'c', 3, 'd'); + + $options = array('aggregate' => 'min'); + $this->assertSame(2, $redis->zinterstore('letters:min', 2, 'letters:1st', 'letters:2nd', $options)); + $this->assertSame(array(array('b', '1'), array('c', '2')), $redis->zrange('letters:min', 0, -1, 'withscores')); + + $options = array('aggregate' => 'max'); + $this->assertSame(2, $redis->zinterstore('letters:max', 2, 'letters:1st', 'letters:2nd', $options)); + $this->assertSame(array(array('b', '2'), array('c', '3')), $redis->zrange('letters:max', 0, -1, 'withscores')); + + $options = array('aggregate' => 'sum'); + $this->assertSame(2, $redis->zinterstore('letters:sum', 2, 'letters:1st', 'letters:2nd', $options)); + $this->assertSame(array(array('b', '3'), array('c', '5')), $redis->zrange('letters:sum', 0, -1, 'withscores')); + } + + /** + * @group connected + */ + public function testStoresIntersectionWithWeightsModifier() + { + $redis = $this->getClient(); + + $redis->zadd('letters:1st', 1, 'a', 2, 'b', 3, 'c'); + $redis->zadd('letters:2nd', 1, 'b', 2, 'c', 3, 'd'); + + $options = array('weights' => array(2, 3)); + $this->assertSame(2, $redis->zinterstore('letters:out', 2, 'letters:1st', 'letters:2nd', $options)); + $this->assertSame(array(array('b', '7'), array('c', '12')), $redis->zrange('letters:out', 0, -1, 'withscores')); + } + + /** + * @group connected + */ + public function testStoresIntersectionWithCombinedModifiers() + { + $redis = $this->getClient(); + + $redis->zadd('letters:1st', 1, 'a', 2, 'b', 3, 'c'); + $redis->zadd('letters:2nd', 1, 'b', 2, 'c', 3, 'd'); + + $options = array('aggregate' => 'max', 'weights' => array(10, 15)); + $this->assertSame(2, $redis->zinterstore('letters:out', 2, 'letters:1st', 'letters:2nd', $options)); + $this->assertSame(array(array('b', '20'), array('c', '30')), $redis->zrange('letters:out', 0, -1, 'withscores')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->zinterstore('zset:destination', 1, 'foo'); + } +} diff --git a/tests/Predis/Commands/ZSetRangeByScoreTest.php b/tests/Predis/Commands/ZSetRangeByScoreTest.php new file mode 100644 index 00000000..1ed193f7 --- /dev/null +++ b/tests/Predis/Commands/ZSetRangeByScoreTest.php @@ -0,0 +1,230 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-zset + */ +class ZSetRangeByScoreTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ZSetRangeByScore'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'ZRANGEBYSCORE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $modifiers = array( + 'withscores' => true, + 'limit' => array(0, 100), + ); + + $arguments = array('zset', 0, 100, $modifiers); + $expected = array('zset', 0, 100, 'LIMIT', 0, 100, 'WITHSCORES'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsWithStringWithscores() + { + $arguments = array('zset', 0, 100, 'withscores'); + $expected = array('zset', 0, 100, 'WITHSCORES'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsWithNamedLimit() + { + $arguments = array('zset', 0, 100, array('limit' => array('offset' => 1, 'count' => 2))); + $expected = array('zset', 0, 100, 'LIMIT', 1, 2); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('element1', 'element2', 'element3'); + $expected = array('element1', 'element2', 'element3'); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testParseResponseWithScores() + { + $raw = array('element1', '1', 'element2', '2', 'element3', '3'); + $expected = array(array('element1', '1'), array('element2', '2'), array('element3', '3')); + + $command = $this->getCommandWithArgumentsArray(array('zset', 0, 1, 'withscores')); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $modifiers = array( + 'withscores' => true, + 'limit' => array(0, 100), + ); + + $arguments = array('zset', 0, 100, $modifiers); + $expected = array('prefix:zset', 0, 100, 'LIMIT', 0, 100, 'WITHSCORES'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsElementsInScoreRange() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + + $this->assertSame(array('a'), $redis->zrangebyscore('letters', -10, -10)); + $this->assertSame(array('c', 'd', 'e', 'f'), $redis->zrangebyscore('letters', 10, 30)); + $this->assertSame(array('d', 'e'), $redis->zrangebyscore('letters', 20, 20)); + $this->assertSame(array(), $redis->zrangebyscore('letters', 30, 0)); + + $this->assertSame(array(), $redis->zrangebyscore('unknown', 0, 30)); + } + + /** + * @group connected + */ + public function testInfinityScoreIntervals() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + + $this->assertSame(array('a', 'b', 'c'), $redis->zrangebyscore('letters', '-inf', 15)); + $this->assertSame(array('d', 'e', 'f'), $redis->zrangebyscore('letters', 15, '+inf')); + $this->assertSame(array('a', 'b', 'c', 'd', 'e', 'f'), $redis->zrangebyscore('letters', '-inf', '+inf')); + } + + /** + * @group connected + */ + public function testExclusiveScoreIntervals() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + + $this->assertSame(array('c', 'd', 'e'), $redis->zrangebyscore('letters', 10, '(30')); + $this->assertSame(array('d', 'e', 'f'), $redis->zrangebyscore('letters', '(10', 30)); + $this->assertSame(array('d', 'e'), $redis->zrangebyscore('letters', '(10', '(30')); + } + + /** + * @group connected + */ + public function testRangeWithWithscoresModifier() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + $expected = array(array('c', '10'), array('d', '20'), array('e', '20')); + + $this->assertSame($expected, $redis->zrangebyscore('letters', 10, 20, 'withscores')); + $this->assertSame($expected, $redis->zrangebyscore('letters', 10, 20, array('withscores' => true))); + } + + /** + * @group connected + */ + public function testRangeWithLimitModifier() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + $expected = array('d', 'e'); + + $this->assertSame($expected, $redis->zrangebyscore('letters', 10, 20, array('limit' => array(1, 2)))); + $this->assertSame($expected, $redis->zrangebyscore('letters', 10, 20, array('limit' => array('offset' => 1, 'count' => 2)))); + } + + /** + * @group connected + */ + public function testRangeWithCombinedModifiers() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + + $options = array('limit' => array(1, 2), 'withscores' => true); + $expected = array(array('d', '20'), array('e', '20')); + + $this->assertSame($expected, $redis->zrangebyscore('letters', 10, 20, $options)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->zrangebyscore('foo', 0, 10); + } +} diff --git a/tests/Predis/Commands/ZSetRangeTest.php b/tests/Predis/Commands/ZSetRangeTest.php new file mode 100644 index 00000000..e92e064e --- /dev/null +++ b/tests/Predis/Commands/ZSetRangeTest.php @@ -0,0 +1,153 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-zset + */ +class ZSetRangeTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ZSetRange'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'ZRANGE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('zset', 0, 100, array('withscores' => true)); + $expected = array('zset', 0, 100, 'WITHSCORES'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsWithStringWithscores() + { + $arguments = array('zset', 0, 100, 'withscores'); + $expected = array('zset', 0, 100, 'WITHSCORES'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('element1', 'element2', 'element3'); + $expected = array('element1', 'element2', 'element3'); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testParseResponseWithScores() + { + $raw = array('element1', '1', 'element2', '2', 'element3', '3'); + $expected = array(array('element1', '1'), array('element2', '2'), array('element3', '3')); + + $command = $this->getCommandWithArgumentsArray(array('zset', 0, 1, 'withscores')); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('zset', 0, 100, array('withscores' => true)); + $expected = array('prefix:zset', 0, 100, 'WITHSCORES'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsElementsInRange() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + + $this->assertSame(array(), $redis->zrange('letters', 1, 0)); + $this->assertSame(array('a'), $redis->zrange('letters', 0, 0)); + $this->assertSame(array('a', 'b', 'c', 'd'), $redis->zrange('letters', 0, 3)); + + $this->assertSame(array('a', 'b', 'c', 'd', 'e', 'f'), $redis->zrange('letters', 0, -1)); + $this->assertSame(array('a', 'b', 'c'), $redis->zrange('letters', 0, -4)); + $this->assertSame(array('c'), $redis->zrange('letters', 2, -4)); + $this->assertSame(array('a', 'b', 'c', 'd', 'e', 'f'), $redis->zrange('letters', -100, 100)); + + $this->assertSame(array(), $redis->zrange('unknown', 0, 30)); + } + + /** + * @group connected + */ + public function testRangeWithWithscoresModifier() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + $expected = array(array('c', '10'), array('d', '20'), array('e', '20')); + + $this->assertSame($expected, $redis->zrange('letters', 2, 4, 'withscores')); + $this->assertSame($expected, $redis->zrange('letters', 2, 4, array('withscores' => true))); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->zrange('foo', 0, 10); + } +} diff --git a/tests/Predis/Commands/ZSetRankTest.php b/tests/Predis/Commands/ZSetRankTest.php new file mode 100644 index 00000000..add3652d --- /dev/null +++ b/tests/Predis/Commands/ZSetRankTest.php @@ -0,0 +1,102 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-zset + */ +class ZSetRankTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ZSetRank'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'ZRANK'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'member'); + $expected = array('key', 'member'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'member'); + $expected = array('prefix:key', 'member'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsRank() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + + $this->assertSame(0, $redis->zrank('letters', 'a')); + $this->assertSame(1, $redis->zrank('letters', 'b')); + $this->assertSame(4, $redis->zrank('letters', 'e')); + + $this->assertNull($redis->zrank('unknown', 'a')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->zrank('foo', 'bar'); + } +} diff --git a/tests/Predis/Commands/ZSetRemoveRangeByRankTest.php b/tests/Predis/Commands/ZSetRemoveRangeByRankTest.php new file mode 100644 index 00000000..18109e3e --- /dev/null +++ b/tests/Predis/Commands/ZSetRemoveRangeByRankTest.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-zset + */ +class ZSetRemoveRangeByRankTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ZSetRemoveRangeByRank'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'ZREMRANGEBYRANK'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 0, 10); + $expected = array('key', 0, 10); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 0, 10); + $expected = array('prefix:key', 0, 10); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testRemovesRangeByRank() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + + $this->assertSame(3, $redis->zremrangebyrank('letters', 2, 4)); + $this->assertSame(array('a', 'b', 'f'), $redis->zrange('letters', 0, -1)); + + $this->assertSame(0, $redis->zremrangebyrank('unknown', 0, 30)); + } + + /** + * @group connected + */ + public function testRemovesRangeByRankWithNegativeIndex() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + + $this->assertSame(3, $redis->zremrangebyrank('letters', -5, 3)); + $this->assertSame(array('a', 'e', 'f'), $redis->zrange('letters', 0, -1)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->zremrangebyrank('foo', 0, 10); + } +} diff --git a/tests/Predis/Commands/ZSetRemoveRangeByScoreTest.php b/tests/Predis/Commands/ZSetRemoveRangeByScoreTest.php new file mode 100644 index 00000000..35edef39 --- /dev/null +++ b/tests/Predis/Commands/ZSetRemoveRangeByScoreTest.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-zset + */ +class ZSetRemoveRangeByScoreTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ZSetRemoveRangeByScore'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'ZREMRANGEBYSCORE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 0, 10); + $expected = array('key', 0, 10); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 0, 10); + $expected = array('prefix:key', 0, 10); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testRemovesRangeByScore() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + + $this->assertSame(3, $redis->zremrangebyscore('letters', 5, 20)); + $this->assertSame(array('a', 'b', 'f'), $redis->zrange('letters', 0, -1)); + + $this->assertSame(0, $redis->zremrangebyscore('unknown', 0, 30)); + } + + /** + * @group connected + */ + public function testRemovesRangeByExclusiveScore() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + + $this->assertSame(2, $redis->zremrangebyscore('letters', '(10', '(30')); + $this->assertSame(array('a', 'b', 'c', 'f'), $redis->zrange('letters', 0, -1)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->zremrangebyscore('foo', 0, 10); + } +} diff --git a/tests/Predis/Commands/ZSetRemoveTest.php b/tests/Predis/Commands/ZSetRemoveTest.php new file mode 100644 index 00000000..3660bda0 --- /dev/null +++ b/tests/Predis/Commands/ZSetRemoveTest.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-zset + */ +class ZSetRemoveTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ZSetRemove'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'ZREM'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('zset', 'member1', 'member2', 'member3'); + $expected = array('zset', 'member1', 'member2', 'member3'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('zset', 'member1', 'member2', 'member3'); + $expected = array('prefix:zset', 'member1', 'member2', 'member3'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testRemovesSpecifiedMembers() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + + $this->assertSame(3, $redis->zrem('letters', 'b', 'd', 'f', 'z')); + $this->assertSame(array('a', 'c', 'e'), $redis->zrange('letters', 0, -1)); + + $this->assertSame(0, $redis->zrem('unknown', 'a')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->zrem('foo', 'bar'); + } +} diff --git a/tests/Predis/Commands/ZSetReverseRangeByScoreTest.php b/tests/Predis/Commands/ZSetReverseRangeByScoreTest.php new file mode 100644 index 00000000..e9415191 --- /dev/null +++ b/tests/Predis/Commands/ZSetReverseRangeByScoreTest.php @@ -0,0 +1,230 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-zset + */ +class ZSetReverseRangeByScoreTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ZSetReverseRangeByScore'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'ZREVRANGEBYSCORE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $modifiers = array( + 'withscores' => true, + 'limit' => array(0, 100), + ); + + $arguments = array('zset', 0, 100, $modifiers); + $expected = array('zset', 0, 100, 'LIMIT', 0, 100, 'WITHSCORES'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsWithStringWithscores() + { + $arguments = array('zset', 0, 100, 'withscores'); + $expected = array('zset', 0, 100, 'WITHSCORES'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsWithNamedLimit() + { + $arguments = array('zset', 0, 100, array('limit' => array('offset' => 1, 'count' => 2))); + $expected = array('zset', 0, 100, 'LIMIT', 1, 2); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('element1', 'element2', 'element3'); + $expected = array('element1', 'element2', 'element3'); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testParseResponseWithScores() + { + $raw = array('element1', '1', 'element2', '2', 'element3', '3'); + $expected = array(array('element1', '1'), array('element2', '2'), array('element3', '3')); + + $command = $this->getCommandWithArgumentsArray(array('zset', 0, 1, 'withscores')); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $modifiers = array( + 'withscores' => true, + 'limit' => array(0, 100), + ); + + $arguments = array('zset', 0, 100, $modifiers); + $expected = array('prefix:zset', 0, 100, 'LIMIT', 0, 100, 'WITHSCORES'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsElementsInScoreRange() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + + $this->assertSame(array('a'), $redis->zrevrangebyscore('letters', -10, -10)); + $this->assertSame(array(), $redis->zrevrangebyscore('letters', 10, 30)); + $this->assertSame(array('e', 'd'), $redis->zrevrangebyscore('letters', 20, 20)); + $this->assertSame(array('f', 'e', 'd', 'c', 'b'), $redis->zrevrangebyscore('letters', 30, 0)); + + $this->assertSame(array(), $redis->zrevrangebyscore('unknown', 0, 30)); + } + + /** + * @group connected + */ + public function testInfinityScoreIntervals() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + + $this->assertSame(array('f', 'e', 'd'), $redis->zrevrangebyscore('letters', '+inf', 15)); + $this->assertSame(array('c', 'b', 'a'), $redis->zrevrangebyscore('letters', 15, '-inf')); + $this->assertSame(array('f', 'e', 'd', 'c', 'b', 'a'), $redis->zrevrangebyscore('letters', '+inf', '-inf')); + } + + /** + * @group connected + */ + public function testExclusiveScoreIntervals() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + + $this->assertSame(array('e', 'd', 'c'), $redis->zrevrangebyscore('letters', '(30', 10)); + $this->assertSame(array('f', 'e', 'd'), $redis->zrevrangebyscore('letters', 30, '(10')); + $this->assertSame(array('e', 'd'), $redis->zrevrangebyscore('letters', '(30', '(10')); + } + + /** + * @group connected + */ + public function testRangeWithWithscoresModifier() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + $expected = array(array('e', '20'), array('d', '20'), array('c', '10')); + + $this->assertSame($expected, $redis->zrevrangebyscore('letters', 20, 10, 'withscores')); + $this->assertSame($expected, $redis->zrevrangebyscore('letters', 20, 10, array('withscores' => true))); + } + + /** + * @group connected + */ + public function testRangeWithLimitModifier() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + $expected = array('d', 'c'); + + $this->assertSame($expected, $redis->zrevrangebyscore('letters', 20, 10, array('limit' => array(1, 2)))); + $this->assertSame($expected, $redis->zrevrangebyscore('letters', 20, 10, array('limit' => array('offset' => 1, 'count' => 2)))); + } + + /** + * @group connected + */ + public function testRangeWithCombinedModifiers() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + + $options = array('limit' => array(1, 2), 'withscores' => true); + $expected = array(array('d', '20'), array('c', '10')); + + $this->assertSame($expected, $redis->zrevrangebyscore('letters', 20, 10, $options)); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->zrevrangebyscore('foo', 0, 10); + } +} diff --git a/tests/Predis/Commands/ZSetReverseRangeTest.php b/tests/Predis/Commands/ZSetReverseRangeTest.php new file mode 100644 index 00000000..6304b117 --- /dev/null +++ b/tests/Predis/Commands/ZSetReverseRangeTest.php @@ -0,0 +1,153 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-zset + */ +class ZSetReverseRangeTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ZSetReverseRange'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'ZREVRANGE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('zset', 0, 100, array('withscores' => true)); + $expected = array('zset', 0, 100, 'WITHSCORES'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsWithStringWithscores() + { + $arguments = array('zset', 0, 100, 'withscores'); + $expected = array('zset', 0, 100, 'WITHSCORES'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $raw = array('element1', 'element2', 'element3'); + $expected = array('element1', 'element2', 'element3'); + + $command = $this->getCommand(); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testParseResponseWithScores() + { + $raw = array('element1', '1', 'element2', '2', 'element3', '3'); + $expected = array(array('element1', '1'), array('element2', '2'), array('element3', '3')); + + $command = $this->getCommandWithArgumentsArray(array('zset', 0, 1, 'withscores')); + + $this->assertSame($expected, $command->parseResponse($raw)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('zset', 0, 100, array('withscores' => true)); + $expected = array('prefix:zset', 0, 100, 'WITHSCORES'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsElementsInRange() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + + $this->assertSame(array(), $redis->zrevrange('letters', 1, 0)); + $this->assertSame(array('f'), $redis->zrevrange('letters', 0, 0)); + $this->assertSame(array('f', 'e', 'd', 'c'), $redis->zrevrange('letters', 0, 3)); + + $this->assertSame(array('f', 'e', 'd', 'c', 'b', 'a'), $redis->zrevrange('letters', 0, -1)); + $this->assertSame(array('f', 'e', 'd'), $redis->zrevrange('letters', 0, -4)); + $this->assertSame(array('d'), $redis->zrevrange('letters', 2, -4)); + $this->assertSame(array('f', 'e', 'd', 'c', 'b', 'a'), $redis->zrevrange('letters', -100, 100)); + + $this->assertSame(array(), $redis->zrevrange('unknown', 0, 30)); + } + + /** + * @group connected + */ + public function testRangeWithWithscoresModifier() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + $expected = array(array('d', '20'), array('c', '10'), array('b', '0')); + + $this->assertSame($expected, $redis->zrevrange('letters', 2, 4, 'withscores')); + $this->assertSame($expected, $redis->zrevrange('letters', 2, 4, array('withscores' => true))); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->zrevrange('foo', 0, 10); + } +} diff --git a/tests/Predis/Commands/ZSetReverseRankTest.php b/tests/Predis/Commands/ZSetReverseRankTest.php new file mode 100644 index 00000000..a2bbc88e --- /dev/null +++ b/tests/Predis/Commands/ZSetReverseRankTest.php @@ -0,0 +1,102 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-zset + */ +class ZSetReverseRankTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ZSetReverseRank'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'ZREVRANK'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'member'); + $expected = array('key', 'member'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'member'); + $expected = array('prefix:key', 'member'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsRank() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + + $this->assertSame(5, $redis->zrevrank('letters', 'a')); + $this->assertSame(4, $redis->zrevrank('letters', 'b')); + $this->assertSame(1, $redis->zrevrank('letters', 'e')); + + $this->assertNull($redis->zrevrank('unknown', 'a')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->zrevrank('foo', 'bar'); + } +} diff --git a/tests/Predis/Commands/ZSetScoreTest.php b/tests/Predis/Commands/ZSetScoreTest.php new file mode 100644 index 00000000..aebaefd0 --- /dev/null +++ b/tests/Predis/Commands/ZSetScoreTest.php @@ -0,0 +1,102 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-zset + */ +class ZSetScoreTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ZSetScore'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'ZSCORE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', 'member'); + $expected = array('key', 'member'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $arguments = array('key', 'member'); + $expected = array('prefix:key', 'member'); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testReturnsRank() + { + $redis = $this->getClient(); + + $redis->zadd('letters', -10, 'a', 0, 'b', 10, 'c', 20, 'd', 20, 'e', 30, 'f'); + + $this->assertSame('-10', $redis->zscore('letters', 'a')); + $this->assertSame('0', $redis->zscore('letters', 'b')); + $this->assertSame('20', $redis->zscore('letters', 'e')); + + $this->assertNull($redis->zscore('unknown', 'a')); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->zscore('foo', 'bar'); + } +} diff --git a/tests/Predis/Commands/ZSetUnionStoreTest.php b/tests/Predis/Commands/ZSetUnionStoreTest.php new file mode 100644 index 00000000..d1bb599c --- /dev/null +++ b/tests/Predis/Commands/ZSetUnionStoreTest.php @@ -0,0 +1,210 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Commands; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @group commands + * @group realm-zset + */ +class ZSetUnionStoreTest extends CommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Commands\ZSetUnionStore'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'ZUNIONSTORE'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $modifiers = array( + 'aggregate' => 'sum', + 'weights' => array(10, 100), + ); + $arguments = array('zset:destination', 2, 'zset1', 'zset2', $modifiers); + + $expected = array( + 'zset:destination', 2, 'zset1', 'zset2', 'WEIGHTS', 10, 100, 'AGGREGATE', 'sum' + ); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testFilterArgumentsSourceKeysAsSingleArray() + { + $modifiers = array( + 'aggregate' => 'sum', + 'weights' => array(10, 100), + ); + $arguments = array('zset:destination', array('zset1', 'zset2'), $modifiers); + + $expected = array( + 'zset:destination', 2, 'zset1', 'zset2', 'WEIGHTS', 10, 100, 'AGGREGATE', 'sum' + ); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group disconnected + */ + public function testPrefixKeys() + { + $modifiers = array( + 'aggregate' => 'sum', + 'weights' => array(10, 100), + ); + $arguments = array('zset:destination', 2, 'zset1', 'zset2', $modifiers); + + $expected = array( + 'prefix:zset:destination', 2, 'prefix:zset1', 'prefix:zset2', 'WEIGHTS', 10, 100, 'AGGREGATE', 'sum' + ); + + $command = $this->getCommandWithArgumentsArray($arguments); + $command->prefixKeys('prefix:'); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group connected + */ + public function testStoresUnionInNewSortedSet() + { + $redis = $this->getClient(); + + $redis->zadd('letters:1st', 1, 'a', 2, 'b', 3, 'c'); + $redis->zadd('letters:2nd', 1, 'b', 2, 'c', 3, 'd'); + + $this->assertSame(4, $redis->zunionstore('letters:out', 2, 'letters:1st', 'letters:2nd')); + $this->assertSame( + array(array('a', '1'), array('b', '3'), array('d', '3'), array('c', '5')), + $redis->zrange('letters:out', 0, -1, 'withscores') + ); + + $this->assertSame(3, $redis->zunionstore('letters:out', 2, 'letters:1st', 'letters:void')); + $this->assertSame(3, $redis->zunionstore('letters:out', 2, 'letters:void', 'letters:2nd')); + $this->assertSame(0, $redis->zunionstore('letters:out', 2, 'letters:void', 'letters:void')); + } + + /** + * @group connected + */ + public function testStoresUnionWithAggregateModifier() + { + $redis = $this->getClient(); + + $redis->zadd('letters:1st', 1, 'a', 2, 'b', 3, 'c'); + $redis->zadd('letters:2nd', 1, 'b', 2, 'c', 3, 'd'); + + $options = array('aggregate' => 'min'); + $this->assertSame(4, $redis->zunionstore('letters:min', 2, 'letters:1st', 'letters:2nd', $options)); + $this->assertSame( + array(array('a', '1'), array('b', '1'), array('c', '2'), array('d', '3')), + $redis->zrange('letters:min', 0, -1, 'withscores') + ); + + $options = array('aggregate' => 'max'); + $this->assertSame(4, $redis->zunionstore('letters:max', 2, 'letters:1st', 'letters:2nd', $options)); + $this->assertSame( + array(array('a', '1'), array('b', '2'), array('c', '3'), array('d', '3')), + $redis->zrange('letters:max', 0, -1, 'withscores') + ); + + $options = array('aggregate' => 'sum'); + $this->assertSame(4, $redis->zunionstore('letters:sum', 2, 'letters:1st', 'letters:2nd', $options)); + $this->assertSame( + array(array('a', '1'), array('b', '3'), array('d', '3'), array('c', '5')), + $redis->zrange('letters:sum', 0, -1, 'withscores') + ); + } + + /** + * @group connected + */ + public function testStoresUnionWithWeightsModifier() + { + $redis = $this->getClient(); + + $redis->zadd('letters:1st', 1, 'a', 2, 'b', 3, 'c'); + $redis->zadd('letters:2nd', 1, 'b', 2, 'c', 3, 'd'); + + $options = array('weights' => array(2, 3)); + $this->assertSame(4, $redis->zunionstore('letters:out', 2, 'letters:1st', 'letters:2nd', $options)); + $this->assertSame( + array(array('a', '2'), array('b', '7'), array('d', '9'), array('c', '12')), + $redis->zrange('letters:out', 0, -1, 'withscores') + ); + } + + /** + * @group connected + */ + public function testStoresUnionWithCombinedModifiers() + { + $redis = $this->getClient(); + + $redis->zadd('letters:1st', 1, 'a', 2, 'b', 3, 'c'); + $redis->zadd('letters:2nd', 1, 'b', 2, 'c', 3, 'd'); + + $options = array('aggregate' => 'max', 'weights' => array(10, 15)); + $this->assertSame(4, $redis->zunionstore('letters:out', 2, 'letters:1st', 'letters:2nd', $options)); + $this->assertSame( + array(array('a', '10'), array('b', '20'), array('c', '30'), array('d', '45')), + $redis->zrange('letters:out', 0, -1, 'withscores') + ); + } + + /** + * @group connected + * @expectedException Predis\ServerException + * @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->zunionstore('zset:destination', 1, 'foo'); + } +} diff --git a/tests/Predis/CommunicationExceptionTest.php b/tests/Predis/CommunicationExceptionTest.php new file mode 100644 index 00000000..9480e166 --- /dev/null +++ b/tests/Predis/CommunicationExceptionTest.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis; + +use \PHPUnit_Framework_TestCase as StandardTestCase; +use Predis\Network\IConnectionSingle; + +/** + * + */ +class CommunicationExceptionTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testExceptionMessage() + { + $message = 'Connection error message.'; + $connection = $this->getMockedConnectionBase(); + $exception = $this->getException($connection, $message); + + $this->setExpectedException('Predis\CommunicationException', $message); + + throw $exception; + } + + /** + * @group disconnected + */ + public function testExceptionConnection() + { + $connection = $this->getMockedConnectionBase(); + $exception = $this->getException($connection, 'ERROR MESSAGE'); + + $this->assertSame($connection, $exception->getConnection()); + } + + /** + * @group disconnected + */ + public function testShouldResetConnection() + { + $connection = $this->getMockedConnectionBase(); + $exception = $this->getException($connection, 'ERROR MESSAGE'); + + $this->assertTrue($exception->shouldResetConnection()); + } + + // ******************************************************************** // + // ---- HELPER METHODS ------------------------------------------------ // + // ******************************************************************** // + + /** + * Returns a mocked connection instance. + * + * @param mixed $parameters Connection parameters. + * @return IConnectionSingle + */ + protected function getMockedConnectionBase($parameters = null) + { + $builder = $this->getMockBuilder('Predis\Network\ConnectionBase'); + + if ($parameters === null) { + $builder->disableOriginalConstructor(); + } + else if (!$parameters instanceof IConnectionParameters) { + $parameters = new ConnectionParameters($parameters); + } + + return $builder->getMockForAbstractClass(array($parameters)); + } + + /** + * Returns a connection exception instance. + * + * @param IConnectionSingle $message Connection instance. + * @param string $message Exception message. + * @param int $code Exception code. + * @param \Exception $inner Inner exception. + * @return \Exception + */ + protected function getException(IConnectionSingle $connection, $message, $code = 0, \Exception $inner = null) + { + $arguments = array($connection, $message, $code, $inner); + $mock = $this->getMockForAbstractClass('Predis\CommunicationException', $arguments); + + return $mock; + } +} diff --git a/tests/Predis/ConnectionFactoryTest.php b/tests/Predis/ConnectionFactoryTest.php new file mode 100644 index 00000000..3832a2bd --- /dev/null +++ b/tests/Predis/ConnectionFactoryTest.php @@ -0,0 +1,353 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * + */ +class ConnectionFactoryTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testImplementsCorrectInterface() + { + $factory = new ConnectionFactory(); + + $this->assertInstanceOf('Predis\IConnectionFactory', $factory); + } + + /** + * @group disconnected + */ + public function testCreateConnection() + { + $factory = new ConnectionFactory(); + + $tcp = new ConnectionParameters(array( + 'scheme' => 'tcp', + 'host' => 'locahost', + )); + + $connection = $factory->create($tcp); + $parameters = $connection->getParameters(); + $this->assertInstanceOf('Predis\Network\StreamConnection', $connection); + $this->assertEquals($tcp->scheme, $parameters->scheme); + $this->assertEquals($tcp->host, $parameters->host); + $this->assertEquals($tcp->database, $parameters->database); + + + $unix = new ConnectionParameters(array( + 'scheme' => 'unix', + 'path' => '/tmp/redis.sock', + )); + + $connection = $factory->create($tcp); + $parameters = $connection->getParameters(); + $this->assertInstanceOf('Predis\Network\StreamConnection', $connection); + $this->assertEquals($tcp->scheme, $parameters->scheme); + $this->assertEquals($tcp->database, $parameters->database); + } + + /** + * @group disconnected + */ + public function testCreateConnectionWithNullParameters() + { + $factory = new ConnectionFactory(); + $connection = $factory->create(null); + $parameters = $connection->getParameters(); + + $this->assertInstanceOf('Predis\Network\IConnectionSingle', $connection); + $this->assertEquals('tcp', $parameters->scheme); + $this->assertFalse($parameters->isSetByUser('custom')); + } + + /** + * @group disconnected + */ + public function testCreateConnectionWithArrayParameters() + { + $factory = new ConnectionFactory(); + $connection = $factory->create(array('scheme' => 'tcp', 'custom' => 'foobar')); + $parameters = $connection->getParameters(); + + $this->assertInstanceOf('Predis\Network\IConnectionSingle', $connection); + $this->assertEquals('tcp', $parameters->scheme); + $this->assertTrue($parameters->isSetByUser('custom')); + } + + /** + * @group disconnected + */ + public function testCreateConnectionWithStringURI() + { + $factory = new ConnectionFactory(); + $connection = $factory->create('tcp://127.0.0.1?custom=foobar'); + $parameters = $connection->getParameters(); + + $this->assertInstanceOf('Predis\Network\IConnectionSingle', $connection); + $this->assertEquals('tcp', $parameters->scheme); + $this->assertTrue($parameters->isSetByUser('custom')); + } + + /** + * @group disconnected + */ + public function testCreateConnectionWithoutInitializationCommands() + { + $profile = $this->getMock('Predis\Profiles\IServerProfile'); + $profile->expects($this->never())->method('create'); + + $factory = new ConnectionFactory(); + $parameters = new ConnectionParameters(); + $connection = $factory->create($parameters, $profile); + + $this->assertInstanceOf('Predis\Network\IConnectionSingle', $connection); + } + + /** + * @group disconnected + */ + public function testCreateConnectionWithInitializationCommands() + { + $test = $this; + $database = 15; + $password = 'foobar'; + $commands = array(); + + $createCommand = function($id, $arguments) use($test, &$commands) { + $commands[$id] = $arguments; + return $test->getMock('Predis\Commands\ICommand'); + }; + + $profile = $this->getMock('Predis\Profiles\IServerProfile'); + $profile->expects($this->exactly(2)) + ->method('createCommand') + ->with($this->isType('string'), $this->isType('array')) + ->will($this->returnCallback($createCommand)); + + $factory = new ConnectionFactory(); + $parameters = new ConnectionParameters(array('database' => $database, 'password' => $password)); + $connection = $factory->create($parameters, $profile); + + $this->assertInstanceOf('Predis\Network\IConnectionSingle', $connection); + $this->assertEquals(2, count($commands)); // TODO: assertCount()? + $this->assertEquals(array($database), $commands['select']); + $this->assertEquals(array($password), $commands['auth']); + } + + /** + * @group disconnected + */ + public function testCreateUndefinedConnection() + { + $scheme = 'unknown'; + $this->setExpectedException('InvalidArgumentException', "Unknown connection scheme: $scheme"); + + $factory = new ConnectionFactory(); + $factory->create(new ConnectionParameters(array('scheme' => $scheme))); + } + + /** + * @group disconnected + */ + public function testDefineConnectionWithFQN() + { + list(, $connectionClass) = $this->getMockConnectionClass(); + + $parameters = new ConnectionParameters(array('scheme' => 'foobar')); + $factory = new ConnectionFactory(); + + $factory->define($parameters->scheme, $connectionClass); + $connection = $factory->create($parameters); + + $this->assertInstanceOf($connectionClass, $connection); + } + + /** + * @group disconnected + */ + public function testDefineConnectionWithCallable() + { + list(, $connectionClass) = $this->getMockConnectionClass(); + + $parameters = new ConnectionParameters(array('scheme' => 'foobar')); + + $initializer = function($parameters) use($connectionClass) { + return new $connectionClass($parameters); + }; + + $initializerMock = $this->getMock('stdClass', array('__invoke')); + $initializerMock->expects($this->exactly(2)) + ->method('__invoke') + ->with($parameters) + ->will($this->returnCallback($initializer)); + + $factory = new ConnectionFactory(); + $factory->define($parameters->scheme, $initializerMock); + $connection1 = $factory->create($parameters); + $connection2 = $factory->create($parameters); + + $this->assertInstanceOf($connectionClass, $connection1); + $this->assertInstanceOf($connectionClass, $connection2); + $this->assertNotSame($connection1, $connection2); + } + + /** + * @group disconnected + */ + public function testDefineConnectionWithInvalidArgument() + { + $this->setExpectedException('InvalidArgumentException'); + + $factory = new ConnectionFactory(); + $factory->define('foobar', new \stdClass()); + } + + /** + * @group disconnected + */ + public function testUndefineDefinedConnection() + { + $this->setExpectedException('InvalidArgumentException', 'Unknown connection scheme: tcp'); + + $factory = new ConnectionFactory(); + $factory->undefine('tcp'); + $factory->create('tcp://127.0.0.1'); + } + + /** + * @group disconnected + */ + public function testUndefineUndefinedConnection() + { + $factory = new ConnectionFactory(); + $factory->undefine('unknown'); + $connection = $factory->create('tcp://127.0.0.1'); + + $this->assertInstanceOf('Predis\Network\IConnectionSingle', $connection); + } + + /** + * @group disconnected + */ + public function testDefineAndUndefineConnection() + { + list(, $connectionClass) = $this->getMockConnectionClass(); + + $factory = new ConnectionFactory(); + + $factory->define('redis', $connectionClass); + $this->assertInstanceOf($connectionClass, $factory->create('redis://127.0.0.1')); + + $factory->undefine('redis'); + $this->setExpectedException('InvalidArgumentException', 'Unknown connection scheme: redis'); + $factory->create('redis://127.0.0.1'); + } + + /** + * @group disconnected + */ + public function testClusterSkipCreationOnConnectionInstance() + { + list(, $connectionClass) = $this->getMockConnectionClass(); + + $cluster = $this->getMock('Predis\Network\IConnectionCluster'); + $cluster->expects($this->exactly(2)) + ->method('add') + ->with($this->isInstanceOf('Predis\Network\IConnectionSingle')); + + $factory = $this->getMock('Predis\ConnectionFactory', array('create')); + $factory->expects($this->never()) + ->method('create'); + + $factory->createCluster($cluster, array(new $connectionClass(), new $connectionClass())); + } + + /** + * @group disconnected + */ + public function testClusterWithMixedConnectionParameters() + { + list(, $connectionClass) = $this->getMockConnectionClass(); + + $cluster = $this->getMock('Predis\Network\IConnectionCluster'); + $cluster->expects($this->exactly(4)) + ->method('add') + ->with($this->isInstanceOf('Predis\Network\IConnectionSingle')); + + $factory = $this->getMock('Predis\ConnectionFactory', array('create')); + $factory->expects($this->exactly(3)) + ->method('create') + ->will($this->returnCallback(function($_, $_) use($connectionClass) { + return new $connectionClass; + })); + + $factory->createCluster($cluster, array(null, 'tcp://127.0.0.1', array('scheme' => 'tcp'), new $connectionClass())); + } + + /** + * @group disconnected + */ + public function testClusterWithEmptyListOfParameters() + { + $cluster = $this->getMock('Predis\Network\IConnectionCluster'); + $cluster->expects($this->never())->method('add'); + + $factory = $this->getMock('Predis\ConnectionFactory', array('create')); + $factory->expects($this->never())->method('create'); + + $factory->createCluster($cluster, array()); + } + + /** + * @group disconnected + * @todo We might want to add a test for IConnectionSingle::pushInitCommand(). + */ + public function testClusterWithServerProfileArgument() + { + list(, $connectionClass) = $this->getMockConnectionClass(); + + $cluster = $this->getMock('Predis\Network\IConnectionCluster'); + $profile = $this->getMock('Predis\Profiles\IServerProfile'); + + $factory = $this->getMock('Predis\ConnectionFactory', array('create')); + $factory->expects($this->exactly(2)) + ->method('create') + ->with($this->anything(), $profile) + ->will($this->returnCallback(function($_, $_) use($connectionClass) { + return new $connectionClass(); + })); + + $nodes = array('tcp://127.0.0.1:7001?password=foo', 'tcp://127.0.0.1:7002?password=bar'); + $factory->createCluster($cluster, $nodes, $profile); + } + + // ******************************************************************** // + // ---- HELPER METHODS ------------------------------------------------ // + // ******************************************************************** // + + /** + * Returns a mocked Predis\Network\IConnectionSingle. + * + * @return Array Mock instance and class name + */ + protected function getMockConnectionClass() + { + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + + return array($connection, get_class($connection)); + } +} diff --git a/tests/Predis/ConnectionParametersTest.php b/tests/Predis/ConnectionParametersTest.php new file mode 100644 index 00000000..ea7d4d77 --- /dev/null +++ b/tests/Predis/ConnectionParametersTest.php @@ -0,0 +1,225 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @todo ConnectionParameters::define(); + * @todo ConnectionParameters::undefine(); + */ +class ConnectionParametersTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testDefaultValues() + { + $defaults = $this->getDefaultParametersArray(); + $parameters = new ConnectionParameters(); + + $this->assertEquals($defaults['scheme'], $parameters->scheme); + $this->assertEquals($defaults['host'], $parameters->host); + $this->assertEquals($defaults['port'], $parameters->port); + $this->assertEquals($defaults['throw_errors'], $parameters->throw_errors); + $this->assertEquals($defaults['iterable_multibulk'], $parameters->iterable_multibulk); + $this->assertEquals($defaults['connection_async'], $parameters->connection_async); + $this->assertEquals($defaults['connection_persistent'], $parameters->connection_persistent); + $this->assertEquals($defaults['connection_timeout'], $parameters->connection_timeout); + $this->assertEquals($defaults['read_write_timeout'], $parameters->read_write_timeout); + $this->assertEquals($defaults['database'], $parameters->database); + $this->assertEquals($defaults['password'], $parameters->password); + $this->assertEquals($defaults['alias'], $parameters->alias); + $this->assertEquals($defaults['weight'], $parameters->weight); + $this->assertEquals($defaults['path'], $parameters->path); + } + + /** + * @group disconnected + */ + public function testIsSet() + { + $parameters = new ConnectionParameters(); + + $this->assertTrue(isset($parameters->scheme)); + $this->assertFalse(isset($parameters->unknown)); + } + + /** + * @group disconnected + */ + public function testIsSetByUser() + { + $parameters = new ConnectionParameters(array('port' => 7000, 'custom' => 'foobar')); + + $this->assertTrue(isset($parameters->scheme)); + $this->assertFalse($parameters->isSetByUser('scheme')); + + $this->assertTrue(isset($parameters->port)); + $this->assertTrue($parameters->isSetByUser('port')); + + $this->assertTrue(isset($parameters->custom)); + $this->assertTrue($parameters->isSetByUser('custom')); + + $this->assertFalse(isset($parameters->unknown)); + $this->assertFalse($parameters->isSetByUser('unknown')); + } + + /** + * @group disconnected + */ + public function testConstructWithUriString() + { + $defaults = $this->getDefaultParametersArray(); + + $overrides = array( + 'port' => 7000, + 'database' => 5, + 'throw_errors' => false, + 'custom' => 'foobar', + ); + + $parameters = new ConnectionParameters($this->getParametersString($overrides)); + + $this->assertEquals($defaults['scheme'], $parameters->scheme); + $this->assertEquals($defaults['host'], $parameters->host); + $this->assertEquals($overrides['port'], $parameters->port); + + $this->assertEquals($overrides['database'], $parameters->database); + $this->assertEquals($overrides['throw_errors'], $parameters->throw_errors); + + $this->assertTrue(isset($parameters->custom)); + $this->assertTrue($parameters->isSetByUser('custom')); + $this->assertEquals($overrides['custom'], $parameters->custom); + + $this->assertFalse(isset($parameters->unknown)); + $this->assertFalse($parameters->isSetByUser('unknown')); + } + + /** + * @group disconnected + */ + public function testToArray() + { + $additional = array('port' => 7000, 'custom' => 'foobar'); + $parameters = new ConnectionParameters($additional); + + $this->assertEquals($this->getParametersArray($additional), $parameters->toArray()); + } + + /** + * @group disconnected + */ + public function testToString() + { + $uri = 'tcp://localhost:7000/?database=15&custom=foobar&throw_errors=0'; + $parameters = new ConnectionParameters($uri); + + $this->assertEquals($uri, (string) $parameters); + } + + /** + * @group disconnected + * @todo Does it actually make sense? + */ + public function testToStringOmitPassword() + { + $uri = 'tcp://localhost:7000/?database=15&custom=foobar&throw_errors=0'; + $parameters = new ConnectionParameters($uri . '&password=foobar'); + + $this->assertEquals($uri, (string) $parameters); + } + + /** + * @group disconnected + */ + public function testSerialization() + { + $parameters = new ConnectionParameters(array('port' => 7000, 'custom' => 'foobar')); + $unserialized = unserialize(serialize($parameters)); + + $this->assertEquals($parameters->scheme, $unserialized->scheme); + $this->assertEquals($parameters->port, $unserialized->port); + + $this->assertTrue(isset($unserialized->custom)); + $this->assertTrue($unserialized->isSetByUser('custom')); + $this->assertEquals($parameters->custom, $unserialized->custom); + + $this->assertFalse(isset($unserialized->unknown)); + $this->assertFalse($unserialized->isSetByUser('unknown')); + } + + // ******************************************************************** // + // ---- HELPER METHODS ------------------------------------------------ // + // ******************************************************************** // + + /** + * Returns a named array with the default connection parameters and their values. + * + * @return Array Default connection parameters. + */ + protected function getDefaultParametersArray() + { + return array( + 'scheme' => 'tcp', + 'host' => '127.0.0.1', + 'port' => 6379, + 'database' => null, + 'password' => null, + 'connection_async' => false, + 'connection_persistent' => false, + 'connection_timeout' => 5.0, + 'read_write_timeout' => null, + 'alias' => null, + 'weight' => null, + 'path' => null, + 'iterable_multibulk' => false, + 'throw_errors' => true, + ); + } + + /** + * Returns a named array with the default connection parameters merged with + * the specified additional parameters. + * + * @param Array $additional Additional connection parameters. + * @return Array Connection parameters. + */ + protected function getParametersArray(Array $additional) + { + return array_merge($this->getDefaultParametersArray(), $additional); + } + + /** + * Returns an URI string representation of the specified connection parameters. + * + * @param Array $parameters Array of connection parameters. + * @return String URI string. + */ + protected function getParametersString(Array $parameters) + { + $defaults = $this->getDefaultParametersArray(); + + $scheme = isset($parameters['scheme']) ? $parameters['scheme'] : $defaults['scheme']; + $host = isset($parameters['host']) ? $parameters['host'] : $defaults['host']; + $port = isset($parameters['port']) ? $parameters['port'] : $defaults['port']; + + unset($parameters['scheme'], $parameters['host'], $parameters['port']); + $uriString = "$scheme://$host:$port/?"; + + foreach ($parameters as $k => $v) { + $uriString .= "$k=$v&"; + } + + return $uriString; + } +} diff --git a/tests/Predis/Distribution/EmptyRingExceptionTest.php b/tests/Predis/Distribution/EmptyRingExceptionTest.php new file mode 100644 index 00000000..a17a9039 --- /dev/null +++ b/tests/Predis/Distribution/EmptyRingExceptionTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Distribution; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @todo Not really useful right now. + */ +class EmptyRingExceptionTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testExceptionMessage() + { + $message = 'Empty Ring'; + $this->setExpectedException('Predis\Distribution\EmptyRingException', $message); + + throw new EmptyRingException($message); + } +} diff --git a/tests/Predis/Distribution/HashRingTest.php b/tests/Predis/Distribution/HashRingTest.php new file mode 100644 index 00000000..0bda99b0 --- /dev/null +++ b/tests/Predis/Distribution/HashRingTest.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Distribution; + +/** + * @todo To be improved. + */ +class HashRingTest extends DistributionStrategyTestCase +{ + /** + * {@inheritdoc} + */ + public function getDistributorInstance() + { + return new HashRing(); + } + + /** + * @group disconnected + */ + public function testGenerateKey() + { + $ring = $this->getDistributorInstance(); + + $this->assertEquals(crc32('foobar'), $ring->generateKey('foobar')); + } + + /** + * @group disconnected + */ + public function testSingleNodeInRing() + { + $node = '127.0.0.1:7000'; + + $ring = $this->getDistributorInstance(); + $ring->add($node); + + $expected = array_fill(0, 20, $node); + $actual = $this->getNodes($ring, 20); + + $this->assertSame($expected, $actual); + } + + /** + * @group disconnected + */ + public function testMultipleNodesInRing() + { + $nodes = array( + '127.0.0.1:7000', + '127.0.0.1:7001', + '127.0.0.1:7002', + ); + + $ring = $this->getDistributorInstance(); + foreach ($nodes as $node) { + $ring->add($node); + } + + $expected = array( + '127.0.0.1:7001', + '127.0.0.1:7001', + '127.0.0.1:7001', + '127.0.0.1:7002', + '127.0.0.1:7002', + '127.0.0.1:7001', + '127.0.0.1:7001', + '127.0.0.1:7000', + '127.0.0.1:7001', + '127.0.0.1:7002', + '127.0.0.1:7002', + '127.0.0.1:7002', + '127.0.0.1:7002', + '127.0.0.1:7000', + '127.0.0.1:7002', + '127.0.0.1:7002', + '127.0.0.1:7002', + '127.0.0.1:7000', + '127.0.0.1:7001', + '127.0.0.1:7002', + ); + + $actual = $this->getNodes($ring, 20); + + $this->assertSame($expected, $actual); + } + + /** + * @group disconnected + */ + public function testSubsequendAddAndRemoveFromRing() + { + $ring = $this->getDistributorInstance(); + + $expected1 = array_fill(0, 10, '127.0.0.1:7000'); + $expected3 = array_fill(0, 10, '127.0.0.1:7001'); + $expected2 = array( + '127.0.0.1:7001', + '127.0.0.1:7001', + '127.0.0.1:7001', + '127.0.0.1:7001', + '127.0.0.1:7001', + '127.0.0.1:7001', + '127.0.0.1:7001', + '127.0.0.1:7000', + '127.0.0.1:7001', + '127.0.0.1:7000', + ); + + $ring->add('127.0.0.1:7000'); + $actual1 = $this->getNodes($ring, 10); + + $ring->add('127.0.0.1:7001'); + $actual2 = $this->getNodes($ring, 10); + + $ring->remove('127.0.0.1:7000'); + $actual3 = $this->getNodes($ring, 10); + + $this->assertSame($expected1, $actual1); + $this->assertSame($expected2, $actual2); + $this->assertSame($expected3, $actual3); + } +} diff --git a/tests/Predis/Distribution/KetamaPureRingTest.php b/tests/Predis/Distribution/KetamaPureRingTest.php new file mode 100644 index 00000000..8552a1b1 --- /dev/null +++ b/tests/Predis/Distribution/KetamaPureRingTest.php @@ -0,0 +1,133 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Distribution; + +/** + * @todo To be improved. + */ +class KetamaPureRingTest extends DistributionStrategyTestCase +{ + /** + * {@inheritdoc} + */ + public function getDistributorInstance() + { + return new KetamaPureRing(); + } + + /** + * @group disconnected + */ + public function testGenerateKey() + { + $ring = $this->getDistributorInstance(); + list(, $hash) = unpack('V', md5('foobar', true)); + + $this->assertEquals($hash, $ring->generateKey('foobar')); + } + + /** + * @group disconnected + */ + public function testSingleNodeInRing() + { + $node = '127.0.0.1:7000'; + + $ring = $this->getDistributorInstance(); + $ring->add($node); + + $expected = array_fill(0, 20, $node); + $actual = $this->getNodes($ring, 20); + + $this->assertSame($expected, $actual); + } + + /** + * @group disconnected + */ + public function testMultipleNodesInRing() + { + $nodes = array( + '127.0.0.1:7000', + '127.0.0.1:7001', + '127.0.0.1:7002', + ); + + $ring = $this->getDistributorInstance(); + foreach ($nodes as $node) { + $ring->add($node); + } + + $expected = array( + '127.0.0.1:7000', + '127.0.0.1:7001', + '127.0.0.1:7000', + '127.0.0.1:7002', + '127.0.0.1:7000', + '127.0.0.1:7001', + '127.0.0.1:7000', + '127.0.0.1:7001', + '127.0.0.1:7000', + '127.0.0.1:7002', + '127.0.0.1:7000', + '127.0.0.1:7000', + '127.0.0.1:7001', + '127.0.0.1:7000', + '127.0.0.1:7001', + '127.0.0.1:7002', + '127.0.0.1:7000', + '127.0.0.1:7002', + '127.0.0.1:7001', + '127.0.0.1:7002', + ); + + $actual = $this->getNodes($ring, 20); + + $this->assertSame($expected, $actual); + } + + /** + * @group disconnected + */ + public function testSubsequendAddAndRemoveFromRing() + { + $ring = $this->getDistributorInstance(); + + $expected1 = array_fill(0, 10, '127.0.0.1:7000'); + $expected3 = array_fill(0, 10, '127.0.0.1:7001'); + $expected2 = array( + '127.0.0.1:7000', + '127.0.0.1:7001', + '127.0.0.1:7000', + '127.0.0.1:7001', + '127.0.0.1:7000', + '127.0.0.1:7001', + '127.0.0.1:7000', + '127.0.0.1:7001', + '127.0.0.1:7000', + '127.0.0.1:7001', + ); + + $ring->add('127.0.0.1:7000'); + $actual1 = $this->getNodes($ring, 10); + + $ring->add('127.0.0.1:7001'); + $actual2 = $this->getNodes($ring, 10); + + $ring->remove('127.0.0.1:7000'); + $actual3 = $this->getNodes($ring, 10); + + $this->assertSame($expected1, $actual1); + $this->assertSame($expected2, $actual2); + $this->assertSame($expected3, $actual3); + } +} diff --git a/tests/Predis/HelpersTest.php b/tests/Predis/HelpersTest.php new file mode 100644 index 00000000..213f7646 --- /dev/null +++ b/tests/Predis/HelpersTest.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * + */ +class HelpersTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testConnectionIsCluster() + { + $single = $this->getMock('Predis\Network\IConnectionSingle'); + $cluster = $this->getMock('Predis\Network\IConnectionCluster'); + + $this->assertFalse(Helpers::isCluster($single)); + $this->assertTrue(Helpers::isCluster($cluster)); + } + + /** + * @group disconnected + */ + public function testOnCommunicationException() + { + $this->setExpectedException('Predis\CommunicationException'); + + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $connection->expects($this->once())->method('isConnected')->will($this->returnValue(true)); + $connection->expects($this->once())->method('disconnect'); + + $exception = $this->getMockForAbstractClass('Predis\CommunicationException', array($connection)); + + Helpers::onCommunicationException($exception); + } + + /** + * @group disconnected + */ + public function testFilterArrayArguments() + { + $arguments = array('arg1', 'arg2', 'arg3', 'arg4'); + + $this->assertSame($arguments, Helpers::filterArrayArguments($arguments)); + $this->assertSame($arguments, Helpers::filterArrayArguments(array($arguments))); + + $arguments = array(array(), array()); + $this->assertSame($arguments, Helpers::filterArrayArguments($arguments)); + + $arguments = array(new \stdClass()); + $this->assertSame($arguments, Helpers::filterArrayArguments($arguments)); + } + + /** + * @group disconnected + */ + public function testFilterVariadicValues() + { + $arguments = array('key', 'value1', 'value2', 'value3'); + + $this->assertSame($arguments, Helpers::filterVariadicValues($arguments)); + $this->assertSame($arguments, Helpers::filterVariadicValues(array('key', array('value1', 'value2', 'value3')))); + + $arguments = array(array(), array()); + $this->assertSame($arguments, Helpers::filterArrayArguments($arguments)); + + $arguments = array(new \stdClass()); + $this->assertSame($arguments, Helpers::filterArrayArguments($arguments)); + } + + /** + * @group disconnected + */ + public function testExtractKeyTag() + { + $this->assertEquals('foo:bar', Helpers::extractKeyTag('foo:bar')); + $this->assertEquals('foo:', Helpers::extractKeyTag('{foo:}bar')); + $this->assertEquals('bar', Helpers::extractKeyTag('foo:{bar}')); + $this->assertEquals('foo:bar', Helpers::extractKeyTag('{foo:bar}')); + $this->assertEquals('', Helpers::extractKeyTag('foo{}:bar')); + $this->assertEquals('', Helpers::extractKeyTag('')); + $this->assertEquals('', Helpers::extractKeyTag('{}')); + } +} diff --git a/tests/Predis/Iterators/MultiBulkResponseSimpleTest.php b/tests/Predis/Iterators/MultiBulkResponseSimpleTest.php new file mode 100644 index 00000000..ac9de50d --- /dev/null +++ b/tests/Predis/Iterators/MultiBulkResponseSimpleTest.php @@ -0,0 +1,123 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Iterators; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +use Predis\Client; + +/** + * @group realm-iterators + */ +class MultiBulkResponseSimpleTest extends StandardTestCase +{ + /** + * @group connected + */ + public function testIterableMultibulk() + { + $client = $this->getClient(); + $client->rpush('metavars', 'foo', 'hoge', 'lol'); + + $this->assertInstanceOf('Iterator', $iterator = $client->lrange('metavars', 0, -1)); + $this->assertInstanceOf('Predis\Iterators\MultiBulkResponseSimple', $iterator); + $this->assertTrue($iterator->valid()); + $this->assertSame(3, $iterator->count()); + + $this->assertSame('foo', $iterator->current()); + $this->assertSame(1, $iterator->next()); + $this->assertTrue($iterator->valid()); + + $this->assertSame('hoge', $iterator->current()); + $this->assertSame(2, $iterator->next()); + $this->assertTrue($iterator->valid()); + + $this->assertSame('lol', $iterator->current()); + $this->assertSame(3, $iterator->next()); + $this->assertFalse($iterator->valid()); + + $this->assertTrue($client->ping()); + } + + /** + * @group connected + */ + public function testSyncWithFalseConsumesReplyFromUnderlyingConnection() + { + $client = $this->getClient(); + $client->rpush('metavars', 'foo', 'hoge', 'lol'); + + $iterator = $client->lrange('metavars', 0, -1); + $iterator->sync(false); + + $this->assertTrue($client->isConnected()); + $this->assertTrue($client->ping()); + } + + /** + * @group connected + */ + public function testSyncWithTrueDropsUnderlyingConnection() + { + $client = $this->getClient(); + $client->rpush('metavars', 'foo', 'hoge', 'lol'); + + $iterator = $client->lrange('metavars', 0, -1); + $iterator->sync(true); + + $this->assertFalse($client->isConnected()); + $this->assertTrue($client->ping()); + } + + /** + * @group connected + */ + public function testGarbageCollectorDropsUnderlyingConnection() + { + $client = $this->getClient(); + $client->rpush('metavars', 'foo', 'hoge', 'lol'); + + $iterator = $client->lrange('metavars', 0, -1); + + unset($iterator); + + $this->assertFalse($client->isConnected()); + $this->assertTrue($client->ping()); + } + + // ******************************************************************** // + // ---- HELPER METHODS ------------------------------------------------ // + // ******************************************************************** // + + /** + * Returns a new client instance. + * + * @return Client + */ + protected function getClient() + { + $parameters = array( + 'host' => REDIS_SERVER_HOST, + 'port' => REDIS_SERVER_PORT, + 'iterable_multibulk' => true, + 'read_write_timeout' => 2, + ); + + $client = new Client($parameters, REDIS_SERVER_VERSION); + $client->connect(); + $client->select(REDIS_SERVER_DBNUM); + $client->flushdb(); + + return $client; + } + +} diff --git a/tests/Predis/Iterators/MultiBulkResponseTupleTest.php b/tests/Predis/Iterators/MultiBulkResponseTupleTest.php new file mode 100644 index 00000000..7c01518b --- /dev/null +++ b/tests/Predis/Iterators/MultiBulkResponseTupleTest.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Iterators; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +use Predis\Client; + +/** + * @group realm-iterators + */ +class MultiBulkResponseTupleTest extends StandardTestCase +{ + /** + * @group connected + */ + public function testIterableMultibulk() + { + $client = $this->getClient(); + $client->zadd('metavars', 1, 'foo', 2, 'hoge', 3, 'lol'); + + $this->assertInstanceOf('OuterIterator', $iterator = $client->zrange('metavars', 0, -1, 'withscores')); + $this->assertInstanceOf('Predis\Iterators\MultiBulkResponseTuple', $iterator); + $this->assertInstanceOf('Predis\Iterators\MultiBulkResponseSimple', $iterator->getInnerIterator()); + $this->assertTrue($iterator->valid()); + $this->assertSame(3, $iterator->count()); + + $this->assertSame(array('foo', '1'), $iterator->current()); + $this->assertSame(1, $iterator->next()); + $this->assertTrue($iterator->valid()); + + $this->assertSame(array('hoge', '2'), $iterator->current()); + $this->assertSame(2, $iterator->next()); + $this->assertTrue($iterator->valid()); + + $this->assertSame(array('lol', '3'), $iterator->current()); + $this->assertSame(3, $iterator->next()); + $this->assertFalse($iterator->valid()); + + $this->assertTrue($client->ping()); + } + + /** + * @group connected + */ + public function testGarbageCollectorDropsUnderlyingConnection() + { + $client = $this->getClient(); + $client->zadd('metavars', 1, 'foo', 2, 'hoge', 3, 'lol'); + + $iterator = $client->zrange('metavars', 0, -1, 'withscores'); + + unset($iterator); + + $this->assertFalse($client->isConnected()); + $this->assertTrue($client->ping()); + } + + // ******************************************************************** // + // ---- HELPER METHODS ------------------------------------------------ // + // ******************************************************************** // + + /** + * Returns a new client instance. + * + * @return Client + */ + protected function getClient() + { + $parameters = array( + 'host' => REDIS_SERVER_HOST, + 'port' => REDIS_SERVER_PORT, + 'iterable_multibulk' => true, + 'read_write_timeout' => 2, + ); + + $client = new Client($parameters, REDIS_SERVER_VERSION); + $client->connect(); + $client->select(REDIS_SERVER_DBNUM); + $client->flushdb(); + + return $client; + } + +} diff --git a/tests/Predis/MonitorContextTest.php b/tests/Predis/MonitorContextTest.php new file mode 100644 index 00000000..2e72c577 --- /dev/null +++ b/tests/Predis/MonitorContextTest.php @@ -0,0 +1,171 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +use Predis\Profiles\ServerProfile; + +/** + * @group realm-monitor + */ +class MonitorContextTest extends StandardTestCase +{ + /** + * @group disconnected + * @expectedException Predis\NotSupportedException + * @expectedExceptionMessage The current profile does not support the MONITOR command + */ + public function testMonitorContextRequireMonitorCommand() + { + $profile = $this->getMock('Predis\Profiles\IServerProfile'); + $profile->expects($this->once()) + ->method('supportsCommand') + ->with('monitor') + ->will($this->returnValue(false)); + + $client = new Client(null, array('profile' => $profile)); + $monitor = new MonitorContext($client); + } + + /** + * @group disconnected + * @expectedException Predis\NotSupportedException + * @expectedExceptionMessage Cannot initialize a monitor context over a cluster of connections + */ + public function testMonitorContextDoesNotWorkOnClusters() + { + $cluster = $this->getMock('Predis\Network\IConnectionCluster'); + + $client = new Client($cluster); + $monitor = new MonitorContext($client); + } + + /** + * @group disconnected + */ + public function testConstructorOpensContext() + { + $cmdMonitor = ServerProfile::getDefault()->createCommand('monitor'); + + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + + $client = $this->getMock('Predis\Client', array('createCommand', 'executeCommand'), array($connection)); + $client->expects($this->once()) + ->method('createCommand') + ->with('monitor', array()) + ->will($this->returnValue($cmdMonitor)); + $client->expects($this->once()) + ->method('executeCommand') + ->with($cmdMonitor); + + $monitor = new MonitorContext($client); + } + + /** + * @group disconnected + * @todo We should investigate why disconnect is invoked 2 times in this test, + * but the reason is probably that the GC invokes __destruct() on monitor + * thus calling $client->disconnect() a second time at the end of the test. + */ + public function testClosingContextClosesConnection() + { + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + + $client = $this->getMock('Predis\Client', array('disconnect'), array($connection)); + $client->expects($this->exactly(2))->method('disconnect'); + + $monitor = new MonitorContext($client); + $monitor->closeContext(); + } + + /** + * @group disconnected + */ + public function testGarbageCollectorRunClosesContext() + { + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + + $client = $this->getMock('Predis\Client', array('disconnect'), array($connection)); + $client->expects($this->once())->method('disconnect'); + + $monitor = new MonitorContext($client); + unset($monitor); + } + + /** + * @group disconnected + */ + public function testCurrentReadsMessageFromConnection() + { + $message = '1323367530.939137 (db 15) "MONITOR"'; + + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $connection->expects($this->once()) + ->method('read') + ->will($this->returnValue($message)); + + $client = new Client($connection); + $monitor = new MonitorContext($client); + + $payload = $monitor->current(); + $this->assertSame(1323367530, (int) $payload->timestamp); + $this->assertSame(15, $payload->database); + $this->assertSame('MONITOR', $payload->command); + $this->assertNull($payload->arguments); + } + + // ******************************************************************** // + // ---- INTEGRATION TESTS --------------------------------------------- // + // ******************************************************************** // + + /** + * @group connected + */ + public function testMonitorAgainstRedisServer() + { + $parameters = array( + 'host' => REDIS_SERVER_HOST, + 'port' => REDIS_SERVER_PORT, + 'database' => REDIS_SERVER_DBNUM, + // Prevents suite from handing on broken test + 'read_write_timeout' => 2, + ); + + $echoed = array(); + + $producer = new Client($parameters, REDIS_SERVER_VERSION); + $producer->connect(); + + $consumer = new Client($parameters, REDIS_SERVER_VERSION); + $consumer->connect(); + + $monitor = new MonitorContext($consumer); + + $producer->echo('message1'); + $producer->echo('message2'); + $producer->echo('QUIT'); + + foreach ($monitor as $message) { + if ($message->command == 'ECHO') { + $echoed[] = $arguments = trim($message->arguments, '"'); + if ($arguments == 'QUIT') { + $monitor->closeContext(); + } + } + } + + $this->assertSame(array('message1', 'message2', 'QUIT'), $echoed); + $this->assertFalse($monitor->valid()); + $this->assertTrue($consumer->ping()); + } +} diff --git a/tests/Predis/Network/ConnectionExceptionTest.php b/tests/Predis/Network/ConnectionExceptionTest.php new file mode 100644 index 00000000..18ae3e06 --- /dev/null +++ b/tests/Predis/Network/ConnectionExceptionTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Network; + +require_once __DIR__.'/../CommunicationExceptionTest.php'; + +use Predis\CommunicationExceptionTest; +use Predis\Network\IConnectionSingle; + +/** + * + */ +class ConnectionExceptionTest extends CommunicationExceptionTest +{ + /** + * {@inheritdoc} + */ + protected function getException(IConnectionSingle $connection, $message, $code = 0, \Exception $inner = null) + { + return new ConnectionException($connection, $message, $code, $inner); + } +} diff --git a/tests/Predis/Network/PhpiredisConnectionTest.php b/tests/Predis/Network/PhpiredisConnectionTest.php new file mode 100644 index 00000000..4999a402 --- /dev/null +++ b/tests/Predis/Network/PhpiredisConnectionTest.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Network; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +use Predis\ConnectionParameters; +use Predis\Profiles\ServerProfile; + +/** + * @group ext-phpiredis + */ +class PhpiredisConnectionTest extends ConnectionTestCase +{ + /** + * @group disconnected + */ + public function testConstructorDoesNotOpenConnection() + { + $connection = new PhpiredisConnection($this->getParameters()); + + $this->assertFalse($connection->isConnected()); + } + + /** + * @group disconnected + */ + public function testExposesConnectionParameters() + { + $parameters = $this->getParameters(); + $connection = new PhpiredisConnection($parameters); + + $this->assertSame($parameters, $connection->getParameters()); + } + + /** + * @group disconnected + * @expectedException InvalidArgumentException + * @expectedExceptionMessage Invalid scheme: udp + */ + public function testThrowsExceptionOnInvalidScheme() + { + $parameters = $this->getParameters(array('scheme' => 'udp')); + $connection = new PhpiredisConnection($parameters); + } + + // ******************************************************************** // + // ---- INTEGRATION TESTS --------------------------------------------- // + // ******************************************************************** // + + /** + * @group connected + */ + public function testExecutesCommandsOnServer() + { + $connection = $this->getConnection($profile, true); + + $cmdPing = $profile->createCommand('ping'); + $cmdEcho = $profile->createCommand('echo', array('echoed')); + $cmdGet = $profile->createCommand('get', array('foobar')); + $cmdRpush = $profile->createCommand('rpush', array('metavars', 'foo', 'hoge', 'lol')); + $cmdLrange = $profile->createCommand('lrange', array('metavars', 0, -1)); + + $this->assertTrue($connection->executeCommand($cmdPing)); + $this->assertSame('echoed', $connection->executeCommand($cmdEcho)); + $this->assertNull($connection->executeCommand($cmdGet)); + $this->assertSame(3, $connection->executeCommand($cmdRpush)); + $this->assertSame(array('foo', 'hoge', 'lol'), $connection->executeCommand($cmdLrange)); + } + + /** + * @group connected + * @expectedException Predis\Protocol\ProtocolException + * @expectedExceptionMessage Protocol error, got "P" as reply type byte + */ + public function testThrowsExceptionOnProtocolDesynchronizationErrors() + { + $connection = $this->getConnection($profile); + $socket = $connection->getResource(); + + $connection->writeCommand($profile->createCommand('ping')); + socket_read($socket, 1); + + $connection->read(); + } + + // ******************************************************************** // + // ---- HELPER METHODS ------------------------------------------------ // + // ******************************************************************** // + + /** + * {@inheritdoc} + */ + protected function getConnection(&$profile = null, $initialize = false, Array $parameters = array()) + { + $parameters = $this->getParameters($parameters); + $profile = $this->getProfile(); + + $connection = new PhpiredisConnection($parameters); + + if ($initialize) { + $connection->pushInitCommand($profile->createCommand('select', array($parameters->database))); + $connection->pushInitCommand($profile->createCommand('flushdb')); + } + + return $connection; + } +} diff --git a/tests/Predis/Network/PredisClusterTest.php b/tests/Predis/Network/PredisClusterTest.php new file mode 100644 index 00000000..2fefa12b --- /dev/null +++ b/tests/Predis/Network/PredisClusterTest.php @@ -0,0 +1,311 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Network; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +use Predis\ConnectionParameters; +use Predis\Profiles\ServerProfile; + +/** + * + */ +class PredisClusterTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testAddingConnectionsToCluster() + { + $connection1 = $this->getMockConnection(); + $connection2 = $this->getMockConnection(); + + $cluster = new PredisCluster(); + $cluster->add($connection1); + $cluster->add($connection2); + + $this->assertSame($connection1, $cluster->getConnectionById(0)); + $this->assertSame($connection2, $cluster->getConnectionById(1)); + } + + /** + * @group disconnected + */ + public function testAddingConnectionsToClusterUsesConnectionAlias() + { + $connection1 = $this->getMockConnection('tcp://host1:7001?alias=node1'); + $connection2 = $this->getMockConnection('tcp://host1:7002?alias=node2'); + + $cluster = new PredisCluster(); + $cluster->add($connection1); + $cluster->add($connection2); + + $this->assertSame($connection1, $cluster->getConnectionById('node1')); + $this->assertSame($connection2, $cluster->getConnectionById('node2')); + } + + /** + * @group disconnected + */ + public function testConnectForcesAllConnectionsToConnect() + { + $connection1 = $this->getMockConnection(); + $connection1->expects($this->once())->method('connect'); + + $connection2 = $this->getMockConnection(); + $connection2->expects($this->once())->method('connect'); + + $cluster = new PredisCluster(); + $cluster->add($connection1); + $cluster->add($connection2); + + $cluster->connect(); + } + + /** + * @group disconnected + */ + public function testDisconnectForcesAllConnectionsToDisconnect() + { + $connection1 = $this->getMockConnection(); + $connection1->expects($this->once())->method('disconnect'); + + $connection2 = $this->getMockConnection(); + $connection2->expects($this->once())->method('disconnect'); + + $cluster = new PredisCluster(); + $cluster->add($connection1); + $cluster->add($connection2); + + $cluster->disconnect(); + } + + /** + * @group disconnected + */ + public function testIsConnectedReturnsTrueIfAtLeastOneConnectionIsOpen() + { + $connection1 = $this->getMockConnection(); + $connection1->expects($this->once()) + ->method('isConnected') + ->will($this->returnValue(false)); + + $connection2 = $this->getMockConnection(); + $connection2->expects($this->once()) + ->method('isConnected') + ->will($this->returnValue(true)); + + $cluster = new PredisCluster(); + $cluster->add($connection1); + $cluster->add($connection2); + + $this->assertTrue($cluster->isConnected()); + } + + /** + * @group disconnected + */ + public function testIsConnectedReturnsFalseIfAllConnectionsAreClosed() + { + $connection1 = $this->getMockConnection(); + $connection1->expects($this->once()) + ->method('isConnected') + ->will($this->returnValue(false)); + + $connection2 = $this->getMockConnection(); + $connection2->expects($this->once()) + ->method('isConnected') + ->will($this->returnValue(false)); + + $cluster = new PredisCluster(); + $cluster->add($connection1); + $cluster->add($connection2); + + $this->assertFalse($cluster->isConnected()); + } + + /** + * @group disconnected + */ + public function testCanReturnAnIteratorForConnections() + { + $connection1 = $this->getMockConnection(); + $connection2 = $this->getMockConnection(); + + $cluster = new PredisCluster(); + $cluster->add($connection1); + $cluster->add($connection2); + + $this->assertInstanceOf('Iterator', $iterator = $cluster->getIterator()); + $connections = iterator_to_array($iterator); + + $this->assertSame($connection1, $connections[0]); + $this->assertSame($connection2, $connections[1]); + } + + /** + * @group disconnected + */ + public function testReturnsCorrectConnectionUsingKey() + { + $connection1 = $this->getMockConnection('tcp://host1:7001'); + $connection2 = $this->getMockConnection('tcp://host1:7002'); + + $cluster = new PredisCluster(); + $cluster->add($connection1); + $cluster->add($connection2); + + $this->assertSame($connection1, $cluster->getConnectionByKey('node01:5431')); + $this->assertSame($connection2, $cluster->getConnectionByKey('node02:3212')); + $this->assertSame($connection1, $cluster->getConnectionByKey('prefix:{node01:5431}')); + $this->assertSame($connection2, $cluster->getConnectionByKey('prefix:{node02:3212}')); + } + + /** + * @group disconnected + */ + public function testReturnsCorrectConnectionUsingCommandInstance() + { + $profile = ServerProfile::getDefault(); + + $connection1 = $this->getMockConnection('tcp://host1:7001'); + $connection2 = $this->getMockConnection('tcp://host1:7002'); + + $cluster = new PredisCluster(); + $cluster->add($connection1); + $cluster->add($connection2); + + $set = $profile->createCommand('set', array('node01:5431', 'foobar')); + $get = $profile->createCommand('get', array('node01:5431')); + $this->assertSame($connection1, $cluster->getConnection($set)); + $this->assertSame($connection1, $cluster->getConnection($get)); + + $set = $profile->createCommand('set', array('prefix:{node01:5431}', 'foobar')); + $get = $profile->createCommand('get', array('prefix:{node01:5431}')); + $this->assertSame($connection1, $cluster->getConnection($set)); + $this->assertSame($connection1, $cluster->getConnection($get)); + + $set = $profile->createCommand('set', array('node02:3212', 'foobar')); + $get = $profile->createCommand('get', array('node02:3212')); + $this->assertSame($connection2, $cluster->getConnection($set)); + $this->assertSame($connection2, $cluster->getConnection($get)); + + $set = $profile->createCommand('set', array('prefix:{node02:3212}', 'foobar')); + $get = $profile->createCommand('get', array('prefix:{node02:3212}')); + $this->assertSame($connection2, $cluster->getConnection($set)); + $this->assertSame($connection2, $cluster->getConnection($get)); + } + + /** + * @group disconnected + * @expectedException Predis\NotSupportedException + * @expectedExceptionMessage Cannot send 'PING' commands to a cluster of connections + */ + public function testThrowsExceptionOnNonShardableCommand() + { + $ping = ServerProfile::getDefault()->createCommand('ping'); + + $cluster = new PredisCluster(); + $cluster->add($this->getMockConnection()); + + $cluster->getConnection($ping); + } + + /** + * @group disconnected + */ + public function testWritesCommandToCorrectConnection() + { + $command = ServerProfile::getDefault()->createCommand('get', array('node01:5431')); + + $connection1 = $this->getMockConnection('tcp://host1:7001'); + $connection1->expects($this->once())->method('writeCommand')->with($command); + + $connection2 = $this->getMockConnection('tcp://host1:7002'); + $connection2->expects($this->never())->method('writeCommand'); + + $cluster = new PredisCluster(); + $cluster->add($connection1); + $cluster->add($connection2); + + $cluster->writeCommand($command); + } + + /** + * @group disconnected + */ + public function testReadsCommandFromCorrectConnection() + { + $command = ServerProfile::getDefault()->createCommand('get', array('node02:3212')); + + $connection1 = $this->getMockConnection('tcp://host1:7001'); + $connection1->expects($this->never())->method('readResponse'); + + $connection2 = $this->getMockConnection('tcp://host1:7002'); + $connection2->expects($this->once())->method('readResponse')->with($command); + + $cluster = new PredisCluster(); + $cluster->add($connection1); + $cluster->add($connection2); + + $cluster->readResponse($command); + } + + /** + * @group disconnected + */ + public function testExecutesCommandOnCorrectConnection() + { + $command = ServerProfile::getDefault()->createCommand('get', array('node01:5431')); + + $connection1 = $this->getMockConnection('tcp://host1:7001'); + $connection1->expects($this->once())->method('executeCommand')->with($command); + + $connection2 = $this->getMockConnection('tcp://host1:7002'); + $connection2->expects($this->never())->method('executeCommand'); + + $cluster = new PredisCluster(); + $cluster->add($connection1); + $cluster->add($connection2); + + $cluster->executeCommand($command); + } + + // ******************************************************************** // + // ---- HELPER METHODS ------------------------------------------------ // + // ******************************************************************** // + + /** + * Returns a base mocked connection from Predis\Network\IConnectionSingle. + * + * @param mixed $parameters Optional parameters. + * @return mixed + */ + protected function getMockConnection($parameters = null) + { + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + + if ($parameters) { + $parameters = new ConnectionParameters($parameters); + $hash = "{$parameters->host}:{$parameters->port}"; + + $connection->expects($this->any()) + ->method('getParameters') + ->will($this->returnValue($parameters)); + $connection->expects($this->any()) + ->method('__toString') + ->will($this->returnValue($hash)); + } + + return $connection; + } +} diff --git a/tests/Predis/Network/StreamConnectionTest.php b/tests/Predis/Network/StreamConnectionTest.php new file mode 100644 index 00000000..f0ca7975 --- /dev/null +++ b/tests/Predis/Network/StreamConnectionTest.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Network; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +use Predis\ConnectionParameters; +use Predis\Profiles\ServerProfile; + +/** + * + */ +class StreamConnectionTest extends ConnectionTestCase +{ + /** + * @group disconnected + */ + public function testConstructorDoesNotOpenConnection() + { + $connection = new StreamConnection($this->getParameters()); + + $this->assertFalse($connection->isConnected()); + } + + /** + * @group disconnected + */ + public function testExposesConnectionParameters() + { + $parameters = $this->getParameters(); + $connection = new StreamConnection($parameters); + + $this->assertSame($parameters, $connection->getParameters()); + } + + /** + * @group disconnected + * @expectedException InvalidArgumentException + * @expectedExceptionMessage Invalid scheme: udp + */ + public function testThrowsExceptionOnInvalidScheme() + { + $parameters = $this->getParameters(array('scheme' => 'udp')); + $connection = new StreamConnection($parameters); + } + + // ******************************************************************** // + // ---- INTEGRATION TESTS --------------------------------------------- // + // ******************************************************************** // + + /** + * @group connected + */ + public function testReadsMultibulkRepliesAsIterators() + { + $connection = $this->getConnection($profile, true, array('iterable_multibulk' => true)); + + $connection->executeCommand($profile->createCommand('rpush', array('metavars', 'foo', 'hoge', 'lol'))); + $connection->writeCommand($profile->createCommand('lrange', array('metavars', 0, -1))); + + $this->assertInstanceOf('Predis\Iterators\MultiBulkResponse', $iterator = $connection->read()); + $this->assertSame(array('foo', 'hoge', 'lol'), iterator_to_array($iterator)); + } + + /** + * @group connected + * @expectedException Predis\Protocol\ProtocolException + * @expectedExceptionMessage Unknown prefix: 'P' + */ + public function testThrowsExceptionOnProtocolDesynchronizationErrors() + { + $connection = $this->getConnection($profile); + $stream = $connection->getResource(); + + $connection->writeCommand($profile->createCommand('ping')); + fread($stream, 1); + + $connection->read(); + } + + // ******************************************************************** // + // ---- HELPER METHODS ------------------------------------------------ // + // ******************************************************************** // + + /** + * {@inheritdoc} + */ + protected function getConnection(&$profile = null, $initialize = false, Array $parameters = array()) + { + $parameters = $this->getParameters($parameters); + $profile = $this->getProfile(); + + $connection = new StreamConnection($parameters); + + if ($initialize) { + $connection->pushInitCommand($profile->createCommand('select', array($parameters->database))); + $connection->pushInitCommand($profile->createCommand('flushdb')); + } + + return $connection; + } +} diff --git a/tests/Predis/Network/WebdisConnectionTest.php b/tests/Predis/Network/WebdisConnectionTest.php new file mode 100644 index 00000000..901eaf8a --- /dev/null +++ b/tests/Predis/Network/WebdisConnectionTest.php @@ -0,0 +1,198 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Network; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +use Predis\ConnectionParameters; +use Predis\Profiles\ServerProfile; + +/** + * @group realm-network + * @group ext-curl + * @group ext-phpiredis + * @group realm-network-webdis + */ +class WebdisConnectionTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testIsConnectedAlwaysReturnsTrue() + { + $connection = new WebdisConnection($this->getParameters()); + + $this->assertTrue($connection->isConnected()); + } + + /** + * @group disconnected + * @expectedException Predis\NotSupportedException + * @expectedExceptionMessage The method Predis\Network\WebdisConnection::writeCommand() is not supported + */ + public function testWritingCommandsIsNotSupported() + { + $connection = new WebdisConnection($this->getParameters()); + $connection->writeCommand($this->getProfile()->createCommand('ping')); + } + + /** + * @group disconnected + * @expectedException Predis\NotSupportedException + * @expectedExceptionMessage The method Predis\Network\WebdisConnection::readResponse() is not supported + */ + public function testReadingResponsesIsNotSupported() + { + $connection = new WebdisConnection($this->getParameters()); + $connection->readResponse($this->getProfile()->createCommand('ping')); + } + + /** + * @group disconnected + * @expectedException Predis\NotSupportedException + * @expectedExceptionMessage The method Predis\Network\WebdisConnection::read() is not supported + */ + public function testReadingFromConnectionIsNotSupported() + { + $connection = new WebdisConnection($this->getParameters()); + $connection->read(); + } + + /** + * @group disconnected + * @expectedException Predis\NotSupportedException + * @expectedExceptionMessage The method Predis\Network\WebdisConnection::pushInitCommand() is not supported + */ + public function testPushingInitCommandsIsNotSupported() + { + $connection = new WebdisConnection($this->getParameters()); + $connection->pushInitCommand($this->getProfile()->createCommand('ping')); + } + + /** + * @group disconnected + * @expectedException Predis\NotSupportedException + * @expectedExceptionMessage Disabled command: SELECT + */ + public function testRejectCommandSelect() + { + $connection = new WebdisConnection($this->getParameters()); + $connection->executeCommand($this->getProfile()->createCommand('select', array(0))); + } + + /** + * @group disconnected + * @expectedException Predis\NotSupportedException + * @expectedExceptionMessage Disabled command: AUTH + */ + public function testRejectCommandAuth() + { + $connection = new WebdisConnection($this->getParameters()); + $connection->executeCommand($this->getProfile()->createCommand('auth', array('foobar'))); + } + + // ******************************************************************** // + // ---- INTEGRATION TESTS --------------------------------------------- // + // ******************************************************************** // + + /** + * @group connected + */ + public function testExecutesCommandsOnServer() + { + $connection = $this->getConnection($profile); + + $cmdPing = $profile->createCommand('ping'); + $cmdEcho = $profile->createCommand('echo', array('echoed')); + $cmdGet = $profile->createCommand('get', array('foobar')); + $cmdRpush = $profile->createCommand('rpush', array('metavars', 'foo', 'hoge', 'lol')); + $cmdLrange = $profile->createCommand('lrange', array('metavars', 0, -1)); + + $this->assertTrue($connection->executeCommand($cmdPing)); + $this->assertSame('echoed', $connection->executeCommand($cmdEcho)); + $this->assertNull($connection->executeCommand($cmdGet)); + $this->assertSame(3, $connection->executeCommand($cmdRpush)); + $this->assertSame(array('foo', 'hoge', 'lol'), $connection->executeCommand($cmdLrange)); + } + + /** + * @group disconnected + * @group slow + * @expectedException Predis\Network\ConnectionException + */ + public function testThrowExceptionWhenUnableToConnect() + { + $parameters = $this->getParameters(array('host' => '169.254.10.10')); + $connection = new WebdisConnection($parameters); + $connection->executeCommand($this->getProfile()->createCommand('ping')); + } + + // ******************************************************************** // + // ---- HELPER METHODS ------------------------------------------------ // + // ******************************************************************** // + + /** + * Returns a named array with the default connection parameters and their values. + * + * @return Array Default connection parameters. + */ + protected function getDefaultParametersArray() + { + return array( + 'scheme' => 'http', + 'host' => WEBDIS_SERVER_HOST, + 'port' => WEBDIS_SERVER_PORT, + ); + } + + /** + * Returns a new instance of connection parameters. + * + * @param array $additional Additional connection parameters. + * @return ConnectionParameters Default connection parameters. + */ + protected function getParameters($additional = array()) + { + $parameters = array_merge($this->getDefaultParametersArray(), $additional); + $parameters = new ConnectionParameters($parameters); + + return $parameters; + } + + /** + * Returns a new instance of server profile. + * + * @param array $additional Additional connection parameters. + * @return ServerProfile + */ + protected function getProfile($version = null) + { + return ServerProfile::get($version ?: REDIS_SERVER_VERSION); + } + + /** + * Returns a new instance of a connection instance. + * + * @param array $parameters Additional connection parameters. + * @return WebdisConnection + */ + protected function getConnection(&$profile = null, Array $parameters = array()) + { + $parameters = $this->getParameters($parameters); + $profile = $this->getProfile(); + + $connection = new WebdisConnection($parameters); + $connection->executeCommand($profile->createCommand('flushdb')); + + return $connection; + } +} diff --git a/tests/Predis/Options/ClientClusterTest.php b/tests/Predis/Options/ClientClusterTest.php new file mode 100644 index 00000000..2cfe88db --- /dev/null +++ b/tests/Predis/Options/ClientClusterTest.php @@ -0,0 +1,125 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Options; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * + */ +class ClientClusterTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testValidationAcceptsFQNStringAsInitializer() + { + $clusterClass = get_class($this->getMock('Predis\Network\IConnectionCluster')); + + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new ClientCluster(); + + $cluster = $option->validate($options, $clusterClass); + + $this->assertInstanceOf('Predis\Network\IConnectionCluster', $cluster); + } + + /** + * @group disconnected + */ + public function testValidationRecognizesCertainPredefinedShortNames() + { + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new ClientCluster(); + + $cluster = $option->validate($options, 'predis'); + + $this->assertInstanceOf('Predis\Network\IConnectionCluster', $cluster); + } + + /** + * @group disconnected + */ + public function testValidationAcceptsCallableObjectAsInitializers() + { + $value = $this->getMock('Predis\Network\IConnectionCluster'); + + $initializer = $this->getMock('stdClass', array('__invoke')); + $initializer->expects($this->once()) + ->method('__invoke') + ->with($this->isInstanceOf('Predis\Options\IClientOptions')) + ->will($this->returnValue($value)); + + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new ClientCluster(); + + $cluster = $option->validate($options, $initializer); + + $this->assertInstanceOf('Predis\Network\IConnectionCluster', $cluster); + $this->assertSame($value, $cluster); + } + + /** + * @group disconnected + */ + public function testValidationThrowsExceptionOnInvalidClassTypes() + { + $this->setExpectedException('InvalidArgumentException'); + + $connectionClass = get_class($this->getMock('Predis\Network\IConnectionSingle')); + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new ClientCluster(); + + $option->validate($options, $connectionClass); + } + + /** + * @group disconnected + */ + public function testValidationThrowsExceptionOnInvalidShortName() + { + $this->setExpectedException('InvalidArgumentException'); + + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new ClientCluster(); + + $option->validate($options, 'unknown'); + } + + /** + * @group disconnected + */ + public function testValidationThrowsExceptionOnInvalidObjectReturnedByCallback() + { + $this->setExpectedException('InvalidArgumentException'); + + $value = function($options) { return new \stdClass(); }; + + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new ClientCluster(); + + $option->validate($options, $value); + } + + /** + * @group disconnected + */ + public function testValidationThrowsExceptionOnInvalidArguments() + { + $this->setExpectedException('InvalidArgumentException'); + + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new ClientCluster(); + + $option->validate($options, new \stdClass()); + } +} diff --git a/tests/Predis/Options/ClientConnectionFactoryTest.php b/tests/Predis/Options/ClientConnectionFactoryTest.php new file mode 100644 index 00000000..9f4d33ba --- /dev/null +++ b/tests/Predis/Options/ClientConnectionFactoryTest.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Options; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +use Predis\ConnectionFactory; + +/** + * + */ +class ClientConnectionFactoryTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testValidationReturnsDefaultFactoryWithSchemeDefinitionsArray() + { + $connectionClass = get_class($this->getMock('Predis\Network\IConnectionSingle')); + $value = array('tcp' => $connectionClass, 'redis' => $connectionClass); + + $options = $this->getMock('Predis\Options\IClientOptions'); + + $default = $this->getMock('Predis\IConnectionFactory'); + $default->expects($this->exactly(2)) + ->method('define') + ->with($this->matchesRegularExpression('/^tcp|redis$/'), $connectionClass); + + $option = $this->getMock('Predis\Options\ClientConnectionFactory', array('getDefault')); + $option->expects($this->once()) + ->method('getDefault') + ->with($options) + ->will($this->returnValue($default)); + + $factory = $option->validate($options, $value); + + $this->assertInstanceOf('Predis\IConnectionFactory', $factory); + $this->assertSame($default, $factory); + } + + /** + * @group disconnected + */ + public function testValidationAcceptsFactoryInstancesAsValue() + { + $value = $this->getMock('Predis\IConnectionFactory'); + $options = $this->getMock('Predis\Options\IClientOptions'); + + $option = $this->getMock('Predis\Options\ClientConnectionFactory', array('getDefault')); + $option->expects($this->never())->method('getDefault'); + + $this->assertSame($value, $option->validate($options, $value)); + } + + /** + * @group disconnected + */ + public function testValidationAcceptsStringAsValue() + { + $factory = 'Predis\ConnectionFactory'; + $options = $this->getMock('Predis\Options\IClientOptions'); + + $option = $this->getMock('Predis\Options\ClientConnectionFactory', array('getDefault')); + $option->expects($this->never())->method('getDefault'); + + $this->assertInstanceOf($factory, $option->validate($options, $factory)); + } + + /** + * @group disconnected + */ + public function testValidationThrowsExceptionOnWrongInvalidArguments() + { + $this->setExpectedException('InvalidArgumentException'); + + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new ClientConnectionFactory(); + + $option->validate($options, new \stdClass()); + } + + /** + * @group disconnected + */ + public function testInvokeReturnsSpecifiedFactoryOrDefault() + { + $value = $this->getMock('Predis\IConnectionFactory'); + $options = $this->getMock('Predis\Options\IClientOptions'); + + $option = $this->getMock('Predis\Options\ClientConnectionFactory', array('validate', 'getDefault')); + $option->expects($this->once()) + ->method('validate') + ->with($options, $value) + ->will($this->returnValue($value)); + $option->expects($this->never())->method('getDefault'); + + $this->assertInstanceOf('Predis\IConnectionFactory', $option($options, $value)); + + $option = $this->getMock('Predis\Options\ClientConnectionFactory', array('validate', 'getDefault')); + $option->expects($this->never())->method('validate'); + $option->expects($this->once()) + ->method('getDefault') + ->with($options) + ->will($this->returnValue($value)); + + $this->assertInstanceOf('Predis\IConnectionFactory', $option($options, null)); + } +} diff --git a/tests/Predis/Options/ClientOptionsTest.php b/tests/Predis/Options/ClientOptionsTest.php new file mode 100644 index 00000000..a2b1090a --- /dev/null +++ b/tests/Predis/Options/ClientOptionsTest.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Options; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * @todo We should test the inner work performed by this class + * using mock objects, but it is quite hard to to that. + */ +class ClientOptionsTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testConstructorWithoutArguments() + { + $options = new ClientOptions(); + + $this->assertInstanceOf('Predis\Profiles\IServerProfile', $options->profile); + $this->assertInstanceOf('Predis\Network\IConnectionCluster', $options->cluster); + $this->assertInstanceOf('Predis\IConnectionFactory', $options->connections); + $this->assertNull($options->prefix); + } + + /** + * @group disconnected + */ + public function testConstructorWithArrayArgument() + { + $options = new ClientOptions(array( + 'cluster' => 'Predis\Network\PredisCluster', + 'connections' => 'Predis\ConnectionFactory', + 'prefix' => 'prefix:', + 'profile' => '2.0', + )); + + $this->assertInstanceOf('Predis\Commands\Processors\ICommandProcessor', $options->prefix); + $this->assertInstanceOf('Predis\Network\IConnectionCluster', $options->cluster); + $this->assertInstanceOf('Predis\Profiles\IServerProfile', $options->profile); + $this->assertInstanceOf('Predis\IConnectionFactory', $options->connections); + } + + /** + * @group disconnected + */ + public function testHandlesCustomOptionsWithoutHandlers() + { + $options = new ClientOptions(array( + 'custom' => 'foobar', + )); + + $this->assertSame('foobar', $options->custom); + } + + /** + * @group disconnected + */ + public function testIsSetReturnsIfOptionHasBeenSetByUser() + { + $options = new ClientOptions(array( + 'prefix' => 'prefix:', + 'custom' => 'foobar', + )); + + $this->assertTrue(isset($options->prefix)); + $this->assertTrue(isset($options->custom)); + $this->assertFalse(isset($options->profile)); + } +} diff --git a/tests/Predis/Options/ClientPrefixTest.php b/tests/Predis/Options/ClientPrefixTest.php new file mode 100644 index 00000000..6fa93a4f --- /dev/null +++ b/tests/Predis/Options/ClientPrefixTest.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Options; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * + */ +class ClientPrefixTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testValidationReturnsCommandProcessor() + { + $value = 'prefix:'; + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new ClientPrefix(); + + $return = $option->validate($options, $value); + + $this->assertInstanceOf('Predis\Commands\Processors\ICommandProcessor', $return); + $this->assertInstanceOf('Predis\Commands\Processors\KeyPrefixProcessor', $return); + $this->assertEquals($value, $return->getPrefix()); + } + + /** + * @group disconnected + */ + public function testDefaultReturnsNull() + { + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new ClientPrefix(); + + $this->assertNull($option->getDefault($options)); + } + + /** + * @group disconnected + */ + public function testInvokeReturnsCommandProcessorOrNull() + { + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new ClientPrefix(); + + $this->assertInstanceOf('Predis\Commands\Processors\ICommandProcessor', $option($options, 'prefix:')); + $this->assertNull($option($options, null)); + } +} diff --git a/tests/Predis/Options/ClientProfileTest.php b/tests/Predis/Options/ClientProfileTest.php new file mode 100644 index 00000000..c771aef6 --- /dev/null +++ b/tests/Predis/Options/ClientProfileTest.php @@ -0,0 +1,172 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Options; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +use Predis\Profiles\ServerProfile; +use Predis\Commands\Processors\KeyPrefixProcessor; + +/** + * + */ +class ClientProfileTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testValidationReturnsServerProfileWithStringValue() + { + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new ClientProfile(); + + $profile = $option->validate($options, '2.0'); + + $this->assertInstanceOf('Predis\Profiles\IServerProfile', $profile); + $this->assertEquals('2.0', $profile->getVersion()); + $this->assertNull($profile->getProcessor()); + } + + /** + * @group disconnected + */ + public function testValidationAcceptsProfileInstancesAsValue() + { + $value = ServerProfile::get('2.0'); + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new ClientProfile(); + + $profile = $option->validate($options, $value); + + $this->assertInstanceOf('Predis\Profiles\IServerProfile', $profile); + $this->assertEquals('2.0', $profile->getVersion()); + $this->assertNull($profile->getProcessor()); + } + + /** + * @group disconnected + */ + public function testValidationThrowsExceptionOnWrongInvalidArguments() + { + $this->setExpectedException('InvalidArgumentException'); + + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new ClientProfile(); + + $option->validate($options, new \stdClass()); + } + + /** + * @group disconnected + */ + public function testDefaultReturnsDefaultServerProfile() + { + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new ClientProfile(); + + $profile = $option->getDefault($options); + + $this->assertInstanceOf('Predis\Profiles\IServerProfile', $profile); + $this->assertInstanceOf(get_class(ServerProfile::getDefault()), $profile); + $this->assertNull($profile->getProcessor()); + } + + /** + * @group disconnected + */ + public function testInvokeReturnsSpecifiedServerProfileOrDefault() + { + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new ClientProfile(); + + $profile = $option($options, '2.0'); + + $this->assertInstanceOf('Predis\Profiles\IServerProfile', $profile); + $this->assertEquals('2.0', $profile->getVersion()); + $this->assertNull($profile->getProcessor()); + + $profile = $option($options, null); + + $this->assertInstanceOf('Predis\Profiles\IServerProfile', $profile); + $this->assertInstanceOf(get_class(ServerProfile::getDefault()), $profile); + $this->assertNull($profile->getProcessor()); + } + + /** + * @group disconnected + * @todo Can't we when trap __isset when mocking an interface? Doesn't seem to work here. + */ + public function testValidateSetsPrefixProcessorFromClientOptions() + { + $options = $this->getMock('Predis\Options\ClientOptions', array('__isset', '__get')); + $options->expects($this->once()) + ->method('__isset') + ->with('prefix') + ->will($this->returnValue(true)); + $options->expects($this->once()) + ->method('__get') + ->with('prefix') + ->will($this->returnValue(new KeyPrefixProcessor('prefix:'))); + + $option = new ClientProfile(); + + $profile = $option->validate($options, '2.0'); + + $this->assertInstanceOf('Predis\Profiles\IServerProfile', $profile); + $this->assertEquals('2.0', $profile->getVersion()); + $this->assertInstanceOf('Predis\Commands\Processors\KeyPrefixProcessor', $profile->getProcessor()); + $this->assertEquals('prefix:', $profile->getProcessor()->getPrefix()); + } + + /** + * @group disconnected + * @todo Can't we when trap __isset when mocking an interface? Doesn't seem to work here. + */ + public function testDefaultSetsPrefixProcessorFromClientOptions() + { + $options = $this->getMock('Predis\Options\ClientOptions', array('__isset', '__get')); + $options->expects($this->once()) + ->method('__isset') + ->with('prefix') + ->will($this->returnValue(true)); + $options->expects($this->once()) + ->method('__get') + ->with('prefix') + ->will($this->returnValue(new KeyPrefixProcessor('prefix:'))); + + $option = new ClientProfile(); + + $profile = $option->getDefault($options); + + $this->assertInstanceOf('Predis\Profiles\IServerProfile', $profile); + $this->assertInstanceOf(get_class(ServerProfile::getDefault()), $profile); + $this->assertInstanceOf('Predis\Commands\Processors\KeyPrefixProcessor', $profile->getProcessor()); + $this->assertEquals('prefix:', $profile->getProcessor()->getPrefix()); + } + + /** + * @group disconnected + */ + public function testValidationDoesNotSetPrefixProcessorWhenValueIsProfileInstance() + { + $options = $this->getMock('Predis\Options\ClientOptions', array('__isset', '__get')); + $options->expects($this->never())->method('__isset'); + $options->expects($this->never())->method('__get'); + + $option = new ClientProfile(); + + $profile = $option->validate($options, ServerProfile::getDefault()); + + $this->assertInstanceOf('Predis\Profiles\IServerProfile', $profile); + $this->assertNull($profile->getProcessor()); + } +} diff --git a/tests/Predis/Options/CustomOptionTest.php b/tests/Predis/Options/CustomOptionTest.php new file mode 100644 index 00000000..32869bf5 --- /dev/null +++ b/tests/Predis/Options/CustomOptionTest.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Options; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * + */ +class CustomOptionTest extends StandardTestCase +{ + /** + * @group disconnected + * @expectedException InvalidArgumentException + */ + public function testConstructorAcceptsOnlyCallablesForValidate() + { + $option = new CustomOption(array('validate' => new \stdClass())); + } + + /** + * @group disconnected + * @expectedException InvalidArgumentException + */ + public function testConstructorAcceptsOnlyCallablesForDefault() + { + $option = new CustomOption(array('default' => new \stdClass())); + } + + /** + * @group disconnected + */ + public function testConstructorIgnoresUnrecognizedParameters() + { + $option = new CustomOption(array('unknown' => new \stdClass())); + + $this->assertNotNull($option); + } + + /** + * @group disconnected + */ + public function testValidateWithoutCallbackReturnsValue() + { + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new CustomOption(); + + $this->assertEquals('test', $option->validate($options, 'test')); + } + + /** + * @group disconnected + */ + public function testDefaultWithoutCallbackReturnsNull() + { + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new CustomOption(); + + $this->assertNull($option->getDefault($options)); + } + + /** + * @group disconnected + */ + public function testInvokeCallsValidateCallback() + { + $value = 'test'; + + $options = $this->getMock('Predis\Options\IClientOptions'); + + $validate = $this->getMock('stdClass', array('__invoke')); + $validate->expects($this->once()) + ->method('__invoke') + ->with($this->isInstanceOf('Predis\Options\IClientOptions'), $value) + ->will($this->returnValue(true)); + + $default = $this->getMock('stdClass', array('__invoke')); + $default->expects($this->never())->method('__invoke'); + + $option = new CustomOption(array('validate' => $validate, 'default' => $default)); + + $this->assertTrue($option($options, $value)); + } + + /** + * @group disconnected + */ + public function testInvokeCallsDefaultCallback() + { + $options = $this->getMock('Predis\Options\IClientOptions'); + + $validate = $this->getMock('stdClass', array('__invoke')); + $validate->expects($this->never())->method('__invoke'); + + $default = $this->getMock('stdClass', array('__invoke')); + $default->expects($this->once()) + ->method('__invoke') + ->with($this->isInstanceOf('Predis\Options\IClientOptions')) + ->will($this->returnValue(true)); + + $option = new CustomOption(array('validate' => $validate, 'default' => $default)); + + $this->assertTrue($option($options, null)); + } +} diff --git a/tests/Predis/Options/OptionTest.php b/tests/Predis/Options/OptionTest.php new file mode 100644 index 00000000..1eab1f11 --- /dev/null +++ b/tests/Predis/Options/OptionTest.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Options; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * + */ +class OptionTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testValidationReturnsTheSameObject() + { + $value = new \stdClass(); + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new Option(); + + $this->assertSame($value, $option->validate($options, $value)); + } + + /** + * @group disconnected + */ + public function testDefaultReturnsNull() + { + $options = $this->getMock('Predis\Options\IClientOptions'); + $option = new Option(); + + $this->assertNull($option->getDefault($options)); + } + + /** + * @group disconnected + */ + public function testInvokePerformsValidationWhenValueIsSet() + { + $value = new \stdClass(); + $options = $this->getMock('Predis\Options\IClientOptions'); + + $option = $this->getMock('Predis\Options\Option', array('validate', 'getDefault')); + $option->expects($this->once()) + ->method('validate') + ->with($options, $value) + ->will($this->returnValue($value)); + $option->expects($this->never())->method('getDefault'); + + $this->assertSame($value, $option($options, $value)); + } + + /** + * @group disconnected + */ + public function testInvokeReturnsDefaultWhenValueIsNotSet() + { + $expected = new \stdClass(); + $options = $this->getMock('Predis\Options\IClientOptions'); + + $option = $this->getMock('Predis\Options\Option', array('validate', 'getDefault')); + $option->expects($this->never())->method('validate'); + $option->expects($this->once()) + ->method('getDefault') + ->with($options) + ->will($this->returnValue($expected)); + + $this->assertSame($expected, $option($options, null)); + } +} diff --git a/tests/Predis/Pipeline/PipelineContextTest.php b/tests/Predis/Pipeline/PipelineContextTest.php new file mode 100644 index 00000000..3e2b78cf --- /dev/null +++ b/tests/Predis/Pipeline/PipelineContextTest.php @@ -0,0 +1,420 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Pipeline; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +use Predis\Client; +use Predis\ClientException; +use Predis\Profiles\ServerProfile; + +/** + * + */ +class PipelineContextTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testConstructorWithoutOptions() + { + $client = new Client(); + $pipeline = new PipelineContext($client); + + $this->assertSame($client, $pipeline->getClient()); + $this->assertInstanceOf('Predis\Pipeline\StandardExecutor', $pipeline->getExecutor()); + } + + /** + * @group disconnected + */ + public function testConstructorWithOptions() + { + $client = new Client(); + $executor = $this->getMock('Predis\Pipeline\IPipelineExecutor'); + $pipeline = new PipelineContext($client, array('executor' => $executor)); + $this->assertSame($executor, $pipeline->getExecutor()); + + $pipeline = new PipelineContext($client, array('safe' => true)); + $this->assertInstanceOf('Predis\Pipeline\SafeExecutor', $pipeline->getExecutor()); + + $options = array('executor' => 'safe'); + $client = new Client($this->getMock('Predis\Network\IConnectionCluster')); + $pipeline = new PipelineContext($client, array('safe' => true)); + $this->assertInstanceOf('Predis\Pipeline\SafeClusterExecutor', $pipeline->getExecutor()); + } + + /** + * @group disconnected + */ + public function testCallDoesNotSendCommandsWithoutExecute() + { + $executor = $this->getMock('Predis\Pipeline\IPipelineExecutor'); + $executor->expects($this->never())->method('executor'); + + $pipeline = new PipelineContext(new Client(), array('executor' => $executor)); + + $pipeline->echo('one'); + $pipeline->echo('two'); + $pipeline->echo('three'); + } + + /** + * @group disconnected + */ + public function testCallReturnsPipelineForFluentInterface() + { + $executor = $this->getMock('Predis\Pipeline\IPipelineExecutor'); + $executor->expects($this->never())->method('executor'); + + $pipeline = new PipelineContext(new Client(), array('executor' => $executor)); + + $this->assertSame($pipeline, $pipeline->echo('one')); + $this->assertSame($pipeline, $pipeline->echo('one')->echo('two')->echo('three')); + } + + /** + * @group disconnected + */ + public function testExecuteCommandDoesNotSendCommandsWithoutExecute() + { + $profile = ServerProfile::getDefault(); + + $executor = $this->getMock('Predis\Pipeline\IPipelineExecutor'); + $executor->expects($this->never())->method('executor'); + + $pipeline = new PipelineContext(new Client(), array('executor' => $executor)); + + $pipeline->executeCommand($profile->createCommand('echo', array('one'))); + $pipeline->executeCommand($profile->createCommand('echo', array('two'))); + $pipeline->executeCommand($profile->createCommand('echo', array('three'))); + } + + /** + * @group disconnected + */ + public function testExecuteWithEmptyBuffer() + { + $executor = $this->getMock('Predis\Pipeline\IPipelineExecutor'); + $executor->expects($this->never())->method('executor'); + + $pipeline = new PipelineContext(new Client(), array('executor' => $executor)); + + $this->assertSame(array(), $pipeline->execute()); + } + + /** + * @group disconnected + */ + public function testExecuteWithFilledBuffer() + { + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $connection->expects($this->exactly(3)) + ->method('writeCommand'); + $connection->expects($this->exactly(3)) + ->method('readResponse') + ->will($this->returnCallback($this->getReadCallback())); + + $pipeline = new PipelineContext(new Client($connection)); + + $pipeline->echo('one'); + $pipeline->echo('two'); + $pipeline->echo('three'); + + $pipeline->flushPipeline(); + + $this->assertSame(array('one', 'two', 'three'), $pipeline->execute()); + } + + /** + * @group disconnected + */ + public function testFlushWithFalseArgumentDiscardsBuffer() + { + $executor = $this->getMock('Predis\Pipeline\IPipelineExecutor'); + $executor->expects($this->never())->method('executor'); + + $pipeline = new PipelineContext(new Client(), array('executor' => $executor)); + + $pipeline->echo('one'); + $pipeline->echo('two'); + $pipeline->echo('three'); + + $pipeline->flushPipeline(false); + + $this->assertSame(array(), $pipeline->execute()); + } + + /** + * @group disconnected + */ + public function testFlushHandlesPartialBuffers() + { + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $connection->expects($this->exactly(4)) + ->method('writeCommand'); + $connection->expects($this->exactly(4)) + ->method('readResponse') + ->will($this->returnCallback($this->getReadCallback())); + + $pipeline = new PipelineContext(new Client($connection)); + + $pipeline->echo('one'); + $pipeline->echo('two'); + $pipeline->flushPipeline(); + $pipeline->echo('three'); + $pipeline->echo('four'); + + $this->assertSame(array('one', 'two', 'three', 'four'), $pipeline->execute()); + } + + /** + * @group disconnected + */ + public function testExecuteAcceptsCallableArgument() + { + $test = $this; + $pipeline = new PipelineContext(new Client()); + + $callable = function($pipe) use($test, $pipeline) { + $test->assertSame($pipeline, $pipe); + $pipe->flushPipeline(false); + }; + + $pipeline->execute($callable); + } + + /** + * @group disconnected + * @expectedException InvalidArgumentException + */ + public function testExecuteDoesNotAcceptNonCallableArgument() + { + $noncallable = new \stdClass(); + + $pipeline = new PipelineContext(new Client()); + $pipeline->execute($noncallable); + } + + /** + * @group disconnected + * @expectedException Predis\ClientException + */ + public function testExecuteInsideCallableArgumentThrowsException() + { + $pipeline = new PipelineContext(new Client()); + + $pipeline->execute(function($pipe) { + $pipe->execute(); + }); + } + + /** + * @group disconnected + */ + public function testExecuteWithCallableArgumentRunsPipelineInCallable() + { + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $connection->expects($this->exactly(4)) + ->method('writeCommand'); + $connection->expects($this->exactly(4)) + ->method('readResponse') + ->will($this->returnCallback($this->getReadCallback())); + + $pipeline = new PipelineContext(new Client($connection)); + + $replies = $pipeline->execute(function($pipe) { + $pipe->echo('one'); + $pipe->echo('two'); + $pipe->echo('three'); + $pipe->echo('four'); + }); + + $this->assertSame(array('one', 'two', 'three', 'four'), $replies); + } + + /** + * @group disconnected + */ + public function testExecuteWithCallableArgumentHandlesExceptions() + { + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $connection->expects($this->never())->method('writeCommand'); + $connection->expects($this->never())->method('readResponse'); + + $pipeline = new PipelineContext(new Client($connection)); + + $exception = null; + $replies = null; + + try { + $replies = $pipeline->execute(function($pipe) { + $pipe->echo('one'); + throw new ClientException('TEST'); + $pipe->echo('two'); + }); + } + catch (\Exception $ex) { + $exception = $ex; + } + + $this->assertInstanceOf('Predis\ClientException', $exception); + $this->assertSame('TEST', $exception->getMessage()); + $this->assertNull($replies); + } + + // ******************************************************************** // + // ---- INTEGRATION TESTS --------------------------------------------- // + // ******************************************************************** // + + /** + * @group connected + */ + public function testIntegrationWithFluentInterface() + { + $pipeline = $this->getClient()->pipeline(); + + $results = $pipeline->echo('one') + ->echo('two') + ->echo('three') + ->execute(); + + $this->assertSame(array('one', 'two', 'three'), $results); + } + + /** + * @group connected + */ + public function testIntegrationWithCallableBlock() + { + $client = $this->getClient(); + + $results = $client->pipeline(function($pipe) { + $pipe->set('foo', 'bar'); + $pipe->get('foo'); + }); + + $this->assertSame(array(true, 'bar'), $results); + $this->assertTrue($client->exists('foo')); + } + + /** + * @group connected + */ + public function testIntegrationWithClientExceptionInCallableBlock() + { + $client = $this->getClient(); + + try { + $client->pipeline(function($pipe) { + $pipe->set('foo', 'bar'); + throw new ClientException('TEST'); + }); + } + catch (\Exception $ex) { + $exception = $ex; + } + + $this->assertInstanceOf('Predis\ClientException', $exception); + $this->assertSame('TEST', $exception->getMessage()); + $this->assertFalse($client->exists('foo')); + } + + /** + * @group connected + */ + public function testIntegrationWithServerExceptionInCallableBlock() + { + $client = $this->getClient(); + + try { + $client->pipeline(function($pipe) { + $pipe->set('foo', 'bar'); + // LPUSH on a string key fails, but won't stop + // the pipeline to send the commands. + $pipe->lpush('foo', 'bar'); + $pipe->set('hoge', 'piyo'); + }); + } + catch (\Exception $ex) { + $exception = $ex; + } + + $this->assertInstanceOf('Predis\ServerException', $exception); + $this->assertTrue($client->exists('foo')); + $this->assertTrue($client->exists('hoge')); + } + + /** + * @group connected + */ + public function testIntegrationWithServerErrorInCallableBlock() + { + $client = $this->getClient(array('throw_errors' => false)); + + $results = $client->pipeline(function($pipe) { + $pipe->set('foo', 'bar'); + $pipe->lpush('foo', 'bar'); // LPUSH on a string key fails. + $pipe->get('foo'); + }); + + $this->assertTrue($results[0]); + $this->assertInstanceOf('Predis\ResponseError', $results[1]); + $this->assertSame('bar', $results[2]); + } + + // ******************************************************************** // + // ---- HELPER METHODS ------------------------------------------------ // + // ******************************************************************** // + + /** + * Returns a client instance connected to the specified Redis + * server instance to perform integration tests. + * + * @return array Additional connection parameters. + * @return Client client instance. + */ + protected function getClient(Array $parameters = array()) + { + $parameters = array_merge(array( + 'scheme' => 'tcp', + 'host' => REDIS_SERVER_HOST, + 'port' => REDIS_SERVER_PORT, + 'database' => REDIS_SERVER_DBNUM, + ), $parameters); + + $client = new Client($parameters, array('profile' => REDIS_SERVER_VERSION)); + + $client->connect(); + $client->flushdb(); + + return $client; + } + + /** + * Helper method that returns a callback used to emulate a reply + * to an ECHO command. + * + * @return \Closure + */ + protected function getReadCallback() + { + return function($command) { + if (($id = $command->getId()) !== 'ECHO') { + throw new \InvalidArgumentException("Expected ECHO, got {$id}"); + } + + list($echoed) = $command->getArguments(); + return $echoed; + }; + } +} diff --git a/tests/Predis/PredisExceptionTest.php b/tests/Predis/PredisExceptionTest.php new file mode 100644 index 00000000..4cfbc656 --- /dev/null +++ b/tests/Predis/PredisExceptionTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * + */ +class PredisExceptionTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testExceptionMessage() + { + $message = 'Predis exception message'; + $exception = $this->getMockForAbstractClass('Predis\PredisException', array($message)); + + $this->setExpectedException('Predis\PredisException', $message); + + throw $exception; + } +} diff --git a/tests/Predis/Profiles/ServerProfileTest.php b/tests/Predis/Profiles/ServerProfileTest.php new file mode 100644 index 00000000..52606cfb --- /dev/null +++ b/tests/Predis/Profiles/ServerProfileTest.php @@ -0,0 +1,265 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Profiles; + +use \PHPUnit_Framework_TestCase as StandardTestCase; +use Predis\Commands\Processors\ProcessorChain; + +/** + * + */ +class ServerProfileTest extends StandardTestCase +{ + const DEFAULT_PROFILE_VERSION = '2.4'; + const DEVELOPMENT_PROFILE_VERSION = '2.6'; + + /** + * @group disconnected + */ + public function testGetVersion() + { + $profile = ServerProfile::get('2.0'); + + $this->assertInstanceOf('Predis\Profiles\IServerProfile', $profile); + $this->assertEquals('2.0', $profile->getVersion()); + } + + /** + * @group disconnected + */ + public function testGetDefault() + { + $profile1 = ServerProfile::get(self::DEFAULT_PROFILE_VERSION); + $profile2 = ServerProfile::get('default'); + $profile3 = ServerProfile::getDefault(); + + $this->assertInstanceOf('Predis\Profiles\IServerProfile', $profile1); + $this->assertInstanceOf('Predis\Profiles\IServerProfile', $profile2); + $this->assertInstanceOf('Predis\Profiles\IServerProfile', $profile3); + $this->assertEquals($profile1->getVersion(), $profile2->getVersion()); + $this->assertEquals($profile2->getVersion(), $profile3->getVersion()); + } + + /** + * @group disconnected + */ + public function testGetDevelopment() + { + $profile1 = ServerProfile::get('dev'); + $profile2 = ServerProfile::getDevelopment(); + + $this->assertInstanceOf('Predis\Profiles\IServerProfile', $profile1); + $this->assertInstanceOf('Predis\Profiles\IServerProfile', $profile2); + $this->assertEquals(self::DEVELOPMENT_PROFILE_VERSION, $profile2->getVersion()); + } + + /** + * @group disconnected + * @expectedException Predis\ClientException + * @expectedExceptionMessage Unknown server profile: 1.0 + */ + public function testGetUndefinedProfile() + { + ServerProfile::get('1.0'); + } + + /** + * @group disconnected + */ + public function testDefineProfile() + { + $profileClass = get_class($this->getMock('Predis\Profiles\IServerProfile')); + + ServerProfile::define('mock', $profileClass); + + $this->assertInstanceOf($profileClass, ServerProfile::get('mock')); + } + + /** + * @group disconnected + * @expectedException InvalidArgumentException + * @expectedExceptionMessage Cannot register 'stdClass' as it is not a valid profile class + */ + public function testDefineInvalidProfile() + { + ServerProfile::define('bogus', 'stdClass'); + } + + /** + * @group disconnected + */ + public function testToString() + { + $this->assertEquals('2.0', (string) ServerProfile::get('2.0')); + } + + /** + * @group disconnected + */ + public function testSupportCommand() + { + $profile = ServerProfile::getDefault(); + + $this->assertTrue($profile->supportsCommand('info')); + $this->assertTrue($profile->supportsCommand('INFO')); + + $this->assertFalse($profile->supportsCommand('unknown')); + $this->assertFalse($profile->supportsCommand('UNKNOWN')); + } + + /** + * @group disconnected + */ + public function testSupportCommands() + { + $profile = ServerProfile::getDefault(); + + $this->assertTrue($profile->supportsCommands(array('get', 'set'))); + $this->assertTrue($profile->supportsCommands(array('GET', 'SET'))); + + $this->assertFalse($profile->supportsCommands(array('get', 'unknown'))); + + $this->assertFalse($profile->supportsCommands(array('unknown1', 'unknown2'))); + } + + /** + * @group disconnected + */ + public function testGetCommandClass() + { + $profile = ServerProfile::getDefault(); + + $this->assertSame('Predis\Commands\ConnectionPing', $profile->getCommandClass('ping')); + $this->assertSame('Predis\Commands\ConnectionPing', $profile->getCommandClass('PING')); + + $this->assertNull($profile->getCommandClass('unknown')); + $this->assertNull($profile->getCommandClass('UNKNOWN')); + } + + /** + * @group disconnected + */ + public function testCreateCommandWithoutArguments() + { + $profile = ServerProfile::getDefault(); + + $command = $profile->createCommand('info'); + $this->assertInstanceOf('Predis\Commands\ICommand', $command); + $this->assertEquals('INFO', $command->getId()); + $this->assertEquals(array(), $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testCreateCommandWithArguments() + { + $profile = ServerProfile::getDefault(); + $arguments = array('foo', 'bar'); + + $command = $profile->createCommand('set', $arguments); + $this->assertInstanceOf('Predis\Commands\ICommand', $command); + $this->assertEquals('SET', $command->getId()); + $this->assertEquals($arguments, $command->getArguments()); + } + + /** + * @group disconnected + * @expectedException Predis\ClientException + * @expectedExceptionMessage 'unknown' is not a registered Redis command + */ + public function testCreateUndefinedCommand() + { + $profile = ServerProfile::getDefault(); + $profile->createCommand('unknown'); + } + + /** + * @group disconnected + */ + public function testGetDefaultProcessor() + { + $profile = ServerProfile::getDefault(); + + $this->assertNull($profile->getProcessor()); + } + + /** + * @group disconnected + */ + public function testSetProcessor() + { + $processor = $this->getMock('Predis\Commands\Processors\ICommandProcessor'); + + $profile = ServerProfile::getDefault(); + $profile->setProcessor($processor); + + $this->assertSame($processor, $profile->getProcessor()); + } + + /** + * @group disconnected + */ + public function testSetAndUnsetProcessor() + { + $processor = $this->getMock('Predis\Commands\Processors\ICommandProcessor'); + $profile = ServerProfile::getDefault(); + + $profile->setProcessor($processor); + $this->assertSame($processor, $profile->getProcessor()); + + $profile->setProcessor(null); + $this->assertNull($profile->getProcessor()); + } + + /** + * @group disconnected + * @todo Could it be that objects passed to the return callback of a mocked + * method are cloned instead of being passed by reference? + */ + public function testSingleProcessor() + { + $argsRef = null; + + $processor = $this->getMock('Predis\Commands\Processors\ICommandProcessor'); + $processor->expects($this->once()) + ->method('process') + ->with($this->isInstanceOf('Predis\Commands\ICommand')) + ->will($this->returnCallback(function($cmd) use(&$argsRef) { + $cmd->setRawArguments($argsRef = array_map('strtoupper', $cmd->getArguments())); + })); + + $profile = ServerProfile::getDefault(); + $profile->setProcessor($processor); + $command = $profile->createCommand('set', array('foo', 'bar')); + + $this->assertSame(array('FOO', 'BAR'), $argsRef); + } + + /** + * @group disconnected + */ + public function testChainOfProcessors() + { + $processor = $this->getMock('Predis\Commands\Processors\ICommandProcessor'); + $processor->expects($this->exactly(2)) + ->method('process'); + + $chain = new ProcessorChain(); + $chain->add($processor); + $chain->add($processor); + + $profile = ServerProfile::getDefault(); + $profile->setProcessor($chain); + $profile->createCommand('info'); + } +} diff --git a/tests/Predis/Profiles/ServerVersion12Test.php b/tests/Predis/Profiles/ServerVersion12Test.php new file mode 100644 index 00000000..ebfdf98c --- /dev/null +++ b/tests/Predis/Profiles/ServerVersion12Test.php @@ -0,0 +1,116 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Profiles; + +/** + * + */ +class ServerVersion12Test extends ServerVersionTestCase +{ + /** + * {@inheritdoc} + */ + public function getProfileInstance() + { + return new ServerVersion12(); + } + + /** + * {@inheritdoc} + */ + public function getExpectedVersion() + { + return '1.2'; + } + + /** + * {@inheritdoc} + */ + public function getExpectedCommands() + { + return array( + 0 => 'exists', + 1 => 'del', + 2 => 'type', + 3 => 'keys', + 4 => 'randomkey', + 5 => 'rename', + 6 => 'renamenx', + 7 => 'expire', + 8 => 'expireat', + 9 => 'ttl', + 10 => 'move', + 11 => 'sort', + 12 => 'set', + 13 => 'setnx', + 14 => 'mset', + 15 => 'msetnx', + 16 => 'get', + 17 => 'mget', + 18 => 'getset', + 19 => 'incr', + 20 => 'incrby', + 21 => 'decr', + 22 => 'decrby', + 23 => 'rpush', + 24 => 'lpush', + 25 => 'llen', + 26 => 'lrange', + 27 => 'ltrim', + 28 => 'lindex', + 29 => 'lset', + 30 => 'lrem', + 31 => 'lpop', + 32 => 'rpop', + 33 => 'rpoplpush', + 34 => 'sadd', + 35 => 'srem', + 36 => 'spop', + 37 => 'smove', + 38 => 'scard', + 39 => 'sismember', + 40 => 'sinter', + 41 => 'sinterstore', + 42 => 'sunion', + 43 => 'sunionstore', + 44 => 'sdiff', + 45 => 'sdiffstore', + 46 => 'smembers', + 47 => 'srandmember', + 48 => 'zadd', + 49 => 'zincrby', + 50 => 'zrem', + 51 => 'zrange', + 52 => 'zrevrange', + 53 => 'zrangebyscore', + 54 => 'zcard', + 55 => 'zscore', + 56 => 'zremrangebyscore', + 57 => 'ping', + 58 => 'auth', + 59 => 'select', + 60 => 'echo', + 61 => 'quit', + 62 => 'info', + 63 => 'slaveof', + 64 => 'monitor', + 65 => 'dbsize', + 66 => 'flushdb', + 67 => 'flushall', + 68 => 'save', + 69 => 'bgsave', + 70 => 'lastsave', + 71 => 'shutdown', + 72 => 'bgrewriteaof', + ); + } +} diff --git a/tests/Predis/Profiles/ServerVersion20Test.php b/tests/Predis/Profiles/ServerVersion20Test.php new file mode 100644 index 00000000..02d17d1e --- /dev/null +++ b/tests/Predis/Profiles/ServerVersion20Test.php @@ -0,0 +1,148 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Profiles; + +/** + * + */ +class ServerVersion20Test extends ServerVersionTestCase +{ + /** + * {@inheritdoc} + */ + public function getProfileInstance() + { + return new ServerVersion20(); + } + + /** + * {@inheritdoc} + */ + public function getExpectedVersion() + { + return '2.0'; + } + + /** + * {@inheritdoc} + */ + public function getExpectedCommands() + { + return array( + 0 => 'exists', + 1 => 'del', + 2 => 'type', + 3 => 'keys', + 4 => 'randomkey', + 5 => 'rename', + 6 => 'renamenx', + 7 => 'expire', + 8 => 'expireat', + 9 => 'ttl', + 10 => 'move', + 11 => 'sort', + 12 => 'set', + 13 => 'setnx', + 14 => 'mset', + 15 => 'msetnx', + 16 => 'get', + 17 => 'mget', + 18 => 'getset', + 19 => 'incr', + 20 => 'incrby', + 21 => 'decr', + 22 => 'decrby', + 23 => 'rpush', + 24 => 'lpush', + 25 => 'llen', + 26 => 'lrange', + 27 => 'ltrim', + 28 => 'lindex', + 29 => 'lset', + 30 => 'lrem', + 31 => 'lpop', + 32 => 'rpop', + 33 => 'rpoplpush', + 34 => 'sadd', + 35 => 'srem', + 36 => 'spop', + 37 => 'smove', + 38 => 'scard', + 39 => 'sismember', + 40 => 'sinter', + 41 => 'sinterstore', + 42 => 'sunion', + 43 => 'sunionstore', + 44 => 'sdiff', + 45 => 'sdiffstore', + 46 => 'smembers', + 47 => 'srandmember', + 48 => 'zadd', + 49 => 'zincrby', + 50 => 'zrem', + 51 => 'zrange', + 52 => 'zrevrange', + 53 => 'zrangebyscore', + 54 => 'zcard', + 55 => 'zscore', + 56 => 'zremrangebyscore', + 57 => 'ping', + 58 => 'auth', + 59 => 'select', + 60 => 'echo', + 61 => 'quit', + 62 => 'info', + 63 => 'slaveof', + 64 => 'monitor', + 65 => 'dbsize', + 66 => 'flushdb', + 67 => 'flushall', + 68 => 'save', + 69 => 'bgsave', + 70 => 'lastsave', + 71 => 'shutdown', + 72 => 'bgrewriteaof', + 73 => 'setex', + 74 => 'append', + 75 => 'substr', + 76 => 'blpop', + 77 => 'brpop', + 78 => 'zunionstore', + 79 => 'zinterstore', + 80 => 'zcount', + 81 => 'zrank', + 82 => 'zrevrank', + 83 => 'zremrangebyrank', + 84 => 'hset', + 85 => 'hsetnx', + 86 => 'hmset', + 87 => 'hincrby', + 88 => 'hget', + 89 => 'hmget', + 90 => 'hdel', + 91 => 'hexists', + 92 => 'hlen', + 93 => 'hkeys', + 94 => 'hvals', + 95 => 'hgetall', + 96 => 'multi', + 97 => 'exec', + 98 => 'discard', + 99 => 'subscribe', + 100 => 'unsubscribe', + 101 => 'psubscribe', + 102 => 'punsubscribe', + 103 => 'publish', + 104 => 'config', + ); + } +} diff --git a/tests/Predis/Profiles/ServerVersion22Test.php b/tests/Predis/Profiles/ServerVersion22Test.php new file mode 100644 index 00000000..0837e648 --- /dev/null +++ b/tests/Predis/Profiles/ServerVersion22Test.php @@ -0,0 +1,163 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Profiles; + +/** + * + */ +class ServerVersion22Test extends ServerVersionTestCase +{ + /** + * {@inheritdoc} + */ + public function getProfileInstance() + { + return new ServerVersion22(); + } + + /** + * {@inheritdoc} + */ + public function getExpectedVersion() + { + return '2.2'; + } + + /** + * {@inheritdoc} + */ + public function getExpectedCommands() + { + return array( + 0 => 'exists', + 1 => 'del', + 2 => 'type', + 3 => 'keys', + 4 => 'randomkey', + 5 => 'rename', + 6 => 'renamenx', + 7 => 'expire', + 8 => 'expireat', + 9 => 'ttl', + 10 => 'move', + 11 => 'sort', + 12 => 'set', + 13 => 'setnx', + 14 => 'mset', + 15 => 'msetnx', + 16 => 'get', + 17 => 'mget', + 18 => 'getset', + 19 => 'incr', + 20 => 'incrby', + 21 => 'decr', + 22 => 'decrby', + 23 => 'rpush', + 24 => 'lpush', + 25 => 'llen', + 26 => 'lrange', + 27 => 'ltrim', + 28 => 'lindex', + 29 => 'lset', + 30 => 'lrem', + 31 => 'lpop', + 32 => 'rpop', + 33 => 'rpoplpush', + 34 => 'sadd', + 35 => 'srem', + 36 => 'spop', + 37 => 'smove', + 38 => 'scard', + 39 => 'sismember', + 40 => 'sinter', + 41 => 'sinterstore', + 42 => 'sunion', + 43 => 'sunionstore', + 44 => 'sdiff', + 45 => 'sdiffstore', + 46 => 'smembers', + 47 => 'srandmember', + 48 => 'zadd', + 49 => 'zincrby', + 50 => 'zrem', + 51 => 'zrange', + 52 => 'zrevrange', + 53 => 'zrangebyscore', + 54 => 'zcard', + 55 => 'zscore', + 56 => 'zremrangebyscore', + 57 => 'ping', + 58 => 'auth', + 59 => 'select', + 60 => 'echo', + 61 => 'quit', + 62 => 'info', + 63 => 'slaveof', + 64 => 'monitor', + 65 => 'dbsize', + 66 => 'flushdb', + 67 => 'flushall', + 68 => 'save', + 69 => 'bgsave', + 70 => 'lastsave', + 71 => 'shutdown', + 72 => 'bgrewriteaof', + 73 => 'setex', + 74 => 'append', + 75 => 'substr', + 76 => 'blpop', + 77 => 'brpop', + 78 => 'zunionstore', + 79 => 'zinterstore', + 80 => 'zcount', + 81 => 'zrank', + 82 => 'zrevrank', + 83 => 'zremrangebyrank', + 84 => 'hset', + 85 => 'hsetnx', + 86 => 'hmset', + 87 => 'hincrby', + 88 => 'hget', + 89 => 'hmget', + 90 => 'hdel', + 91 => 'hexists', + 92 => 'hlen', + 93 => 'hkeys', + 94 => 'hvals', + 95 => 'hgetall', + 96 => 'multi', + 97 => 'exec', + 98 => 'discard', + 99 => 'subscribe', + 100 => 'unsubscribe', + 101 => 'psubscribe', + 102 => 'punsubscribe', + 103 => 'publish', + 104 => 'config', + 105 => 'persist', + 106 => 'strlen', + 107 => 'setrange', + 108 => 'getrange', + 109 => 'setbit', + 110 => 'getbit', + 111 => 'rpushx', + 112 => 'lpushx', + 113 => 'linsert', + 114 => 'brpoplpush', + 115 => 'zrevrangebyscore', + 116 => 'watch', + 117 => 'unwatch', + 118 => 'object', + 119 => 'slowlog', + ); + } +} diff --git a/tests/Predis/Profiles/ServerVersion24Test.php b/tests/Predis/Profiles/ServerVersion24Test.php new file mode 100644 index 00000000..239d5b09 --- /dev/null +++ b/tests/Predis/Profiles/ServerVersion24Test.php @@ -0,0 +1,164 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Profiles; + +/** + * + */ +class ServerVersion24Test extends ServerVersionTestCase +{ + /** + * {@inheritdoc} + */ + public function getProfileInstance() + { + return new ServerVersion24(); + } + + /** + * {@inheritdoc} + */ + public function getExpectedVersion() + { + return '2.4'; + } + + /** + * {@inheritdoc} + */ + public function getExpectedCommands() + { + return array( + 0 => 'exists', + 1 => 'del', + 2 => 'type', + 3 => 'keys', + 4 => 'randomkey', + 5 => 'rename', + 6 => 'renamenx', + 7 => 'expire', + 8 => 'expireat', + 9 => 'ttl', + 10 => 'move', + 11 => 'sort', + 12 => 'set', + 13 => 'setnx', + 14 => 'mset', + 15 => 'msetnx', + 16 => 'get', + 17 => 'mget', + 18 => 'getset', + 19 => 'incr', + 20 => 'incrby', + 21 => 'decr', + 22 => 'decrby', + 23 => 'rpush', + 24 => 'lpush', + 25 => 'llen', + 26 => 'lrange', + 27 => 'ltrim', + 28 => 'lindex', + 29 => 'lset', + 30 => 'lrem', + 31 => 'lpop', + 32 => 'rpop', + 33 => 'rpoplpush', + 34 => 'sadd', + 35 => 'srem', + 36 => 'spop', + 37 => 'smove', + 38 => 'scard', + 39 => 'sismember', + 40 => 'sinter', + 41 => 'sinterstore', + 42 => 'sunion', + 43 => 'sunionstore', + 44 => 'sdiff', + 45 => 'sdiffstore', + 46 => 'smembers', + 47 => 'srandmember', + 48 => 'zadd', + 49 => 'zincrby', + 50 => 'zrem', + 51 => 'zrange', + 52 => 'zrevrange', + 53 => 'zrangebyscore', + 54 => 'zcard', + 55 => 'zscore', + 56 => 'zremrangebyscore', + 57 => 'ping', + 58 => 'auth', + 59 => 'select', + 60 => 'echo', + 61 => 'quit', + 62 => 'info', + 63 => 'slaveof', + 64 => 'monitor', + 65 => 'dbsize', + 66 => 'flushdb', + 67 => 'flushall', + 68 => 'save', + 69 => 'bgsave', + 70 => 'lastsave', + 71 => 'shutdown', + 72 => 'bgrewriteaof', + 73 => 'setex', + 74 => 'append', + 75 => 'substr', + 76 => 'blpop', + 77 => 'brpop', + 78 => 'zunionstore', + 79 => 'zinterstore', + 80 => 'zcount', + 81 => 'zrank', + 82 => 'zrevrank', + 83 => 'zremrangebyrank', + 84 => 'hset', + 85 => 'hsetnx', + 86 => 'hmset', + 87 => 'hincrby', + 88 => 'hget', + 89 => 'hmget', + 90 => 'hdel', + 91 => 'hexists', + 92 => 'hlen', + 93 => 'hkeys', + 94 => 'hvals', + 95 => 'hgetall', + 96 => 'multi', + 97 => 'exec', + 98 => 'discard', + 99 => 'subscribe', + 100 => 'unsubscribe', + 101 => 'psubscribe', + 102 => 'punsubscribe', + 103 => 'publish', + 104 => 'config', + 105 => 'persist', + 106 => 'strlen', + 107 => 'setrange', + 108 => 'getrange', + 109 => 'setbit', + 110 => 'getbit', + 111 => 'rpushx', + 112 => 'lpushx', + 113 => 'linsert', + 114 => 'brpoplpush', + 115 => 'zrevrangebyscore', + 116 => 'watch', + 117 => 'unwatch', + 118 => 'object', + 119 => 'slowlog', + 120 => 'client', + ); + } +} diff --git a/tests/Predis/Profiles/ServerVersionNextTest.php b/tests/Predis/Profiles/ServerVersionNextTest.php new file mode 100644 index 00000000..76679bd2 --- /dev/null +++ b/tests/Predis/Profiles/ServerVersionNextTest.php @@ -0,0 +1,173 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Profiles; + +/** + * + */ +class ServerVersionNextTest extends ServerVersionTestCase +{ + /** + * {@inheritdoc} + */ + public function getProfileInstance() + { + return new ServerVersionNext(); + } + + /** + * {@inheritdoc} + */ + public function getExpectedVersion() + { + return '2.6'; + } + + /** + * {@inheritdoc} + */ + public function getExpectedCommands() + { + return array( + 0 => 'exists', + 1 => 'del', + 2 => 'type', + 3 => 'keys', + 4 => 'randomkey', + 5 => 'rename', + 6 => 'renamenx', + 7 => 'expire', + 8 => 'expireat', + 9 => 'ttl', + 10 => 'move', + 11 => 'sort', + 12 => 'set', + 13 => 'setnx', + 14 => 'mset', + 15 => 'msetnx', + 16 => 'get', + 17 => 'mget', + 18 => 'getset', + 19 => 'incr', + 20 => 'incrby', + 21 => 'decr', + 22 => 'decrby', + 23 => 'rpush', + 24 => 'lpush', + 25 => 'llen', + 26 => 'lrange', + 27 => 'ltrim', + 28 => 'lindex', + 29 => 'lset', + 30 => 'lrem', + 31 => 'lpop', + 32 => 'rpop', + 33 => 'rpoplpush', + 34 => 'sadd', + 35 => 'srem', + 36 => 'spop', + 37 => 'smove', + 38 => 'scard', + 39 => 'sismember', + 40 => 'sinter', + 41 => 'sinterstore', + 42 => 'sunion', + 43 => 'sunionstore', + 44 => 'sdiff', + 45 => 'sdiffstore', + 46 => 'smembers', + 47 => 'srandmember', + 48 => 'zadd', + 49 => 'zincrby', + 50 => 'zrem', + 51 => 'zrange', + 52 => 'zrevrange', + 53 => 'zrangebyscore', + 54 => 'zcard', + 55 => 'zscore', + 56 => 'zremrangebyscore', + 57 => 'ping', + 58 => 'auth', + 59 => 'select', + 60 => 'echo', + 61 => 'quit', + 62 => 'info', + 63 => 'slaveof', + 64 => 'monitor', + 65 => 'dbsize', + 66 => 'flushdb', + 67 => 'flushall', + 68 => 'save', + 69 => 'bgsave', + 70 => 'lastsave', + 71 => 'shutdown', + 72 => 'bgrewriteaof', + 73 => 'setex', + 74 => 'append', + 75 => 'substr', + 76 => 'blpop', + 77 => 'brpop', + 78 => 'zunionstore', + 79 => 'zinterstore', + 80 => 'zcount', + 81 => 'zrank', + 82 => 'zrevrank', + 83 => 'zremrangebyrank', + 84 => 'hset', + 85 => 'hsetnx', + 86 => 'hmset', + 87 => 'hincrby', + 88 => 'hget', + 89 => 'hmget', + 90 => 'hdel', + 91 => 'hexists', + 92 => 'hlen', + 93 => 'hkeys', + 94 => 'hvals', + 95 => 'hgetall', + 96 => 'multi', + 97 => 'exec', + 98 => 'discard', + 99 => 'subscribe', + 100 => 'unsubscribe', + 101 => 'psubscribe', + 102 => 'punsubscribe', + 103 => 'publish', + 104 => 'config', + 105 => 'persist', + 106 => 'strlen', + 107 => 'setrange', + 108 => 'getrange', + 109 => 'setbit', + 110 => 'getbit', + 111 => 'rpushx', + 112 => 'lpushx', + 113 => 'linsert', + 114 => 'brpoplpush', + 115 => 'zrevrangebyscore', + 116 => 'watch', + 117 => 'unwatch', + 118 => 'object', + 119 => 'slowlog', + 120 => 'client', + 121 => 'pttl', + 122 => 'pexpire', + 123 => 'pexpireat', + 124 => 'psetex', + 125 => 'incrbyfloat', + 126 => 'hincrbyfloat', + 127 => 'eval', + 128 => 'evalsha', + 129 => 'script', + ); + } +} diff --git a/tests/Predis/Protocol/ProtocolExceptionTest.php b/tests/Predis/Protocol/ProtocolExceptionTest.php new file mode 100644 index 00000000..0e970d33 --- /dev/null +++ b/tests/Predis/Protocol/ProtocolExceptionTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Protocol; + +require_once __DIR__.'/../CommunicationExceptionTest.php'; + +use Predis\CommunicationExceptionTest; +use Predis\Network\IConnectionSingle; + +/** + * + */ +class ProtocolExceptionTest extends CommunicationExceptionTest +{ + /** + * {@inheritdoc} + */ + protected function getException(IConnectionSingle $connection, $message, $code = 0, \Exception $inner = null) + { + return new ProtocolException($connection, $message, $code, $inner); + } +} diff --git a/tests/Predis/PubSub/DispatcherLoopTest.php b/tests/Predis/PubSub/DispatcherLoopTest.php new file mode 100644 index 00000000..7c646762 --- /dev/null +++ b/tests/Predis/PubSub/DispatcherLoopTest.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\PubSub; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +use Predis\Client; +use Predis\Profiles\ServerProfile; + +/** + * @group realm-pubsub + */ +class DispatcherLoopTest extends StandardTestCase +{ + // ******************************************************************** // + // ---- INTEGRATION TESTS --------------------------------------------- // + // ******************************************************************** // + + /** + * @group connected + */ + public function testDispatcherLoopAgainstRedisServer() + { + $parameters = array( + 'host' => REDIS_SERVER_HOST, + 'port' => REDIS_SERVER_PORT, + 'database' => REDIS_SERVER_DBNUM, + // Prevents suite from handing on broken test + 'read_write_timeout' => 2, + ); + + $producer = new Client($parameters, REDIS_SERVER_VERSION); + $producer->connect(); + + $consumer = new Client($parameters, REDIS_SERVER_VERSION); + $consumer->connect(); + + $dispatcher = new DispatcherLoop($consumer); + + $function01 = $this->getMock('stdClass', array('__invoke')); + $function01->expects($this->exactly(2)) + ->method('__invoke') + ->with($this->logicalOr( + $this->equalTo('01:argument'), + $this->equalTo('01:quit') + )) + ->will($this->returnCallback(function($arg) use($dispatcher) { + if ($arg === '01:quit') { + $dispatcher->stop(); + } + })); + + $function02 = $this->getMock('stdClass', array('__invoke')); + $function02->expects($this->once()) + ->method('__invoke') + ->with('02:argument'); + + $function03 = $this->getMock('stdClass', array('__invoke')); + $function03->expects($this->never()) + ->method('__invoke'); + + $dispatcher->attachCallback('function:01', $function01); + $dispatcher->attachCallback('function:02', $function02); + $dispatcher->attachCallback('function:03', $function03); + + $producer->publish('function:01', '01:argument'); + $producer->publish('function:02', '02:argument'); + $producer->publish('function:01', '01:quit'); + + $dispatcher->run(); + + $this->assertTrue($consumer->ping()); + } +} diff --git a/tests/Predis/PubSub/PubSubContextTest.php b/tests/Predis/PubSub/PubSubContextTest.php new file mode 100644 index 00000000..e398fb30 --- /dev/null +++ b/tests/Predis/PubSub/PubSubContextTest.php @@ -0,0 +1,294 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\PubSub; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +use Predis\Client; +use Predis\Profiles\ServerProfile; + +/** + * @group realm-pubsub + */ +class PubSubContextTest extends StandardTestCase +{ + /** + * @group disconnected + * @expectedException Predis\NotSupportedException + * @expectedExceptionMessage The current profile does not support PUB/SUB related commands + */ + public function testPubSubContextRequirePubSubRelatedCommand() + { + $profile = $this->getMock('Predis\Profiles\IServerProfile'); + $profile->expects($this->any()) + ->method('supportsCommands') + ->will($this->returnValue(false)); + + $client = new Client(null, array('profile' => $profile)); + $pubsub = new PubSubContext($client); + } + + /** + * @group disconnected + * @expectedException Predis\NotSupportedException + * @expectedExceptionMessage Cannot initialize a PUB/SUB context over a cluster of connections + */ + public function testPubSubContextDoesNotWorkOnClusters() + { + $cluster = $this->getMock('Predis\Network\IConnectionCluster'); + + $client = new Client($cluster); + $pubsub = new PubSubContext($client); + } + + /** + * @group disconnected + */ + public function testConstructorWithoutSubscriptionsDoesNotOpenContext() + { + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + + $client = $this->getMock('Predis\Client', array('executeCommand'), array($connection)); + $client->expects($this->never())->method('executeCommand'); + + $pubsub = new PubSubContext($client); + } + + /** + * @group disconnected + */ + public function testConstructorWithSubscriptionsOpensContext() + { + $profile = ServerProfile::get(REDIS_SERVER_VERSION); + + $cmdSubscribe = $profile->createCommand('subscribe', array('channel:foo')); + $cmdPsubscribe = $profile->createCommand('psubscribe', array('channels:*')); + + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $connection->expects($this->exactly(2))->method('writeCommand'); + + $client = $this->getMock('Predis\Client', array('createCommand', 'writeCommand'), array($connection)); + $client->expects($this->exactly(2)) + ->method('createCommand') + ->with($this->logicalOr($this->equalTo('subscribe'), $this->equalTo('psubscribe'))) + ->will($this->returnCallback(function($id, $args) use($profile) { + return $profile->createCommand($id, $args); + })); + + $options = array('subscribe' => 'channel:foo', 'psubscribe' => 'channels:*'); + $pubsub = new PubSubContext($client, $options); + } + + /** + * @group disconnected + */ + public function testClosingContextWithTrueClosesConnection() + { + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + + $client = $this->getMock('Predis\Client', array('disconnect'), array($connection)); + $client->expects($this->exactly(1))->method('disconnect'); + + $pubsub = new PubSubContext($client, array('subscribe' => 'channel:foo')); + + $connection->expects($this->never())->method('writeCommand'); + + $pubsub->closeContext(true); + } + + /** + * @group disconnected + */ + public function testClosingContextWithFalseSendsUnsubscriptions() + { + $profile = ServerProfile::get(REDIS_SERVER_VERSION); + $classUnsubscribe = $profile->getCommandClass('unsubscribe'); + $classPunsubscribe = $profile->getCommandClass('punsubscribe'); + + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + + $client = $this->getMock('Predis\Client', array('disconnect'), array($connection)); + + $options = array('subscribe' => 'channel:foo', 'psubscribe' => 'channels:*'); + $pubsub = new PubSubContext($client, $options); + + $connection->expects($this->exactly(2)) + ->method('writeCommand') + ->with($this->logicalOr( + $this->isInstanceOf($classUnsubscribe), + $this->isInstanceOf($classPunsubscribe) + )); + + $pubsub->closeContext(false); + } + + /** + * @group disconnected + */ + public function testIsNotValidWhenNotSubscribed() + { + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $client = $this->getMock('Predis\Client', array('disconnect'), array($connection)); + + $pubsub = new PubSubContext($client); + + $this->assertFalse($pubsub->valid()); + $this->assertNull($pubsub->next()); + } + + /** + * @group disconnected + */ + public function testReadsMessageFromConnection() + { + $rawmessage = array('message', 'channel:foo', 'message from channel'); + + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $connection->expects($this->once())->method('read')->will($this->returnValue($rawmessage)); + + $client = new Client($connection); + $pubsub = new PubSubContext($client, array('subscribe' => 'channel:foo')); + + $message = $pubsub->current(); + $this->assertSame('message', $message->kind); + $this->assertSame('channel:foo', $message->channel); + $this->assertSame('message from channel', $message->payload); + } + + /** + * @group disconnected + */ + public function testReadsPmessageFromConnection() + { + $rawmessage = array('pmessage', 'channel:*', 'channel:foo', 'message from channel'); + + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $connection->expects($this->once())->method('read')->will($this->returnValue($rawmessage)); + + $client = new Client($connection); + $pubsub = new PubSubContext($client, array('psubscribe' => 'channel:*')); + + $message = $pubsub->current(); + $this->assertSame('pmessage', $message->kind); + $this->assertSame('channel:*', $message->pattern); + $this->assertSame('channel:foo', $message->channel); + $this->assertSame('message from channel', $message->payload); + } + + /** + * @group disconnected + */ + public function testReadsSubscriptionMessageFromConnection() + { + $rawmessage = array('subscribe', 'channel:foo', 1); + + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $connection->expects($this->once())->method('read')->will($this->returnValue($rawmessage)); + + $client = new Client($connection); + $pubsub = new PubSubContext($client, array('subscribe' => 'channel:foo')); + + $message = $pubsub->current(); + $this->assertSame('subscribe', $message->kind); + $this->assertSame('channel:foo', $message->channel); + $this->assertSame(1, $message->payload); + } + + /** + * @group disconnected + */ + public function testReadsUnsubscriptionMessageFromConnection() + { + $rawmessage = array('unsubscribe', 'channel:foo', 1); + + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $connection->expects($this->once())->method('read')->will($this->returnValue($rawmessage)); + + $client = new Client($connection); + $pubsub = new PubSubContext($client, array('subscribe' => 'channel:foo')); + + $message = $pubsub->current(); + $this->assertSame('unsubscribe', $message->kind); + $this->assertSame('channel:foo', $message->channel); + $this->assertSame(1, $message->payload); + } + + /** + * @group disconnected + */ + public function testUnsubscriptionMessageWithZeroChannelCountInvalidatesContext() + { + $rawmessage = array('unsubscribe', 'channel:foo', 0); + + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $connection->expects($this->once())->method('read')->will($this->returnValue($rawmessage)); + + $client = new Client($connection); + $pubsub = new PubSubContext($client, array('subscribe' => 'channel:foo')); + + $this->assertTrue($pubsub->valid()); + + $message = $pubsub->current(); + $this->assertSame('unsubscribe', $message->kind); + $this->assertSame('channel:foo', $message->channel); + $this->assertSame(0, $message->payload); + + $this->assertFalse($pubsub->valid()); + } + + // ******************************************************************** // + // ---- INTEGRATION TESTS --------------------------------------------- // + // ******************************************************************** // + + /** + * @group connected + */ + public function testPubSubAgainstRedisServer() + { + $parameters = array( + 'host' => REDIS_SERVER_HOST, + 'port' => REDIS_SERVER_PORT, + 'database' => REDIS_SERVER_DBNUM, + // Prevents suite from handing on broken test + 'read_write_timeout' => 2, + ); + + $messages = array(); + + $producer = new Client($parameters, REDIS_SERVER_VERSION); + $producer->connect(); + + $consumer = new Client($parameters, REDIS_SERVER_VERSION); + $consumer->connect(); + + $pubsub = new PubSubContext($consumer); + $pubsub->subscribe('channel:foo'); + + $producer->publish('channel:foo', 'message1'); + $producer->publish('channel:foo', 'message2'); + $producer->publish('channel:foo', 'QUIT'); + + foreach ($pubsub as $message) { + if ($message->kind !== 'message') { + continue; + } + $messages[] = ($payload = $message->payload); + if ($payload === 'QUIT') { + $pubsub->closeContext(); + } + } + + $this->assertSame(array('message1', 'message2', 'QUIT'), $messages); + $this->assertFalse($pubsub->valid()); + $this->assertTrue($consumer->ping()); + } +} diff --git a/tests/Predis/ResponseErrorTest.php b/tests/Predis/ResponseErrorTest.php new file mode 100644 index 00000000..560534d5 --- /dev/null +++ b/tests/Predis/ResponseErrorTest.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * + */ +class ResponseErrorTest extends StandardTestCase +{ + const ERR_WRONG_KEY_TYPE = 'ERR Operation against a key holding the wrong kind of value'; + + /** + * @group disconnected + */ + public function testResponseErrorClass() + { + $error = new ResponseError(self::ERR_WRONG_KEY_TYPE); + + $this->assertInstanceOf('Predis\IRedisServerError', $error); + $this->assertInstanceOf('Predis\IReplyObject', $error); + } + + /** + * @group disconnected + */ + public function testErrorMessage() + { + $error = new ResponseError(self::ERR_WRONG_KEY_TYPE); + + $this->assertEquals(self::ERR_WRONG_KEY_TYPE, $error->getMessage()); + } + + /** + * @group disconnected + */ + public function testErrorType() + { + $exception = new ResponseError(self::ERR_WRONG_KEY_TYPE); + + $this->assertEquals('ERR', $exception->getErrorType()); + } + + /** + * @group disconnected + */ + public function testToString() + { + $error = new ResponseError(self::ERR_WRONG_KEY_TYPE); + + $this->assertEquals(self::ERR_WRONG_KEY_TYPE, (string) $error); + } +} diff --git a/tests/Predis/ResponseQueuedTest.php b/tests/Predis/ResponseQueuedTest.php new file mode 100644 index 00000000..c88b6865 --- /dev/null +++ b/tests/Predis/ResponseQueuedTest.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * + */ +class ResponseQueuedTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testResponseQueuedClass() + { + $queued = new ResponseQueued(); + + $this->assertInstanceOf('Predis\IReplyObject', $queued); + } + + /** + * @group disconnected + */ + public function testToString() + { + $queued = new ResponseQueued(); + + $this->assertEquals('QUEUED', (string) $queued); + } + + /** + * @group disconnected + */ + public function testQueuedProperty() + { + $queued = new ResponseQueued(); + + $this->assertTrue(isset($queued->queued)); + $this->assertTrue($queued->queued); + } +} diff --git a/tests/Predis/ServerExceptionTest.php b/tests/Predis/ServerExceptionTest.php new file mode 100644 index 00000000..85cf5023 --- /dev/null +++ b/tests/Predis/ServerExceptionTest.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +/** + * + */ +class ServerExceptionTest extends StandardTestCase +{ + const ERR_WRONG_KEY_TYPE = 'ERR Operation against a key holding the wrong kind of value'; + + /** + * @group disconnected + */ + public function testExceptionMessage() + { + $this->setExpectedException('Predis\ServerException', self::ERR_WRONG_KEY_TYPE); + + throw new ServerException(self::ERR_WRONG_KEY_TYPE); + } + + /** + * @group disconnected + */ + public function testExceptionClass() + { + $exception = new ServerException(self::ERR_WRONG_KEY_TYPE); + + $this->assertInstanceOf('Predis\ServerException', $exception); + $this->assertInstanceOf('Predis\IRedisServerError', $exception); + $this->assertInstanceOf('Predis\IReplyObject', $exception); + $this->assertInstanceOf('Predis\PredisException', $exception); + } + + /** + * @group disconnected + */ + public function testErrorType() + { + $exception = new ServerException(self::ERR_WRONG_KEY_TYPE); + + $this->assertEquals('ERR', $exception->getErrorType()); + } + + /** + * @group disconnected + */ + public function testToResponseError() + { + $exception = new ServerException(self::ERR_WRONG_KEY_TYPE); + $error = $exception->toResponseError(); + + $this->assertInstanceOf('Predis\ResponseError', $error); + + $this->assertEquals($exception->getMessage(), $error->getMessage()); + $this->assertEquals($exception->getErrorType(), $error->getErrorType()); + } +} diff --git a/tests/Predis/Transaction/AbortedMultiExecExceptionTest.php b/tests/Predis/Transaction/AbortedMultiExecExceptionTest.php new file mode 100644 index 00000000..ad4f06ee --- /dev/null +++ b/tests/Predis/Transaction/AbortedMultiExecExceptionTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Transaction; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +use Predis\Client; + +/** + * + */ +class AbortedMultiExecExceptionTest extends StandardTestCase +{ + /** + * @group disconnected + */ + public function testExceptionClass() + { + $client = new Client(); + $transaction = new MultiExecContext($client); + $exception = new AbortedMultiExecException($transaction, 'ABORTED'); + + $this->assertInstanceOf('Predis\PredisException', $exception); + $this->assertSame('ABORTED', $exception->getMessage()); + $this->assertSame($transaction, $exception->getTransaction()); + } +} diff --git a/tests/Predis/Transaction/MultiExecContextTest.php b/tests/Predis/Transaction/MultiExecContextTest.php new file mode 100644 index 00000000..db34df48 --- /dev/null +++ b/tests/Predis/Transaction/MultiExecContextTest.php @@ -0,0 +1,726 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Transaction; + +use \PHPUnit_Framework_TestCase as StandardTestCase; + +use Predis\Client; +use Predis\ResponseQueued; +use Predis\ServerException; +use Predis\Commands\ICommand; + +/** + * @group realm-transaction + */ +class MultiExecContextTest extends StandardTestCase +{ + /** + * @group disconnected + * @expectedException Predis\NotSupportedException + * @expectedExceptionMessage The current profile does not support MULTI, EXEC and DISCARD + */ + public function testThrowsExceptionOnUnsupportedMultiExecInProfile() + { + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $client = new Client($connection, '1.2'); + $tx = new MultiExecContext($client); + } + + /** + * @group disconnected + * @expectedException Predis\NotSupportedException + * @expectedExceptionMessage The current profile does not support WATCH and UNWATCH + */ + public function testThrowsExceptionOnUnsupportedWatchUnwatchInProfile() + { + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $client = new Client($connection, '2.0'); + $tx = new MultiExecContext($client, array('options' => 'cas')); + + $tx->watch('foo'); + } + + /** + * @group disconnected + */ + public function testExecutionWithFluentInterface() + { + $commands = array(); + $expected = array('one', 'two', 'three'); + + $callback = $this->getExecuteCallback($expected, $commands); + $tx = $this->getMockedTransaction($callback); + + $this->assertSame($expected, $tx->echo('one')->echo('two')->echo('three')->execute()); + $this->assertSame(array('MULTI', 'ECHO', 'ECHO', 'ECHO', 'EXEC'), self::commandsToIDs($commands)); + } + + /** + * @group disconnected + */ + public function testExecutionWithCallable() + { + $commands = array(); + $expected = array('one', 'two', 'three'); + + $callback = $this->getExecuteCallback($expected, $commands); + $tx = $this->getMockedTransaction($callback); + + $replies = $tx->execute(function($tx) { + $tx->echo('one'); + $tx->echo('two'); + $tx->echo('three'); + }); + + $this->assertSame($expected, $replies); + $this->assertSame(array('MULTI', 'ECHO', 'ECHO', 'ECHO', 'EXEC'), self::commandsToIDs($commands)); + } + + /** + * @group disconnected + */ + public function testCannotMixExecutionWithFluentInterfaceAndCallable() + { + $commands = array(); + + $callback = $this->getExecuteCallback(null, $commands); + $tx = $this->getMockedTransaction($callback); + + $exception = null; + + try { + $tx->echo('foo')->execute(function($tx) { $tx->echo('bar'); }); + } + catch (\Exception $ex) { + $exception = $ex; + } + + $this->assertInstanceOf('Predis\ClientException', $exception); + $this->assertSame(array('MULTI', 'ECHO', 'DISCARD'), self::commandsToIDs($commands)); + } + + /** + * @group disconnected + */ + public function testEmptyTransactionDoesNotSendMultiExecCommands() + { + $commands = array(); + + $callback = $this->getExecuteCallback(null, $commands); + $tx = $this->getMockedTransaction($callback); + + $replies = $tx->execute(function($tx) { + // NOOP + }); + + $this->assertNull($replies); + $this->assertSame(array(), self::commandsToIDs($commands)); + } + + /** + * @group disconnected + * @expectedException Predis\ClientException + * @expectedExceptionMessage Cannot invoke 'execute' or 'exec' inside an active client transaction block + */ + public function testThrowsExceptionOnExecInsideTransactionBlock() + { + $commands = array(); + + $callback = $this->getExecuteCallback(null, $commands); + $tx = $this->getMockedTransaction($callback); + + $replies = $tx->execute(function($tx) { + $tx->exec(); + }); + + $this->assertNull($replies); + $this->assertSame(array(), self::commandsToIDs($commands)); + } + + /** + * @group disconnected + */ + public function testEmptyTransactionIgnoresDiscard() + { + $commands = array(); + + $callback = $this->getExecuteCallback(null, $commands); + $tx = $this->getMockedTransaction($callback); + + $replies = $tx->execute(function($tx) { + $tx->discard(); + }); + + $this->assertNull($replies); + $this->assertSame(array(), self::commandsToIDs($commands)); + } + + /** + * @group disconnected + */ + public function testTransactionWithCommandsSendsDiscard() + { + $commands = array(); + + $callback = $this->getExecuteCallback(null, $commands); + $tx = $this->getMockedTransaction($callback); + + $replies = $tx->execute(function($tx) { + $tx->set('foo', 'bar'); + $tx->get('foo'); + $tx->discard(); + }); + + $this->assertNull($replies); + $this->assertSame(array('MULTI', 'SET', 'GET', 'DISCARD'), self::commandsToIDs($commands)); + } + + /** + * @group disconnected + */ + public function testSendMultiOnCommandsFollowingDiscard() + { + $commands = array(); + $expected = array('after DISCARD'); + + $callback = $this->getExecuteCallback($expected, $commands); + $tx = $this->getMockedTransaction($callback); + + $replies = $tx->execute(function($tx) { + $tx->echo('before DISCARD'); + $tx->discard(); + $tx->echo('after DISCARD'); + }); + + $this->assertSame($replies, $expected); + $this->assertSame(array('MULTI', 'ECHO', 'DISCARD', 'MULTI', 'ECHO', 'EXEC'), self::commandsToIDs($commands)); + } + /** + * @group disconnected + * @expectedException Predis\ClientException + */ + public function testThrowsExceptionOnWatchInsideMulti() + { + $callback = $this->getExecuteCallback(); + $tx = $this->getMockedTransaction($callback); + + $tx->echo('foobar')->watch('foo')->execute(); + } + + /** + * @group disconnected + */ + public function testUnwatchInsideMulti() + { + $commands = array(); + $expected = array('foobar', true); + + $callback = $this->getExecuteCallback($expected, $commands); + $tx = $this->getMockedTransaction($callback); + + $replies = $tx->echo('foobar')->unwatch('foo')->execute(); + + $this->assertSame($replies, $expected); + $this->assertSame(array('MULTI', 'ECHO', 'UNWATCH', 'EXEC'), self::commandsToIDs($commands)); + } + + /** + * @group disconnected + */ + public function testAutomaticWatchInOptions() + { + $txCommands = $casCommands = array(); + $expected = array('bar', 'piyo'); + $options = array('watch' => array('foo', 'hoge')); + + $callback = $this->getExecuteCallback($expected, $txCommands, $casCommands); + $tx = $this->getMockedTransaction($callback, $options); + + $replies = $tx->execute(function($tx) { + $tx->get('foo'); + $tx->get('hoge'); + }); + + $this->assertSame($replies, $expected); + $this->assertSame(array('WATCH'), self::commandsToIDs($casCommands)); + $this->assertSame(array('foo', 'hoge'), $casCommands[0]->getArguments()); + $this->assertSame(array('MULTI', 'GET', 'GET', 'EXEC'), self::commandsToIDs($txCommands)); + } + /** + * @group disconnected + */ + public function testCheckAndSetWithFluentInterface() + { + $txCommands = $casCommands = array(); + $expected = array('bar', 'piyo'); + $options = array('cas' => true, 'watch' => array('foo', 'hoge')); + + $callback = $this->getExecuteCallback($expected, $txCommands, $casCommands); + $tx = $this->getMockedTransaction($callback, $options); + + $tx->watch('foobar'); + $this->assertSame('DUMMY_REPLY', $tx->get('foo')); + $this->assertSame('DUMMY_REPLY', $tx->get('hoge')); + + $replies = $tx->multi() + ->get('foo') + ->get('hoge') + ->execute(); + + $this->assertSame($replies, $expected); + $this->assertSame(array('WATCH', 'WATCH', 'GET', 'GET'), self::commandsToIDs($casCommands)); + $this->assertSame(array('MULTI', 'GET', 'GET', 'EXEC'), self::commandsToIDs($txCommands)); + } + + /** + * @group disconnected + */ + public function testCheckAndSetWithBlock() + { + $txCommands = $casCommands = array(); + $expected = array('bar', 'piyo'); + $options = array('cas' => true, 'watch' => array('foo', 'hoge')); + + $callback = $this->getExecuteCallback($expected, $txCommands, $casCommands); + $tx = $this->getMockedTransaction($callback, $options); + + $test = $this; + $replies = $tx->execute(function($tx) use($test) { + $tx->watch('foobar'); + + $reply1 = $tx->get('foo'); + $reply2 = $tx->get('hoge'); + + $test->assertSame('DUMMY_REPLY', $reply1); + $test->assertSame('DUMMY_REPLY', $reply2); + + $tx->multi(); + + $tx->get('foo'); + $tx->get('hoge'); + }); + + $this->assertSame($replies, $expected); + $this->assertSame(array('WATCH', 'WATCH', 'GET', 'GET'), self::commandsToIDs($casCommands)); + $this->assertSame(array('MULTI', 'GET', 'GET', 'EXEC'), self::commandsToIDs($txCommands)); + } + + /** + * @group disconnected + */ + public function testCheckAndSetWithEmptyBlock() + { + $txCommands = $casCommands = array(); + $options = array('cas' => true); + + $callback = $this->getExecuteCallback(array(), $txCommands, $casCommands); + $tx = $this->getMockedTransaction($callback, $options); + + $tx->execute(function($tx) { + $tx->multi(); + }); + + $this->assertSame(array(), self::commandsToIDs($casCommands)); + $this->assertSame(array(), self::commandsToIDs($txCommands)); + } + + /** + * @group disconnected + */ + public function testCheckAndSetWithoutExec() + { + $txCommands = $casCommands = array(); + $options = array('cas' => true); + + $callback = $this->getExecuteCallback(array(), $txCommands, $casCommands); + $tx = $this->getMockedTransaction($callback, $options); + + $tx->execute(function($tx) { + $bar = $tx->get('foo'); + $tx->set('hoge', 'piyo'); + }); + + $this->assertSame(array('GET', 'SET'), self::commandsToIDs($casCommands)); + $this->assertSame(array(), self::commandsToIDs($txCommands)); + } + + /** + * @group disconnected + * @expectedException InvalidArgumentException + * @expectedExceptionMessage Automatic retries can be used only when a transaction block is provided + */ + public function testThrowsExceptionOnAutomaticRetriesWithFluentInterface() + { + $options = array('retry' => 1); + + $callback = $this->getExecuteCallback(); + $tx = $this->getMockedTransaction($callback, $options); + + $tx->echo('message')->execute(); + } + + /** + * @group disconnected + */ + public function testAutomaticRetryOnServerSideTransactionAbort() + { + $casCommands = $txCommands = array(); + $expected = array('bar'); + $options = array('watch' => array('foo', 'bar'), 'retry' => ($attempts = 2) + 1); + + $sentinel = $this->getMock('stdClass', array('signal')); + $sentinel->expects($this->exactly($attempts))->method('signal'); + + $callback = $this->getExecuteCallback($expected, $txCommands, $casCommands); + $tx = $this->getMockedTransaction($callback, $options); + + $replies = $tx->execute(function($tx) use($sentinel, &$attempts) { + $tx->get('foo'); + if ($attempts > 0) { + $attempts -= 1; + $sentinel->signal(); + $tx->echo('!!ABORT!!'); + } + }); + + $this->assertSame($replies, $expected); + $this->assertSame(array('WATCH'), self::commandsToIDs($casCommands)); + $this->assertSame(array('foo', 'bar'), $casCommands[0]->getArguments()); + $this->assertSame(array('MULTI', 'GET', 'EXEC'), self::commandsToIDs($txCommands)); + } + + /** + * @group disconnected + * @expectedException Predis\Transaction\AbortedMultiExecException + */ + public function testThrowsExceptionOnServerSideTransactionAbort() + { + $callback = $this->getExecuteCallback(); + $tx = $this->getMockedTransaction($callback); + + $replies = $tx->execute(function($tx) { + $tx->echo('!!ABORT!!'); + }); + } + + /** + * @group disconnected + */ + public function testHandlesStandardExceptionsInBlock() + { + $commands = array(); + $expected = array('foobar', true); + + $callback = $this->getExecuteCallback($expected, $commands); + $tx = $this->getMockedTransaction($callback); + + $replies = null; + + try { + $replies = $tx->execute(function($tx) { + $tx->set('foo', 'bar'); + $tx->get('foo'); + throw new \RuntimeException('TEST'); + }); + } + catch (\Exception $ex) { + // NOOP + } + + $this->assertNull($replies, $expected); + $this->assertSame(array('MULTI', 'SET', 'GET', 'DISCARD'), self::commandsToIDs($commands)); + } + + /** + * @group disconnected + */ + public function testHandlesServerExceptionsInBlock() + { + $commands = array(); + $expected = array('foobar', true); + + $callback = $this->getExecuteCallback($expected, $commands); + $tx = $this->getMockedTransaction($callback); + + $replies = null; + + try { + $replies = $tx->execute(function($tx) { + $tx->set('foo', 'bar'); + $tx->echo('ERR Invalid operation'); + $tx->get('foo'); + }); + } + catch (ServerException $ex) { + $tx->discard(); + } + + $this->assertNull($replies); + $this->assertSame(array('MULTI', 'SET', 'ECHO', 'DISCARD'), self::commandsToIDs($commands)); + } + + // ******************************************************************** // + // ---- INTEGRATION TESTS --------------------------------------------- // + // ******************************************************************** // + + /** + * @group connected + */ + public function testIntegrationHandlesStandardExceptionsInBlock() + { + $client = $this->getClient(); + $exception = null; + + try { + $client->multiExec(function($tx) { + $tx->set('foo', 'bar'); + throw new \RuntimeException("TEST"); + }); + } + catch (\Exception $ex) { + $exception = $ex; + } + + $this->assertInstanceOf('RuntimeException', $exception); + $this->assertFalse($client->exists('foo')); + } + + /** + * @group connected + */ + public function testIntegrationSendMultiOnCommandsAfterDiscard() + { + $client = $this->getClient(); + + $replies = $client->multiExec(function($tx) { + $tx->set('foo', 'bar'); + $tx->discard(); + $tx->set('hoge', 'piyo'); + }); + + $this->assertSame(1, count($replies)); + $this->assertFalse($client->exists('foo')); + $this->assertTrue($client->exists('hoge')); + } + + /** + * @group connected + */ + public function testIntegrationWritesOnWatchedKeysAbortTransaction() + { + $exception = null; + $client1 = $this->getClient(); + $client2 = $this->getClient(); + + try { + $client1->multiExec(array('watch' => 'sentinel'), function($tx) use($client2) { + $tx->set('sentinel', 'client1'); + $tx->get('sentinel'); + $client2->set('sentinel', 'client2'); + }); + } + catch (AbortedMultiExecException $ex) { + $exception = $ex; + } + + $this->assertInstanceOf('Predis\Transaction\AbortedMultiExecException', $exception); + $this->assertSame('client2', $client1->get('sentinel')); + } + + /** + * @group connected + */ + public function testIntegrationCheckAndSetWithDiscardAndRetry() + { + $client = $this->getClient(); + + $client->set('foo', 'bar'); + $options = array('watch' => 'foo', 'cas' => true); + + $replies = $client->multiExec($options, function($tx) { + $tx->watch('foobar'); + $foo = $tx->get('foo'); + $tx->multi(); + $tx->set('foobar', $foo); + $tx->discard(); + $tx->mget('foo', 'foobar'); + }); + + $this->assertInternalType('array', $replies); + $this->assertSame(array(array('bar', null)), $replies); + + $hijack = true; + $client2 = $this->getClient(); + $client->set('foo', 'bar'); + + $options = array('watch' => 'foo', 'cas' => true, 'retry' => 1); + $replies = $client->multiExec($options, function($tx) use($client2, &$hijack) { + $foo = $tx->get('foo'); + $tx->multi(); + $tx->set('foobar', $foo); + $tx->discard(); + if ($hijack) { + $hijack = false; + $client2->set('foo', 'hijacked!'); + } + $tx->mget('foo', 'foobar'); + }); + + $this->assertInternalType('array', $replies); + $this->assertSame(array(array('hijacked!', null)), $replies); + } + + // ******************************************************************** // + // ---- HELPER METHODS ------------------------------------------------ // + // ******************************************************************** // + + /** + * Returns a mocked instance of Predis\Network\IConnectionSingle using + * the specified callback to return values from the executeCommand method. + * + * @param \Closure $executeCallback + * @return \Predis\Network\IConnectionSingle + */ + protected function getMockedConnection($executeCallback) + { + $connection = $this->getMock('Predis\Network\IConnectionSingle'); + $connection->expects($this->any()) + ->method('executeCommand') + ->will($this->returnCallback($executeCallback)); + + return $connection; + } + + /** + * Returns a mocked instance of Predis\Transaction\MultiExecContext using + * the specified callback to return values from the executeCommand method + * of the underlying connection. + * + * @param \Closure $executeCallback + * @return MultiExecContext + */ + protected function getMockedTransaction($executeCallback, $options = array()) + { + $connection = $this->getMockedConnection($executeCallback); + $client = new Client($connection); + $transaction = new MultiExecContext($client, $options); + + return $transaction; + } + + /** + * Returns a callback that emulates a server-side MULTI/EXEC transaction context. + * + * @param array $expected Expected replies. + * @param array $commands Reference to an array that stores the whole flow of commands. + * @return \Closure + */ + protected function getExecuteCallback($expected = array(), &$commands = array(), &$cas = array()) + { + $multi = $watch = $abort = false; + + return function(ICommand $command) use(&$expected, &$commands, &$cas, &$multi, &$watch, &$abort) { + $cmd = $command->getId(); + + if ($multi || $cmd === 'MULTI') { + $commands[] = $command; + } + else { + $cas[] = $command; + } + + switch ($cmd) { + case 'WATCH': + if ($multi) { + throw new ServerException("ERR $cmd inside MULTI is not allowed"); + } + return $watch = true; + + case 'MULTI': + if ($multi) { + throw new ServerException("ERR MULTI calls can not be nested"); + } + return $multi = true; + + case 'EXEC': + if (!$multi) { + throw new ServerException("ERR $cmd without MULTI"); + } + $watch = $multi = false; + if ($abort) { + $commands = $cas = array(); + $abort = false; + return null; + } + return $expected; + + case 'DISCARD': + if (!$multi) { + throw new ServerException("ERR $cmd without MULTI"); + } + $watch = $multi = false; + return true; + + case 'ECHO': + @list($trigger) = $command->getArguments(); + if (strpos($trigger, 'ERR ') === 0) { + throw new ServerException($trigger); + } + if ($trigger === '!!ABORT!!' && $multi) { + $abort = true; + } + return new ResponseQueued(); + + case 'UNWATCH': + $watch = false; + + default: + return $multi ? new ResponseQueued() : 'DUMMY_REPLY'; + } + }; + } + + /** + * Converts an array of instances of Predis\Commands\ICommand and + * returns an array containing their IDs. + * + * @param array $commands List of commands instances. + * @return array + */ + protected static function commandsToIDs($commands) { + return array_map(function($cmd) { return $cmd->getId(); }, $commands); + } + + /** + * Returns a client instance connected to the specified Redis + * server instance to perform integration tests. + * + * @return array Additional connection parameters. + * @return Client client instance. + */ + protected function getClient(Array $parameters = array()) + { + $parameters = array_merge(array( + 'scheme' => 'tcp', + 'host' => REDIS_SERVER_HOST, + 'port' => REDIS_SERVER_PORT, + 'database' => REDIS_SERVER_DBNUM, + ), $parameters); + + $client = new Client($parameters, array('profile' => REDIS_SERVER_VERSION)); + + $client->connect(); + $client->flushdb(); + + return $client; + } +} diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 00000000..269a2b9b --- /dev/null +++ b/tests/README.md @@ -0,0 +1,88 @@ +# About testing Predis # + +__ATTENTION__: Do not run this test suite against instances of Redis running in +production environments or containing data you are interested in! If you still +want to test this software on a production server without hitting the database, +please read on to undestand how to disable integration tests. + +Predis ships with a comprehensive test suite that uses __PHPUnit__ to cover every +aspect of the library. The suite is organized into several unit groups with the +PHPUnit `@group` annotation which makes it possible to run only selected groups +of tests. The main groups are: + + - __disconnected__: generic tests that verify the correct behaviour of the + library without requiring an active connection to Redis. + - __connected__: integration tests that require an active connection to Redis + - __commands__: tests for the implementation of Redis commands. + - __slow__: tests that might slow down the execution of the test suite, they + can be either __connected__ or __disconnected__. + +A list of all the available groups in the suite can be obtained by running: + +```bash +$ phpunit --list-groups +``` +Groups of tests can be disabled or enabled via the XML configuration file or the +standard command-line test runner. Please note that due to a bug in PHPUnit, +older versions ignore the `--group` option when the group is excluded in the XML +configuration file. More details about this issue are available on [PHPUnit's bug +tracker](http://github.com/sebastianbergmann/phpunit/issues/320). + +Certain groups of tests that require native extensions, such as `ext-curl` or +`ext-phpiredis`, are excluded by default in the XML configuration file. If you want +to test Predis using the phpiredis-based connection or against an instance of Webdis, +you should remove those groups of tests from the exclusion list in `phpunit.xml`. + +### Combining groups for inclusion or exclusion with the command-line runner ### + +```bash +$ phpunit --group disconnected --exclude-group commands,slow +``` + +### Integration tests ### + +The suite performs integration tests against a running instance of Redis (>= 2.4.0 +is required) to verify the correct behaviour of the implementation of each command +and certain abstractions implemented in Predis that depend on them. These tests are +identified by the __connected__ group. + +Integration tests for commands that are not defined in the specified server profile +(see the value of the `TEST_SERVER_VERSION` constant in `phpunit.xml`) are marked +as __skipped__ automatically. + +By default, the test suite is configured to execute integration tests using the +server profile for Redis v2.4 (which is the current stable version of Redis). You +can optionally run the suite against a Redis instance built from the `unstable` +branch with the development profile by changing the `TEST_SERVER_VERSION` to `dev` +in the `phpunit.xml` file. + +If you do not have a Redis instance up and running or available for testing, you +can disable integration tests completely by excluding the __connected__ group: + +```bash +$ phpunit --exclude-group connected +``` + +### Slow tests ### + +Certain tests can slow down the execution of the test suite. These tests can be disabled +by excluding the by the __slow__ group: + +```bash +$ phpunit --exclude-group slow +``` + +### Testing Redis commands ### + +We also provide an helper script in the `bin` directory that can be used to automatically +generate a file with the scheleton of a test case to test a Redis command by specifying +the name of the class in the `Predis\Commands` namespace (only classes in this namespace +are considered valid). For example, to generate a test case for `SET` (represented by the +`Predis\Commands\StringSet` class): + +```bash +$ ./bin/generate-command-test.php --class=StringSet +``` +Each command has its own realm (commands that operate on strings, lists, sets and such) +and this realm is automatically inferred from the name of the specified class. The realm +can be also specified manually using the `--realm` option. diff --git a/test/bootstrap.php b/tests/bootstrap.php similarity index 50% rename from test/bootstrap.php rename to tests/bootstrap.php index 3566dd55..43c600ea 100644 --- a/test/bootstrap.php +++ b/tests/bootstrap.php @@ -10,4 +10,9 @@ */ require __DIR__.'/../autoload.php'; -require __DIR__.'/PredisShared.php'; + +require __DIR__.'/PHPUnit/ArrayHasSameValuesConstraint.php'; +require __DIR__.'/PHPUnit/CommandTestCase.php'; +require __DIR__.'/PHPUnit/ConnectionTestCase.php'; +require __DIR__.'/PHPUnit/ServerVersionTestCase.php'; +require __DIR__.'/PHPUnit/DistributionStrategyTestCase.php';