pax_global_header00006660000000000000000000000064121104323010014475gustar00rootroot0000000000000052 comment=8c0498a893ec1bee5a98c602ad3a07855aa22113 predis-0.8.3/000077500000000000000000000000001211043230100127735ustar00rootroot00000000000000predis-0.8.3/.gitignore000066400000000000000000000001101211043230100147530ustar00rootroot00000000000000*.tgz *.phar phpunit.xml package.xml composer.lock experiments/ vendor/ predis-0.8.3/.travis.yml000066400000000000000000000002761211043230100151110ustar00rootroot00000000000000language: php php: - 5.3 - 5.4 - 5.5 branches: except: - v0.5 - v0.6 - php5.2_backport - documentation services: redis-server script: phpunit -c phpunit.xml.travisci predis-0.8.3/CHANGELOG.NAMING.md000066400000000000000000000063001211043230100155530ustar00rootroot00000000000000# Namespaces, interfaces and classes renamed in Predis v0.8 # ____________________________________________ Some namespaces, interfaces and classes in Predis v0.8 have been renamed to follow a common rule inspired by the naming conventions adopted by the Symfony2 project. This is a list of all the changes: ### Renamed namespaces ### - `Predis\Network` => `Predis\Connection` - `Predis\Profiles` => `Predis\Profile` - `Predis\Iterators` => `Predis\Iterator` - `Predis\Options` => `Predis\Option` - `Predis\Commands` => `Predis\Command` - `Predis\Commands\Processors` => `Predis\Command\Processor` ### Renamed interfaces ### - `Predis\IReplyObject` => `Predis\ResponseObjectInterface` - `Predis\IRedisServerError` => `Predis\ResponseErrorInterface` - `Predis\Options\IOption` => `Predis\Option\OptionInterface` - `Predis\Options\IClientOptions` => `Predis\Option\ClientOptionsInterface` - `Predis\Profile\IServerProfile` => `Predis\Profile\ServerProfileInterface` - `Predis\Pipeline\IPipelineExecutor` => `Predis\Pipeline\PipelineExecutorInterface` - `Predis\Distribution\INodeKeyGenerator` => `Predis\Distribution\HashGeneratorInterface` - `Predis\Distribution\IDistributionStrategy` => `Predis\Distribution\DistributionStrategyInterface` - `Predis\Protocol\IProtocolProcessor` => `Predis\Protocol\ProtocolInterface` - `Predis\Protocol\IResponseReader` => `Predis\Protocol\ResponseReaderInterface` - `Predis\Protocol\IResponseHandler` => `Predis\Protocol\ResponseHandlerInterface` - `Predis\Protocol\ICommandSerializer` => `Predis\Protocol\CommandSerializerInterface` - `Predis\Protocol\IComposableProtocolProcessor` => `Predis\Protocol\ComposableProtocolInterface` - `Predis\Network\IConnection` => `Predis\Connection\ConnectionInterface` - `Predis\Network\IConnectionSingle` => `Predis\Connection\SingleConnectionInterface` - `Predis\Network\IConnectionComposable` => `Predis\Connection\ComposableConnectionInterface` - `Predis\Network\IConnectionCluster` => `Predis\Connection\ClusterConnectionInterface` - `Predis\Network\IConnectionReplication` => `Predis\Connection\ReplicationConnectionInterface` - `Predis\Commands\ICommand` => `Predis\Command\CommandInterface` - `Predis\Commands\IPrefixable` => `Predis\Command\PrefixableCommandInterface` - `Predis\Command\Processor\ICommandProcessor` => `Predis\Command\Processor\CommandProcessorInterface` - `Predis\Command\Processor\ICommandProcessorChain` => `Predis\Command\Processor\CommandProcessorChainInterface` - `Predis\Command\Processor\IProcessingSupport` => `Predis\Command\Processor\CommandProcessingInterface` ### Renamed classes ### - `Predis\Commands\Command` => `Predis\Command\AbstractCommand` - `Predis\Network\ConnectionBase` => `Predis\Connection\AbstractConnection` ### Classes or interfaces moved to different namespaces ### - `Predis\MonitorContext` => `Predis\Monitor\MonitorContext` - `Predis\ConnectionParameters` => `Predis\Connection\ConnectionParameters` - `Predis\ConnectionParametersInterface` => `Predis\Connection\ConnectionParametersInterface` - `Predis\ConnectionFactory` => `Predis\Connection\ConnectionFactory` - `Predis\ConnectionFactoryInterface` => `Predis\Connection\ConnectionFactoryInterface` predis-0.8.3/CHANGELOG.md000066400000000000000000000624231211043230100146130ustar00rootroot00000000000000v0.8.3 (2013-02-18) =============================================================================== - Added `CLIENT SETNAME` and `CLIENT GETNAME` (ISSUE #102). - Implemented the `Predis\Connection\PhpiredisStreamConnection` class using the `phpiredis` extension like `Predis\Connection\PhpiredisStreamConnection`, but without requiring the `socket` extension since it relies on PHP's streams. - Added support for the TCP_NODELAY flag via the `tcp_nodelay` parameter for stream-based connections, namely `Predis\Connection\StreamConnection` and `Predis\Connection\PhpiredisStreamConnection` (requires PHP >= 5.4.0). - Updated the aggregated connection class for redis-cluster to work with 16384 hash slots instead of 4096 to reflect the recent change from redis unstable ([see this commit](https://github.com/antirez/redis/commit/ebd666d)). - The constructor of `Predis\Client` now accepts a callable as first argument returning `Predis\Connection\ConnectionInterface`. Users can create their own self-contained strategies to create and set up the underlying connection. - Users should return `0` from `Predis\Command\ScriptedCommand::getKeysCount()` instead of `FALSE` to indicate that all of the arguments of a Lua script must be used to populate `ARGV[]`. This does not represent a breaking change. - The `Predis\Helpers` class has been deprecated and it will be removed in future releases. v0.8.2 (2013-02-03) =============================================================================== - Added `Predis\Session\SessionHandler` to make it easy to store PHP sessions on Redis using Predis. Please note that this class needs either PHP >= 5.4.0 or a polyfill for PHP's `SessionHandlerInterface`. - Added the ability to get the default value of a client option directly from `Predis\Option\ClientOption` using the `getDefault()` method by passing the option name or its instance. - __FIX__: the standard pipeline executor was not using the response parser methods associated to commands to process raw responses (ISSUE #101). v0.8.1 (2013-01-19) =============================================================================== - The `connections` client option can now accept a callable object returning an instance of `Predis\Connection\ConnectionFactoryInterface`. - Client options accepting callable objects as factories now pass their actual instance to the callable as the second argument. - `Predis\Command\Processor\KeyPrefixProcessor` can now be directly casted to string to obtain the current prefix, useful with string interpolation. - Added an optional callable argument to `Predis\Cluster\Distribution\HashRing` and `Predis\Cluster\Distribution\KetamaPureRing` constructor that can be used to customize how the distributor should extract the connection hash when initializing the nodes distribution (ISSUE #36). - Correctly handle `TTL` and `PTTL` returning -2 on non existing keys starting with Redis 2.8. - __FIX__: a missing use directive in `Predis\Transaction\MultiExecContext` caused PHP errors when Redis did not return `+QUEUED` replies to commands when inside a MULTI / EXEC context. - __FIX__: the `parseResponse()` method implemented for a scripted command was ignored when retrying to execute a Lua script by falling back to `EVAL` after a `-NOSCRIPT` error (ISSUE #94). - __FIX__: when subclassing `Predis\Client` the `getClientFor()` method returns a new instance of the subclass instead of a new instance of `Predis\Client`. v0.8.0 (2012-10-23) =============================================================================== - The default server profile for Redis is now `2.6`. - Certain connection parameters have been renamed: - `connection_async` is now `async_connect` - `connection_timeout` is now `timeout` - `connection_persistent` is now `persistent` - The `throw_errors` connection parameter has been removed and replaced by the new `exceptions` client option since exceptions on `-ERR` replies returned by Redis are not generated by connection classes anymore but instead are thrown by the client class and other abstractions such as pipeline contexts. - Added smart support for redis-cluster (Redis v3.0) in addition to the usual cluster implementation that uses client-side sharding. - Various namespaces and classes have been renamed to follow rules inspired by the Symfony2 naming conventions. - The second argument of the constructor of `Predis\Client` does not accept strings or instances of `Predis\Profile\ServerProfileInterface` anymore. To specify a server profile you must explicitly set `profile` in the array of client options. - `Predis\Command\ScriptedCommand` internally relies on `EVALSHA` instead of `EVAL` thus avoiding to send Lua scripts bodies on each request. The client automatically resends the command falling back to `EVAL` when Redis returns a `-NOSCRIPT` error. Automatic fallback to `EVAL` does not work with pipelines, inside a `MULTI / EXEC` context or with plain `EVALSHA` commands. - Complex responses are no more parsed by connection classes as they must be processed by consumer classes using the handler associated to the issued command. This means that executing commands directly on connections only returns simple Redis types, but nothing changes when using `Predis\Client` or the provided abstractions for pipelines and transactions. - Iterators for multi-bulk replies now skip the response parsing method of the command that generated the response and are passed directly to user code. Pipeline and transaction objects still consume automatically iterators. - Cluster and replication connections now extend a new common interface, `Predis\Connection\AggregatedConnectionInterface`. - `Predis\Connection\MasterSlaveReplication` now uses an external strategy class to handle the logic for checking readable / writable commands and Lua scripts. - Command pipelines have been optimized for both speed and code cleanness, but at the cost of bringing a breaking change in the signature of the interface for pipeline executors. - Added a new pipeline executor that sends commands wrapped in a MULTI / EXEC context to make the execution atomic: if a pipeline fails at a certain point then the whole pipeline is discarded. - The key-hashing mechanism for commands is now handled externally and is no more a competence of each command class. This change is neeeded to support both client-side sharding and Redis cluster. - `Predis\Options\Option` is now abstract, see `Predis\Option\AbstractOption`. v0.7.3 (2012-06-01) =============================================================================== - New commands available in the Redis v2.6 profile (dev): `BITOP`, `BITCOUNT`. - When the number of keys `Predis\Commands\ScriptedCommand` is negative, Predis will count from the end of the arguments list to calculate the actual number of keys that will be interpreted as elements for `KEYS` by the underlying `EVAL` command. - __FIX__: `examples\CustomDistributionStrategy.php` had a mistyped constructor call and produced a bad distribution due to an error as pointed in ISSUE #63. This bug is limited to the above mentioned example and does not affect the classes implemented in the `Predis\Distribution` namespace. - __FIX__: `Predis\Commands\ServerEvalSHA::getScriptHash()` was calculating the hash while it just needs to return the first argument of the command. - __FIX__: `Predis\Autoloader` has been modified to allow cascading autoloaders for the `Predis` namespace. v0.7.2 (2012-04-01) =============================================================================== - Added `2.6` in the server profiles aliases list for the upcoming Redis 2.6. `2.4` is still the default server profile. `dev` now targets Redis 2.8. - Connection instances can be serialized and unserialized using `serialize()` and `unserialize()`. This is handy in certain scenarios such as client-side clustering or replication to lower the overhead of initializing a connection object with many sub-connections since unserializing them can be up to 5x times faster. - Reworked the default autoloader to make it faster. It is also possible to prepend it in PHP's autoload stack. - __FIX__: fixed parsing of the payload returned by `MONITOR` with Redis 2.6. v0.7.1 (2011-12-27) =============================================================================== - The PEAR channel on PearHub has been deprecated in favour of `pear.nrk.io`. - Miscellaneous minor fixes. - Added transparent support for master / slave replication configurations where write operations are performed on the master server and read operations are routed to one of the slaves. Please refer to ISSUE #21 for a bit of history and more details about replication support in Predis. - The `profile` client option now accepts a callable object used to initialize a new instance of `Predis\Profiles\IServerProfile`. - Exposed a method for MULTI / EXEC contexts that adds the ability to execute instances of Redis commands against transaction objects. v0.7.0 (2011-12-11) =============================================================================== - Predis now adheres to the PSR-0 standard which means that there is no more a single file holding all the classes of the library, but multiple files (one for each class). You can use any PSR-0 compatible autoloader to load Predis or just leverage the default one shipped with the library by requiring the `Predis/Autoloader.php` and call `Predis\Autoloader::register()`. - The default server profile for Redis is now 2.4. The `dev` profile supports all the features of Redis 2.6 (currently unstable) such as Lua scripting. - Support for long aliases (method names) for Redis commands has been dropped. - Redis 1.0 is no more supported. From now on Predis will use only the unified protocol to serialize commands. - It is possible to prefix keys transparently on a client-level basis with the new `prefix` client option. - An external connection factory is used to initialize new connection instances and developers can now register their own connection classes using the new `connections` client option. - It is possible to connect locally to Redis using UNIX domain sockets. Just use `unix:///path/to/redis.sock` or a named array just like in the following example: `array('scheme' => 'unix', 'path' => '/path/to/redis.sock');`. - If the `phpiredis` extension is loaded by PHP, it is now possible to use an alternative connection class that leverages it to make Predis faster on many cases, especially when dealing with big multibulk replies, with the the only downside that persistent connections are not supported. Please refer to the documentation to see how to activate this class using the new `connections` client option. - Predis is capable to talk with Webdis, albeit with some limitations such as the lack of pipelining and transactions, just by using the `http` scheme in in the connection parameters. All is needed is PHP with the `curl` and the `phpiredis` extensions loaded. - Way too many changes in the public API to make a list here, we just tried to make all the Redis commands compatible with previous releases of v0.6 so that you do not have to worry if you are simply using Predis as a client. Probably the only breaking changes that should be mentioned here are: - `throw_on_error` has been renamed to `throw_errors` and it is a connection parameter instead of a client option, along with `iterable_multibulk`. - `key_distribution` has been removed from the client options. To customize the distribution strategy you must provide a callable object to the new `cluster` client option to configure and then return a new instance of `Predis\Network\IConnectionCluster`. - `Predis\Client::create()` has been removed. Just use the constructor to set up a new instance of `Predis\Client`. - `Predis\Client::pipelineSafe()` was deprecated in Predis v0.6.1 and now has finally removed. Use `Predis\Client::pipeline(array('safe' => true))`. - `Predis\Client::rawCommand()` has been removed due to inconsistencies with the underlying connection abstractions. You can still get the raw resource out of a connection with `Predis\Network\IConnectionSingle::getResource()` so that you can talk directly with Redis. - The `Predis\MultiBulkCommand` class has been merged into `Predis\Command` and thus removed. Serialization of commands is now a competence of connections. - The `Predis\IConnection` interface has been splitted into two new interfaces: `Predis\Network\IConnectionSingle` and `Predis\Network\IConnectionCluster`. - The constructor of `Predis\Client` now accepts more type of arguments such as instances of `Predis\IConnectionParameters` and `Predis\Network\IConnection`. v0.6.6 (2011-04-01) =============================================================================== - Switched to Redis 2.2 as the default server profile (there are no changes that would break compatibility with previous releases). Long command names are no more supported by default but if you need them you can still require `Predis_Compatibility.php` to avoid breaking compatibility. - Added a `VERSION` constant to `Predis\Client`. - Some performance improvements for multibulk replies (parsing them is about 16% faster than the previous version). A few core classes have been heavily optimized to reduce overhead when creating new instances. - Predis now uses by default a new protocol reader, more lightweight and faster than the default handler-based one. Users can revert to the old protocol reader with the `reader` client option set to `composable`. This client option can also accept custom reader classes implementing the new `Predis\IResponseReader` interface. - Added support for connecting to Redis using UNIX domain sockets (ISSUE #25). - The `read_write_timeout` connection parameter can now be set to 0 or false to disable read and write timeouts on connections. The old behaviour of -1 is still intact. - `ZUNIONSTORE` and `ZINTERSTORE` can accept an array to specify a list of the source keys to be used to populate the destination key. - `MGET`, `SINTER`, `SUNION` and `SDIFF` can accept an array to specify a list of keys. `SINTERSTORE`, `SUNIONSTORE` and `SDIFFSTORE` can also accept an array to specify the list of source keys. - `SUBSCRIBE` and `PSUBSCRIBE` can accept a list of channels for subscription. - __FIX__: some client-side clean-ups for `MULTI/EXEC` were handled incorrectly in a couple of corner cases (ISSUE #27). v0.6.5 (2011-02-12) =============================================================================== - __FIX__: due to an untested internal change introduced in v0.6.4, a wrong handling of bulk reads of zero-length values was producing protocol desynchronization errors (ISSUE #20). v0.6.4 (2011-02-12) =============================================================================== - Various performance improvements (15% ~ 25%) especially when dealing with long multibulk replies or when using clustered connections. - Added the `on_retry` option to `Predis\MultiExecBlock` that can be used to specify an external callback (or any callable object) that gets invoked whenever a transaction is aborted by the server. - Added inline (p)subscribtion via options when initializing an instance of `Predis\PubSubContext`. v0.6.3 (2011-01-01) =============================================================================== - New commands available in the Redis v2.2 profile (dev): - Strings: `SETRANGE`, `GETRANGE`, `SETBIT`, `GETBIT` - Lists : `BRPOPLPUSH` - The abstraction for `MULTI/EXEC` transactions has been dramatically improved by providing support for check-and-set (CAS) operations when using Redis >= 2.2. Aborted transactions can also be optionally replayed in automatic up to a user-defined number of times, after which a `Predis\AbortedMultiExec` exception is thrown. v0.6.2 (2010-11-28) =============================================================================== - Minor internal improvements and clean ups. - New commands available in the Redis v2.2 profile (dev): - Strings: `STRLEN` - Lists : `LINSERT`, `RPUSHX`, `LPUSHX` - ZSets : `ZREVRANGEBYSCORE` - Misc. : `PERSIST` - WATCH also accepts a single array parameter with the keys that should be monitored during a transaction. - Improved the behaviour of `Predis\MultiExecBlock` in certain corner cases. - Improved parameters checking for the SORT command. - __FIX__: the `STORE` parameter for the `SORT` command didn't work correctly when using `0` as the target key (ISSUE #13). - __FIX__: the methods for `UNWATCH` and `DISCARD` do not break anymore method chaining with `Predis\MultiExecBlock`. v0.6.1 (2010-07-11) =============================================================================== - Minor internal improvements and clean ups. - New commands available in the Redis v2.2 profile (dev): - Misc. : `WATCH`, `UNWATCH` - Optional modifiers for `ZRANGE`, `ZREVRANGE` and `ZRANGEBYSCORE` queries are supported using an associative array passed as the last argument of their respective methods. - The `LIMIT` modifier for `ZRANGEBYSCORE` can be specified using either: - an indexed array: `array($offset, $count)` - an associative array: `array('offset' => $offset, 'count' => $count)` - The method `Predis\Client::__construct()` now accepts also instances of `Predis\ConnectionParameters`. - `Predis\MultiExecBlock` and `Predis\PubSubContext` now throw an exception when trying to create their instances using a profile that does not support the required Redis commands or when the client is connected to a cluster of connections. - Various improvements to `Predis\MultiExecBlock`: - fixes and more consistent behaviour across various usage cases. - support for `WATCH` and `UNWATCH` when using the current development profile (Redis v2.2) and aborted transactions. - New signature for `Predis\Client::multiExec()` which is now able to accept an array of options for the underlying instance of `Predis\MultiExecBlock`. Backwards compatibility with previous releases of Predis is ensured. - New signature for `Predis\Client::pipeline()` which is now able to accept an array of options for the underlying instance of Predis\CommandPipeline. Backwards compatibility with previous releases of Predis is ensured. The method `Predis\Client::pipelineSafe()` is to be considered deprecated. - __FIX__: The `WEIGHT` modifier for `ZUNIONSTORE` and `ZINTERSTORE` was handled incorrectly with more than two weights specified. v0.6.0 (2010-05-24) =============================================================================== - Switched to the new multi-bulk request protocol for all of the commands in the Redis 1.2 and Redis 2.0 profiles. Inline and bulk requests are now deprecated as they will be removed in future releases of Redis. - The default server profile is `2.0` (targeting Redis 2.0.x). If you are using older versions of Redis, it is highly recommended that you specify which server profile the client should use (e.g. `1.2` when connecting to instances of Redis 1.2.x). - Support for Redis 1.0 is now optional and it is provided by requiring 'Predis_Compatibility.php' before creating an instance of `Predis\Client`. - New commands added to the Redis 2.0 profile since Predis 0.5.1: - Strings: `SETEX`, `APPEND`, `SUBSTR` - ZSets : `ZCOUNT`, `ZRANK`, `ZUNIONSTORE`, `ZINTERSTORE`, `ZREMBYRANK`, `ZREVRANK` - Hashes : `HSET`, `HSETNX`, `HMSET`, `HINCRBY`, `HGET`, `HMGET`, `HDEL`, `HEXISTS`, `HLEN`, `HKEYS`, `HVALS`, `HGETALL` - PubSub : `PUBLISH`, `SUBSCRIBE`, `UNSUBSCRIBE` - Misc. : `DISCARD`, `CONFIG` - Introduced client-level options with the new `Predis\ClientOptions` class. Options can be passed to the constructor of `Predis\Client` in its second argument as an array or an instance of `Predis\ClientOptions`. For brevity's sake and compatibility with older versions, the constructor still accepts an instance of `Predis\RedisServerProfile` in its second argument. The currently supported client options are: - `profile` [default: `2.0` as of Predis 0.6.0]: specifies which server profile to use when connecting to Redis. This option accepts an instance of `Predis\RedisServerProfile` or a string that indicates the version. - `key_distribution` [default: `Predis\Distribution\HashRing`]: specifies which key distribution strategy to use to distribute keys among the servers that compose a cluster. This option accepts an instance of `Predis\Distribution\IDistributionStrategy` so that users can implement their own key distribution strategy. `Predis\Distribution\KetamaPureRing` is an alternative distribution strategy providing a pure-PHP implementation of the same algorithm used by libketama. - `throw_on_error` [default: `TRUE`]: server errors can optionally be handled "silently": instead of throwing an exception, the client returns an error response type. - `iterable_multibulk` [EXPERIMENTAL - default: `FALSE`]: in addition to the classic way of fetching a whole multibulk reply into an array, the client can now optionally stream a multibulk reply down to the user code by using PHP iterators. It is just a little bit slower, but it can save a lot of memory in certain scenarios. - New parameters for connections: - `alias` [default: not set]: every connection can now be identified by an alias that is useful to get a specific connections when connected to a cluster of Redis servers. - `weight` [default: not set]: allows to balance keys asymmetrically across multiple servers. This is useful when you have servers with different amounts of memory to distribute the load of your keys accordingly. - `connection_async` [default: `FALSE`]: estabilish connections to servers in a non-blocking way, so that the client is not blocked while the socket resource performs the actual connection. - `connection_persistent` [default: `FALSE`]: the underlying socket resource is left open when a script ends its lifecycle. Persistent connections can lead to unpredictable or strange behaviours, so they should be used with extreme care. - Introduced the `Predis\Pipeline\IPipelineExecutor` interface. Classes that implements this interface are used internally by the `Predis\CommandPipeline` class to change the behaviour of the pipeline when writing/reading commands from one or multiple servers. Here is the list of the default executors: - `Predis\Pipeline\StandardExecutor`: exceptions generated by server errors might be thrown depending on the options passed to the client (see the `throw_on_error` client option). Instead, protocol or network errors always throw exceptions. This is the default executor for single and clustered connections and shares the same behaviour of Predis 0.5.x. - `Predis\Pipeline\SafeExecutor`: exceptions generated by server, protocol or network errors are not thrown but returned in the response array as instances of `Predis\ResponseError` or `Predis\CommunicationException`. - `Predis\Pipeline\SafeClusterExecutor`: this executor shares the same behaviour of `Predis\Pipeline\SafeExecutor` but it is geared towards clustered connections. - Support for PUB/SUB is handled by the new `Predis\PubSubContext` class, which could also be used to build a callback dispatcher for PUB/SUB scenarios. - When connected to a cluster of connections, it is now possible to get a new `Predis\Client` instance for a single connection of the cluster by passing its alias/index to the new `Predis\Client::getClientFor()` method. - `Predis\CommandPipeline` and `Predis\MultiExecBlock` return their instances when invokink commands, thus allowing method chaining in pipelines and multi-exec blocks. - `Predis\MultiExecBlock` can handle the new `DISCARD` command. - Connections now support float values for the `connection_timeout` parameter to express timeouts with a microsecond resolution. - __FIX__: TCP connections now respect the read/write timeout parameter when reading the payload of server responses. Previously, `stream_get_contents()` was being used internally to read data from a connection but it looks like PHP does not honour the specified timeout for socket streams when inside this function. - __FIX__: The `GET` parameter for the `SORT` command now accepts also multiple key patterns by passing an array of strings. (ISSUE #1). * __FIX__: Replies to the `DEL` command return the number of elements deleted by the server and not 0 or 1 interpreted as a boolean response. (ISSUE #4). v0.5.1 (2010-01-23) =============================================================================== * `RPOPLPUSH` has been changed from bulk command to inline command in Redis 1.2.1, so `ListPopLastPushHead` now extends `InlineCommand`. The old behavior is still available via the `ListPopLastPushHeadBulk` class so that you can override the server profile if you need the old (and uncorrect) behaviour when connecting to a Redis 1.2.0 instance. * Added missing support for `BGREWRITEAOF` for Redis >= 1.2.0. * Implemented a factory method for the `RedisServerProfile` class to ease the creation of new server profile instances based on a version string. v0.5.0 (2010-01-09) =============================================================================== * First versioned release of Predis predis-0.8.3/CONTRIBUTING.md000066400000000000000000000044261211043230100152320ustar00rootroot00000000000000## Filing bug reports ## Bugs or feature requests can be posted online on the [GitHub issues](http://github.com/nrk/predis/issues) section of the project. When reporting bugs, in addition to the obvious description of your issue you __must__ always provide some essential information about your environment such as: 1. version of Predis (check the `VERSION` file or the `Predis\Client::VERSION` constant). 2. version of Redis (check the `redis_version` field returned by [`INFO`](http://redis.io/commands/info)). 3. version of PHP. 4. name and version of the operating system. 5. when possible, a small snippet of code that reproduces the issue. __Think about it__: we do not have a crystal ball and cannot predict things and peer into the unknown, so please provide as much details as possible to help us isolating issues and fix them. __Never__ use GitHub issues to post generic questions about Predis! When you have questions about how Predis works or how it can be used, please just hop me an email and I will get back to you as soon as possible. ## Contributing code ## 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 (possibly with tests covering your modifications) 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. When writing code please follow the [basic coding (PSR-1)](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md) and [coding style (PSR-2)](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) standards and stick with the conventions used in Predis to name classes and interfaces. Please also follow some basic [commit guidelines](http://git-scm.com/book/ch5-2.html#Commit-Guidelines) before opening pull requests. predis-0.8.3/FAQ.md000066400000000000000000000207771211043230100137410ustar00rootroot00000000000000# Some frequently asked questions about Predis # _________________________________________________ ### What is the point of Predis? ### The main point of Predis is about offering a highly customizable client for Redis that can be easily extended by developers while still being reasonabily fast. With Predis you can swap almost any class used internally with your own custom implementation: you can build connection classes, or new distribution strategies for client-side sharding, or class handlers to replace existing commands or add new ones. All of this can be achieved without messing with the source code of the library and directly in your own application. Given the fast pace at which Redis is developed and adds new features, this can be a great asset that allows you to add new and still missing features or commands, or change the behaviour of the library without the need to break your dependencies in production code (well, at least to some degree). ### Does Predis support UNIX domain sockets and persistent connections? ### Yes. Obviously, persistent connections actually work when using PHP configured as a persistent process that gets recycled between requests (see [PHP-FPM](http://php-fpm.org/)). ### Does Predis support transparent (de)serialization of values? ### No, and it will not ever do that for you by default. The reason behind this decision is that serialization is usually something that developers prefer to customize depending on their needs and can not be easily generalized when using Redis because of the many possible access patterns for the data. This does not mean that it is impossible to have such a feature, you can leverage Predis' extensibility to define your own serialization-aware commands. See [here](http://github.com/nrk/predis/issues/29#issuecomment-1202624) for more details on how to implement such a feature with a practical example. ### How can I force Predis to connect to Redis before sending any command? ### Explicitly connecting to Redis is usually not needed since the client library relies on lazily initialized connections to the server, but this behavior can be inconvenient in certain scenarios when you absolutely need to do an upfront check to detect if the server is up and running and eventually catch exceptions on failures. In this case developers can use `Predis\Client::connect()` to explicitly connect to the server: ```php $client = new Predis\Client(); try { $client->connect(); } catch (Predis\Connection\ConnectionException $exception) { // We could not connect to Redis! Your handling code goes here. } $client->info(); ``` ### How Predis implements abstraction of Redis commands? ### The approach used in Predis to implement the abstraction of Redis commands is quite simple. By default every command in the library follows exactly the same argument list as defined in the great online [Redis documentation](http://redis.io/commands) which makes things pretty easy if you already know how Redis works or if you need to look up how to use certain commands. Alternatively, variadic commands can accept an array for keys or values (depending on the command) instead of a list of arguments. See for example how [RPUSH](http://redis.io/commands/rpush) or [HMSET](http://redis.io/commands/hmset) work: ```php $client->rpush('my:list', 'value1', 'value2', 'value3'); // values as arguments $client->rpush('my:list', array('value1', 'value2', 'value3')); // values as single argument array $client->hmset('my:hash', 'field1', 'value1', 'field2', 'value2'); // values as arguments $client->hmset('my:hash', array('field1'=>'value1', 'field2'=>'value2'); // values as single named array ``` The only exception to this _rule_ is the [SORT](http://redis.io/commands/sort) command for which modifiers are [passed using a named array](tests/Predis/Command/KeySortTest.php#L56-77). # Frequently asked questions about performances # _________________________________________________ ### Predis is a pure-PHP implementation: it can not be fast enough! ### It really depends, but most of the times the answer is: _yes, it is fast enough_. I will give you a couple of easy numbers using a single Predis client with PHP 5.4.7 (custom build) and Redis 2.2 (localhost) under Ubuntu 12.04.1 (running on a Intel Q6600): 21500 SET/sec using 12 bytes for both key and value 21000 GET/sec while retrieving the very same values 0.130 seconds to fetch 30000 keys using _KEYS *_. How does it compare with a nice C-based extension such as [__phpredis__](http://github.com/nicolasff/phpredis)? 30100 SET/sec using 12 bytes for both key and value 29400 GET/sec while retrieving the very same values 0.035 seconds to fetch 30000 keys using "KEYS *"". Wow, __phpredis__ looks so much faster! Well we are comparing a C extension with a pure-PHP library so lower numbers are quite expected, but there is a fundamental flaw in them: is this really how you are going to use Redis in your application? Are you really going to send thousands of commands in a for-loop for each page request using a single client instance? If so, well I guess you are probably doing something wrong. Also, if you need to SET or GET multiple keys you should definitely use commands such as MSET and MGET. You can also use pipelining to get more performances when this technique can be used. There is one more thing. We have tested the overhead of Predis by connecting on a localhost instance of Redis, but how these numbers change when we hit the network by connecting to instances of Redis that reside on other servers? Using Predis: 3200 SET/sec using 12 bytes for both key and value 3200 GET/sec while retrieving the very same values 0.132 seconds to fetch 30000 keys using "KEYS *". Using phpredis: 3500 SET/sec using 12 bytes for both key and value 3500 GET/sec while retrieving the very same values 0.045 seconds to fetch 30000 keys using "KEYS *". There you go, you get almost the same average numbers and the reason is quite simple: network latency is a real performance killer and you cannot do (almost) anything about that. As a disclaimer, please remember that we are measuring the overhead of client libraries implementations and the effects of the network round-trip time, we are not really measuring how fast Redis is. Redis shines the best with thousands of concurrent clients doing requests! Also, actual performances should be measured according to how your application will use Redis. ### I am convinced, but performances for multi-bulk replies (e.g. _KEYS *_) are still worse ### Fair enough, but there is actually an option for you if you need even more speed and it consists on installing __[phpiredis](http://github.com/nrk/phpiredis)__ (note the additional _i_ in the name) and let Predis using it. __phpiredis__ is a C-based extension that wraps __hiredis__ (the official Redis C client library) with a thin layer that exposes its features to PHP. You can choose between two different connection backend classes: `Predis\Connection\PhpiredisConnection` (it depends on the `socket` extension) and `Predis\Connection\PhpiredisStreamConnection` (it uses PHP's native streams). You will now get the benefits of a faster protocol parser just by adding a couple of lines of code: ```php $client = new Predis\Client('tcp://127.0.0.1', array( 'connections' => array( 'tcp' => 'Predis\Connection\PhpiredisConnection', 'unix' => 'Predis\Connection\PhpiredisConnection', ), )); ``` As simple as it is, nothing will really change in the way you use the library in your application. So, how fast is it now? There are not much improvements for inline or short bulk replies (e.g. _SET_ or _GET_), but the speed for parsing multi-bulk replies is now on par with phpredis: Using Predis with a phpiredis-based connection to fetch 30000 keys using _KEYS *_: 0.035 seconds from a local Redis instance 0.047 seconds from a remote Redis instance ### If I need to install a C extension to get better performances, why not using phpredis? ### Good question. Generically speaking, if you need absolute uber-speed using localhost instances of Redis and you do not care about abstractions built around some Redis features such as MULTI / EXEC, or if you do not need any kind of extensibility or guaranteed backwards compatibility with different versions of Redis (Predis currently supports from 1.2 up to 2.6, and even the current development version), then using __phpredis__ can make sense for you. Otherwise, Predis is perfect for the job. __phpiredis__ can give you a nice speed bump, but using it is not mandatory. predis-0.8.3/LICENSE000066400000000000000000000020531211043230100140000ustar00rootroot00000000000000Copyright (c) 2009-2013 Daniele Alessandri Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. predis-0.8.3/README.md000066400000000000000000000251571211043230100142640ustar00rootroot00000000000000# Predis # Predis is a flexible and feature-complete PHP (>= 5.3) client library for the Redis key-value store. The library does not require any additional extension loaded in PHP but it can be optionally paired with the [phpiredis](https://github.com/nrk/phpiredis) C-based extension to lower the overhead of serializing and parsing the Redis protocol. Predis is also available in an asynchronous fashion through the experimental client provided by the [Predis\Async](http://github.com/nrk/predis-async) library. For a list of frequently asked questions about Predis see our [FAQ](FAQ.md). More details are available on the [official wiki](http://wiki.github.com/nrk/predis) of the project. ## Main features ## - Wide range of Redis versions supported (from __1.2__ to __2.6__ and unstable) using server profiles. - Smart support for [redis-cluster](http://redis.io/topics/cluster-spec) (Redis >= 3.0). - Client-side sharding via consistent hashing or custom distribution strategies. - Support for master / slave replication configurations (write on master, read from slaves). - Transparent key prefixing strategy capable of handling any command known that has keys in its arguments. - Command pipelining on single and aggregated connections. - Abstraction for Redis transactions (Redis >= 2.0) with support for CAS operations (Redis >= 2.2). - Abstraction for Lua scripting (Redis >= 2.6) capable of automatically switching between `EVAL` and `EVALSHA`. - Connections to Redis instances are lazily established upon the first call to a command by the client. - Ability to connect to Redis using TCP/IP or UNIX domain sockets with support for persistent connections. - Ability to specify alternative connection classes to use different types of network or protocol backends. - Flexible system to define and register your own set of commands or server profiles to client instances. ## How to use Predis ## Predis is available on [Packagist](http://packagist.org/packages/predis/predis) for an easy installation using [Composer](http://packagist.org/about-composer). Composer helps you manage dependencies for your projects and libraries without much hassle which makes it the preferred way to get up and running with new applications. Alternatively, the library is available on our [own PEAR channel](http://pear.nrk.io) for a more traditional installation via PEAR. Zip and tar.gz archives are also downloadable from GitHub by browsing the list of [tagged releases](http://github.com/nrk/predis/tags). ### Loading the library ### Predis relies on the autoloading features of PHP to load its files when needed and complies with the [PSR-0 standard](http://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) which makes it compatible with most of the major frameworks and libraries. Autoloading in your application is handled automatically when managing the dependencies with Composer, but you can also leverage its own autoloader class if you are going to use it in a project or script without any PSR-0 compliant autoloading facility: ```php set('foo', 'bar'); $value = $redis->get('foo'); ``` It is possible to specify the various connection parameters using URI strings or named arrays: ```php $redis = new Predis\Client('tcp://10.0.0.1:6379'); // is equivalent to: $redis = new Predis\Client(array( 'scheme' => 'tcp', 'host' => '10.0.0.1', 'port' => 6379, )); ``` ### Pipelining commands to multiple instances of Redis with client-side sharding ### Pipelining helps with performances when there is the need to send many commands to a server in one go. Furthermore, pipelining works transparently even on aggregated connections. To achieve this, Predis supports client-side sharding using consistent-hashing on keys while clustered connections are supported natively by the client class. ```php $redis = new Predis\Client(array( array('host' => '10.0.0.1', 'port' => 6379), array('host' => '10.0.0.2', 'port' => 6379) )); $replies = $redis->pipeline(function ($pipe) { for ($i = 0; $i < 1000; $i++) { $pipe->set("key:$i", str_pad($i, 4, '0', 0)); $pipe->get("key:$i"); } }); ``` ### Multiple and customizable connection backends ### Predis can optionally use different connection backends to connect to Redis. Two of them leverage the [phpiredis](http://github.com/nrk/phpiredis) C-based extension resulting in a major speed bump especially when dealing with long multibulk replies, namely `Predis\Connection\PhpiredisConnection` (the `socket` extension is also required) and `Predis\Connection\StreamPhpiredisConnection` (it does not require additional extensions since it relies on PHP's native streams). Both of them can connect to Redis using standard TCP/IP connections or UNIX domain sockets: ```php $client = new Predis\Client('tcp://127.0.0.1', array( 'connections' => array( 'tcp' => 'Predis\Connection\PhpiredisConnection', 'unix' => 'Predis\Connection\PhpiredisStreamConnection', ) )); ``` Developers can also create their own connection backends to add support for new protocols, extend existing ones or provide different implementations. Connection backend classes must implement `Predis\Connection\SingleConnectionInterface` or extend `Predis\Connection\AbstractConnection`: ```php class MyConnectionClass implements Predis\Connection\SingleConnectionInterface { // implementation goes here } // Let Predis automatically use your own class to handle connections identified by the tcp scheme. $client = new Predis\Client('tcp://127.0.0.1', array( 'connections' => array('tcp' => 'MyConnectionClass') )); ``` For a more in-depth insight on how to create new connection backends you can look at the actual implementation of the classes contained in the `Predis\Connection` namespace. ### Defining and registering new commands on the client at runtime ### Let's suppose Redis just added the support for a brand new feature associated with a new command. If you want to start using the above mentioned new feature right away without messing with Predis source code or waiting for it to find its way into a stable Predis release, then you can start off by creating a new class that matches the command type and its behaviour and then bind it to a client instance at runtime. Actually, it is easier done than said: ```php class BrandNewRedisCommand extends Predis\Command\AbstractCommand { public function getId() { return 'NEWCMD'; } } $redis = new Predis\Client(); $redis->getProfile()->defineCommand('newcmd', 'BrandNewRedisCommand'); $redis->newcmd(); ``` ### Abstraction for handling Lua scripts as plain Redis commands ### A scripted command in Predis is an abstraction for [Lua scripting](http://redis.io/commands/eval) with Redis >= 2.6 that allows to use a Lua script as if it was a plain Redis command registered in the server profile being used by the client instance. Internally, scripted commands use [EVALSHA](http://redis.io/commands/evalsha) to refer to a Lua script by its SHA1 hash in order to save bandwidth, but they are capable of falling back to [EVAL](http://redis.io/commands/eval) when needed: ```php class ListPushRandomValue extends Predis\Command\ScriptedCommand { public function getKeysCount() { return 1; } public function getScript() { return <<getProfile()->defineCommand('lpushrand', 'ListPushRandomValue'); $value = $client->lpushrand('random_values', $seed = mt_rand()); ``` ## Test suite ## __ATTENTION__: Do not ever run the test suite shipped with Predis against instances of Redis running in production environments or containing data you are interested in! 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 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 `REDIS_SERVER_VERSION` to `dev` in the `phpunit.xml` file. More details on testing Predis can be found in [the tests README](tests/README.md). Predis uses Travis CI for continuous integration. You can find the results of the test suite and the build history [on its project page](http://travis-ci.org/nrk/predis). ## Dependencies ## - PHP >= 5.3.2 - PHPUnit >= 3.5.0 (needed to run the test suite) ## Links ## ### Project ### - [Source code](http://github.com/nrk/predis/) - [Wiki](http://wiki.github.com/nrk/predis/) - [Issue tracker](http://github.com/nrk/predis/issues) - [PEAR channel](http://pear.nrk.io) ### Related ### - [Redis](http://redis.io/) - [PHP](http://php.net/) - [PHPUnit](http://www.phpunit.de/) - [Git](http://git-scm.com/) ## Author ## - [Daniele Alessandri](mailto:suppakilla@gmail.com) ([twitter](http://twitter.com/JoL1hAHN)) ## Contributors ## - [Lorenzo Castelli](http://github.com/lcastelli) - [Jordi Boggiano](http://github.com/Seldaek) ([twitter](http://twitter.com/seldaek)) - [Sebastian Waisbrot](http://github.com/seppo0010) ([twitter](http://twitter.com/seppo0010)) for his past work on extending [phpiredis](http://github.com/nrk/phpiredis) for Predis. ## License ## The code for Predis is distributed under the terms of the MIT license (see [LICENSE](LICENSE)). predis-0.8.3/VERSION000066400000000000000000000000061211043230100140370ustar00rootroot000000000000000.8.3 predis-0.8.3/autoload.php000066400000000000000000000004771211043230100153240ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require __DIR__.'/lib/Predis/Autoloader.php'; Predis\Autoloader::register(); predis-0.8.3/bin/000077500000000000000000000000001211043230100135435ustar00rootroot00000000000000predis-0.8.3/bin/create-phar.php000077500000000000000000000042301211043230100164510ustar00rootroot00000000000000#!/usr/bin/env php * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ // -------------------------------------------------------------------------- // // In order to be able to execute this script to create a Phar archive of Predis, // the Phar module must be loaded and the "phar.readonly" directive php.ini must // be set to "off". You can change the values in the $options array to customize // the creation of the Phar archive to better suit your needs. // -------------------------------------------------------------------------- // $options = array( 'name' => 'predis', 'project_path' => __DIR__ . '/../lib/', 'compression' => Phar::NONE, 'append_version' => true, ); function getPharFilename($options) { $filename = $options['name']; // NOTE: do not consider "append_version" with Phar compression do to a bug in // Phar::compress() when renaming phar archives containing dots in their name. if ($options['append_version'] && $options['compression'] === Phar::NONE) { $versionFile = @fopen(__DIR__ . '/../VERSION', 'r'); if ($versionFile === false) { throw new Exception("Could not locate the VERSION file."); } $version = trim(fgets($versionFile)); fclose($versionFile); $filename .= "_$version"; } return "$filename.phar"; } function getPharStub($options) { return <<compress($options['compression']); $phar->setStub(getPharStub($options)); $phar->buildFromDirectory($options['project_path']); predis-0.8.3/bin/create-single-file.php000077500000000000000000000400161211043230100177170ustar00rootroot00000000000000#!/usr/bin/env php * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ // -------------------------------------------------------------------------- // // This script can be used to automatically glue all the .php files of Predis // into a single monolithic script file that can be used without an autoloader, // just like the other previous versions of the library. // // Much of its complexity is due to the fact that we cannot simply join PHP // files, but namespaces and classes definitions must follow a precise order // when dealing with subclassing and inheritance. // // The current implementation is pretty naïve, but it should do for now. // -------------------------------------------------------------------------- // class CommandLine { public static function getOptions() { $parameters = array( 's:' => 'source:', 'o:' => 'output:', 'e:' => 'exclude:', 'E:' => 'exclude-classes:', ); $getops = getopt(implode(array_keys($parameters)), $parameters); $options = array( 'source' => __DIR__ . "/../lib/", 'output' => PredisFile::NS_ROOT . '.php', 'exclude' => array(), ); foreach ($getops as $option => $value) { switch ($option) { case 's': case 'source': $options['source'] = $value; break; case 'o': case 'output': $options['output'] = $value; break; case 'E': case 'exclude-classes': $options['exclude'] = @file($value, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: $value; break; case 'e': case 'exclude': $options['exclude'] = is_array($value) ? $value : array($value); break; } } return $options; } } class PredisFile { const NS_ROOT = 'Predis'; private $namespaces; public function __construct() { $this->namespaces = array(); } public static function from($libraryPath, Array $exclude = array()) { $nsroot = self::NS_ROOT; $predisFile = new PredisFile(); $libIterator = new RecursiveDirectoryIterator("$libraryPath$nsroot"); foreach (new RecursiveIteratorIterator($libIterator) as $classFile) { if (!$classFile->isFile()) { continue; } $namespace = strtr(str_replace($libraryPath, '', $classFile->getPath()), '/', '\\'); if (in_array(sprintf('%s\\%s', $namespace, $classFile->getBasename('.php')), $exclude)) { continue; } $phpNamespace = $predisFile->getNamespace($namespace); if ($phpNamespace === false) { $phpNamespace = new PhpNamespace($namespace); $predisFile->addNamespace($phpNamespace); } $phpClass = new PhpClass($phpNamespace, $classFile); } return $predisFile; } public function addNamespace(PhpNamespace $namespace) { if (isset($this->namespaces[(string)$namespace])) { throw new InvalidArgumentException("Duplicated namespace"); } $this->namespaces[(string)$namespace] = $namespace; } public function getNamespaces() { return $this->namespaces; } public function getNamespace($namespace) { if (!isset($this->namespaces[$namespace])) { return false; } return $this->namespaces[$namespace]; } public function getClassByFQN($classFqn) { if (($nsLastPos = strrpos($classFqn, '\\')) !== false) { $namespace = $this->getNamespace(substr($classFqn, 0, $nsLastPos)); if ($namespace === false) { return null; } $className = substr($classFqn, $nsLastPos + 1); return $namespace->getClass($className); } return null; } private function calculateDependencyScores(&$classes, $fqn) { if (!isset($classes[$fqn])) { $classes[$fqn] = 0; } $classes[$fqn] += 1; if (($phpClass = $this->getClassByFQN($fqn)) === null) { throw new RuntimeException( "Cannot found the class $fqn which is required by other subclasses. Are you missing a file?" ); } foreach ($phpClass->getDependencies() as $fqn) { $this->calculateDependencyScores($classes, $fqn); } } private function getDependencyScores() { $classes = array(); foreach ($this->getNamespaces() as $phpNamespace) { foreach ($phpNamespace->getClasses() as $phpClass) { $this->calculateDependencyScores($classes, $phpClass->getFQN()); } } return $classes; } private function getOrderedNamespaces($dependencyScores) { $namespaces = array_fill_keys(array_unique( array_map( function ($fqn) { return PhpNamespace::extractName($fqn); }, array_keys($dependencyScores) ) ), 0); foreach ($dependencyScores as $classFqn => $score) { $namespaces[PhpNamespace::extractName($classFqn)] += $score; } arsort($namespaces); return array_keys($namespaces); } private function getOrderedClasses(PhpNamespace $phpNamespace, $classes) { $nsClassesFQNs = array_map(function ($cl) { return $cl->getFQN(); }, $phpNamespace->getClasses()); $nsOrderedClasses = array(); foreach ($nsClassesFQNs as $nsClassFQN) { $nsOrderedClasses[$nsClassFQN] = $classes[$nsClassFQN]; } arsort($nsOrderedClasses); return array_keys($nsOrderedClasses); } public function getPhpCode() { $buffer = array("getDependencyScores(); $namespaces = $this->getOrderedNamespaces($classes); foreach ($namespaces as $namespace) { $phpNamespace = $this->getNamespace($namespace); // generate namespace directive $buffer[] = $phpNamespace->getPhpCode(); $buffer[] = "\n"; // generate use directives $useDirectives = $phpNamespace->getUseDirectives(); if (count($useDirectives) > 0) { $buffer[] = $useDirectives->getPhpCode(); $buffer[] = "\n"; } // generate classes bodies $nsClasses = $this->getOrderedClasses($phpNamespace, $classes); foreach ($nsClasses as $classFQN) { $buffer[] = $this->getClassByFQN($classFQN)->getPhpCode(); $buffer[] = "\n\n"; } $buffer[] = "/* " . str_repeat("-", 75) . " */"; $buffer[] = "\n\n"; } return implode($buffer); } public function saveTo($outputFile) { // TODO: add more sanity checks if ($outputFile === null || $outputFile === '') { throw new InvalidArgumentException('You must specify a valid output file'); } file_put_contents($outputFile, $this->getPhpCode()); } } class PhpNamespace implements IteratorAggregate { private $namespace; private $classes; public function __construct($namespace) { $this->namespace = $namespace; $this->classes = array(); $this->useDirectives = new PhpUseDirectives($this); } public static function extractName($fqn) { $nsSepLast = strrpos($fqn, '\\'); if ($nsSepLast === false) { return $fqn; } $ns = substr($fqn, 0, $nsSepLast); return $ns !== '' ? $ns : null; } public function addClass(PhpClass $class) { $this->classes[$class->getName()] = $class; } public function getClass($className) { if (isset($this->classes[$className])) { return $this->classes[$className]; } } public function getClasses() { return array_values($this->classes); } public function getIterator() { return new \ArrayIterator($this->getClasses()); } public function getUseDirectives() { return $this->useDirectives; } public function getPhpCode() { return "namespace $this->namespace;\n"; } public function __toString() { return $this->namespace; } } class PhpUseDirectives implements Countable, IteratorAggregate { private $use; private $aliases; private $namespace; public function __construct(PhpNamespace $namespace) { $this->use = array(); $this->aliases = array(); $this->namespace = $namespace; } public function add($use, $as = null) { if (in_array($use, $this->use)) { return; } $this->use[] = $use; $this->aliases[$as ?: PhpClass::extractName($use)] = $use; } public function getList() { return $this->use; } public function getIterator() { return new \ArrayIterator($this->getList()); } public function getPhpCode() { $reducer = function ($str, $use) { return $str .= "use $use;\n"; }; return array_reduce($this->getList(), $reducer, ''); } public function getNamespace() { return $this->namespace; } public function getFQN($className) { if (($nsSepFirst = strpos($className, '\\')) === false) { if (isset($this->aliases[$className])) { return $this->aliases[$className]; } return (string)$this->getNamespace() . "\\$className"; } if ($nsSepFirst != 0) { throw new InvalidArgumentException("Partially qualified names are not supported"); } return $className; } public function count() { return count($this->use); } } class PhpClass { const LICENSE_HEADER = << * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ LICENSE; private $namespace; private $file; private $body; private $implements; private $extends; private $name; public function __construct(PhpNamespace $namespace, SplFileInfo $classFile) { $this->namespace = $namespace; $this->file = $classFile; $this->implements = array(); $this->extends = array(); $this->extractData(); $namespace->addClass($this); } public static function extractName($fqn) { $nsSepLast = strrpos($fqn, '\\'); if ($nsSepLast === false) { return $fqn; } return substr($fqn, $nsSepLast + 1); } private function extractData() { $useDirectives = $this->getNamespace()->getUseDirectives(); $useExtractor = function ($m) use ($useDirectives) { $useDirectives->add(($namespacedPath = $m[1])); }; $classBuffer = stream_get_contents(fopen($this->getFile()->getPathname(), 'r')); $classBuffer = str_replace(self::LICENSE_HEADER, '', $classBuffer); $classBuffer = preg_replace('/<\?php\s?\\n\s?/', '', $classBuffer); $classBuffer = preg_replace('/\s?\?>\n?/ms', '', $classBuffer); $classBuffer = preg_replace('/namespace\s+[\w\d_\\\\]+;\s?/', '', $classBuffer); $classBuffer = preg_replace_callback('/use\s+([\w\d_\\\\]+)(\s+as\s+.*)?;\s?\n?/', $useExtractor, $classBuffer); $this->body = trim($classBuffer); $this->extractHierarchy(); } private function extractHierarchy() { $implements = array(); $extends = array(); $extractor = function ($iterator, $callback) { $className = ''; $iterator->seek($iterator->key() + 1); while ($iterator->valid()) { $token = $iterator->current(); if (is_string($token)) { if (preg_match('/\s?,\s?/', $token)) { $callback(trim($className)); $className = ''; } else if ($token == '{') { $callback(trim($className)); return; } } switch ($token[0]) { case T_NS_SEPARATOR: $className .= '\\'; break; case T_STRING: $className .= $token[1]; break; case T_IMPLEMENTS: case T_EXTENDS: $callback(trim($className)); $iterator->seek($iterator->key() - 1); return; } $iterator->next(); } }; $tokens = token_get_all("getPhpCode())); $iterator = new ArrayIterator($tokens); while ($iterator->valid()) { $token = $iterator->current(); if (is_string($token)) { $iterator->next(); continue; } switch ($token[0]) { case T_CLASS: case T_INTERFACE: $iterator->seek($iterator->key() + 2); $tk = $iterator->current(); $this->name = $tk[1]; break; case T_IMPLEMENTS: $extractor($iterator, function ($fqn) use (&$implements) { $implements[] = $fqn; }); break; case T_EXTENDS: $extractor($iterator, function ($fqn) use (&$extends) { $extends[] = $fqn; }); break; } $iterator->next(); } $this->implements = $this->guessFQN($implements); $this->extends = $this->guessFQN($extends); } public function guessFQN($classes) { $useDirectives = $this->getNamespace()->getUseDirectives(); return array_map(array($useDirectives, 'getFQN'), $classes); } public function getImplementedInterfaces($all = false) { if ($all) { return $this->implements; } return array_filter( $this->implements, function ($cn) { return strpos($cn, 'Predis\\') === 0; } ); } public function getExtendedClasses($all = false) { if ($all) { return $this->extemds; } return array_filter( $this->extends, function ($cn) { return strpos($cn, 'Predis\\') === 0; } ); } public function getDependencies($all = false) { return array_merge( $this->getImplementedInterfaces($all), $this->getExtendedClasses($all) ); } public function getNamespace() { return $this->namespace; } public function getFile() { return $this->file; } public function getName() { return $this->name; } public function getFQN() { return (string)$this->getNamespace() . '\\' . $this->name; } public function getPhpCode() { return $this->body; } public function __toString() { return "class " . $this->getName() . '{ ... }'; } } /* -------------------------------------------------------------------------- */ $options = CommandLine::getOptions(); $predisFile = PredisFile::from($options['source'], $options['exclude']); $predisFile->saveTo($options['output']); predis-0.8.3/bin/generate-command-test.php000077500000000000000000000164231211043230100204500ustar00rootroot00000000000000#!/usr/bin/env php * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ // -------------------------------------------------------------------------- // // This script 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\Command namespace (only classes in this namespace are valid). // For example, to generate a test case for SET (which is represented by the // Predis\Command\StringSet class): // // $ ./bin/generate-command-test.php --class=StringSet // // Here is a list of optional arguments: // // --realm: each command has its own realm (commands that operate on strings, // lists, sets and such) but while this realm is usually inferred from the name // of the specified class, sometimes it can be useful to override it with a // custom one. // // --output: write the generated test case to the specified path instead of // the default one. // // --overwrite: pre-existing test files are not overwritten unless this option // is explicitly specified. // -------------------------------------------------------------------------- // use Predis\Command\CommandInterface; use Predis\Command\PrefixableCommandInterface; 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\\Command\\{$options['class']}"; $options['path'] = "Predis/Command/{$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\Command\CommandInterface')) { throw new RuntimeException("Class $class must implement Predis\Command\CommandInterface."); } $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(CommandInterface $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\Command; 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 PrefixableCommandInterface) { $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(); predis-0.8.3/composer.json000066400000000000000000000013411211043230100155140ustar00rootroot00000000000000{ "name": "predis/predis", "type": "library", "description": "Flexible and feature-complete PHP client library for Redis", "keywords": ["nosql", "redis", "predis"], "homepage": "http://github.com/nrk/predis", "license": "MIT", "authors": [ { "name": "Daniele Alessandri", "email": "suppakilla@gmail.com", "homepage": "http://clorophilla.net" } ], "require": { "php": ">=5.3.2" }, "suggest": { "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol", "ext-curl": "Allows access to Webdis when paired with phpiredis" }, "autoload": { "psr-0": {"Predis": "lib/"} } } predis-0.8.3/examples/000077500000000000000000000000001211043230100146115ustar00rootroot00000000000000predis-0.8.3/examples/CustomDistributionStrategy.php000066400000000000000000000042741211043230100227260ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require 'SharedConfigurations.php'; // Developers can customize the distribution strategy used by the client // to distribute keys among a cluster of servers simply by creating a class // that implements Predis\Distribution\DistributionStrategyInterface. use Predis\Connection\PredisCluster; use Predis\Cluster\Distribution\DistributionStrategyInterface; use Predis\Cluster\Hash\HashGeneratorInterface; class NaiveDistributionStrategy implements DistributionStrategyInterface, HashGeneratorInterface { private $nodes; private $nodesCount; public function __construct() { $this->nodes = array(); $this->nodesCount = 0; } public function add($node, $weight = null) { $this->nodes[] = $node; $this->nodesCount++; } public function remove($node) { $this->nodes = array_filter($this->nodes, function ($n) use ($node) { return $n !== $node; }); $this->nodesCount = count($this->nodes); } public function get($key) { if (0 === $count = $this->nodesCount) { throw new RuntimeException('No connections'); } return $this->nodes[$count > 1 ? abs($key % $count) : 0]; } public function hash($value) { return crc32($value); } public function getHashGenerator() { return $this; } } $options = array( 'cluster' => function () { $distributor = new NaiveDistributionStrategy(); $cluster = new PredisCluster($distributor); return $cluster; }, ); $client = new Predis\Client($multiple_servers, $options); for ($i = 0; $i < 100; $i++) { $client->set("key:$i", str_pad($i, 4, '0', 0)); $client->get("key:$i"); } $server1 = $client->getClientFor('first')->info(); $server2 = $client->getClientFor('second')->info(); printf("Server '%s' has %d keys while server '%s' has %d keys.\n", 'first', $server1['db15']['keys'], 'second', $server2['db15']['keys'] ); predis-0.8.3/examples/DispatcherLoop.php000066400000000000000000000037771211043230100202600ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require 'SharedConfigurations.php'; /* This is a basic example on how to use the Predis\DispatcherLoop class. To see this example in action you can just use redis-cli and publish some messages to the 'events' and 'control' channel, e.g.: ./redis-cli PUBLISH events first PUBLISH events second PUBLISH events third PUBLISH control terminate_dispatcher */ // Create a client and disable r/w timeout on the socket $client = new Predis\Client($single_server + array('read_write_timeout' => 0)); // Create a Predis\DispatcherLoop instance and attach a bunch of callbacks. $dispatcher = new Predis\PubSub\DispatcherLoop($client); // Demonstrate how to use a callable class as a callback for Predis\DispatcherLoop. class EventsListener implements Countable { private $events; public function __construct() { $this->events = array(); } public function count() { return count($this->events); } public function getEvents() { return $this->events; } public function __invoke($payload) { $this->events[] = $payload; } } // Attach our callable class to the dispatcher. $dispatcher->attachCallback('events', ($events = new EventsListener())); // Attach a function to control the dispatcher loop termination with a message. $dispatcher->attachCallback('control', function ($payload) use ($dispatcher) { if ($payload === 'terminate_dispatcher') { $dispatcher->stop(); } }); // Run the dispatcher loop until the callback attached to the 'control' channel // receives 'terminate_dispatcher' as a message. $dispatcher->run(); // Display our achievements! echo "We received {$events->count()} messages!\n"; // Say goodbye :-) $info = $client->info(); print_r("Goodbye from Redis v{$info['redis_version']}!\n"); predis-0.8.3/examples/KeyPrefixes.php000066400000000000000000000016771211043230100175730ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require 'SharedConfigurations.php'; // Predis ships with a KeyPrefixProcessor class that is used to transparently // prefix each key before sending commands to Redis, even for complex commands // such as SORT, ZUNIONSTORE and ZINTERSTORE. Key prefixes are useful to create // user-level namespaces for you keyspace, thus eliminating the need for separate // logical databases. $client = new Predis\Client($single_server, array('prefix' => 'nrk:')); $client->mset(array('foo' => 'bar', 'lol' => 'wut')); var_dump($client->mget('foo', 'lol')); /* array(2) { [0]=> string(3) "bar" [1]=> string(3) "wut" } */ var_dump($client->keys('*')); /* array(2) { [0]=> string(7) "nrk:foo" [1]=> string(7) "nrk:lol" } */ predis-0.8.3/examples/MasterSlaveReplication.php000066400000000000000000000033131211043230100217420ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require 'SharedConfigurations.php'; // Predis supports master / slave replication scenarios where write operations are // performed on the master server and read operations are executed against one of // the slaves. The behaviour of commands or EVAL scripts can be customized at will. // As soon as a write operation is performed, all the subsequent requests (reads // or writes) will be served by the master server. // // This example must be executed with the second Redis server acting as the slave // of the first one using the SLAVEOF command. // $parameters = array( 'tcp://127.0.0.1:6379?database=15&alias=master', 'tcp://127.0.0.1:6380?database=15&alias=slave', ); $options = array('replication' => true); $client = new Predis\Client($parameters, $options); // Read operation. $exists = $client->exists('foo') ? 'yes' : 'no'; $current = $client->getConnection()->getCurrent()->getParameters(); echo "Does 'foo' exist on {$current->alias}? $exists.\n"; // Write operation. $client->set('foo', 'bar'); $current = $client->getConnection()->getCurrent()->getParameters(); echo "Now 'foo' has been set to 'bar' on {$current->alias}!\n"; // Read operation. $bar = $client->get('foo'); $current = $client->getConnection()->getCurrent()->getParameters(); echo "We just fetched 'foo' from {$current->alias} and its value is '$bar'.\n"; /* OUTPUT: Does 'foo' exist on slave? yes. Now 'foo' has been set to 'bar' on master! We just fetched 'foo' from master and its value is 'bar'. */ predis-0.8.3/examples/MasterSlaveReplicationComplex.php000066400000000000000000000051561211043230100233010ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require 'SharedConfigurations.php'; // Predis allows to set Lua scripts as read-only operations in the context of // replication. This works for both EVAL and EVALSHA and also for the client-side // abstraction built upon them (Predis\Command\ScriptedCommand). This example // shows a slightly more complex configuration that injects a new scripted command // in the server profile used by the new client instance and marks it marks it as // a read-only operation for replication so that it will be executed on slaves. use Predis\Command\ScriptedCommand; use Predis\Connection\MasterSlaveReplication; use Predis\Profile\ServerProfile; use Predis\Replication\ReplicationStrategy; // ------------------------------------------------------------------------- // // Define a new scripted command that returns all the fields // of a variable number of hashes with a single roundtrip. class HashMultipleGetAll extends ScriptedCommand { const BODY = << function ($options, $option) { $profile = $options->getDefault($option); $profile->defineCommand('hmgetall', 'HashMultipleGetAll'); return $profile; }, 'replication' => function ($options) { $strategy = new ReplicationStrategy(); $strategy->setScriptReadOnly(HashMultipleGetAll::BODY); $replication = new MasterSlaveReplication($strategy); return $replication; }, ); // ------------------------------------------------------------------------- // $client = new Predis\Client($parameters, $options); // Execute the following commands on the master server using redis-cli: // $ ./redis-cli HMSET metavars foo bar hoge piyo // $ ./redis-cli HMSET servers master host1 slave host2 $hashes = $client->hmgetall('metavars', 'servers'); $replication = $client->getConnection(); $stillOnSlave = $replication->getCurrent() === $replication->getConnectionById('slave'); echo "Is still on slave? ", $stillOnSlave ? 'YES' : 'NO', "!\n"; var_export($hashes); predis-0.8.3/examples/MonitorContext.php000066400000000000000000000030271211043230100203200ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require 'SharedConfigurations.php'; // This is a basic example on how to use the Predis\MonitorContext class. // You can use redis-cli to send commands to the same Redis instance your client is // connected to, and then type "ECHO QUIT_MONITOR" in redis-cli when you want to // exit the monitor loop and terminate this script in a graceful way. // Create a client and disable r/w timeout on the socket. $client = new Predis\Client($single_server + array('read_write_timeout' => 0)); // Use only one instance of DateTime, we will update the timestamp later. $timestamp = new DateTime(); foreach (($monitor = $client->monitor()) as $event) { $timestamp->setTimestamp((int) $event->timestamp); // If we notice a ECHO command with the message QUIT_MONITOR, we close the // monitor context and then break the loop. if ($event->command === 'ECHO' && $event->arguments === '"QUIT_MONITOR"') { echo "Exiting the monitor loop...\n"; $monitor->closeContext(); break; } echo "* Received {$event->command} on DB {$event->database} at {$timestamp->format(DateTime::W3C)}\n"; if (isset($event->arguments)) { echo " Arguments: {$event->arguments}\n"; } } // Say goodbye :-) $info = $client->info(); print_r("Goodbye from Redis v{$info['redis_version']}!\n"); predis-0.8.3/examples/MultiBulkReplyIterators.php000066400000000000000000000034311211043230100221440ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require 'SharedConfigurations.php'; // Operations such as LRANGE, ZRANGE and others can potentially generate replies // containing a huge number of items. In some corner cases, such replies might // end up exhausting the maximum allowed memory allocated for a PHP process. // Multibulk iterators can be handy because they allow you to stream multibulk // replies using plain old PHP iterators, making it possible to iterate them with // a classic `foreach` loop and avoiding to consume an excessive amount of memory. // // PS: please note that multibulk iterators are supported only by the standard // connection backend class (Predis\Connection\StreamConnection) and not the // phpiredis-based one (Predis\Connection\PhpiredisConnection). // Create a client and force the connection to use iterable multibulk responses. $client = new Predis\Client($single_server + array('iterable_multibulk' => true)); // Prepare an hash with some fields and their respective values. $client->hmset('metavars', array('foo' => 'bar', 'hoge' => 'piyo', 'lol' => 'wut')); // By default multibulk iterators iterate over the reply as a list of items... foreach ($client->hgetall('metavars') as $index => $item) { echo "[$index] $item\n"; } /* OUTPUT: [0] foo [1] bar [2] hoge [3] piyo [4] lol [5] wut */ // ... but certain multibulk replies are better represented as lists of tuples. foreach ($client->hgetall('metavars')->asTuple() as $index => $kv) { list($key, $value) = $kv; echo "[$index] $key => $value\n"; } /* OUTPUT: [0] foo => bar [1] hoge => piyo [2] lol => wut */ predis-0.8.3/examples/MultiExecTransactionsWithCAS.php000066400000000000000000000027371211043230100230060ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require 'SharedConfigurations.php'; // This is an implementation of an atomic client-side ZPOP using the support for // check-and-set (CAS) operations with MULTI/EXEC transactions, as described in // "WATCH explained" from http://redis.io/topics/transactions // // First, populate your database with a tiny sample data set: // // ./redis-cli // SELECT 15 // ZADD zset 1 a // ZADD zset 2 b // ZADD zset 3 c function zpop($client, $key) { $element = null; $options = array( 'cas' => true, // Initialize with support for CAS operations 'watch' => $key, // Key that needs to be WATCHed to detect changes 'retry' => 3, // Number of retries on aborted transactions, after // which the client bails out with an exception. ); $client->multiExec($options, function ($tx) use ($key, &$element) { @list($element) = $tx->zrange($key, 0, 0); if (isset($element)) { $tx->multi(); // With CAS, MULTI *must* be explicitly invoked. $tx->zrem($key, $element); } }); return $element; } $client = new Predis\Client($single_server); $zpopped = zpop($client, 'zset'); echo isset($zpopped) ? "ZPOPed $zpopped" : "Nothing to ZPOP!", "\n"; predis-0.8.3/examples/MultipleSetAndGet.php000066400000000000000000000013721211043230100206570ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require 'SharedConfigurations.php'; // redis can set keys and their relative values in one go // using MSET, then the same values can be retrieved with // a single command using MGET. $mkv = array( 'usr:0001' => 'First user', 'usr:0002' => 'Second user', 'usr:0003' => 'Third user' ); $client = new Predis\Client($single_server); $client->mset($mkv); $retval = $client->mget(array_keys($mkv)); print_r($retval); /* OUTPUT: Array ( [0] => First user [1] => Second user [2] => Third user ) */ predis-0.8.3/examples/PipelineContext.php000066400000000000000000000016351211043230100204410ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require 'SharedConfigurations.php'; // When you have a whole set of consecutive commands to send to // a redis server, you can use a pipeline to improve performances. $client = new Predis\Client($single_server); $replies = $client->pipeline(function ($pipe) { $pipe->ping(); $pipe->flushdb(); $pipe->incrby('counter', 10); $pipe->incrby('counter', 30); $pipe->exists('counter'); $pipe->get('counter'); $pipe->mget('does_not_exist', 'counter'); }); print_r($replies); /* OUTPUT: Array ( [0] => 1 [1] => 1 [2] => 10 [3] => 40 [4] => 1 [5] => 40 [6] => Array ( [0] => [1] => 40 ) ) */ predis-0.8.3/examples/PubSubContext.php000066400000000000000000000036441211043230100200760ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require 'SharedConfigurations.php'; // Redis 2.0 features new commands that allow clients to subscribe for // events published on certain channels (PUBSUB). // Create a client and disable r/w timeout on the socket $client = new Predis\Client($single_server + array('read_write_timeout' => 0)); // Initialize a new pubsub context $pubsub = $client->pubSub(); // Subscribe to your channels $pubsub->subscribe('control_channel', 'notifications'); // Start processing the pubsup messages. Open a terminal and use redis-cli // to push messages to the channels. Examples: // ./redis-cli PUBLISH notifications "this is a test" // ./redis-cli PUBLISH control_channel quit_loop foreach ($pubsub as $message) { switch ($message->kind) { case 'subscribe': echo "Subscribed to {$message->channel}\n"; break; case 'message': if ($message->channel == 'control_channel') { if ($message->payload == 'quit_loop') { echo "Aborting pubsub loop...\n"; $pubsub->unsubscribe(); } else { echo "Received an unrecognized command: {$message->payload}.\n"; } } else { echo "Received the following message from {$message->channel}:\n", " {$message->payload}\n\n"; } break; } } // Always unset the pubsub context instance when you are done! The // class destructor will take care of cleanups and prevent protocol // desynchronizations between the client and the server. unset($pubsub); // Say goodbye :-) $info = $client->info(); print_r("Goodbye from Redis v{$info['redis_version']}!\n"); predis-0.8.3/examples/ServerSideScripting.php000066400000000000000000000031061211043230100212600ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require 'SharedConfigurations.php'; // This example will not work with versions of Redis < 2.6. // // Additionally to the EVAL command defined in the current development profile, the new // Predis\Command\ScriptedCommand base class can be used to build an higher abstraction // for our "scripted" commands so that they will appear just like any other command on // the client-side. This is a quick example used to implement INCREX. use Predis\Command\ScriptedCommand; class IncrementExistingKeysBy extends ScriptedCommand { public function getKeysCount() { // Tell Predis to use all the arguments but the last one as arguments // for KEYS. The last one will be used to populate ARGV. return -1; } public function getScript() { return <<getProfile()->defineCommand('increxby', 'IncrementExistingKeysBy'); $client->mset('foo', 10, 'foobar', 100); var_export($client->increxby('foo', 'foofoo', 'foobar', 50)); /* array ( 0 => 60, 1 => NULL, 2 => 150, ) */ predis-0.8.3/examples/SessionHandler.php000066400000000000000000000031721211043230100202460ustar00rootroot00000000000000= 5.4 but can be used on PHP 5.3 if a polyfill for // SessionHandlerInterface (see http://www.php.net/class.sessionhandlerinterface.php) // is provided either by you or an external package like `symfony/http-foundation`. if (!interface_exists('SessionHandlerInterface')) { die("ATTENTION: the session handler implemented by Predis needs PHP >= 5.4.0 or a polyfill ". "for \SessionHandlerInterface either provided by you or an external package.\n"); } // Instantiate a new client just like you would normally do. We'll prefix our session keys here. $client = new Predis\Client($single_server, array('prefix' => 'sessions:')); // Set `gc_maxlifetime` so that a session will be expired after 5 seconds since last access. $handler = new Predis\Session\SessionHandler($client, array('gc_maxlifetime' => 5)); // Register our session handler (it uses `session_set_save_handler()` internally). $handler->register(); // Set a fixed session ID just for the sake of our example. session_id('example_session_id'); session_start(); if (isset($_SESSION['foo'])) { echo "Session has `foo` set to {$_SESSION['foo']}\n"; } else { $_SESSION['foo'] = $value = mt_rand(); echo "Empty session, `foo` has been set with $value\n"; } predis-0.8.3/examples/SharedConfigurations.php000066400000000000000000000012511211043230100214420ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require __DIR__.'/../autoload.php'; $single_server = array( 'host' => '127.0.0.1', 'port' => 6379, 'database' => 15 ); $multiple_servers = array( array( 'host' => '127.0.0.1', 'port' => 6379, 'database' => 15, 'alias' => 'first', ), array( 'host' => '127.0.0.1', 'port' => 6380, 'database' => 15, 'alias' => 'second', ), ); predis-0.8.3/examples/SimpleDebuggableConnection.php000066400000000000000000000040731211043230100225410ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require 'SharedConfigurations.php'; use Predis\Command\CommandInterface; use Predis\Connection\StreamConnection; class SimpleDebuggableConnection extends StreamConnection { private $tstart = 0; private $debugBuffer = array(); public function connect() { $this->tstart = microtime(true); parent::connect(); } private function storeDebug(CommandInterface $command, $direction) { $firtsArg = $command->getArgument(0); $timestamp = round(microtime(true) - $this->tstart, 4); $debug = $command->getId(); $debug .= isset($firtsArg) ? " $firtsArg " : ' '; $debug .= "$direction $this"; $debug .= " [{$timestamp}s]"; $this->debugBuffer[] = $debug; } public function writeCommand(CommandInterface $command) { parent::writeCommand($command); $this->storeDebug($command, '->'); } public function readResponse(CommandInterface $command) { $reply = parent::readResponse($command); $this->storeDebug($command, '<-'); return $reply; } public function getDebugBuffer() { return $this->debugBuffer; } } $options = array( 'connections' => array( 'tcp' => 'SimpleDebuggableConnection', ), ); $client = new Predis\Client($single_server, $options); $client->set('foo', 'bar'); $client->get('foo'); $client->info(); print_r($client->getConnection()->getDebugBuffer()); /* OUTPUT: Array ( [0] => SELECT 15 -> 127.0.0.1:6379 [0.0008s] [1] => SELECT 15 <- 127.0.0.1:6379 [0.0012s] [2] => SET foo -> 127.0.0.1:6379 [0.0014s] [3] => SET foo <- 127.0.0.1:6379 [0.0014s] [4] => GET foo -> 127.0.0.1:6379 [0.0016s] [5] => GET foo <- 127.0.0.1:6379 [0.0018s] [6] => INFO -> 127.0.0.1:6379 [0.002s] [7] => INFO <- 127.0.0.1:6379 [0.0025s] ) */ predis-0.8.3/examples/SimpleSetAndGet.php000066400000000000000000000007371211043230100203210ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require 'SharedConfigurations.php'; // simple set and get scenario $client = new Predis\Client($single_server); $client->set('library', 'predis'); $retval = $client->get('library'); var_dump($retval); /* OUTPUT string(6) "predis" */ predis-0.8.3/lib/000077500000000000000000000000001211043230100135415ustar00rootroot00000000000000predis-0.8.3/lib/Predis/000077500000000000000000000000001211043230100147675ustar00rootroot00000000000000predis-0.8.3/lib/Predis/Autoloader.php000066400000000000000000000032471211043230100176050ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis; /** * Implements a lightweight PSR-0 compliant autoloader. * * @author Eric Naeseth * @author Daniele Alessandri */ class Autoloader { private $directory; private $prefix; private $prefixLength; /** * @param string $baseDirectory Base directory where the source files are located. */ public function __construct($baseDirectory = __DIR__) { $this->directory = $baseDirectory; $this->prefix = __NAMESPACE__ . '\\'; $this->prefixLength = strlen($this->prefix); } /** * Registers the autoloader class with the PHP SPL autoloader. * * @param boolean $prepend Prepend the autoloader on the stack instead of appending it. */ public static function register($prepend = false) { spl_autoload_register(array(new self, 'autoload'), true, $prepend); } /** * Loads a class from a file using its fully qualified name. * * @param string $className Fully qualified name of a class. */ public function autoload($className) { if (0 === strpos($className, $this->prefix)) { $parts = explode('\\', substr($className, $this->prefixLength)); $filepath = $this->directory.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $parts).'.php'; if (is_file($filepath)) { require($filepath); } } } } predis-0.8.3/lib/Predis/BasicClientInterface.php000066400000000000000000000013031211043230100214760ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis; use Predis\Command\CommandInterface; /** * Defines the interface of a basic client object or abstraction that * can send commands to Redis. * * @author Daniele Alessandri */ interface BasicClientInterface { /** * Executes the specified Redis command. * * @param CommandInterface $command A Redis command. * @return mixed */ public function executeCommand(CommandInterface $command); } predis-0.8.3/lib/Predis/Client.php000066400000000000000000000313731211043230100167250ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis; use Predis\Command\CommandInterface; use Predis\Command\ScriptedCommand; use Predis\Connection\AggregatedConnectionInterface; use Predis\Connection\ConnectionInterface; use Predis\Connection\ConnectionFactory; use Predis\Connection\ConnectionFactoryInterface; use Predis\Monitor\MonitorContext; use Predis\Option\ClientOptions; use Predis\Option\ClientOptionsInterface; use Predis\Pipeline\PipelineContext; use Predis\Profile\ServerProfile; use Predis\Profile\ServerProfileInterface; use Predis\PubSub\PubSubContext; use Predis\Transaction\MultiExecContext; /** * Main class that exposes the most high-level interface to interact with Redis. * * @author Daniele Alessandri */ class Client implements ClientInterface { const VERSION = '0.8.3'; private $options; private $profile; private $connection; /** * Initializes a new client with optional connection parameters and client options. * * @param mixed $parameters Connection parameters for one or multiple servers. * @param mixed $options Options that specify certain behaviours for the client. */ public function __construct($parameters = null, $options = null) { $this->options = $this->filterOptions($options); $this->profile = $this->options->profile; $this->connection = $this->initializeConnection($parameters); } /** * Creates an instance of Predis\Option\ClientOptions from various types of * arguments (string, array, Predis\Profile\ServerProfile) or returns the * passed object if it is an instance of Predis\Option\ClientOptions. * * @param mixed $options Client options. * @return ClientOptions */ protected function filterOptions($options) { if (!isset($options)) { return new ClientOptions(); } if (is_array($options)) { return new ClientOptions($options); } if ($options instanceof ClientOptionsInterface) { return $options; } throw new \InvalidArgumentException("Invalid type for client options"); } /** * Initializes one or multiple connection (cluster) objects from various * types of arguments (string, array) or returns the passed object if it * implements Predis\Connection\ConnectionInterface. * * @param mixed $parameters Connection parameters or instance. * @return ConnectionInterface */ protected function initializeConnection($parameters) { if ($parameters instanceof ConnectionInterface) { return $parameters; } if (is_array($parameters) && isset($parameters[0])) { $options = $this->options; $replication = isset($options->replication) && $options->replication; $connection = $options->{$replication ? 'replication' : 'cluster'}; return $options->connections->createAggregated($connection, $parameters); } if (is_callable($parameters)) { $connection = call_user_func($parameters, $this->options); if (!$connection instanceof ConnectionInterface) { throw new \InvalidArgumentException( 'Callable parameters must return instances of Predis\Connection\ConnectionInterface' ); } return $connection; } return $this->options->connections->create($parameters); } /** * {@inheritdoc} */ public function getProfile() { return $this->profile; } /** * {@inheritdoc} */ public function getOptions() { return $this->options; } /** * Returns the connection factory object used by the client. * * @return ConnectionFactoryInterface */ public function getConnectionFactory() { return $this->options->connections; } /** * Returns a new instance of a client for the specified connection when the * client is connected to a cluster. The new instance will use the same * options of the original client. * * @return Client */ public function getClientFor($connectionID) { if (!$connection = $this->getConnectionById($connectionID)) { throw new \InvalidArgumentException("Invalid connection ID: '$connectionID'"); } return new static($connection, $this->options); } /** * Opens the connection to the server. */ public function connect() { $this->connection->connect(); } /** * Disconnects from the server. */ public function disconnect() { $this->connection->disconnect(); } /** * Disconnects from the server. * * This method is an alias of disconnect(). */ public function quit() { $this->disconnect(); } /** * Checks if the underlying connection is connected to Redis. * * @return Boolean True means that the connection is open. * False means that the connection is closed. */ public function isConnected() { return $this->connection->isConnected(); } /** * {@inheritdoc} */ public function getConnection() { return $this->connection; } /** * Retrieves a single connection out of an aggregated connections instance. * * @param string $connectionId Index or alias of the connection. * @return SingleConnectionInterface */ public function getConnectionById($connectionId) { if (!$this->connection instanceof AggregatedConnectionInterface) { throw new NotSupportedException('Retrieving connections by ID is supported only when using aggregated connections'); } return $this->connection->getConnectionById($connectionId); } /** * Dynamically invokes a Redis command with the specified arguments. * * @param string $method The name of a Redis command. * @param array $arguments The arguments for the command. * @return mixed */ public function __call($method, $arguments) { $command = $this->profile->createCommand($method, $arguments); $response = $this->connection->executeCommand($command); if ($response instanceof ResponseObjectInterface) { if ($response instanceof ResponseErrorInterface) { $response = $this->onResponseError($command, $response); } return $response; } return $command->parseResponse($response); } /** * {@inheritdoc} */ public function createCommand($method, $arguments = array()) { return $this->profile->createCommand($method, $arguments); } /** * {@inheritdoc} */ public function executeCommand(CommandInterface $command) { $response = $this->connection->executeCommand($command); if ($response instanceof ResponseObjectInterface) { if ($response instanceof ResponseErrorInterface) { $response = $this->onResponseError($command, $response); } return $response; } return $command->parseResponse($response); } /** * Handles -ERR responses returned by Redis. * * @param CommandInterface $command The command that generated the error. * @param ResponseErrorInterface $response The error response instance. * @return mixed */ protected function onResponseError(CommandInterface $command, ResponseErrorInterface $response) { if ($command instanceof ScriptedCommand && $response->getErrorType() === 'NOSCRIPT') { $eval = $this->createCommand('eval'); $eval->setRawArguments($command->getEvalArguments()); $response = $this->executeCommand($eval); if (!$response instanceof ResponseObjectInterface) { $response = $command->parseResponse($response); } return $response; } if ($this->options->exceptions) { throw new ServerException($response->getMessage()); } return $response; } /** * Calls the specified initializer method on $this with 0, 1 or 2 arguments. * * TODO: Invert $argv and $initializer. * * @param array $argv Arguments for the initializer. * @param string $initializer The initializer method. * @return mixed */ private function sharedInitializer($argv, $initializer) { switch (count($argv)) { case 0: return $this->$initializer(); case 1: list($arg0) = $argv; return is_array($arg0) ? $this->$initializer($arg0) : $this->$initializer(null, $arg0); case 2: list($arg0, $arg1) = $argv; return $this->$initializer($arg0, $arg1); default: return $this->$initializer($this, $argv); } } /** * Creates a new pipeline context and returns it, or returns the results of * a pipeline executed inside the optionally provided callable object. * * @param mixed $arg,... Options for the context, a callable object, or both. * @return PipelineContext|array */ public function pipeline(/* arguments */) { return $this->sharedInitializer(func_get_args(), 'initPipeline'); } /** * Pipeline context initializer. * * @param array $options Options for the context. * @param mixed $callable Optional callable object used to execute the context. * @return PipelineContext|array */ protected function initPipeline(Array $options = null, $callable = null) { $executor = isset($options['executor']) ? $options['executor'] : null; if (is_callable($executor)) { $executor = call_user_func($executor, $this, $options); } $pipeline = new PipelineContext($this, $executor); $replies = $this->pipelineExecute($pipeline, $callable); return $replies; } /** * Executes a pipeline context when a callable object is passed. * * @param array $options Options of the context initialization. * @param mixed $callable Optional callable object used to execute the context. * @return PipelineContext|array */ private function pipelineExecute(PipelineContext $pipeline, $callable) { return isset($callable) ? $pipeline->execute($callable) : $pipeline; } /** * Creates a new transaction context and returns it, or returns the results of * a transaction executed inside the optionally provided callable object. * * @param mixed $arg,... Options for the context, a callable object, or both. * @return MultiExecContext|array */ public function multiExec(/* arguments */) { return $this->sharedInitializer(func_get_args(), 'initMultiExec'); } /** * Transaction context initializer. * * @param array $options Options for the context. * @param mixed $callable Optional callable object used to execute the context. * @return MultiExecContext|array */ protected function initMultiExec(Array $options = null, $callable = null) { $transaction = new MultiExecContext($this, $options ?: array()); return isset($callable) ? $transaction->execute($callable) : $transaction; } /** * Creates a new Publish / Subscribe context and returns it, or executes it * inside the optionally provided callable object. * * @param mixed $arg,... Options for the context, a callable object, or both. * @return MultiExecContext|array */ public function pubSub(/* arguments */) { return $this->sharedInitializer(func_get_args(), 'initPubSub'); } /** * Publish / Subscribe context initializer. * * @param array $options Options for the context. * @param mixed $callable Optional callable object used to execute the context. * @return PubSubContext */ protected function initPubSub(Array $options = null, $callable = null) { $pubsub = new PubSubContext($this, $options); if (!isset($callable)) { return $pubsub; } foreach ($pubsub as $message) { if (call_user_func($callable, $pubsub, $message) === false) { $pubsub->closeContext(); } } } /** * Returns a new monitor context. * * @return MonitorContext */ public function monitor() { return new MonitorContext($this); } } predis-0.8.3/lib/Predis/ClientException.php000066400000000000000000000006551211043230100206030ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis; /** * Exception class that identifies client-side errors. * * @author Daniele Alessandri */ class ClientException extends PredisException { } predis-0.8.3/lib/Predis/ClientInterface.php000066400000000000000000000031131211043230100205350ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis; use Predis\Connection\ConnectionInterface; use Predis\Option\ClientOptionsInterface; use Predis\Profile\ServerProfileInterface; /** * Interface defining the most important parts needed to create an * high-level Redis client object that can interact with other * building blocks of Predis. * * @author Daniele Alessandri */ interface ClientInterface extends BasicClientInterface { /** * Returns the server profile used by the client. * * @return ServerProfileInterface */ public function getProfile(); /** * Returns the client options specified upon initialization. * * @return ClientOptionsInterface */ public function getOptions(); /** * Opens the connection to the server. */ public function connect(); /** * Disconnects from the server. */ public function disconnect(); /** * Returns the underlying connection instance. * * @return ConnectionInterface */ public function getConnection(); /** * Creates a new instance of the specified Redis command. * * @param string $method The name of a Redis command. * @param array $arguments The arguments for the command. * @return CommandInterface */ public function createCommand($method, $arguments = array()); } predis-0.8.3/lib/Predis/Cluster/000077500000000000000000000000001211043230100164105ustar00rootroot00000000000000predis-0.8.3/lib/Predis/Cluster/CommandHashStrategyInterface.php000066400000000000000000000021121211043230100246430ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Cluster; use Predis\Command\CommandInterface; /** * Interface for classes defining the strategy used to calculate an hash * out of keys extracted from supported commands. * * This is mostly useful to support clustering via client-side sharding. * * @author Daniele Alessandri */ interface CommandHashStrategyInterface { /** * Returns the hash for the given command using the specified algorithm, or null * if the command cannot be hashed. * * @param CommandInterface $command Command to be hashed. * @return int */ public function getHash(CommandInterface $command); /** * Returns the hash for the given key using the specified algorithm. * * @param string $key Key to be hashed. * @return string */ public function getKeyHash($key); } predis-0.8.3/lib/Predis/Cluster/Distribution/000077500000000000000000000000001211043230100210675ustar00rootroot00000000000000predis-0.8.3/lib/Predis/Cluster/Distribution/DistributionStrategyInterface.php000066400000000000000000000022561211043230100276300ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Cluster\Distribution; /** * A distributor implements the logic to automatically distribute * keys among several nodes for client-side sharding. * * @author Daniele Alessandri */ interface DistributionStrategyInterface { /** * Adds a node to the distributor with an optional weight. * * @param mixed $node Node object. * @param int $weight Weight for the node. */ public function add($node, $weight = null); /** * Removes a node from the distributor. * * @param mixed $node Node object. */ public function remove($node); /** * Gets a node from the distributor using the computed hash of a key. * * @return mixed */ public function get($key); /** * Returns the underlying hash generator instance. * * @return Predis\Cluster\Hash\HashGeneratorInterface */ public function getHashGenerator(); } predis-0.8.3/lib/Predis/Cluster/Distribution/EmptyRingException.php000066400000000000000000000006711211043230100254010ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Cluster\Distribution; /** * Exception class that identifies empty rings. * * @author Daniele Alessandri */ class EmptyRingException extends \Exception { } predis-0.8.3/lib/Predis/Cluster/Distribution/HashRing.php000066400000000000000000000147661211043230100233210ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Cluster\Distribution; use Predis\Cluster\Hash\HashGeneratorInterface; /** * This class implements an hashring-based distributor that uses the same * algorithm of memcache to distribute keys in a cluster using client-side * sharding. * * @author Daniele Alessandri * @author Lorenzo Castelli */ class HashRing implements DistributionStrategyInterface, HashGeneratorInterface { const DEFAULT_REPLICAS = 128; const DEFAULT_WEIGHT = 100; private $ring; private $ringKeys; private $ringKeysCount; private $replicas; private $nodeHashCallback; private $nodes = array(); /** * @param int $replicas Number of replicas in the ring. * @param mixed $nodeHashCallback Callback returning the string used to calculate the hash of a node. */ public function __construct($replicas = self::DEFAULT_REPLICAS, $nodeHashCallback = null) { $this->replicas = $replicas; $this->nodeHashCallback = $nodeHashCallback; } /** * Adds a node to the ring with an optional weight. * * @param mixed $node Node object. * @param int $weight Weight for the node. */ public function add($node, $weight = null) { // In case of collisions in the hashes of the nodes, the node added // last wins, thus the order in which nodes are added is significant. $this->nodes[] = array('object' => $node, 'weight' => (int) $weight ?: $this::DEFAULT_WEIGHT); $this->reset(); } /** * {@inheritdoc} */ public function remove($node) { // A node is removed by resetting the ring so that it's recreated from // scratch, in order to reassign possible hashes with collisions to the // right node according to the order in which they were added in the // first place. for ($i = 0; $i < count($this->nodes); ++$i) { if ($this->nodes[$i]['object'] === $node) { array_splice($this->nodes, $i, 1); $this->reset(); break; } } } /** * Resets the distributor. */ private function reset() { unset( $this->ring, $this->ringKeys, $this->ringKeysCount ); } /** * Returns the initialization status of the distributor. * * @return Boolean */ private function isInitialized() { return isset($this->ringKeys); } /** * Calculates the total weight of all the nodes in the distributor. * * @return int */ private function computeTotalWeight() { $totalWeight = 0; foreach ($this->nodes as $node) { $totalWeight += $node['weight']; } return $totalWeight; } /** * Initializes the distributor. */ private function initialize() { if ($this->isInitialized()) { return; } if (!$this->nodes) { throw new EmptyRingException('Cannot initialize empty hashring'); } $this->ring = array(); $totalWeight = $this->computeTotalWeight(); $nodesCount = count($this->nodes); foreach ($this->nodes as $node) { $weightRatio = $node['weight'] / $totalWeight; $this->addNodeToRing($this->ring, $node, $nodesCount, $this->replicas, $weightRatio); } ksort($this->ring, SORT_NUMERIC); $this->ringKeys = array_keys($this->ring); $this->ringKeysCount = count($this->ringKeys); } /** * Implements the logic needed to add a node to the hashring. * * @param array $ring Source hashring. * @param mixed $node Node object to be added. * @param int $totalNodes Total number of nodes. * @param int $replicas Number of replicas in the ring. * @param float $weightRatio Weight ratio for the node. */ protected function addNodeToRing(&$ring, $node, $totalNodes, $replicas, $weightRatio) { $nodeObject = $node['object']; $nodeHash = $this->getNodeHash($nodeObject); $replicas = (int) round($weightRatio * $totalNodes * $replicas); for ($i = 0; $i < $replicas; $i++) { $key = crc32("$nodeHash:$i"); $ring[$key] = $nodeObject; } } /** * {@inheritdoc} */ protected function getNodeHash($nodeObject) { if ($this->nodeHashCallback === null) { return (string) $nodeObject; } return call_user_func($this->nodeHashCallback, $nodeObject); } /** * Calculates the hash for the specified value. * * @param string $value Input value. * @return int */ public function hash($value) { return crc32($value); } /** * {@inheritdoc} */ public function get($key) { return $this->ring[$this->getNodeKey($key)]; } /** * Calculates the corrisponding key of a node distributed in the hashring. * * @param int $key Computed hash of a key. * @return int */ private function getNodeKey($key) { $this->initialize(); $ringKeys = $this->ringKeys; $upper = $this->ringKeysCount - 1; $lower = 0; while ($lower <= $upper) { $index = ($lower + $upper) >> 1; $item = $ringKeys[$index]; if ($item > $key) { $upper = $index - 1; } else if ($item < $key) { $lower = $index + 1; } else { return $item; } } return $ringKeys[$this->wrapAroundStrategy($upper, $lower, $this->ringKeysCount)]; } /** * Implements a strategy to deal with wrap-around errors during binary searches. * * @param int $upper * @param int $lower * @param int $ringKeysCount * @return int */ protected function wrapAroundStrategy($upper, $lower, $ringKeysCount) { // Binary search for the last item in ringkeys with a value less or // equal to the key. If no such item exists, return the last item. return $upper >= 0 ? $upper : $ringKeysCount - 1; } /** * {@inheritdoc} */ public function getHashGenerator() { return $this; } } predis-0.8.3/lib/Predis/Cluster/Distribution/KetamaPureRing.php000066400000000000000000000036161211043230100244640ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Cluster\Distribution; /** * This class implements an hashring-based distributor that uses the same * algorithm of libketama to distribute keys in a cluster using client-side * sharding. * * @author Daniele Alessandri * @author Lorenzo Castelli */ class KetamaPureRing extends HashRing { const DEFAULT_REPLICAS = 160; /** * @param mixed $nodeHashCallback Callback returning the string used to calculate the hash of a node. */ public function __construct($nodeHashCallback = null) { parent::__construct($this::DEFAULT_REPLICAS, $nodeHashCallback); } /** * {@inheritdoc} */ protected function addNodeToRing(&$ring, $node, $totalNodes, $replicas, $weightRatio) { $nodeObject = $node['object']; $nodeHash = $this->getNodeHash($nodeObject); $replicas = (int) floor($weightRatio * $totalNodes * ($replicas / 4)); for ($i = 0; $i < $replicas; $i++) { $unpackedDigest = unpack('V4', md5("$nodeHash-$i", true)); foreach ($unpackedDigest as $key) { $ring[$key] = $nodeObject; } } } /** * {@inheritdoc} */ public function hash($value) { $hash = unpack('V', md5($value, true)); return $hash[1]; } /** * {@inheritdoc} */ protected function wrapAroundStrategy($upper, $lower, $ringKeysCount) { // Binary search for the first item in _ringkeys with a value greater // or equal to the key. If no such item exists, return the first item. return $lower < $ringKeysCount ? $lower : 0; } } predis-0.8.3/lib/Predis/Cluster/Hash/000077500000000000000000000000001211043230100172735ustar00rootroot00000000000000predis-0.8.3/lib/Predis/Cluster/Hash/CRC16HashGenerator.php000066400000000000000000000061701211043230100232410ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Cluster\Hash; /** * This class implements the CRC-CCITT-16 algorithm used by redis-cluster. * * @author Daniele Alessandri */ class CRC16HashGenerator implements HashGeneratorInterface { private static $CCITT_16 = array( 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0, ); /** * {@inheritdoc} */ public function hash($value) { // CRC-CCITT-16 algorithm $crc = 0; $CCITT_16 = self::$CCITT_16; $strlen = strlen($value); for ($i = 0; $i < $strlen; $i++) { $crc = (($crc << 8) ^ $CCITT_16[($crc >> 8) ^ ord($value[$i])]) & 0xFFFF; } return $crc; } } predis-0.8.3/lib/Predis/Cluster/Hash/HashGeneratorInterface.php000066400000000000000000000013171211043230100243610ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Cluster\Hash; /** * A generator of node keys implements the logic used to calculate the hash of * a key to distribute the respective operations among nodes. * * @author Daniele Alessandri */ interface HashGeneratorInterface { /** * Generates an hash that is used by the distributor algorithm * * @param string $value Value used to generate the hash. * @return int */ public function hash($value); } predis-0.8.3/lib/Predis/Cluster/PredisClusterHashStrategy.php000066400000000000000000000324461211043230100242510ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Cluster; use Predis\Cluster\Hash\HashGeneratorInterface; use Predis\Command\CommandInterface; use Predis\Command\ScriptedCommand; /** * Default class used by Predis for client-side sharding to calculate * hashes out of keys of supported commands. * * @author Daniele Alessandri */ class PredisClusterHashStrategy implements CommandHashStrategyInterface { private $commands; private $hashGenerator; /** * @param HashGeneratorInterface $hashGenerator Hash generator instance. */ public function __construct(HashGeneratorInterface $hashGenerator) { $this->commands = $this->getDefaultCommands(); $this->hashGenerator = $hashGenerator; } /** * Returns the default map of supported commands with their handlers. * * @return array */ protected function getDefaultCommands() { $keyIsFirstArgument = array($this, 'getKeyFromFirstArgument'); $keysAreAllArguments = array($this, 'getKeyFromAllArguments'); return array( /* commands operating on the key space */ 'EXISTS' => $keyIsFirstArgument, 'DEL' => $keysAreAllArguments, 'TYPE' => $keyIsFirstArgument, 'EXPIRE' => $keyIsFirstArgument, 'EXPIREAT' => $keyIsFirstArgument, 'PERSIST' => $keyIsFirstArgument, 'PEXPIRE' => $keyIsFirstArgument, 'PEXPIREAT' => $keyIsFirstArgument, 'TTL' => $keyIsFirstArgument, 'PTTL' => $keyIsFirstArgument, 'SORT' => $keyIsFirstArgument, // TODO /* commands operating on string values */ 'APPEND' => $keyIsFirstArgument, 'DECR' => $keyIsFirstArgument, 'DECRBY' => $keyIsFirstArgument, 'GET' => $keyIsFirstArgument, 'GETBIT' => $keyIsFirstArgument, 'MGET' => $keysAreAllArguments, 'SET' => $keyIsFirstArgument, 'GETRANGE' => $keyIsFirstArgument, 'GETSET' => $keyIsFirstArgument, 'INCR' => $keyIsFirstArgument, 'INCRBY' => $keyIsFirstArgument, 'SETBIT' => $keyIsFirstArgument, 'SETEX' => $keyIsFirstArgument, 'MSET' => array($this, 'getKeyFromInterleavedArguments'), 'MSETNX' => array($this, 'getKeyFromInterleavedArguments'), 'SETNX' => $keyIsFirstArgument, 'SETRANGE' => $keyIsFirstArgument, 'STRLEN' => $keyIsFirstArgument, 'SUBSTR' => $keyIsFirstArgument, 'BITOP' => array($this, 'getKeyFromBitOp'), 'BITCOUNT' => $keyIsFirstArgument, /* commands operating on lists */ 'LINSERT' => $keyIsFirstArgument, 'LINDEX' => $keyIsFirstArgument, 'LLEN' => $keyIsFirstArgument, 'LPOP' => $keyIsFirstArgument, 'RPOP' => $keyIsFirstArgument, 'RPOPLPUSH' => $keysAreAllArguments, 'BLPOP' => array($this, 'getKeyFromBlockingListCommands'), 'BRPOP' => array($this, 'getKeyFromBlockingListCommands'), 'BRPOPLPUSH' => array($this, 'getKeyFromBlockingListCommands'), 'LPUSH' => $keyIsFirstArgument, 'LPUSHX' => $keyIsFirstArgument, 'RPUSH' => $keyIsFirstArgument, 'RPUSHX' => $keyIsFirstArgument, 'LRANGE' => $keyIsFirstArgument, 'LREM' => $keyIsFirstArgument, 'LSET' => $keyIsFirstArgument, 'LTRIM' => $keyIsFirstArgument, /* commands operating on sets */ 'SADD' => $keyIsFirstArgument, 'SCARD' => $keyIsFirstArgument, 'SDIFF' => $keysAreAllArguments, 'SDIFFSTORE' => $keysAreAllArguments, 'SINTER' => $keysAreAllArguments, 'SINTERSTORE' => $keysAreAllArguments, 'SUNION' => $keysAreAllArguments, 'SUNIONSTORE' => $keysAreAllArguments, 'SISMEMBER' => $keyIsFirstArgument, 'SMEMBERS' => $keyIsFirstArgument, 'SPOP' => $keyIsFirstArgument, 'SRANDMEMBER' => $keyIsFirstArgument, 'SREM' => $keyIsFirstArgument, /* commands operating on sorted sets */ 'ZADD' => $keyIsFirstArgument, 'ZCARD' => $keyIsFirstArgument, 'ZCOUNT' => $keyIsFirstArgument, 'ZINCRBY' => $keyIsFirstArgument, 'ZINTERSTORE' => array($this, 'getKeyFromZsetAggregationCommands'), 'ZRANGE' => $keyIsFirstArgument, 'ZRANGEBYSCORE' => $keyIsFirstArgument, 'ZRANK' => $keyIsFirstArgument, 'ZREM' => $keyIsFirstArgument, 'ZREMRANGEBYRANK' => $keyIsFirstArgument, 'ZREMRANGEBYSCORE' => $keyIsFirstArgument, 'ZREVRANGE' => $keyIsFirstArgument, 'ZREVRANGEBYSCORE' => $keyIsFirstArgument, 'ZREVRANK' => $keyIsFirstArgument, 'ZSCORE' => $keyIsFirstArgument, 'ZUNIONSTORE' => array($this, 'getKeyFromZsetAggregationCommands'), /* commands operating on hashes */ 'HDEL' => $keyIsFirstArgument, 'HEXISTS' => $keyIsFirstArgument, 'HGET' => $keyIsFirstArgument, 'HGETALL' => $keyIsFirstArgument, 'HMGET' => $keyIsFirstArgument, 'HINCRBY' => $keyIsFirstArgument, 'HINCRBYFLOAT' => $keyIsFirstArgument, 'HKEYS' => $keyIsFirstArgument, 'HLEN' => $keyIsFirstArgument, 'HSET' => $keyIsFirstArgument, 'HSETNX' => $keyIsFirstArgument, 'HVALS' => $keyIsFirstArgument, /* scripting */ 'EVAL' => array($this, 'getKeyFromScriptingCommands'), 'EVALSHA' => array($this, 'getKeyFromScriptingCommands'), ); } /** * Returns the list of IDs for the supported commands. * * @return array */ public function getSupportedCommands() { return array_keys($this->commands); } /** * Sets an handler for the specified command ID. * * The signature of the callback must have a single parameter * of type Predis\Command\CommandInterface. * * When the callback argument is omitted or NULL, the previously * associated handler for the specified command ID is removed. * * @param string $commandId The ID of the command to be handled. * @param mixed $callback A valid callable object or NULL. */ public function setCommandHandler($commandId, $callback = null) { $commandId = strtoupper($commandId); if (!isset($callback)) { unset($this->commands[$commandId]); return; } if (!is_callable($callback)) { throw new \InvalidArgumentException("Callback must be a valid callable object or NULL"); } $this->commands[$commandId] = $callback; } /** * Extracts the key from the first argument of a command instance. * * @param CommandInterface $command Command instance. * @return string */ protected function getKeyFromFirstArgument(CommandInterface $command) { return $command->getArgument(0); } /** * Extracts the key from a command with multiple keys only when all keys * in the arguments array produce the same hash. * * @param CommandInterface $command Command instance. * @return string */ protected function getKeyFromAllArguments(CommandInterface $command) { $arguments = $command->getArguments(); if ($this->checkSameHashForKeys($arguments)) { return $arguments[0]; } } /** * Extracts the key from a command with multiple keys only when all keys * in the arguments array produce the same hash. * * @param CommandInterface $command Command instance. * @return string */ protected function getKeyFromInterleavedArguments(CommandInterface $command) { $arguments = $command->getArguments(); $keys = array(); for ($i = 0; $i < count($arguments); $i += 2) { $keys[] = $arguments[$i]; } if ($this->checkSameHashForKeys($keys)) { return $arguments[0]; } } /** * Extracts the key from BLPOP and BRPOP commands. * * @param CommandInterface $command Command instance. * @return string */ protected function getKeyFromBlockingListCommands(CommandInterface $command) { $arguments = $command->getArguments(); if ($this->checkSameHashForKeys(array_slice($arguments, 0, count($arguments) - 1))) { return $arguments[0]; } } /** * Extracts the key from BITOP command. * * @param CommandInterface $command Command instance. * @return string */ protected function getKeyFromBitOp(CommandInterface $command) { $arguments = $command->getArguments(); if ($this->checkSameHashForKeys(array_slice($arguments, 1, count($arguments)))) { return $arguments[1]; } } /** * Extracts the key from ZINTERSTORE and ZUNIONSTORE commands. * * @param CommandInterface $command Command instance. * @return string */ protected function getKeyFromZsetAggregationCommands(CommandInterface $command) { $arguments = $command->getArguments(); $keys = array_merge(array($arguments[0]), array_slice($arguments, 2, $arguments[1])); if ($this->checkSameHashForKeys($keys)) { return $arguments[0]; } } /** * Extracts the key from EVAL and EVALSHA commands. * * @param CommandInterface $command Command instance. * @return string */ protected function getKeyFromScriptingCommands(CommandInterface $command) { if ($command instanceof ScriptedCommand) { $keys = $command->getKeys(); } else { $keys = array_slice($args = $command->getArguments(), 2, $args[1]); } if ($keys && $this->checkSameHashForKeys($keys)) { return $keys[0]; } } /** * {@inheritdoc} */ public function getHash(CommandInterface $command) { $hash = $command->getHash(); if (!isset($hash) && isset($this->commands[$cmdID = $command->getId()])) { $key = call_user_func($this->commands[$cmdID], $command); if (isset($key)) { $hash = $this->getKeyHash($key); $command->setHash($hash); } } return $hash; } /** * {@inheritdoc} */ public function getKeyHash($key) { $key = $this->extractKeyTag($key); $hash = $this->hashGenerator->hash($key); return $hash; } /** * Checks if the specified array of keys will generate the same hash. * * @param array $keys Array of keys. * @return Boolean */ protected function checkSameHashForKeys(Array $keys) { if (!$count = count($keys)) { return false; } $currentKey = $this->extractKeyTag($keys[0]); for ($i = 1; $i < $count; $i++) { $nextKey = $this->extractKeyTag($keys[$i]); if ($currentKey !== $nextKey) { return false; } $currentKey = $nextKey; } return true; } /** * Returns only the hashable part of a key (delimited by "{...}"), or the * whole key if a key tag is not found in the string. * * @param string $key A key. * @return string */ protected function extractKeyTag($key) { if (false !== $start = strpos($key, '{')) { if (false !== $end = strpos($key, '}', $start)) { $key = substr($key, ++$start, $end - $start); } } return $key; } } predis-0.8.3/lib/Predis/Cluster/RedisClusterHashStrategy.php000066400000000000000000000243571211043230100240730ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Cluster; use Predis\Cluster\Hash\CRC16HashGenerator; use Predis\Command\CommandInterface; /** * Default class used by Predis to calculate hashes out of keys of * commands supported by redis-cluster. * * @author Daniele Alessandri */ class RedisClusterHashStrategy implements CommandHashStrategyInterface { private $commands; private $hashGenerator; /** * */ public function __construct() { $this->commands = $this->getDefaultCommands(); $this->hashGenerator = new CRC16HashGenerator(); } /** * Returns the default map of supported commands with their handlers. * * @return array */ protected function getDefaultCommands() { $keyIsFirstArgument = array($this, 'getKeyFromFirstArgument'); return array( /* commands operating on the key space */ 'EXISTS' => $keyIsFirstArgument, 'DEL' => array($this, 'getKeyFromAllArguments'), 'TYPE' => $keyIsFirstArgument, 'EXPIRE' => $keyIsFirstArgument, 'EXPIREAT' => $keyIsFirstArgument, 'PERSIST' => $keyIsFirstArgument, 'PEXPIRE' => $keyIsFirstArgument, 'PEXPIREAT' => $keyIsFirstArgument, 'TTL' => $keyIsFirstArgument, 'PTTL' => $keyIsFirstArgument, 'SORT' => $keyIsFirstArgument, // TODO /* commands operating on string values */ 'APPEND' => $keyIsFirstArgument, 'DECR' => $keyIsFirstArgument, 'DECRBY' => $keyIsFirstArgument, 'GET' => $keyIsFirstArgument, 'GETBIT' => $keyIsFirstArgument, 'MGET' => array($this, 'getKeyFromAllArguments'), 'SET' => $keyIsFirstArgument, 'GETRANGE' => $keyIsFirstArgument, 'GETSET' => $keyIsFirstArgument, 'INCR' => $keyIsFirstArgument, 'INCRBY' => $keyIsFirstArgument, 'SETBIT' => $keyIsFirstArgument, 'SETEX' => $keyIsFirstArgument, 'MSET' => array($this, 'getKeyFromInterleavedArguments'), 'MSETNX' => array($this, 'getKeyFromInterleavedArguments'), 'SETNX' => $keyIsFirstArgument, 'SETRANGE' => $keyIsFirstArgument, 'STRLEN' => $keyIsFirstArgument, 'SUBSTR' => $keyIsFirstArgument, 'BITCOUNT' => $keyIsFirstArgument, /* commands operating on lists */ 'LINSERT' => $keyIsFirstArgument, 'LINDEX' => $keyIsFirstArgument, 'LLEN' => $keyIsFirstArgument, 'LPOP' => $keyIsFirstArgument, 'RPOP' => $keyIsFirstArgument, 'BLPOP' => array($this, 'getKeyFromBlockingListCommands'), 'BRPOP' => array($this, 'getKeyFromBlockingListCommands'), 'LPUSH' => $keyIsFirstArgument, 'LPUSHX' => $keyIsFirstArgument, 'RPUSH' => $keyIsFirstArgument, 'RPUSHX' => $keyIsFirstArgument, 'LRANGE' => $keyIsFirstArgument, 'LREM' => $keyIsFirstArgument, 'LSET' => $keyIsFirstArgument, 'LTRIM' => $keyIsFirstArgument, /* commands operating on sets */ 'SADD' => $keyIsFirstArgument, 'SCARD' => $keyIsFirstArgument, 'SISMEMBER' => $keyIsFirstArgument, 'SMEMBERS' => $keyIsFirstArgument, 'SPOP' => $keyIsFirstArgument, 'SRANDMEMBER' => $keyIsFirstArgument, 'SREM' => $keyIsFirstArgument, /* commands operating on sorted sets */ 'ZADD' => $keyIsFirstArgument, 'ZCARD' => $keyIsFirstArgument, 'ZCOUNT' => $keyIsFirstArgument, 'ZINCRBY' => $keyIsFirstArgument, 'ZRANGE' => $keyIsFirstArgument, 'ZRANGEBYSCORE' => $keyIsFirstArgument, 'ZRANK' => $keyIsFirstArgument, 'ZREM' => $keyIsFirstArgument, 'ZREMRANGEBYRANK' => $keyIsFirstArgument, 'ZREMRANGEBYSCORE' => $keyIsFirstArgument, 'ZREVRANGE' => $keyIsFirstArgument, 'ZREVRANGEBYSCORE' => $keyIsFirstArgument, 'ZREVRANK' => $keyIsFirstArgument, 'ZSCORE' => $keyIsFirstArgument, /* commands operating on hashes */ 'HDEL' => $keyIsFirstArgument, 'HEXISTS' => $keyIsFirstArgument, 'HGET' => $keyIsFirstArgument, 'HGETALL' => $keyIsFirstArgument, 'HMGET' => $keyIsFirstArgument, 'HINCRBY' => $keyIsFirstArgument, 'HINCRBYFLOAT' => $keyIsFirstArgument, 'HKEYS' => $keyIsFirstArgument, 'HLEN' => $keyIsFirstArgument, 'HSET' => $keyIsFirstArgument, 'HSETNX' => $keyIsFirstArgument, 'HVALS' => $keyIsFirstArgument, /* scripting */ 'EVAL' => array($this, 'getKeyFromScriptingCommands'), 'EVALSHA' => array($this, 'getKeyFromScriptingCommands'), ); } /** * Returns the list of IDs for the supported commands. * * @return array */ public function getSupportedCommands() { return array_keys($this->commands); } /** * Sets an handler for the specified command ID. * * The signature of the callback must have a single parameter * of type Predis\Command\CommandInterface. * * When the callback argument is omitted or NULL, the previously * associated handler for the specified command ID is removed. * * @param string $commandId The ID of the command to be handled. * @param mixed $callback A valid callable object or NULL. */ public function setCommandHandler($commandId, $callback = null) { $commandId = strtoupper($commandId); if (!isset($callback)) { unset($this->commands[$commandId]); return; } if (!is_callable($callback)) { throw new \InvalidArgumentException("Callback must be a valid callable object or NULL"); } $this->commands[$commandId] = $callback; } /** * Extracts the key from the first argument of a command instance. * * @param CommandInterface $command Command instance. * @return string */ protected function getKeyFromFirstArgument(CommandInterface $command) { return $command->getArgument(0); } /** * Extracts the key from a command that can accept multiple keys ensuring * that only one key is actually specified to comply with redis-cluster. * * @param CommandInterface $command Command instance. * @return string */ protected function getKeyFromAllArguments(CommandInterface $command) { $arguments = $command->getArguments(); if (count($arguments) === 1) { return $arguments[0]; } } /** * Extracts the key from a command that can accept multiple keys ensuring * that only one key is actually specified to comply with redis-cluster. * * @param CommandInterface $command Command instance. * @return string */ protected function getKeyFromInterleavedArguments(CommandInterface $command) { $arguments = $command->getArguments(); if (count($arguments) === 2) { return $arguments[0]; } } /** * Extracts the key from BLPOP and BRPOP commands ensuring that only one key * is actually specified to comply with redis-cluster. * * @param CommandInterface $command Command instance. * @return string */ protected function getKeyFromBlockingListCommands(CommandInterface $command) { $arguments = $command->getArguments(); if (count($arguments) === 2) { return $arguments[0]; } } /** * Extracts the key from EVAL and EVALSHA commands. * * @param CommandInterface $command Command instance. * @return string */ protected function getKeyFromScriptingCommands(CommandInterface $command) { if ($command instanceof ScriptedCommand) { $keys = $command->getKeys(); } else { $keys = array_slice($args = $command->getArguments(), 2, $args[1]); } if (count($keys) === 1) { return $keys[0]; } } /** * {@inheritdoc} */ public function getHash(CommandInterface $command) { $hash = $command->getHash(); if (!isset($hash) && isset($this->commands[$cmdID = $command->getId()])) { $key = call_user_func($this->commands[$cmdID], $command); if (isset($key)) { $hash = $this->hashGenerator->hash($key); $command->setHash($hash); } } return $hash; } /** * {@inheritdoc} */ public function getKeyHash($key) { return $this->hashGenerator->hash($key); } } predis-0.8.3/lib/Predis/Command/000077500000000000000000000000001211043230100163455ustar00rootroot00000000000000predis-0.8.3/lib/Predis/Command/AbstractCommand.php000066400000000000000000000070101211043230100221160ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * Base class for Redis commands. * * @author Daniele Alessandri */ abstract class AbstractCommand implements CommandInterface { private $hash; private $arguments = array(); /** * Returns a filtered array of the arguments. * * @param array $arguments List of arguments. * @return array */ protected function filterArguments(Array $arguments) { return $arguments; } /** * {@inheritdoc} */ public function setArguments(Array $arguments) { $this->arguments = $this->filterArguments($arguments); unset($this->hash); } /** * Sets the arguments array without filtering. * * @param array $arguments List of arguments. */ public function setRawArguments(Array $arguments) { $this->arguments = $arguments; unset($this->hash); } /** * {@inheritdoc} */ public function getArguments() { return $this->arguments; } /** * Gets the argument from the arguments list at the specified index. * * @param array $arguments Position of the argument. */ public function getArgument($index) { if (isset($this->arguments[$index])) { return $this->arguments[$index]; } } /** * {@inheritdoc} */ public function setHash($hash) { $this->hash = $hash; } /** * {@inheritdoc} */ public function getHash() { if (isset($this->hash)) { return $this->hash; } } /** * {@inheritdoc} */ public function parseResponse($data) { return $data; } /** * Helper function used to reduce a list of arguments to a string. * * @param string $accumulator Temporary string. * @param string $argument Current argument. * @return string */ protected function toStringArgumentReducer($accumulator, $argument) { if (strlen($argument) > 32) { $argument = substr($argument, 0, 32) . '[...]'; } $accumulator .= " $argument"; return $accumulator; } /** * Returns a partial string representation of the command with its arguments. * * @return string */ public function __toString() { return array_reduce( $this->getArguments(), array($this, 'toStringArgumentReducer'), $this->getId() ); } /** * Normalizes the arguments array passed to a Redis command. * * @param array $arguments Arguments for a command. * @return array */ public static function normalizeArguments(Array $arguments) { if (count($arguments) === 1 && is_array($arguments[0])) { return $arguments[0]; } return $arguments; } /** * Normalizes the arguments array passed to a variadic Redis command. * * @param array $arguments Arguments for a command. * @return array */ public static function normalizeVariadic(Array $arguments) { if (count($arguments) === 2 && is_array($arguments[1])) { return array_merge(array($arguments[0]), $arguments[1]); } return $arguments; } } predis-0.8.3/lib/Predis/Command/CommandInterface.php000066400000000000000000000031421211043230100222550ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * Defines an abstraction representing a Redis command. * @author Daniele Alessandri */ interface CommandInterface { /** * Gets the ID of a Redis command. * * @return string */ public function getId(); /** * Set the hash for the command. * * @param int $hash Calculated hash. */ public function setHash($hash); /** * Returns the hash of the command. * * @return int */ public function getHash(); /** * Sets the arguments for the command. * * @param array $arguments List of arguments. */ public function setArguments(Array $arguments); /** * Sets the raw arguments for the command without processing them. * * @param array $arguments List of arguments. */ public function setRawArguments(Array $arguments); /** * Gets the arguments of the command. * * @return array */ public function getArguments(); /** * Gets the argument of the command at the specified index. * * @return array */ public function getArgument($index); /** * Parses a reply buffer and returns a PHP object. * * @param string $data Binary string containing the whole reply. * @return mixed */ public function parseResponse($data); } predis-0.8.3/lib/Predis/Command/ConnectionAuth.php000066400000000000000000000010051211043230100217730ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/auth * @author Daniele Alessandri */ class ConnectionAuth extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'AUTH'; } } predis-0.8.3/lib/Predis/Command/ConnectionEcho.php000066400000000000000000000010051211043230100217500ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/echo * @author Daniele Alessandri */ class ConnectionEcho extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'ECHO'; } } predis-0.8.3/lib/Predis/Command/ConnectionPing.php000066400000000000000000000012201211043230100217660ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/ping * @author Daniele Alessandri */ class ConnectionPing extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'PING'; } /** * {@inheritdoc} */ public function parseResponse($data) { return $data === 'PONG' ? true : false; } } predis-0.8.3/lib/Predis/Command/ConnectionQuit.php000066400000000000000000000010051211043230100220140ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/quit * @author Daniele Alessandri */ class ConnectionQuit extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'QUIT'; } } predis-0.8.3/lib/Predis/Command/ConnectionSelect.php000066400000000000000000000010131211043230100223100ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/select * @author Daniele Alessandri */ class ConnectionSelect extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'SELECT'; } } predis-0.8.3/lib/Predis/Command/HashDelete.php000066400000000000000000000012421211043230100210630ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/hdel * @author Daniele Alessandri */ class HashDelete extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'HDEL'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { return self::normalizeVariadic($arguments); } } predis-0.8.3/lib/Predis/Command/HashExists.php000066400000000000000000000012011211043230100211330ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/hexists * @author Daniele Alessandri */ class HashExists extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'HEXISTS'; } /** * {@inheritdoc} */ public function parseResponse($data) { return (bool) $data; } } predis-0.8.3/lib/Predis/Command/HashGet.php000066400000000000000000000010001211043230100203700ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/hget * @author Daniele Alessandri */ class HashGet extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'HGET'; } } predis-0.8.3/lib/Predis/Command/HashGetAll.php000066400000000000000000000014011211043230100210260ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/hgetall * @author Daniele Alessandri */ class HashGetAll extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'HGETALL'; } /** * {@inheritdoc} */ public function parseResponse($data) { $result = array(); for ($i = 0; $i < count($data); $i++) { $result[$data[$i]] = $data[++$i]; } return $result; } } predis-0.8.3/lib/Predis/Command/HashGetMultiple.php000066400000000000000000000012511211043230100221140ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/hmget * @author Daniele Alessandri */ class HashGetMultiple extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'HMGET'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { return self::normalizeVariadic($arguments); } } predis-0.8.3/lib/Predis/Command/HashIncrementBy.php000066400000000000000000000010161211043230100220770ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/hincrby * @author Daniele Alessandri */ class HashIncrementBy extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'HINCRBY'; } } predis-0.8.3/lib/Predis/Command/HashIncrementByFloat.php000066400000000000000000000010351211043230100230660ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/hincrbyfloat * @author Daniele Alessandri */ class HashIncrementByFloat extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'HINCRBYFLOAT'; } } predis-0.8.3/lib/Predis/Command/HashKeys.php000066400000000000000000000010031211043230100205670ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/hkeys * @author Daniele Alessandri */ class HashKeys extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'HKEYS'; } } predis-0.8.3/lib/Predis/Command/HashLength.php000066400000000000000000000010031211043230100210750ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/hlen * @author Daniele Alessandri */ class HashLength extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'HLEN'; } } predis-0.8.3/lib/Predis/Command/HashSet.php000066400000000000000000000011701211043230100204140ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/hset * @author Daniele Alessandri */ class HashSet extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'HSET'; } /** * {@inheritdoc} */ public function parseResponse($data) { return (bool) $data; } } predis-0.8.3/lib/Predis/Command/HashSetMultiple.php000066400000000000000000000017321211043230100221340ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/hmset * @author Daniele Alessandri */ class HashSetMultiple extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'HMSET'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { if (count($arguments) === 2 && is_array($arguments[1])) { $flattenedKVs = array($arguments[0]); $args = $arguments[1]; foreach ($args as $k => $v) { $flattenedKVs[] = $k; $flattenedKVs[] = $v; } return $flattenedKVs; } return $arguments; } } predis-0.8.3/lib/Predis/Command/HashSetPreserve.php000066400000000000000000000012041211043230100221260ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/hsetnx * @author Daniele Alessandri */ class HashSetPreserve extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'HSETNX'; } /** * {@inheritdoc} */ public function parseResponse($data) { return (bool) $data; } } predis-0.8.3/lib/Predis/Command/HashValues.php000066400000000000000000000010051211043230100211150ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/hvals * @author Daniele Alessandri */ class HashValues extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'HVALS'; } } predis-0.8.3/lib/Predis/Command/KeyDelete.php000066400000000000000000000015121211043230100207300ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/del * @author Daniele Alessandri */ class KeyDelete extends AbstractCommand implements PrefixableCommandInterface { /** * {@inheritdoc} */ public function getId() { return 'DEL'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { return self::normalizeArguments($arguments); } /** * {@inheritdoc} */ public function prefixKeys($prefix) { PrefixHelpers::all($this, $prefix); } } predis-0.8.3/lib/Predis/Command/KeyExists.php000066400000000000000000000011761211043230100210130ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/exists * @author Daniele Alessandri */ class KeyExists extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'EXISTS'; } /** * {@inheritdoc} */ public function parseResponse($data) { return (bool) $data; } } predis-0.8.3/lib/Predis/Command/KeyExpire.php000066400000000000000000000011761211043230100207700ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/expire * @author Daniele Alessandri */ class KeyExpire extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'EXPIRE'; } /** * {@inheritdoc} */ public function parseResponse($data) { return (bool) $data; } } predis-0.8.3/lib/Predis/Command/KeyExpireAt.php000066400000000000000000000012041211043230100212450ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/expireat * @author Daniele Alessandri */ class KeyExpireAt extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'EXPIREAT'; } /** * {@inheritdoc} */ public function parseResponse($data) { return (bool) $data; } } predis-0.8.3/lib/Predis/Command/KeyKeys.php000066400000000000000000000010001211043230100204310ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/keys * @author Daniele Alessandri */ class KeyKeys extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'KEYS'; } } predis-0.8.3/lib/Predis/Command/KeyKeysV12x.php000066400000000000000000000010431211043230100211210ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/keys * @author Daniele Alessandri * @deprecated */ class KeyKeysV12x extends KeyKeys { /** * {@inheritdoc} */ public function parseResponse($data) { return explode(' ', $data); } } predis-0.8.3/lib/Predis/Command/KeyMove.php000066400000000000000000000011701211043230100204340ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/move * @author Daniele Alessandri */ class KeyMove extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'MOVE'; } /** * {@inheritdoc} */ public function parseResponse($data) { return (bool) $data; } } predis-0.8.3/lib/Predis/Command/KeyPersist.php000066400000000000000000000012011211043230100211520ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/persist * @author Daniele Alessandri */ class KeyPersist extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'PERSIST'; } /** * {@inheritdoc} */ public function parseResponse($data) { return (bool) $data; } } predis-0.8.3/lib/Predis/Command/KeyPreciseExpire.php000066400000000000000000000010071211043230100222740ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/pexpire * @author Daniele Alessandri */ class KeyPreciseExpire extends KeyExpire { /** * {@inheritdoc} */ public function getId() { return 'PEXPIRE'; } } predis-0.8.3/lib/Predis/Command/KeyPreciseExpireAt.php000066400000000000000000000010171211043230100225620ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/pexpireat * @author Daniele Alessandri */ class KeyPreciseExpireAt extends KeyExpireAt { /** * {@inheritdoc} */ public function getId() { return 'PEXPIREAT'; } } predis-0.8.3/lib/Predis/Command/KeyPreciseTimeToLive.php000066400000000000000000000010111211043230100230540ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/pttl * @author Daniele Alessandri */ class KeyPreciseTimeToLive extends KeyTimeToLive { /** * {@inheritdoc} */ public function getId() { return 'PTTL'; } } predis-0.8.3/lib/Predis/Command/KeyRandom.php000066400000000000000000000012211211043230100207430ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/randomkey * @author Daniele Alessandri */ class KeyRandom extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'RANDOMKEY'; } /** * {@inheritdoc} */ public function parseResponse($data) { return $data !== '' ? $data : null; } } predis-0.8.3/lib/Predis/Command/KeyRename.php000066400000000000000000000012601211043230100207350ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/rename * @author Daniele Alessandri */ class KeyRename extends AbstractCommand implements PrefixableCommandInterface { /** * {@inheritdoc} */ public function getId() { return 'RENAME'; } /** * {@inheritdoc} */ public function prefixKeys($prefix) { PrefixHelpers::all($this, $prefix); } } predis-0.8.3/lib/Predis/Command/KeyRenamePreserve.php000066400000000000000000000012021211043230100224450ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/renamenx * @author Daniele Alessandri */ class KeyRenamePreserve extends KeyRename { /** * {@inheritdoc} */ public function getId() { return 'RENAMENX'; } /** * {@inheritdoc} */ public function parseResponse($data) { return (bool) $data; } } predis-0.8.3/lib/Predis/Command/KeySort.php000066400000000000000000000055661211043230100204720ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/sort * @author Daniele Alessandri */ class KeySort extends AbstractCommand implements PrefixableCommandInterface { /** * {@inheritdoc} */ public function getId() { return 'SORT'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { if (count($arguments) === 1) { return $arguments; } $query = array($arguments[0]); $sortParams = array_change_key_case($arguments[1], CASE_UPPER); if (isset($sortParams['BY'])) { $query[] = 'BY'; $query[] = $sortParams['BY']; } if (isset($sortParams['GET'])) { $getargs = $sortParams['GET']; if (is_array($getargs)) { foreach ($getargs as $getarg) { $query[] = 'GET'; $query[] = $getarg; } } else { $query[] = 'GET'; $query[] = $getargs; } } if (isset($sortParams['LIMIT']) && is_array($sortParams['LIMIT']) && count($sortParams['LIMIT']) == 2) { $query[] = 'LIMIT'; $query[] = $sortParams['LIMIT'][0]; $query[] = $sortParams['LIMIT'][1]; } if (isset($sortParams['SORT'])) { $query[] = strtoupper($sortParams['SORT']); } if (isset($sortParams['ALPHA']) && $sortParams['ALPHA'] == true) { $query[] = 'ALPHA'; } if (isset($sortParams['STORE'])) { $query[] = 'STORE'; $query[] = $sortParams['STORE']; } return $query; } /** * {@inheritdoc} */ public function prefixKeys($prefix) { $arguments = $this->getArguments(); $arguments[0] = "$prefix{$arguments[0]}"; if (($count = count($arguments)) > 1) { for ($i = 1; $i < $count; $i++) { switch ($arguments[$i]) { case 'BY': case 'STORE': $arguments[$i] = "$prefix{$arguments[++$i]}"; break; case 'GET': $value = $arguments[++$i]; if ($value !== '#') { $arguments[$i] = "$prefix$value"; } break; case 'LIMIT'; $i += 2; break; } } } $this->setRawArguments($arguments); } } predis-0.8.3/lib/Predis/Command/KeyTimeToLive.php000066400000000000000000000010041211043230100215430ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/ttl * @author Daniele Alessandri */ class KeyTimeToLive extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'TTL'; } } predis-0.8.3/lib/Predis/Command/KeyType.php000066400000000000000000000010001211043230100204370ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/type * @author Daniele Alessandri */ class KeyType extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'TYPE'; } } predis-0.8.3/lib/Predis/Command/ListIndex.php000066400000000000000000000010061211043230100207560ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/lindex * @author Daniele Alessandri */ class ListIndex extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'LINDEX'; } } predis-0.8.3/lib/Predis/Command/ListInsert.php000066400000000000000000000010111211043230100211470ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/linsert * @author Daniele Alessandri */ class ListInsert extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'LINSERT'; } } predis-0.8.3/lib/Predis/Command/ListLength.php000066400000000000000000000010031211043230100211250ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/llen * @author Daniele Alessandri */ class ListLength extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'LLEN'; } } predis-0.8.3/lib/Predis/Command/ListPopFirst.php000066400000000000000000000010051211043230100214540ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/lpop * @author Daniele Alessandri */ class ListPopFirst extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'LPOP'; } } predis-0.8.3/lib/Predis/Command/ListPopFirstBlocking.php000066400000000000000000000017641211043230100231410ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/blpop * @author Daniele Alessandri */ class ListPopFirstBlocking extends AbstractCommand implements PrefixableCommandInterface { /** * {@inheritdoc} */ public function getId() { 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} */ public function prefixKeys($prefix) { PrefixHelpers::skipLast($this, $prefix); } } predis-0.8.3/lib/Predis/Command/ListPopLast.php000066400000000000000000000010041211043230100212670ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/rpop * @author Daniele Alessandri */ class ListPopLast extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'RPOP'; } } predis-0.8.3/lib/Predis/Command/ListPopLastBlocking.php000066400000000000000000000010211211043230100227370ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/brpop * @author Daniele Alessandri */ class ListPopLastBlocking extends ListPopFirstBlocking { /** * {@inheritdoc} */ public function getId() { return 'BRPOP'; } } predis-0.8.3/lib/Predis/Command/ListPopLastPushHead.php000066400000000000000000000013001211043230100227100ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/rpoplpush * @author Daniele Alessandri */ class ListPopLastPushHead extends AbstractCommand implements PrefixableCommandInterface { /** * {@inheritdoc} */ public function getId() { return 'RPOPLPUSH'; } /** * {@inheritdoc} */ public function prefixKeys($prefix) { PrefixHelpers::all($this, $prefix); } } predis-0.8.3/lib/Predis/Command/ListPopLastPushHeadBlocking.php000066400000000000000000000013171211043230100243710ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/brpoplpush * @author Daniele Alessandri */ class ListPopLastPushHeadBlocking extends AbstractCommand implements PrefixableCommandInterface { /** * {@inheritdoc} */ public function getId() { return 'BRPOPLPUSH'; } /** * {@inheritdoc} */ public function prefixKeys($prefix) { PrefixHelpers::skipLast($this, $prefix); } } predis-0.8.3/lib/Predis/Command/ListPushHead.php000066400000000000000000000010021211043230100214040ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/lpush * @author Daniele Alessandri */ class ListPushHead extends ListPushTail { /** * {@inheritdoc} */ public function getId() { return 'LPUSH'; } } predis-0.8.3/lib/Predis/Command/ListPushHeadX.php000066400000000000000000000010121211043230100215350ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/lpushx * @author Daniele Alessandri */ class ListPushHeadX extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'LPUSHX'; } } predis-0.8.3/lib/Predis/Command/ListPushTail.php000066400000000000000000000012461211043230100214460ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/rpush * @author Daniele Alessandri */ class ListPushTail extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'RPUSH'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { return self::normalizeVariadic($arguments); } } predis-0.8.3/lib/Predis/Command/ListPushTailX.php000066400000000000000000000010121211043230100215650ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/rpushx * @author Daniele Alessandri */ class ListPushTailX extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'RPUSHX'; } } predis-0.8.3/lib/Predis/Command/ListRange.php000066400000000000000000000010061211043230100207430ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/lrange * @author Daniele Alessandri */ class ListRange extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'LRANGE'; } } predis-0.8.3/lib/Predis/Command/ListRemove.php000066400000000000000000000010031211043230100211410ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/lrem * @author Daniele Alessandri */ class ListRemove extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'LREM'; } } predis-0.8.3/lib/Predis/Command/ListSet.php000066400000000000000000000010001211043230100204340ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/lset * @author Daniele Alessandri */ class ListSet extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'LSET'; } } predis-0.8.3/lib/Predis/Command/ListTrim.php000066400000000000000000000010031211043230100206170ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/ltrim * @author Daniele Alessandri */ class ListTrim extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'LTRIM'; } } predis-0.8.3/lib/Predis/Command/PrefixHelpers.php000066400000000000000000000055071211043230100216450ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * Class that defines a few helpers method for prefixing keys. * * @author Daniele Alessandri */ class PrefixHelpers { /** * Applies the specified prefix only the first argument. * * @param CommandInterface $command Command instance. * @param string $prefix Prefix string. */ public static function first(CommandInterface $command, $prefix) { if ($arguments = $command->getArguments()) { $arguments[0] = "$prefix{$arguments[0]}"; $command->setRawArguments($arguments); } } /** * Applies the specified prefix to all the arguments. * * @param CommandInterface $command Command instance. * @param string $prefix Prefix string. */ public static function all(CommandInterface $command, $prefix) { $arguments = $command->getArguments(); foreach ($arguments as &$key) { $key = "$prefix$key"; } $command->setRawArguments($arguments); } /** * Applies the specified prefix only to even arguments in the list. * * @param CommandInterface $command Command instance. * @param string $prefix Prefix string. */ public static function interleaved(CommandInterface $command, $prefix) { $arguments = $command->getArguments(); $length = count($arguments); for ($i = 0; $i < $length; $i += 2) { $arguments[$i] = "$prefix{$arguments[$i]}"; } $command->setRawArguments($arguments); } /** * Applies the specified prefix to all the arguments but the first one. * * @param CommandInterface $command Command instance. * @param string $prefix Prefix string. */ public static function skipFirst(CommandInterface $command, $prefix) { $arguments = $command->getArguments(); $length = count($arguments); for ($i = 1; $i < $length; $i++) { $arguments[$i] = "$prefix{$arguments[$i]}"; } $command->setRawArguments($arguments); } /** * Applies the specified prefix to all the arguments but the last one. * * @param CommandInterface $command Command instance. * @param string $prefix Prefix string. */ public static function skipLast(CommandInterface $command, $prefix) { $arguments = $command->getArguments(); $length = count($arguments); for ($i = 0; $i < $length - 1; $i++) { $arguments[$i] = "$prefix{$arguments[$i]}"; } $command->setRawArguments($arguments); } } predis-0.8.3/lib/Predis/Command/PrefixableCommand.php000066400000000000000000000013411211043230100224350ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * Base class for Redis commands with prefixable keys. * * @author Daniele Alessandri */ abstract class PrefixableCommand extends AbstractCommand implements PrefixableCommandInterface { /** * {@inheritdoc} */ public function prefixKeys($prefix) { if ($arguments = $this->getArguments()) { $arguments[0] = "$prefix{$arguments[0]}"; $this->setRawArguments($arguments); } } } predis-0.8.3/lib/Predis/Command/PrefixableCommandInterface.php000066400000000000000000000011471211043230100242620ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * Defines a command whose keys can be prefixed. * * @author Daniele Alessandri */ interface PrefixableCommandInterface { /** * Prefixes all the keys found in the arguments of the command. * * @param string $prefix String used to prefix the keys. */ public function prefixKeys($prefix); } predis-0.8.3/lib/Predis/Command/Processor/000077500000000000000000000000001211043230100203245ustar00rootroot00000000000000predis-0.8.3/lib/Predis/Command/Processor/CommandProcessingInterface.php000066400000000000000000000014561211043230100262770ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command\Processor; /** * Defines an object that can process commands using command processors. * * @author Daniele Alessandri */ interface CommandProcessingInterface { /** * Associates a command processor. * * @param CommandProcessorInterface $processor The command processor. */ public function setProcessor(CommandProcessorInterface $processor); /** * Returns the associated command processor. * * @return CommandProcessorInterface */ public function getProcessor(); } predis-0.8.3/lib/Predis/Command/Processor/CommandProcessorChainInterface.php000066400000000000000000000021531211043230100271000ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command\Processor; /** * A command processor chain processes a command using multiple chained command * processor before it is sent to Redis. * * @author Daniele Alessandri */ interface CommandProcessorChainInterface extends CommandProcessorInterface, \IteratorAggregate, \Countable { /** * Adds a command processor. * * @param CommandProcessorInterface $processor A command processor. */ public function add(CommandProcessorInterface $processor); /** * Removes a command processor from the chain. * * @param CommandProcessorInterface $processor A command processor. */ public function remove(CommandProcessorInterface $processor); /** * Returns an ordered list of the command processors in the chain. * * @return array */ public function getProcessors(); } predis-0.8.3/lib/Predis/Command/Processor/CommandProcessorInterface.php000066400000000000000000000012251211043230100261340ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command\Processor; use Predis\Command\CommandInterface; /** * A command processor processes commands before they are sent to Redis. * * @author Daniele Alessandri */ interface CommandProcessorInterface { /** * Processes a Redis command. * * @param CommandInterface $command Redis command. */ public function process(CommandInterface $command); } predis-0.8.3/lib/Predis/Command/Processor/KeyPrefixProcessor.php000066400000000000000000000027101211043230100246430ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command\Processor; use Predis\Command\CommandInterface; use Predis\Command\PrefixableCommandInterface; /** * Command processor that is used to prefix the keys contained in the arguments * of a Redis command. * * @author Daniele Alessandri */ class KeyPrefixProcessor implements CommandProcessorInterface { private $prefix; /** * @param string $prefix Prefix for the keys. */ public function __construct($prefix) { $this->setPrefix($prefix); } /** * Sets a prefix that is applied to all the keys. * * @param string $prefix Prefix for the keys. */ public function setPrefix($prefix) { $this->prefix = $prefix; } /** * Gets the current prefix. * * @return string */ public function getPrefix() { return $this->prefix; } /** * {@inheritdoc} */ public function process(CommandInterface $command) { if ($command instanceof PrefixableCommandInterface) { $command->prefixKeys($this->prefix); } } /** * {@inheritdoc} */ public function __toString() { return $this->getPrefix(); } } predis-0.8.3/lib/Predis/Command/Processor/ProcessorChain.php000066400000000000000000000055231211043230100237640ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command\Processor; use Predis\Command\CommandInterface; /** * Default implementation of a command processors chain. * * @author Daniele Alessandri */ class ProcessorChain implements CommandProcessorChainInterface, \ArrayAccess { private $processors = array(); /** * @param array $processors List of instances of CommandProcessorInterface. */ public function __construct($processors = array()) { foreach ($processors as $processor) { $this->add($processor); } } /** * {@inheritdoc} */ public function add(CommandProcessorInterface $processor) { $this->processors[] = $processor; } /** * {@inheritdoc} */ public function remove(CommandProcessorInterface $processor) { if (false !== $index = array_search($processor, $this->processors, true)) { unset($this[$index]); } } /** * {@inheritdoc} */ public function process(CommandInterface $command) { for ($i = 0; $i < $count = count($this->processors); $i++) { $this->processors[$i]->process($command); } } /** * {@inheritdoc} */ public function getProcessors() { return $this->processors; } /** * Returns an iterator over the list of command processor in the chain. * * @return \ArrayIterator */ public function getIterator() { return new \ArrayIterator($this->processors); } /** * Returns the number of command processors in the chain. * * @return int */ public function count() { return count($this->processors); } /** * {@inheritdoc} */ public function offsetExists($index) { return isset($this->processors[$index]); } /** * {@inheritdoc} */ public function offsetGet($index) { return $this->processors[$index]; } /** * {@inheritdoc} */ public function offsetSet($index, $processor) { if (!$processor instanceof CommandProcessorInterface) { throw new \InvalidArgumentException( 'A processor chain can hold only instances of classes implementing '. 'the Predis\Command\Processor\CommandProcessorInterface interface' ); } $this->processors[$index] = $processor; } /** * {@inheritdoc} */ public function offsetUnset($index) { unset($this->processors[$index]); $this->processors = array_values($this->processors); } } predis-0.8.3/lib/Predis/Command/PubSubPublish.php000066400000000000000000000010141211043230100216010ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/publish * @author Daniele Alessandri */ class PubSubPublish extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'PUBLISH'; } } predis-0.8.3/lib/Predis/Command/PubSubSubscribe.php000066400000000000000000000015341211043230100221230ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/subscribe * @author Daniele Alessandri */ class PubSubSubscribe extends AbstractCommand implements PrefixableCommandInterface { /** * {@inheritdoc} */ public function getId() { return 'SUBSCRIBE'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { return self::normalizeArguments($arguments); } /** * {@inheritdoc} */ public function prefixKeys($prefix) { PrefixHelpers::all($this, $prefix); } } predis-0.8.3/lib/Predis/Command/PubSubSubscribeByPattern.php000066400000000000000000000010331211043230100237460ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/psubscribe * @author Daniele Alessandri */ class PubSubSubscribeByPattern extends PubSubSubscribe { /** * {@inheritdoc} */ public function getId() { return 'PSUBSCRIBE'; } } predis-0.8.3/lib/Predis/Command/PubSubUnsubscribe.php000066400000000000000000000015421211043230100224650ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/unsubscribe * @author Daniele Alessandri */ class PubSubUnsubscribe extends AbstractCommand implements PrefixableCommandInterface { /** * {@inheritdoc} */ public function getId() { return 'UNSUBSCRIBE'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { return self::normalizeArguments($arguments); } /** * {@inheritdoc} */ public function prefixKeys($prefix) { PrefixHelpers::all($this, $prefix); } } predis-0.8.3/lib/Predis/Command/PubSubUnsubscribeByPattern.php000066400000000000000000000010431211043230100243120ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/punsubscribe * @author Daniele Alessandri */ class PubSubUnsubscribeByPattern extends PubSubUnsubscribe { /** * {@inheritdoc} */ public function getId() { return 'PUNSUBSCRIBE'; } } predis-0.8.3/lib/Predis/Command/ScriptedCommand.php000066400000000000000000000034531211043230100221370ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * Base class used to implement an higher level abstraction for "virtual" * commands based on EVAL. * * @link http://redis.io/commands/eval * @author Daniele Alessandri */ abstract class ScriptedCommand extends ServerEvalSHA { /** * Gets the body of a Lua script. * * @return string */ public abstract function getScript(); /** * Specifies the number of arguments that should be considered as keys. * * The default behaviour for the base class is to return 0 to indicate that * all the elements of the arguments array should be considered as keys, but * subclasses can enforce a static number of keys. * * @return int */ protected function getKeysCount() { return 0; } /** * Returns the elements from the arguments that are identified as keys. * * @return array */ public function getKeys() { return array_slice($this->getArguments(), 2, $this->getKeysCount()); } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { if (($numkeys = $this->getKeysCount()) && $numkeys < 0) { $numkeys = count($arguments) + $numkeys; } return array_merge(array(sha1($this->getScript()), (int) $numkeys), $arguments); } /** * @return array */ public function getEvalArguments() { $arguments = $this->getArguments(); $arguments[0] = $this->getScript(); return $arguments; } } predis-0.8.3/lib/Predis/Command/ServerBackgroundRewriteAOF.php000066400000000000000000000013051211043230100242130ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/bgrewriteaof * @author Daniele Alessandri */ class ServerBackgroundRewriteAOF extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'BGREWRITEAOF'; } /** * {@inheritdoc} */ public function parseResponse($data) { return $data == 'Background append only file rewriting started'; } } predis-0.8.3/lib/Predis/Command/ServerBackgroundSave.php000066400000000000000000000012571211043230100231500ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/bgsave * @author Daniele Alessandri */ class ServerBackgroundSave extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'BGSAVE'; } /** * {@inheritdoc} */ public function parseResponse($data) { return $data === 'Background saving started' ? true : $data; } } predis-0.8.3/lib/Predis/Command/ServerClient.php000066400000000000000000000030101211043230100214550ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/client * @author Daniele Alessandri */ class ServerClient extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'CLIENT'; } /** * {@inheritdoc} */ public function parseResponse($data) { $args = array_change_key_case($this->getArguments(), CASE_UPPER); switch (strtoupper($args[0])) { case 'LIST': return $this->parseClientList($data); case 'KILL': case 'GETNAME': case 'SETNAME': default: return $data; } } /** * Parses the reply buffer and returns the list of clients returned by * the CLIENT LIST command. * * @param string $data Reply buffer * @return array */ protected function parseClientList($data) { $clients = array(); foreach (explode("\n", $data, -1) as $clientData) { $client = array(); foreach (explode(' ', $clientData) as $kv) { @list($k, $v) = explode('=', $kv); $client[$k] = $v; } $clients[] = $client; } return $clients; } } predis-0.8.3/lib/Predis/Command/ServerConfig.php000066400000000000000000000016671211043230100214640ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/config-set * @link http://redis.io/commands/config-get * @link http://redis.io/commands/config-resetstat * @author Daniele Alessandri */ class ServerConfig extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'CONFIG'; } /** * {@inheritdoc} */ public function parseResponse($data) { if (is_array($data)) { $result = array(); for ($i = 0; $i < count($data); $i++) { $result[$data[$i]] = $data[++$i]; } return $result; } return $data; } } predis-0.8.3/lib/Predis/Command/ServerDatabaseSize.php000066400000000000000000000010151211043230100226010ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/dbsize * @author Daniele Alessandri */ class ServerDatabaseSize extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'DBSIZE'; } } predis-0.8.3/lib/Predis/Command/ServerEval.php000066400000000000000000000020421211043230100211320ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/eval * @author Daniele Alessandri */ class ServerEval extends AbstractCommand implements PrefixableCommandInterface { /** * {@inheritdoc} */ public function getId() { return 'EVAL'; } /** * {@inheritdoc} */ public function prefixKeys($prefix) { $arguments = $this->getArguments(); for ($i = 2; $i < $arguments[1] + 2; $i++) { $arguments[$i] = "$prefix{$arguments[$i]}"; } $this->setRawArguments($arguments); } /** * Calculates the SHA1 hash of the body of the script. * * @return string SHA1 hash. */ public function getScriptHash() { return sha1($this->getArgument(0)); } } predis-0.8.3/lib/Predis/Command/ServerEvalSHA.php000066400000000000000000000013141211043230100214670ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/evalsha * @author Daniele Alessandri */ class ServerEvalSHA extends ServerEval { /** * {@inheritdoc} */ public function getId() { return 'EVALSHA'; } /** * Returns the SHA1 hash of the body of the script. * * @return string SHA1 hash. */ public function getScriptHash() { return $this->getArgument(0); } } predis-0.8.3/lib/Predis/Command/ServerFlushAll.php000066400000000000000000000010151211043230100217540ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/flushall * @author Daniele Alessandri */ class ServerFlushAll extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'FLUSHALL'; } } predis-0.8.3/lib/Predis/Command/ServerFlushDatabase.php000066400000000000000000000010201211043230100227440ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/flushdb * @author Daniele Alessandri */ class ServerFlushDatabase extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'FLUSHDB'; } } predis-0.8.3/lib/Predis/Command/ServerInfo.php000066400000000000000000000043431211043230100211440ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/info * @author Daniele Alessandri */ class ServerInfo extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'INFO'; } /** * {@inheritdoc} */ public function parseResponse($data) { $info = array(); $infoLines = preg_split('/\r?\n/', $data); foreach ($infoLines as $row) { @list($k, $v) = explode(':', $row); if ($row === '' || !isset($v)) { continue; } if (!preg_match('/^db\d+$/', $k)) { if ($k === 'allocation_stats') { $info[$k] = $this->parseAllocationStats($v); continue; } $info[$k] = $v; } else { $info[$k] = $this->parseDatabaseStats($v); } } return $info; } /** * Parses the reply buffer and extracts the statistics of each logical DB. * * @param string $str Reply buffer. * @return array */ protected function parseDatabaseStats($str) { $db = array(); foreach (explode(',', $str) as $dbvar) { list($dbvk, $dbvv) = explode('=', $dbvar); $db[trim($dbvk)] = $dbvv; } return $db; } /** * Parses the reply buffer and extracts the allocation statistics. * * @param string $str Reply buffer. * @return array */ protected function parseAllocationStats($str) { $stats = array(); foreach (explode(',', $str) as $kv) { @list($size, $objects, $extra) = explode('=', $kv); // hack to prevent incorrect values when parsing the >=256 key if (isset($extra)) { $size = ">=$objects"; $objects = $extra; } $stats[$size] = $objects; } return $stats; } } predis-0.8.3/lib/Predis/Command/ServerInfoV26x.php000066400000000000000000000026661211043230100216400ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/info * @author Daniele Alessandri */ class ServerInfoV26x extends ServerInfo { /** * {@inheritdoc} */ public function parseResponse($data) { $info = array(); $current = null; $infoLines = preg_split('/\r?\n/', $data); if (isset($infoLines[0]) && $infoLines[0][0] !== '#') { return parent::parseResponse($data); } foreach ($infoLines as $row) { if ($row === '') { continue; } if (preg_match('/^# (\w+)$/', $row, $matches)) { $info[$matches[1]] = array(); $current = &$info[$matches[1]]; continue; } list($k, $v) = explode(':', $row); if (!preg_match('/^db\d+$/', $k)) { if ($k === 'allocation_stats') { $current[$k] = $this->parseAllocationStats($v); continue; } $current[$k] = $v; } else { $current[$k] = $this->parseDatabaseStats($v); } } return $info; } } predis-0.8.3/lib/Predis/Command/ServerLastSave.php000066400000000000000000000010151211043230100217640ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/lastsave * @author Daniele Alessandri */ class ServerLastSave extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'LASTSAVE'; } } predis-0.8.3/lib/Predis/Command/ServerMonitor.php000066400000000000000000000010121211043230100216660ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/monitor * @author Daniele Alessandri */ class ServerMonitor extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'MONITOR'; } } predis-0.8.3/lib/Predis/Command/ServerObject.php000066400000000000000000000010071211043230100214510ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/object * @author Daniele Alessandri */ class ServerObject extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'OBJECT'; } } predis-0.8.3/lib/Predis/Command/ServerSave.php000066400000000000000000000010011211043230100211330ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/save * @author Daniele Alessandri */ class ServerSave extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'SAVE'; } } predis-0.8.3/lib/Predis/Command/ServerScript.php000066400000000000000000000010071211043230100215070ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/script * @author Daniele Alessandri */ class ServerScript extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'SCRIPT'; } } predis-0.8.3/lib/Predis/Command/ServerShutdown.php000066400000000000000000000010151211043230100220550ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/shutdown * @author Daniele Alessandri */ class ServerShutdown extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'SHUTDOWN'; } } predis-0.8.3/lib/Predis/Command/ServerSlaveOf.php000066400000000000000000000014071211043230100216060ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/slaveof * @author Daniele Alessandri */ class ServerSlaveOf extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'SLAVEOF'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { if (count($arguments) === 0 || $arguments[0] === 'NO ONE') { return array('NO', 'ONE'); } return $arguments; } } predis-0.8.3/lib/Predis/Command/ServerSlowlog.php000066400000000000000000000020031211043230100216660ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/slowlog * @author Daniele Alessandri */ class ServerSlowlog extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'SLOWLOG'; } /** * {@inheritdoc} */ public function parseResponse($data) { if (is_array($data)) { $log = array(); foreach ($data as $index => $entry) { $log[$index] = array( 'id' => $entry[0], 'timestamp' => $entry[1], 'duration' => $entry[2], 'command' => $entry[3], ); } return $log; } return $data; } } predis-0.8.3/lib/Predis/Command/ServerTime.php000066400000000000000000000010011211043230100211330ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/time * @author Daniele Alessandri */ class ServerTime extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'TIME'; } } predis-0.8.3/lib/Predis/Command/SetAdd.php000066400000000000000000000012361211043230100202240ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/sadd * @author Daniele Alessandri */ class SetAdd extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'SADD'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { return self::normalizeVariadic($arguments); } } predis-0.8.3/lib/Predis/Command/SetCardinality.php000066400000000000000000000010111211043230100217660ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/scard * @author Daniele Alessandri */ class SetCardinality extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'SCARD'; } } predis-0.8.3/lib/Predis/Command/SetDifference.php000066400000000000000000000010061211043230100215610ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/sdiff * @author Daniele Alessandri */ class SetDifference extends SetIntersection { /** * {@inheritdoc} */ public function getId() { return 'SDIFF'; } } predis-0.8.3/lib/Predis/Command/SetDifferenceStore.php000066400000000000000000000010321211043230100225750ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/sdiffstore * @author Daniele Alessandri */ class SetDifferenceStore extends SetIntersectionStore { /** * {@inheritdoc} */ public function getId() { return 'SDIFFSTORE'; } } predis-0.8.3/lib/Predis/Command/SetIntersection.php000066400000000000000000000015261211043230100222040ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/sinter * @author Daniele Alessandri */ class SetIntersection extends AbstractCommand implements PrefixableCommandInterface { /** * {@inheritdoc} */ public function getId() { return 'SINTER'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { return self::normalizeArguments($arguments); } /** * {@inheritdoc} */ public function prefixKeys($prefix) { PrefixHelpers::all($this, $prefix); } } predis-0.8.3/lib/Predis/Command/SetIntersectionStore.php000066400000000000000000000017351211043230100232230ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/sinterstore * @author Daniele Alessandri */ class SetIntersectionStore extends AbstractCommand implements PrefixableCommandInterface { /** * {@inheritdoc} */ public function getId() { return 'SINTERSTORE'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { if (count($arguments) === 2 && is_array($arguments[1])) { return array_merge(array($arguments[0]), $arguments[1]); } return $arguments; } /** * {@inheritdoc} */ public function prefixKeys($prefix) { PrefixHelpers::all($this, $prefix); } } predis-0.8.3/lib/Predis/Command/SetIsMember.php000066400000000000000000000012061211043230100212340ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/sismember * @author Daniele Alessandri */ class SetIsMember extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'SISMEMBER'; } /** * {@inheritdoc} */ public function parseResponse($data) { return (bool) $data; } } predis-0.8.3/lib/Predis/Command/SetMembers.php000066400000000000000000000010131211043230100211170ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/smembers * @author Daniele Alessandri */ class SetMembers extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'SMEMBERS'; } } predis-0.8.3/lib/Predis/Command/SetMove.php000066400000000000000000000014511211043230100204410ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/smove * @author Daniele Alessandri */ class SetMove extends AbstractCommand implements PrefixableCommandInterface { /** * {@inheritdoc} */ public function getId() { return 'SMOVE'; } /** * {@inheritdoc} */ public function prefixKeys($prefix) { PrefixHelpers::skipLast($this, $prefix); } /** * {@inheritdoc} */ public function parseResponse($data) { return (bool) $data; } } predis-0.8.3/lib/Predis/Command/SetPop.php000066400000000000000000000007771211043230100203030ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/spop * @author Daniele Alessandri */ class SetPop extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'SPOP'; } } predis-0.8.3/lib/Predis/Command/SetRandomMember.php000066400000000000000000000010261211043230100221010ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/srandmember * @author Daniele Alessandri */ class SetRandomMember extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'SRANDMEMBER'; } } predis-0.8.3/lib/Predis/Command/SetRemove.php000066400000000000000000000012411211043230100207650ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/srem * @author Daniele Alessandri */ class SetRemove extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'SREM'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { return self::normalizeVariadic($arguments); } } predis-0.8.3/lib/Predis/Command/SetUnion.php000066400000000000000000000010031211043230100206140ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/sunion * @author Daniele Alessandri */ class SetUnion extends SetIntersection { /** * {@inheritdoc} */ public function getId() { return 'SUNION'; } } predis-0.8.3/lib/Predis/Command/SetUnionStore.php000066400000000000000000000010271211043230100216370ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/sunionstore * @author Daniele Alessandri */ class SetUnionStore extends SetIntersectionStore { /** * {@inheritdoc} */ public function getId() { return 'SUNIONSTORE'; } } predis-0.8.3/lib/Predis/Command/StringAppend.php000066400000000000000000000010111211043230100214450ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/append * @author Daniele Alessandri */ class StringAppend extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'APPEND'; } } predis-0.8.3/lib/Predis/Command/StringBitCount.php000066400000000000000000000010171211043230100217730ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/bitcount * @author Daniele Alessandri */ class StringBitCount extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'BITCOUNT'; } } predis-0.8.3/lib/Predis/Command/StringBitOp.php000066400000000000000000000020551211043230100212640ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/bitop * @author Daniele Alessandri */ class StringBitOp extends AbstractCommand implements PrefixableCommandInterface { /** * {@inheritdoc} */ public function getId() { return 'BITOP'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { if (count($arguments) === 3 && is_array($arguments[2])) { list($operation, $destination, ) = $arguments; $arguments = $arguments[2]; array_unshift($arguments, $operation, $destination); } return $arguments; } /** * {@inheritdoc} */ public function prefixKeys($prefix) { PrefixHelpers::skipFirst($this, $prefix); } } predis-0.8.3/lib/Predis/Command/StringDecrement.php000066400000000000000000000010101211043230100221430ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/decr * @author Daniele Alessandri */ class StringDecrement extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'DECR'; } } predis-0.8.3/lib/Predis/Command/StringDecrementBy.php000066400000000000000000000010161211043230100224440ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/decrby * @author Daniele Alessandri */ class StringDecrementBy extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'DECRBY'; } } predis-0.8.3/lib/Predis/Command/StringGet.php000066400000000000000000000010001211043230100207530ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/get * @author Daniele Alessandri */ class StringGet extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'GET'; } } predis-0.8.3/lib/Predis/Command/StringGetBit.php000066400000000000000000000010111211043230100214140ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/getbit * @author Daniele Alessandri */ class StringGetBit extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'GETBIT'; } } predis-0.8.3/lib/Predis/Command/StringGetMultiple.php000066400000000000000000000015241211043230100225020ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/mget * @author Daniele Alessandri */ class StringGetMultiple extends AbstractCommand implements PrefixableCommandInterface { /** * {@inheritdoc} */ public function getId() { return 'MGET'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { return self::normalizeArguments($arguments); } /** * {@inheritdoc} */ public function prefixKeys($prefix) { PrefixHelpers::all($this, $prefix); } } predis-0.8.3/lib/Predis/Command/StringGetRange.php000066400000000000000000000010171211043230100217400ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/getrange * @author Daniele Alessandri */ class StringGetRange extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'GETRANGE'; } } predis-0.8.3/lib/Predis/Command/StringGetSet.php000066400000000000000000000010111211043230100214310ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/getset * @author Daniele Alessandri */ class StringGetSet extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'GETSET'; } } predis-0.8.3/lib/Predis/Command/StringIncrement.php000066400000000000000000000010101211043230100221610ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/incr * @author Daniele Alessandri */ class StringIncrement extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'INCR'; } } predis-0.8.3/lib/Predis/Command/StringIncrementBy.php000066400000000000000000000010161211043230100224620ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/incrby * @author Daniele Alessandri */ class StringIncrementBy extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'INCRBY'; } } predis-0.8.3/lib/Predis/Command/StringIncrementByFloat.php000066400000000000000000000010351211043230100234510ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/incrbyfloat * @author Daniele Alessandri */ class StringIncrementByFloat extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'INCRBYFLOAT'; } } predis-0.8.3/lib/Predis/Command/StringPreciseSetExpire.php000066400000000000000000000010211211043230100234620ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/psetex * @author Daniele Alessandri */ class StringPreciseSetExpire extends StringSetExpire { /** * {@inheritdoc} */ public function getId() { return 'PSETEX'; } } predis-0.8.3/lib/Predis/Command/StringSet.php000066400000000000000000000010001211043230100207670ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/set * @author Daniele Alessandri */ class StringSet extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'SET'; } } predis-0.8.3/lib/Predis/Command/StringSetBit.php000066400000000000000000000010111211043230100214300ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/setbit * @author Daniele Alessandri */ class StringSetBit extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'SETBIT'; } } predis-0.8.3/lib/Predis/Command/StringSetExpire.php000066400000000000000000000010121211043230100221470ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/setex * @author Daniele Alessandri */ class StringSetExpire extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'SETEX'; } } predis-0.8.3/lib/Predis/Command/StringSetMultiple.php000066400000000000000000000021771211043230100225230ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/mset * @author Daniele Alessandri */ class StringSetMultiple extends AbstractCommand implements PrefixableCommandInterface { /** * {@inheritdoc} */ public function getId() { return 'MSET'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { if (count($arguments) === 1 && is_array($arguments[0])) { $flattenedKVs = array(); $args = $arguments[0]; foreach ($args as $k => $v) { $flattenedKVs[] = $k; $flattenedKVs[] = $v; } return $flattenedKVs; } return $arguments; } /** * {@inheritdoc} */ public function prefixKeys($prefix) { PrefixHelpers::interleaved($this, $prefix); } } predis-0.8.3/lib/Predis/Command/StringSetMultiplePreserve.php000066400000000000000000000012161211043230100242300ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/msetnx * @author Daniele Alessandri */ class StringSetMultiplePreserve extends StringSetMultiple { /** * {@inheritdoc} */ public function getId() { return 'MSETNX'; } /** * {@inheritdoc} */ public function parseResponse($data) { return (bool) $data; } } predis-0.8.3/lib/Predis/Command/StringSetPreserve.php000066400000000000000000000012041211043230100225110ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/setnx * @author Daniele Alessandri */ class StringSetPreserve extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'SETNX'; } /** * {@inheritdoc} */ public function parseResponse($data) { return (bool) $data; } } predis-0.8.3/lib/Predis/Command/StringSetRange.php000066400000000000000000000010171211043230100217540ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/setrange * @author Daniele Alessandri */ class StringSetRange extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'SETRANGE'; } } predis-0.8.3/lib/Predis/Command/StringStrlen.php000066400000000000000000000010111211043230100215050ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/strlen * @author Daniele Alessandri */ class StringStrlen extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'STRLEN'; } } predis-0.8.3/lib/Predis/Command/StringSubstr.php000066400000000000000000000010111211043230100215200ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/substr * @author Daniele Alessandri */ class StringSubstr extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'SUBSTR'; } } predis-0.8.3/lib/Predis/Command/TransactionDiscard.php000066400000000000000000000010171211043230100226340ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/discard * @author Daniele Alessandri */ class TransactionDiscard extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'DISCARD'; } } predis-0.8.3/lib/Predis/Command/TransactionExec.php000066400000000000000000000010061211043230100221450ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/exec * @author Daniele Alessandri */ class TransactionExec extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'EXEC'; } } predis-0.8.3/lib/Predis/Command/TransactionMulti.php000066400000000000000000000010111211043230100223470ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/multi * @author Daniele Alessandri */ class TransactionMulti extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'MULTI'; } } predis-0.8.3/lib/Predis/Command/TransactionUnwatch.php000066400000000000000000000012071211043230100226750ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/unwatch * @author Daniele Alessandri */ class TransactionUnwatch extends AbstractCommand { /** * {@inheritdoc} */ public function getId() { return 'UNWATCH'; } /** * {@inheritdoc} */ public function parseResponse($data) { return (bool) $data; } } predis-0.8.3/lib/Predis/Command/TransactionWatch.php000066400000000000000000000020371211043230100223340ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/watch * @author Daniele Alessandri */ class TransactionWatch extends AbstractCommand implements PrefixableCommandInterface { /** * {@inheritdoc} */ public function getId() { return 'WATCH'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { if (isset($arguments[0]) && is_array($arguments[0])) { return $arguments[0]; } return $arguments; } /** * {@inheritdoc} */ public function prefixKeys($prefix) { PrefixHelpers::all($this, $prefix); } /** * {@inheritdoc} */ public function parseResponse($data) { return (bool) $data; } } predis-0.8.3/lib/Predis/Command/ZSetAdd.php000066400000000000000000000016721211043230100203620ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/zadd * @author Daniele Alessandri */ class ZSetAdd extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'ZADD'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { if (count($arguments) === 2 && is_array($arguments[1])) { $flattened = array($arguments[0]); foreach($arguments[1] as $member => $score) { $flattened[] = $score; $flattened[] = $member; } return $flattened; } return $arguments; } } predis-0.8.3/lib/Predis/Command/ZSetCardinality.php000066400000000000000000000010121211043230100221210ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/zcard * @author Daniele Alessandri */ class ZSetCardinality extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'ZCARD'; } } predis-0.8.3/lib/Predis/Command/ZSetCount.php000066400000000000000000000010061211043230100207510ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/zcount * @author Daniele Alessandri */ class ZSetCount extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'ZCOUNT'; } } predis-0.8.3/lib/Predis/Command/ZSetIncrementBy.php000066400000000000000000000010161211043230100221010ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/zincrby * @author Daniele Alessandri */ class ZSetIncrementBy extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'ZINCRBY'; } } predis-0.8.3/lib/Predis/Command/ZSetIntersectionStore.php000066400000000000000000000010311211043230100233420ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/zinterstore * @author Daniele Alessandri */ class ZSetIntersectionStore extends ZSetUnionStore { /** * {@inheritdoc} */ public function getId() { return 'ZINTERSTORE'; } } predis-0.8.3/lib/Predis/Command/ZSetRange.php000066400000000000000000000044231211043230100207230ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/zrange * @author Daniele Alessandri */ class ZSetRange extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'ZRANGE'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { if (count($arguments) === 4) { $lastType = gettype($arguments[3]); if ($lastType === 'string' && strtolower($arguments[3]) === 'withscores') { // Used for compatibility with older versions $arguments[3] = array('WITHSCORES' => true); $lastType = 'array'; } if ($lastType === 'array') { $options = $this->prepareOptions(array_pop($arguments)); return array_merge($arguments, $options); } } return $arguments; } /** * Returns a list of options and modifiers compatible with Redis. * * @param array $options List of options. * @return array */ protected function prepareOptions($options) { $opts = array_change_key_case($options, CASE_UPPER); $finalizedOpts = array(); if (isset($opts['WITHSCORES'])) { $finalizedOpts[] = 'WITHSCORES'; } return $finalizedOpts; } /** * Checks for the presence of the WITHSCORES modifier. * * @return Boolean */ protected function withScores() { $arguments = $this->getArguments(); if (count($arguments) < 4) { return false; } return strtoupper($arguments[3]) === 'WITHSCORES'; } /** * {@inheritdoc} */ public function parseResponse($data) { if ($this->withScores()) { $result = array(); for ($i = 0; $i < count($data); $i++) { $result[] = array($data[$i], $data[++$i]); } return $result; } return $data; } } predis-0.8.3/lib/Predis/Command/ZSetRangeByScore.php000066400000000000000000000031001211043230100222010ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/zrangebyscore * @author Daniele Alessandri */ class ZSetRangeByScore extends ZSetRange { /** * {@inheritdoc} */ public function getId() { return 'ZRANGEBYSCORE'; } /** * {@inheritdoc} */ protected function prepareOptions($options) { $opts = array_change_key_case($options, CASE_UPPER); $finalizedOpts = array(); if (isset($opts['LIMIT']) && is_array($opts['LIMIT'])) { $limit = array_change_key_case($opts['LIMIT'], CASE_UPPER); $finalizedOpts[] = 'LIMIT'; $finalizedOpts[] = isset($limit['OFFSET']) ? $limit['OFFSET'] : $limit[0]; $finalizedOpts[] = isset($limit['COUNT']) ? $limit['COUNT'] : $limit[1]; } return array_merge($finalizedOpts, parent::prepareOptions($options)); } /** * {@inheritdoc} */ protected function withScores() { $arguments = $this->getArguments(); for ($i = 3; $i < count($arguments); $i++) { switch (strtoupper($arguments[$i])) { case 'WITHSCORES': return true; case 'LIMIT': $i += 2; break; } } return false; } } predis-0.8.3/lib/Predis/Command/ZSetRank.php000066400000000000000000000010031211043230100205510ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/zrank * @author Daniele Alessandri */ class ZSetRank extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'ZRANK'; } } predis-0.8.3/lib/Predis/Command/ZSetRemove.php000066400000000000000000000012421211043230100211200ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/zrem * @author Daniele Alessandri */ class ZSetRemove extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'ZREM'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { return self::normalizeVariadic($arguments); } } predis-0.8.3/lib/Predis/Command/ZSetRemoveRangeByRank.php000066400000000000000000000010441211043230100232040ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/zremrangebyrank * @author Daniele Alessandri */ class ZSetRemoveRangeByRank extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'ZREMRANGEBYRANK'; } } predis-0.8.3/lib/Predis/Command/ZSetRemoveRangeByScore.php000066400000000000000000000010471211043230100233670ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/zremrangebyscore * @author Daniele Alessandri */ class ZSetRemoveRangeByScore extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'ZREMRANGEBYSCORE'; } } predis-0.8.3/lib/Predis/Command/ZSetReverseRange.php000066400000000000000000000010131211043230100222470ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/zrevrange * @author Daniele Alessandri */ class ZSetReverseRange extends ZSetRange { /** * {@inheritdoc} */ public function getId() { return 'ZREVRANGE'; } } predis-0.8.3/lib/Predis/Command/ZSetReverseRangeByScore.php000066400000000000000000000010471211043230100235450ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/zrevrangebyscore * @author Daniele Alessandri */ class ZSetReverseRangeByScore extends ZSetRangeByScore { /** * {@inheritdoc} */ public function getId() { return 'ZREVRANGEBYSCORE'; } } predis-0.8.3/lib/Predis/Command/ZSetReverseRank.php000066400000000000000000000010201211043230100221040ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/zrevrank * @author Daniele Alessandri */ class ZSetReverseRank extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'ZREVRANK'; } } predis-0.8.3/lib/Predis/Command/ZSetScore.php000066400000000000000000000010061211043230100207340ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/zscore * @author Daniele Alessandri */ class ZSetScore extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'ZSCORE'; } } predis-0.8.3/lib/Predis/Command/ZSetUnionStore.php000066400000000000000000000042261211043230100217750ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; /** * @link http://redis.io/commands/zunionstore * @author Daniele Alessandri */ class ZSetUnionStore extends PrefixableCommand { /** * {@inheritdoc} */ public function getId() { return 'ZUNIONSTORE'; } /** * {@inheritdoc} */ protected function filterArguments(Array $arguments) { $options = array(); $argc = count($arguments); if ($argc > 2 && is_array($arguments[$argc - 1])) { $options = $this->prepareOptions(array_pop($arguments)); } if (is_array($arguments[1])) { $arguments = array_merge( array($arguments[0], count($arguments[1])), $arguments[1] ); } return array_merge($arguments, $options); } /** * Returns a list of options and modifiers compatible with Redis. * * @param array $options List of options. * @return array */ private function prepareOptions($options) { $opts = array_change_key_case($options, CASE_UPPER); $finalizedOpts = array(); if (isset($opts['WEIGHTS']) && is_array($opts['WEIGHTS'])) { $finalizedOpts[] = 'WEIGHTS'; foreach ($opts['WEIGHTS'] as $weight) { $finalizedOpts[] = $weight; } } if (isset($opts['AGGREGATE'])) { $finalizedOpts[] = 'AGGREGATE'; $finalizedOpts[] = $opts['AGGREGATE']; } return $finalizedOpts; } /** * {@inheritdoc} */ public function prefixKeys($prefix) { $arguments = $this->getArguments(); $arguments[0] = "$prefix{$arguments[0]}"; $length = ((int) $arguments[1]) + 2; for ($i = 2; $i < $length; $i++) { $arguments[$i] = "$prefix{$arguments[$i]}"; } $this->setRawArguments($arguments); } } predis-0.8.3/lib/Predis/CommunicationException.php000066400000000000000000000036731211043230100221750ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis; use Predis\Connection\SingleConnectionInterface; /** * Base exception class for network-related errors. * * @author Daniele Alessandri */ abstract class CommunicationException extends PredisException { private $connection; /** * @param SingleConnectionInterface $connection Connection that generated the exception. * @param string $message Error message. * @param int $code Error code. * @param \Exception $innerException Inner exception for wrapping the original error. */ public function __construct( SingleConnectionInterface $connection, $message = null, $code = null, \Exception $innerException = null ) { parent::__construct($message, $code, $innerException); $this->connection = $connection; } /** * Gets the connection that generated the exception. * * @return SingleConnectionInterface */ public function getConnection() { return $this->connection; } /** * Indicates if the receiver should reset the underlying connection. * * @return Boolean */ public function shouldResetConnection() { return true; } /** * Offers a generic and reusable method to handle exceptions generated by * a connection object. * * @param CommunicationException $exception Exception. */ public static function handle(CommunicationException $exception) { if ($exception->shouldResetConnection()) { $connection = $exception->getConnection(); if ($connection->isConnected()) { $connection->disconnect(); } } throw $exception; } } predis-0.8.3/lib/Predis/Connection/000077500000000000000000000000001211043230100170665ustar00rootroot00000000000000predis-0.8.3/lib/Predis/Connection/AbstractConnection.php000066400000000000000000000122451211043230100233660ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\ClientException; use Predis\CommunicationException; use Predis\NotSupportedException; use Predis\Command\CommandInterface; use Predis\Protocol\ProtocolException; /** * Base class with the common logic used by connection classes to communicate with Redis. * * @author Daniele Alessandri */ abstract class AbstractConnection implements SingleConnectionInterface { private $resource; private $cachedId; protected $parameters; protected $initCmds = array(); /** * @param ConnectionParametersInterface $parameters Parameters used to initialize the connection. */ public function __construct(ConnectionParametersInterface $parameters) { $this->parameters = $this->checkParameters($parameters); } /** * Disconnects from the server and destroys the underlying resource when * PHP's garbage collector kicks in. */ public function __destruct() { $this->disconnect(); } /** * Checks some of the parameters used to initialize the connection. * * @param ConnectionParametersInterface $parameters Parameters used to initialize the connection. */ protected function checkParameters(ConnectionParametersInterface $parameters) { switch ($parameters->scheme) { case 'unix': if (!isset($parameters->path)) { throw new \InvalidArgumentException('Missing UNIX domain socket path'); } case 'tcp': return $parameters; default: throw new \InvalidArgumentException("Invalid scheme: {$parameters->scheme}"); } } /** * Creates the underlying resource used to communicate with Redis. * * @return mixed */ protected abstract function createResource(); /** * {@inheritdoc} */ public function isConnected() { return isset($this->resource); } /** * {@inheritdoc} */ public function connect() { if ($this->isConnected()) { throw new ClientException('Connection already estabilished'); } $this->resource = $this->createResource(); } /** * {@inheritdoc} */ public function disconnect() { unset($this->resource); } /** * {@inheritdoc} */ public function pushInitCommand(CommandInterface $command) { $this->initCmds[] = $command; } /** * {@inheritdoc} */ public function executeCommand(CommandInterface $command) { $this->writeCommand($command); return $this->readResponse($command); } /** * {@inheritdoc} */ public function readResponse(CommandInterface $command) { return $this->read(); } /** * Helper method to handle connection errors. * * @param string $message Error message. * @param int $code Error code. */ protected function onConnectionError($message, $code = null) { CommunicationException::handle(new ConnectionException($this, $message, $code)); } /** * Helper method to handle protocol errors. * * @param string $message Error message. */ protected function onProtocolError($message) { CommunicationException::handle(new ProtocolException($this, $message)); } /** * Helper method to handle not supported connection parameters. * * @param string $option Name of the option. * @param mixed $parameters Parameters used to initialize the connection. */ protected function onInvalidOption($option, $parameters = null) { $class = get_called_class(); $message = "Invalid option for connection $class: $option"; if (isset($parameters)) { $message .= sprintf(' [%s => %s]', $option, $parameters->{$option}); } throw new NotSupportedException($message); } /** * {@inheritdoc} */ public function getResource() { if (isset($this->resource)) { return $this->resource; } $this->connect(); return $this->resource; } /** * {@inheritdoc} */ public function getParameters() { return $this->parameters; } /** * Gets an identifier for the connection. * * @return string */ protected function getIdentifier() { if ($this->parameters->scheme === 'unix') { return $this->parameters->path; } return "{$this->parameters->host}:{$this->parameters->port}"; } /** * {@inheritdoc} */ public function __toString() { if (!isset($this->cachedId)) { $this->cachedId = $this->getIdentifier(); } return $this->cachedId; } /** * {@inheritdoc} */ public function __sleep() { return array('parameters', 'initCmds'); } } predis-0.8.3/lib/Predis/Connection/AggregatedConnectionInterface.php000066400000000000000000000031231211043230100254710ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\Command\CommandInterface; /** * Defines a virtual connection composed by multiple connection objects. * * @author Daniele Alessandri */ interface AggregatedConnectionInterface extends ConnectionInterface { /** * Adds a connection instance to the aggregated connection. * * @param SingleConnectionInterface $connection Instance of a connection. */ public function add(SingleConnectionInterface $connection); /** * Removes the specified connection instance from the aggregated * connection. * * @param SingleConnectionInterface $connection Instance of a connection. * @return Boolean Returns true if the connection was in the pool. */ public function remove(SingleConnectionInterface $connection); /** * Gets the actual connection instance in charge of the specified command. * * @param CommandInterface $command Instance of a Redis command. * @return SingleConnectionInterface */ public function getConnection(CommandInterface $command); /** * Retrieves a connection instance from the aggregated connection * using an alias. * * @param string $connectionId Alias of a connection * @return SingleConnectionInterface */ public function getConnectionById($connectionId); } predis-0.8.3/lib/Predis/Connection/ClusterConnectionInterface.php000066400000000000000000000010401211043230100250540ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\Command\CommandInterface; /** * Defines a cluster of Redis servers formed by aggregating multiple * connection objects. * * @author Daniele Alessandri */ interface ClusterConnectionInterface extends AggregatedConnectionInterface { } predis-0.8.3/lib/Predis/Connection/ComposableConnectionInterface.php000066400000000000000000000025551211043230100255330ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\Protocol\ProtocolInterface; /** * Defines a connection object used to communicate with a single Redis server * that leverages an external protocol processor to handle pluggable protocol * handlers. * * @author Daniele Alessandri */ interface ComposableConnectionInterface extends SingleConnectionInterface { /** * Sets the protocol processor used by the connection. * * @param ProtocolInterface $protocol Protocol processor. */ public function setProtocol(ProtocolInterface $protocol); /** * Gets the protocol processor used by the connection. */ public function getProtocol(); /** * Writes a buffer that contains a serialized Redis command. * * @param string $buffer Serialized Redis command. */ public function writeBytes($buffer); /** * Reads a specified number of bytes from the connection. * * @param string */ public function readBytes($length); /** * Reads a line from the connection. * * @param string */ public function readLine(); } predis-0.8.3/lib/Predis/Connection/ComposableStreamConnection.php000066400000000000000000000062351211043230100250650ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\Command\CommandInterface; use Predis\Protocol\ProtocolInterface; use Predis\Protocol\Text\TextProtocol; /** * Connection abstraction to Redis servers based on PHP's stream that uses an * external protocol processor defining the protocol used for the communication. * * @author Daniele Alessandri */ class ComposableStreamConnection extends StreamConnection implements ComposableConnectionInterface { private $protocol; /** * @param ConnectionParametersInterface $parameters Parameters used to initialize the connection. * @param ProtocolInterface $protocol A protocol processor. */ public function __construct(ConnectionParametersInterface $parameters, ProtocolInterface $protocol = null) { $this->parameters = $this->checkParameters($parameters); $this->protocol = $protocol ?: new TextProtocol(); } /** * {@inheritdoc} */ public function setProtocol(ProtocolInterface $protocol) { if ($protocol === null) { throw new \InvalidArgumentException("The protocol instance cannot be a null value"); } $this->protocol = $protocol; } /** * {@inheritdoc} */ public function getProtocol() { return $this->protocol; } /** * {@inheritdoc} */ public function writeBytes($buffer) { parent::writeBytes($buffer); } /** * {@inheritdoc} */ public function readBytes($length) { if ($length <= 0) { throw new \InvalidArgumentException('Length parameter must be greater than 0'); } $value = ''; $socket = $this->getResource(); do { $chunk = fread($socket, $length); if ($chunk === false || $chunk === '') { $this->onConnectionError('Error while reading bytes from the server'); } $value .= $chunk; } while (($length -= strlen($chunk)) > 0); return $value; } /** * {@inheritdoc} */ public function readLine() { $value = ''; $socket = $this->getResource(); do { $chunk = fgets($socket); if ($chunk === false || $chunk === '') { $this->onConnectionError('Error while reading line from the server'); } $value .= $chunk; } while (substr($value, -2) !== "\r\n"); return substr($value, 0, -2); } /** * {@inheritdoc} */ public function writeCommand(CommandInterface $command) { $this->protocol->write($this, $command); } /** * {@inheritdoc} */ public function read() { return $this->protocol->read($this); } /** * {@inheritdoc} */ public function __sleep() { return array_diff(array_merge(parent::__sleep(), array('protocol')), array('mbiterable')); } } predis-0.8.3/lib/Predis/Connection/ConnectionException.php000066400000000000000000000007561211043230100235650ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\CommunicationException; /** * Exception class that identifies connection-related errors. * * @author Daniele Alessandri */ class ConnectionException extends CommunicationException { } predis-0.8.3/lib/Predis/Connection/ConnectionFactory.php000066400000000000000000000124171211043230100232330ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\Profile\ServerProfile; use Predis\Profile\ServerProfileInterface; /** * Provides a default factory for Redis connections that maps URI schemes * to connection classes implementing Predis\Connection\SingleConnectionInterface. * * @author Daniele Alessandri */ class ConnectionFactory implements ConnectionFactoryInterface { protected $schemes; protected $profile; /** * Initializes a new instance of the default connection factory class used by Predis. * * @param ServerProfileInterface $profile Server profile used to initialize new connections. */ public function __construct(ServerProfileInterface $profile = null) { $this->schemes = $this->getDefaultSchemes(); $this->profile = $profile; } /** * Returns a named array that maps URI schemes to connection classes. * * @return array Map of URI schemes and connection classes. */ protected function getDefaultSchemes() { return array( 'tcp' => 'Predis\Connection\StreamConnection', 'unix' => 'Predis\Connection\StreamConnection', 'http' => 'Predis\Connection\WebdisConnection', ); } /** * Checks if the provided argument represents a valid connection class * implementing Predis\Connection\SingleConnectionInterface. Optionally, * callable objects are used for lazy initialization of connection objects. * * @param mixed $initializer FQN of a connection class or a callable for lazy initialization. * @return mixed */ protected function checkInitializer($initializer) { if (is_callable($initializer)) { return $initializer; } $initializerReflection = new \ReflectionClass($initializer); if (!$initializerReflection->isSubclassOf('Predis\Connection\SingleConnectionInterface')) { throw new \InvalidArgumentException( 'A connection initializer must be a valid connection class or a callable object' ); } return $initializer; } /** * {@inheritdoc} */ public function define($scheme, $initializer) { $this->schemes[$scheme] = $this->checkInitializer($initializer); } /** * {@inheritdoc} */ public function undefine($scheme) { unset($this->schemes[$scheme]); } /** * {@inheritdoc} */ public function create($parameters) { if (!$parameters instanceof ConnectionParametersInterface) { $parameters = new ConnectionParameters($parameters ?: array()); } $scheme = $parameters->scheme; if (!isset($this->schemes[$scheme])) { throw new \InvalidArgumentException("Unknown connection scheme: $scheme"); } $initializer = $this->schemes[$scheme]; if (is_callable($initializer)) { $connection = call_user_func($initializer, $parameters, $this); } else { $connection = new $initializer($parameters); $this->prepareConnection($connection); } if (!$connection instanceof SingleConnectionInterface) { throw new \InvalidArgumentException( 'Objects returned by connection initializers must implement ' . 'Predis\Connection\SingleConnectionInterface' ); } return $connection; } /** * {@inheritdoc} */ public function createAggregated(AggregatedConnectionInterface $connection, Array $parameters) { foreach ($parameters as $node) { $connection->add($node instanceof SingleConnectionInterface ? $node : $this->create($node)); } return $connection; } /** * Prepares a connection object after its initialization. * * @param SingleConnectionInterface $connection Instance of a connection object. */ protected function prepareConnection(SingleConnectionInterface $connection) { if (isset($this->profile)) { $parameters = $connection->getParameters(); if (isset($parameters->password)) { $command = $this->profile->createCommand('auth', array($parameters->password)); $connection->pushInitCommand($command); } if (isset($parameters->database)) { $command = $this->profile->createCommand('select', array($parameters->database)); $connection->pushInitCommand($command); } } } /** * Sets the server profile used to create initialization commands for connections. * * @param ServerProfileInterface $profile Server profile instance. */ public function setProfile(ServerProfileInterface $profile) { $this->profile = $profile; } /** * Returns the server profile used to create initialization commands for connections. * * @return ServerProfileInterface */ public function getProfile() { return $this->profile; } } predis-0.8.3/lib/Predis/Connection/ConnectionFactoryInterface.php000066400000000000000000000033171211043230100250530ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\Profile\ServerProfileInterface; /** * Interface that must be implemented by classes that provide their own mechanism * to create and initialize new instances of Predis\Connection\SingleConnectionInterface. * * @author Daniele Alessandri */ interface ConnectionFactoryInterface { /** * Defines or overrides the connection class identified by a scheme prefix. * * @param string $scheme URI scheme identifying the connection class. * @param mixed $initializer FQN of a connection class or a callable object for lazy initialization. */ public function define($scheme, $initializer); /** * Undefines the connection identified by a scheme prefix. * * @param string $scheme Parameters for the connection. */ public function undefine($scheme); /** * Creates a new connection object. * * @param mixed $parameters Parameters for the connection. * @return Predis\Connection\SingleConnectionInterface */ public function create($parameters); /** * Prepares an aggregation of connection objects. * * @param AggregatedConnectionInterface Instance of an aggregated connection class. * @param array $parameters List of parameters for each connection object. * @return Predis\Connection\AggregatedConnectionInterface */ public function createAggregated(AggregatedConnectionInterface $cluster, Array $parameters); } predis-0.8.3/lib/Predis/Connection/ConnectionInterface.php000066400000000000000000000026761211043230100235320ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\Command\CommandInterface; /** * Defines a connection object used to communicate with one or multiple * Redis servers. * * @author Daniele Alessandri */ interface ConnectionInterface { /** * Opens the connection. */ public function connect(); /** * Closes the connection. */ public function disconnect(); /** * Returns if the connection is open. * * @return Boolean */ public function isConnected(); /** * Write a Redis command on the connection. * * @param CommandInterface $command Instance of a Redis command. */ public function writeCommand(CommandInterface $command); /** * Reads the reply for a Redis command from the connection. * * @param CommandInterface $command Instance of a Redis command. * @return mixed */ public function readResponse(CommandInterface $command); /** * Writes a Redis command to the connection and reads back the reply. * * @param CommandInterface $command Instance of a Redis command. * @return mixed */ public function executeCommand(CommandInterface $command); } predis-0.8.3/lib/Predis/Connection/ConnectionParameters.php000066400000000000000000000103501211043230100237210ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\ClientException; use Predis\Option\OptionInterface; /** * Handles parsing and validation of connection parameters. * * @author Daniele Alessandri */ class ConnectionParameters implements ConnectionParametersInterface { private $parameters; private static $defaults = array( 'scheme' => 'tcp', 'host' => '127.0.0.1', 'port' => 6379, 'timeout' => 5.0, ); /** * @param string|array Connection parameters in the form of an URI string or a named array. */ public function __construct($parameters = array()) { if (!is_array($parameters)) { $parameters = self::parseURI($parameters); } $this->parameters = $this->filter($parameters) + $this->getDefaults(); } /** * Returns some default parameters with their values. * * @return array */ protected function getDefaults() { return self::$defaults; } /** * Returns cast functions for user-supplied parameter values. * * @return array */ protected function getValueCasters() { return array( 'port' => 'self::castInteger', 'async_connect' => 'self::castBoolean', 'persistent' => 'self::castBoolean', 'timeout' => 'self::castFloat', 'read_write_timeout' => 'self::castFloat', 'iterable_multibulk' => 'self::castBoolean', ); } /** * Validates value as boolean. * * @param mixed $value Input value. * @return boolean */ private static function castBoolean($value) { return (bool) $value; } /** * Validates value as float. * * @param mixed $value Input value. * @return float */ private static function castFloat($value) { return (float) $value; } /** * Validates value as integer. * * @param mixed $value Input value. * @return int */ private static function castInteger($value) { return (int) $value; } /** * Parses an URI string and returns an array of connection parameters. * * @param string $uri Connection string. * @return array */ public static function parseURI($uri) { if (stripos($uri, 'unix') === 0) { // Hack to support URIs for UNIX sockets with minimal effort. $uri = str_ireplace('unix:///', 'unix://localhost/', $uri); } if (!($parsed = @parse_url($uri)) || !isset($parsed['host'])) { throw new ClientException("Invalid URI: $uri"); } if (isset($parsed['query'])) { foreach (explode('&', $parsed['query']) as $kv) { @list($k, $v) = explode('=', $kv); $parsed[$k] = $v; } unset($parsed['query']); } return $parsed; } /** * Validates and converts each value of the connection parameters array. * * @param array $parameters Connection parameters. * @return array */ private function filter(Array $parameters) { if ($parameters) { $casters = array_intersect_key($this->getValueCasters(), $parameters); foreach ($casters as $parameter => $caster) { $parameters[$parameter] = call_user_func($caster, $parameters[$parameter]); } } return $parameters; } /** * {@inheritdoc} */ public function __get($parameter) { if (isset($this->{$parameter})) { return $this->parameters[$parameter]; } } /** * {@inheritdoc} */ public function __isset($parameter) { return isset($this->parameters[$parameter]); } /** * {@inheritdoc} */ public function toArray() { return $this->parameters; } /** * {@inheritdoc} */ public function __sleep() { return array('parameters'); } } predis-0.8.3/lib/Predis/Connection/ConnectionParametersInterface.php000066400000000000000000000020121211043230100255360ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; /** * Interface that must be implemented by classes that provide their own mechanism * to parse and handle connection parameters. * * @author Daniele Alessandri */ interface ConnectionParametersInterface { /** * Checks if the specified parameters is set. * * @param string $property Name of the property. * @return Boolean */ public function __isset($parameter); /** * Returns the value of the specified parameter. * * @param string $parameter Name of the parameter. * @return mixed */ public function __get($parameter); /** * Returns an array representation of the connection parameters. * * @return array */ public function toArray(); } predis-0.8.3/lib/Predis/Connection/MasterSlaveReplication.php000066400000000000000000000131341211043230100242210ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\NotSupportedException; use Predis\Command\CommandInterface; use Predis\Replication\ReplicationStrategy; /** * Aggregated connection class used by to handle replication with a * group of servers in a master/slave configuration. * * @author Daniele Alessandri */ class MasterSlaveReplication implements ReplicationConnectionInterface { protected $strategy; protected $master; protected $slaves; protected $current; /** * */ public function __construct(ReplicationStrategy $strategy = null) { $this->slaves = array(); $this->strategy = $strategy ?: new ReplicationStrategy(); } /** * Checks if one master and at least one slave have been defined. */ protected function check() { if (!isset($this->master) || !$this->slaves) { throw new \RuntimeException('Replication needs a master and at least one slave.'); } } /** * Resets the connection state. */ protected function reset() { $this->current = null; } /** * {@inheritdoc} */ public function add(SingleConnectionInterface $connection) { $alias = $connection->getParameters()->alias; if ($alias === 'master') { $this->master = $connection; } else { $this->slaves[$alias ?: count($this->slaves)] = $connection; } $this->reset(); } /** * {@inheritdoc} */ public function remove(SingleConnectionInterface $connection) { if ($connection->getParameters()->alias === 'master') { $this->master = null; $this->reset(); return true; } else { if (($id = array_search($connection, $this->slaves, true)) !== false) { unset($this->slaves[$id]); $this->reset(); return true; } } return false; } /** * {@inheritdoc} */ public function getConnection(CommandInterface $command) { if ($this->current === null) { $this->check(); $this->current = $this->strategy->isReadOperation($command) ? $this->pickSlave() : $this->master; return $this->current; } if ($this->current === $this->master) { return $this->current; } if (!$this->strategy->isReadOperation($command)) { $this->current = $this->master; } return $this->current; } /** * {@inheritdoc} */ public function getConnectionById($connectionId) { if ($connectionId === 'master') { return $this->master; } if (isset($this->slaves[$connectionId])) { return $this->slaves[$connectionId]; } return null; } /** * {@inheritdoc} */ public function switchTo($connection) { $this->check(); if (!$connection instanceof SingleConnectionInterface) { $connection = $this->getConnectionById($connection); } if ($connection !== $this->master && !in_array($connection, $this->slaves, true)) { throw new \InvalidArgumentException('The specified connection is not valid.'); } $this->current = $connection; } /** * {@inheritdoc} */ public function getCurrent() { return $this->current; } /** * {@inheritdoc} */ public function getMaster() { return $this->master; } /** * {@inheritdoc} */ public function getSlaves() { return array_values($this->slaves); } /** * Returns the underlying replication strategy. * * @return ReplicationStrategy */ public function getReplicationStrategy() { return $this->strategy; } /** * Returns a random slave. * * @return SingleConnectionInterface */ protected function pickSlave() { return $this->slaves[array_rand($this->slaves)]; } /** * {@inheritdoc} */ public function isConnected() { return $this->current ? $this->current->isConnected() : false; } /** * {@inheritdoc} */ public function connect() { if ($this->current === null) { $this->check(); $this->current = $this->pickSlave(); } $this->current->connect(); } /** * {@inheritdoc} */ public function disconnect() { if ($this->master) { $this->master->disconnect(); } foreach ($this->slaves as $connection) { $connection->disconnect(); } } /** * {@inheritdoc} */ public function writeCommand(CommandInterface $command) { $this->getConnection($command)->writeCommand($command); } /** * {@inheritdoc} */ public function readResponse(CommandInterface $command) { return $this->getConnection($command)->readResponse($command); } /** * {@inheritdoc} */ public function executeCommand(CommandInterface $command) { return $this->getConnection($command)->executeCommand($command); } /** * {@inheritdoc} */ public function __sleep() { return array('master', 'slaves', 'strategy'); } } predis-0.8.3/lib/Predis/Connection/PhpiredisConnection.php000066400000000000000000000255451211043230100235610ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\ClientException; use Predis\NotSupportedException; use Predis\ResponseError; use Predis\ResponseQueued; use Predis\Command\CommandInterface; /** * This class provides the implementation of a Predis connection that uses the * PHP socket extension for network communication and wraps the phpiredis C * extension (PHP bindings for hiredis) to parse the Redis protocol. Everything * is highly experimental (even the very same phpiredis since it is quite new), * so use it at your own risk. * * This class is mainly intended to provide an optional low-overhead alternative * for processing replies from Redis compared to the standard pure-PHP classes. * Differences in speed when dealing with short inline replies are practically * nonexistent, the actual speed boost is for long multibulk replies when this * protocol processor can parse and return replies very fast. * * For instructions on how to build and install the phpiredis extension, please * consult the repository of the project. * * The connection parameters supported by this class are: * * - scheme: it can be either 'tcp' or 'unix'. * - host: hostname or IP address of the server. * - port: TCP port of the server. * - timeout: timeout to perform the connection. * - read_write_timeout: timeout of read / write operations. * * @link http://github.com/nrk/phpiredis * @author Daniele Alessandri */ class PhpiredisConnection extends AbstractConnection { const ERR_MSG_EXTENSION = 'The %s extension must be loaded in order to be able to use this connection class'; private $reader; /** * {@inheritdoc} */ public function __construct(ConnectionParametersInterface $parameters) { $this->checkExtensions(); $this->initializeReader(); parent::__construct($parameters); } /** * Disconnects from the server and destroys the underlying resource and the * protocol reader resource when PHP's garbage collector kicks in. */ public function __destruct() { phpiredis_reader_destroy($this->reader); parent::__destruct(); } /** * Checks if the socket and phpiredis extensions are loaded in PHP. */ private function checkExtensions() { if (!function_exists('socket_create')) { throw new NotSupportedException(sprintf(self::ERR_MSG_EXTENSION, 'socket')); } if (!function_exists('phpiredis_reader_create')) { throw new NotSupportedException(sprintf(self::ERR_MSG_EXTENSION, 'phpiredis')); } } /** * {@inheritdoc} */ protected function checkParameters(ConnectionParametersInterface $parameters) { if (isset($parameters->iterable_multibulk)) { $this->onInvalidOption('iterable_multibulk', $parameters); } if (isset($parameters->persistent)) { $this->onInvalidOption('persistent', $parameters); } return parent::checkParameters($parameters); } /** * Initializes the protocol reader resource. */ private function initializeReader() { $reader = phpiredis_reader_create(); phpiredis_reader_set_status_handler($reader, $this->getStatusHandler()); phpiredis_reader_set_error_handler($reader, $this->getErrorHandler()); $this->reader = $reader; } /** * Gets the handler used by the protocol reader to handle status replies. * * @return \Closure */ private function getStatusHandler() { return function ($payload) { switch ($payload) { case 'OK': return true; case 'QUEUED': return new ResponseQueued(); default: return $payload; } }; } /** * Gets the handler used by the protocol reader to handle Redis errors. * * @param Boolean $throw_errors Specify if Redis errors throw exceptions. * @return \Closure */ private function getErrorHandler() { return function ($errorMessage) { return new ResponseError($errorMessage); }; } /** * Helper method used to throw exceptions on socket errors. */ private function emitSocketError() { $errno = socket_last_error(); $errstr = socket_strerror($errno); $this->disconnect(); $this->onConnectionError(trim($errstr), $errno); } /** * {@inheritdoc} */ protected function createResource() { $parameters = $this->parameters; $isUnix = $this->parameters->scheme === 'unix'; $domain = $isUnix ? AF_UNIX : AF_INET; $protocol = $isUnix ? 0 : SOL_TCP; $socket = @call_user_func('socket_create', $domain, SOCK_STREAM, $protocol); if (!is_resource($socket)) { $this->emitSocketError(); } $this->setSocketOptions($socket, $parameters); return $socket; } /** * Sets options on the socket resource from the connection parameters. * * @param resource $socket Socket resource. * @param ConnectionParametersInterface $parameters Parameters used to initialize the connection. */ private function setSocketOptions($socket, ConnectionParametersInterface $parameters) { if ($parameters->scheme !== 'tcp') { return; } if (!socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1)) { $this->emitSocketError(); } if (!socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1)) { $this->emitSocketError(); } if (isset($parameters->read_write_timeout)) { $rwtimeout = $parameters->read_write_timeout; $timeoutSec = floor($rwtimeout); $timeoutUsec = ($rwtimeout - $timeoutSec) * 1000000; $timeout = array( 'sec' => $timeoutSec, 'usec' => $timeoutUsec, ); if (!socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, $timeout)) { $this->emitSocketError(); } if (!socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, $timeout)) { $this->emitSocketError(); } } } /** * Gets the address from the connection parameters. * * @param ConnectionParametersInterface $parameters Parameters used to initialize the connection. * @return string */ private function getAddress(ConnectionParametersInterface $parameters) { if ($parameters->scheme === 'unix') { return $parameters->path; } $host = $parameters->host; if (ip2long($host) === false) { if (($address = gethostbyname($host)) === $host) { $this->onConnectionError("Cannot resolve the address of $host"); } return $address; } return $host; } /** * Opens the actual connection to the server with a timeout. * * @param ConnectionParametersInterface $parameters Parameters used to initialize the connection. * @return string */ private function connectWithTimeout(ConnectionParametersInterface $parameters) { $host = self::getAddress($parameters); $socket = $this->getResource(); socket_set_nonblock($socket); if (@socket_connect($socket, $host, $parameters->port) === false) { $error = socket_last_error(); if ($error != SOCKET_EINPROGRESS && $error != SOCKET_EALREADY) { $this->emitSocketError(); } } socket_set_block($socket); $null = null; $selectable = array($socket); $timeout = $parameters->timeout; $timeoutSecs = floor($timeout); $timeoutUSecs = ($timeout - $timeoutSecs) * 1000000; $selected = socket_select($selectable, $selectable, $null, $timeoutSecs, $timeoutUSecs); if ($selected === 2) { $this->onConnectionError('Connection refused', SOCKET_ECONNREFUSED); } if ($selected === 0) { $this->onConnectionError('Connection timed out', SOCKET_ETIMEDOUT); } if ($selected === false) { $this->emitSocketError(); } } /** * {@inheritdoc} */ public function connect() { parent::connect(); $this->connectWithTimeout($this->parameters); if ($this->initCmds) { $this->sendInitializationCommands(); } } /** * {@inheritdoc} */ public function disconnect() { if ($this->isConnected()) { socket_close($this->getResource()); parent::disconnect(); } } /** * Sends the initialization commands to Redis when the connection is opened. */ private function sendInitializationCommands() { foreach ($this->initCmds as $command) { $this->writeCommand($command); } foreach ($this->initCmds as $command) { $this->readResponse($command); } } /** * {@inheritdoc} */ protected function write($buffer) { $socket = $this->getResource(); while (($length = strlen($buffer)) > 0) { $written = socket_write($socket, $buffer, $length); if ($length === $written) { return; } if ($written === false) { $this->onConnectionError('Error while writing bytes to the server'); } $buffer = substr($buffer, $written); } } /** * {@inheritdoc} */ public function read() { $socket = $this->getResource(); $reader = $this->reader; while (($state = phpiredis_reader_get_state($reader)) === PHPIREDIS_READER_STATE_INCOMPLETE) { if (@socket_recv($socket, $buffer, 4096, 0) === false || $buffer === '') { $this->emitSocketError(); } phpiredis_reader_feed($reader, $buffer); } if ($state === PHPIREDIS_READER_STATE_COMPLETE) { return phpiredis_reader_get_reply($reader); } else { $this->onProtocolError(phpiredis_reader_get_error($reader)); } } /** * {@inheritdoc} */ public function writeCommand(CommandInterface $command) { $cmdargs = $command->getArguments(); array_unshift($cmdargs, $command->getId()); $this->write(phpiredis_format_command($cmdargs)); } /** * {@inheritdoc} */ public function __wakeup() { $this->checkExtensions(); $this->initializeReader(); } } predis-0.8.3/lib/Predis/Connection/PhpiredisStreamConnection.php000066400000000000000000000126741211043230100247340ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\NotSupportedException; use Predis\ResponseError; use Predis\ResponseQueued; use Predis\Command\CommandInterface; /** * This class provides the implementation of a Predis connection that uses PHP's * streams for network communication and wraps the phpiredis C extension (PHP * bindings for hiredis) to parse and serialize the Redis protocol. Everything * is highly experimental (even the very same phpiredis since it is quite new), * so use it at your own risk. * * This class is mainly intended to provide an optional low-overhead alternative * for processing replies from Redis compared to the standard pure-PHP classes. * Differences in speed when dealing with short inline replies are practically * nonexistent, the actual speed boost is for long multibulk replies when this * protocol processor can parse and return replies very fast. * * For instructions on how to build and install the phpiredis extension, please * consult the repository of the project. * * The connection parameters supported by this class are: * * - scheme: it can be either 'tcp' or 'unix'. * - host: hostname or IP address of the server. * - port: TCP port of the server. * - timeout: timeout to perform the connection. * - read_write_timeout: timeout of read / write operations. * - async_connect: performs the connection asynchronously. * - tcp_nodelay: enables or disables Nagle's algorithm for coalescing. * - persistent: the connection is left intact after a GC collection. * * @link https://github.com/nrk/phpiredis * @author Daniele Alessandri */ class PhpiredisStreamConnection extends StreamConnection { private $reader; /** * {@inheritdoc} */ public function __construct(ConnectionParametersInterface $parameters) { $this->checkExtensions(); $this->initializeReader(); parent::__construct($parameters); } /** * {@inheritdoc} */ public function __destruct() { phpiredis_reader_destroy($this->reader); parent::__destruct(); } /** * Checks if the phpiredis extension is loaded in PHP. */ protected function checkExtensions() { if (!function_exists('phpiredis_reader_create')) { throw new NotSupportedException( 'The phpiredis extension must be loaded in order to be able to use this connection class' ); } } /** * {@inheritdoc} */ protected function checkParameters(ConnectionParametersInterface $parameters) { if (isset($parameters->iterable_multibulk)) { $this->onInvalidOption('iterable_multibulk', $parameters); } return parent::checkParameters($parameters); } /** * Initializes the protocol reader resource. */ protected function initializeReader() { $reader = phpiredis_reader_create(); phpiredis_reader_set_status_handler($reader, $this->getStatusHandler()); phpiredis_reader_set_error_handler($reader, $this->getErrorHandler()); $this->reader = $reader; } /** * Gets the handler used by the protocol reader to handle status replies. * * @return \Closure */ protected function getStatusHandler() { return function ($payload) { switch ($payload) { case 'OK': return true; case 'QUEUED': return new ResponseQueued(); default: return $payload; } }; } /** * Gets the handler used by the protocol reader to handle Redis errors. * * @param Boolean $throw_errors Specify if Redis errors throw exceptions. * @return \Closure */ protected function getErrorHandler() { return function ($errorMessage) { return new ResponseError($errorMessage); }; } /** * {@inheritdoc} */ public function read() { $socket = $this->getResource(); $reader = $this->reader; while (PHPIREDIS_READER_STATE_INCOMPLETE === $state = phpiredis_reader_get_state($reader)) { $buffer = fread($socket, 4096); if ($buffer === false || $buffer === '') { $this->onConnectionError('Error while reading bytes from the server'); return; } phpiredis_reader_feed($reader, $buffer); } if ($state === PHPIREDIS_READER_STATE_COMPLETE) { return phpiredis_reader_get_reply($reader); } else { $this->onProtocolError(phpiredis_reader_get_error($reader)); } } /** * {@inheritdoc} */ public function writeCommand(CommandInterface $command) { $cmdargs = $command->getArguments(); array_unshift($cmdargs, $command->getId()); $this->writeBytes(phpiredis_format_command($cmdargs)); } /** * {@inheritdoc} */ public function __sleep() { return array_diff(parent::__sleep(), array('mbiterable')); } /** * {@inheritdoc} */ public function __wakeup() { $this->checkExtensions(); $this->initializeReader(); } } predis-0.8.3/lib/Predis/Connection/PredisCluster.php000066400000000000000000000130421211043230100223670ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\ClientException; use Predis\NotSupportedException; use Predis\Cluster\PredisClusterHashStrategy; use Predis\Cluster\Distribution\DistributionStrategyInterface; use Predis\Cluster\Distribution\HashRing; use Predis\Command\CommandInterface; /** * Abstraction for a cluster of aggregated connections to various Redis servers * implementing client-side sharding based on pluggable distribution strategies. * * @author Daniele Alessandri * @todo Add the ability to remove connections from pool. */ class PredisCluster implements ClusterConnectionInterface, \IteratorAggregate, \Countable { private $pool; private $strategy; private $distributor; /** * @param DistributionStrategyInterface $distributor Distribution strategy used by the cluster. */ public function __construct(DistributionStrategyInterface $distributor = null) { $distributor = $distributor ?: new HashRing(); $this->pool = array(); $this->strategy = new PredisClusterHashStrategy($distributor->getHashGenerator()); $this->distributor = $distributor; } /** * {@inheritdoc} */ public function isConnected() { foreach ($this->pool as $connection) { if ($connection->isConnected()) { return true; } } return false; } /** * {@inheritdoc} */ public function connect() { foreach ($this->pool as $connection) { $connection->connect(); } } /** * {@inheritdoc} */ public function disconnect() { foreach ($this->pool as $connection) { $connection->disconnect(); } } /** * {@inheritdoc} */ public function add(SingleConnectionInterface $connection) { $parameters = $connection->getParameters(); if (isset($parameters->alias)) { $this->pool[$parameters->alias] = $connection; } else { $this->pool[] = $connection; } $weight = isset($parameters->weight) ? $parameters->weight : null; $this->distributor->add($connection, $weight); } /** * {@inheritdoc} */ public function remove(SingleConnectionInterface $connection) { if (($id = array_search($connection, $this->pool, true)) !== false) { unset($this->pool[$id]); $this->distributor->remove($connection); return true; } return false; } /** * Removes a connection instance using its alias or index. * * @param string $connectionId Alias or index of a connection. * @return Boolean Returns true if the connection was in the pool. */ public function removeById($connectionId) { if ($connection = $this->getConnectionById($connectionId)) { return $this->remove($connection); } return false; } /** * {@inheritdoc} */ public function getConnection(CommandInterface $command) { $hash = $this->strategy->getHash($command); if (!isset($hash)) { throw new NotSupportedException("Cannot use {$command->getId()} with a cluster of connections"); } $node = $this->distributor->get($hash); return $node; } /** * {@inheritdoc} */ public function getConnectionById($connectionId) { return isset($this->pool[$connectionId]) ? $this->pool[$connectionId] : null; } /** * Retrieves a connection instance from the cluster using a key. * * @param string $key Key of a Redis value. * @return SingleConnectionInterface */ public function getConnectionByKey($key) { $hash = $this->strategy->getKeyHash($key); $node = $this->distributor->get($hash); return $node; } /** * Returns the underlying command hash strategy used to hash * commands by their keys. * * @return Predis\Cluster\CommandHashStrategyInterface */ public function getCommandHashStrategy() { return $this->strategy; } /** * {@inheritdoc} */ public function count() { return count($this->pool); } /** * {@inheritdoc} */ public function getIterator() { return new \ArrayIterator($this->pool); } /** * {@inheritdoc} */ public function writeCommand(CommandInterface $command) { $this->getConnection($command)->writeCommand($command); } /** * {@inheritdoc} */ public function readResponse(CommandInterface $command) { return $this->getConnection($command)->readResponse($command); } /** * {@inheritdoc} */ public function executeCommand(CommandInterface $command) { return $this->getConnection($command)->executeCommand($command); } /** * Executes the specified Redis command on all the nodes of a cluster. * * @param CommandInterface $command A Redis command. * @return array */ public function executeCommandOnNodes(CommandInterface $command) { $replies = array(); foreach ($this->pool as $connection) { $replies[] = $connection->executeCommand($command); } return $replies; } } predis-0.8.3/lib/Predis/Connection/RedisCluster.php000066400000000000000000000236351211043230100222200ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\ClientException; use Predis\NotSupportedException; use Predis\ResponseErrorInterface; use Predis\Cluster\RedisClusterHashStrategy; use Predis\Command\CommandInterface; /** * Abstraction for Redis cluster (Redis v3.0). * * @author Daniele Alessandri */ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \Countable { private $pool; private $slots; private $slotsMap; private $slotsPerNode; private $strategy; private $connections; /** * @param ConnectionFactoryInterface $connections Connection factory object. */ public function __construct(ConnectionFactoryInterface $connections = null) { $this->pool = array(); $this->slots = array(); $this->strategy = new RedisClusterHashStrategy(); $this->connections = $connections ?: new ConnectionFactory(); } /** * {@inheritdoc} */ public function isConnected() { foreach ($this->pool as $connection) { if ($connection->isConnected()) { return true; } } return false; } /** * {@inheritdoc} */ public function connect() { foreach ($this->pool as $connection) { $connection->connect(); } } /** * {@inheritdoc} */ public function disconnect() { foreach ($this->pool as $connection) { $connection->disconnect(); } } /** * {@inheritdoc} */ public function add(SingleConnectionInterface $connection) { $this->pool[(string) $connection] = $connection; unset( $this->slotsMap, $this->slotsPerNode ); } /** * {@inheritdoc} */ public function remove(SingleConnectionInterface $connection) { if (($id = array_search($connection, $this->pool, true)) !== false) { unset( $this->pool[$id], $this->slotsMap, $this->slotsPerNode ); return true; } return false; } /** * Removes a connection instance using its alias or index. * * @param string $connectionId Alias or index of a connection. * @return Boolean Returns true if the connection was in the pool. */ public function removeById($connectionId) { if (isset($this->pool[$connectionId])) { unset( $this->pool[$connectionId], $this->slotsMap, $this->slotsPerNode ); return true; } return false; } /** * Builds the slots map for the cluster. * * @return array */ public function buildSlotsMap() { $this->slotsMap = array(); $this->slotsPerNode = (int) (16384 / count($this->pool)); foreach ($this->pool as $connectionID => $connection) { $parameters = $connection->getParameters(); if (!isset($parameters->slots)) { continue; } list($first, $last) = explode('-', $parameters->slots, 2); $this->setSlots($first, $last, $connectionID); } return $this->slotsMap; } /** * Returns the current slots map for the cluster. * * @return array */ public function getSlotsMap() { if (!isset($this->slotsMap)) { $this->slotsMap = array(); } return $this->slotsMap; } /** * Preassociate a connection to a set of slots to avoid runtime guessing. * * @todo Check type or existence of the specified connection. * @todo Cluster loses the slots assigned with this methods when adding / removing connections. * * @param int $first Initial slot. * @param int $last Last slot. * @param SingleConnectionInterface|string $connection ID or connection instance. */ public function setSlots($first, $last, $connection) { if ($first < 0x0000 || $first > 0x3FFF || $last < 0x0000 || $last > 0x3FFF || $last < $first) { throw new \OutOfBoundsException("Invalid slot values for $connection: [$first-$last]"); } $this->slotsMap = $this->getSlotsMap() + array_fill($first, $last - $first + 1, (string) $connection); } /** * {@inheritdoc} */ public function getConnection(CommandInterface $command) { $hash = $this->strategy->getHash($command); if (!isset($hash)) { throw new NotSupportedException("Cannot use {$command->getId()} with redis-cluster"); } $slot = $hash & 0x3FFF; if (isset($this->slots[$slot])) { return $this->slots[$slot]; } $this->slots[$slot] = $connection = $this->pool[$this->guessNode($slot)]; return $connection; } /** * Returns the connection associated to the specified slot. * * @param int $slot Slot ID. * @return SingleConnectionInterface */ public function getConnectionBySlot($slot) { if ($slot < 0x0000 || $slot > 0x3FFF) { throw new \OutOfBoundsException("Invalid slot value [$slot]"); } if (isset($this->slots[$slot])) { return $this->slots[$slot]; } return $this->pool[$this->guessNode($slot)]; } /** * {@inheritdoc} */ public function getConnectionById($connectionId) { return isset($this->pool[$connectionId]) ? $this->pool[$connectionId] : null; } /** * Tries guessing the correct node associated to the given slot using a precalculated * slots map or the same logic used by redis-trib to initialize a redis cluster. * * @param int $slot Slot ID. * @return string */ protected function guessNode($slot) { if (!isset($this->slotsMap)) { $this->buildSlotsMap(); } if (isset($this->slotsMap[$slot])) { return $this->slotsMap[$slot]; } $index = min((int) ($slot / $this->slotsPerNode), count($this->pool) - 1); $nodes = array_keys($this->pool); return $nodes[$index]; } /** * Handles -MOVED or -ASK replies by re-executing the command on the server * specified by the Redis reply. * * @param CommandInterface $command Command that generated the -MOVE or -ASK reply. * @param string $request Type of request (either 'MOVED' or 'ASK'). * @param string $details Parameters of the MOVED/ASK request. * @return mixed */ protected function onMoveRequest(CommandInterface $command, $request, $details) { list($slot, $host) = explode(' ', $details, 2); $connection = $this->getConnectionById($host); if (!isset($connection)) { $parameters = array('host' => null, 'port' => null); list($parameters['host'], $parameters['port']) = explode(':', $host, 2); $connection = $this->connections->create($parameters); } switch ($request) { case 'MOVED': $this->move($connection, $slot); return $this->executeCommand($command); case 'ASK': return $connection->executeCommand($command); default: throw new ClientException("Unexpected request type for a move request: $request"); } } /** * Assign the connection instance to a new slot and adds it to the * pool if the connection was not already part of the pool. * * @param SingleConnectionInterface $connection Connection instance * @param int $slot Target slot. */ protected function move(SingleConnectionInterface $connection, $slot) { $this->pool[(string) $connection] = $connection; $this->slots[(int) $slot] = $connection; } /** * Returns the underlying command hash strategy used to hash * commands by their keys. * * @return Predis\Cluster\CommandHashStrategyInterface */ public function getCommandHashStrategy() { return $this->strategy; } /** * {@inheritdoc} */ public function count() { return count($this->pool); } /** * {@inheritdoc} */ public function getIterator() { return new \ArrayIterator(array_values($this->pool)); } /** * Handles -ERR replies from Redis. * * @param CommandInterface $command Command that generated the -ERR reply. * @param ResponseErrorInterface $error Redis error reply object. * @return mixed */ protected function handleServerError(CommandInterface $command, ResponseErrorInterface $error) { list($type, $details) = explode(' ', $error->getMessage(), 2); switch ($type) { case 'MOVED': case 'ASK': return $this->onMoveRequest($command, $type, $details); default: return $error; } } /** * {@inheritdoc} */ public function writeCommand(CommandInterface $command) { $this->getConnection($command)->writeCommand($command); } /** * {@inheritdoc} */ public function readResponse(CommandInterface $command) { return $this->getConnection($command)->readResponse($command); } /** * {@inheritdoc} */ public function executeCommand(CommandInterface $command) { $connection = $this->getConnection($command); $reply = $connection->executeCommand($command); if ($reply instanceof ResponseErrorInterface) { return $this->handleServerError($command, $reply); } return $reply; } } predis-0.8.3/lib/Predis/Connection/ReplicationConnectionInterface.php000066400000000000000000000022731211043230100257150ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\Command\CommandInterface; /** * Defines a group of Redis servers in a master/slave replication configuration. * * @author Daniele Alessandri */ interface ReplicationConnectionInterface extends AggregatedConnectionInterface { /** * Switches the internal connection object being used. * * @param string $connection Alias of a connection */ public function switchTo($connection); /** * Retrieves the connection object currently being used. * * @return SingleConnectionInterface */ public function getCurrent(); /** * Retrieves the connection object to the master Redis server. * * @return SingleConnectionInterface */ public function getMaster(); /** * Retrieves a list of connection objects to slaves Redis servers. * * @return SingleConnectionInterface */ public function getSlaves(); } predis-0.8.3/lib/Predis/Connection/SingleConnectionInterface.php000066400000000000000000000025731211043230100246700ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\Command\CommandInterface; /** * Defines a connection object used to communicate with a single Redis server. * * @author Daniele Alessandri */ interface SingleConnectionInterface extends ConnectionInterface { /** * Returns a string representation of the connection. * * @return string */ public function __toString(); /** * Returns the underlying resource used to communicate with a Redis server. * * @return mixed */ public function getResource(); /** * Gets the parameters used to initialize the connection object. * * @return ConnectionParametersInterface */ public function getParameters(); /** * Pushes the instance of a Redis command to the queue of commands executed * when the actual connection to a server is estabilished. * * @param CommandInterface $command Instance of a Redis command. */ public function pushInitCommand(CommandInterface $command); /** * Reads a reply from the server. * * @return mixed */ public function read(); } predis-0.8.3/lib/Predis/Connection/StreamConnection.php000066400000000000000000000207651211043230100230640ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\NotSupportedException; use Predis\ResponseError; use Predis\ResponseQueued; use Predis\Command\CommandInterface; use Predis\Iterator\MultiBulkResponseSimple; /** * Standard connection to Redis servers implemented on top of PHP's streams. * The connection parameters supported by this class are: * * - scheme: it can be either 'tcp' or 'unix'. * - host: hostname or IP address of the server. * - port: TCP port of the server. * - timeout: timeout to perform the connection. * - read_write_timeout: timeout of read / write operations. * - async_connect: performs the connection asynchronously. * - tcp_nodelay: enables or disables Nagle's algorithm for coalescing. * - persistent: the connection is left intact after a GC collection. * - iterable_multibulk: multibulk replies treated as iterable objects. * * @author Daniele Alessandri */ class StreamConnection extends AbstractConnection { private $mbiterable; /** * {@inheritdoc} */ public function __construct(ConnectionParametersInterface $parameters) { $this->mbiterable = (bool) $parameters->iterable_multibulk; parent::__construct($parameters); } /** * Disconnects from the server and destroys the underlying resource when * PHP's garbage collector kicks in only if the connection has not been * marked as persistent. */ public function __destruct() { if (isset($this->parameters) && !$this->parameters->persistent) { $this->disconnect(); } } /** * {@inheritdoc} */ protected function createResource() { $parameters = $this->parameters; $initializer = "{$parameters->scheme}StreamInitializer"; return $this->$initializer($parameters); } /** * Initializes a TCP stream resource. * * @param ConnectionParametersInterface $parameters Parameters used to initialize the connection. * @return resource */ private function tcpStreamInitializer(ConnectionParametersInterface $parameters) { $uri = "tcp://{$parameters->host}:{$parameters->port}/"; $flags = STREAM_CLIENT_CONNECT; if (isset($parameters->async_connect) && $parameters->async_connect) { $flags |= STREAM_CLIENT_ASYNC_CONNECT; } if (isset($parameters->persistent) && $parameters->persistent) { $flags |= STREAM_CLIENT_PERSISTENT; } $resource = @stream_socket_client($uri, $errno, $errstr, $parameters->timeout, $flags); if (!$resource) { $this->onConnectionError(trim($errstr), $errno); } if (isset($parameters->read_write_timeout)) { $rwtimeout = $parameters->read_write_timeout; $rwtimeout = $rwtimeout > 0 ? $rwtimeout : -1; $timeoutSeconds = floor($rwtimeout); $timeoutUSeconds = ($rwtimeout - $timeoutSeconds) * 1000000; stream_set_timeout($resource, $timeoutSeconds, $timeoutUSeconds); } if (isset($parameters->tcp_nodelay) && version_compare(PHP_VERSION, '5.4.0') >= 0) { $socket = socket_import_stream($resource); socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $parameters->tcp_nodelay); } return $resource; } /** * Initializes a UNIX stream resource. * * @param ConnectionParametersInterface $parameters Parameters used to initialize the connection. * @return resource */ private function unixStreamInitializer(ConnectionParametersInterface $parameters) { $uri = "unix://{$parameters->path}"; $flags = STREAM_CLIENT_CONNECT; if ($parameters->persistent) { $flags |= STREAM_CLIENT_PERSISTENT; } $resource = @stream_socket_client($uri, $errno, $errstr, $parameters->timeout, $flags); if (!$resource) { $this->onConnectionError(trim($errstr), $errno); } return $resource; } /** * {@inheritdoc} */ public function connect() { parent::connect(); if ($this->initCmds) { $this->sendInitializationCommands(); } } /** * {@inheritdoc} */ public function disconnect() { if ($this->isConnected()) { fclose($this->getResource()); parent::disconnect(); } } /** * Sends the initialization commands to Redis when the connection is opened. */ private function sendInitializationCommands() { foreach ($this->initCmds as $command) { $this->writeCommand($command); } foreach ($this->initCmds as $command) { $this->readResponse($command); } } /** * Performs a write operation on the stream of the buffer containing a * command serialized with the Redis wire protocol. * * @param string $buffer Redis wire protocol representation of a command. */ protected function writeBytes($buffer) { $socket = $this->getResource(); while (($length = strlen($buffer)) > 0) { $written = fwrite($socket, $buffer); if ($length === $written) { return; } if ($written === false || $written === 0) { $this->onConnectionError('Error while writing bytes to the server'); } $buffer = substr($buffer, $written); } } /** * {@inheritdoc} */ public function read() { $socket = $this->getResource(); $chunk = fgets($socket); if ($chunk === false || $chunk === '') { $this->onConnectionError('Error while reading line from the server'); } $prefix = $chunk[0]; $payload = substr($chunk, 1, -2); switch ($prefix) { case '+': // inline switch ($payload) { case 'OK': return true; case 'QUEUED': return new ResponseQueued(); default: return $payload; } case '$': // bulk $size = (int) $payload; if ($size === -1) { return null; } $bulkData = ''; $bytesLeft = ($size += 2); do { $chunk = fread($socket, min($bytesLeft, 4096)); if ($chunk === false || $chunk === '') { $this->onConnectionError('Error while reading bytes from the server'); } $bulkData .= $chunk; $bytesLeft = $size - strlen($bulkData); } while ($bytesLeft > 0); return substr($bulkData, 0, -2); case '*': // multi bulk $count = (int) $payload; if ($count === -1) { return null; } if ($this->mbiterable) { return new MultiBulkResponseSimple($this, $count); } $multibulk = array(); for ($i = 0; $i < $count; $i++) { $multibulk[$i] = $this->read(); } return $multibulk; case ':': // integer return (int) $payload; case '-': // error return new ResponseError($payload); default: $this->onProtocolError("Unknown prefix: '$prefix'"); } } /** * {@inheritdoc} */ public function writeCommand(CommandInterface $command) { $commandId = $command->getId(); $arguments = $command->getArguments(); $cmdlen = strlen($commandId); $reqlen = count($arguments) + 1; $buffer = "*{$reqlen}\r\n\${$cmdlen}\r\n{$commandId}\r\n"; for ($i = 0; $i < $reqlen - 1; $i++) { $argument = $arguments[$i]; $arglen = strlen($argument); $buffer .= "\${$arglen}\r\n{$argument}\r\n"; } $this->writeBytes($buffer); } /** * {@inheritdoc} */ public function __sleep() { return array_merge(parent::__sleep(), array('mbiterable')); } } predis-0.8.3/lib/Predis/Connection/WebdisConnection.php000066400000000000000000000215151211043230100230400ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use Predis\NotSupportedException; use Predis\ResponseError; use Predis\Command\CommandInterface; use Predis\Connection\ConnectionException; use Predis\Protocol\ProtocolException; /** * This class implements a Predis connection that actually talks with Webdis * instead of connecting directly to Redis. It relies on the cURL extension to * communicate with the web server and the phpiredis extension to parse the * protocol of the replies returned in the http response bodies. * * Some features are not yet available or they simply cannot be implemented: * - Pipelining commands. * - Publish / Subscribe. * - MULTI / EXEC transactions (not yet supported by Webdis). * * The connection parameters supported by this class are: * * - scheme: must be 'http'. * - host: hostname or IP address of the server. * - port: TCP port of the server. * - timeout: timeout to perform the connection. * - user: username for authentication. * - pass: password for authentication. * * @link http://webd.is * @link http://github.com/nicolasff/webdis * @link http://github.com/seppo0010/phpiredis * @author Daniele Alessandri */ class WebdisConnection implements SingleConnectionInterface { const ERR_MSG_EXTENSION = 'The %s extension must be loaded in order to be able to use this connection class'; private $parameters; private $resource; private $reader; /** * @param ConnectionParametersInterface $parameters Parameters used to initialize the connection. */ public function __construct(ConnectionParametersInterface $parameters) { $this->checkExtensions(); if ($parameters->scheme !== 'http') { throw new \InvalidArgumentException("Invalid scheme: {$parameters->scheme}"); } $this->parameters = $parameters; $this->resource = $this->initializeCurl($parameters); $this->reader = $this->initializeReader($parameters); } /** * Frees the underlying cURL and protocol reader resources when PHP's * garbage collector kicks in. */ public function __destruct() { curl_close($this->resource); phpiredis_reader_destroy($this->reader); } /** * Helper method used to throw on unsupported methods. */ private function throwNotSupportedException($function) { $class = __CLASS__; throw new NotSupportedException("The method $class::$function() is not supported"); } /** * Checks if the cURL and phpiredis extensions are loaded in PHP. */ private function checkExtensions() { if (!function_exists('curl_init')) { throw new NotSupportedException(sprintf(self::ERR_MSG_EXTENSION, 'curl')); } if (!function_exists('phpiredis_reader_create')) { throw new NotSupportedException(sprintf(self::ERR_MSG_EXTENSION, 'phpiredis')); } } /** * Initializes cURL. * * @param ConnectionParametersInterface $parameters Parameters used to initialize the connection. * @return resource */ private function initializeCurl(ConnectionParametersInterface $parameters) { $options = array( CURLOPT_FAILONERROR => true, CURLOPT_CONNECTTIMEOUT_MS => $parameters->timeout * 1000, CURLOPT_URL => "{$parameters->scheme}://{$parameters->host}:{$parameters->port}", CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_POST => true, CURLOPT_WRITEFUNCTION => array($this, 'feedReader'), ); if (isset($parameters->user, $parameters->pass)) { $options[CURLOPT_USERPWD] = "{$parameters->user}:{$parameters->pass}"; } curl_setopt_array($resource = curl_init(), $options); return $resource; } /** * Initializes phpiredis' protocol reader. * * @param ConnectionParametersInterface $parameters Parameters used to initialize the connection. * @return resource */ private function initializeReader(ConnectionParametersInterface $parameters) { $reader = phpiredis_reader_create(); phpiredis_reader_set_status_handler($reader, $this->getStatusHandler()); phpiredis_reader_set_error_handler($reader, $this->getErrorHandler()); return $reader; } /** * Gets the handler used by the protocol reader to handle status replies. * * @return \Closure */ protected function getStatusHandler() { return function ($payload) { return $payload === 'OK' ? true : $payload; }; } /** * Gets the handler used by the protocol reader to handle Redis errors. * * @return \Closure */ protected function getErrorHandler() { return function ($errorMessage) { return new ResponseError($errorMessage); }; } /** * Feeds phpredis' reader resource with the data read from the network. * * @param resource $resource Reader resource. * @param string $buffer Buffer with the reply read from the network. * @return int */ protected function feedReader($resource, $buffer) { phpiredis_reader_feed($this->reader, $buffer); return strlen($buffer); } /** * {@inheritdoc} */ public function connect() { // NOOP } /** * {@inheritdoc} */ public function disconnect() { // NOOP } /** * {@inheritdoc} */ public function isConnected() { return true; } /** * Checks if the specified command is supported by this connection class. * * @param CommandInterface $command The instance of a Redis command. * @return string */ protected function getCommandId(CommandInterface $command) { switch (($commandId = $command->getId())) { case 'AUTH': case 'SELECT': case 'MULTI': case 'EXEC': case 'WATCH': case 'UNWATCH': case 'DISCARD': case 'MONITOR': throw new NotSupportedException("Disabled command: {$command->getId()}"); default: return $commandId; } } /** * {@inheritdoc} */ public function writeCommand(CommandInterface $command) { $this->throwNotSupportedException(__FUNCTION__); } /** * {@inheritdoc} */ public function readResponse(CommandInterface $command) { $this->throwNotSupportedException(__FUNCTION__); } /** * {@inheritdoc} */ public function executeCommand(CommandInterface $command) { $resource = $this->resource; $commandId = $this->getCommandId($command); if ($arguments = $command->getArguments()) { $arguments = implode('/', array_map('urlencode', $arguments)); $serializedCommand = "$commandId/$arguments.raw"; } else { $serializedCommand = "$commandId.raw"; } curl_setopt($resource, CURLOPT_POSTFIELDS, $serializedCommand); if (curl_exec($resource) === false) { $error = curl_error($resource); $errno = curl_errno($resource); throw new ConnectionException($this, trim($error), $errno); } if (phpiredis_reader_get_state($this->reader) !== PHPIREDIS_READER_STATE_COMPLETE) { throw new ProtocolException($this, phpiredis_reader_get_error($this->reader)); } return phpiredis_reader_get_reply($this->reader); } /** * {@inheritdoc} */ public function getResource() { return $this->resource; } /** * {@inheritdoc} */ public function getParameters() { return $this->parameters; } /** * {@inheritdoc} */ public function pushInitCommand(CommandInterface $command) { $this->throwNotSupportedException(__FUNCTION__); } /** * {@inheritdoc} */ public function read() { $this->throwNotSupportedException(__FUNCTION__); } /** * {@inheritdoc} */ public function __toString() { return "{$this->parameters->host}:{$this->parameters->port}"; } /** * {@inheritdoc} */ public function __sleep() { return array('parameters'); } /** * {@inheritdoc} */ public function __wakeup() { $this->checkExtensions(); $parameters = $this->getParameters(); $this->resource = $this->initializeCurl($parameters); $this->reader = $this->initializeReader($parameters); } } predis-0.8.3/lib/Predis/ExecutableContextInterface.php000066400000000000000000000012301211043230100227430ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis; /** * Defines the interface of a basic client object or abstraction that * can send commands to Redis. * * @author Daniele Alessandri */ interface ExecutableContextInterface { /** * Starts the execution of the context. * * @param mixed $callable Optional callback for execution. * @return array */ public function execute($callable = null); } predis-0.8.3/lib/Predis/Helpers.php000066400000000000000000000042431211043230100171050ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis; use Predis\Connection\AggregatedConnectionInterface; use Predis\Connection\ClusterConnectionInterface; use Predis\Connection\ConnectionInterface; /** * Defines a few helper methods. * * @author Daniele Alessandri * @deprecated Deprecated since v0.8.3. */ class Helpers { /** * Offers a generic and reusable method to handle exceptions generated by * a connection object. * * @deprecated Deprecated since v0.8.3 - moved in Predis\CommunicationException::handle() * @param CommunicationException $exception Exception. */ public static function onCommunicationException(CommunicationException $exception) { if ($exception->shouldResetConnection()) { $connection = $exception->getConnection(); if ($connection->isConnected()) { $connection->disconnect(); } } throw $exception; } /** * Normalizes the arguments array passed to a Redis command. * * @deprecated Deprecated since v0.8.3 - moved in Predis\Command\AbstractCommand::normalizeArguments() * @param array $arguments Arguments for a command. * @return array */ public static function filterArrayArguments(Array $arguments) { if (count($arguments) === 1 && is_array($arguments[0])) { return $arguments[0]; } return $arguments; } /** * Normalizes the arguments array passed to a variadic Redis command. * * @deprecated Deprecated since v0.8.3 - moved in Predis\Command\AbstractCommand::normalizeVariadic() * @param array $arguments Arguments for a command. * @return array */ public static function filterVariadicValues(Array $arguments) { if (count($arguments) === 2 && is_array($arguments[1])) { return array_merge(array($arguments[0]), $arguments[1]); } return $arguments; } } predis-0.8.3/lib/Predis/Iterator/000077500000000000000000000000001211043230100165605ustar00rootroot00000000000000predis-0.8.3/lib/Predis/Iterator/MultiBulkResponse.php000066400000000000000000000037111211043230100227220ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Iterator; use Predis\ResponseObjectInterface; /** * Iterator that abstracts the access to multibulk replies and allows * them to be consumed by user's code in a streaming fashion. * * @author Daniele Alessandri */ abstract class MultiBulkResponse implements \Iterator, \Countable, ResponseObjectInterface { protected $position; protected $current; protected $replySize; /** * {@inheritdoc} */ public function rewind() { // NOOP } /** * {@inheritdoc} */ public function current() { return $this->current; } /** * {@inheritdoc} */ public function key() { return $this->position; } /** * {@inheritdoc} */ public function next() { if (++$this->position < $this->replySize) { $this->current = $this->getValue(); } return $this->position; } /** * {@inheritdoc} */ public function valid() { return $this->position < $this->replySize; } /** * Returns the number of items of the whole multibulk reply. * * This method should be used to get the size of the current multibulk * reply without using iterator_count, which actually consumes the * iterator to calculate the size (rewinding is not supported). * * @return int */ public function count() { return $this->replySize; } /** * Returns the current position of the iterator. * * @return int */ public function getPosition() { return $this->position; } /** * {@inheritdoc} */ protected abstract function getValue(); } predis-0.8.3/lib/Predis/Iterator/MultiBulkResponseSimple.php000066400000000000000000000045031211043230100240740ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Iterator; use Predis\Connection\SingleConnectionInterface; /** * Streams a multibulk reply. * * @author Daniele Alessandri */ class MultiBulkResponseSimple extends MultiBulkResponse { private $connection; /** * @param SingleConnectionInterface $connection Connection to Redis. * @param int $size Number of elements of the multibulk reply. */ public function __construct(SingleConnectionInterface $connection, $size) { $this->connection = $connection; $this->position = 0; $this->current = $size > 0 ? $this->getValue() : null; $this->replySize = $size; } /** * Handles the synchronization of the client with the Redis protocol * then PHP's garbage collector kicks in (e.g. then the iterator goes * out of the scope of a foreach). */ public function __destruct() { $this->sync(true); } /** * Synchronizes the client with the queued elements that have not been * read from the connection by consuming the rest of the multibulk reply, * or simply by dropping the connection. * * @param Boolean $drop True to synchronize the client by dropping the connection. * False to synchronize the client by consuming the multibulk reply. */ public function sync($drop = false) { if ($drop == true) { if ($this->valid()) { $this->position = $this->replySize; $this->connection->disconnect(); } } else { while ($this->valid()) { $this->next(); } } } /** * Reads the next item of the multibulk reply from the server. * * @return mixed */ protected function getValue() { return $this->connection->read(); } /** * Returns an iterator that reads the multi-bulk response as * list of tuples. * * @return MultiBulkResponseTuple */ public function asTuple() { return new MultiBulkResponseTuple($this); } } predis-0.8.3/lib/Predis/Iterator/MultiBulkResponseTuple.php000066400000000000000000000040531211043230100237340ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Iterator; /** * Abstracts the access to a streamable list of tuples represented * as a multibulk reply that alternates keys and values. * * @author Daniele Alessandri */ class MultiBulkResponseTuple extends MultiBulkResponse implements \OuterIterator { private $iterator; /** * @param MultiBulkResponseSimple $iterator Multibulk reply iterator. */ public function __construct(MultiBulkResponseSimple $iterator) { $this->checkPreconditions($iterator); $virtualSize = count($iterator) / 2; $this->iterator = $iterator; $this->position = $iterator->getPosition(); $this->current = $virtualSize > 0 ? $this->getValue() : null; $this->replySize = $virtualSize; } /** * Checks for valid preconditions. * * @param MultiBulkResponseSimple $iterator Multibulk reply iterator. */ protected function checkPreconditions(MultiBulkResponseSimple $iterator) { if ($iterator->getPosition() !== 0) { throw new \RuntimeException('Cannot initialize a tuple iterator with an already initiated iterator'); } if (($size = count($iterator)) % 2 !== 0) { throw new \UnexpectedValueException("Invalid reply size for a tuple iterator [$size]"); } } /** * {@inheritdoc} */ public function getInnerIterator() { return $this->iterator; } /** * {@inheritdoc} */ public function __destruct() { $this->iterator->sync(true); } /** * {@inheritdoc} */ protected function getValue() { $k = $this->iterator->current(); $this->iterator->next(); $v = $this->iterator->current(); $this->iterator->next(); return array($k, $v); } } predis-0.8.3/lib/Predis/Monitor/000077500000000000000000000000001211043230100164165ustar00rootroot00000000000000predis-0.8.3/lib/Predis/Monitor/MonitorContext.php000066400000000000000000000100541211043230100221230ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Monitor; use Predis\ClientInterface; use Predis\NotSupportedException; use Predis\Connection\AggregatedConnectionInterface; /** * Client-side abstraction of a Redis MONITOR context. * * @author Daniele Alessandri */ class MonitorContext implements \Iterator { private $client; private $isValid; private $position; /** * @param ClientInterface Client instance used by the context. */ public function __construct(ClientInterface $client) { $this->checkCapabilities($client); $this->client = $client; $this->openContext(); } /** * Automatically closes the context when PHP's garbage collector kicks in. */ public function __destruct() { $this->closeContext(); } /** * Checks if the passed client instance satisfies the required conditions * needed to initialize a monitor context. * * @param ClientInterface Client instance used by the context. */ private function checkCapabilities(ClientInterface $client) { if ($client->getConnection() instanceof AggregatedConnectionInterface) { throw new NotSupportedException('Cannot initialize a monitor context when using aggregated connections'); } if ($client->getProfile()->supportsCommand('monitor') === false) { throw new NotSupportedException('The current profile does not support the MONITOR command'); } } /** * Initializes the context and sends the MONITOR command to the server. */ protected function openContext() { $this->isValid = true; $monitor = $this->client->createCommand('monitor'); $this->client->executeCommand($monitor); } /** * Closes the context. Internally this is done by disconnecting from server * since there is no way to terminate the stream initialized by MONITOR. */ public function closeContext() { $this->client->disconnect(); $this->isValid = false; } /** * {@inheritdoc} */ public function rewind() { // NOOP } /** * Returns the last message payload retrieved from the server. * * @return Object */ public function current() { return $this->getValue(); } /** * {@inheritdoc} */ public function key() { return $this->position; } /** * {@inheritdoc} */ public function next() { $this->position++; } /** * Checks if the the context is still in a valid state to continue. * * @return Boolean */ public function valid() { return $this->isValid; } /** * Waits for a new message from the server generated by MONITOR and * returns it when available. * * @return Object */ private function getValue() { $database = 0; $client = null; $event = $this->client->getConnection()->read(); $callback = function ($matches) use (&$database, &$client) { if (2 === $count = count($matches)) { // Redis <= 2.4 $database = (int) $matches[1]; } if (4 === $count) { // Redis >= 2.6 $database = (int) $matches[2]; $client = $matches[3]; } return ' '; }; $event = preg_replace_callback('/ \(db (\d+)\) | \[(\d+) (.*?)\] /', $callback, $event, 1); @list($timestamp, $command, $arguments) = explode(' ', $event, 3); return (object) array( 'timestamp' => (float) $timestamp, 'database' => $database, 'client' => $client, 'command' => substr($command, 1, -1), 'arguments' => $arguments, ); } } predis-0.8.3/lib/Predis/NotSupportedException.php000066400000000000000000000007521211043230100220310ustar00rootroot00000000000000 * * 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 { } predis-0.8.3/lib/Predis/Option/000077500000000000000000000000001211043230100162375ustar00rootroot00000000000000predis-0.8.3/lib/Predis/Option/AbstractOption.php000066400000000000000000000016721211043230100217120ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; /** * Implements a client option. * * @author Daniele Alessandri */ abstract class AbstractOption implements OptionInterface { /** * {@inheritdoc} */ public function filter(ClientOptionsInterface $options, $value) { return $value; } /** * {@inheritdoc} */ public function getDefault(ClientOptionsInterface $options) { return null; } /** * {@inheritdoc} */ public function __invoke(ClientOptionsInterface $options, $value) { if (isset($value)) { return $this->filter($options, $value); } return $this->getDefault($options); } } predis-0.8.3/lib/Predis/Option/ClientCluster.php000066400000000000000000000054161211043230100215360ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; use Predis\Connection\ClusterConnectionInterface; use Predis\Connection\PredisCluster; use Predis\Connection\RedisCluster; /** * Option class that returns a connection cluster to be used by a client. * * @author Daniele Alessandri */ class ClientCluster extends AbstractOption { /** * Checks if the specified value is a valid instance of ClusterConnectionInterface. * * @param ClusterConnectionInterface $cluster Instance of a connection cluster. * @return ClusterConnectionInterface */ protected function checkInstance($cluster) { if (!$cluster instanceof ClusterConnectionInterface) { throw new \InvalidArgumentException('Instance of Predis\Connection\ClusterConnectionInterface expected'); } return $cluster; } /** * {@inheritdoc} */ public function filter(ClientOptionsInterface $options, $value) { if (is_callable($value)) { return $this->checkInstance(call_user_func($value, $options, $this)); } $initializer = $this->getInitializer($options, $value); return $this->checkInstance($initializer()); } /** * Returns an initializer for the specified FQN or type. * * @param string $fqnOrType Type of cluster or FQN of a class implementing ClusterConnectionInterface. * @param ClientOptionsInterface $options Instance of the client options. * @return \Closure */ protected function getInitializer(ClientOptionsInterface $options, $fqnOrType) { switch ($fqnOrType) { case 'predis': return function () { return new PredisCluster(); }; case 'redis': return function () use ($options) { $connectionFactory = $options->connections; $cluster = new RedisCluster($connectionFactory); return $cluster; }; 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(); }; } } /** * {@inheritdoc} */ public function getDefault(ClientOptionsInterface $options) { return new PredisCluster(); } } predis-0.8.3/lib/Predis/Option/ClientConnectionFactory.php000066400000000000000000000036521211043230100235440ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; use Predis\Connection\ConnectionFactory; use Predis\Connection\ConnectionFactoryInterface; /** * Option class that returns a connection factory to be used by a client. * * @author Daniele Alessandri */ class ClientConnectionFactory extends AbstractOption { /** * {@inheritdoc} */ public function filter(ClientOptionsInterface $options, $value) { if ($value instanceof ConnectionFactoryInterface) { return $value; } if (is_array($value)) { $factory = $this->getDefault($options); foreach ($value as $scheme => $initializer) { $factory->define($scheme, $initializer); } return $factory; } if (is_callable($value)) { $factory = call_user_func($value, $options, $this); if (!$factory instanceof ConnectionFactoryInterface) { throw new \InvalidArgumentException('Instance of Predis\Connection\ConnectionFactoryInterface expected'); } return $factory; } if (@class_exists($value)) { $factory = new $value(); if (!$factory instanceof ConnectionFactoryInterface) { throw new \InvalidArgumentException("Class $value must be an instance of Predis\Connection\ConnectionFactoryInterface"); } return $factory; } throw new \InvalidArgumentException('Invalid value for the connections option'); } /** * {@inheritdoc} */ public function getDefault(ClientOptionsInterface $options) { return new ConnectionFactory($options->profile); } } predis-0.8.3/lib/Predis/Option/ClientExceptions.php000066400000000000000000000013451211043230100222330ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; /** * Option class used to specify if the client should throw server exceptions. * * @author Daniele Alessandri */ class ClientExceptions extends AbstractOption { /** * {@inheritdoc} */ public function filter(ClientOptionsInterface $options, $value) { return (bool) $value; } /** * {@inheritdoc} */ public function getDefault(ClientOptionsInterface $options) { return true; } } predis-0.8.3/lib/Predis/Option/ClientOptions.php000066400000000000000000000063341211043230100215500ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; /** * Class that manages client options with filtering and conversion. * * @author Daniele Alessandri */ class ClientOptions implements ClientOptionsInterface { private $handlers; private $defined; private $options = array(); /** * @param array $options Array of client options. */ public function __construct(Array $options = array()) { $this->handlers = $this->initialize($options); $this->defined = array_fill_keys(array_keys($options), true); } /** * Ensures that the default options are initialized. * * @return array */ protected function getDefaultOptions() { return array( 'profile' => new ClientProfile(), 'connections' => new ClientConnectionFactory(), 'cluster' => new ClientCluster(), 'replication' => new ClientReplication(), 'prefix' => new ClientPrefix(), 'exceptions' => new ClientExceptions(), ); } /** * Initializes client options handlers. * * @param array $options List of client options values. * @return array */ protected function initialize(Array $options) { $handlers = $this->getDefaultOptions(); foreach ($options as $option => $value) { if (isset($handlers[$option])) { $handler = $handlers[$option]; $handlers[$option] = function ($options) use ($handler, $value) { return $handler->filter($options, $value); }; } else { $this->options[$option] = $value; } } return $handlers; } /** * Checks if the specified option is set. * * @param string $option Name of the option. * @return Boolean */ public function __isset($option) { return isset($this->defined[$option]); } /** * Returns the value of the specified option. * * @param string $option Name of the option. * @return mixed */ public function __get($option) { if (isset($this->options[$option])) { return $this->options[$option]; } if (isset($this->handlers[$option])) { $handler = $this->handlers[$option]; $value = $handler instanceof OptionInterface ? $handler->getDefault($this) : $handler($this); $this->options[$option] = $value; return $value; } } /** * Returns the default value for the specified option. * * @param string|OptionInterface $option Name or instance of the option. * @return mixed */ public function getDefault($option) { if ($option instanceof OptionInterface) { return $option->getDefault($this); } $options = $this->getDefaultOptions(); if (isset($options[$option])) { return $options[$option]->getDefault($this); } } } predis-0.8.3/lib/Predis/Option/ClientOptionsInterface.php000066400000000000000000000006431211043230100233660ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; /** * Marker interface defining a client options bag. * * @author Daniele Alessandri */ interface ClientOptionsInterface { } predis-0.8.3/lib/Predis/Option/ClientPrefix.php000066400000000000000000000012171211043230100213450ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; use Predis\Command\Processor\KeyPrefixProcessor; /** * Option class that handles the prefixing of keys in commands. * * @author Daniele Alessandri */ class ClientPrefix extends AbstractOption { /** * {@inheritdoc} */ public function filter(ClientOptionsInterface $options, $value) { return new KeyPrefixProcessor($value); } } predis-0.8.3/lib/Predis/Option/ClientProfile.php000066400000000000000000000026251211043230100215140ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; use Predis\Profile\ServerProfile; use Predis\Profile\ServerProfileInterface; /** * Option class that handles server profiles to be used by a client. * * @author Daniele Alessandri */ class ClientProfile extends AbstractOption { /** * {@inheritdoc} */ public function filter(ClientOptionsInterface $options, $value) { if (is_string($value)) { $value = ServerProfile::get($value); if (isset($options->prefix)) { $value->setProcessor($options->prefix); } } if (is_callable($value)) { $value = call_user_func($value, $options, $this); } if (!$value instanceof ServerProfileInterface) { throw new \InvalidArgumentException('Invalid value for the profile option'); } return $value; } /** * {@inheritdoc} */ public function getDefault(ClientOptionsInterface $options) { $profile = ServerProfile::getDefault(); if (isset($options->prefix)) { $profile->setProcessor($options->prefix); } return $profile; } } predis-0.8.3/lib/Predis/Option/ClientReplication.php000066400000000000000000000043511211043230100223630ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; use Predis\Connection\MasterSlaveReplication; use Predis\Connection\ReplicationConnectionInterface; /** * Option class that returns a replication connection be used by a client. * * @author Daniele Alessandri */ class ClientReplication extends AbstractOption { /** * Checks if the specified value is a valid instance of ReplicationConnectionInterface. * * @param ReplicationConnectionInterface $connection Instance of a replication connection. * @return ReplicationConnectionInterface */ protected function checkInstance($connection) { if (!$connection instanceof ReplicationConnectionInterface) { throw new \InvalidArgumentException('Instance of Predis\Connection\ReplicationConnectionInterface expected'); } return $connection; } /** * {@inheritdoc} */ public function filter(ClientOptionsInterface $options, $value) { if (is_callable($value)) { $connection = call_user_func($value, $options, $this); if (!$connection instanceof ReplicationConnectionInterface) { throw new \InvalidArgumentException('Instance of Predis\Connection\ReplicationConnectionInterface expected'); } return $connection; } if (is_string($value)) { if (!class_exists($value)) { throw new \InvalidArgumentException("Class $value does not exist"); } if (!($connection = new $value()) instanceof ReplicationConnectionInterface) { throw new \InvalidArgumentException('Instance of Predis\Connection\ReplicationConnectionInterface expected'); } return $connection; } if ($value == true) { return $this->getDefault($options); } } /** * {@inheritdoc} */ public function getDefault(ClientOptionsInterface $options) { return new MasterSlaveReplication(); } } predis-0.8.3/lib/Predis/Option/CustomOption.php000066400000000000000000000040371211043230100214170ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; /** * Implements a generic class used to dynamically define a client option. * * @author Daniele Alessandri */ class CustomOption implements OptionInterface { private $filter; private $default; /** * @param array $options List of options */ public function __construct(Array $options = array()) { $this->filter = $this->ensureCallable($options, 'filter'); $this->default = $this->ensureCallable($options, 'default'); } /** * Checks if the specified value in the options array is a callable object. * * @param array $options Array of options * @param string $key Target option. */ private function ensureCallable($options, $key) { if (!isset($options[$key])) { return; } if (is_callable($callable = $options[$key])) { return $callable; } throw new \InvalidArgumentException("The parameter $key must be callable"); } /** * {@inheritdoc} */ public function filter(ClientOptionsInterface $options, $value) { if (isset($value)) { if ($this->filter === null) { return $value; } return call_user_func($this->filter, $options, $value); } } /** * {@inheritdoc} */ public function getDefault(ClientOptionsInterface $options) { if (!isset($this->default)) { return; } return call_user_func($this->default, $options); } /** * {@inheritdoc} */ public function __invoke(ClientOptionsInterface $options, $value) { if (isset($value)) { return $this->filter($options, $value); } return $this->getDefault($options); } } predis-0.8.3/lib/Predis/Option/OptionInterface.php000066400000000000000000000020651211043230100220440ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; /** * Interface that defines a client option. * * @author Daniele Alessandri */ interface OptionInterface { /** * Filters (and optionally converts) the passed value. * * @param mixed $value Input value. * @return mixed */ public function filter(ClientOptionsInterface $options, $value); /** * Returns a default value for the option. * * @param mixed $value Input value. * @return mixed */ public function getDefault(ClientOptionsInterface $options); /** * Filters a value and, if no value is specified, returns * the default one defined by the option. * * @param mixed $value Input value. * @return mixed */ public function __invoke(ClientOptionsInterface $options, $value); } predis-0.8.3/lib/Predis/Pipeline/000077500000000000000000000000001211043230100165345ustar00rootroot00000000000000predis-0.8.3/lib/Predis/Pipeline/FireAndForgetExecutor.php000066400000000000000000000026431211043230100234500ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Pipeline; use SplQueue; use Predis\Connection\ConnectionInterface; use Predis\Connection\ReplicationConnectionInterface; /** * Implements a pipeline executor strategy that writes a list of commands to * the connection object but does not read back their replies. * * @author Daniele Alessandri */ class FireAndForgetExecutor implements PipelineExecutorInterface { /** * Allows the pipeline executor to perform operations on the * connection before starting to execute the commands stored * in the pipeline. * * @param ConnectionInterface Connection instance. */ protected function checkConnection(ConnectionInterface $connection) { if ($connection instanceof ReplicationConnectionInterface) { $connection->switchTo('master'); } } /** * {@inheritdoc} */ public function execute(ConnectionInterface $connection, SplQueue $commands) { $this->checkConnection($connection); while (!$commands->isEmpty()) { $connection->writeCommand($commands->dequeue()); } $connection->disconnect(); return array(); } } predis-0.8.3/lib/Predis/Pipeline/MultiExecExecutor.php000066400000000000000000000116471211043230100226740ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Pipeline; use Iterator; use SplQueue; use Predis\ClientException; use Predis\ResponseErrorInterface; use Predis\ResponseObjectInterface; use Predis\ResponseQueued; use Predis\ServerException; use Predis\Connection\ConnectionInterface; use Predis\Connection\SingleConnectionInterface; use Predis\Profile\ServerProfile; use Predis\Profile\ServerProfileInterface; /** * Implements a pipeline executor that wraps the whole pipeline * in a MULTI / EXEC context to make sure that it is executed * correctly. * * @author Daniele Alessandri */ class MultiExecExecutor implements PipelineExecutorInterface { protected $profile; /** * */ public function __construct(ServerProfileInterface $profile = null) { $this->setProfile($profile ?: ServerProfile::getDefault()); } /** * Allows the pipeline executor to perform operations on the * connection before starting to execute the commands stored * in the pipeline. * * @param ConnectionInterface Connection instance. */ protected function checkConnection(ConnectionInterface $connection) { if (!$connection instanceof SingleConnectionInterface) { $class = __CLASS__; throw new ClientException("$class can be used only with single connections"); } } /** * {@inheritdoc} */ public function execute(ConnectionInterface $connection, SplQueue $commands) { $this->checkConnection($connection); $cmd = $this->profile->createCommand('multi'); $connection->executeCommand($cmd); foreach ($commands as $command) { $connection->writeCommand($command); } foreach ($commands as $command) { $response = $connection->readResponse($command); if ($response instanceof ResponseErrorInterface) { $cmd = $this->profile->createCommand('discard'); $connection->executeCommand($cmd); throw new ServerException($response->getMessage()); } } $cmd = $this->profile->createCommand('exec'); $responses = $connection->executeCommand($cmd); if (!isset($responses)) { throw new ClientException('The underlying transaction has been aborted by the server'); } if (count($responses) !== count($commands)) { throw new ClientException("Invalid number of replies [expected: ".count($commands)." - actual: ".count($responses)."]"); } $consumer = $responses instanceof Iterator ? 'consumeIteratorResponse' : 'consumeArrayResponse'; return $this->$consumer($commands, $responses); } /** * Consumes an iterator response returned by EXEC. * * @param SplQueue $commands Pipelined commands * @param Iterator $responses Responses returned by EXEC. * @return array */ protected function consumeIteratorResponse(SplQueue $commands, Iterator $responses) { $values = array(); foreach ($responses as $response) { $command = $commands->dequeue(); if ($response instanceof ResponseObjectInterface) { if ($response instanceof Iterator) { $response = iterator_to_array($response); $values[] = $command->parseResponse($response); } else { $values[] = $response; } } else { $values[] = $command->parseResponse($response); } } return $values; } /** * Consumes an array response returned by EXEC. * * @param SplQueue $commands Pipelined commands * @param Array $responses Responses returned by EXEC. * @return array */ protected function consumeArrayResponse(SplQueue $commands, Array &$responses) { $size = count($commands); $values = array(); for ($i = 0; $i < $size; $i++) { $command = $commands->dequeue(); $response = $responses[$i]; if ($response instanceof ResponseObjectInterface) { $values[$i] = $response; } else { $values[$i] = $command->parseResponse($response); } unset($responses[$i]); } return $values; } /** * @param ServerProfileInterface $profile Server profile. */ public function setProfile(ServerProfileInterface $profile) { if (!$profile->supportsCommands(array('multi', 'exec', 'discard'))) { throw new ClientException('The specified server profile must support MULTI, EXEC and DISCARD.'); } $this->profile = $profile; } } predis-0.8.3/lib/Predis/Pipeline/PipelineContext.php000066400000000000000000000117561211043230100223710ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Pipeline; use SplQueue; use Predis\BasicClientInterface; use Predis\ClientException; use Predis\ClientInterface; use Predis\ExecutableContextInterface; use Predis\Command\CommandInterface; /** * Abstraction of a pipeline context where write and read operations * of commands and their replies over the network are pipelined. * * @author Daniele Alessandri */ class PipelineContext implements BasicClientInterface, ExecutableContextInterface { private $client; private $executor; private $pipeline; private $replies = array(); private $running = false; /** * @param ClientInterface $client Client instance used by the context. * @param PipelineExecutorInterface $executor Pipeline executor instace. */ public function __construct(ClientInterface $client, PipelineExecutorInterface $executor = null) { $this->client = $client; $this->executor = $executor ?: $this->createExecutor($client); $this->pipeline = new SplQueue(); } /** * Returns a pipeline executor depending on the kind of the underlying * connection and the passed options. * * @param ClientInterface Client instance used by the context. * @return PipelineExecutorInterface */ protected function createExecutor(ClientInterface $client) { $options = $client->getOptions(); if (isset($options->exceptions)) { return new StandardExecutor($options->exceptions); } return new StandardExecutor(); } /** * Queues a command into the pipeline buffer. * * @param string $method Command ID. * @param array $arguments Arguments for the command. * @return PipelineContext */ public function __call($method, $arguments) { $command = $this->client->createCommand($method, $arguments); $this->recordCommand($command); return $this; } /** * Queues a command instance into the pipeline buffer. * * @param CommandInterface $command Command to queue in the buffer. */ protected function recordCommand(CommandInterface $command) { $this->pipeline->enqueue($command); } /** * Queues a command instance into the pipeline buffer. * * @param CommandInterface $command Command to queue in the buffer. */ public function executeCommand(CommandInterface $command) { $this->recordCommand($command); } /** * Flushes the buffer that holds the queued commands. * * @param Boolean $send Specifies if the commands in the buffer should be sent to Redis. * @return PipelineContext */ public function flushPipeline($send = true) { if ($send && !$this->pipeline->isEmpty()) { $connection = $this->client->getConnection(); $replies = $this->executor->execute($connection, $this->pipeline); $this->replies = array_merge($this->replies, $replies); } else { $this->pipeline = new SplQueue(); } return $this; } /** * Marks the running status of the pipeline. * * @param Boolean $bool True if the pipeline is running. * False if the pipeline is not running. */ private function setRunning($bool) { if ($bool === true && $this->running === true) { throw new ClientException("This pipeline is already opened"); } $this->running = $bool; } /** * Handles the actual execution of the whole pipeline. * * @param mixed $callable Optional callback for execution. * @return array */ public function execute($callable = null) { if ($callable && !is_callable($callable)) { throw new \InvalidArgumentException('Argument passed must be a callable object'); } $this->setRunning(true); $pipelineBlockException = null; try { if ($callable !== null) { call_user_func($callable, $this); } $this->flushPipeline(); } catch (\Exception $exception) { $pipelineBlockException = $exception; } $this->setRunning(false); if ($pipelineBlockException !== null) { throw $pipelineBlockException; } return $this->replies; } /** * Returns the underlying client instance used by the pipeline object. * * @return ClientInterface */ public function getClient() { return $this->client; } /** * Returns the underlying pipeline executor used by the pipeline object. * * @return PipelineExecutorInterface */ public function getExecutor() { return $this->executor; } } predis-0.8.3/lib/Predis/Pipeline/PipelineExecutorInterface.php000066400000000000000000000015371211043230100243600ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Pipeline; use SplQueue; use Predis\Connection\ConnectionInterface; /** * Defines a strategy to write a list of commands to the network * and read back their replies. * * @author Daniele Alessandri */ interface PipelineExecutorInterface { /** * Writes a list of commands to the network and reads back their replies. * * @param ConnectionInterface $connection Connection to Redis. * @param SplQueue $commands Commands queued for execution. * @return array */ public function execute(ConnectionInterface $connection, SplQueue $commands); } predis-0.8.3/lib/Predis/Pipeline/SafeClusterExecutor.php000066400000000000000000000042271211043230100232110ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Pipeline; use SplQueue; use Predis\CommunicationException; use Predis\Connection\ConnectionInterface; /** * Implements a pipeline executor strategy for connection clusters that does * not fail when an error is encountered, but adds the returned error in the * replies array. * * @author Daniele Alessandri */ class SafeClusterExecutor implements PipelineExecutorInterface { /** * {@inheritdoc} */ public function execute(ConnectionInterface $connection, SplQueue $commands) { $size = count($commands); $values = array(); $connectionExceptions = array(); foreach ($commands as $command) { $cmdConnection = $connection->getConnection($command); if (isset($connectionExceptions[spl_object_hash($cmdConnection)])) { continue; } try { $cmdConnection->writeCommand($command); } catch (CommunicationException $exception) { $connectionExceptions[spl_object_hash($cmdConnection)] = $exception; } } for ($i = 0; $i < $size; $i++) { $command = $commands->dequeue(); $cmdConnection = $connection->getConnection($command); $connectionObjectHash = spl_object_hash($cmdConnection); if (isset($connectionExceptions[$connectionObjectHash])) { $values[$i] = $connectionExceptions[$connectionObjectHash]; continue; } try { $response = $cmdConnection->readResponse($command); $values[$i] = $response instanceof \Iterator ? iterator_to_array($response) : $response; } catch (CommunicationException $exception) { $values[$i] = $exception; $connectionExceptions[$connectionObjectHash] = $exception; } } return $values; } } predis-0.8.3/lib/Predis/Pipeline/SafeExecutor.php000066400000000000000000000031641211043230100216460ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Pipeline; use SplQueue; use Predis\CommunicationException; use Predis\ServerException; use Predis\Connection\ConnectionInterface; /** * Implements a pipeline executor strategy that does not fail when an error is * encountered, but adds the returned error in the replies array. * * @author Daniele Alessandri */ class SafeExecutor implements PipelineExecutorInterface { /** * {@inheritdoc} */ public function execute(ConnectionInterface $connection, SplQueue $commands) { $size = count($commands); $values = array(); foreach ($commands as $command) { try { $connection->writeCommand($command); } catch (CommunicationException $exception) { return array_fill(0, $size, $exception); } } for ($i = 0; $i < $size; $i++) { $command = $commands->dequeue(); try { $response = $connection->readResponse($command); $values[$i] = $response instanceof \Iterator ? iterator_to_array($response) : $response; } catch (CommunicationException $exception) { $toAdd = count($commands) - count($values); $values = array_merge($values, array_fill(0, $toAdd, $exception)); break; } } return $values; } } predis-0.8.3/lib/Predis/Pipeline/StandardExecutor.php000066400000000000000000000066721211043230100225370ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Pipeline; use Iterator; use SplQueue; use Predis\ResponseErrorInterface; use Predis\ResponseObjectInterface; use Predis\ServerException; use Predis\Command\CommandInterface; use Predis\Connection\ConnectionInterface; use Predis\Connection\ReplicationConnectionInterface; /** * Implements the standard pipeline executor strategy used * to write a list of commands and read their replies over * a connection to Redis. * * @author Daniele Alessandri */ class StandardExecutor implements PipelineExecutorInterface { protected $exceptions; /** * @param bool $exceptions Specifies if the executor should throw exceptions on server errors. */ public function __construct($exceptions = true) { $this->exceptions = (bool) $exceptions; } /** * Allows the pipeline executor to perform operations on the * connection before starting to execute the commands stored * in the pipeline. * * @param ConnectionInterface Connection instance. */ protected function checkConnection(ConnectionInterface $connection) { if ($connection instanceof ReplicationConnectionInterface) { $connection->switchTo('master'); } } /** * Handles a response object. * * @param ConnectionInterface $connection * @param CommandInterface $command * @param ResponseObjectInterface $response * @return mixed */ protected function onResponseObject(ConnectionInterface $connection, CommandInterface $command, ResponseObjectInterface $response) { if ($response instanceof ResponseErrorInterface) { return $this->onResponseError($connection, $response); } if ($response instanceof Iterator) { return $command->parseResponse(iterator_to_array($response)); } return $response; } /** * Handles -ERR responses returned by Redis. * * @param ConnectionInterface $connection The connection that returned the error. * @param ResponseErrorInterface $response The error response instance. */ protected function onResponseError(ConnectionInterface $connection, ResponseErrorInterface $response) { if (!$this->exceptions) { return $response; } // Force disconnection to prevent protocol desynchronization. $connection->disconnect(); $message = $response->getMessage(); throw new ServerException($message); } /** * {@inheritdoc} */ public function execute(ConnectionInterface $connection, SplQueue $commands) { $this->checkConnection($connection); foreach ($commands as $command) { $connection->writeCommand($command); } $values = array(); while (!$commands->isEmpty()) { $command = $commands->dequeue(); $response = $connection->readResponse($command); if ($response instanceof ResponseObjectInterface) { $values[] = $this->onResponseObject($connection, $command, $response); } else { $values[] = $command->parseResponse($response); } } return $values; } } predis-0.8.3/lib/Predis/PredisException.php000066400000000000000000000006551211043230100206130ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis; /** * Base exception class for Predis-related errors. * * @author Daniele Alessandri */ abstract class PredisException extends \Exception { } predis-0.8.3/lib/Predis/Profile/000077500000000000000000000000001211043230100163675ustar00rootroot00000000000000predis-0.8.3/lib/Predis/Profile/ServerProfile.php000066400000000000000000000133271211043230100216750ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Profile; use Predis\ClientException; use Predis\Command\Processor\CommandProcessingInterface; use Predis\Command\Processor\CommandProcessorInterface; /** * Base class that implements common functionalities of server profiles. * * @author Daniele Alessandri */ abstract class ServerProfile implements ServerProfileInterface, CommandProcessingInterface { private static $profiles; private $commands; private $processor; /** * */ public function __construct() { $this->commands = $this->getSupportedCommands(); } /** * Returns a map of all the commands supported by the profile and their * actual PHP classes. * * @return array */ protected abstract function getSupportedCommands(); /** * Returns the default server profile. * * @return ServerProfileInterface */ public static function getDefault() { return self::get('default'); } /** * Returns the development server profile. * * @return ServerProfileInterface */ public static function getDevelopment() { return self::get('dev'); } /** * Returns a map of all the server profiles supported by default and their * actual PHP classes. * * @return array */ private static function getDefaultProfiles() { return array( '1.2' => 'Predis\Profile\ServerVersion12', '2.0' => 'Predis\Profile\ServerVersion20', '2.2' => 'Predis\Profile\ServerVersion22', '2.4' => 'Predis\Profile\ServerVersion24', '2.6' => 'Predis\Profile\ServerVersion26', 'default' => 'Predis\Profile\ServerVersion26', 'dev' => 'Predis\Profile\ServerVersionNext', ); } /** * Registers a new server profile. * * @param string $alias Profile version or alias. * @param string $profileClass FQN of a class implementing Predis\Profile\ServerProfileInterface. */ public static function define($alias, $profileClass) { if (!isset(self::$profiles)) { self::$profiles = self::getDefaultProfiles(); } $profileReflection = new \ReflectionClass($profileClass); if (!$profileReflection->isSubclassOf('Predis\Profile\ServerProfileInterface')) { throw new \InvalidArgumentException("Cannot register '$profileClass' as it is not a valid profile class"); } self::$profiles[$alias] = $profileClass; } /** * Returns the specified server profile. * * @param string $version Profile version or alias. * @return ServerProfileInterface */ public static function get($version) { if (!isset(self::$profiles)) { self::$profiles = self::getDefaultProfiles(); } if (!isset(self::$profiles[$version])) { throw new ClientException("Unknown server profile: $version"); } $profile = self::$profiles[$version]; return new $profile(); } /** * {@inheritdoc} */ public function supportsCommands(Array $commands) { foreach ($commands as $command) { if (!$this->supportsCommand($command)) { return false; } } return true; } /** * {@inheritdoc} */ public function supportsCommand($command) { 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} */ public function createCommand($method, $arguments = array()) { $method = strtolower($method); if (!isset($this->commands[$method])) { throw new ClientException("'$method' is not a registered Redis command"); } $commandClass = $this->commands[$method]; $command = new $commandClass(); $command->setArguments($arguments); if (isset($this->processor)) { $this->processor->process($command); } return $command; } /** * Defines a new commands in the server profile. * * @param string $alias Command ID. * @param string $command FQN of a class implementing Predis\Command\CommandInterface. */ public function defineCommand($alias, $command) { $commandReflection = new \ReflectionClass($command); if (!$commandReflection->isSubclassOf('Predis\Command\CommandInterface')) { throw new \InvalidArgumentException("Cannot register '$command' as it is not a valid Redis command"); } $this->commands[strtolower($alias)] = $command; } /** * {@inheritdoc} */ public function setProcessor(CommandProcessorInterface $processor = null) { $this->processor = $processor; } /** * {@inheritdoc} */ public function getProcessor() { return $this->processor; } /** * Returns the version of server profile as its string representation. * * @return string */ public function __toString() { return $this->getVersion(); } } predis-0.8.3/lib/Predis/Profile/ServerProfileInterface.php000066400000000000000000000025641211043230100235170ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Profile; /** * A server profile defines features and commands supported by certain * versions of Redis. Instances of Predis\Client should use a server * profile matching the version of Redis in use. * * @author Daniele Alessandri */ interface ServerProfileInterface { /** * Gets a profile version corresponding to a Redis version. * * @return string */ public function getVersion(); /** * Checks if the profile supports the specified command. * * @param string $command Command ID. * @return Boolean */ public function supportsCommand($command); /** * Checks if the profile supports the specified list of commands. * * @param array $commands List of command IDs. * @return string */ public function supportsCommands(Array $commands); /** * Creates a new command instance. * * @param string $method Command ID. * @param array $arguments Arguments for the command. * @return Predis\Command\CommandInterface */ public function createCommand($method, $arguments = array()); } predis-0.8.3/lib/Predis/Profile/ServerVersion12.php000066400000000000000000000145711211043230100220670ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Profile; /** * Server profile for Redis v1.2.x. * * @author Daniele Alessandri */ class ServerVersion12 extends ServerProfile { /** * {@inheritdoc} */ public function getVersion() { return '1.2'; } /** * {@inheritdoc} */ public function getSupportedCommands() { return array( /* ---------------- Redis 1.2 ---------------- */ /* commands operating on the key space */ 'exists' => 'Predis\Command\KeyExists', 'del' => 'Predis\Command\KeyDelete', 'type' => 'Predis\Command\KeyType', 'keys' => 'Predis\Command\KeyKeysV12x', 'randomkey' => 'Predis\Command\KeyRandom', 'rename' => 'Predis\Command\KeyRename', 'renamenx' => 'Predis\Command\KeyRenamePreserve', 'expire' => 'Predis\Command\KeyExpire', 'expireat' => 'Predis\Command\KeyExpireAt', 'ttl' => 'Predis\Command\KeyTimeToLive', 'move' => 'Predis\Command\KeyMove', 'sort' => 'Predis\Command\KeySort', /* commands operating on string values */ 'set' => 'Predis\Command\StringSet', 'setnx' => 'Predis\Command\StringSetPreserve', 'mset' => 'Predis\Command\StringSetMultiple', 'msetnx' => 'Predis\Command\StringSetMultiplePreserve', 'get' => 'Predis\Command\StringGet', 'mget' => 'Predis\Command\StringGetMultiple', 'getset' => 'Predis\Command\StringGetSet', 'incr' => 'Predis\Command\StringIncrement', 'incrby' => 'Predis\Command\StringIncrementBy', 'decr' => 'Predis\Command\StringDecrement', 'decrby' => 'Predis\Command\StringDecrementBy', /* commands operating on lists */ 'rpush' => 'Predis\Command\ListPushTail', 'lpush' => 'Predis\Command\ListPushHead', 'llen' => 'Predis\Command\ListLength', 'lrange' => 'Predis\Command\ListRange', 'ltrim' => 'Predis\Command\ListTrim', 'lindex' => 'Predis\Command\ListIndex', 'lset' => 'Predis\Command\ListSet', 'lrem' => 'Predis\Command\ListRemove', 'lpop' => 'Predis\Command\ListPopFirst', 'rpop' => 'Predis\Command\ListPopLast', 'rpoplpush' => 'Predis\Command\ListPopLastPushHead', /* commands operating on sets */ 'sadd' => 'Predis\Command\SetAdd', 'srem' => 'Predis\Command\SetRemove', 'spop' => 'Predis\Command\SetPop', 'smove' => 'Predis\Command\SetMove', 'scard' => 'Predis\Command\SetCardinality', 'sismember' => 'Predis\Command\SetIsMember', 'sinter' => 'Predis\Command\SetIntersection', 'sinterstore' => 'Predis\Command\SetIntersectionStore', 'sunion' => 'Predis\Command\SetUnion', 'sunionstore' => 'Predis\Command\SetUnionStore', 'sdiff' => 'Predis\Command\SetDifference', 'sdiffstore' => 'Predis\Command\SetDifferenceStore', 'smembers' => 'Predis\Command\SetMembers', 'srandmember' => 'Predis\Command\SetRandomMember', /* commands operating on sorted sets */ 'zadd' => 'Predis\Command\ZSetAdd', 'zincrby' => 'Predis\Command\ZSetIncrementBy', 'zrem' => 'Predis\Command\ZSetRemove', 'zrange' => 'Predis\Command\ZSetRange', 'zrevrange' => 'Predis\Command\ZSetReverseRange', 'zrangebyscore' => 'Predis\Command\ZSetRangeByScore', 'zcard' => 'Predis\Command\ZSetCardinality', 'zscore' => 'Predis\Command\ZSetScore', 'zremrangebyscore' => 'Predis\Command\ZSetRemoveRangeByScore', /* connection related commands */ 'ping' => 'Predis\Command\ConnectionPing', 'auth' => 'Predis\Command\ConnectionAuth', 'select' => 'Predis\Command\ConnectionSelect', 'echo' => 'Predis\Command\ConnectionEcho', 'quit' => 'Predis\Command\ConnectionQuit', /* remote server control commands */ 'info' => 'Predis\Command\ServerInfo', 'slaveof' => 'Predis\Command\ServerSlaveOf', 'monitor' => 'Predis\Command\ServerMonitor', 'dbsize' => 'Predis\Command\ServerDatabaseSize', 'flushdb' => 'Predis\Command\ServerFlushDatabase', 'flushall' => 'Predis\Command\ServerFlushAll', 'save' => 'Predis\Command\ServerSave', 'bgsave' => 'Predis\Command\ServerBackgroundSave', 'lastsave' => 'Predis\Command\ServerLastSave', 'shutdown' => 'Predis\Command\ServerShutdown', 'bgrewriteaof' => 'Predis\Command\ServerBackgroundRewriteAOF', ); } } predis-0.8.3/lib/Predis/Profile/ServerVersion20.php000066400000000000000000000221771211043230100220670ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Profile; /** * Server profile for Redis v2.0.x. * * @author Daniele Alessandri */ class ServerVersion20 extends ServerProfile { /** * {@inheritdoc} */ public function getVersion() { return '2.0'; } /** * {@inheritdoc} */ public function getSupportedCommands() { return array( /* ---------------- Redis 1.2 ---------------- */ /* commands operating on the key space */ 'exists' => 'Predis\Command\KeyExists', 'del' => 'Predis\Command\KeyDelete', 'type' => 'Predis\Command\KeyType', 'keys' => 'Predis\Command\KeyKeys', 'randomkey' => 'Predis\Command\KeyRandom', 'rename' => 'Predis\Command\KeyRename', 'renamenx' => 'Predis\Command\KeyRenamePreserve', 'expire' => 'Predis\Command\KeyExpire', 'expireat' => 'Predis\Command\KeyExpireAt', 'ttl' => 'Predis\Command\KeyTimeToLive', 'move' => 'Predis\Command\KeyMove', 'sort' => 'Predis\Command\KeySort', /* commands operating on string values */ 'set' => 'Predis\Command\StringSet', 'setnx' => 'Predis\Command\StringSetPreserve', 'mset' => 'Predis\Command\StringSetMultiple', 'msetnx' => 'Predis\Command\StringSetMultiplePreserve', 'get' => 'Predis\Command\StringGet', 'mget' => 'Predis\Command\StringGetMultiple', 'getset' => 'Predis\Command\StringGetSet', 'incr' => 'Predis\Command\StringIncrement', 'incrby' => 'Predis\Command\StringIncrementBy', 'decr' => 'Predis\Command\StringDecrement', 'decrby' => 'Predis\Command\StringDecrementBy', /* commands operating on lists */ 'rpush' => 'Predis\Command\ListPushTail', 'lpush' => 'Predis\Command\ListPushHead', 'llen' => 'Predis\Command\ListLength', 'lrange' => 'Predis\Command\ListRange', 'ltrim' => 'Predis\Command\ListTrim', 'lindex' => 'Predis\Command\ListIndex', 'lset' => 'Predis\Command\ListSet', 'lrem' => 'Predis\Command\ListRemove', 'lpop' => 'Predis\Command\ListPopFirst', 'rpop' => 'Predis\Command\ListPopLast', 'rpoplpush' => 'Predis\Command\ListPopLastPushHead', /* commands operating on sets */ 'sadd' => 'Predis\Command\SetAdd', 'srem' => 'Predis\Command\SetRemove', 'spop' => 'Predis\Command\SetPop', 'smove' => 'Predis\Command\SetMove', 'scard' => 'Predis\Command\SetCardinality', 'sismember' => 'Predis\Command\SetIsMember', 'sinter' => 'Predis\Command\SetIntersection', 'sinterstore' => 'Predis\Command\SetIntersectionStore', 'sunion' => 'Predis\Command\SetUnion', 'sunionstore' => 'Predis\Command\SetUnionStore', 'sdiff' => 'Predis\Command\SetDifference', 'sdiffstore' => 'Predis\Command\SetDifferenceStore', 'smembers' => 'Predis\Command\SetMembers', 'srandmember' => 'Predis\Command\SetRandomMember', /* commands operating on sorted sets */ 'zadd' => 'Predis\Command\ZSetAdd', 'zincrby' => 'Predis\Command\ZSetIncrementBy', 'zrem' => 'Predis\Command\ZSetRemove', 'zrange' => 'Predis\Command\ZSetRange', 'zrevrange' => 'Predis\Command\ZSetReverseRange', 'zrangebyscore' => 'Predis\Command\ZSetRangeByScore', 'zcard' => 'Predis\Command\ZSetCardinality', 'zscore' => 'Predis\Command\ZSetScore', 'zremrangebyscore' => 'Predis\Command\ZSetRemoveRangeByScore', /* connection related commands */ 'ping' => 'Predis\Command\ConnectionPing', 'auth' => 'Predis\Command\ConnectionAuth', 'select' => 'Predis\Command\ConnectionSelect', 'echo' => 'Predis\Command\ConnectionEcho', 'quit' => 'Predis\Command\ConnectionQuit', /* remote server control commands */ 'info' => 'Predis\Command\ServerInfo', 'slaveof' => 'Predis\Command\ServerSlaveOf', 'monitor' => 'Predis\Command\ServerMonitor', 'dbsize' => 'Predis\Command\ServerDatabaseSize', 'flushdb' => 'Predis\Command\ServerFlushDatabase', 'flushall' => 'Predis\Command\ServerFlushAll', 'save' => 'Predis\Command\ServerSave', 'bgsave' => 'Predis\Command\ServerBackgroundSave', 'lastsave' => 'Predis\Command\ServerLastSave', 'shutdown' => 'Predis\Command\ServerShutdown', 'bgrewriteaof' => 'Predis\Command\ServerBackgroundRewriteAOF', /* ---------------- Redis 2.0 ---------------- */ /* commands operating on string values */ 'setex' => 'Predis\Command\StringSetExpire', 'append' => 'Predis\Command\StringAppend', 'substr' => 'Predis\Command\StringSubstr', /* commands operating on lists */ 'blpop' => 'Predis\Command\ListPopFirstBlocking', 'brpop' => 'Predis\Command\ListPopLastBlocking', /* commands operating on sorted sets */ 'zunionstore' => 'Predis\Command\ZSetUnionStore', 'zinterstore' => 'Predis\Command\ZSetIntersectionStore', 'zcount' => 'Predis\Command\ZSetCount', 'zrank' => 'Predis\Command\ZSetRank', 'zrevrank' => 'Predis\Command\ZSetReverseRank', 'zremrangebyrank' => 'Predis\Command\ZSetRemoveRangeByRank', /* commands operating on hashes */ 'hset' => 'Predis\Command\HashSet', 'hsetnx' => 'Predis\Command\HashSetPreserve', 'hmset' => 'Predis\Command\HashSetMultiple', 'hincrby' => 'Predis\Command\HashIncrementBy', 'hget' => 'Predis\Command\HashGet', 'hmget' => 'Predis\Command\HashGetMultiple', 'hdel' => 'Predis\Command\HashDelete', 'hexists' => 'Predis\Command\HashExists', 'hlen' => 'Predis\Command\HashLength', 'hkeys' => 'Predis\Command\HashKeys', 'hvals' => 'Predis\Command\HashValues', 'hgetall' => 'Predis\Command\HashGetAll', /* transactions */ 'multi' => 'Predis\Command\TransactionMulti', 'exec' => 'Predis\Command\TransactionExec', 'discard' => 'Predis\Command\TransactionDiscard', /* publish - subscribe */ 'subscribe' => 'Predis\Command\PubSubSubscribe', 'unsubscribe' => 'Predis\Command\PubSubUnsubscribe', 'psubscribe' => 'Predis\Command\PubSubSubscribeByPattern', 'punsubscribe' => 'Predis\Command\PubSubUnsubscribeByPattern', 'publish' => 'Predis\Command\PubSubPublish', /* remote server control commands */ 'config' => 'Predis\Command\ServerConfig', ); } } predis-0.8.3/lib/Predis/Profile/ServerVersion22.php000066400000000000000000000251401211043230100220620ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Profile; /** * Server profile for Redis v2.2.x. * * @author Daniele Alessandri */ class ServerVersion22 extends ServerProfile { /** * {@inheritdoc} */ public function getVersion() { return '2.2'; } /** * {@inheritdoc} */ public function getSupportedCommands() { return array( /* ---------------- Redis 1.2 ---------------- */ /* commands operating on the key space */ 'exists' => 'Predis\Command\KeyExists', 'del' => 'Predis\Command\KeyDelete', 'type' => 'Predis\Command\KeyType', 'keys' => 'Predis\Command\KeyKeys', 'randomkey' => 'Predis\Command\KeyRandom', 'rename' => 'Predis\Command\KeyRename', 'renamenx' => 'Predis\Command\KeyRenamePreserve', 'expire' => 'Predis\Command\KeyExpire', 'expireat' => 'Predis\Command\KeyExpireAt', 'ttl' => 'Predis\Command\KeyTimeToLive', 'move' => 'Predis\Command\KeyMove', 'sort' => 'Predis\Command\KeySort', /* commands operating on string values */ 'set' => 'Predis\Command\StringSet', 'setnx' => 'Predis\Command\StringSetPreserve', 'mset' => 'Predis\Command\StringSetMultiple', 'msetnx' => 'Predis\Command\StringSetMultiplePreserve', 'get' => 'Predis\Command\StringGet', 'mget' => 'Predis\Command\StringGetMultiple', 'getset' => 'Predis\Command\StringGetSet', 'incr' => 'Predis\Command\StringIncrement', 'incrby' => 'Predis\Command\StringIncrementBy', 'decr' => 'Predis\Command\StringDecrement', 'decrby' => 'Predis\Command\StringDecrementBy', /* commands operating on lists */ 'rpush' => 'Predis\Command\ListPushTail', 'lpush' => 'Predis\Command\ListPushHead', 'llen' => 'Predis\Command\ListLength', 'lrange' => 'Predis\Command\ListRange', 'ltrim' => 'Predis\Command\ListTrim', 'lindex' => 'Predis\Command\ListIndex', 'lset' => 'Predis\Command\ListSet', 'lrem' => 'Predis\Command\ListRemove', 'lpop' => 'Predis\Command\ListPopFirst', 'rpop' => 'Predis\Command\ListPopLast', 'rpoplpush' => 'Predis\Command\ListPopLastPushHead', /* commands operating on sets */ 'sadd' => 'Predis\Command\SetAdd', 'srem' => 'Predis\Command\SetRemove', 'spop' => 'Predis\Command\SetPop', 'smove' => 'Predis\Command\SetMove', 'scard' => 'Predis\Command\SetCardinality', 'sismember' => 'Predis\Command\SetIsMember', 'sinter' => 'Predis\Command\SetIntersection', 'sinterstore' => 'Predis\Command\SetIntersectionStore', 'sunion' => 'Predis\Command\SetUnion', 'sunionstore' => 'Predis\Command\SetUnionStore', 'sdiff' => 'Predis\Command\SetDifference', 'sdiffstore' => 'Predis\Command\SetDifferenceStore', 'smembers' => 'Predis\Command\SetMembers', 'srandmember' => 'Predis\Command\SetRandomMember', /* commands operating on sorted sets */ 'zadd' => 'Predis\Command\ZSetAdd', 'zincrby' => 'Predis\Command\ZSetIncrementBy', 'zrem' => 'Predis\Command\ZSetRemove', 'zrange' => 'Predis\Command\ZSetRange', 'zrevrange' => 'Predis\Command\ZSetReverseRange', 'zrangebyscore' => 'Predis\Command\ZSetRangeByScore', 'zcard' => 'Predis\Command\ZSetCardinality', 'zscore' => 'Predis\Command\ZSetScore', 'zremrangebyscore' => 'Predis\Command\ZSetRemoveRangeByScore', /* connection related commands */ 'ping' => 'Predis\Command\ConnectionPing', 'auth' => 'Predis\Command\ConnectionAuth', 'select' => 'Predis\Command\ConnectionSelect', 'echo' => 'Predis\Command\ConnectionEcho', 'quit' => 'Predis\Command\ConnectionQuit', /* remote server control commands */ 'info' => 'Predis\Command\ServerInfo', 'slaveof' => 'Predis\Command\ServerSlaveOf', 'monitor' => 'Predis\Command\ServerMonitor', 'dbsize' => 'Predis\Command\ServerDatabaseSize', 'flushdb' => 'Predis\Command\ServerFlushDatabase', 'flushall' => 'Predis\Command\ServerFlushAll', 'save' => 'Predis\Command\ServerSave', 'bgsave' => 'Predis\Command\ServerBackgroundSave', 'lastsave' => 'Predis\Command\ServerLastSave', 'shutdown' => 'Predis\Command\ServerShutdown', 'bgrewriteaof' => 'Predis\Command\ServerBackgroundRewriteAOF', /* ---------------- Redis 2.0 ---------------- */ /* commands operating on string values */ 'setex' => 'Predis\Command\StringSetExpire', 'append' => 'Predis\Command\StringAppend', 'substr' => 'Predis\Command\StringSubstr', /* commands operating on lists */ 'blpop' => 'Predis\Command\ListPopFirstBlocking', 'brpop' => 'Predis\Command\ListPopLastBlocking', /* commands operating on sorted sets */ 'zunionstore' => 'Predis\Command\ZSetUnionStore', 'zinterstore' => 'Predis\Command\ZSetIntersectionStore', 'zcount' => 'Predis\Command\ZSetCount', 'zrank' => 'Predis\Command\ZSetRank', 'zrevrank' => 'Predis\Command\ZSetReverseRank', 'zremrangebyrank' => 'Predis\Command\ZSetRemoveRangeByRank', /* commands operating on hashes */ 'hset' => 'Predis\Command\HashSet', 'hsetnx' => 'Predis\Command\HashSetPreserve', 'hmset' => 'Predis\Command\HashSetMultiple', 'hincrby' => 'Predis\Command\HashIncrementBy', 'hget' => 'Predis\Command\HashGet', 'hmget' => 'Predis\Command\HashGetMultiple', 'hdel' => 'Predis\Command\HashDelete', 'hexists' => 'Predis\Command\HashExists', 'hlen' => 'Predis\Command\HashLength', 'hkeys' => 'Predis\Command\HashKeys', 'hvals' => 'Predis\Command\HashValues', 'hgetall' => 'Predis\Command\HashGetAll', /* transactions */ 'multi' => 'Predis\Command\TransactionMulti', 'exec' => 'Predis\Command\TransactionExec', 'discard' => 'Predis\Command\TransactionDiscard', /* publish - subscribe */ 'subscribe' => 'Predis\Command\PubSubSubscribe', 'unsubscribe' => 'Predis\Command\PubSubUnsubscribe', 'psubscribe' => 'Predis\Command\PubSubSubscribeByPattern', 'punsubscribe' => 'Predis\Command\PubSubUnsubscribeByPattern', 'publish' => 'Predis\Command\PubSubPublish', /* remote server control commands */ 'config' => 'Predis\Command\ServerConfig', /* ---------------- Redis 2.2 ---------------- */ /* commands operating on the key space */ 'persist' => 'Predis\Command\KeyPersist', /* commands operating on string values */ 'strlen' => 'Predis\Command\StringStrlen', 'setrange' => 'Predis\Command\StringSetRange', 'getrange' => 'Predis\Command\StringGetRange', 'setbit' => 'Predis\Command\StringSetBit', 'getbit' => 'Predis\Command\StringGetBit', /* commands operating on lists */ 'rpushx' => 'Predis\Command\ListPushTailX', 'lpushx' => 'Predis\Command\ListPushHeadX', 'linsert' => 'Predis\Command\ListInsert', 'brpoplpush' => 'Predis\Command\ListPopLastPushHeadBlocking', /* commands operating on sorted sets */ 'zrevrangebyscore' => 'Predis\Command\ZSetReverseRangeByScore', /* transactions */ 'watch' => 'Predis\Command\TransactionWatch', 'unwatch' => 'Predis\Command\TransactionUnwatch', /* remote server control commands */ 'object' => 'Predis\Command\ServerObject', 'slowlog' => 'Predis\Command\ServerSlowlog', ); } } predis-0.8.3/lib/Predis/Profile/ServerVersion24.php000066400000000000000000000254341211043230100220720ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Profile; /** * Server profile for Redis v2.4.x. * * @author Daniele Alessandri */ class ServerVersion24 extends ServerProfile { /** * {@inheritdoc} */ public function getVersion() { return '2.4'; } /** * {@inheritdoc} */ public function getSupportedCommands() { return array( /* ---------------- Redis 1.2 ---------------- */ /* commands operating on the key space */ 'exists' => 'Predis\Command\KeyExists', 'del' => 'Predis\Command\KeyDelete', 'type' => 'Predis\Command\KeyType', 'keys' => 'Predis\Command\KeyKeys', 'randomkey' => 'Predis\Command\KeyRandom', 'rename' => 'Predis\Command\KeyRename', 'renamenx' => 'Predis\Command\KeyRenamePreserve', 'expire' => 'Predis\Command\KeyExpire', 'expireat' => 'Predis\Command\KeyExpireAt', 'ttl' => 'Predis\Command\KeyTimeToLive', 'move' => 'Predis\Command\KeyMove', 'sort' => 'Predis\Command\KeySort', /* commands operating on string values */ 'set' => 'Predis\Command\StringSet', 'setnx' => 'Predis\Command\StringSetPreserve', 'mset' => 'Predis\Command\StringSetMultiple', 'msetnx' => 'Predis\Command\StringSetMultiplePreserve', 'get' => 'Predis\Command\StringGet', 'mget' => 'Predis\Command\StringGetMultiple', 'getset' => 'Predis\Command\StringGetSet', 'incr' => 'Predis\Command\StringIncrement', 'incrby' => 'Predis\Command\StringIncrementBy', 'decr' => 'Predis\Command\StringDecrement', 'decrby' => 'Predis\Command\StringDecrementBy', /* commands operating on lists */ 'rpush' => 'Predis\Command\ListPushTail', 'lpush' => 'Predis\Command\ListPushHead', 'llen' => 'Predis\Command\ListLength', 'lrange' => 'Predis\Command\ListRange', 'ltrim' => 'Predis\Command\ListTrim', 'lindex' => 'Predis\Command\ListIndex', 'lset' => 'Predis\Command\ListSet', 'lrem' => 'Predis\Command\ListRemove', 'lpop' => 'Predis\Command\ListPopFirst', 'rpop' => 'Predis\Command\ListPopLast', 'rpoplpush' => 'Predis\Command\ListPopLastPushHead', /* commands operating on sets */ 'sadd' => 'Predis\Command\SetAdd', 'srem' => 'Predis\Command\SetRemove', 'spop' => 'Predis\Command\SetPop', 'smove' => 'Predis\Command\SetMove', 'scard' => 'Predis\Command\SetCardinality', 'sismember' => 'Predis\Command\SetIsMember', 'sinter' => 'Predis\Command\SetIntersection', 'sinterstore' => 'Predis\Command\SetIntersectionStore', 'sunion' => 'Predis\Command\SetUnion', 'sunionstore' => 'Predis\Command\SetUnionStore', 'sdiff' => 'Predis\Command\SetDifference', 'sdiffstore' => 'Predis\Command\SetDifferenceStore', 'smembers' => 'Predis\Command\SetMembers', 'srandmember' => 'Predis\Command\SetRandomMember', /* commands operating on sorted sets */ 'zadd' => 'Predis\Command\ZSetAdd', 'zincrby' => 'Predis\Command\ZSetIncrementBy', 'zrem' => 'Predis\Command\ZSetRemove', 'zrange' => 'Predis\Command\ZSetRange', 'zrevrange' => 'Predis\Command\ZSetReverseRange', 'zrangebyscore' => 'Predis\Command\ZSetRangeByScore', 'zcard' => 'Predis\Command\ZSetCardinality', 'zscore' => 'Predis\Command\ZSetScore', 'zremrangebyscore' => 'Predis\Command\ZSetRemoveRangeByScore', /* connection related commands */ 'ping' => 'Predis\Command\ConnectionPing', 'auth' => 'Predis\Command\ConnectionAuth', 'select' => 'Predis\Command\ConnectionSelect', 'echo' => 'Predis\Command\ConnectionEcho', 'quit' => 'Predis\Command\ConnectionQuit', /* remote server control commands */ 'info' => 'Predis\Command\ServerInfo', 'slaveof' => 'Predis\Command\ServerSlaveOf', 'monitor' => 'Predis\Command\ServerMonitor', 'dbsize' => 'Predis\Command\ServerDatabaseSize', 'flushdb' => 'Predis\Command\ServerFlushDatabase', 'flushall' => 'Predis\Command\ServerFlushAll', 'save' => 'Predis\Command\ServerSave', 'bgsave' => 'Predis\Command\ServerBackgroundSave', 'lastsave' => 'Predis\Command\ServerLastSave', 'shutdown' => 'Predis\Command\ServerShutdown', 'bgrewriteaof' => 'Predis\Command\ServerBackgroundRewriteAOF', /* ---------------- Redis 2.0 ---------------- */ /* commands operating on string values */ 'setex' => 'Predis\Command\StringSetExpire', 'append' => 'Predis\Command\StringAppend', 'substr' => 'Predis\Command\StringSubstr', /* commands operating on lists */ 'blpop' => 'Predis\Command\ListPopFirstBlocking', 'brpop' => 'Predis\Command\ListPopLastBlocking', /* commands operating on sorted sets */ 'zunionstore' => 'Predis\Command\ZSetUnionStore', 'zinterstore' => 'Predis\Command\ZSetIntersectionStore', 'zcount' => 'Predis\Command\ZSetCount', 'zrank' => 'Predis\Command\ZSetRank', 'zrevrank' => 'Predis\Command\ZSetReverseRank', 'zremrangebyrank' => 'Predis\Command\ZSetRemoveRangeByRank', /* commands operating on hashes */ 'hset' => 'Predis\Command\HashSet', 'hsetnx' => 'Predis\Command\HashSetPreserve', 'hmset' => 'Predis\Command\HashSetMultiple', 'hincrby' => 'Predis\Command\HashIncrementBy', 'hget' => 'Predis\Command\HashGet', 'hmget' => 'Predis\Command\HashGetMultiple', 'hdel' => 'Predis\Command\HashDelete', 'hexists' => 'Predis\Command\HashExists', 'hlen' => 'Predis\Command\HashLength', 'hkeys' => 'Predis\Command\HashKeys', 'hvals' => 'Predis\Command\HashValues', 'hgetall' => 'Predis\Command\HashGetAll', /* transactions */ 'multi' => 'Predis\Command\TransactionMulti', 'exec' => 'Predis\Command\TransactionExec', 'discard' => 'Predis\Command\TransactionDiscard', /* publish - subscribe */ 'subscribe' => 'Predis\Command\PubSubSubscribe', 'unsubscribe' => 'Predis\Command\PubSubUnsubscribe', 'psubscribe' => 'Predis\Command\PubSubSubscribeByPattern', 'punsubscribe' => 'Predis\Command\PubSubUnsubscribeByPattern', 'publish' => 'Predis\Command\PubSubPublish', /* remote server control commands */ 'config' => 'Predis\Command\ServerConfig', /* ---------------- Redis 2.2 ---------------- */ /* commands operating on the key space */ 'persist' => 'Predis\Command\KeyPersist', /* commands operating on string values */ 'strlen' => 'Predis\Command\StringStrlen', 'setrange' => 'Predis\Command\StringSetRange', 'getrange' => 'Predis\Command\StringGetRange', 'setbit' => 'Predis\Command\StringSetBit', 'getbit' => 'Predis\Command\StringGetBit', /* commands operating on lists */ 'rpushx' => 'Predis\Command\ListPushTailX', 'lpushx' => 'Predis\Command\ListPushHeadX', 'linsert' => 'Predis\Command\ListInsert', 'brpoplpush' => 'Predis\Command\ListPopLastPushHeadBlocking', /* commands operating on sorted sets */ 'zrevrangebyscore' => 'Predis\Command\ZSetReverseRangeByScore', /* transactions */ 'watch' => 'Predis\Command\TransactionWatch', 'unwatch' => 'Predis\Command\TransactionUnwatch', /* remote server control commands */ 'object' => 'Predis\Command\ServerObject', 'slowlog' => 'Predis\Command\ServerSlowlog', /* ---------------- Redis 2.4 ---------------- */ /* remote server control commands */ 'client' => 'Predis\Command\ServerClient', ); } } predis-0.8.3/lib/Predis/Profile/ServerVersion26.php000066400000000000000000000300711211043230100220650ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Profile; /** * Server profile for Redis v2.6.x. * * @author Daniele Alessandri */ class ServerVersion26 extends ServerProfile { /** * {@inheritdoc} */ public function getVersion() { return '2.6'; } /** * {@inheritdoc} */ public function getSupportedCommands() { return array( /* ---------------- Redis 1.2 ---------------- */ /* commands operating on the key space */ 'exists' => 'Predis\Command\KeyExists', 'del' => 'Predis\Command\KeyDelete', 'type' => 'Predis\Command\KeyType', 'keys' => 'Predis\Command\KeyKeys', 'randomkey' => 'Predis\Command\KeyRandom', 'rename' => 'Predis\Command\KeyRename', 'renamenx' => 'Predis\Command\KeyRenamePreserve', 'expire' => 'Predis\Command\KeyExpire', 'expireat' => 'Predis\Command\KeyExpireAt', 'ttl' => 'Predis\Command\KeyTimeToLive', 'move' => 'Predis\Command\KeyMove', 'sort' => 'Predis\Command\KeySort', /* commands operating on string values */ 'set' => 'Predis\Command\StringSet', 'setnx' => 'Predis\Command\StringSetPreserve', 'mset' => 'Predis\Command\StringSetMultiple', 'msetnx' => 'Predis\Command\StringSetMultiplePreserve', 'get' => 'Predis\Command\StringGet', 'mget' => 'Predis\Command\StringGetMultiple', 'getset' => 'Predis\Command\StringGetSet', 'incr' => 'Predis\Command\StringIncrement', 'incrby' => 'Predis\Command\StringIncrementBy', 'decr' => 'Predis\Command\StringDecrement', 'decrby' => 'Predis\Command\StringDecrementBy', /* commands operating on lists */ 'rpush' => 'Predis\Command\ListPushTail', 'lpush' => 'Predis\Command\ListPushHead', 'llen' => 'Predis\Command\ListLength', 'lrange' => 'Predis\Command\ListRange', 'ltrim' => 'Predis\Command\ListTrim', 'lindex' => 'Predis\Command\ListIndex', 'lset' => 'Predis\Command\ListSet', 'lrem' => 'Predis\Command\ListRemove', 'lpop' => 'Predis\Command\ListPopFirst', 'rpop' => 'Predis\Command\ListPopLast', 'rpoplpush' => 'Predis\Command\ListPopLastPushHead', /* commands operating on sets */ 'sadd' => 'Predis\Command\SetAdd', 'srem' => 'Predis\Command\SetRemove', 'spop' => 'Predis\Command\SetPop', 'smove' => 'Predis\Command\SetMove', 'scard' => 'Predis\Command\SetCardinality', 'sismember' => 'Predis\Command\SetIsMember', 'sinter' => 'Predis\Command\SetIntersection', 'sinterstore' => 'Predis\Command\SetIntersectionStore', 'sunion' => 'Predis\Command\SetUnion', 'sunionstore' => 'Predis\Command\SetUnionStore', 'sdiff' => 'Predis\Command\SetDifference', 'sdiffstore' => 'Predis\Command\SetDifferenceStore', 'smembers' => 'Predis\Command\SetMembers', 'srandmember' => 'Predis\Command\SetRandomMember', /* commands operating on sorted sets */ 'zadd' => 'Predis\Command\ZSetAdd', 'zincrby' => 'Predis\Command\ZSetIncrementBy', 'zrem' => 'Predis\Command\ZSetRemove', 'zrange' => 'Predis\Command\ZSetRange', 'zrevrange' => 'Predis\Command\ZSetReverseRange', 'zrangebyscore' => 'Predis\Command\ZSetRangeByScore', 'zcard' => 'Predis\Command\ZSetCardinality', 'zscore' => 'Predis\Command\ZSetScore', 'zremrangebyscore' => 'Predis\Command\ZSetRemoveRangeByScore', /* connection related commands */ 'ping' => 'Predis\Command\ConnectionPing', 'auth' => 'Predis\Command\ConnectionAuth', 'select' => 'Predis\Command\ConnectionSelect', 'echo' => 'Predis\Command\ConnectionEcho', 'quit' => 'Predis\Command\ConnectionQuit', /* remote server control commands */ 'info' => 'Predis\Command\ServerInfo', 'slaveof' => 'Predis\Command\ServerSlaveOf', 'monitor' => 'Predis\Command\ServerMonitor', 'dbsize' => 'Predis\Command\ServerDatabaseSize', 'flushdb' => 'Predis\Command\ServerFlushDatabase', 'flushall' => 'Predis\Command\ServerFlushAll', 'save' => 'Predis\Command\ServerSave', 'bgsave' => 'Predis\Command\ServerBackgroundSave', 'lastsave' => 'Predis\Command\ServerLastSave', 'shutdown' => 'Predis\Command\ServerShutdown', 'bgrewriteaof' => 'Predis\Command\ServerBackgroundRewriteAOF', /* ---------------- Redis 2.0 ---------------- */ /* commands operating on string values */ 'setex' => 'Predis\Command\StringSetExpire', 'append' => 'Predis\Command\StringAppend', 'substr' => 'Predis\Command\StringSubstr', /* commands operating on lists */ 'blpop' => 'Predis\Command\ListPopFirstBlocking', 'brpop' => 'Predis\Command\ListPopLastBlocking', /* commands operating on sorted sets */ 'zunionstore' => 'Predis\Command\ZSetUnionStore', 'zinterstore' => 'Predis\Command\ZSetIntersectionStore', 'zcount' => 'Predis\Command\ZSetCount', 'zrank' => 'Predis\Command\ZSetRank', 'zrevrank' => 'Predis\Command\ZSetReverseRank', 'zremrangebyrank' => 'Predis\Command\ZSetRemoveRangeByRank', /* commands operating on hashes */ 'hset' => 'Predis\Command\HashSet', 'hsetnx' => 'Predis\Command\HashSetPreserve', 'hmset' => 'Predis\Command\HashSetMultiple', 'hincrby' => 'Predis\Command\HashIncrementBy', 'hget' => 'Predis\Command\HashGet', 'hmget' => 'Predis\Command\HashGetMultiple', 'hdel' => 'Predis\Command\HashDelete', 'hexists' => 'Predis\Command\HashExists', 'hlen' => 'Predis\Command\HashLength', 'hkeys' => 'Predis\Command\HashKeys', 'hvals' => 'Predis\Command\HashValues', 'hgetall' => 'Predis\Command\HashGetAll', /* transactions */ 'multi' => 'Predis\Command\TransactionMulti', 'exec' => 'Predis\Command\TransactionExec', 'discard' => 'Predis\Command\TransactionDiscard', /* publish - subscribe */ 'subscribe' => 'Predis\Command\PubSubSubscribe', 'unsubscribe' => 'Predis\Command\PubSubUnsubscribe', 'psubscribe' => 'Predis\Command\PubSubSubscribeByPattern', 'punsubscribe' => 'Predis\Command\PubSubUnsubscribeByPattern', 'publish' => 'Predis\Command\PubSubPublish', /* remote server control commands */ 'config' => 'Predis\Command\ServerConfig', /* ---------------- Redis 2.2 ---------------- */ /* commands operating on the key space */ 'persist' => 'Predis\Command\KeyPersist', /* commands operating on string values */ 'strlen' => 'Predis\Command\StringStrlen', 'setrange' => 'Predis\Command\StringSetRange', 'getrange' => 'Predis\Command\StringGetRange', 'setbit' => 'Predis\Command\StringSetBit', 'getbit' => 'Predis\Command\StringGetBit', /* commands operating on lists */ 'rpushx' => 'Predis\Command\ListPushTailX', 'lpushx' => 'Predis\Command\ListPushHeadX', 'linsert' => 'Predis\Command\ListInsert', 'brpoplpush' => 'Predis\Command\ListPopLastPushHeadBlocking', /* commands operating on sorted sets */ 'zrevrangebyscore' => 'Predis\Command\ZSetReverseRangeByScore', /* transactions */ 'watch' => 'Predis\Command\TransactionWatch', 'unwatch' => 'Predis\Command\TransactionUnwatch', /* remote server control commands */ 'object' => 'Predis\Command\ServerObject', 'slowlog' => 'Predis\Command\ServerSlowlog', /* ---------------- Redis 2.4 ---------------- */ /* remote server control commands */ 'client' => 'Predis\Command\ServerClient', /* ---------------- Redis 2.6 ---------------- */ /* commands operating on the key space */ 'pttl' => 'Predis\Command\KeyPreciseTimeToLive', 'pexpire' => 'Predis\Command\KeyPreciseExpire', 'pexpireat' => 'Predis\Command\KeyPreciseExpireAt', /* commands operating on string values */ 'psetex' => 'Predis\Command\StringPreciseSetExpire', 'incrbyfloat' => 'Predis\Command\StringIncrementByFloat', 'bitop' => 'Predis\Command\StringBitOp', 'bitcount' => 'Predis\Command\StringBitCount', /* commands operating on hashes */ 'hincrbyfloat' => 'Predis\Command\HashIncrementByFloat', /* scripting */ 'eval' => 'Predis\Command\ServerEval', 'evalsha' => 'Predis\Command\ServerEvalSHA', 'script' => 'Predis\Command\ServerScript', /* remote server control commands */ 'info' => 'Predis\Command\ServerInfoV26x', 'time' => 'Predis\Command\ServerTime', ); } } predis-0.8.3/lib/Predis/Profile/ServerVersionNext.php000066400000000000000000000013071211043230100225540ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Profile; /** * Server profile for the current unstable version of Redis. * * @author Daniele Alessandri */ class ServerVersionNext extends ServerVersion26 { /** * {@inheritdoc} */ public function getVersion() { return '2.8'; } /** * {@inheritdoc} */ public function getSupportedCommands() { return array_merge(parent::getSupportedCommands(), array()); } } predis-0.8.3/lib/Predis/Protocol/000077500000000000000000000000001211043230100165705ustar00rootroot00000000000000predis-0.8.3/lib/Predis/Protocol/CommandSerializerInterface.php000066400000000000000000000012371211043230100245350ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol; use Predis\Command\CommandInterface; /** * Interface that defines a custom serializer for Redis commands. * * @author Daniele Alessandri */ interface CommandSerializerInterface { /** * Serializes a Redis command. * * @param CommandInterface $command Redis command. * @return string */ public function serialize(CommandInterface $command); } predis-0.8.3/lib/Predis/Protocol/ComposableProtocolInterface.php000066400000000000000000000026241211043230100247340ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol; /** * Interface that defines a customizable protocol processor that serializes * Redis commands and parses replies returned by the server to PHP objects * using a pluggable set of classes defining the underlying wire protocol. * * @author Daniele Alessandri */ interface ComposableProtocolInterface extends ProtocolInterface { /** * Sets the command serializer to be used by the protocol processor. * * @param CommandSerializerInterface $serializer Command serializer. */ public function setSerializer(CommandSerializerInterface $serializer); /** * Returns the command serializer used by the protocol processor. * * @return CommandSerializerInterface */ public function getSerializer(); /** * Sets the response reader to be used by the protocol processor. * * @param ResponseReaderInterface $reader Response reader. */ public function setReader(ResponseReaderInterface $reader); /** * Returns the response reader used by the protocol processor. * * @return ResponseReaderInterface */ public function getReader(); } predis-0.8.3/lib/Predis/Protocol/ProtocolException.php000066400000000000000000000010151211043230100227560ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol; use Predis\CommunicationException; /** * Exception class that identifies errors encountered while * handling the Redis wire protocol. * * @author Daniele Alessandri */ class ProtocolException extends CommunicationException { } predis-0.8.3/lib/Predis/Protocol/ProtocolInterface.php000066400000000000000000000022071211043230100227240ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol; use Predis\Command\CommandInterface; use Predis\Connection\ComposableConnectionInterface; /** * Interface that defines a protocol processor that serializes Redis commands * and parses replies returned by the server to PHP objects. * * @author Daniele Alessandri */ interface ProtocolInterface extends ResponseReaderInterface { /** * Writes a Redis command on the specified connection. * * @param ComposableConnectionInterface $connection Connection to Redis. * @param CommandInterface $command Redis command. */ public function write(ComposableConnectionInterface $connection, CommandInterface $command); /** * Sets the options for the protocol processor. * * @param string $option Name of the option. * @param mixed $value Value of the option. */ public function setOption($option, $value); } predis-0.8.3/lib/Predis/Protocol/ResponseHandlerInterface.php000066400000000000000000000015171211043230100242220ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol; use Predis\Connection\ComposableConnectionInterface; /** * Interface that defines an handler able to parse a reply. * * @author Daniele Alessandri */ interface ResponseHandlerInterface { /** * Parses a type of reply returned by Redis and reads more data from the * connection if needed. * * @param ComposableConnectionInterface $connection Connection to Redis. * @param string $payload Initial payload of the reply. * @return mixed */ function handle(ComposableConnectionInterface $connection, $payload); } predis-0.8.3/lib/Predis/Protocol/ResponseReaderInterface.php000066400000000000000000000014521211043230100240450ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol; use Predis\Connection\ComposableConnectionInterface; /** * Interface that defines a response reader able to parse replies returned by * Redis and deserialize them to PHP objects. * * @author Daniele Alessandri */ interface ResponseReaderInterface { /** * Reads replies from a connection to Redis and deserializes them. * * @param ComposableConnectionInterface $connection Connection to Redis. * @return mixed */ public function read(ComposableConnectionInterface $connection); } predis-0.8.3/lib/Predis/Protocol/Text/000077500000000000000000000000001211043230100175145ustar00rootroot00000000000000predis-0.8.3/lib/Predis/Protocol/Text/ComposableTextProtocol.php000066400000000000000000000062221211043230100247020ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use Predis\Command\CommandInterface; use Predis\Connection\ComposableConnectionInterface; use Predis\Protocol\ResponseReaderInterface; use Predis\Protocol\CommandSerializerInterface; use Predis\Protocol\ComposableProtocolInterface; /** * Implements a customizable protocol processor that uses the standard Redis * wire protocol to serialize Redis commands and parse replies returned by * the server using a pluggable set of classes. * * @link http://redis.io/topics/protocol * @author Daniele Alessandri */ class ComposableTextProtocol implements ComposableProtocolInterface { private $serializer; private $reader; /** * @param array $options Set of options used to initialize the protocol processor. */ public function __construct(Array $options = array()) { $this->setSerializer(new TextCommandSerializer()); $this->setReader(new TextResponseReader()); if (count($options) > 0) { $this->initializeOptions($options); } } /** * Initializes the protocol processor using a set of options. * * @param array $options Set of options. */ private function initializeOptions(Array $options) { foreach ($options as $k => $v) { $this->setOption($k, $v); } } /** * {@inheritdoc} */ public function setOption($option, $value) { switch ($option) { case 'iterable_multibulk': $handler = $value ? new ResponseMultiBulkStreamHandler() : new ResponseMultiBulkHandler(); $this->reader->setHandler(TextProtocol::PREFIX_MULTI_BULK, $handler); break; default: throw new \InvalidArgumentException("The option $option is not supported by the current protocol"); } } /** * {@inheritdoc} */ public function serialize(CommandInterface $command) { return $this->serializer->serialize($command); } /** * {@inheritdoc} */ public function write(ComposableConnectionInterface $connection, CommandInterface $command) { $connection->writeBytes($this->serializer->serialize($command)); } /** * {@inheritdoc} */ public function read(ComposableConnectionInterface $connection) { return $this->reader->read($connection); } /** * {@inheritdoc} */ public function setSerializer(CommandSerializerInterface $serializer) { $this->serializer = $serializer; } /** * {@inheritdoc} */ public function getSerializer() { return $this->serializer; } /** * {@inheritdoc} */ public function setReader(ResponseReaderInterface $reader) { $this->reader = $reader; } /** * {@inheritdoc} */ public function getReader() { return $this->reader; } } predis-0.8.3/lib/Predis/Protocol/Text/ResponseBulkHandler.php000066400000000000000000000027071211043230100241450ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use Predis\CommunicationException; use Predis\Connection\ComposableConnectionInterface; use Predis\Protocol\ProtocolException; use Predis\Protocol\ResponseHandlerInterface; /** * Implements a response handler for bulk replies using the standard wire * protocol defined by Redis. * * @link http://redis.io/topics/protocol * @author Daniele Alessandri */ class ResponseBulkHandler implements ResponseHandlerInterface { /** * Handles a bulk reply returned by Redis. * * @param ComposableConnectionInterface $connection Connection to Redis. * @param string $lengthString Bytes size of the bulk reply. * @return string */ public function handle(ComposableConnectionInterface $connection, $lengthString) { $length = (int) $lengthString; if ("$length" !== $lengthString) { CommunicationException::handle(new ProtocolException( $connection, "Cannot parse '$lengthString' as bulk length" )); } if ($length >= 0) { return substr($connection->readBytes($length + 2), 0, -2); } if ($length == -1) { return null; } } } predis-0.8.3/lib/Predis/Protocol/Text/ResponseErrorHandler.php000066400000000000000000000017061211043230100243370ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use Predis\ResponseError; use Predis\Connection\ComposableConnectionInterface; use Predis\Protocol\ResponseHandlerInterface; /** * Implements a response handler for error replies using the standard wire * protocol defined by Redis. * * This handler returns a reply object to notify the user that an error has * occurred on the server. * * @link http://redis.io/topics/protocol * @author Daniele Alessandri */ class ResponseErrorHandler implements ResponseHandlerInterface { /** * {@inheritdoc} */ public function handle(ComposableConnectionInterface $connection, $errorMessage) { return new ResponseError($errorMessage); } } predis-0.8.3/lib/Predis/Protocol/Text/ResponseIntegerHandler.php000066400000000000000000000025151211043230100246420ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use Predis\CommunicationException; use Predis\Connection\ComposableConnectionInterface; use Predis\Protocol\ProtocolException; use Predis\Protocol\ResponseHandlerInterface; /** * Implements a response handler for integer replies using the standard wire * protocol defined by Redis. * * @link http://redis.io/topics/protocol * @author Daniele Alessandri */ class ResponseIntegerHandler implements ResponseHandlerInterface { /** * Handles an integer reply returned by Redis. * * @param ComposableConnectionInterface $connection Connection to Redis. * @param string $number String representation of an integer. * @return int */ public function handle(ComposableConnectionInterface $connection, $number) { if (is_numeric($number)) { return (int) $number; } if ($number !== 'nil') { CommunicationException::handle(new ProtocolException( $connection, "Cannot parse '$number' as numeric response" )); } return null; } } predis-0.8.3/lib/Predis/Protocol/Text/ResponseMultiBulkHandler.php000066400000000000000000000040551211043230100251560ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use Predis\CommunicationException; use Predis\Connection\ComposableConnectionInterface; use Predis\Protocol\ProtocolException; use Predis\Protocol\ResponseHandlerInterface; /** * Implements a response handler for multi-bulk replies using the standard * wire protocol defined by Redis. * * @link http://redis.io/topics/protocol * @author Daniele Alessandri */ class ResponseMultiBulkHandler implements ResponseHandlerInterface { /** * Handles a multi-bulk reply returned by Redis. * * @param ComposableConnectionInterface $connection Connection to Redis. * @param string $lengthString Number of items in the multi-bulk reply. * @return array */ public function handle(ComposableConnectionInterface $connection, $lengthString) { $length = (int) $lengthString; if ("$length" !== $lengthString) { CommunicationException::handle(new ProtocolException( $connection, "Cannot parse '$lengthString' as multi-bulk length" )); } if ($length === -1) { return null; } $list = array(); if ($length > 0) { $handlersCache = array(); $reader = $connection->getProtocol()->getReader(); for ($i = 0; $i < $length; $i++) { $header = $connection->readLine(); $prefix = $header[0]; if (isset($handlersCache[$prefix])) { $handler = $handlersCache[$prefix]; } else { $handler = $reader->getHandler($prefix); $handlersCache[$prefix] = $handler; } $list[$i] = $handler->handle($connection, substr($header, 1)); } } return $list; } } predis-0.8.3/lib/Predis/Protocol/Text/ResponseMultiBulkStreamHandler.php000066400000000000000000000027411211043230100263320ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use Predis\CommunicationException; use Predis\Connection\ComposableConnectionInterface; use Predis\Iterator\MultiBulkResponseSimple; use Predis\Protocol\ProtocolException; use Predis\Protocol\ResponseHandlerInterface; /** * Implements a response handler for iterable multi-bulk replies using the * standard wire protocol defined by Redis. * * @link http://redis.io/topics/protocol * @author Daniele Alessandri */ class ResponseMultiBulkStreamHandler implements ResponseHandlerInterface { /** * Handles a multi-bulk reply returned by Redis in a streamable fashion. * * @param ComposableConnectionInterface $connection Connection to Redis. * @param string $lengthString Number of items in the multi-bulk reply. * @return MultiBulkResponseSimple */ public function handle(ComposableConnectionInterface $connection, $lengthString) { $length = (int) $lengthString; if ("$length" != $lengthString) { CommunicationException::handle(new ProtocolException( $connection, "Cannot parse '$lengthString' as multi-bulk length" )); } return new MultiBulkResponseSimple($connection, $length); } } predis-0.8.3/lib/Predis/Protocol/Text/ResponseStatusHandler.php000066400000000000000000000020001211043230100245150ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use Predis\ResponseQueued; use Predis\Connection\ComposableConnectionInterface; use Predis\Protocol\ResponseHandlerInterface; /** * Implements a response handler for status replies using the standard wire * protocol defined by Redis. * * @link http://redis.io/topics/protocol * @author Daniele Alessandri */ class ResponseStatusHandler implements ResponseHandlerInterface { /** * {@inheritdoc} */ public function handle(ComposableConnectionInterface $connection, $status) { switch ($status) { case 'OK': return true; case 'QUEUED': return new ResponseQueued(); default: return $status; } } } predis-0.8.3/lib/Predis/Protocol/Text/TextCommandSerializer.php000066400000000000000000000022551211043230100245060ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use Predis\Command\CommandInterface; use Predis\Protocol\CommandSerializerInterface; /** * Implements a pluggable command serializer using the standard wire protocol * defined by Redis. * * @link http://redis.io/topics/protocol * @author Daniele Alessandri */ class TextCommandSerializer implements CommandSerializerInterface { /** * {@inheritdoc} */ public function serialize(CommandInterface $command) { $commandId = $command->getId(); $arguments = $command->getArguments(); $cmdlen = strlen($commandId); $reqlen = count($arguments) + 1; $buffer = "*{$reqlen}\r\n\${$cmdlen}\r\n{$commandId}\r\n"; for ($i = 0; $i < $reqlen - 1; $i++) { $argument = $arguments[$i]; $arglen = strlen($argument); $buffer .= "\${$arglen}\r\n{$argument}\r\n"; } return $buffer; } } predis-0.8.3/lib/Predis/Protocol/Text/TextProtocol.php000066400000000000000000000067161211043230100227050ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use Predis\CommunicationException; use Predis\ResponseError; use Predis\ResponseQueued; use Predis\ServerException; use Predis\Command\CommandInterface; use Predis\Connection\ComposableConnectionInterface; use Predis\Iterator\MultiBulkResponseSimple; use Predis\Protocol\ProtocolException; use Predis\Protocol\ProtocolInterface; /** * Implements a protocol processor for the standard wire protocol defined by Redis. * * @link http://redis.io/topics/protocol * @author Daniele Alessandri */ class TextProtocol implements ProtocolInterface { const NEWLINE = "\r\n"; const OK = 'OK'; const ERROR = 'ERR'; const QUEUED = 'QUEUED'; const NULL = 'nil'; const PREFIX_STATUS = '+'; const PREFIX_ERROR = '-'; const PREFIX_INTEGER = ':'; const PREFIX_BULK = '$'; const PREFIX_MULTI_BULK = '*'; const BUFFER_SIZE = 4096; private $mbiterable; private $serializer; /** * */ public function __construct() { $this->mbiterable = false; $this->serializer = new TextCommandSerializer(); } /** * {@inheritdoc} */ public function write(ComposableConnectionInterface $connection, CommandInterface $command) { $connection->writeBytes($this->serializer->serialize($command)); } /** * {@inheritdoc} */ public function read(ComposableConnectionInterface $connection) { $chunk = $connection->readLine(); $prefix = $chunk[0]; $payload = substr($chunk, 1); switch ($prefix) { case '+': // inline switch ($payload) { case 'OK': return true; case 'QUEUED': return new ResponseQueued(); default: return $payload; } case '$': // bulk $size = (int) $payload; if ($size === -1) { return null; } return substr($connection->readBytes($size + 2), 0, -2); case '*': // multi bulk $count = (int) $payload; if ($count === -1) { return null; } if ($this->mbiterable) { return new MultiBulkResponseSimple($connection, $count); } $multibulk = array(); for ($i = 0; $i < $count; $i++) { $multibulk[$i] = $this->read($connection); } return $multibulk; case ':': // integer return (int) $payload; case '-': // error return new ResponseError($payload); default: CommunicationException::handle(new ProtocolException( $connection, "Unknown prefix: '$prefix'" )); } } /** * {@inheritdoc} */ public function setOption($option, $value) { switch ($option) { case 'iterable_multibulk': $this->mbiterable = (bool) $value; break; } } } predis-0.8.3/lib/Predis/Protocol/Text/TextResponseReader.php000066400000000000000000000064271211043230100240240ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use Predis\CommunicationException; use Predis\Connection\ComposableConnectionInterface; use Predis\Protocol\ProtocolException; use Predis\Protocol\ResponseHandlerInterface; use Predis\Protocol\ResponseReaderInterface; /** * Implements a pluggable response reader using the standard wire protocol * defined by Redis. * * @link http://redis.io/topics/protocol * @author Daniele Alessandri */ class TextResponseReader implements ResponseReaderInterface { private $handlers; /** * */ public function __construct() { $this->handlers = $this->getDefaultHandlers(); } /** * Returns the default set of response handlers for all the type of replies * that can be returned by Redis. */ private function getDefaultHandlers() { return array( TextProtocol::PREFIX_STATUS => new ResponseStatusHandler(), TextProtocol::PREFIX_ERROR => new ResponseErrorHandler(), TextProtocol::PREFIX_INTEGER => new ResponseIntegerHandler(), TextProtocol::PREFIX_BULK => new ResponseBulkHandler(), TextProtocol::PREFIX_MULTI_BULK => new ResponseMultiBulkHandler(), ); } /** * Sets a response handler for a certain prefix that identifies a type of * reply that can be returned by Redis. * * @param string $prefix Identifier for a type of reply. * @param ResponseHandlerInterface $handler Response handler for the reply. */ public function setHandler($prefix, ResponseHandlerInterface $handler) { $this->handlers[$prefix] = $handler; } /** * Returns the response handler associated to a certain type of reply that * can be returned by Redis. * * @param string $prefix Identifier for a type of reply. * @return ResponseHandlerInterface */ public function getHandler($prefix) { if (isset($this->handlers[$prefix])) { return $this->handlers[$prefix]; } } /** * {@inheritdoc} */ public function read(ComposableConnectionInterface $connection) { $header = $connection->readLine(); if ($header === '') { $this->protocolError($connection, 'Unexpected empty header'); } $prefix = $header[0]; if (!isset($this->handlers[$prefix])) { $this->protocolError($connection, "Unknown prefix: '$prefix'"); } $handler = $this->handlers[$prefix]; return $handler->handle($connection, substr($header, 1)); } /** * Helper method used to handle a protocol error generated while reading a * reply from a connection to Redis. * * @param ComposableConnectionInterface $connection Connection to Redis that generated the error. * @param string $message Error message. */ private function protocolError(ComposableConnectionInterface $connection, $message) { CommunicationException::handle(new ProtocolException($connection, $message)); } } predis-0.8.3/lib/Predis/PubSub/000077500000000000000000000000001211043230100161675ustar00rootroot00000000000000predis-0.8.3/lib/Predis/PubSub/AbstractPubSubContext.php000066400000000000000000000121671211043230100231400ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\PubSub; use Predis\ClientException; use Predis\ClientInterface; use Predis\NotSupportedException; /** * Client-side abstraction of a Publish / Subscribe context. * * @author Daniele Alessandri */ abstract class AbstractPubSubContext implements \Iterator { const SUBSCRIBE = 'subscribe'; const UNSUBSCRIBE = 'unsubscribe'; const PSUBSCRIBE = 'psubscribe'; const PUNSUBSCRIBE = 'punsubscribe'; const MESSAGE = 'message'; const PMESSAGE = 'pmessage'; const STATUS_VALID = 1; // 0b0001 const STATUS_SUBSCRIBED = 2; // 0b0010 const STATUS_PSUBSCRIBED = 4; // 0b0100 private $position = null; private $statusFlags = self::STATUS_VALID; /** * Automatically closes the context when PHP's garbage collector kicks in. */ public function __destruct() { $this->closeContext(true); } /** * Checks if the specified flag is valid in the state of the context. * * @param int $value Flag. * @return Boolean */ protected function isFlagSet($value) { return ($this->statusFlags & $value) === $value; } /** * Subscribes to the specified channels. * * @param mixed $arg,... One or more channel names. */ public function subscribe(/* arguments */) { $this->writeCommand(self::SUBSCRIBE, func_get_args()); $this->statusFlags |= self::STATUS_SUBSCRIBED; } /** * Unsubscribes from the specified channels. * * @param mixed $arg,... One or more channel names. */ public function unsubscribe(/* arguments */) { $this->writeCommand(self::UNSUBSCRIBE, func_get_args()); } /** * Subscribes to the specified channels using a pattern. * * @param mixed $arg,... One or more channel name patterns. */ public function psubscribe(/* arguments */) { $this->writeCommand(self::PSUBSCRIBE, func_get_args()); $this->statusFlags |= self::STATUS_PSUBSCRIBED; } /** * Unsubscribes from the specified channels using a pattern. * * @param mixed $arg,... One or more channel name patterns. */ public function punsubscribe(/* arguments */) { $this->writeCommand(self::PUNSUBSCRIBE, func_get_args()); } /** * 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($force = false) { if (!$this->valid()) { return false; } if ($force) { $this->invalidate(); $this->disconnect(); } else { if ($this->isFlagSet(self::STATUS_SUBSCRIBED)) { $this->unsubscribe(); } if ($this->isFlagSet(self::STATUS_PSUBSCRIBED)) { $this->punsubscribe(); } } return !$force; } /** * Closes the underlying connection on forced disconnection. */ protected abstract function disconnect(); /** * Writes a Redis command on the underlying connection. * * @param string $method ID of the command. * @param array $arguments List of arguments. */ protected abstract function writeCommand($method, $arguments); /** * {@inheritdoc} */ public function rewind() { // NOOP } /** * Returns the last message payload retrieved from the server and generated * by one of the active subscriptions. * * @return array */ public function current() { return $this->getValue(); } /** * {@inheritdoc} */ public function key() { return $this->position; } /** * {@inheritdoc} */ public function next() { if ($this->valid()) { $this->position++; } return $this->position; } /** * Checks if the the context is still in a valid state to continue. * * @return Boolean */ public function valid() { $isValid = $this->isFlagSet(self::STATUS_VALID); $subscriptionFlags = self::STATUS_SUBSCRIBED | self::STATUS_PSUBSCRIBED; $hasSubscriptions = ($this->statusFlags & $subscriptionFlags) > 0; return $isValid && $hasSubscriptions; } /** * Resets the state of the context. */ protected function invalidate() { $this->statusFlags = 0; // 0b0000; } /** * Waits for a new message from the server generated by one of the active * subscriptions and returns it when available. * * @return array */ protected abstract function getValue(); } predis-0.8.3/lib/Predis/PubSub/DispatcherLoop.php000066400000000000000000000075111211043230100216240ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\PubSub; use Predis\ClientInterface; /** * Method-dispatcher loop built around the client-side abstraction of a Redis * Publish / Subscribe context. * * @author Daniele Alessandri */ class DispatcherLoop { private $client; private $pubSubContext; private $callbacks; private $defaultCallback; private $subscriptionCallback; /** * @param ClientInterface Client instance used by the context. */ public function __construct(ClientInterface $client) { $this->callbacks = array(); $this->client = $client; $this->pubSubContext = $client->pubSub(); } /** * Checks if the passed argument is a valid callback. * * @param mixed A callback. */ protected function validateCallback($callable) { if (!is_callable($callable)) { throw new \InvalidArgumentException("A valid callable object must be provided"); } } /** * Returns the underlying Publish / Subscribe context. * * @return PubSubContext */ public function getPubSubContext() { return $this->pubSubContext; } /** * Sets a callback that gets invoked upon new subscriptions. * * @param mixed $callable A callback. */ public function subscriptionCallback($callable = null) { if (isset($callable)) { $this->validateCallback($callable); } $this->subscriptionCallback = $callable; } /** * Sets a callback that gets invoked when a message is received on a * channel that does not have an associated callback. * * @param mixed $callable A callback. */ public function defaultCallback($callable = null) { if (isset($callable)) { $this->validateCallback($callable); } $this->subscriptionCallback = $callable; } /** * Binds a callback to a channel. * * @param string $channel Channel name. * @param Callable $callback A callback. */ public function attachCallback($channel, $callback) { $this->validateCallback($callback); $this->callbacks[$channel] = $callback; $this->pubSubContext->subscribe($channel); } /** * Stops listening to a channel and removes the associated callback. * * @param string $channel Redis channel. */ public function detachCallback($channel) { if (isset($this->callbacks[$channel])) { unset($this->callbacks[$channel]); $this->pubSubContext->unsubscribe($channel); } } /** * Starts the dispatcher loop. */ public function run() { foreach ($this->pubSubContext as $message) { $kind = $message->kind; if ($kind !== PubSubContext::MESSAGE && $kind !== PubSubContext::PMESSAGE) { if (isset($this->subscriptionCallback)) { $callback = $this->subscriptionCallback; call_user_func($callback, $message); } continue; } if (isset($this->callbacks[$message->channel])) { $callback = $this->callbacks[$message->channel]; call_user_func($callback, $message->payload); } else if (isset($this->defaultCallback)) { $callback = $this->defaultCallback; call_user_func($callback, $message); } } } /** * Terminates the dispatcher loop. */ public function stop() { $this->pubSubContext->closeContext(); } } predis-0.8.3/lib/Predis/PubSub/PubSubContext.php000066400000000000000000000074301211043230100214510ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\PubSub; use Predis\ClientException; use Predis\ClientInterface; use Predis\Command\AbstractCommand as Command; use Predis\NotSupportedException; use Predis\Connection\AggregatedConnectionInterface; /** * Client-side abstraction of a Publish / Subscribe context. * * @author Daniele Alessandri */ class PubSubContext extends AbstractPubSubContext { private $client; private $options; /** * @param ClientInterface Client instance used by the context. * @param array Options for the context initialization. */ public function __construct(ClientInterface $client, Array $options = null) { $this->checkCapabilities($client); $this->options = $options ?: array(); $this->client = $client; $this->genericSubscribeInit('subscribe'); $this->genericSubscribeInit('psubscribe'); } /** * Checks if the passed client instance satisfies the required conditions * needed to initialize a Publish / Subscribe context. * * @param ClientInterface Client instance used by the context. */ private function checkCapabilities(ClientInterface $client) { if ($client->getConnection() instanceof AggregatedConnectionInterface) { throw new NotSupportedException('Cannot initialize a PUB/SUB context when using aggregated connections'); } $commands = array('publish', 'subscribe', 'unsubscribe', 'psubscribe', 'punsubscribe'); if ($client->getProfile()->supportsCommands($commands) === false) { throw new NotSupportedException('The current profile does not support PUB/SUB related commands'); } } /** * This method shares the logic to handle both SUBSCRIBE and PSUBSCRIBE. * * @param string $subscribeAction Type of subscription. */ private function genericSubscribeInit($subscribeAction) { if (isset($this->options[$subscribeAction])) { $this->$subscribeAction($this->options[$subscribeAction]); } } /** * {@inheritdoc} */ protected function writeCommand($method, $arguments) { $arguments = Command::normalizeArguments($arguments); $command = $this->client->createCommand($method, $arguments); $this->client->getConnection()->writeCommand($command); } /** * {@inheritdoc} */ protected function disconnect() { $this->client->disconnect(); } /** * {@inheritdoc} */ protected function getValue() { $response = $this->client->getConnection()->read(); switch ($response[0]) { case self::SUBSCRIBE: case self::UNSUBSCRIBE: case self::PSUBSCRIBE: case self::PUNSUBSCRIBE: if ($response[2] === 0) { $this->invalidate(); } case self::MESSAGE: return (object) array( 'kind' => $response[0], 'channel' => $response[1], 'payload' => $response[2], ); case self::PMESSAGE: return (object) array( 'kind' => $response[0], 'pattern' => $response[1], 'channel' => $response[2], 'payload' => $response[3], ); default: $message = "Received an unknown message type {$response[0]} inside of a pubsub context"; throw new ClientException($message); } } } predis-0.8.3/lib/Predis/Replication/000077500000000000000000000000001211043230100172405ustar00rootroot00000000000000predis-0.8.3/lib/Predis/Replication/ReplicationStrategy.php000066400000000000000000000154141211043230100237520ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Replication; use Predis\NotSupportedException; use Predis\Command\CommandInterface; /** * Defines a strategy for master/reply replication. * * @author Daniele Alessandri */ class ReplicationStrategy { protected $disallowed; protected $readonly; protected $readonlySHA1; /** * */ public function __construct() { $this->disallowed = $this->getDisallowedOperations(); $this->readonly = $this->getReadOnlyOperations(); $this->readonlySHA1 = array(); } /** * Returns if the specified command performs a read-only operation * against a key stored on Redis. * * @param CommandInterface $command Instance of Redis command. * @return Boolean */ public function isReadOperation(CommandInterface $command) { if (isset($this->disallowed[$id = $command->getId()])) { throw new NotSupportedException("The command $id is not allowed in replication mode"); } if (isset($this->readonly[$id])) { if (true === $readonly = $this->readonly[$id]) { return true; } return call_user_func($readonly, $command); } if (($eval = $id === 'EVAL') || $id === 'EVALSHA') { $sha1 = $eval ? sha1($command->getArgument(0)) : $command->getArgument(0); if (isset($this->readonlySHA1[$sha1])) { if (true === $readonly = $this->readonlySHA1[$sha1]) { return true; } return call_user_func($readonly, $command); } } return false; } /** * Returns if the specified command is disallowed in a master/slave * replication context. * * @param CommandInterface $command Instance of Redis command. * @return Boolean */ public function isDisallowedOperation(CommandInterface $command) { return isset($this->disallowed[$command->getId()]); } /** * Checks if a SORT command is a readable operation by parsing the arguments * array of the specified commad instance. * * @param CommandInterface $command Instance of Redis command. * @return Boolean */ protected function isSortReadOnly(CommandInterface $command) { $arguments = $command->getArguments(); return ($c = count($arguments)) === 1 ? true : $arguments[$c - 2] !== 'STORE'; } /** * Marks a command as a read-only operation. When the behaviour of a * command can be decided only at runtime depending on its arguments, * a callable object can be provided to dynamically check if the passed * instance of a command performs write operations or not. * * @param string $commandID ID of the command. * @param mixed $readonly A boolean or a callable object. */ public function setCommandReadOnly($commandID, $readonly = true) { $commandID = strtoupper($commandID); if ($readonly) { $this->readonly[$commandID] = $readonly; } else { unset($this->readonly[$commandID]); } } /** * Marks a Lua script for EVAL and EVALSHA as a read-only operation. When * the behaviour of a script can be decided only at runtime depending on * its arguments, a callable object can be provided to dynamically check * if the passed instance of EVAL or EVALSHA performs write operations or * not. * * @param string $script Body of the Lua script. * @param mixed $readonly A boolean or a callable object. */ public function setScriptReadOnly($script, $readonly = true) { $sha1 = sha1($script); if ($readonly) { $this->readonlySHA1[$sha1] = $readonly; } else { unset($this->readonlySHA1[$sha1]); } } /** * Returns the default list of disallowed commands. * * @return array */ protected function getDisallowedOperations() { return array( 'SHUTDOWN' => true, 'INFO' => true, 'DBSIZE' => true, 'LASTSAVE' => true, 'CONFIG' => true, 'MONITOR' => true, 'SLAVEOF' => true, 'SAVE' => true, 'BGSAVE' => true, 'BGREWRITEAOF' => true, 'SLOWLOG' => true, ); } /** * Returns the default list of commands performing read-only operations. * * @return array */ protected function getReadOnlyOperations() { return array( 'EXISTS' => true, 'TYPE' => true, 'KEYS' => true, 'RANDOMKEY' => true, 'TTL' => true, 'GET' => true, 'MGET' => true, 'SUBSTR' => true, 'STRLEN' => true, 'GETRANGE' => true, 'GETBIT' => true, 'LLEN' => true, 'LRANGE' => true, 'LINDEX' => true, 'SCARD' => true, 'SISMEMBER' => true, 'SINTER' => true, 'SUNION' => true, 'SDIFF' => true, 'SMEMBERS' => true, 'SRANDMEMBER' => true, 'ZRANGE' => true, 'ZREVRANGE' => true, 'ZRANGEBYSCORE' => true, 'ZREVRANGEBYSCORE' => true, 'ZCARD' => true, 'ZSCORE' => true, 'ZCOUNT' => true, 'ZRANK' => true, 'ZREVRANK' => true, 'HGET' => true, 'HMGET' => true, 'HEXISTS' => true, 'HLEN' => true, 'HKEYS' => true, 'HVALS' => true, 'HGETALL' => true, 'PING' => true, 'AUTH' => true, 'SELECT' => true, 'ECHO' => true, 'QUIT' => true, 'OBJECT' => true, 'BITCOUNT' => true, 'TIME' => true, 'SORT' => array($this, 'isSortReadOnly'), ); } } predis-0.8.3/lib/Predis/ResponseError.php000066400000000000000000000022051211043230100203070ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis; /** * Represents an error returned by Redis (-ERR replies) during the execution * of a command on the server. * * @author Daniele Alessandri */ class ResponseError implements ResponseErrorInterface { private $message; /** * @param string $message Error message returned by Redis */ public function __construct($message) { $this->message = $message; } /** * {@inheritdoc} */ public function getMessage() { return $this->message; } /** * {@inheritdoc} */ public function getErrorType() { list($errorType, ) = explode(' ', $this->getMessage(), 2); return $errorType; } /** * Converts the object to its string representation. * * @return string */ public function __toString() { return $this->getMessage(); } } predis-0.8.3/lib/Predis/ResponseErrorInterface.php000066400000000000000000000014331211043230100221320ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis; /** * Represents an error returned by Redis (replies identified by "-" in the * Redis response protocol) during the execution of an operation on the server. * * @author Daniele Alessandri */ interface ResponseErrorInterface extends ResponseObjectInterface { /** * Returns the error message * * @return string */ public function getMessage(); /** * Returns the error type (e.g. ERR, ASK, MOVED) * * @return string */ public function getErrorType(); } predis-0.8.3/lib/Predis/ResponseObjectInterface.php000066400000000000000000000006331211043230100222500ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis; /** * Represents a complex reply object from Redis. * * @author Daniele Alessandri */ interface ResponseObjectInterface { } predis-0.8.3/lib/Predis/ResponseQueued.php000066400000000000000000000022041211043230100204450ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis; /** * Represents a +QUEUED response returned by Redis as a reply to each command * executed inside a MULTI/ EXEC transaction. * * @author Daniele Alessandri */ class ResponseQueued implements ResponseObjectInterface { /** * Converts the object to its string representation. * * @return string */ public function __toString() { return 'QUEUED'; } /** * Returns the value of the specified property. * * @param string $property Name of the property. * @return mixed */ public function __get($property) { return $property === 'queued'; } /** * Checks if the specified property is set. * * @param string $property Name of the property. * @return Boolean */ public function __isset($property) { return $property === 'queued'; } } predis-0.8.3/lib/Predis/ServerException.php000066400000000000000000000016421211043230100206300ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis; /** * Exception class that identifies server-side Redis errors. * * @author Daniele Alessandri */ class ServerException extends PredisException implements ResponseErrorInterface { /** * Gets the type of the error returned by Redis. * * @return string */ public function getErrorType() { list($errorType, ) = explode(' ', $this->getMessage(), 2); return $errorType; } /** * Converts the exception to an instance of ResponseError. * * @return ResponseError */ public function toResponseError() { return new ResponseError($this->getMessage()); } } predis-0.8.3/lib/Predis/Session/000077500000000000000000000000001211043230100164125ustar00rootroot00000000000000predis-0.8.3/lib/Predis/Session/SessionHandler.php000066400000000000000000000057631211043230100220570ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Session; use SessionHandlerInterface; use Predis\ClientInterface; /** * Session handler class that relies on Predis\Client to store PHP's sessions * data into one or multiple Redis servers. * * This class is mostly intended for PHP 5.4 but it can be used under PHP 5.3 provided * that a polyfill for `SessionHandlerInterface` is defined by either you or an external * package such as `symfony/http-foundation`. * * @author Daniele Alessandri */ class SessionHandler implements SessionHandlerInterface { protected $client; protected $ttl; /** * @param ClientInterface $client Fully initialized client instance. * @param array $options Session handler options. */ public function __construct(ClientInterface $client, Array $options = array()) { $this->client = $client; $this->ttl = (int) (isset($options['gc_maxlifetime']) ? $options['gc_maxlifetime'] : ini_get('session.gc_maxlifetime')); } /** * Registers the handler instance as the current session handler. */ public function register() { if (version_compare(PHP_VERSION, '5.4.0') >= 0) { session_set_save_handler($this, true); } else { session_set_save_handler( array($this, 'open'), array($this, 'close'), array($this, 'read'), array($this, 'write'), array($this, 'destroy'), array($this, 'gc') ); } } /** * {@inheritdoc} */ public function open($save_path, $session_id) { // NOOP return true; } /** * {@inheritdoc} */ public function close() { // NOOP return true; } /** * {@inheritdoc} */ public function gc($maxlifetime) { // NOOP return true; } /** * {@inheritdoc} */ public function read($session_id) { if ($data = $this->client->get($session_id)) { return $data; } return ''; } /** * {@inheritdoc} */ public function write($session_id, $session_data) { $this->client->setex($session_id, $this->ttl, $session_data); return true; } /** * {@inheritdoc} */ public function destroy($session_id) { $this->client->del($session_id); return true; } /** * Returns the underlying client instance. * * @return ClientInterface */ public function getClient() { return $this->client; } /** * Returns the session max lifetime value. * * @return int */ public function getMaxLifeTime() { return $this->ttl; } } predis-0.8.3/lib/Predis/Transaction/000077500000000000000000000000001211043230100172545ustar00rootroot00000000000000predis-0.8.3/lib/Predis/Transaction/AbortedMultiExecException.php000066400000000000000000000021171211043230100250450ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Transaction; use Predis\PredisException; /** * Exception class that identifies MULTI / EXEC transactions aborted by Redis. * * @author Daniele Alessandri */ class AbortedMultiExecException extends PredisException { private $transaction; /** * @param MultiExecContext $transaction Transaction that generated the exception. * @param string $message Error message. * @param int $code Error code. */ public function __construct(MultiExecContext $transaction, $message, $code = null) { parent::__construct($message, $code); $this->transaction = $transaction; } /** * Returns the transaction that generated the exception. * * @return MultiExecContext */ public function getTransaction() { return $this->transaction; } } predis-0.8.3/lib/Predis/Transaction/MultiExecContext.php000066400000000000000000000303501211043230100232320ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Transaction; use SplQueue; use Predis\BasicClientInterface; use Predis\ClientException; use Predis\ClientInterface; use Predis\CommunicationException; use Predis\ExecutableContextInterface; use Predis\NotSupportedException; use Predis\ResponseErrorInterface; use Predis\ResponseQueued; use Predis\ServerException; use Predis\Command\CommandInterface; use Predis\Connection\AggregatedConnectionInterface; use Predis\Protocol\ProtocolException; /** * Client-side abstraction of a Redis transaction based on MULTI / EXEC. * * @author Daniele Alessandri */ class MultiExecContext implements BasicClientInterface, ExecutableContextInterface { const STATE_RESET = 0; // 0b00000 const STATE_INITIALIZED = 1; // 0b00001 const STATE_INSIDEBLOCK = 2; // 0b00010 const STATE_DISCARDED = 4; // 0b00100 const STATE_CAS = 8; // 0b01000 const STATE_WATCH = 16; // 0b10000 private $state; private $canWatch; protected $client; protected $options; protected $commands; /** * @param ClientInterface Client instance used by the context. * @param array Options for the context initialization. */ public function __construct(ClientInterface $client, Array $options = null) { $this->checkCapabilities($client); $this->options = $options ?: array(); $this->client = $client; $this->reset(); } /** * Sets the internal state flags. * * @param int $flags Set of flags */ protected function setState($flags) { $this->state = $flags; } /** * Gets the internal state flags. * * @return int */ protected function getState() { return $this->state; } /** * Sets one or more flags. * * @param int $flags Set of flags */ protected function flagState($flags) { $this->state |= $flags; } /** * Resets one or more flags. * * @param int $flags Set of flags */ protected function unflagState($flags) { $this->state &= ~$flags; } /** * Checks is a flag is set. * * @param int $flags Flag * @return Boolean */ protected function checkState($flags) { return ($this->state & $flags) === $flags; } /** * Checks if the passed client instance satisfies the required conditions * needed to initialize a transaction context. * * @param ClientInterface Client instance used by the context. */ private function checkCapabilities(ClientInterface $client) { if ($client->getConnection() instanceof AggregatedConnectionInterface) { throw new NotSupportedException('Cannot initialize a MULTI/EXEC context when using aggregated connections'); } $profile = $client->getProfile(); if ($profile->supportsCommands(array('multi', 'exec', 'discard')) === false) { throw new NotSupportedException('The current profile does not support MULTI, EXEC and DISCARD'); } $this->canWatch = $profile->supportsCommands(array('watch', 'unwatch')); } /** * Checks if WATCH and UNWATCH are supported by the server profile. */ private function isWatchSupported() { if ($this->canWatch === false) { throw new NotSupportedException('The current profile does not support WATCH and UNWATCH'); } } /** * Resets the state of a transaction. */ protected function reset() { $this->setState(self::STATE_RESET); $this->commands = new SplQueue(); } /** * Initializes a new transaction. */ protected function initialize() { if ($this->checkState(self::STATE_INITIALIZED)) { return; } $options = $this->options; if (isset($options['cas']) && $options['cas']) { $this->flagState(self::STATE_CAS); } if (isset($options['watch'])) { $this->watch($options['watch']); } $cas = $this->checkState(self::STATE_CAS); $discarded = $this->checkState(self::STATE_DISCARDED); if (!$cas || ($cas && $discarded)) { $this->client->multi(); if ($discarded) { $this->unflagState(self::STATE_CAS); } } $this->unflagState(self::STATE_DISCARDED); $this->flagState(self::STATE_INITIALIZED); } /** * Dynamically invokes a Redis command with the specified arguments. * * @param string $method Command ID. * @param array $arguments Arguments for the command. * @return mixed */ public function __call($method, $arguments) { $command = $this->client->createCommand($method, $arguments); $response = $this->executeCommand($command); return $response; } /** * Executes the specified Redis command. * * @param CommandInterface $command A Redis command. * @return mixed */ public function executeCommand(CommandInterface $command) { $this->initialize(); $response = $this->client->executeCommand($command); if ($this->checkState(self::STATE_CAS)) { return $response; } if (!$response instanceof ResponseQueued) { $this->onProtocolError('The server did not respond with a QUEUED status reply'); } $this->commands->enqueue($command); return $this; } /** * Executes WATCH on one or more keys. * * @param string|array $keys One or more keys. * @return mixed */ public function watch($keys) { $this->isWatchSupported(); if ($this->checkState(self::STATE_INITIALIZED) && !$this->checkState(self::STATE_CAS)) { throw new ClientException('WATCH after MULTI is not allowed'); } $reply = $this->client->watch($keys); $this->flagState(self::STATE_WATCH); return $reply; } /** * Finalizes the transaction on the server by executing MULTI on the server. * * @return MultiExecContext */ public function multi() { if ($this->checkState(self::STATE_INITIALIZED | self::STATE_CAS)) { $this->unflagState(self::STATE_CAS); $this->client->multi(); } else { $this->initialize(); } return $this; } /** * Executes UNWATCH. * * @return MultiExecContext */ public function unwatch() { $this->isWatchSupported(); $this->unflagState(self::STATE_WATCH); $this->__call('unwatch', array()); return $this; } /** * Resets a transaction by UNWATCHing the keys that are being WATCHed and * DISCARDing the pending commands that have been already sent to the server. * * @return MultiExecContext */ public function discard() { if ($this->checkState(self::STATE_INITIALIZED)) { $command = $this->checkState(self::STATE_CAS) ? 'unwatch' : 'discard'; $this->client->$command(); $this->reset(); $this->flagState(self::STATE_DISCARDED); } return $this; } /** * Executes the whole transaction. * * @return mixed */ public function exec() { return $this->execute(); } /** * Checks the state of the transaction before execution. * * @param mixed $callable Callback for execution. */ private function checkBeforeExecution($callable) { if ($this->checkState(self::STATE_INSIDEBLOCK)) { 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'); } if (!$this->commands->isEmpty()) { $this->discard(); 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'); } } /** * Handles the actual execution of the whole transaction. * * @param mixed $callable Optional callback for execution. * @return array */ public function execute($callable = null) { $this->checkBeforeExecution($callable); $reply = null; $values = array(); $attempts = isset($this->options['retry']) ? (int) $this->options['retry'] : 0; do { if ($callable !== null) { $this->executeTransactionBlock($callable); } if ($this->commands->isEmpty()) { if ($this->checkState(self::STATE_WATCH)) { $this->discard(); } return; } $reply = $this->client->exec(); if ($reply === null) { if ($attempts === 0) { $message = 'The current transaction has been aborted by the server'; throw new AbortedMultiExecException($this, $message); } $this->reset(); if (isset($this->options['on_retry']) && is_callable($this->options['on_retry'])) { call_user_func($this->options['on_retry'], $this, $attempts); } continue; } break; } while ($attempts-- > 0); $exec = $reply instanceof \Iterator ? iterator_to_array($reply) : $reply; $commands = $this->commands; $size = count($exec); if ($size !== count($commands)) { $this->onProtocolError("EXEC returned an unexpected number of replies"); } $clientOpts = $this->client->getOptions(); $useExceptions = isset($clientOpts->exceptions) ? $clientOpts->exceptions : true; for ($i = 0; $i < $size; $i++) { $commandReply = $exec[$i]; if ($commandReply instanceof ResponseErrorInterface && $useExceptions) { $message = $commandReply->getMessage(); throw new ServerException($message); } if ($commandReply instanceof \Iterator) { $commandReply = iterator_to_array($commandReply); } $values[$i] = $commands->dequeue()->parseResponse($commandReply); } return $values; } /** * Passes the current transaction context to a callable block for execution. * * @param mixed $callable Callback. */ protected function executeTransactionBlock($callable) { $blockException = null; $this->flagState(self::STATE_INSIDEBLOCK); try { call_user_func($callable, $this); } catch (CommunicationException $exception) { $blockException = $exception; } catch (ServerException $exception) { $blockException = $exception; } catch (\Exception $exception) { $blockException = $exception; $this->discard(); } $this->unflagState(self::STATE_INSIDEBLOCK); if ($blockException !== null) { throw $blockException; } } /** * Helper method that handles protocol errors encountered inside a transaction. * * @param string $message Error message. */ private function onProtocolError($message) { // Since a MULTI/EXEC block cannot be initialized when using aggregated // connections, we can safely assume that Predis\Client::getConnection() // will always return an instance of Predis\Connection\SingleConnectionInterface. CommunicationException::handle(new ProtocolException( $this->client->getConnection(), $message )); } } predis-0.8.3/package.ini000066400000000000000000000015621211043230100150730ustar00rootroot00000000000000; This file is meant to be used with Onion http://c9s.github.com/Onion/ ; For instructions on how to build a PEAR package of Predis please follow ; the instructions at this URL: ; ; https://github.com/c9s/Onion#a-quick-tutorial-for-building-pear-package ; [package] name = "Predis" desc = "Flexible and feature-complete PHP client library for Redis" homepage = "http://github.com/nrk/predis" license = "MIT" version = "0.8.3" stability = "stable" channel = "pear.nrk.io" author = "Daniele Alessandri \"nrk\" " [require] php = ">= 5.3.2" pearinstaller = "1.4.1" [roles] *.md = doc lib = php [optional phpiredis] hint = "Add support for faster protocol handling with phpiredis" extensions[] = socket extensions[] = phpiredis [optional webdis] hint = "Add support for Webdis" extensions[] = curl extensions[] = phpiredis predis-0.8.3/phpunit.xml.dist000066400000000000000000000022371211043230100161520ustar00rootroot00000000000000 tests/Predis/ ext-phpiredis ext-curl realm-webdis lib/Predis/ predis-0.8.3/phpunit.xml.travisci000066400000000000000000000023701211043230100170310ustar00rootroot00000000000000 tests/Predis/ ext-phpiredis ext-curl realm-webdis lib/Predis/ predis-0.8.3/tests/000077500000000000000000000000001211043230100141355ustar00rootroot00000000000000predis-0.8.3/tests/PHPUnit/000077500000000000000000000000001211043230100154245ustar00rootroot00000000000000predis-0.8.3/tests/PHPUnit/ArrayHasSameValuesConstraint.php000066400000000000000000000024341211043230100237050ustar00rootroot00000000000000 * * 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, $description = '', $returnResult = FALSE) { $description = $description ?: 'Failed asserting that two arrays have the same elements.'; if (count($this->array) !== count($other)) { throw new PHPUnit_Framework_ExpectationFailedException($description); } if (array_diff($this->array, $other)) { throw new PHPUnit_Framework_ExpectationFailedException($description); } return true; } /** * {@inheritdoc} */ public function toString() { return 'two arrays have the same elements.'; } }predis-0.8.3/tests/PHPUnit/CommandTestCase.php000066400000000000000000000122721211043230100211530ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\Client; use Predis\Profile\ServerProfile; use Predis\Profile\ServerProfileInterface; /** * */ abstract class CommandTestCase extends StandardTestCase { /** * Returns the expected command. * * @return CommandInterface|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 CommandInterface */ protected function getCommand() { $command = $this->getExpectedCommand(); return $command instanceof CommandInterface ? $command : new $command(); } /** * Return the server profile used during the tests. * * @return ServerProfileInterface */ 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 PrefixableCommandInterface; } /** * Returns a new command instance with the specified arguments. * * @param ... List of arguments for the command. * @return CommandInterface */ 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 CommandInterface */ 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\Command\CommandInterface', $command); $this->assertEquals($this->getExpectedId(), $command->getId()); } /** * @param string $expectedVersion * @param string $message Optional message. * @throws \RuntimeException when unable to retrieve server info or redis version * @throws \PHPUnit_Framework_SkippedTestError when expected redis version is not met */ protected function markTestSkippedOnRedisVersionBelow($expectedVersion, $message = '') { $client = $this->getClient(); $info = array_change_key_case($client->info()); if (isset($info['server']['redis_version'])) { // Redis >= 2.6 $version = $info['server']['redis_version']; } else if (isset($info['redis_version'])) { // Redis < 2.6 $version = $info['redis_version']; } else { throw new \RuntimeException('Unable to retrieve server info'); } if (version_compare($version, $expectedVersion) <= -1) { $this->markTestSkipped($message ?: "Test requires Redis $expectedVersion, current is $version."); } } /** * @group disconnected */ public function testRawArguments() { $expected = array('1st', '2nd', '3rd', '4th'); $command = $this->getCommand(); $command->setRawArguments($expected); $this->assertSame($expected, $command->getArguments()); } } predis-0.8.3/tests/PHPUnit/ConnectionTestCase.php000066400000000000000000000262021211043230100216720ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\Profile\ServerProfile; /** * @group realm-connection */ abstract class ConnectionTestCase extends StandardTestCase { /** * @group disconnected * @group slow * @expectedException Predis\Connection\ConnectionException */ public function testThrowExceptionWhenUnableToConnect() { $parameters = array('host' => '169.254.10.10', '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->assertSame('PONG', $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->never()) ->method('parseResponse'); $this->assertSame('PONG', $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->never()) ->method('parseResponse'); $connection->writeCommand($cmdPing); $this->assertSame('PONG', $connection->readResponse($cmdPing)); } /** * @group connected */ public function testIsAbleToWriteMultipleCommandsAndReadThemBackForPipelining() { $connection = $this->getConnection($profile); $cmdPing = $this->getMock($profile->getCommandClass('ping'), array('parseResponse')); $cmdPing->expects($this->never()) ->method('parseResponse'); $cmdEcho = $this->getMock($profile->getCommandClass('echo'), array('parseResponse')); $cmdEcho->setArguments(array('ECHOED')); $cmdEcho->expects($this->never()) ->method('parseResponse'); $connection = $this->getConnection(); $connection->writeCommand($cmdPing); $connection->writeCommand($cmdEcho); $this->assertSame('PONG', $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('getArguments')); $cmdPing->expects($this->once()) ->method('getArguments') ->will($this->returnValue(array())); $cmdEcho = $this->getMock($profile->getCommandClass('echo'), array('getArguments')); $cmdEcho->expects($this->once()) ->method('getArguments') ->will($this->returnValue(array('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 */ public function testReadsErrorRepliesAsResponseErrorObjects() { $connection = $this->getConnection($profile, true); $connection->executeCommand($profile->createCommand('set', array('foo', 'bar'))); $connection->writeCommand($profile->createCommand('rpush', array('foo', 'baz'))); $this->assertInstanceOf('Predis\ResponseError', $error = $connection->read()); $this->assertRegExp('/[ERR|WRONGTYPE] 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\Connection\ConnectionException * @expectedExceptionMessage Connection timed out */ public function testThrowsExceptionOnConnectionTimeout() { $connection = $this->getConnection($_, false, array('host' => '169.254.10.10', 'timeout' => 0.5)); $connection->connect(); } /** * @group connected * @group slow * @expectedException Predis\Connection\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()); } predis-0.8.3/tests/PHPUnit/DistributionStrategyTestCase.php000066400000000000000000000031741211043230100240000ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Cluster\Distribution; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ abstract class DistributionStrategyTestCase extends StandardTestCase { /** * Returns a new instance of the tested distributor. * * @return Predis\Cluster\Distribution\DistributionStrategyInterface */ protected abstract function getDistributorInstance(); /** * Returns a list of nodes from the hashring. * * @param DistributionStrategyInterface $ring Hashring instance. * @param int $iterations Number of nodes to fetch. * @return array Nodes from the hashring. */ protected function getNodes(DistributionStrategyInterface $ring, $iterations = 10) { $nodes = array(); for ($i = 0; $i < $iterations; $i++) { $key = $ring->hash($i * $i); $nodes[] = $ring->get($key); } return $nodes; } /** * @group disconnected */ public function testEmptyRingThrowsException() { $this->setExpectedException('Predis\Cluster\Distribution\EmptyRingException'); $ring = $this->getDistributorInstance(); $ring->get('nodekey'); } /** * @group disconnected */ public function testRemoveOnEmptyRingDoesNotThrowException() { $ring = $this->getDistributorInstance(); $this->assertNull($ring->remove('node')); } } predis-0.8.3/tests/PHPUnit/ServerVersionTestCase.php000066400000000000000000000034731211043230100224140ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Profile; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ abstract class ServerVersionTestCase extends StandardTestCase { /** * Returns a new instance of the tested profile. * * @return ServerProfileInterface */ 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 ServerProfileInterface $profile Server profile instance. * @return array */ protected function getCommands(ServerProfileInterface $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); } } predis-0.8.3/tests/Predis/000077500000000000000000000000001211043230100153635ustar00rootroot00000000000000predis-0.8.3/tests/Predis/ClientExceptionTest.php000066400000000000000000000016441211043230100220360ustar00rootroot00000000000000 * * 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); } } predis-0.8.3/tests/Predis/ClientTest.php000066400000000000000000000662051211043230100201630ustar00rootroot00000000000000 * * 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\Connection\ConnectionFactory; use Predis\Connection\MasterSlaveReplication; use Predis\Connection\PredisCluster; use Predis\Profile\ServerProfile; /** * */ class ClientTest extends StandardTestCase { /** * @group disconnected */ public function testConstructorWithoutArguments() { $client = new Client(); $connection = $client->getConnection(); $this->assertInstanceOf('Predis\Connection\SingleConnectionInterface', $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\Connection\SingleConnectionInterface', $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\Connection\SingleConnectionInterface', $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\Connection\ClusterConnectionInterface', $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\Connection\ClusterConnectionInterface', $client->getConnection()); } /** * @group disconnected */ public function testConstructorWithArrayOfConnectionsArgument() { $connection1 = $this->getMock('Predis\Connection\SingleConnectionInterface'); $connection2 = $this->getMock('Predis\Connection\SingleConnectionInterface'); $client = new Client(array($connection1, $connection2)); $this->assertInstanceOf('Predis\Connection\ClusterConnectionInterface', $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\Connection\SingleConnectionInterface', $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->createAggregated($cluster, array('tcp://localhost:7000', 'tcp://localhost:7001')); $client = new Client($cluster); $this->assertInstanceOf('Predis\Connection\ClusterConnectionInterface', $client->getConnection()); $this->assertSame($cluster, $client->getConnection()); } /** * @group disconnected */ public function testConstructorWithReplicationArgument() { $replication = new MasterSlaveReplication(); $factory = new ConnectionFactory(); $factory->createAggregated($replication, array('tcp://host1?alias=master', 'tcp://host2?alias=slave')); $client = new Client($replication); $this->assertInstanceOf('Predis\Connection\ReplicationConnectionInterface', $client->getConnection()); $this->assertSame($replication, $client->getConnection()); } /** * @group disconnected */ public function testConstructorWithCallableArgument() { $connection = $this->getMock('Predis\Connection\ConnectionInterface'); $callable = $this->getMock('stdClass', array('__invoke')); $callable->expects($this->once()) ->method('__invoke') ->with($this->isInstanceOf('Predis\Option\ClientOptions')) ->will($this->returnValue($connection)); $client = new Client($callable); $this->assertSame($connection, $client->getConnection()); } /** * @group disconnected * @expectedException InvalidArgumentException * @expectedExceptionMessage Callable parameters must return instances of Predis\Connection\ConnectionInterface */ public function testConstructorWithCallableArgumentButInvalidReturnType() { $wrongType = $this->getMock('stdClass'); $callable = $this->getMock('stdClass', array('__invoke')); $callable->expects($this->once()) ->method('__invoke') ->with($this->isInstanceOf('Predis\Option\ClientOptions')) ->will($this->returnValue($wrongType)); $client = new Client($callable); } /** * @group disconnected */ public function testConstructorWithNullAndArrayArgument() { $factory = $this->getMock('Predis\Connection\ConnectionFactoryInterface'); $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\Command\Processor\KeyPrefixProcessor', $profile->getProcessor()); $this->assertSame('prefix:', $profile->getProcessor()->getPrefix()); $this->assertSame($factory, $client->getConnectionFactory()); } /** * @group disconnected */ public function testConstructorWithArrayAndOptionReplicationArgument() { $arg1 = array('tcp://host1?alias=master', 'tcp://host2?alias=slave'); $arg2 = array('replication' => true); $client = new Client($arg1, $arg2); $this->assertInstanceOf('Predis\Connection\ReplicationConnectionInterface', $connection = $client->getConnection()); $this->assertSame('host1', $connection->getConnectionById('master')->getParameters()->host); $this->assertSame('host2', $connection->getConnectionById('slave')->getParameters()->host); } /** * @group disconnected */ public function testConnectAndDisconnect() { $connection = $this->getMock('Predis\Connection\ConnectionInterface'); $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\Connection\ConnectionInterface'); $connection->expects($this->once())->method('isConnected'); $client = new Client($connection); $client->isConnected(); } /** * @group disconnected */ public function testQuitIsAliasForDisconnect() { $connection = $this->getMock('Predis\Connection\ConnectionInterface'); $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\Profile\ServerProfileInterface'); $profile->expects($this->once()) ->method('createCommand') ->with('ping', array()) ->will($this->returnValue($ping)); $client = new Client(null, array('profile' => $profile)); $this->assertSame($ping, $client->createCommand('ping', array())); } /** * @group disconnected */ public function testExecuteCommandReturnsParsedReplies() { $profile = ServerProfile::getDefault(); $ping = $profile->createCommand('ping', array()); $hgetall = $profile->createCommand('hgetall', array('metavars', 'foo', 'hoge')); $connection= $this->getMock('Predis\Connection\ConnectionInterface'); $connection->expects($this->at(0)) ->method('executeCommand') ->with($ping) ->will($this->returnValue('PONG')); $connection->expects($this->at(1)) ->method('executeCommand') ->with($hgetall) ->will($this->returnValue(array('foo', 'bar', 'hoge', 'piyo'))); $client = new Client($connection); $this->assertTrue($client->executeCommand($ping)); $this->assertSame(array('foo' => 'bar', 'hoge' => 'piyo'), $client->executeCommand($hgetall)); } /** * @group disconnected * @expectedException Predis\ServerException * @expectedExceptionMessage Operation against a key holding the wrong kind of value */ public function testExecuteCommandThrowsExceptionOnRedisError() { $ping = ServerProfile::getDefault()->createCommand('ping', array()); $expectedResponse = new ResponseError('ERR Operation against a key holding the wrong kind of value'); $connection= $this->getMock('Predis\Connection\ConnectionInterface'); $connection->expects($this->once()) ->method('executeCommand') ->will($this->returnValue($expectedResponse)); $client = new Client($connection); $client->executeCommand($ping); } /** * @group disconnected */ public function testExecuteCommandReturnsErrorResponseOnRedisError() { $ping = ServerProfile::getDefault()->createCommand('ping', array()); $expectedResponse = new ResponseError('ERR Operation against a key holding the wrong kind of value'); $connection= $this->getMock('Predis\Connection\ConnectionInterface'); $connection->expects($this->once()) ->method('executeCommand') ->will($this->returnValue($expectedResponse)); $client = new Client($connection, array('exceptions' => false)); $response = $client->executeCommand($ping); $this->assertSame($response, $expectedResponse); } /** * @group disconnected */ public function testCallingRedisCommandExecutesInstanceOfCommand() { $ping = ServerProfile::getDefault()->createCommand('ping', array()); $connection = $this->getMock('Predis\Connection\ConnectionInterface'); $connection->expects($this->once()) ->method('executeCommand') ->with($this->isInstanceOf('Predis\Command\ConnectionPing')) ->will($this->returnValue('PONG')); $profile = $this->getMock('Predis\Profile\ServerProfileInterface'); $profile->expects($this->once()) ->method('createCommand') ->with('ping', array()) ->will($this->returnValue($ping)); $options = array('profile' => $profile); $client = $this->getMock('Predis\Client', array('createCommand'), array($connection, $options)); $this->assertTrue($client->ping()); } /** * @group disconnected * @expectedException Predis\ServerException * @expectedExceptionMessage Operation against a key holding the wrong kind of value */ public function testCallingRedisCommandThrowsExceptionOnServerError() { $expectedResponse = new ResponseError('ERR Operation against a key holding the wrong kind of value'); $connection = $this->getMock('Predis\Connection\ConnectionInterface'); $connection->expects($this->once()) ->method('executeCommand') ->with($this->isInstanceOf('Predis\Command\ConnectionPing')) ->will($this->returnValue($expectedResponse)); $client = new Client($connection); $client->ping(); } /** * @group disconnected */ public function testCallingRedisCommandReturnsErrorResponseOnRedisError() { $expectedResponse = new ResponseError('ERR Operation against a key holding the wrong kind of value'); $connection = $this->getMock('Predis\Connection\ConnectionInterface'); $connection->expects($this->once()) ->method('executeCommand') ->with($this->isInstanceOf('Predis\Command\ConnectionPing')) ->will($this->returnValue($expectedResponse)); $client = new Client($connection, array('exceptions' => false)); $response = $client->ping(); $this->assertSame($response, $expectedResponse); } /** * @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 testGetConnectionFromAggregatedConnectionWithAlias() { $client = new Client(array('tcp://host1?alias=node01', 'tcp://host2?alias=node02')); $this->assertInstanceOf('Predis\Connection\ClusterConnectionInterface', $cluster = $client->getConnection()); $this->assertInstanceOf('Predis\Connection\SingleConnectionInterface', $node01 = $client->getConnectionById('node01')); $this->assertInstanceOf('Predis\Connection\SingleConnectionInterface', $node02 = $client->getConnectionById('node02')); $this->assertSame('host1', $node01->getParameters()->host); $this->assertSame('host2', $node02->getParameters()->host); } /** * @group disconnected * @expectedException Predis\NotSupportedException * @expectedExceptionMessage Retrieving connections by ID is supported only when using aggregated connections */ public function testGetConnectionByIdWorksOnlyWithAggregatedConnections() { $client = new Client(); $client->getConnectionById('node01'); } /** * @group disconnected */ public function testCreateClientWithConnectionFromAggregatedConnection() { $client = new Client(array('tcp://host1?alias=node01', 'tcp://host2?alias=node02'), array('prefix' => 'pfx:')); $this->assertInstanceOf('Predis\Connection\ClusterConnectionInterface', $cluster = $client->getConnection()); $this->assertInstanceOf('Predis\Connection\SingleConnectionInterface', $node01 = $client->getConnectionById('node01')); $this->assertInstanceOf('Predis\Connection\SingleConnectionInterface', $node02 = $client->getConnectionById('node02')); $clientNode02 = $client->getClientFor('node02'); $this->assertInstanceOf('Predis\Client', $clientNode02); $this->assertSame($node02, $clientNode02->getConnection()); $this->assertSame($client->getOptions(), $clientNode02->getOptions()); } /** * @group disconnected */ public function testGetClientForReturnsInstanceOfSubclass() { $nodes = array('tcp://host1?alias=node01', 'tcp://host2?alias=node02'); $client = $this->getMock('Predis\Client', array('dummy'), array($nodes), 'SubclassedClient'); $this->assertInstanceOf('SubclassedClient', $client->getClientFor('node02')); } /** * @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\PipelineExecutorInterface'); $options = array('executor' => $executor); $this->assertInstanceOf('Predis\Pipeline\PipelineContext', $pipeline = $client->pipeline($options)); $this->assertSame($executor, $pipeline->getExecutor()); $options = array('executor' => function ($client, $options) use ($executor) { return $executor; }); $this->assertInstanceOf('Predis\Pipeline\PipelineContext', $pipeline = $client->pipeline($options)); $this->assertSame($executor, $pipeline->getExecutor()); } /** * @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\PipelineExecutorInterface'); $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\Connection\SingleConnectionInterface'); $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\Connection\SingleConnectionInterface'); $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\Connection\SingleConnectionInterface'); $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\Connection\SingleConnectionInterface'); $client = new Client($connection); $this->assertInstanceOf('Predis\Monitor\MonitorContext', $monitor = $client->monitor()); } /** * @group disconnected */ public function testClientResendScriptedCommandUsingEvalOnNoScriptErrors() { $command = $this->getMockForAbstractClass('Predis\Command\ScriptedCommand', array(), '', true, true, true, array('parseResponse')); $command->expects($this->once()) ->method('getScript') ->will($this->returnValue('return redis.call(\'exists\', KEYS[1])')); $command->expects($this->once()) ->method('parseResponse') ->with('OK') ->will($this->returnValue(true)); $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $connection->expects($this->at(0)) ->method('executeCommand') ->with($command) ->will($this->returnValue(new ResponseError('NOSCRIPT'))); $connection->expects($this->at(1)) ->method('executeCommand') ->with($this->isInstanceOf('Predis\Command\ServerEval')) ->will($this->returnValue('OK')); $client = new Client($connection); $this->assertTrue($client->executeCommand($command)); } // ******************************************************************** // // ---- 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; } } predis-0.8.3/tests/Predis/Cluster/000077500000000000000000000000001211043230100170045ustar00rootroot00000000000000predis-0.8.3/tests/Predis/Cluster/Distribution/000077500000000000000000000000001211043230100214635ustar00rootroot00000000000000predis-0.8.3/tests/Predis/Cluster/Distribution/EmptyRingExceptionTest.php000066400000000000000000000013141211043230100266300ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Cluster\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\Cluster\Distribution\EmptyRingException', $message); throw new EmptyRingException($message); } } predis-0.8.3/tests/Predis/Cluster/Distribution/HashRingTest.php000066400000000000000000000073311211043230100245430ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Cluster\Distribution; /** * @todo To be improved. */ class HashRingTest extends DistributionStrategyTestCase { /** * {@inheritdoc} */ public function getDistributorInstance() { return new HashRing(); } /** * @group disconnected */ public function testHash() { $ring = $this->getDistributorInstance(); $this->assertEquals(crc32('foobar'), $ring->hash('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); } /** * @todo This tests should be moved in Predis\Cluster\Distribution\DistributionStrategyTestCase * @group disconnected */ public function testCallbackToGetNodeHash() { $node = '127.0.0.1:7000'; $replicas = HashRing::DEFAULT_REPLICAS; $callable = $this->getMock('stdClass', array('__invoke')); $callable->expects($this->once()) ->method('__invoke') ->with($node) ->will($this->returnValue($node)); $ring = new HashRing($replicas, $callable); $ring->add($node); $this->getNodes($ring); } } predis-0.8.3/tests/Predis/Cluster/Distribution/KetamaPureRingTest.php000066400000000000000000000073401211043230100257160ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Cluster\Distribution; /** * @todo To be improved. */ class KetamaPureRingTest extends DistributionStrategyTestCase { /** * {@inheritdoc} */ public function getDistributorInstance() { return new KetamaPureRing(); } /** * @group disconnected */ public function testHash() { $ring = $this->getDistributorInstance(); list(, $hash) = unpack('V', md5('foobar', true)); $this->assertEquals($hash, $ring->hash('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); } /** * @todo This tests should be moved in Predis\Cluster\Distribution\DistributionStrategyTestCase * @group disconnected */ public function testCallbackToGetNodeHash() { $node = '127.0.0.1:7000'; $callable = $this->getMock('stdClass', array('__invoke')); $callable->expects($this->once()) ->method('__invoke') ->with($node) ->will($this->returnValue($node)); $ring = new KetamaPureRing($callable); $ring->add($node); $this->getNodes($ring); } } predis-0.8.3/tests/Predis/Cluster/PredisClusterHashStrategyTest.php000066400000000000000000000324571211043230100255070ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Cluster; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\Cluster\Distribution\HashRing; use Predis\Profile\ServerProfile; /** * */ class PredisClusterHashStrategyTest extends StandardTestCase { /** * @group disconnected */ public function testSupportsKeyTags() { // NOTE: 32 and 64 bits PHP runtimes can produce different hash values. $expected = PHP_INT_SIZE == 4 ? -1938594527 : 2356372769; $strategy = $this->getHashStrategy(); $this->assertSame($expected, $strategy->getKeyHash('{foo}')); $this->assertSame($expected, $strategy->getKeyHash('{foo}:bar')); $this->assertSame($expected, $strategy->getKeyHash('{foo}:baz')); $this->assertSame($expected, $strategy->getKeyHash('bar:{foo}:bar')); $this->assertSame(0, $strategy->getKeyHash('')); $this->assertSame(0, $strategy->getKeyHash('{}')); } /** * @group disconnected */ public function testSupportedCommands() { $strategy = $this->getHashStrategy(); $this->assertSame($this->getExpectedCommands(), $strategy->getSupportedCommands()); } /** * @group disconnected */ public function testReturnsNullOnUnsupportedCommand() { $strategy = $this->getHashStrategy(); $command = ServerProfile::getDevelopment()->createCommand('ping'); $this->assertNull($strategy->getHash($command)); } /** * @group disconnected */ public function testFirstKeyCommands() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $arguments = array('key'); foreach ($this->getExpectedCommands('keys-first') as $commandID) { $command = $profile->createCommand($commandID, $arguments); $this->assertNotNull($strategy->getHash($command), $commandID); } } /** * @group disconnected */ public function testAllKeysCommands() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $arguments = array('{key}:1', '{key}:2', '{key}:3', '{key}:4'); foreach ($this->getExpectedCommands('keys-all') as $commandID) { $command = $profile->createCommand($commandID, $arguments); $this->assertNotNull($strategy->getHash($command), $commandID); } } /** * @group disconnected */ public function testInterleavedKeysCommands() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $arguments = array('{key}:1', 'value1', '{key}:2', 'value2'); foreach ($this->getExpectedCommands('keys-interleaved') as $commandID) { $command = $profile->createCommand($commandID, $arguments); $this->assertNotNull($strategy->getHash($command), $commandID); } } /** * @group disconnected */ public function testKeysForBlockingListCommands() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $arguments = array('{key}:1', '{key}:2', 10); foreach ($this->getExpectedCommands('keys-blockinglist') as $commandID) { $command = $profile->createCommand($commandID, $arguments); $this->assertNotNull($strategy->getHash($command), $commandID); } } /** * @group disconnected */ public function testKeysForZsetAggregationCommands() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $arguments = array('{key}:destination', 2, '{key}:1', '{key}:1', array('aggregate' => 'SUM')); foreach ($this->getExpectedCommands('keys-zaggregated') as $commandID) { $command = $profile->createCommand($commandID, $arguments); $this->assertNotNull($strategy->getHash($command), $commandID); } } /** * @group disconnected */ public function testKeysForBitOpCommand() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $arguments = array('AND', '{key}:destination', '{key}:src:1', '{key}:src:2'); foreach ($this->getExpectedCommands('keys-bitop') as $commandID) { $command = $profile->createCommand($commandID, $arguments); $this->assertNotNull($strategy->getHash($command), $commandID); } } /** * @group disconnected */ public function testKeysForScriptCommand() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $arguments = array('%SCRIPT%', 2, '{key}:1', '{key}:2', 'value1', 'value2'); foreach ($this->getExpectedCommands('keys-script') as $commandID) { $command = $profile->createCommand($commandID, $arguments); $this->assertNotNull($strategy->getHash($command), $commandID); } } /** * @group disconnected */ public function testKeysForScriptedCommand() { $strategy = $this->getHashStrategy(); $arguments = array('{key}:1', '{key}:2', 'value1', 'value2'); $command = $this->getMock('Predis\Command\ScriptedCommand', array('getScript', 'getKeysCount')); $command->expects($this->once()) ->method('getScript') ->will($this->returnValue('return true')); $command->expects($this->exactly(2)) ->method('getKeysCount') ->will($this->returnValue(2)); $command->setArguments($arguments); $this->assertNotNull($strategy->getHash($command), "Scripted Command [{$command->getId()}]"); } /** * @group disconnected */ public function testUnsettingCommandHandler() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $strategy->setCommandHandler('set'); $strategy->setCommandHandler('get', null); $command = $profile->createCommand('set', array('key', 'value')); $this->assertNull($strategy->getHash($command)); $command = $profile->createCommand('get', array('key')); $this->assertNull($strategy->getHash($command)); } /** * @group disconnected */ public function testSettingCustomCommandHandler() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $callable = $this->getMock('stdClass', array('__invoke')); $callable->expects($this->once()) ->method('__invoke') ->with($this->isInstanceOf('Predis\Command\CommandInterface')) ->will($this->returnValue('key')); $strategy->setCommandHandler('get', $callable); $command = $profile->createCommand('get', array('key')); $this->assertNotNull($strategy->getHash($command)); } // ******************************************************************** // // ---- HELPER METHODS ------------------------------------------------ // // ******************************************************************** // /** * Creates the default hash strategy object. * * @return CommandHashStrategyInterface */ protected function getHashStrategy() { $distributor = new HashRing(); $hashGenerator = $distributor->getHashGenerator(); $strategy = new PredisClusterHashStrategy($hashGenerator); return $strategy; } /** * Returns the list of expected supported commands. * * @param string $type Optional type of command (based on its keys) * @return array */ protected function getExpectedCommands($type = null) { $commands = array( /* commands operating on the key space */ 'EXISTS' => 'keys-first', 'DEL' => 'keys-all', 'TYPE' => 'keys-first', 'EXPIRE' => 'keys-first', 'EXPIREAT' => 'keys-first', 'PERSIST' => 'keys-first', 'PEXPIRE' => 'keys-first', 'PEXPIREAT' => 'keys-first', 'TTL' => 'keys-first', 'PTTL' => 'keys-first', 'SORT' => 'keys-first', // TODO /* commands operating on string values */ 'APPEND' => 'keys-first', 'DECR' => 'keys-first', 'DECRBY' => 'keys-first', 'GET' => 'keys-first', 'GETBIT' => 'keys-first', 'MGET' => 'keys-all', 'SET' => 'keys-first', 'GETRANGE' => 'keys-first', 'GETSET' => 'keys-first', 'INCR' => 'keys-first', 'INCRBY' => 'keys-first', 'SETBIT' => 'keys-first', 'SETEX' => 'keys-first', 'MSET' => 'keys-interleaved', 'MSETNX' => 'keys-interleaved', 'SETNX' => 'keys-first', 'SETRANGE' => 'keys-first', 'STRLEN' => 'keys-first', 'SUBSTR' => 'keys-first', 'BITOP' => 'keys-bitop', 'BITCOUNT' => 'keys-first', /* commands operating on lists */ 'LINSERT' => 'keys-first', 'LINDEX' => 'keys-first', 'LLEN' => 'keys-first', 'LPOP' => 'keys-first', 'RPOP' => 'keys-first', 'RPOPLPUSH' => 'keys-all', 'BLPOP' => 'keys-blockinglist', 'BRPOP' => 'keys-blockinglist', 'BRPOPLPUSH' => 'keys-blockinglist', 'LPUSH' => 'keys-first', 'LPUSHX' => 'keys-first', 'RPUSH' => 'keys-first', 'RPUSHX' => 'keys-first', 'LRANGE' => 'keys-first', 'LREM' => 'keys-first', 'LSET' => 'keys-first', 'LTRIM' => 'keys-first', /* commands operating on sets */ 'SADD' => 'keys-first', 'SCARD' => 'keys-first', 'SDIFF' => 'keys-all', 'SDIFFSTORE' => 'keys-all', 'SINTER' => 'keys-all', 'SINTERSTORE' => 'keys-all', 'SUNION' => 'keys-all', 'SUNIONSTORE' => 'keys-all', 'SISMEMBER' => 'keys-first', 'SMEMBERS' => 'keys-first', 'SPOP' => 'keys-first', 'SRANDMEMBER' => 'keys-first', 'SREM' => 'keys-first', /* commands operating on sorted sets */ 'ZADD' => 'keys-first', 'ZCARD' => 'keys-first', 'ZCOUNT' => 'keys-first', 'ZINCRBY' => 'keys-first', 'ZINTERSTORE' => 'keys-zaggregated', 'ZRANGE' => 'keys-first', 'ZRANGEBYSCORE' => 'keys-first', 'ZRANK' => 'keys-first', 'ZREM' => 'keys-first', 'ZREMRANGEBYRANK' => 'keys-first', 'ZREMRANGEBYSCORE' => 'keys-first', 'ZREVRANGE' => 'keys-first', 'ZREVRANGEBYSCORE' => 'keys-first', 'ZREVRANK' => 'keys-first', 'ZSCORE' => 'keys-first', 'ZUNIONSTORE' => 'keys-zaggregated', /* commands operating on hashes */ 'HDEL' => 'keys-first', 'HEXISTS' => 'keys-first', 'HGET' => 'keys-first', 'HGETALL' => 'keys-first', 'HMGET' => 'keys-first', 'HINCRBY' => 'keys-first', 'HINCRBYFLOAT' => 'keys-first', 'HKEYS' => 'keys-first', 'HLEN' => 'keys-first', 'HSET' => 'keys-first', 'HSETNX' => 'keys-first', 'HVALS' => 'keys-first', /* scripting */ 'EVAL' => 'keys-script', 'EVALSHA' => 'keys-script', ); if (isset($type)) { $commands = array_filter($commands, function ($expectedType) use ($type) { return $expectedType === $type; }); } return array_keys($commands); } } predis-0.8.3/tests/Predis/Cluster/RedisClusterHashStrategyTest.php000066400000000000000000000312161211043230100253170ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Cluster; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\Profile\ServerProfile; /** * */ class RedisClusterHashStrategyTest extends StandardTestCase { /** * @group disconnected */ public function testDoesNotSupportKeyTags() { $strategy = $this->getHashStrategy(); $this->assertSame(35910, $strategy->getKeyHash('{foo}')); $this->assertSame(60032, $strategy->getKeyHash('{foo}:bar')); $this->assertSame(27528, $strategy->getKeyHash('{foo}:baz')); $this->assertSame(34064, $strategy->getKeyHash('bar:{foo}:bar')); } /** * @group disconnected */ public function testSupportedCommands() { $strategy = $this->getHashStrategy(); $this->assertSame($this->getExpectedCommands(), $strategy->getSupportedCommands()); } /** * @group disconnected */ public function testReturnsNullOnUnsupportedCommand() { $strategy = $this->getHashStrategy(); $command = ServerProfile::getDevelopment()->createCommand('ping'); $this->assertNull($strategy->getHash($command)); } /** * @group disconnected */ public function testFirstKeyCommands() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $arguments = array('key'); foreach ($this->getExpectedCommands('keys-first') as $commandID) { $command = $profile->createCommand($commandID, $arguments); $this->assertNotNull($strategy->getHash($command), $commandID); } } /** * @group disconnected */ public function testAllKeysCommandsWithOneKey() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $arguments = array('key'); foreach ($this->getExpectedCommands('keys-all') as $commandID) { $command = $profile->createCommand($commandID, $arguments); $this->assertNotNull($strategy->getHash($command), $commandID); } } /** * @group disconnected */ public function testAllKeysCommandsWithMoreKeys() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $arguments = array('key1', 'key2'); foreach ($this->getExpectedCommands('keys-all') as $commandID) { $command = $profile->createCommand($commandID, $arguments); $this->assertNull($strategy->getHash($command), $commandID); } } /** * @group disconnected */ public function testInterleavedKeysCommandsWithOneKey() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $arguments = array('key:1', 'value1'); foreach ($this->getExpectedCommands('keys-interleaved') as $commandID) { $command = $profile->createCommand($commandID, $arguments); $this->assertNotNull($strategy->getHash($command), $commandID); } } /** * @group disconnected */ public function testInterleavedKeysCommandsWithMoreKeys() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $arguments = array('key:1', 'value1', 'key:2', 'value2'); foreach ($this->getExpectedCommands('keys-interleaved') as $commandID) { $command = $profile->createCommand($commandID, $arguments); $this->assertNull($strategy->getHash($command), $commandID); } } /** * @group disconnected */ public function testKeysForBlockingListCommandsWithOneKey() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $arguments = array('key:1', 10); foreach ($this->getExpectedCommands('keys-blockinglist') as $commandID) { $command = $profile->createCommand($commandID, $arguments); $this->assertNotNull($strategy->getHash($command), $commandID); } } /** * @group disconnected */ public function testKeysForBlockingListCommandsWithMoreKeys() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $arguments = array('key:1', 'key:2', 10); foreach ($this->getExpectedCommands('keys-blockinglist') as $commandID) { $command = $profile->createCommand($commandID, $arguments); $this->assertNull($strategy->getHash($command), $commandID); } } /** * @group disconnected */ public function testKeysForScriptCommand() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $arguments = array('%SCRIPT%', 1, 'key:1', 'value1'); foreach ($this->getExpectedCommands('keys-script') as $commandID) { $command = $profile->createCommand($commandID, $arguments); $this->assertNotNull($strategy->getHash($command), $commandID); } } /** * @group disconnected */ public function testKeysForScriptedCommand() { $strategy = $this->getHashStrategy(); $arguments = array('key:1', 'value1'); $command = $this->getMock('Predis\Command\ScriptedCommand', array('getScript', 'getKeysCount')); $command->expects($this->once()) ->method('getScript') ->will($this->returnValue('return true')); $command->expects($this->exactly(1)) ->method('getKeysCount') ->will($this->returnValue(1)); $command->setArguments($arguments); $this->assertNotNull($strategy->getHash($command), "Scripted Command [{$command->getId()}]"); } /** * @group disconnected */ public function testUnsettingCommandHandler() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $strategy->setCommandHandler('set'); $strategy->setCommandHandler('get', null); $command = $profile->createCommand('set', array('key', 'value')); $this->assertNull($strategy->getHash($command)); $command = $profile->createCommand('get', array('key')); $this->assertNull($strategy->getHash($command)); } /** * @group disconnected */ public function testSettingCustomCommandHandler() { $strategy = $this->getHashStrategy(); $profile = ServerProfile::getDevelopment(); $callable = $this->getMock('stdClass', array('__invoke')); $callable->expects($this->once()) ->method('__invoke') ->with($this->isInstanceOf('Predis\Command\CommandInterface')) ->will($this->returnValue('key')); $strategy->setCommandHandler('get', $callable); $command = $profile->createCommand('get', array('key')); $this->assertNotNull($strategy->getHash($command)); } // ******************************************************************** // // ---- HELPER METHODS ------------------------------------------------ // // ******************************************************************** // /** * Creates the default hash strategy object. * * @return CommandHashStrategyInterface */ protected function getHashStrategy() { $strategy = new RedisClusterHashStrategy(); return $strategy; } /** * Returns the list of expected supported commands. * * @param string $type Optional type of command (based on its keys) * @return array */ protected function getExpectedCommands($type = null) { $commands = array( /* commands operating on the key space */ 'EXISTS' => 'keys-first', 'DEL' => 'keys-all', 'TYPE' => 'keys-first', 'EXPIRE' => 'keys-first', 'EXPIREAT' => 'keys-first', 'PERSIST' => 'keys-first', 'PEXPIRE' => 'keys-first', 'PEXPIREAT' => 'keys-first', 'TTL' => 'keys-first', 'PTTL' => 'keys-first', 'SORT' => 'keys-first', // TODO /* commands operating on string values */ 'APPEND' => 'keys-first', 'DECR' => 'keys-first', 'DECRBY' => 'keys-first', 'GET' => 'keys-first', 'GETBIT' => 'keys-first', 'MGET' => 'keys-all', 'SET' => 'keys-first', 'GETRANGE' => 'keys-first', 'GETSET' => 'keys-first', 'INCR' => 'keys-first', 'INCRBY' => 'keys-first', 'SETBIT' => 'keys-first', 'SETEX' => 'keys-first', 'MSET' => 'keys-interleaved', 'MSETNX' => 'keys-interleaved', 'SETNX' => 'keys-first', 'SETRANGE' => 'keys-first', 'STRLEN' => 'keys-first', 'SUBSTR' => 'keys-first', 'BITCOUNT' => 'keys-first', /* commands operating on lists */ 'LINSERT' => 'keys-first', 'LINDEX' => 'keys-first', 'LLEN' => 'keys-first', 'LPOP' => 'keys-first', 'RPOP' => 'keys-first', 'BLPOP' => 'keys-blockinglist', 'BRPOP' => 'keys-blockinglist', 'LPUSH' => 'keys-first', 'LPUSHX' => 'keys-first', 'RPUSH' => 'keys-first', 'RPUSHX' => 'keys-first', 'LRANGE' => 'keys-first', 'LREM' => 'keys-first', 'LSET' => 'keys-first', 'LTRIM' => 'keys-first', /* commands operating on sets */ 'SADD' => 'keys-first', 'SCARD' => 'keys-first', 'SISMEMBER' => 'keys-first', 'SMEMBERS' => 'keys-first', 'SPOP' => 'keys-first', 'SRANDMEMBER' => 'keys-first', 'SREM' => 'keys-first', /* commands operating on sorted sets */ 'ZADD' => 'keys-first', 'ZCARD' => 'keys-first', 'ZCOUNT' => 'keys-first', 'ZINCRBY' => 'keys-first', 'ZRANGE' => 'keys-first', 'ZRANGEBYSCORE' => 'keys-first', 'ZRANK' => 'keys-first', 'ZREM' => 'keys-first', 'ZREMRANGEBYRANK' => 'keys-first', 'ZREMRANGEBYSCORE' => 'keys-first', 'ZREVRANGE' => 'keys-first', 'ZREVRANGEBYSCORE' => 'keys-first', 'ZREVRANK' => 'keys-first', 'ZSCORE' => 'keys-first', /* commands operating on hashes */ 'HDEL' => 'keys-first', 'HEXISTS' => 'keys-first', 'HGET' => 'keys-first', 'HGETALL' => 'keys-first', 'HMGET' => 'keys-first', 'HINCRBY' => 'keys-first', 'HINCRBYFLOAT' => 'keys-first', 'HKEYS' => 'keys-first', 'HLEN' => 'keys-first', 'HSET' => 'keys-first', 'HSETNX' => 'keys-first', 'HVALS' => 'keys-first', /* scripting */ 'EVAL' => 'keys-script', 'EVALSHA' => 'keys-script', ); if (isset($type)) { $commands = array_filter($commands, function ($expectedType) use ($type) { return $expectedType === $type; }); } return array_keys($commands); } } predis-0.8.3/tests/Predis/Command/000077500000000000000000000000001211043230100167415ustar00rootroot00000000000000predis-0.8.3/tests/Predis/Command/CommandTest.php000066400000000000000000000117211211043230100216720ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class CommandTest extends StandardTestCase { /** * @group disconnected */ public function testImplementsCorrectInterface() { $command = $this->getMockForAbstractClass('Predis\Command\AbstractCommand'); $this->assertInstanceOf('Predis\Command\CommandInterface', $command); } /** * @group disconnected */ public function testGetEmptyArguments() { $command = $this->getMockForAbstractClass('Predis\Command\AbstractCommand'); $this->assertEmpty($command->getArguments()); } /** * @group disconnected */ public function testSetRawArguments() { $arguments = array('1st', '2nd', '3rd'); $command = $this->getMockForAbstractClass('Predis\Command\AbstractCommand'); $command->setRawArguments($arguments); $this->assertEquals($arguments, $command->getArguments()); } /** * @group disconnected * * @todo Since AbstractCommand::filterArguments is protected we cannot set an expectation * for it when AbstractCommand::setArguments() is invoked. I wonder how we can do that. */ public function testSetArguments() { $arguments = array('1st', '2nd', '3rd'); $command = $this->getMockForAbstractClass('Predis\Command\AbstractCommand'); $command->setArguments($arguments); $this->assertEquals($arguments, $command->getArguments()); } /** * @group disconnected */ public function testGetArgumentAtIndex() { $arguments = array('1st', '2nd', '3rd'); $command = $this->getMockForAbstractClass('Predis\Command\AbstractCommand'); $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\Command\AbstractCommand'); $this->assertEquals($response, $command->parseResponse($response)); } /** * @group disconnected */ public function testSetAndGetHash() { $hash = "key-hash"; $command = $this->getMockForAbstractClass('Predis\Command\AbstractCommand'); $command->setRawArguments(array('key')); $this->assertNull($command->getHash()); $command->setHash($hash); $this->assertSame($hash, $command->getHash()); } /** * @group disconnected */ public function testToString() { $expected = 'SET key value'; $arguments = array('key', 'value'); $command = $this->getMockForAbstractClass('Predis\Command\AbstractCommand'); $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\Command\AbstractCommand'); $command->expects($this->once())->method('getId')->will($this->returnValue('SET')); $command->setRawArguments($arguments); $this->assertEquals($expected, (string) $command); } /** * @group disconnected */ public function testNormalizeArguments() { $arguments = array('arg1', 'arg2', 'arg3', 'arg4'); $this->assertSame($arguments, AbstractCommand::normalizeArguments($arguments)); $this->assertSame($arguments, AbstractCommand::normalizeArguments(array($arguments))); $arguments = array(array(), array()); $this->assertSame($arguments, AbstractCommand::normalizeArguments($arguments)); $arguments = array(new \stdClass()); $this->assertSame($arguments, AbstractCommand::normalizeArguments($arguments)); } /** * @group disconnected */ public function testNormalizeVariadic() { $arguments = array('key', 'value1', 'value2', 'value3'); $this->assertSame($arguments, AbstractCommand::normalizeVariadic($arguments)); $this->assertSame($arguments, AbstractCommand::normalizeVariadic(array('key', array('value1', 'value2', 'value3')))); $arguments = array(new \stdClass()); $this->assertSame($arguments, AbstractCommand::normalizeVariadic($arguments)); } } predis-0.8.3/tests/Predis/Command/ConnectionAuthTest.php000066400000000000000000000023571211043230100232420ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-connection */ class ConnectionAuthTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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)); } } predis-0.8.3/tests/Predis/Command/ConnectionEchoTest.php000066400000000000000000000027571211043230100232230ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-connection */ class ConnectionEchoTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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)); } } predis-0.8.3/tests/Predis/Command/ConnectionPingTest.php000066400000000000000000000025241211043230100232320ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-connection */ class ConnectionPingTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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()); } } predis-0.8.3/tests/Predis/Command/ConnectionQuitTest.php000066400000000000000000000026331211043230100232600ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-connection */ class ConnectionQuitTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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)); } } predis-0.8.3/tests/Predis/Command/ConnectionSelectTest.php000066400000000000000000000033671211043230100235620ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-connection */ class ConnectionSelectTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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); } } predis-0.8.3/tests/Predis/Command/HashDeleteTest.php000066400000000000000000000053551211043230100223300ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-hash */ class HashDeleteTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->hdel('foo', 'bar'); } } predis-0.8.3/tests/Predis/Command/HashExistsTest.php000066400000000000000000000045121211043230100223770ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-hash */ class HashExistsTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->hexists('foo', 'bar'); } } predis-0.8.3/tests/Predis/Command/HashGetAllTest.php000066400000000000000000000046071211043230100222750ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-hash */ class HashGetAllTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->hgetall('foo'); } } predis-0.8.3/tests/Predis/Command/HashGetMultipleTest.php000066400000000000000000000060641211043230100233570ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-hash */ class HashGetMultipleTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->hmget('foo', 'bar'); } } predis-0.8.3/tests/Predis/Command/HashGetTest.php000066400000000000000000000043571211043230100216460ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-hash */ class HashGetTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->hget('foo', 'bar'); } } predis-0.8.3/tests/Predis/Command/HashIncrementByFloatTest.php000066400000000000000000000063661211043230100243360ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-hash */ class HashIncrementByFloatTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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); } } predis-0.8.3/tests/Predis/Command/HashIncrementByTest.php000066400000000000000000000061761211043230100233470ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-hash */ class HashIncrementByTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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); } } predis-0.8.3/tests/Predis/Command/HashKeysTest.php000066400000000000000000000044351211043230100220370ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-hash */ class HashKeysTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->hkeys('foo'); } } predis-0.8.3/tests/Predis/Command/HashLengthTest.php000066400000000000000000000041701211043230100223410ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-hash */ class HashLengthTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->hlen('foo'); } } predis-0.8.3/tests/Predis/Command/HashSetMultipleTest.php000066400000000000000000000063751211043230100234000ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-hash */ class HashSetMultipleTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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'); } } predis-0.8.3/tests/Predis/Command/HashSetPreserveTest.php000066400000000000000000000046761211043230100234020ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-hash */ class HashSetPreserveTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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'); } } predis-0.8.3/tests/Predis/Command/HashSetTest.php000066400000000000000000000045201211043230100216520ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-hash */ class HashSetTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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'); } } predis-0.8.3/tests/Predis/Command/HashValuesTest.php000066400000000000000000000044431211043230100223620ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-hash */ class HashValuesTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->hvals('foo'); } } predis-0.8.3/tests/Predis/Command/KeyDeleteTest.php000066400000000000000000000046571211043230100222010ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-key */ class KeyDeleteTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); } } predis-0.8.3/tests/Predis/Command/KeyExistsTest.php000066400000000000000000000037171211043230100222520ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-key */ class KeyExistsTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); } } predis-0.8.3/tests/Predis/Command/KeyExpireAtTest.php000066400000000000000000000047601211043230100225130ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-key */ class KeyExpireAtTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); } } predis-0.8.3/tests/Predis/Command/KeyExpireTest.php000066400000000000000000000053451211043230100222260ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-key */ class KeyExpireTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); } } predis-0.8.3/tests/Predis/Command/KeyKeysTest.php000066400000000000000000000043261211043230100217030ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-key */ class KeyKeysTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); } } predis-0.8.3/tests/Predis/Command/KeyKeysV12xTest.php000066400000000000000000000033241211043230100223610ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; 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\Command\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()); } } predis-0.8.3/tests/Predis/Command/KeyMoveTest.php000066400000000000000000000045551211043230100217020ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-key */ class KeyMoveTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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); } } predis-0.8.3/tests/Predis/Command/KeyPersistTest.php000066400000000000000000000044241211043230100224200ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-key */ class KeyPersistTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); } } predis-0.8.3/tests/Predis/Command/KeyPreciseExpireAtTest.php000066400000000000000000000045141211043230100240230ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-key */ class KeyPreciseExpireAtTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); } } predis-0.8.3/tests/Predis/Command/KeyPreciseExpireTest.php000066400000000000000000000055151211043230100235400ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-key */ class KeyPreciseExpireTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); } } predis-0.8.3/tests/Predis/Command/KeyPreciseTimeToLiveTest.php000066400000000000000000000046201211043230100243210ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-key */ class KeyPreciseTimeToLiveTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 testReturnsLessThanZeroOnNonExpiringKeys() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $this->assertSame(-1, $redis->pttl('foo')); } /** * @group connected * @todo PTTL changed in Redis >= 2.8 to return -2 on non existing keys, we * should handle this case with a better solution than the current one. */ public function testReturnsLessThanZeroOnNonExistingKeys() { $redis = $this->getClient(); $this->assertLessThanOrEqual(-1, $redis->pttl('foo')); } } predis-0.8.3/tests/Predis/Command/KeyRandomTest.php000066400000000000000000000033121211043230100222020ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-key */ class KeyRandomTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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()); } } predis-0.8.3/tests/Predis/Command/KeyRenamePreserveTest.php000066400000000000000000000043251211043230100237120ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-key */ class KeyRenamePreserveTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); } } predis-0.8.3/tests/Predis/Command/KeyRenameTest.php000066400000000000000000000041561211043230100222000ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-key */ class KeyRenameTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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'); } } predis-0.8.3/tests/Predis/Command/KeySortTest.php000066400000000000000000000154661211043230100217260ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-key */ class KeySortTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->sort('foo'); } } predis-0.8.3/tests/Predis/Command/KeyTimeToLiveTest.php000066400000000000000000000045571211043230100230170ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-key */ class KeyTimeToLiveTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 testReturnsLessThanZeroOnNonExpiringKeys() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $this->assertSame(-1, $redis->ttl('foo')); } /** * @group connected * @todo TTL changed in Redis >= 2.8 to return -2 on non existing keys, we * should handle this case with a better solution than the current one. */ public function testReturnsLessThanZeroOnNonExistingKeys() { $redis = $this->getClient(); $this->assertLessThanOrEqual(-1, $redis->ttl('foo')); } } predis-0.8.3/tests/Predis/Command/KeyTypeTest.php000066400000000000000000000043161211043230100217100ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-key */ class KeyTypeTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); } } predis-0.8.3/tests/Predis/Command/ListIndexTest.php000066400000000000000000000052071211043230100222210ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-list */ class ListIndexTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->lindex('foo', 0); } } predis-0.8.3/tests/Predis/Command/ListInsertTest.php000066400000000000000000000057201211043230100224160ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-list */ class ListInsertTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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'); } } predis-0.8.3/tests/Predis/Command/ListLengthTest.php000066400000000000000000000045311211043230100223720ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-list */ class ListLengthTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->llen('foo'); } } predis-0.8.3/tests/Predis/Command/ListPopFirstBlockingTest.php000066400000000000000000000043111211043230100243640ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; 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\Command\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()); } } predis-0.8.3/tests/Predis/Command/ListPopFirstTest.php000066400000000000000000000046141211043230100227210ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-list */ class ListPopFirstTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->lpop('foo'); } } predis-0.8.3/tests/Predis/Command/ListPopLastBlockingTest.php000066400000000000000000000043071211043230100242050ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; 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\Command\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()); } } predis-0.8.3/tests/Predis/Command/ListPopLastPushHeadBlockingTest.php000066400000000000000000000034171211043230100256300ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; 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\Command\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()); } } predis-0.8.3/tests/Predis/Command/ListPopLastPushHeadTest.php000066400000000000000000000075661211043230100241700ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-list */ class ListPopLastPushHeadTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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 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'); } } predis-0.8.3/tests/Predis/Command/ListPopLastTest.php000066400000000000000000000046111211043230100225320ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-list */ class ListPopLastTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->rpop('foo'); } } predis-0.8.3/tests/Predis/Command/ListPushHeadTest.php000066400000000000000000000054201211043230100226500ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-list */ class ListPushHeadTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('metavars', 'foo'); $redis->lpush('metavars', 'hoge'); } } predis-0.8.3/tests/Predis/Command/ListPushHeadXTest.php000066400000000000000000000050341211043230100230010ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-list */ class ListPushHeadXTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('metavars', 'foo'); $redis->lpushx('metavars', 'hoge'); } } predis-0.8.3/tests/Predis/Command/ListPushTailTest.php000066400000000000000000000054201211043230100227000ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-list */ class ListPushTailTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('metavars', 'foo'); $redis->rpush('metavars', 'hoge'); } } predis-0.8.3/tests/Predis/Command/ListPushTailXTest.php000066400000000000000000000050341211043230100230310ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-list */ class ListPushTailXTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('metavars', 'foo'); $redis->rpushx('metavars', 'hoge'); } } predis-0.8.3/tests/Predis/Command/ListRangeTest.php000066400000000000000000000076471211043230100222200ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-list */ class ListRangeTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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); } } predis-0.8.3/tests/Predis/Command/ListRemoveTest.php000066400000000000000000000065061211043230100224120ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-list */ class ListRemoveTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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); } } predis-0.8.3/tests/Predis/Command/ListSetTest.php000066400000000000000000000050331211043230100217020ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-list */ class ListSetTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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'); } } predis-0.8.3/tests/Predis/Command/ListTrimTest.php000066400000000000000000000071701211043230100220660ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-list */ class ListTrimTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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); } } predis-0.8.3/tests/Predis/Command/PrefixHelpersTest.php000066400000000000000000000043611211043230100230760ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; 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\Command\AbstractCommand'); $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\Command\AbstractCommand'); $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\Command\AbstractCommand'); $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\Command\AbstractCommand'); $command->setRawArguments($arguments); PrefixHelpers::skipLast($command, 'prefix:'); $this->assertSame($expected, $command->getArguments()); } } predis-0.8.3/tests/Predis/Command/PrefixableCommandTest.php000066400000000000000000000026171211043230100237000ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class PrefixableCommandTest extends StandardTestCase { /** * @group disconnected */ public function testImplementsCorrectInterface() { $command = $this->getMockForAbstractClass('Predis\Command\PrefixableCommand'); $this->assertInstanceOf('Predis\Command\PrefixableCommandInterface', $command); $this->assertInstanceOf('Predis\Command\CommandInterface', $command); } /** * @group disconnected */ public function testAddPrefixToFirstArgument() { $command = $this->getMockForAbstractClass('Predis\Command\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\Command\PrefixableCommand'); $command->prefixKeys('prefix:'); $this->assertEmpty($command->getArguments()); } } predis-0.8.3/tests/Predis/Command/Processor/000077500000000000000000000000001211043230100207205ustar00rootroot00000000000000predis-0.8.3/tests/Predis/Command/Processor/KeyPrefixProcessorTest.php000066400000000000000000000044161211043230100261040ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command\Processor; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class KeyPrefixProcessorTest extends StandardTestCase { /** * @group disconnected */ public function testConstructorWithPrefix() { $prefix = 'prefix:'; $processor = new KeyPrefixProcessor($prefix); $this->assertInstanceOf('Predis\Command\Processor\CommandProcessorInterface', $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\Command\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\Command\CommandInterface'); $command->expects($this->never())->method('prefixKeys'); $processor = new KeyPrefixProcessor($prefix); $processor->process($command); } /** * @group disconnected */ public function testInstanceCanBeCastedToString() { $prefix = 'prefix:'; $processor = new KeyPrefixProcessor($prefix); $this->assertEquals($prefix, (string) $processor); } } predis-0.8.3/tests/Predis/Command/Processor/ProcessorChainTest.php000066400000000000000000000115731211043230100252220ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command\Processor; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class ProcessorChainTest extends StandardTestCase { /** * @group disconnected */ public function testConstructor() { $chain = new ProcessorChain(); $this->assertInstanceOf('Predis\Command\Processor\CommandProcessorInterface', $chain); $this->assertInstanceOf('Predis\Command\Processor\CommandProcessorChainInterface', $chain); $this->assertEmpty($chain->getProcessors()); } /** * @group disconnected */ public function testConstructorWithProcessorsArray() { $processors = array( $this->getMock('Predis\Command\Processor\CommandProcessorInterface'), $this->getMock('Predis\Command\Processor\CommandProcessorInterface'), ); $chain = new ProcessorChain($processors); $this->assertSame($processors, $chain->getProcessors()); } /** * @group disconnected */ public function testCountProcessors() { $processors = array( $this->getMock('Predis\Command\Processor\CommandProcessorInterface'), $this->getMock('Predis\Command\Processor\CommandProcessorInterface'), ); $chain = new ProcessorChain($processors); $this->assertEquals(2, $chain->count()); } /** * @group disconnected */ public function testAddProcessors() { $processors = array( $this->getMock('Predis\Command\Processor\CommandProcessorInterface'), $this->getMock('Predis\Command\Processor\CommandProcessorInterface'), ); $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\Command\Processor\CommandProcessorInterface'), $this->getMock('Predis\Command\Processor\CommandProcessorInterface'), ); $processors2 = array( $this->getMock('Predis\Command\Processor\CommandProcessorInterface'), $this->getMock('Predis\Command\Processor\CommandProcessorInterface'), ); $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\Command\Processor\CommandProcessorInterface'), $this->getMock('Predis\Command\Processor\CommandProcessorInterface'), ); $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\Command\Processor\CommandProcessorInterface'); $processors = array( $this->getMock('Predis\Command\Processor\CommandProcessorInterface'), $this->getMock('Predis\Command\Processor\CommandProcessorInterface'), ); $chain = new ProcessorChain($processors); $chain->remove($processor); $this->assertSame($processors, $chain->getProcessors()); } /** * @group disconnected */ public function testRemoveProcessorFromEmptyChain() { $processor = $this->getMock('Predis\Command\Processor\CommandProcessorInterface'); $chain = new ProcessorChain(); $this->assertEmpty($chain->getProcessors()); $chain->remove($processor); $this->assertEmpty($chain->getProcessors()); } /** * @group disconnected */ public function testProcessChain() { $command = $this->getMock('Predis\Command\CommandInterface'); $processor1 = $this->getMock('Predis\Command\Processor\CommandProcessorInterface'); $processor1->expects($this->once())->method('process')->with($command); $processor2 = $this->getMock('Predis\Command\Processor\CommandProcessorInterface'); $processor2->expects($this->once())->method('process')->with($command); $processors = array($processor1, $processor2); $chain = new ProcessorChain($processors); $chain->process($command); } } predis-0.8.3/tests/Predis/Command/PubSubPublishTest.php000066400000000000000000000036161211043230100230470ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-pubsub */ class PubSubPublishTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); } } predis-0.8.3/tests/Predis/Command/PubSubSubscribeByPatternTest.php000066400000000000000000000113651211043230100252130ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-pubsub */ class PubSubSubscribeByPatternTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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'); } } predis-0.8.3/tests/Predis/Command/PubSubSubscribeTest.php000066400000000000000000000111711211043230100233550ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-pubsub */ class PubSubSubscribeTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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'); } } predis-0.8.3/tests/Predis/Command/PubSubUnsubscribeByPatternTest.php000066400000000000000000000075121211043230100255550ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-pubsub */ class PubSubUnsubscribeByPatternTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); } } predis-0.8.3/tests/Predis/Command/PubSubUnsubscribeTest.php000066400000000000000000000072431211043230100237250ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-pubsub */ class PubSubUnsubscribeTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); list($_, $unsubscribed1, $_) = $redis->unsubscribe(); list($_, $unsubscribed2, $_) = $redis->getConnection()->read(); $this->assertSameValues(array('channel:foo', 'channel:bar'), array($unsubscribed1, $unsubscribed2)); $this->assertSame('echoed', $redis->echo('echoed')); } } predis-0.8.3/tests/Predis/Command/ScriptedCommandTest.php000066400000000000000000000151711211043230100233730ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; 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] }'; const LUA_SCRIPT_SHA1 = '6e07f61f502e36d123fe28523076af588f5c315e'; /** * @group disconnected */ public function testGetArguments() { $arguments = array('key1', 'key2', 'value1', 'value2'); $command = $this->getMock('Predis\Command\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_SHA1, 2), $arguments), $command->getArguments()); } /** * @group disconnected */ public function testGetArgumentsWithNegativeKeysCount() { $arguments = array('key1', 'key2', 'value1', 'value2'); $command = $this->getMock('Predis\Command\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_SHA1, 2), $arguments), $command->getArguments()); } /** * @group disconnected */ public function testGetArgumentsWithZeroKeysCount() { $arguments = array('value1', 'value2', 'value3'); $command = $this->getMock('Predis\Command\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(0)); $command->setArguments($arguments); $this->assertSame(array_merge(array(self::LUA_SCRIPT_SHA1, 0), $arguments), $command->getArguments()); } /** * @group disconnected */ public function testGetKeys() { $arguments = array('key1', 'key2', 'value1', 'value2'); $command = $this->getMock('Predis\Command\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 testGetKeysWithZeroKeysCount() { $arguments = array('value1', 'value2', 'value3'); $command = $this->getMock('Predis\Command\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(0)); $command->setArguments($arguments); $this->assertSame(array(), $command->getKeys()); } /** * @group disconnected */ public function testGetKeysWithNegativeKeysCount() { $arguments = array('key1', 'key2', 'value1', 'value2'); $command = $this->getMock('Predis\Command\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\Command\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 testPrefixKeysWithNegativeKeysCount() { $arguments = array('foo', 'hoge', 'bar', 'piyo'); $expected = array('prefix:foo', 'prefix:hoge'); $command = $this->getMock('Predis\Command\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\Command\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(self::LUA_SCRIPT_SHA1, $command->getScriptHash()); } } predis-0.8.3/tests/Predis/Command/ServerBackgroundRewriteAOFTest.php000066400000000000000000000021351211043230100254510ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-server */ class ServerBackgroundRewriteAOFTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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)); } } predis-0.8.3/tests/Predis/Command/ServerBackgroundSaveTest.php000066400000000000000000000021131211043230100243740ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-server */ class ServerBackgroundSaveTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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)); } } predis-0.8.3/tests/Predis/Command/ServerClientTest.php000066400000000000000000000135021211043230100227200ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-server */ class ServerClientTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 testFilterArgumentsOfClientGetname() { $arguments = $expected = array('getname'); $command = $this->getCommand(); $command->setArguments($arguments); $this->assertSame($expected, $command->getArguments()); } /** * @group disconnected */ public function testFilterArgumentsOfClientSetname() { $arguments = $expected = array('setname', 'connection-a'); $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 */ public function testGetsNameOfConnection() { $this->markTestSkippedOnRedisVersionBelow('2.6.9'); $redis = $this->getClient(); $clientName = $redis->client('GETNAME'); $this->assertNull($clientName); $expectedConnectionName = 'foo-bar'; $this->assertTrue($redis->client('SETNAME', $expectedConnectionName)); $this->assertEquals($expectedConnectionName, $redis->client('GETNAME')); } /** * @group connected */ public function testSetsNameOfConnection() { $this->markTestSkippedOnRedisVersionBelow('2.6.9'); $redis = $this->getClient(); $expectedConnectionName = 'foo-baz'; $this->assertTrue($redis->client('SETNAME', $expectedConnectionName)); $this->assertEquals($expectedConnectionName, $redis->client('GETNAME')); } /** * @return array */ public function invalidConnectionNameProvider() { return array( array('foo space'), array('foo \n'), array('foo $'), ); } /** * @group connected * @expectedException Predis\ServerException * @dataProvider invalidConnectionNameProvider */ public function testInvalidSetNameOfConnection($invalidConnectionName) { $this->markTestSkippedOnRedisVersionBelow('2.6.9'); $redis = $this->getClient(); $redis->client('SETNAME', $invalidConnectionName); } /** * @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')); } } predis-0.8.3/tests/Predis/Command/ServerConfigTest.php000066400000000000000000000102471211043230100227120ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-server */ class ServerConfigTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); } } predis-0.8.3/tests/Predis/Command/ServerDatabaseSizeTest.php000066400000000000000000000024671211043230100240510ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-server */ class ServerDatabaseSizeTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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()); } } predis-0.8.3/tests/Predis/Command/ServerEvalSHATest.php000066400000000000000000000061651211043230100227340ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-scripting */ class ServerEvalSHATest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 disconnected */ public function testGetScriptHash() { $command = $this->getCommandWithArgumentsArray(array($sha1 = sha1('return true')), 0); $this->assertSame($sha1, $command->getScriptHash()); } /** * @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); } } predis-0.8.3/tests/Predis/Command/ServerEvalTest.php000066400000000000000000000055601211043230100223760ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-scripting */ class ServerEvalTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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); } } predis-0.8.3/tests/Predis/Command/ServerFlushAllTest.php000066400000000000000000000021011211043230100232050ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-server */ class ServerFlushAllTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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)); } } predis-0.8.3/tests/Predis/Command/ServerFlushDatabaseTest.php000066400000000000000000000025441211043230100242140ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-server */ class ServerFlushDatabaseTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); } } predis-0.8.3/tests/Predis/Command/ServerInfoTest.php000066400000000000000000000166211211043230100224020ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-server */ class ServerInfoTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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); } } predis-0.8.3/tests/Predis/Command/ServerInfoV26xTest.php000066400000000000000000000200641211043230100230640ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-server */ class ServerInfoV26xTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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); } } predis-0.8.3/tests/Predis/Command/ServerLastSaveTest.php000066400000000000000000000024201211043230100232210ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-server */ class ServerLastSaveTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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()); } } predis-0.8.3/tests/Predis/Command/ServerMonitorTest.php000066400000000000000000000033001211043230100231240ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-server * @group realm-monitor */ class ServerMonitorTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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)); // NOTE: Starting with 2.6 Redis does not return the "MONITOR" message after // +OK to the client that issued the MONITOR command. if (version_compare($this->getProfile()->getVersion(), '2.4', '<=')) { $this->assertRegExp('/\d+.\d+(\s?\(db \d+\))? "MONITOR"/', $connection->read()); } } } predis-0.8.3/tests/Predis/Command/ServerObjectTest.php000066400000000000000000000047511211043230100227160ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-server */ class ServerObjectTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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'); } } predis-0.8.3/tests/Predis/Command/ServerSaveTest.php000066400000000000000000000020651211043230100224020ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-server */ class ServerSaveTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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)); } } predis-0.8.3/tests/Predis/Command/ServerScriptTest.php000066400000000000000000000050021211043230100227420ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-scripting */ class ServerScriptTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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'); } } predis-0.8.3/tests/Predis/Command/ServerShutdownTest.php000066400000000000000000000016341211043230100233200ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-server */ class ServerShutdownTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\ServerShutdown'; } /** * {@inheritdoc} */ protected function getExpectedId() { return 'SHUTDOWN'; } /** * @group disconnected */ public function testFilterArguments() { $command = $this->getCommand(); $command->setArguments(array()); $this->assertSame(array(), $command->getArguments()); } } predis-0.8.3/tests/Predis/Command/ServerSlaveOfTest.php000066400000000000000000000035221211043230100230420ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-server */ class ServerSlaveOfTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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)); } } predis-0.8.3/tests/Predis/Command/ServerSlowlogTest.php000066400000000000000000000056321211043230100231350ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; 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\Command\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(); $config = $redis->config('get', 'slowlog-log-slower-than'); $threshold = array_pop($config); $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'); } } predis-0.8.3/tests/Predis/Command/ServerTimeTest.php000066400000000000000000000030141211043230100223750ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-server */ class ServerTimeTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\ServerTime'; } /** * {@inheritdoc} */ protected function getExpectedId() { return 'TIME'; } /** * @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() { $expected = array(1331114908, 453990); $command = $this->getCommand(); $this->assertSame($expected, $command->parseResponse($expected)); } /** * @group connected */ public function testReturnsServerTime() { $redis = $this->getClient(); $this->assertInternalType('array', $time = $redis->time()); $this->assertInternalType('string', $time[0]); $this->assertInternalType('string', $time[1]); } } predis-0.8.3/tests/Predis/Command/SetAddTest.php000066400000000000000000000052251211043230100214620ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-set */ class SetAddTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('metavars', 'foo'); $redis->sadd('metavars', 'hoge'); } } predis-0.8.3/tests/Predis/Command/SetCardinalityTest.php000066400000000000000000000044001211043230100232270ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-set */ class SetCardinalityTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('metavars', 'foo'); $redis->scard('metavars'); } } predis-0.8.3/tests/Predis/Command/SetDifferenceStoreTest.php000066400000000000000000000071561211043230100240460ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-set */ class SetDifferenceStoreTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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'); } } predis-0.8.3/tests/Predis/Command/SetDifferenceTest.php000066400000000000000000000066321211043230100230270ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-set */ class SetDifferenceTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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'); } } predis-0.8.3/tests/Predis/Command/SetIntersectionStoreTest.php000066400000000000000000000100301211043230100244430ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-set */ class SetIntersectionStoreTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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'); } } predis-0.8.3/tests/Predis/Command/SetIntersectionTest.php000066400000000000000000000071441211043230100234420ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-set */ class SetIntersectionTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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'); } } predis-0.8.3/tests/Predis/Command/SetIsMemberTest.php000066400000000000000000000047151211043230100225000ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-set */ class SetIsMemberTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->sismember('foo', 'bar'); } } predis-0.8.3/tests/Predis/Command/SetMembersTest.php000066400000000000000000000044771211043230100223740ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-set */ class SetMembersTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->smembers('foo'); } } predis-0.8.3/tests/Predis/Command/SetMoveTest.php000066400000000000000000000061421211043230100216770ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-set */ class SetMoveTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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 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'); } } predis-0.8.3/tests/Predis/Command/SetPopTest.php000066400000000000000000000042651211043230100215330ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-set */ class SetPopTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->spop('foo'); } } predis-0.8.3/tests/Predis/Command/SetRandomMemberTest.php000066400000000000000000000046341211043230100233450ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-set */ class SetRandomMemberTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->srandmember('foo'); } } predis-0.8.3/tests/Predis/Command/SetRemoveTest.php000066400000000000000000000054311211043230100222260ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-set */ class SetRemoveTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->srem('foo', 'bar'); } } predis-0.8.3/tests/Predis/Command/SetUnionStoreTest.php000066400000000000000000000071571211043230100231050ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-set */ class SetUnionStoreTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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'); } } predis-0.8.3/tests/Predis/Command/SetUnionTest.php000066400000000000000000000066341211043230100220670ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-set */ class SetUnionTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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'); } } predis-0.8.3/tests/Predis/Command/StringAppendTest.php000066400000000000000000000047521211043230100227200ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringAppendTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->lpush('metavars', 'foo'); $redis->append('metavars', 'bar'); } } predis-0.8.3/tests/Predis/Command/StringBitCountTest.php000066400000000000000000000046651211043230100232430ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringBitCountTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\StringBitCount'; } /** * {@inheritdoc} */ protected function getExpectedId() { return 'BITCOUNT'; } /** * @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() { $raw = 10; $expected = 10; $command = $this->getCommand(); $this->assertSame($expected, $command->parseResponse($raw)); } /** * @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 testReturnsNumberOfBitsSet() { $redis = $this->getClient(); $redis->setbit('key', 1, 1); $redis->setbit('key', 10, 1); $redis->setbit('key', 16, 1); $redis->setbit('key', 22, 1); $redis->setbit('key', 32, 1); $this->assertSame(5, $redis->bitcount('key'), 'Count bits set (without range)'); $this->assertSame(3, $redis->bitcount('key', 2, 4), 'Count bits set (with range)'); } /** * @group connected * @expectedException Predis\ServerException * @expectedExceptionMessage Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->lpush('key', 'list'); $redis->bitcount('key'); } } predis-0.8.3/tests/Predis/Command/StringBitOpTest.php000066400000000000000000000114531211043230100225220ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringBitOpTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\StringBitOp'; } /** * {@inheritdoc} */ protected function getExpectedId() { return 'BITOP'; } /** * @group disconnected */ public function testFilterArguments() { $arguments = array('AND', 'key:dst', 'key:01', 'key:02'); $expected = array('AND', 'key:dst', 'key:01', 'key:02'); $command = $this->getCommand(); $command->setArguments($arguments); $this->assertSame($expected, $command->getArguments()); } /** * @group disconnected */ public function testFilterArgumentsKeysAsSingleArray() { $arguments = array('AND', 'key:dst', array('key:01', 'key:02')); $expected = array('AND', 'key:dst', 'key:01', 'key:02'); $command = $this->getCommand(); $command->setArguments($arguments); $this->assertSame($expected, $command->getArguments()); } /** * @group disconnected */ public function testParseResponse() { $raw = 10; $expected = 10; $command = $this->getCommand(); $this->assertSame($expected, $command->parseResponse($raw)); } /** * @group disconnected */ public function testPrefixKeys() { $arguments = array('AND', 'key:dst', 'key:01', 'key:02'); $expected = array('AND', 'prefix:key:dst', 'prefix:key:01', 'prefix:key:02'); $command = $this->getCommandWithArgumentsArray($arguments); $command->prefixKeys('prefix:'); $this->assertSame($expected, $command->getArguments()); } /** * @group connected */ public function testCanPerformBitwiseAND() { $redis = $this->getClient(); $redis->set('key:src:1', "h\x80"); $redis->set('key:src:2', "R"); $this->assertSame(2, $redis->bitop('AND', 'key:dst', 'key:src:1', 'key:src:2')); $this->assertSame("@\x00", $redis->get('key:dst')); } /** * @group connected */ public function testCanPerformBitwiseOR() { $redis = $this->getClient(); $redis->set('key:src:1', "h\x80"); $redis->set('key:src:2', "R"); $this->assertSame(2, $redis->bitop('OR', 'key:dst', 'key:src:1', 'key:src:2')); $this->assertSame("z\x80", $redis->get('key:dst')); } /** * @group connected */ public function testCanPerformBitwiseXOR() { $redis = $this->getClient(); $redis->set('key:src:1', "h\x80"); $redis->set('key:src:2', "R"); $this->assertSame(2, $redis->bitop('XOR', 'key:dst', 'key:src:1', 'key:src:2')); $this->assertSame(":\x80", $redis->get('key:dst')); } /** * @group connected */ public function testCanPerformBitwiseNOT() { $redis = $this->getClient(); $redis->set('key:src:1', "h\x80"); $this->assertSame(2, $redis->bitop('NOT', 'key:dst', 'key:src:1')); $this->assertSame("\x97\x7f", $redis->get('key:dst')); } /** * @group connected * @expectedException Predis\ServerException * @expectedExceptionMessage ERR BITOP NOT must be called with a single source key. */ public function testBitwiseNOTAcceptsOnlyOneSourceKey() { $this->getClient()->bitop('NOT', 'key:dst', 'key:src:1', 'key:src:2'); } /** * @group connected * @expectedException Predis\ServerException * @expectedExceptionMessage ERR syntax error */ public function testThrowsExceptionOnInvalidOperation() { $this->getClient()->bitop('NOOP', 'key:dst', 'key:src:1', 'key:src:2'); } /** * @group connected * @expectedException Predis\ServerException * @expectedExceptionMessage Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnInvalidSourceKey() { $redis = $this->getClient(); $redis->lpush('key:src:1', 'list'); $redis->bitop('AND', 'key:dst', 'key:src:1', 'key:src:2'); } /** * @group connected */ public function testDoesNotThrowExceptionOnInvalidDestinationKey() { $redis = $this->getClient(); $redis->lpush('key:dst', 'list'); $redis->bitop('AND', 'key:dst', 'key:src:1', 'key:src:2'); $this->assertSame('none', $redis->type('key:dst')); } } predis-0.8.3/tests/Predis/Command/StringDecrementByTest.php000066400000000000000000000061521211043230100237060ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringDecrementByTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->lpush('metavars', 'foo'); $redis->decrby('metavars', 10); } } predis-0.8.3/tests/Predis/Command/StringDecrementTest.php000066400000000000000000000052751211043230100234200ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringDecrementTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->lpush('metavars', 'foo'); $redis->decr('metavars'); } } predis-0.8.3/tests/Predis/Command/StringGetBitTest.php000066400000000000000000000061541211043230100226650ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringGetBitTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->lpush('metavars', 'foo'); $redis->getbit('metavars', '1'); } } predis-0.8.3/tests/Predis/Command/StringGetMultipleTest.php000066400000000000000000000055221211043230100237400ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringGetMultipleTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); } } predis-0.8.3/tests/Predis/Command/StringGetRangeTest.php000066400000000000000000000053021211043230100231750ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringGetRangeTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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); } } predis-0.8.3/tests/Predis/Command/StringGetSetTest.php000066400000000000000000000043651211043230100227040ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringGetSetTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->lpush('metavars', 'foo'); $redis->getset('metavars', 'foo'); } } predis-0.8.3/tests/Predis/Command/StringGetTest.php000066400000000000000000000051101211043230100222150ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringGetTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->rpush('metavars', 'foo'); $redis->get('metavars'); } } predis-0.8.3/tests/Predis/Command/StringIncrementByFloatTest.php000066400000000000000000000062641211043230100247160ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringIncrementByFloatTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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); } } predis-0.8.3/tests/Predis/Command/StringIncrementByTest.php000066400000000000000000000061601211043230100237230ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringIncrementByTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->lpush('metavars', 'foo'); $redis->incrby('metavars', 10); } } predis-0.8.3/tests/Predis/Command/StringIncrementTest.php000066400000000000000000000045431211043230100234330ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringIncrementTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->lpush('metavars', 'foo'); $redis->incr('metavars'); } } predis-0.8.3/tests/Predis/Command/StringPreciseSetExpireTest.php000066400000000000000000000061001211043230100247210ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringPreciseSetExpireTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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'); } } predis-0.8.3/tests/Predis/Command/StringSetBitTest.php000066400000000000000000000072111211043230100226740ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringSetBitTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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); } } predis-0.8.3/tests/Predis/Command/StringSetExpireTest.php000066400000000000000000000056371211043230100234240ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringSetExpireTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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'); } } predis-0.8.3/tests/Predis/Command/StringSetMultiplePreserveTest.php000066400000000000000000000052451211043230100254720ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringSetMultiplePreserveTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); } } predis-0.8.3/tests/Predis/Command/StringSetMultipleTest.php000066400000000000000000000044251211043230100237550ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringSetMultipleTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); } } predis-0.8.3/tests/Predis/Command/StringSetRangeTest.php000066400000000000000000000065511211043230100232200ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringSetRangeTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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'); } } predis-0.8.3/tests/Predis/Command/StringSetTest.php000066400000000000000000000034311211043230100222350ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringSetTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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')); } } predis-0.8.3/tests/Predis/Command/StringStrlenTest.php000066400000000000000000000045171211043230100227570ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-string */ class StringStrlenTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->lpush('metavars', 'foo'); $redis->strlen('metavars'); } } predis-0.8.3/tests/Predis/Command/StringSubstrTest.php000066400000000000000000000033271211043230100227700ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; 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\Command\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()); } } predis-0.8.3/tests/Predis/Command/TransactionDiscardTest.php000066400000000000000000000033421211043230100240730ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-transaction */ class TransactionDiscardTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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(); } } predis-0.8.3/tests/Predis/Command/TransactionExecTest.php000066400000000000000000000045111211043230100234050ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-transaction */ class TransactionExecTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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(); } } predis-0.8.3/tests/Predis/Command/TransactionMultiTest.php000066400000000000000000000041021211043230100236070ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-transaction */ class TransactionMultiTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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\ResponseObjectInterface', $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(); } } predis-0.8.3/tests/Predis/Command/TransactionUnwatchTest.php000066400000000000000000000034071211043230100241350ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-transaction */ class TransactionUnwatchTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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()); } } predis-0.8.3/tests/Predis/Command/TransactionWatchTest.php000066400000000000000000000065461211043230100236010ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-transaction */ class TransactionWatchTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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'); } } predis-0.8.3/tests/Predis/Command/ZSetAddTest.php000066400000000000000000000062031211043230100216110ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-zset */ class ZSetAddTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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'); } } predis-0.8.3/tests/Predis/Command/ZSetCardinalityTest.php000066400000000000000000000041621211043230100233660ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-zset */ class ZSetCardinalityTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->zcard('foo'); } } predis-0.8.3/tests/Predis/Command/ZSetCountTest.php000066400000000000000000000064431211043230100222170ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-zset */ class ZSetCountTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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); } } predis-0.8.3/tests/Predis/Command/ZSetIncrementByTest.php000066400000000000000000000045151211043230100233440ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-zset */ class ZSetIncrementByTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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'); } } predis-0.8.3/tests/Predis/Command/ZSetIntersectionStoreTest.php000066400000000000000000000137031211043230100246070ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-zset */ class ZSetIntersectionStoreTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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'); } } predis-0.8.3/tests/Predis/Command/ZSetRangeByScoreTest.php000066400000000000000000000152261211043230100234510ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-zset */ class ZSetRangeByScoreTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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); } } predis-0.8.3/tests/Predis/Command/ZSetRangeTest.php000066400000000000000000000103641211043230100221600ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-zset */ class ZSetRangeTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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); } } predis-0.8.3/tests/Predis/Command/ZSetRankTest.php000066400000000000000000000044501211043230100220160ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-zset */ class ZSetRankTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->zrank('foo', 'bar'); } } predis-0.8.3/tests/Predis/Command/ZSetRemoveRangeByRankTest.php000066400000000000000000000053211211043230100244420ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-zset */ class ZSetRemoveRangeByRankTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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); } } predis-0.8.3/tests/Predis/Command/ZSetRemoveRangeByScoreTest.php000066400000000000000000000053371211043230100246310ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-zset */ class ZSetRemoveRangeByScoreTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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); } } predis-0.8.3/tests/Predis/Command/ZSetRemoveTest.php000066400000000000000000000045771211043230100223720ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-zset */ class ZSetRemoveTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->zrem('foo', 'bar'); } } predis-0.8.3/tests/Predis/Command/ZSetReverseRangeByScoreTest.php000066400000000000000000000153371211043230100250100ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-zset */ class ZSetReverseRangeByScoreTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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); } } predis-0.8.3/tests/Predis/Command/ZSetReverseRangeTest.php000066400000000000000000000104451211043230100235140ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-zset */ class ZSetReverseRangeTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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); } } predis-0.8.3/tests/Predis/Command/ZSetReverseRankTest.php000066400000000000000000000045101211043230100233470ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-zset */ class ZSetReverseRankTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->zrevrank('foo', 'bar'); } } predis-0.8.3/tests/Predis/Command/ZSetScoreTest.php000066400000000000000000000044711211043230100222010ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-zset */ class ZSetScoreTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 Operation against a key holding the wrong kind of value */ public function testThrowsExceptionOnWrongType() { $redis = $this->getClient(); $redis->set('foo', 'bar'); $redis->zscore('foo', 'bar'); } } predis-0.8.3/tests/Predis/Command/ZSetUnionStoreTest.php000066400000000000000000000144621211043230100232340ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Command; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @group commands * @group realm-zset */ class ZSetUnionStoreTest extends CommandTestCase { /** * {@inheritdoc} */ protected function getExpectedCommand() { return 'Predis\Command\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 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'); } } predis-0.8.3/tests/Predis/CommunicationExceptionTest.php000066400000000000000000000066701211043230100234310ustar00rootroot00000000000000 * * 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\Connection\SingleConnectionInterface; /** * */ 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()); } /** * @group disconnected * @expectedException Predis\CommunicationException * @expectedExceptionMessage Communication error */ public function testCommunicationExceptionHandling() { $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $connection->expects($this->once())->method('isConnected')->will($this->returnValue(true)); $connection->expects($this->once())->method('disconnect'); $exception = $this->getException($connection, 'Communication error'); CommunicationException::handle($exception); } // ******************************************************************** // // ---- HELPER METHODS ------------------------------------------------ // // ******************************************************************** // /** * Returns a mocked connection instance. * * @param mixed $parameters Connection parameters. * @return SingleConnectionInterface */ protected function getMockedConnectionBase($parameters = null) { $builder = $this->getMockBuilder('Predis\Connection\AbstractConnection'); if ($parameters === null) { $builder->disableOriginalConstructor(); } else if (!$parameters instanceof ConnectionParametersInterface) { $parameters = new ConnectionParameters($parameters); } return $builder->getMockForAbstractClass(array($parameters)); } /** * Returns a connection exception instance. * * @param SingleConnectionInterface $message Connection instance. * @param string $message Exception message. * @param int $code Exception code. * @param \Exception $inner Inner exception. * @return \Exception */ protected function getException(SingleConnectionInterface $connection, $message, $code = 0, \Exception $inner = null) { $arguments = array($connection, $message, $code, $inner); $mock = $this->getMockForAbstractClass('Predis\CommunicationException', $arguments); return $mock; } } predis-0.8.3/tests/Predis/Connection/000077500000000000000000000000001211043230100174625ustar00rootroot00000000000000predis-0.8.3/tests/Predis/Connection/ComposableStreamConnectionTest.php000066400000000000000000000074371211043230100263260ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\Profile\ServerProfile; /** * */ class ComposableStreamConnectionTest extends ConnectionTestCase { /** * @group disconnected */ public function testConstructorDoesNotOpenConnection() { $connection = new ComposableStreamConnection($this->getParameters()); $this->assertFalse($connection->isConnected()); } /** * @group disconnected */ public function testExposesParameters() { $parameters = $this->getParameters(); $connection = new ComposableStreamConnection($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 ComposableStreamConnection($parameters); } /** * @group disconnected */ public function testCanBeSerialized() { $parameters = $this->getParameters(array('alias' => 'redis', 'read_write_timeout' => 10)); $connection = new ComposableStreamConnection($parameters); $unserialized = unserialize(serialize($connection)); $this->assertEquals($connection, $unserialized); } // ******************************************************************** // // ---- INTEGRATION TESTS --------------------------------------------- // // ******************************************************************** // /** * @group connected */ public function testReadsMultibulkRepliesAsIterators() { $connection = $this->getConnection($profile, true); $connection->getProtocol()->setOption('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\Iterator\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 ComposableStreamConnection($parameters); if ($initialize) { $connection->pushInitCommand($profile->createCommand('select', array($parameters->database))); $connection->pushInitCommand($profile->createCommand('flushdb')); } return $connection; } } predis-0.8.3/tests/Predis/Connection/ConnectionExceptionTest.php000066400000000000000000000013551211043230100250150ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; require_once __DIR__.'/../CommunicationExceptionTest.php'; use Predis\CommunicationExceptionTest; use Predis\Connection\SingleConnectionInterface; /** * */ class ConnectionExceptionTest extends CommunicationExceptionTest { /** * {@inheritdoc} */ protected function getException(SingleConnectionInterface $connection, $message, $code = 0, \Exception $inner = null) { return new ConnectionException($connection, $message, $code, $inner); } } predis-0.8.3/tests/Predis/Connection/ConnectionFactoryTest.php000066400000000000000000000316111211043230100244640ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class ConnectionFactoryTest extends StandardTestCase { /** * @group disconnected */ public function testImplementsCorrectInterface() { $factory = new ConnectionFactory(); $this->assertInstanceOf('Predis\Connection\ConnectionFactoryInterface', $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\Connection\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\Connection\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\Connection\SingleConnectionInterface', $connection); $this->assertEquals('tcp', $parameters->scheme); $this->assertFalse(isset($parameters->custom)); $this->assertNull($parameters->custom); } /** * @group disconnected */ public function testCreateConnectionWithArrayParameters() { $factory = new ConnectionFactory(); $connection = $factory->create(array('scheme' => 'tcp', 'custom' => 'foobar')); $parameters = $connection->getParameters(); $this->assertInstanceOf('Predis\Connection\SingleConnectionInterface', $connection); $this->assertEquals('tcp', $parameters->scheme); $this->assertTrue(isset($parameters->custom)); $this->assertSame('foobar', $parameters->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\Connection\SingleConnectionInterface', $connection); $this->assertEquals('tcp', $parameters->scheme); $this->assertTrue(isset($parameters->custom)); $this->assertSame('foobar', $parameters->custom); } /** * @group disconnected */ public function testCreateConnectionWithoutInitializationCommands() { $profile = $this->getMock('Predis\Profile\ServerProfileInterface'); $profile->expects($this->never())->method('create'); $factory = new ConnectionFactory($profile); $parameters = new ConnectionParameters(); $connection = $factory->create($parameters); $this->assertInstanceOf('Predis\Connection\SingleConnectionInterface', $connection); } /** * @group disconnected */ public function testCreateConnectionWithInitializationCommands() { $test = $this; $database = 15; $password = 'foobar'; $commands = array(); $createCommand = function ($id, $arguments) use ($test, &$commands) { $commands[$id] = $arguments; $command = $test->getMock('Predis\Command\CommandInterface'); return $command; }; $profile = $this->getMock('Predis\Profile\ServerProfileInterface'); $profile->expects($this->exactly(2)) ->method('createCommand') ->with($this->isType('string'), $this->isType('array')) ->will($this->returnCallback($createCommand)); $factory = new ConnectionFactory($profile); $parameters = new ConnectionParameters(array('database' => $database, 'password' => $password)); $connection = $factory->create($parameters); $this->assertInstanceOf('Predis\Connection\SingleConnectionInterface', $connection); $this->assertEquals(2, count($commands)); // TODO: assertCount()? $this->assertEquals(array($database), $commands['select']); $this->assertEquals(array($password), $commands['auth']); } /** * @group disconnected * @todo This test smells but there's no other way around it right now. */ public function testCreateConnectionWithDatabaseAndPasswordButNoProfile() { $parameters = new ConnectionParameters(array('database' => 0, 'password' => 'foobar')); $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $connection->expects($this->never()) ->method('getParameters') ->will($this->returnValue($parameters)); $connection->expects($this->never()) ->method('pushInitCommand'); $factory = new ConnectionFactory(); $reflection = new \ReflectionObject($factory); $prepareConnection = $reflection->getMethod('prepareConnection'); $prepareConnection->setAccessible(true); $prepareConnection->invoke($factory, $connection); } /** * @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\Connection\SingleConnectionInterface', $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 testAggregatedConnectionSkipCreationOnConnectionInstance() { list(, $connectionClass) = $this->getMockConnectionClass(); $cluster = $this->getMock('Predis\Connection\ClusterConnectionInterface'); $cluster->expects($this->exactly(2)) ->method('add') ->with($this->isInstanceOf('Predis\Connection\SingleConnectionInterface')); $factory = $this->getMock('Predis\Connection\ConnectionFactory', array('create')); $factory->expects($this->never()) ->method('create'); $factory->createAggregated($cluster, array(new $connectionClass(), new $connectionClass())); } /** * @group disconnected */ public function testAggregatedConnectionWithMixedParameters() { list(, $connectionClass) = $this->getMockConnectionClass(); $cluster = $this->getMock('Predis\Connection\ClusterConnectionInterface'); $cluster->expects($this->exactly(4)) ->method('add') ->with($this->isInstanceOf('Predis\Connection\SingleConnectionInterface')); $factory = $this->getMock('Predis\Connection\ConnectionFactory', array('create')); $factory->expects($this->exactly(3)) ->method('create') ->will($this->returnCallback(function ($_) use ($connectionClass) { return new $connectionClass; })); $factory->createAggregated($cluster, array(null, 'tcp://127.0.0.1', array('scheme' => 'tcp'), new $connectionClass())); } /** * @group disconnected */ public function testAggregatedConnectionWithEmptyListOfParameters() { $cluster = $this->getMock('Predis\Connection\ClusterConnectionInterface'); $cluster->expects($this->never())->method('add'); $factory = $this->getMock('Predis\Connection\ConnectionFactory', array('create')); $factory->expects($this->never())->method('create'); $factory->createAggregated($cluster, array()); } /** * @group disconnected * @todo We might want to add a test for SingleConnectionInterface::pushInitCommand(). */ public function testAggregatedConnectionWithServerProfileArgument() { list(, $connectionClass) = $this->getMockConnectionClass(); $cluster = $this->getMock('Predis\Connection\ClusterConnectionInterface'); $profile = $this->getMock('Predis\Profile\ServerProfileInterface'); $factory = $this->getMock('Predis\Connection\ConnectionFactory', array('create'), array($profile)); $factory->expects($this->exactly(2)) ->method('create') ->with($this->anything()) ->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->createAggregated($cluster, $nodes); } // ******************************************************************** // // ---- HELPER METHODS ------------------------------------------------ // // ******************************************************************** // /** * Returns a mocked Predis\Connection\SingleConnectionInterface. * * @return Array Mock instance and class name */ protected function getMockConnectionClass() { $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); return array($connection, get_class($connection)); } } predis-0.8.3/tests/Predis/Connection/ConnectionParametersTest.php000066400000000000000000000153341211043230100251640ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * @todo ConnectionParameters::define(); * @todo ConnectionParameters::undefine(); */ class ParametersTest 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['timeout'], $parameters->timeout); } /** * @group disconnected */ public function testIsSet() { $parameters = new ConnectionParameters(); $this->assertTrue(isset($parameters->scheme)); $this->assertFalse(isset($parameters->unknown)); } /** * @group disconnected */ public function testUserDefinedParameters() { $parameters = new ConnectionParameters(array('port' => 7000, 'custom' => 'foobar')); $this->assertTrue(isset($parameters->scheme)); $this->assertSame('tcp', $parameters->scheme); $this->assertTrue(isset($parameters->port)); $this->assertSame(7000, $parameters->port); $this->assertTrue(isset($parameters->custom)); $this->assertSame('foobar', $parameters->custom); $this->assertFalse(isset($parameters->unknown)); $this->assertNull($parameters->unknown); } /** * @group disconnected */ public function testConstructWithUriString() { $defaults = $this->getDefaultParametersArray(); $overrides = array( 'port' => 7000, 'database' => 5, 'iterable_multibulk' => 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['iterable_multibulk'], $parameters->iterable_multibulk); $this->assertTrue(isset($parameters->custom)); $this->assertEquals($overrides['custom'], $parameters->custom); $this->assertFalse(isset($parameters->unknown)); $this->assertNull($parameters->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 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->assertEquals($parameters->custom, $unserialized->custom); $this->assertFalse(isset($unserialized->unknown)); $this->assertNull($unserialized->unknown); } /** * @group disconnected */ public function testParsingURI() { $uri = 'tcp://10.10.10.10:6400?timeout=0.5&persistent=1'; $expected = array( 'scheme' => 'tcp', 'host' => '10.10.10.10', 'port' => 6400, 'timeout' => '0.5', 'persistent' => '1', ); $this->assertSame($expected, ConnectionParameters::parseURI($uri)); } /** * @group disconnected */ public function testParsingUnixDomainURI() { $uri = 'unix:///tmp/redis.sock?timeout=0.5&persistent=1'; $expected = array( 'scheme' => 'unix', 'host' => 'localhost', 'path' => '/tmp/redis.sock', 'timeout' => '0.5', 'persistent' => '1', ); $this->assertSame($expected, ConnectionParameters::parseURI($uri)); } /** * @group disconnected * @expectedException Predis\ClientException * @expectedExceptionMessage Invalid URI: tcp://invalid:uri */ public function testParsingURIThrowOnInvalidURI() { ConnectionParameters::parseURI('tcp://invalid:uri'); } // ******************************************************************** // // ---- 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, 'timeout' => 5.0, ); } /** * 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; } } predis-0.8.3/tests/Predis/Connection/MasterSlaveReplicationTest.php000066400000000000000000000501771211043230100254650ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\Profile\ServerProfile; use Predis\Replication\ReplicationStrategy; /** * */ class MasterSlaveReplicationTest extends StandardTestCase { /** * @group disconnected */ public function testAddingConnectionsToReplication() { $master = $this->getMockConnection('tcp://host1?alias=master'); $slave1 = $this->getMockConnection('tcp://host2?alias=slave1'); $slave2 = $this->getMockConnection('tcp://host3?alias=slave2'); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave1); $replication->add($slave2); $this->assertSame($master, $replication->getConnectionById('master')); $this->assertSame($slave1, $replication->getConnectionById('slave1')); $this->assertSame($slave2, $replication->getConnectionById('slave2')); $this->assertSame($master, $replication->getMaster()); $this->assertSame(array($slave1, $slave2), $replication->getSlaves()); } /** * @group disconnected */ public function testRemovingConnectionsFromReplication() { $master = $this->getMockConnection('tcp://host1?alias=master'); $slave1 = $this->getMockConnection('tcp://host2?alias=slave1'); $slave2 = $this->getMockConnection('tcp://host3?alias=slave2'); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave1); $this->assertTrue($replication->remove($slave1)); $this->assertFalse($replication->remove($slave2)); $this->assertSame($master, $replication->getMaster()); $this->assertSame(array(), $replication->getSlaves()); } /** * @group disconnected * @expectedException RuntimeException * @expectedExceptionMessage Replication needs a master and at least one slave */ public function testThrowsExceptionOnEmptyReplication() { $replication = new MasterSlaveReplication(); $replication->connect(); } /** * @group disconnected * @expectedException RuntimeException * @expectedExceptionMessage Replication needs a master and at least one slave */ public function testThrowsExceptionOnMissingMaster() { $replication = new MasterSlaveReplication(); $replication->add($this->getMockConnection('tcp://host2?alias=slave1')); $replication->connect(); } /** * @group disconnected * @expectedException RuntimeException * @expectedExceptionMessage Replication needs a master and at least one slave */ public function testThrowsExceptionOnMissingSlave() { $replication = new MasterSlaveReplication(); $replication->add($this->getMockConnection('tcp://host1?alias=master')); $replication->connect(); } /** * @group disconnected */ public function testConnectForcesConnectionToOneOfSlaves() { $master = $this->getMockConnection('tcp://host1?alias=master'); $master->expects($this->never())->method('connect'); $slave = $this->getMockConnection('tcp://host2?alias=slave1'); $slave->expects($this->once())->method('connect'); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave); $replication->connect(); } /** * @group disconnected */ public function testIsConnectedReturnsTrueIfAtLeastOneConnectionIsOpen() { $master = $this->getMockConnection('tcp://host1?alias=master'); $master->expects($this->never())->method('isConnected')->will($this->returnValue(false)); $slave = $this->getMockConnection('tcp://host2?alias=slave1'); $slave->expects($this->once())->method('isConnected')->will($this->returnValue(true)); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave); $replication->connect(); $this->assertTrue($replication->isConnected()); } /** * @group disconnected */ public function testIsConnectedReturnsFalseIfAllConnectionsAreClosed() { $master = $this->getMockConnection('tcp://host1?alias=master'); $master->expects($this->any())->method('isConnected')->will($this->returnValue(false)); $slave = $this->getMockConnection('tcp://host2?alias=slave1'); $slave->expects($this->any())->method('isConnected')->will($this->returnValue(false)); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave); $this->assertFalse($replication->isConnected()); $replication->connect(); $replication->disconnect(); $this->assertFalse($replication->isConnected()); } /** * @group disconnected */ public function testDisconnectForcesCurrentConnectionToDisconnect() { $master = $this->getMockConnection('tcp://host1?alias=master'); $master->expects($this->once())->method('disconnect'); $slave = $this->getMockConnection('tcp://host2?alias=slave1'); $slave->expects($this->once())->method('disconnect'); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave); $replication->disconnect(); } /** * @group disconnected */ public function testCanSwitchConnectionByAlias() { $master = $this->getMockConnection('tcp://host1?alias=master'); $slave1 = $this->getMockConnection('tcp://host2?alias=slave1'); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave1); $this->assertNull($replication->getCurrent()); $replication->switchTo('master'); $this->assertSame($master, $replication->getCurrent()); $replication->switchTo('slave1'); $this->assertSame($slave1, $replication->getCurrent()); } /** * @group disconnected * @expectedException InvalidArgumentException * @expectedExceptionMessage The specified connection is not valid */ public function testThrowsErrorWhenSwitchingToUnknownConnection() { $replication = new MasterSlaveReplication(); $replication->add($this->getMockConnection('tcp://host1?alias=master')); $replication->add($this->getMockConnection('tcp://host2?alias=slave1')); $replication->switchTo('unknown'); } /** * @group disconnected */ public function testUsesSlavesOnReadOnlyCommands() { $profile = ServerProfile::getDefault(); $master = $this->getMockConnection('tcp://host1?alias=master'); $slave1 = $this->getMockConnection('tcp://host2?alias=slave1'); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave1); $cmd = $profile->createCommand('exists', array('foo')); $this->assertSame($slave1, $replication->getConnection($cmd)); $cmd = $profile->createCommand('get', array('foo')); $this->assertSame($slave1, $replication->getConnection($cmd)); } /** * @group disconnected */ public function testUsesMasterOnWriteCommands() { $profile = ServerProfile::getDefault(); $master = $this->getMockConnection('tcp://host1?alias=master'); $slave1 = $this->getMockConnection('tcp://host2?alias=slave1'); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave1); $cmd = $profile->createCommand('set', array('foo', 'bar')); $this->assertSame($master, $replication->getConnection($cmd)); $cmd = $profile->createCommand('get', array('foo')); $this->assertSame($master, $replication->getConnection($cmd)); } /** * @group disconnected */ public function testSwitchesFromSlaveToMasterOnWriteCommands() { $profile = ServerProfile::getDefault(); $master = $this->getMockConnection('tcp://host1?alias=master'); $slave1 = $this->getMockConnection('tcp://host2?alias=slave1'); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave1); $cmd = $profile->createCommand('exists', array('foo')); $this->assertSame($slave1, $replication->getConnection($cmd)); $cmd = $profile->createCommand('set', array('foo', 'bar')); $this->assertSame($master, $replication->getConnection($cmd)); $cmd = $profile->createCommand('exists', array('foo')); $this->assertSame($master, $replication->getConnection($cmd)); } /** * @group disconnected */ public function testWritesCommandToCorrectConnection() { $profile = ServerProfile::getDefault(); $cmdExists = $profile->createCommand('exists', array('foo')); $cmdSet = $profile->getDefault()->createCommand('set', array('foo', 'bar')); $master = $this->getMockConnection('tcp://host1?alias=master'); $master->expects($this->once())->method('writeCommand')->with($cmdSet); $slave1 = $this->getMockConnection('tcp://host2?alias=slave1'); $slave1->expects($this->once())->method('writeCommand')->with($cmdExists); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave1); $replication->writeCommand($cmdExists); $replication->writeCommand($cmdSet); } /** * @group disconnected */ public function testReadsCommandFromCorrectConnection() { $profile = ServerProfile::getDefault(); $cmdExists = $profile->createCommand('exists', array('foo')); $cmdSet = $profile->getDefault()->createCommand('set', array('foo', 'bar')); $master = $this->getMockConnection('tcp://host1?alias=master'); $master->expects($this->once())->method('readResponse')->with($cmdSet); $slave1 = $this->getMockConnection('tcp://host2?alias=slave1'); $slave1->expects($this->once())->method('readResponse')->with($cmdExists); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave1); $replication->readResponse($cmdExists); $replication->readResponse($cmdSet); } /** * @group disconnected */ public function testExecutesCommandOnCorrectConnection() { $profile = ServerProfile::getDefault(); $cmdExists = $profile->createCommand('exists', array('foo')); $cmdSet = $profile->getDefault()->createCommand('set', array('foo', 'bar')); $master = $this->getMockConnection('tcp://host1?alias=master'); $master->expects($this->once())->method('executeCommand')->with($cmdSet); $slave1 = $this->getMockConnection('tcp://host2?alias=slave1'); $slave1->expects($this->once())->method('executeCommand')->with($cmdExists); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave1); $replication->executeCommand($cmdExists); $replication->executeCommand($cmdSet); } /** * @group disconnected */ public function testWatchTriggersSwitchToMasterConnection() { $profile = ServerProfile::getDefault(); $cmdWatch = $profile->createCommand('watch', array('foo')); $master = $this->getMockConnection('tcp://host1?alias=master'); $master->expects($this->once())->method('executeCommand')->with($cmdWatch); $slave1 = $this->getMockConnection('tcp://host2?alias=slave1'); $slave1->expects($this->never())->method('executeCommand'); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave1); $replication->executeCommand($cmdWatch); } /** * @group disconnected */ public function testMultiTriggersSwitchToMasterConnection() { $profile = ServerProfile::getDefault(); $cmdMulti = $profile->createCommand('multi'); $master = $this->getMockConnection('tcp://host1?alias=master'); $master->expects($this->once())->method('executeCommand')->with($cmdMulti); $slave1 = $this->getMockConnection('tcp://host2?alias=slave1'); $slave1->expects($this->never())->method('executeCommand'); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave1); $replication->executeCommand($cmdMulti); } /** * @group disconnected */ public function testEvalTriggersSwitchToMasterConnection() { $profile = ServerProfile::get('dev'); $cmdEval = $profile->createCommand('eval', array("return redis.call('info')")); $master = $this->getMockConnection('tcp://host1?alias=master'); $master->expects($this->once())->method('executeCommand')->with($cmdEval); $slave1 = $this->getMockConnection('tcp://host2?alias=slave1'); $slave1->expects($this->never())->method('executeCommand'); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave1); $replication->executeCommand($cmdEval); } /** * @group disconnected */ public function testSortTriggersSwitchToMasterConnectionOnStoreModifier() { $profile = ServerProfile::get('dev'); $cmdSortNormal = $profile->createCommand('sort', array('key')); $cmdSortStore = $profile->createCommand('sort', array('key', array('store' => 'key:store'))); $master = $this->getMockConnection('tcp://host1?alias=master'); $master->expects($this->once())->method('executeCommand')->with($cmdSortStore); $slave1 = $this->getMockConnection('tcp://host2?alias=slave1'); $slave1->expects($this->once())->method('executeCommand')->with($cmdSortNormal); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave1); $replication->executeCommand($cmdSortNormal); $replication->executeCommand($cmdSortStore); } /** * @group disconnected * @expectedException Predis\NotSupportedException * @expectedExceptionMessage The command INFO is not allowed in replication mode */ public function testThrowsExceptionOnNonSupportedCommand() { $cmd = ServerProfile::getDefault()->createCommand('info'); $replication = new MasterSlaveReplication(); $replication->add($this->getMockConnection('tcp://host1?alias=master')); $replication->add($this->getMockConnection('tcp://host2?alias=slave1')); $replication->getConnection($cmd); } /** * @group disconnected */ public function testCanOverrideReadOnlyFlagForCommands() { $profile = ServerProfile::getDefault(); $cmdSet = $profile->createCommand('set', array('foo', 'bar')); $cmdGet = $profile->createCommand('get', array('foo')); $master = $this->getMockConnection('tcp://host1?alias=master'); $master->expects($this->once())->method('executeCommand')->with($cmdGet); $slave1 = $this->getMockConnection('tcp://host2?alias=slave1'); $slave1->expects($this->once())->method('executeCommand')->with($cmdSet); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave1); $replication->getReplicationStrategy()->setCommandReadOnly($cmdSet->getId(), true); $replication->getReplicationStrategy()->setCommandReadOnly($cmdGet->getId(), false); $replication->executeCommand($cmdSet); $replication->executeCommand($cmdGet); } /** * @group disconnected */ public function testAcceptsCallableToOverrideReadOnlyFlagForCommands() { $profile = ServerProfile::getDefault(); $cmdExistsFoo = $profile->createCommand('exists', array('foo')); $cmdExistsBar = $profile->createCommand('exists', array('bar')); $master = $this->getMockConnection('tcp://host1?alias=master'); $master->expects($this->once())->method('executeCommand')->with($cmdExistsBar); $slave1 = $this->getMockConnection('tcp://host2?alias=slave1'); $slave1->expects($this->once())->method('executeCommand')->with($cmdExistsFoo); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave1); $replication->getReplicationStrategy()->setCommandReadOnly('exists', function ($cmd) { list($arg1) = $cmd->getArguments(); return $arg1 === 'foo'; }); $replication->executeCommand($cmdExistsFoo); $replication->executeCommand($cmdExistsBar); } /** * @group disconnected */ public function testCanSetReadOnlyFlagForEvalScripts() { $profile = ServerProfile::get('dev'); $cmdEval = $profile->createCommand('eval', array($script = "return redis.call('info');")); $cmdEvalSha = $profile->createCommand('evalsha', array($scriptSHA1 = sha1($script))); $master = $this->getMockConnection('tcp://host1?alias=master'); $master->expects($this->never())->method('executeCommand'); $slave1 = $this->getMockConnection('tcp://host2?alias=slave1'); $slave1->expects($this->exactly(2)) ->method('executeCommand') ->with($this->logicalOr($cmdEval, $cmdEvalSha)); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave1); $replication->getReplicationStrategy()->setScriptReadOnly($script); $replication->executeCommand($cmdEval); $replication->executeCommand($cmdEvalSha); } /** * @group disconnected */ public function testExposesReplicationStrategy() { $replication = new MasterSlaveReplication(); $this->assertInstanceOf('Predis\Replication\ReplicationStrategy', $replication->getReplicationStrategy()); $strategy = new ReplicationStrategy(); $replication = new MasterSlaveReplication($strategy); $this->assertSame($strategy, $replication->getReplicationStrategy()); } /** * @group disconnected */ public function testCanBeSerialized() { $master = $this->getMockConnection('tcp://host1?alias=master'); $slave1 = $this->getMockConnection('tcp://host2?alias=slave1'); $replication = new MasterSlaveReplication(); $replication->add($master); $replication->add($slave1); $unserialized = unserialize(serialize($replication)); $this->assertEquals($master, $unserialized->getConnectionById('master')); $this->assertEquals($slave1, $unserialized->getConnectionById('slave1')); } // ******************************************************************** // // ---- HELPER METHODS ------------------------------------------------ // // ******************************************************************** // /** * Returns a base mocked connection from Predis\Connection\SingleConnectionInterface. * * @param mixed $parameters Optional parameters. * @return mixed */ protected function getMockConnection($parameters = null) { $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); 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; } } predis-0.8.3/tests/Predis/Connection/PhpiredisConnectionTest.php000066400000000000000000000102441211043230100250030ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\Profile\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 testExposesParameters() { $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); } /** * @group disconnected */ public function testCanBeSerialized() { $parameters = $this->getParameters(array('alias' => 'redis', 'read_write_timeout' => 10)); $connection = new PhpiredisConnection($parameters); $unserialized = unserialize(serialize($connection)); $this->assertInstanceOf('Predis\Connection\PhpiredisConnection', $unserialized); $this->assertEquals($parameters, $unserialized->getParameters()); } // ******************************************************************** // // ---- 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->assertSame('PONG', $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; } } predis-0.8.3/tests/Predis/Connection/PhpiredisStreamConnectionTest.php000066400000000000000000000115421211043230100261610ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\Profile\ServerProfile; /** * @group ext-phpiredis */ class PhpiredisStreamConnectionTest extends ConnectionTestCase { /** * @group disconnected */ public function testConstructorDoesNotOpenConnection() { $connection = new PhpiredisStreamConnection($this->getParameters()); $this->assertFalse($connection->isConnected()); } /** * @group disconnected */ public function testExposesParameters() { $parameters = $this->getParameters(); $connection = new PhpiredisStreamConnection($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 PhpiredisStreamConnection($parameters); } /** * @group disconnected */ public function testCanBeSerialized() { $parameters = $this->getParameters(array('alias' => 'redis', 'read_write_timeout' => 10)); $connection = new PhpiredisStreamConnection($parameters); $unserialized = unserialize(serialize($connection)); $this->assertInstanceOf('Predis\Connection\PhpiredisStreamConnection', $unserialized); $this->assertEquals($parameters, $unserialized->getParameters()); } // ******************************************************************** // // ---- INTEGRATION TESTS --------------------------------------------- // // ******************************************************************** // /** * @group connected */ public function testAcceptsTcpNodelayParameter() { if (!version_compare(PHP_VERSION, '5.4.0', '>=')) { $this->markTestSkipped('Setting TCP_NODELAY on PHP socket streams works on PHP >= 5.4.0'); } $connection = new PhpiredisStreamConnection($this->getParameters(array('tcp_nodelay' => false))); $connection->connect(); $this->assertTrue($connection->isConnected()); $connection = new PhpiredisStreamConnection($this->getParameters(array('tcp_nodelay' => true))); $connection->connect(); $this->assertTrue($connection->isConnected()); } /** * @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->assertSame('PONG', $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')); fread($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 PhpiredisStreamConnection($parameters); if ($initialize) { $connection->pushInitCommand($profile->createCommand('select', array($parameters->database))); $connection->pushInitCommand($profile->createCommand('flushdb')); } return $connection; } } predis-0.8.3/tests/Predis/Connection/PredisClusterTest.php000066400000000000000000000323631211043230100236320ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\Profile\ServerProfile; /** * */ class PredisClusterTest extends StandardTestCase { /** * @group disconnected */ public function testExposesCommandHashStrategy() { $cluster = new PredisCluster(); $this->assertInstanceOf('Predis\Cluster\PredisClusterHashStrategy', $cluster->getCommandHashStrategy()); } /** * @group disconnected */ public function testAddingConnectionsToCluster() { $connection1 = $this->getMockConnection(); $connection2 = $this->getMockConnection(); $cluster = new PredisCluster(); $cluster->add($connection1); $cluster->add($connection2); $this->assertSame(2, count($cluster)); $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(2, count($cluster)); $this->assertSame($connection1, $cluster->getConnectionById('node1')); $this->assertSame($connection2, $cluster->getConnectionById('node2')); } /** * @group disconnected */ public function testRemovingConnectionsFromCluster() { $connection1 = $this->getMockConnection(); $connection2 = $this->getMockConnection(); $connection3 = $this->getMockConnection(); $cluster = new PredisCluster(); $cluster->add($connection1); $cluster->add($connection2); $this->assertTrue($cluster->remove($connection1)); $this->assertFalse($cluster->remove($connection3)); $this->assertSame(1, count($cluster)); } /** * @group disconnected */ public function testRemovingConnectionsFromClusterByAlias() { $connection1 = $this->getMockConnection(); $connection2 = $this->getMockConnection('tcp://host1:7001?alias=node2'); $connection3 = $this->getMockConnection('tcp://host1:7002?alias=node3'); $connection4 = $this->getMockConnection('tcp://host1:7003?alias=node4'); $cluster = new PredisCluster(); $cluster->add($connection1); $cluster->add($connection2); $cluster->add($connection3); $this->assertTrue($cluster->removeById(0)); $this->assertTrue($cluster->removeById('node2')); $this->assertFalse($cluster->removeById('node4')); $this->assertSame(1, count($cluster)); } /** * @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 use PING with 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); } /** * @group disconnected */ public function testExecuteCommandOnEachNode() { $ping = ServerProfile::getDefault()->createCommand('ping', array()); $connection1 = $this->getMock('Predis\Connection\SingleConnectionInterface'); $connection1->expects($this->once()) ->method('executeCommand') ->with($ping) ->will($this->returnValue(true)); $connection2 = $this->getMock('Predis\Connection\SingleConnectionInterface'); $connection2->expects($this->once()) ->method('executeCommand') ->with($ping) ->will($this->returnValue(false)); $cluster = new PredisCluster(); $cluster->add($connection1); $cluster->add($connection2); $this->assertSame(array(true, false), $cluster->executeCommandOnNodes($ping)); } /** * @group disconnected */ public function testCanBeSerialized() { $connection1 = $this->getMockConnection('tcp://host1?alias=first'); $connection2 = $this->getMockConnection('tcp://host2?alias=second'); $cluster = new PredisCluster(); $cluster->add($connection1); $cluster->add($connection2); // We use the following line to initialize the underlying hashring. $cluster->getConnectionByKey('foo'); $unserialized = unserialize(serialize($cluster)); $this->assertEquals($cluster, $unserialized); } // ******************************************************************** // // ---- HELPER METHODS ------------------------------------------------ // // ******************************************************************** // /** * Returns a base mocked connection from Predis\Connection\SingleConnectionInterface. * * @param mixed $parameters Optional parameters. * @return mixed */ protected function getMockConnection($parameters = null) { $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); 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; } } predis-0.8.3/tests/Predis/Connection/RedisClusterTest.php000066400000000000000000000530401211043230100234450ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\ResponseError; use Predis\Profile\ServerProfile; /** * */ class RedisClusterTest extends StandardTestCase { /** * @group disconnected */ public function testExposesCommandHashStrategy() { $cluster = new RedisCluster(); $this->assertInstanceOf('Predis\Cluster\RedisClusterHashStrategy', $cluster->getCommandHashStrategy()); } /** * @group disconnected */ public function testAddingConnectionsToCluster() { $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $cluster = new RedisCluster(); $cluster->add($connection1); $cluster->add($connection2); $this->assertSame(2, count($cluster)); $this->assertSame($connection1, $cluster->getConnectionById('127.0.0.1:6379')); $this->assertSame($connection2, $cluster->getConnectionById('127.0.0.1:6380')); } /** * @group disconnected */ public function testRemovingConnectionsFromCluster() { $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $connection3 = $this->getMockConnection('tcp://127.0.0.1:6371'); $cluster = new RedisCluster(); $cluster->add($connection1); $cluster->add($connection2); $this->assertTrue($cluster->remove($connection1)); $this->assertFalse($cluster->remove($connection3)); $this->assertSame(1, count($cluster)); } /** * @group disconnected */ public function testRemovingConnectionsFromClusterByAlias() { $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $cluster = new RedisCluster(); $cluster->add($connection1); $cluster->add($connection2); $this->assertTrue($cluster->removeById('127.0.0.1:6380')); $this->assertFalse($cluster->removeById('127.0.0.1:6390')); $this->assertSame(1, count($cluster)); } /** * @group disconnected */ public function testCountReturnsNumberOfConnectionsInPool() { $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $connection3 = $this->getMockConnection('tcp://127.0.0.1:6381'); $cluster = new RedisCluster(); $cluster->add($connection1); $cluster->add($connection2); $cluster->add($connection3); $this->assertSame(3, count($cluster)); $cluster->remove($connection3); $this->assertSame(2, count($cluster)); } /** * @group disconnected */ public function testConnectForcesAllConnectionsToConnect() { $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection1->expects($this->once())->method('connect'); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $connection2->expects($this->once())->method('connect'); $cluster = new RedisCluster(); $cluster->add($connection1); $cluster->add($connection2); $cluster->connect(); } /** * @group disconnected */ public function testDisconnectForcesAllConnectionsToDisconnect() { $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection1->expects($this->once())->method('disconnect'); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $connection2->expects($this->once())->method('disconnect'); $cluster = new RedisCluster(); $cluster->add($connection1); $cluster->add($connection2); $cluster->disconnect(); } /** * @group disconnected */ public function testIsConnectedReturnsTrueIfAtLeastOneConnectionIsOpen() { $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection1->expects($this->once()) ->method('isConnected') ->will($this->returnValue(false)); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $connection2->expects($this->once()) ->method('isConnected') ->will($this->returnValue(true)); $cluster = new RedisCluster(); $cluster->add($connection1); $cluster->add($connection2); $this->assertTrue($cluster->isConnected()); } /** * @group disconnected */ public function testIsConnectedReturnsFalseIfAllConnectionsAreClosed() { $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection1->expects($this->once()) ->method('isConnected') ->will($this->returnValue(false)); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $connection2->expects($this->once()) ->method('isConnected') ->will($this->returnValue(false)); $cluster = new RedisCluster(); $cluster->add($connection1); $cluster->add($connection2); $this->assertFalse($cluster->isConnected()); } /** * @group disconnected */ public function testCanReturnAnIteratorForConnections() { $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $cluster = new RedisCluster(); $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 testCanAssignConnectionsToCustomSlots() { $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $connection3 = $this->getMockConnection('tcp://127.0.0.1:6381'); $cluster = new RedisCluster(); $cluster->add($connection1); $cluster->add($connection2); $cluster->add($connection3); $cluster->setSlots(0, 1364, '127.0.0.1:6379'); $cluster->setSlots(1365, 2729, '127.0.0.1:6380'); $cluster->setSlots(2730, 4095, '127.0.0.1:6381'); $expectedMap = array_merge( array_fill(0, 1365, '127.0.0.1:6379'), array_fill(1364, 1365, '127.0.0.1:6380'), array_fill(2729, 1366, '127.0.0.1:6381') ); $this->assertSame($expectedMap, $cluster->getSlotsMap()); } /** * @group disconnected */ public function testAddingConnectionResetsSlotsMap() { $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $cluster = new RedisCluster(); $cluster->add($connection1); $cluster->setSlots(0, 4095, '127.0.0.1:6379'); $this->assertSame(array_fill(0, 4096, '127.0.0.1:6379'), $cluster->getSlotsMap()); $cluster->add($connection2); $this->assertEmpty($cluster->getSlotsMap()); } /** * @group disconnected */ public function testRemovingConnectionResetsSlotsMap() { $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $cluster = new RedisCluster(); $cluster->add($connection1); $cluster->add($connection2); $cluster->setSlots(0, 2047, '127.0.0.1:6379'); $cluster->setSlots(2048, 4095, '127.0.0.1:6380'); $expectedMap = array_merge( array_fill(0, 2048, '127.0.0.1:6379'), array_fill(2048, 2048, '127.0.0.1:6380') ); $this->assertSame($expectedMap, $cluster->getSlotsMap()); $cluster->remove($connection1); $this->assertEmpty($cluster->getSlotsMap()); } /** * @group disconnected */ public function testCanAssignConnectionsToCustomSlotsFromParameters() { $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379?slots=0-5460'); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380?slots=5461-10921'); $connection3 = $this->getMockConnection('tcp://127.0.0.1:6381?slots=10922-16383'); $cluster = new RedisCluster(); $cluster->add($connection1); $cluster->add($connection2); $cluster->add($connection3); $expectedMap = array_merge( array_fill(0, 5461, '127.0.0.1:6379'), array_fill(5460, 5461, '127.0.0.1:6380'), array_fill(10921, 5462, '127.0.0.1:6381') ); $cluster->buildSlotsMap(); $this->assertSame($expectedMap, $cluster->getSlotsMap()); } /** * @group disconnected */ public function testReturnsCorrectConnectionUsingSlotID() { $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $connection3 = $this->getMockConnection('tcp://127.0.0.1:6381'); $cluster = new RedisCluster(); $cluster->add($connection1); $cluster->add($connection2); $cluster->add($connection3); $this->assertSame($connection1, $cluster->getConnectionBySlot(0)); $this->assertSame($connection2, $cluster->getConnectionBySlot(5461)); $this->assertSame($connection3, $cluster->getConnectionBySlot(10922)); $cluster->setSlots(5461, 7096, '127.0.0.1:6380'); $this->assertSame($connection2, $cluster->getConnectionBySlot(5461)); } /** * @group disconnected */ public function testReturnsCorrectConnectionUsingCommandInstance() { $profile = ServerProfile::getDefault(); $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $connection3 = $this->getMockConnection('tcp://127.0.0.1:6381'); $cluster = new RedisCluster(); $cluster->add($connection1); $cluster->add($connection2); $cluster->add($connection3); $set = $profile->createCommand('set', array('node:1001', 'foobar')); $get = $profile->createCommand('get', array('node:1001')); $this->assertSame($connection1, $cluster->getConnection($set)); $this->assertSame($connection1, $cluster->getConnection($get)); $set = $profile->createCommand('set', array('node:1048', 'foobar')); $get = $profile->createCommand('get', array('node:1048')); $this->assertSame($connection2, $cluster->getConnection($set)); $this->assertSame($connection2, $cluster->getConnection($get)); $set = $profile->createCommand('set', array('node:1082', 'foobar')); $get = $profile->createCommand('get', array('node:1082')); $this->assertSame($connection3, $cluster->getConnection($set)); $this->assertSame($connection3, $cluster->getConnection($get)); } /** * @group disconnected */ public function testWritesCommandToCorrectConnection() { $command = ServerProfile::getDefault()->createCommand('get', array('node:1001')); $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection1->expects($this->once())->method('writeCommand')->with($command); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $connection2->expects($this->never())->method('writeCommand'); $cluster = new RedisCluster(); $cluster->add($connection1); $cluster->add($connection2); $cluster->writeCommand($command); } /** * @group disconnected */ public function testReadsCommandFromCorrectConnection() { $command = ServerProfile::getDefault()->createCommand('get', array('node:1050')); $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection1->expects($this->never())->method('readResponse'); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $connection2->expects($this->once())->method('readResponse')->with($command); $cluster = new RedisCluster(); $cluster->add($connection1); $cluster->add($connection2); $cluster->readResponse($command); } /** * @group disconnected */ public function testDoesNotSupportKeyTags() { $profile = ServerProfile::getDefault(); $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $cluster = new RedisCluster(); $cluster->add($connection1); $cluster->add($connection2); $set = $profile->createCommand('set', array('{node:1001}:foo', 'foobar')); $get = $profile->createCommand('get', array('{node:1001}:foo')); $this->assertSame($connection1, $cluster->getConnection($set)); $this->assertSame($connection1, $cluster->getConnection($get)); $set = $profile->createCommand('set', array('{node:1001}:bar', 'foobar')); $get = $profile->createCommand('get', array('{node:1001}:bar')); $this->assertSame($connection2, $cluster->getConnection($set)); $this->assertSame($connection2, $cluster->getConnection($get)); } /** * @group disconnected */ public function testAskResponseWithConnectionInPool() { $askResponse = new ResponseError('ASK 1970 127.0.0.1:6380'); $command = ServerProfile::getDefault()->createCommand('get', array('node:1001')); $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection1->expects($this->exactly(2)) ->method('executeCommand') ->with($command) ->will($this->onConsecutiveCalls($askResponse, 'foobar')); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $connection2->expects($this->exactly(1)) ->method('executeCommand') ->with($command) ->will($this->returnValue('foobar')); $factory = $this->getMock('Predis\Connection\ConnectionFactory'); $factory->expects($this->never())->method('create'); $cluster = new RedisCluster($factory); $cluster->add($connection1); $cluster->add($connection2); $this->assertSame('foobar', $cluster->executeCommand($command)); $this->assertSame('foobar', $cluster->executeCommand($command)); $this->assertSame(2, count($cluster)); } /** * @group disconnected */ public function testAskResponseWithConnectionNotInPool() { $askResponse = new ResponseError('ASK 1970 127.0.0.1:6381'); $command = ServerProfile::getDefault()->createCommand('get', array('node:1001')); $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection1->expects($this->exactly(2)) ->method('executeCommand') ->with($command) ->will($this->onConsecutiveCalls($askResponse, 'foobar')); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $connection2->expects($this->never()) ->method('executeCommand'); $connection3 = $this->getMockConnection('tcp://127.0.0.1:6381'); $connection3->expects($this->once()) ->method('executeCommand') ->with($command) ->will($this->returnValue('foobar')); $factory = $this->getMock('Predis\Connection\ConnectionFactory'); $factory->expects($this->once()) ->method('create') ->with(array('host' => '127.0.0.1', 'port' => '6381')) ->will($this->returnValue($connection3)); $cluster = new RedisCluster($factory); $cluster->add($connection1); $cluster->add($connection2); $this->assertSame('foobar', $cluster->executeCommand($command)); $this->assertSame('foobar', $cluster->executeCommand($command)); $this->assertSame(2, count($cluster)); } /** * @group disconnected */ public function testMovedResponseWithConnectionInPool() { $movedResponse = new ResponseError('MOVED 1970 127.0.0.1:6380'); $command = ServerProfile::getDefault()->createCommand('get', array('node:1001')); $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection1->expects($this->exactly(1)) ->method('executeCommand') ->with($command) ->will($this->returnValue($movedResponse)); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $connection2->expects($this->exactly(2)) ->method('executeCommand') ->with($command) ->will($this->onConsecutiveCalls('foobar', 'foobar')); $factory = $this->getMock('Predis\Connection\ConnectionFactory'); $factory->expects($this->never())->method('create'); $cluster = new RedisCluster($factory); $cluster->add($connection1); $cluster->add($connection2); $this->assertSame('foobar', $cluster->executeCommand($command)); $this->assertSame('foobar', $cluster->executeCommand($command)); $this->assertSame(2, count($cluster)); } /** * @group disconnected */ public function testMovedResponseWithConnectionNotInPool() { $movedResponse = new ResponseError('MOVED 1970 127.0.0.1:6381'); $command = ServerProfile::getDefault()->createCommand('get', array('node:1001')); $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379'); $connection1->expects($this->once()) ->method('executeCommand') ->with($command) ->will($this->returnValue($movedResponse)); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); $connection2->expects($this->never()) ->method('executeCommand'); $connection3 = $this->getMockConnection('tcp://127.0.0.1:6381'); $connection3->expects($this->exactly(2)) ->method('executeCommand') ->with($command) ->will($this->onConsecutiveCalls('foobar', 'foobar')); $factory = $this->getMock('Predis\Connection\ConnectionFactory'); $factory->expects($this->once()) ->method('create') ->with(array('host' => '127.0.0.1', 'port' => '6381')) ->will($this->returnValue($connection3)); $cluster = new RedisCluster($factory); $cluster->add($connection1); $cluster->add($connection2); $this->assertSame('foobar', $cluster->executeCommand($command)); $this->assertSame('foobar', $cluster->executeCommand($command)); $this->assertSame(3, count($cluster)); } /** * @group disconnected * @expectedException Predis\NotSupportedException * @expectedExceptionMessage Cannot use PING with redis-cluster */ public function testThrowsExceptionOnNonSupportedCommand() { $ping = ServerProfile::getDefault()->createCommand('ping'); $cluster = new RedisCluster(); $cluster->add($this->getMockConnection('tcp://127.0.0.1:6379')); $cluster->getConnection($ping); } /** * @group disconnected */ public function testCanBeSerialized() { $connection1 = $this->getMockConnection('tcp://127.0.0.1:6379?slots=0-1364'); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380?slots=1365-2729'); $connection3 = $this->getMockConnection('tcp://127.0.0.1:6381?slots=2730-4095'); $cluster = new RedisCluster(); $cluster->add($connection1); $cluster->add($connection2); $cluster->add($connection3); $cluster->buildSlotsMap(); $unserialized = unserialize(serialize($cluster)); $this->assertEquals($cluster, $unserialized); } // ******************************************************************** // // ---- HELPER METHODS ------------------------------------------------ // // ******************************************************************** // /** * Returns a base mocked connection from Predis\Connection\SingleConnectionInterface. * * @param mixed $parameters Optional parameters. * @return mixed */ protected function getMockConnection($parameters = null) { $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); 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; } } predis-0.8.3/tests/Predis/Connection/StreamConnectionTest.php000066400000000000000000000105051211043230100243070ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\Profile\ServerProfile; /** * */ class StreamConnectionTest extends ConnectionTestCase { /** * @group disconnected */ public function testConstructorDoesNotOpenConnection() { $connection = new StreamConnection($this->getParameters()); $this->assertFalse($connection->isConnected()); } /** * @group disconnected */ public function testExposesParameters() { $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); } /** * @group disconnected */ public function testCanBeSerialized() { $parameters = $this->getParameters(array('alias' => 'redis', 'read_write_timeout' => 10)); $connection = new StreamConnection($parameters); $unserialized = unserialize(serialize($connection)); $this->assertEquals($connection, $unserialized); } // ******************************************************************** // // ---- INTEGRATION TESTS --------------------------------------------- // // ******************************************************************** // /** * @group connected */ public function testAcceptsTcpNodelayParameter() { if (!version_compare(PHP_VERSION, '5.4.0', '>=')) { $this->markTestSkipped('Setting TCP_NODELAY on PHP socket streams works on PHP >= 5.4.0'); } $connection = new StreamConnection($this->getParameters(array('tcp_nodelay' => false))); $connection->connect(); $this->assertTrue($connection->isConnected()); $connection = new StreamConnection($this->getParameters(array('tcp_nodelay' => true))); $connection->connect(); $this->assertTrue($connection->isConnected()); } /** * @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\Iterator\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; } } predis-0.8.3/tests/Predis/Connection/WebdisConnectionTest.php000066400000000000000000000156571211043230100243060ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Connection; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\Profile\ServerProfile; /** * @group ext-curl * @group ext-phpiredis * @group realm-connection * @group realm-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\Connection\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\Connection\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\Connection\WebdisConnection::read() is not supported */ public function testReadingFromConnectionIsNotSupported() { $connection = new WebdisConnection($this->getParameters()); $connection->read(); } /** * @group disconnected * @expectedException Predis\NotSupportedException * @expectedExceptionMessage The method Predis\Connection\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'))); } /** * @group disconnected */ public function testCanBeSerialized() { $parameters = $this->getParameters(array('alias' => 'webdis')); $connection = new WebdisConnection($parameters); $unserialized = unserialize(serialize($connection)); $this->assertInstanceOf('Predis\Connection\WebdisConnection', $unserialized); $this->assertEquals($parameters, $unserialized->getParameters()); } // ******************************************************************** // // ---- 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->assertSame('PONG', $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\Connection\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; } } predis-0.8.3/tests/Predis/HelpersTest.php000066400000000000000000000042111211043230100203340ustar00rootroot00000000000000 * * 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 testOnCommunicationException() { $this->setExpectedException('Predis\CommunicationException'); $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $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)); } } predis-0.8.3/tests/Predis/Iterator/000077500000000000000000000000001211043230100171545ustar00rootroot00000000000000predis-0.8.3/tests/Predis/Iterator/MultiBulkResponseSimpleTest.php000066400000000000000000000074631211043230100253400ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Iterator; 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\Iterator\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 testIterableMultibulkCanBeWrappedAsTupleIterator() { $client = $this->getClient(); $client->mset('foo', 'bar', 'hoge', 'piyo'); $this->assertInstanceOf('Predis\Iterator\MultiBulkResponseSimple', $iterator = $client->mget('foo', 'bar')); $this->assertInstanceOf('Predis\Iterator\MultiBulkResponseTuple', $iterator->asTuple()); } /** * @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, ); $options = array( 'profile' => REDIS_SERVER_VERSION, ); $client = new Client($parameters, $options); $client->connect(); $client->select(REDIS_SERVER_DBNUM); $client->flushdb(); return $client; } } predis-0.8.3/tests/Predis/Iterator/MultiBulkResponseTupleTest.php000066400000000000000000000073241211043230100251740ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Iterator; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\Client; /** * @group realm-iterators */ class MultiBulkResponseTupleTest extends StandardTestCase { /** * @group disconnected * @expectedException RuntimeException * @expectedExceptionMessage Cannot initialize a tuple iterator with an already initiated iterator */ public function testInitiatedMultiBulkIteratorsAreNotValid() { $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $iterator = new MultiBulkResponseSimple($connection, 2); $iterator->next(); new MultiBulkResponseTuple($iterator); } /** * @group disconnected * @expectedException UnexpectedValueException * @expectedExceptionMessage Invalid reply size for a tuple iterator [3] */ public function testMultiBulkWithOddSizesAreInvalid() { $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $iterator = new MultiBulkResponseSimple($connection, 3); new MultiBulkResponseTuple($iterator); } /** * @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')->asTuple()); $this->assertInstanceOf('Predis\Iterator\MultiBulkResponseTuple', $iterator); $this->assertInstanceOf('Predis\Iterator\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')->asTuple(); 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, ); $options = array( 'profile' => REDIS_SERVER_VERSION, ); $client = new Client($parameters, $options); $client->connect(); $client->select(REDIS_SERVER_DBNUM); $client->flushdb(); return $client; } } predis-0.8.3/tests/Predis/Monitor/000077500000000000000000000000001211043230100170125ustar00rootroot00000000000000predis-0.8.3/tests/Predis/Monitor/MonitorContextTest.php000066400000000000000000000145531211043230100233670ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Monitor; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\Client; use Predis\Profile\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\Profile\ServerProfileInterface'); $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 when using aggregated connections */ public function testMonitorContextDoesNotWorkOnClusters() { $cluster = $this->getMock('Predis\Connection\ClusterConnectionInterface'); $client = new Client($cluster); $monitor = new MonitorContext($client); } /** * @group disconnected */ public function testConstructorOpensContext() { $cmdMonitor = ServerProfile::getDefault()->createCommand('monitor'); $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $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\Connection\SingleConnectionInterface'); $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\Connection\SingleConnectionInterface'); $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 testReadsMessageFromConnectionToRedis24() { $message = '1323367530.939137 (db 15) "MONITOR"'; $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $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->assertNull($payload->client); $this->assertSame('MONITOR', $payload->command); $this->assertNull($payload->arguments); } /** * @group disconnected */ public function testReadsMessageFromConnectionToRedis26() { $message = '1323367530.939137 [15 127.0.0.1:37265] "MONITOR"'; $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $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('127.0.0.1:37265', $payload->client); $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, ); $options = array('profile' => REDIS_SERVER_VERSION); $echoed = array(); $producer = new Client($parameters, $options); $producer->connect(); $consumer = new Client($parameters, $options); $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()); } } predis-0.8.3/tests/Predis/Option/000077500000000000000000000000001211043230100166335ustar00rootroot00000000000000predis-0.8.3/tests/Predis/Option/AbstractOptionTest.php000066400000000000000000000044131211043230100231420ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class AbstractOptionTest extends StandardTestCase { /** * @group disconnected */ public function testValidationReturnsTheSameObject() { $value = new \stdClass(); $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = $this->getMockForAbstractClass('Predis\Option\AbstractOption'); $this->assertSame($value, $option->filter($options, $value)); } /** * @group disconnected */ public function testDefaultReturnsNull() { $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = $this->getMockForAbstractClass('Predis\Option\AbstractOption'); $this->assertNull($option->getDefault($options)); } /** * @group disconnected */ public function testInvokePerformsValidationWhenValueIsSet() { $value = new \stdClass(); $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = $this->getMock('Predis\Option\AbstractOption', array('filter', 'getDefault')); $option->expects($this->once()) ->method('filter') ->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\Option\ClientOptionsInterface'); $option = $this->getMock('Predis\Option\AbstractOption', array('filter', 'getDefault')); $option->expects($this->never())->method('filter'); $option->expects($this->once()) ->method('getDefault') ->with($options) ->will($this->returnValue($expected)); $this->assertSame($expected, $option($options, null)); } } predis-0.8.3/tests/Predis/Option/ClientClusterTest.php000066400000000000000000000072261211043230100227730ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class ClientClusterTest extends StandardTestCase { /** * @group disconnected */ public function testValidationAcceptsFQNStringAsInitializer() { $clusterClass = get_class($this->getMock('Predis\Connection\ClusterConnectionInterface')); $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientCluster(); $cluster = $option->filter($options, $clusterClass); $this->assertInstanceOf('Predis\Connection\ClusterConnectionInterface', $cluster); } /** * @group disconnected */ public function testValidationRecognizesCertainPredefinedShortNames() { $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientCluster(); $cluster = $option->filter($options, 'predis'); $this->assertInstanceOf('Predis\Connection\ClusterConnectionInterface', $cluster); } /** * @group disconnected */ public function testValidationAcceptsCallableObjectAsInitializers() { $value = $this->getMock('Predis\Connection\ClusterConnectionInterface'); $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientCluster(); $initializer = $this->getMock('stdClass', array('__invoke')); $initializer->expects($this->once()) ->method('__invoke') ->with($this->isInstanceOf('Predis\Option\ClientOptionsInterface'), $option) ->will($this->returnValue($value)); $cluster = $option->filter($options, $initializer, $option); $this->assertInstanceOf('Predis\Connection\ClusterConnectionInterface', $cluster); $this->assertSame($value, $cluster); } /** * @group disconnected */ public function testValidationThrowsExceptionOnInvalidClassTypes() { $this->setExpectedException('InvalidArgumentException'); $connectionClass = get_class($this->getMock('Predis\Connection\SingleConnectionInterface')); $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientCluster(); $option->filter($options, $connectionClass); } /** * @group disconnected */ public function testValidationThrowsExceptionOnInvalidShortName() { $this->setExpectedException('InvalidArgumentException'); $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientCluster(); $option->filter($options, 'unknown'); } /** * @group disconnected */ public function testValidationThrowsExceptionOnInvalidObjectReturnedByCallback() { $this->setExpectedException('InvalidArgumentException'); $value = function ($options) { return new \stdClass(); }; $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientCluster(); $option->filter($options, $value); } /** * @group disconnected */ public function testValidationThrowsExceptionOnInvalidArguments() { $this->setExpectedException('InvalidArgumentException'); $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientCluster(); $option->filter($options, new \stdClass()); } } predis-0.8.3/tests/Predis/Option/ClientConnectionFactoryTest.php000066400000000000000000000114731211043230100250000ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\Connection\ConnectionFactory; /** * */ class ClientConnectionFactoryTest extends StandardTestCase { /** * @group disconnected */ public function testValidationReturnsDefaultFactoryWithSchemeDefinitionsArray() { $connectionClass = get_class($this->getMock('Predis\Connection\SingleConnectionInterface')); $value = array('tcp' => $connectionClass, 'redis' => $connectionClass); $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $default = $this->getMock('Predis\Connection\ConnectionFactoryInterface'); $default->expects($this->exactly(2)) ->method('define') ->with($this->matchesRegularExpression('/^tcp|redis$/'), $connectionClass); $option = $this->getMock('Predis\Option\ClientConnectionFactory', array('getDefault')); $option->expects($this->once()) ->method('getDefault') ->with($options) ->will($this->returnValue($default)); $factory = $option->filter($options, $value); $this->assertInstanceOf('Predis\Connection\ConnectionFactoryInterface', $factory); $this->assertSame($default, $factory); } /** * @group disconnected */ public function testValidationAcceptsFactoryInstancesAsValue() { $value = $this->getMock('Predis\Connection\ConnectionFactoryInterface'); $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = $this->getMock('Predis\Option\ClientConnectionFactory', array('getDefault')); $option->expects($this->never())->method('getDefault'); $this->assertSame($value, $option->filter($options, $value)); } /** * @group disconnected */ public function testValidationAcceptsCallableObjectAsInitializers() { $value = $this->getMock('Predis\Connection\ConnectionFactoryInterface'); $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientConnectionFactory(); $initializer = $this->getMock('stdClass', array('__invoke')); $initializer->expects($this->once()) ->method('__invoke') ->with($this->isInstanceOf('Predis\Option\ClientOptionsInterface'), $option) ->will($this->returnValue($value)); $cluster = $option->filter($options, $initializer, $option); $this->assertInstanceOf('Predis\Connection\ConnectionFactoryInterface', $cluster); $this->assertSame($value, $cluster); } /** * @group disconnected */ public function testValidationAcceptsStringAsValue() { $factory = 'Predis\Connection\ConnectionFactory'; $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = $this->getMock('Predis\Option\ClientConnectionFactory', array('getDefault')); $option->expects($this->never())->method('getDefault'); $this->assertInstanceOf($factory, $option->filter($options, $factory)); } /** * @group disconnected */ public function testValidationThrowsExceptionOnWrongInvalidArguments() { $this->setExpectedException('InvalidArgumentException'); $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientConnectionFactory(); $option->filter($options, new \stdClass()); } /** * @group disconnected */ public function testInvokeReturnsSpecifiedFactoryOrDefault() { $value = $this->getMock('Predis\Connection\ConnectionFactoryInterface'); $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = $this->getMock('Predis\Option\ClientConnectionFactory', array('filter', 'getDefault')); $option->expects($this->once()) ->method('filter') ->with($options, $value) ->will($this->returnValue($value)); $option->expects($this->never())->method('getDefault'); $this->assertInstanceOf('Predis\Connection\ConnectionFactoryInterface', $option($options, $value)); $option = $this->getMock('Predis\Option\ClientConnectionFactory', array('filter', 'getDefault')); $option->expects($this->never())->method('filter'); $option->expects($this->once()) ->method('getDefault') ->with($options) ->will($this->returnValue($value)); $this->assertInstanceOf('Predis\Connection\ConnectionFactoryInterface', $option($options, null)); } } predis-0.8.3/tests/Predis/Option/ClientExceptionsTest.php000066400000000000000000000012301211043230100234600ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class ClientExceptionsTest extends StandardTestCase { /** * @group disconnected */ public function testDefaultReturnsTrue() { $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientExceptions(); $this->assertTrue($option->getDefault($options)); } } predis-0.8.3/tests/Predis/Option/ClientOptionsTest.php000066400000000000000000000071621211043230100230040ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; 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\Connection\ConnectionFactoryInterface', $options->connections); $this->assertInstanceOf('Predis\Profile\ServerProfileInterface', $options->profile); $this->assertInstanceOf('Predis\Connection\ClusterConnectionInterface', $options->cluster); $this->assertNull($options->prefix); } /** * @group disconnected */ public function testConstructorWithArrayArgument() { $options = new ClientOptions(array( 'cluster' => 'Predis\Connection\PredisCluster', 'connections' => 'Predis\Connection\ConnectionFactory', 'prefix' => 'prefix:', 'profile' => '2.0', 'exceptions' => false, )); $this->assertInstanceOf('Predis\Connection\ConnectionFactoryInterface', $options->connections); $this->assertInstanceOf('Predis\Profile\ServerProfileInterface', $options->profile); $this->assertInstanceOf('Predis\Connection\ClusterConnectionInterface', $options->cluster); $this->assertInstanceOf('Predis\Command\Processor\CommandProcessorInterface', $options->prefix); $this->assertInternalType('bool', $options->exceptions); } /** * @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)); } /** * @group disconnected */ public function testGetDefaultUsingOptionName() { $options = new ClientOptions(); $this->assertInstanceOf('Predis\Connection\PredisCluster', $options->getDefault('cluster')); } /** * @group disconnected */ public function testGetDefaultUsingUnhandledOptionName() { $options = new ClientOptions(); $option = new ClientCluster(); $this->assertNull($options->getDefault('foo')); } /** * @group disconnected */ public function testGetDefaultUsingOptionInstance() { $options = new ClientOptions(); $option = new ClientCluster(); $this->assertInstanceOf('Predis\Connection\PredisCluster', $options->getDefault($option)); } /** * @group disconnected */ public function testGetDefaultUsingUnhandledOptionInstance() { $options = new ClientOptions(); $option = new CustomOption(array( 'default' => function ($options) { return 'foo'; }, )); $this->assertSame('foo', $options->getDefault($option)); } } predis-0.8.3/tests/Predis/Option/ClientPrefixTest.php000066400000000000000000000031151211043230100226000ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class ClientPrefixTest extends StandardTestCase { /** * @group disconnected */ public function testValidationReturnsCommandProcessor() { $value = 'prefix:'; $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientPrefix(); $return = $option->filter($options, $value); $this->assertInstanceOf('Predis\Command\Processor\CommandProcessorInterface', $return); $this->assertInstanceOf('Predis\Command\Processor\KeyPrefixProcessor', $return); $this->assertEquals($value, $return->getPrefix()); } /** * @group disconnected */ public function testDefaultReturnsNull() { $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientPrefix(); $this->assertNull($option->getDefault($options)); } /** * @group disconnected */ public function testInvokeReturnsCommandProcessorOrNull() { $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientPrefix(); $this->assertInstanceOf('Predis\Command\Processor\CommandProcessorInterface', $option($options, 'prefix:')); $this->assertNull($option($options, null)); } } predis-0.8.3/tests/Predis/Option/ClientProfileTest.php000066400000000000000000000161201211043230100227430ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\Command\Processor\KeyPrefixProcessor; use Predis\Profile\ServerProfile; /** * */ class ClientProfileTest extends StandardTestCase { /** * @group disconnected */ public function testValidationReturnsServerProfileWithStringValue() { $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientProfile(); $profile = $option->filter($options, '2.0'); $this->assertInstanceOf('Predis\Profile\ServerProfileInterface', $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\Option\ClientOptionsInterface'); $option = new ClientProfile(); $profile = $option->filter($options, $value); $this->assertInstanceOf('Predis\Profile\ServerProfileInterface', $profile); $this->assertEquals('2.0', $profile->getVersion()); $this->assertNull($profile->getProcessor()); } /** * @group disconnected */ public function testValidationAcceptsCallableObjectAsInitializers() { $value = $this->getMock('Predis\Profile\ServerProfileInterface'); $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientProfile(); $initializer = $this->getMock('stdClass', array('__invoke')); $initializer->expects($this->once()) ->method('__invoke') ->with($this->isInstanceOf('Predis\Option\ClientOptionsInterface'), $option) ->will($this->returnValue($value)); $profile = $option->filter($options, $initializer, $option); $this->assertInstanceOf('Predis\Profile\ServerProfileInterface', $profile); $this->assertSame($value, $profile); } /** * @group disconnected */ public function testValidationThrowsExceptionOnWrongInvalidArguments() { $this->setExpectedException('InvalidArgumentException'); $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientProfile(); $option->filter($options, new \stdClass()); } /** * @group disconnected */ public function testDefaultReturnsDefaultServerProfile() { $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientProfile(); $profile = $option->getDefault($options); $this->assertInstanceOf('Predis\Profile\ServerProfileInterface', $profile); $this->assertInstanceOf(get_class(ServerProfile::getDefault()), $profile); $this->assertNull($profile->getProcessor()); } /** * @group disconnected */ public function testInvokeReturnsSpecifiedServerProfileOrDefault() { $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientProfile(); $profile = $option($options, '2.0'); $this->assertInstanceOf('Predis\Profile\ServerProfileInterface', $profile); $this->assertEquals('2.0', $profile->getVersion()); $this->assertNull($profile->getProcessor()); $profile = $option($options, null); $this->assertInstanceOf('Predis\Profile\ServerProfileInterface', $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 testFilterSetsPrefixProcessorFromClientOptions() { $options = $this->getMock('Predis\Option\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->filter($options, '2.0'); $this->assertInstanceOf('Predis\Profile\ServerProfileInterface', $profile); $this->assertEquals('2.0', $profile->getVersion()); $this->assertInstanceOf('Predis\Command\Processor\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\Option\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\Profile\ServerProfileInterface', $profile); $this->assertInstanceOf(get_class(ServerProfile::getDefault()), $profile); $this->assertInstanceOf('Predis\Command\Processor\KeyPrefixProcessor', $profile->getProcessor()); $this->assertEquals('prefix:', $profile->getProcessor()->getPrefix()); } /** * @group disconnected */ public function testValidationDoesNotSetPrefixProcessorWhenValueIsProfileInstance() { $options = $this->getMock('Predis\Option\ClientOptions', array('__isset', '__get')); $options->expects($this->never())->method('__isset'); $options->expects($this->never())->method('__get'); $option = new ClientProfile(); $profile = $option->filter($options, ServerProfile::getDefault()); $this->assertInstanceOf('Predis\Profile\ServerProfileInterface', $profile); $this->assertNull($profile->getProcessor()); } /** * @group disconnected * @expectedException InvalidArgumentException * @expectedExceptionMessage Invalid value for the profile option */ public function testValidationThrowsExceptionOnInvalidObjectReturnedByCallback() { $value = function ($options) { return new \stdClass(); }; $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientProfile(); $option->filter($options, $value); } } predis-0.8.3/tests/Predis/Option/ClientReplicationTest.php000066400000000000000000000061141211043230100236160ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class ClientReplicationTest extends StandardTestCase { /** * @group disconnected */ public function testValidationAcceptsFQNStringAsInitializer() { $replicationClass = get_class($this->getMock('Predis\Connection\ReplicationConnectionInterface')); $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientReplication(); $replication = $option->filter($options, $replicationClass); $this->assertInstanceOf('Predis\Connection\ReplicationConnectionInterface', $replication); } /** * @group disconnected */ public function testValidationAcceptsBooleanValue() { $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientReplication(); $replication = $option->filter($options, true); $this->assertInstanceOf('Predis\Connection\ReplicationConnectionInterface', $replication); $replication = $option->filter($options, false); $this->assertNull($replication); } /** * @group disconnected */ public function testValidationAcceptsCallableObjectAsInitializers() { $value = $this->getMock('Predis\Connection\ReplicationConnectionInterface'); $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientReplication(); $initializer = $this->getMock('stdClass', array('__invoke')); $initializer->expects($this->once()) ->method('__invoke') ->with($this->isInstanceOf('Predis\Option\ClientOptionsInterface'), $option) ->will($this->returnValue($value)); $replication = $option->filter($options, $initializer, $option); $this->assertInstanceOf('Predis\Connection\ReplicationConnectionInterface', $replication); $this->assertSame($value, $replication); } /** * @group disconnected * @expectedException InvalidArgumentException */ public function testValidationThrowsExceptionOnInvalidObjectReturnedByCallback() { $value = function ($options) { return new \stdClass(); }; $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientReplication(); $option->filter($options, $value); } /** * @group disconnected * @expectedException InvalidArgumentException */ public function testValidationThrowsExceptionOnInvalidClassTypes() { $connectionClass = get_class($this->getMock('Predis\Connection\SingleConnectionInterface')); $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new ClientReplication(); $option->filter($options, $connectionClass); } } predis-0.8.3/tests/Predis/Option/CustomOptionTest.php000066400000000000000000000061771211043230100226620ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Option; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class CustomOptionTest extends StandardTestCase { /** * @group disconnected * @expectedException InvalidArgumentException */ public function testConstructorAcceptsOnlyCallablesForFilter() { $option = new CustomOption(array('filter' => 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 testFilterWithoutCallbackReturnsValue() { $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new CustomOption(); $this->assertEquals('test', $option->filter($options, 'test')); } /** * @group disconnected */ public function testDefaultWithoutCallbackReturnsNull() { $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $option = new CustomOption(); $this->assertNull($option->getDefault($options)); } /** * @group disconnected */ public function testInvokeCallsFilterCallback() { $value = 'test'; $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $filter = $this->getMock('stdClass', array('__invoke')); $filter->expects($this->once()) ->method('__invoke') ->with($this->isInstanceOf('Predis\Option\ClientOptionsInterface'), $value) ->will($this->returnValue(true)); $default = $this->getMock('stdClass', array('__invoke')); $default->expects($this->never())->method('__invoke'); $option = new CustomOption(array('filter' => $filter, 'default' => $default)); $this->assertTrue($option($options, $value)); } /** * @group disconnected */ public function testInvokeCallsDefaultCallback() { $options = $this->getMock('Predis\Option\ClientOptionsInterface'); $filter = $this->getMock('stdClass', array('__invoke')); $filter->expects($this->never())->method('__invoke'); $default = $this->getMock('stdClass', array('__invoke')); $default->expects($this->once()) ->method('__invoke') ->with($this->isInstanceOf('Predis\Option\ClientOptionsInterface')) ->will($this->returnValue(true)); $option = new CustomOption(array('filter' => $filter, 'default' => $default)); $this->assertTrue($option($options, null)); } } predis-0.8.3/tests/Predis/Pipeline/000077500000000000000000000000001211043230100171305ustar00rootroot00000000000000predis-0.8.3/tests/Predis/Pipeline/FireAndForgetExecutorTest.php000066400000000000000000000047301211043230100247030ustar00rootroot00000000000000 * * 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 SplQueue; use Predis\Profile\ServerProfile; /** * */ class FireAndForgetExecutorTest extends StandardTestCase { /** * @group disconnected */ public function testExecutorWithSingleConnection() { $executor = new FireAndForgetExecutor(); $pipeline = $this->getCommandsQueue(); $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $connection->expects($this->exactly(3)) ->method('writeCommand'); $connection->expects($this->never()) ->method('readResponse'); $replies = $executor->execute($connection, $pipeline); $this->assertTrue($pipeline->isEmpty()); $this->assertEmpty($replies); } /** * @group disconnected */ public function testExecutorWithReplicationConnection() { $executor = new FireAndForgetExecutor(); $pipeline = $this->getCommandsQueue(); $connection = $this->getMock('Predis\Connection\ReplicationConnectionInterface'); $connection->expects($this->once()) ->method('switchTo') ->with('master'); $connection->expects($this->exactly(3)) ->method('writeCommand'); $connection->expects($this->never()) ->method('readResponse'); $replies = $executor->execute($connection, $pipeline); $this->assertTrue($pipeline->isEmpty()); $this->assertEmpty($replies); } // ******************************************************************** // // ---- HELPER METHODS ------------------------------------------------ // // ******************************************************************** // /** * Returns a list of queued command instances. * * @return SplQueue */ protected function getCommandsQueue() { $profile = ServerProfile::getDevelopment(); $pipeline = new SplQueue(); $pipeline->enqueue($profile->createCommand('ping')); $pipeline->enqueue($profile->createCommand('ping')); $pipeline->enqueue($profile->createCommand('ping')); return $pipeline; } } predis-0.8.3/tests/Predis/Pipeline/MultiExecExecutorTest.php000066400000000000000000000143351211043230100241250ustar00rootroot00000000000000 * * 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 ArrayIterator; use SplQueue; use Predis\ResponseError; use Predis\ResponseObjectInterface; use Predis\ResponseQueued; use Predis\Profile\ServerProfile; /** * */ class ResponseIteratorStub extends ArrayIterator implements ResponseObjectInterface { } /** * */ class MultiExecExecutorTest extends StandardTestCase { /** * @group disconnected */ public function testExecutorWithSingleConnection() { $executor = new MultiExecExecutor(); $pipeline = $this->getCommandsQueue(); $queued = new ResponseQueued(); $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $connection->expects($this->exactly(2)) ->method('executeCommand') ->will($this->onConsecutiveCalls(true, array('PONG', 'PONG', 'PONG'))); $connection->expects($this->exactly(3)) ->method('writeCommand'); $connection->expects($this->at(3)) ->method('readResponse') ->will($this->onConsecutiveCalls($queued, $queued, $queued)); $replies = $executor->execute($connection, $pipeline); $this->assertTrue($pipeline->isEmpty()); $this->assertSame(array(true, true, true), $replies); } /** * @group disconnected */ public function testExecutorWithSingleConnectionReturningIterator() { $executor = new MultiExecExecutor(); $pipeline = $this->getCommandsQueue(); $queued = new ResponseQueued(); $execResponse = new ResponseIteratorStub(array('PONG', 'PONG', 'PONG')); $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $connection->expects($this->exactly(2)) ->method('executeCommand') ->will($this->onConsecutiveCalls(true, $execResponse)); $connection->expects($this->exactly(3)) ->method('writeCommand'); $connection->expects($this->at(3)) ->method('readResponse') ->will($this->onConsecutiveCalls($queued, $queued, $queued)); $replies = $executor->execute($connection, $pipeline); $this->assertTrue($pipeline->isEmpty()); $this->assertSame(array(true, true, true), $replies); } /** * @group disconnected * @expectedException Predis\ClientException * @expectedExceptionMessage The underlying transaction has been aborted by the server */ public function testExecutorWithAbortedTransaction() { $executor = new MultiExecExecutor(); $pipeline = $this->getCommandsQueue(); $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $connection->expects($this->exactly(2)) ->method('executeCommand') ->will($this->onConsecutiveCalls(true, null)); $executor->execute($connection, $pipeline); } /** * @group disconnected * @expectedException Predis\ServerException * @expectedExceptionMessage ERR Test error */ public function testExecutorWithErrorInTransaction() { $executor = new MultiExecExecutor(); $pipeline = $this->getCommandsQueue(); $queued = new ResponseQueued(); $error = new ResponseError('ERR Test error'); $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $connection->expects($this->at(0)) ->method('executeCommand') ->will($this->returnValue(true)); $connection->expects($this->exactly(3)) ->method('readResponse') ->will($this->onConsecutiveCalls($queued, $queued, $error)); $connection->expects($this->at(7)) ->method('executeCommand') ->with($this->isInstanceOf('Predis\Command\TransactionDiscard')); $executor->execute($connection, $pipeline); } /** * @group disconnected */ public function testExecutorWithErrorInCommandResponse() { $executor = new MultiExecExecutor(); $pipeline = $this->getCommandsQueue(); $queued = new ResponseQueued(); $error = new ResponseError('ERR Test error'); $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $connection->expects($this->exactly(3)) ->method('readResponse') ->will($this->onConsecutiveCalls($queued, $queued, $queued)); $connection->expects($this->at(7)) ->method('executeCommand') ->will($this->returnValue(array('PONG', 'PONG', $error))); $replies = $executor->execute($connection, $pipeline); $this->assertSame(array(true, true, $error), $replies); } /** * @group disconnected * @expectedException Predis\ClientException * @expectedExceptionMessage Predis\Pipeline\MultiExecExecutor can be used only with single connections */ public function testExecutorWithAggregatedConnection() { $executor = new MultiExecExecutor(); $pipeline = $this->getCommandsQueue(); $connection = $this->getMock('Predis\Connection\ReplicationConnectionInterface'); $replies = $executor->execute($connection, $pipeline); } // ******************************************************************** // // ---- HELPER METHODS ------------------------------------------------ // // ******************************************************************** // /** * Returns a list of queued command instances. * * @return SplQueue */ protected function getCommandsQueue() { $profile = ServerProfile::getDevelopment(); $pipeline = new SplQueue(); $pipeline->enqueue($profile->createCommand('ping')); $pipeline->enqueue($profile->createCommand('ping')); $pipeline->enqueue($profile->createCommand('ping')); return $pipeline; } } predis-0.8.3/tests/Predis/Pipeline/PipelineContextTest.php000066400000000000000000000312511211043230100236150ustar00rootroot00000000000000 * * 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\Profile\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 testConstructorWithExecutorArgument() { $client = new Client(); $executor = $this->getMock('Predis\Pipeline\PipelineExecutorInterface'); $pipeline = new PipelineContext($client, $executor); $this->assertSame($executor, $pipeline->getExecutor()); } /** * @group disconnected */ public function testCallDoesNotSendCommandsWithoutExecute() { $executor = $this->getMock('Predis\Pipeline\PipelineExecutorInterface'); $executor->expects($this->never())->method('executor'); $pipeline = new PipelineContext(new Client(), $executor); $pipeline->echo('one'); $pipeline->echo('two'); $pipeline->echo('three'); } /** * @group disconnected */ public function testCallReturnsPipelineForFluentInterface() { $executor = $this->getMock('Predis\Pipeline\PipelineExecutorInterface'); $executor->expects($this->never())->method('executor'); $pipeline = new PipelineContext(new Client(), $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\PipelineExecutorInterface'); $executor->expects($this->never())->method('executor'); $pipeline = new PipelineContext(new Client(), $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\PipelineExecutorInterface'); $executor->expects($this->never())->method('executor'); $pipeline = new PipelineContext(new Client(), $executor); $this->assertSame(array(), $pipeline->execute()); } /** * @group disconnected */ public function testExecuteWithFilledBuffer() { $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $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\PipelineExecutorInterface'); $executor->expects($this->never())->method('executor'); $pipeline = new PipelineContext(new Client(), $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\Connection\SingleConnectionInterface'); $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\Connection\SingleConnectionInterface'); $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\Connection\SingleConnectionInterface'); $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 testOutOfBandMessagesInsidePipeline() { $oob = null; $client = $this->getClient(); $results = $client->pipeline(function ($pipe) use (&$oob) { $pipe->set('foo', 'bar'); $oob = $pipe->getClient()->echo('oob message'); $pipe->get('foo'); }); $this->assertSame(array(true, 'bar'), $results); $this->assertSame('oob message', $oob); $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(), array('exceptions' => 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 array Additional client options. * @return Client New client instance. */ protected function getClient(Array $parameters = array(), Array $options = array()) { $parameters = array_merge(array( 'scheme' => 'tcp', 'host' => REDIS_SERVER_HOST, 'port' => REDIS_SERVER_PORT, 'database' => REDIS_SERVER_DBNUM, ), $parameters); $options = array_merge(array( 'profile' => REDIS_SERVER_VERSION, ), $options); $client = new Client($parameters, $options); $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; }; } } predis-0.8.3/tests/Predis/Pipeline/StandardExecutorTest.php000066400000000000000000000116051211043230100237630ustar00rootroot00000000000000 * * 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 SplQueue; use Predis\ResponseError; use Predis\ResponseObjectInterface; use Predis\Profile\ServerProfile; /** * */ class StandardExecutorTest extends StandardTestCase { /** * @group disconnected */ public function testExecutorWithSingleConnection() { $executor = new StandardExecutor(); $pipeline = $this->getCommandsQueue(); $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $connection->expects($this->exactly(3)) ->method('writeCommand'); $connection->expects($this->exactly(3)) ->method('readResponse') ->will($this->returnValue('PONG')); $replies = $executor->execute($connection, $pipeline); $this->assertTrue($pipeline->isEmpty()); $this->assertSame(array(true, true, true), $replies); } /** * @group disconnected */ public function testExecutorWithReplicationConnection() { $executor = new StandardExecutor(); $pipeline = $this->getCommandsQueue(); $connection = $this->getMock('Predis\Connection\ReplicationConnectionInterface'); $connection->expects($this->once()) ->method('switchTo') ->with('master'); $connection->expects($this->exactly(3)) ->method('writeCommand'); $connection->expects($this->exactly(3)) ->method('readResponse') ->will($this->returnValue('PONG')); $replies = $executor->execute($connection, $pipeline); $this->assertTrue($pipeline->isEmpty()); $this->assertSame(array(true, true, true), $replies); } /** * @group disconnected */ public function testExecutorDoesNotParseResponseObjects() { $executor = new StandardExecutor(); $response = $this->getMock('Predis\ResponseObjectInterface'); $this->simpleResponseObjectTest($executor, $response); } /** * @group disconnected */ public function testExecutorCanReturnRedisErrors() { $executor = new StandardExecutor(false); $response = $this->getMock('Predis\ResponseErrorInterface'); $this->simpleResponseObjectTest($executor, $response); } /** * @group disconnected * @expectedException Predis\ServerException * @expectedExceptionMessage ERR Test error */ public function testExecutorCanThrowExceptions() { $executor = new StandardExecutor(true); $pipeline = $this->getCommandsQueue(); $error = new ResponseError('ERR Test error'); $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $connection->expects($this->once()) ->method('readResponse') ->will($this->returnValue($error)); $executor->execute($connection, $pipeline); } // ******************************************************************** // // ---- HELPER METHODS ------------------------------------------------ // // ******************************************************************** // /** * Executes a test for the Predis\ResponseObjectInterface type. * * @param PipelineExecutorInterface $executor * @param ResponseObjectInterface $response */ protected function simpleResponseObjectTest(PipelineExecutorInterface $executor, ResponseObjectInterface $response) { $pipeline = new SplQueue(); $command = $this->getMock('Predis\Command\CommandInterface'); $command->expects($this->never()) ->method('parseResponse'); $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $connection->expects($this->once()) ->method('writeCommand'); $connection->expects($this->once()) ->method('readResponse') ->will($this->returnValue($response)); $pipeline->enqueue($command); $replies = $executor->execute($connection, $pipeline); $this->assertTrue($pipeline->isEmpty()); $this->assertSame(array($response), $replies); } /** * Returns a list of queued command instances. * * @return SplQueue */ protected function getCommandsQueue() { $profile = ServerProfile::getDevelopment(); $pipeline = new SplQueue(); $pipeline->enqueue($profile->createCommand('ping')); $pipeline->enqueue($profile->createCommand('ping')); $pipeline->enqueue($profile->createCommand('ping')); return $pipeline; } } predis-0.8.3/tests/Predis/PredisExceptionTest.php000066400000000000000000000013221211043230100220370ustar00rootroot00000000000000 * * 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; } } predis-0.8.3/tests/Predis/Profile/000077500000000000000000000000001211043230100167635ustar00rootroot00000000000000predis-0.8.3/tests/Predis/Profile/ServerProfileTest.php000066400000000000000000000211551211043230100231270ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Profile; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\Command\Processor\ProcessorChain; /** * */ class ServerProfileTest extends StandardTestCase { const DEFAULT_PROFILE_VERSION = '2.6'; const DEVELOPMENT_PROFILE_VERSION = '2.8'; /** * @group disconnected */ public function testGetVersion() { $profile = ServerProfile::get('2.0'); $this->assertInstanceOf('Predis\Profile\ServerProfileInterface', $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\Profile\ServerProfileInterface', $profile1); $this->assertInstanceOf('Predis\Profile\ServerProfileInterface', $profile2); $this->assertInstanceOf('Predis\Profile\ServerProfileInterface', $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\Profile\ServerProfileInterface', $profile1); $this->assertInstanceOf('Predis\Profile\ServerProfileInterface', $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\Profile\ServerProfileInterface')); 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\Command\ConnectionPing', $profile->getCommandClass('ping')); $this->assertSame('Predis\Command\ConnectionPing', $profile->getCommandClass('PING')); $this->assertNull($profile->getCommandClass('unknown')); $this->assertNull($profile->getCommandClass('UNKNOWN')); } /** * @group disconnected */ public function testDefineCommand() { $profile = ServerProfile::getDefault(); $command = $this->getMock('Predis\Command\CommandInterface'); $profile->defineCommand('mock', get_class($command)); $this->assertTrue($profile->supportsCommand('mock')); $this->assertTrue($profile->supportsCommand('MOCK')); $this->assertSame(get_class($command), $profile->getCommandClass('mock')); } /** * @group disconnected * @expectedException InvalidArgumentException * @expectedExceptionMessage Cannot register 'stdClass' as it is not a valid Redis command */ public function testDefineInvalidCommand() { $profile = ServerProfile::getDefault(); $profile->defineCommand('mock', 'stdClass'); } /** * @group disconnected */ public function testCreateCommandWithoutArguments() { $profile = ServerProfile::getDefault(); $command = $profile->createCommand('info'); $this->assertInstanceOf('Predis\Command\CommandInterface', $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\Command\CommandInterface', $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\Command\Processor\CommandProcessorInterface'); $profile = ServerProfile::getDefault(); $profile->setProcessor($processor); $this->assertSame($processor, $profile->getProcessor()); } /** * @group disconnected */ public function testSetAndUnsetProcessor() { $processor = $this->getMock('Predis\Command\Processor\CommandProcessorInterface'); $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\Command\Processor\CommandProcessorInterface'); $processor->expects($this->once()) ->method('process') ->with($this->isInstanceOf('Predis\Command\CommandInterface')) ->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\Command\Processor\CommandProcessorInterface'); $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'); } } predis-0.8.3/tests/Predis/Profile/ServerVersion12Test.php000066400000000000000000000052651211043230100233230ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Profile; /** * */ 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', ); } } predis-0.8.3/tests/Predis/Profile/ServerVersion20Test.php000066400000000000000000000071231211043230100233150ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Profile; /** * */ 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', ); } } predis-0.8.3/tests/Predis/Profile/ServerVersion22Test.php000066400000000000000000000100331211043230100233110ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Profile; /** * */ 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', ); } } predis-0.8.3/tests/Predis/Profile/ServerVersion24Test.php000066400000000000000000000100701211043230100233140ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Profile; /** * */ 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', ); } } predis-0.8.3/tests/Predis/Profile/ServerVersion26Test.php000066400000000000000000000106371211043230100233270ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Profile; /** * */ class ServerVersion26Test extends ServerVersionTestCase { /** * {@inheritdoc} */ public function getProfileInstance() { return new ServerVersion26(); } /** * {@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 => 'bitop', 127 => 'bitcount', 128 => 'hincrbyfloat', 129 => 'eval', 130 => 'evalsha', 131 => 'script', 132 => 'time', ); } } predis-0.8.3/tests/Predis/Profile/ServerVersionNextTest.php000066400000000000000000000106431211043230100240130ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Profile; /** * */ class ServerVersionNextTest extends ServerVersionTestCase { /** * {@inheritdoc} */ public function getProfileInstance() { return new ServerVersionNext(); } /** * {@inheritdoc} */ public function getExpectedVersion() { return '2.8'; } /** * {@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 => 'bitop', 127 => 'bitcount', 128 => 'hincrbyfloat', 129 => 'eval', 130 => 'evalsha', 131 => 'script', 132 => 'time', ); } } predis-0.8.3/tests/Predis/Protocol/000077500000000000000000000000001211043230100171645ustar00rootroot00000000000000predis-0.8.3/tests/Predis/Protocol/ProtocolExceptionTest.php000066400000000000000000000013471211043230100242220ustar00rootroot00000000000000 * * 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\Connection\SingleConnectionInterface; /** * */ class ProtocolExceptionTest extends CommunicationExceptionTest { /** * {@inheritdoc} */ protected function getException(SingleConnectionInterface $connection, $message, $code = 0, \Exception $inner = null) { return new ProtocolException($connection, $message, $code, $inner); } } predis-0.8.3/tests/Predis/Protocol/Text/000077500000000000000000000000001211043230100201105ustar00rootroot00000000000000predis-0.8.3/tests/Predis/Protocol/Text/ComposableTextProtocolTest.php000066400000000000000000000066031211043230100261410ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class ComposableTextProtocolTest extends StandardTestCase { /** * @group disconnected */ public function testCustomSerializer() { $serializer = $this->getMock('Predis\Protocol\CommandSerializerInterface'); $protocol = new ComposableTextProtocol(); $protocol->setSerializer($serializer); $this->assertSame($serializer, $protocol->getSerializer()); } /** * @group disconnected */ public function testCustomReader() { $reader = $this->getMock('Predis\Protocol\ResponseReaderInterface'); $protocol = new ComposableTextProtocol(); $protocol->setReader($reader); $this->assertSame($reader, $protocol->getReader()); } /** * @group disconnected */ public function testConnectionWrite() { $serialized = "*1\r\n$4\r\nPING\r\n"; $command = $this->getMock('Predis\Command\CommandInterface'); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $serializer = $this->getMock('Predis\Protocol\CommandSerializerInterface'); $protocol = new ComposableTextProtocol(); $protocol->setSerializer($serializer); $connection->expects($this->once()) ->method('writeBytes') ->with($this->equalTo($serialized)); $serializer->expects($this->once()) ->method('serialize') ->with($command) ->will($this->returnValue($serialized)); $protocol->write($connection, $command); } /** * @group disconnected */ public function testConnectionRead() { $serialized = "*1\r\n$4\r\nPING\r\n"; $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $reader = $this->getMock('Predis\Protocol\ResponseReaderInterface'); $protocol = new ComposableTextProtocol(); $protocol->setReader($reader); $reader->expects($this->once()) ->method('read') ->with($connection) ->will($this->returnValue('bulk')); $this->assertSame('bulk', $protocol->read($connection)); } /** * @group disconnected */ public function testSetMultibulkOption() { $protocol = new ComposableTextProtocol(); $reader = $protocol->getReader(); $protocol->setOption('iterable_multibulk', true); $this->assertInstanceOf('Predis\Protocol\Text\ResponseMultiBulkStreamHandler', $reader->getHandler('*')); $protocol->setOption('iterable_multibulk', false); $this->assertInstanceOf('Predis\Protocol\Text\ResponseMultiBulkHandler', $reader->getHandler('*')); } /** * @group disconnected * @expectedException InvalidArgumentException * @expectedExceptionMessage The option unknown_option is not supported by the current protocol */ public function testSetInvalidOption() { $protocol = new ComposableTextProtocol(); $protocol->setOption('unknown_option', true); } } predis-0.8.3/tests/Predis/Protocol/Text/ResponseBulkHandlerTest.php000066400000000000000000000050231211043230100253730ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class ResponseBulkHandlerTest extends StandardTestCase { /** * @group disconnected */ public function testZeroLengthBulk() { $handler = new ResponseBulkHandler(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->never())->method('readLine'); $connection->expects($this->once()) ->method('readBytes') ->with($this->equalTo(2)) ->will($this->returnValue("\r\n")); $this->assertSame('', $handler->handle($connection, '0')); } /** * @group disconnected */ public function testBulk() { $bulk = "This is a bulk string."; $bulkLengh = (string) strlen($bulk); $handler = new ResponseBulkHandler(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->never())->method('readLine'); $connection->expects($this->once()) ->method('readBytes') ->with($this->equalTo($bulkLengh + 2)) ->will($this->returnValue("$bulk\r\n")); $this->assertSame($bulk, $handler->handle($connection, $bulkLengh)); } /** * @group disconnected */ public function testNull() { $handler = new ResponseBulkHandler(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->never())->method('readLine'); $connection->expects($this->never())->method('readBytes'); $this->assertNull($handler->handle($connection, '-1')); } /** * @group disconnected * @expectedException Predis\Protocol\ProtocolException * @expectedExceptionMessage Cannot parse 'invalid' as bulk length */ public function testInvalidLength() { $handler = new ResponseBulkHandler(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->never())->method('readLine'); $connection->expects($this->never())->method('readBytes'); $handler->handle($connection, 'invalid'); } } predis-0.8.3/tests/Predis/Protocol/Text/ResponseErrorHandlerTest.php000066400000000000000000000020051211043230100255640ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class ResponseErrorHandlerTest extends StandardTestCase { /** * @group disconnected */ public function testOk() { $handler = new ResponseErrorHandler(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->never())->method('readLine'); $connection->expects($this->never())->method('readBytes'); $message = "ERR Operation against a key holding the wrong kind of value"; $response = $handler->handle($connection, $message); $this->assertInstanceOf('Predis\ResponseError', $response); $this->assertSame($message, $response->getMessage()); } } predis-0.8.3/tests/Predis/Protocol/Text/ResponseIntegerHandlerTest.php000066400000000000000000000037651211043230100261060ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\ResponseQueued; /** * */ class ResponseIntegerHandlerTest extends StandardTestCase { /** * @group disconnected */ public function testInteger() { $handler = new ResponseIntegerHandler(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->never())->method('readLine'); $connection->expects($this->never())->method('readBytes'); $this->assertSame(0, $handler->handle($connection, '0')); $this->assertSame(1, $handler->handle($connection, '1')); $this->assertSame(10, $handler->handle($connection, '10')); $this->assertSame(-10, $handler->handle($connection, '-10')); } /** * @group disconnected */ public function testNull() { $handler = new ResponseIntegerHandler(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->never())->method('readLine'); $connection->expects($this->never())->method('readBytes'); $this->assertNull($handler->handle($connection, 'nil')); } /** * @group disconnected * @expectedException Predis\Protocol\ProtocolException * @expectedExceptionMessage Cannot parse 'invalid' as numeric response */ public function testInvalid() { $handler = new ResponseIntegerHandler(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->never())->method('readLine'); $connection->expects($this->never())->method('readBytes'); $handler->handle($connection, 'invalid'); } } predis-0.8.3/tests/Predis/Protocol/Text/ResponseMultiBulkHandlerTest.php000066400000000000000000000045711211043230100264150ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class ResponseMultiBulkHandlerTest extends StandardTestCase { /** * @group disconnected */ public function testMultiBulk() { $handler = new ResponseMultiBulkHandler(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->once()) ->method('getProtocol') ->will($this->returnValue(new ComposableTextProtocol())); $connection->expects($this->at(1)) ->method('readLine') ->will($this->returnValue("$3")); $connection->expects($this->at(2)) ->method('readBytes') ->will($this->returnValue("foo\r\n")); $connection->expects($this->at(3)) ->method('readLine') ->will($this->returnValue("$3")); $connection->expects($this->at(4)) ->method('readBytes') ->will($this->returnValue("bar\r\n")); $this->assertSame(array('foo', 'bar'), $handler->handle($connection, '2')); } /** * @group disconnected */ public function testNull() { $handler = new ResponseMultiBulkHandler(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->never())->method('readLine'); $connection->expects($this->never())->method('readBytes'); $this->assertNull($handler->handle($connection, '-1')); } /** * @group disconnected * @expectedException Predis\Protocol\ProtocolException * @expectedExceptionMessage Cannot parse 'invalid' as multi-bulk length */ public function testInvalid() { $handler = new ResponseMultiBulkHandler(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->never())->method('readLine'); $connection->expects($this->never())->method('readBytes'); $handler->handle($connection, 'invalid'); } } predis-0.8.3/tests/Predis/Protocol/Text/ResponseMultiBulkStreamHandlerTest.php000066400000000000000000000026461211043230100275720ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class ResponseMultiBulkStreamHandlerTest extends StandardTestCase { /** * @group disconnected */ public function testOk() { $handler = new ResponseMultiBulkStreamHandler(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->never())->method('readLine'); $connection->expects($this->never())->method('readBytes'); $this->assertInstanceOf('Predis\Iterator\MultiBulkResponseSimple', $handler->handle($connection, '1')); } /** * @group disconnected * @expectedException Predis\Protocol\ProtocolException * @expectedExceptionMessage Cannot parse 'invalid' as multi-bulk length */ public function testInvalid() { $handler = new ResponseMultiBulkStreamHandler(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->never())->method('readLine'); $connection->expects($this->never())->method('readBytes'); $handler->handle($connection, 'invalid'); } } predis-0.8.3/tests/Predis/Protocol/Text/ResponseStatusHandlerTest.php000066400000000000000000000034001211043230100257560ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\ResponseQueued; /** * */ class ResponseStatusHandlerTest extends StandardTestCase { /** * @group disconnected */ public function testOk() { $handler = new ResponseStatusHandler(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->never())->method('readLine'); $connection->expects($this->never())->method('readBytes'); $this->assertTrue($handler->handle($connection, 'OK')); } /** * @group disconnected */ public function testQueued() { $handler = new ResponseStatusHandler(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->never())->method('readLine'); $connection->expects($this->never())->method('readBytes'); $this->assertInstanceOf('Predis\ResponseQueued', $handler->handle($connection, 'QUEUED')); } /** * @group disconnected */ public function testPlainString() { $handler = new ResponseStatusHandler(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->never())->method('readLine'); $connection->expects($this->never())->method('readBytes'); $this->assertSame('Background saving started', $handler->handle($connection, 'Background saving started')); } } predis-0.8.3/tests/Predis/Protocol/Text/TextCommandSerializerTest.php000066400000000000000000000031711211043230100257400ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class TextCommandSerializerTest extends StandardTestCase { /** * @group disconnected */ public function testSerializerIdWithNoArguments() { $serializer = new TextCommandSerializer(); $command = $this->getMock('Predis\Command\CommandInterface'); $command->expects($this->once()) ->method('getId') ->will($this->returnValue('PING')); $command->expects($this->once()) ->method('getArguments') ->will($this->returnValue(array())); $result = $serializer->serialize($command); $this->assertSame("*1\r\n$4\r\nPING\r\n", $result); } /** * @group disconnected */ public function testSerializerIdWithArguments() { $serializer = new TextCommandSerializer(); $command = $this->getMock('Predis\Command\CommandInterface'); $command->expects($this->once()) ->method('getId') ->will($this->returnValue('SET')); $command->expects($this->once()) ->method('getArguments') ->will($this->returnValue(array('key', 'value'))); $result = $serializer->serialize($command); $this->assertSame("*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n", $result); } } predis-0.8.3/tests/Predis/Protocol/Text/TextProtocolTest.php000066400000000000000000000067171211043230100241420ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class TextProtocolTest extends StandardTestCase { /** * @group disconnected */ public function testConnectionWrite() { $serialized = "*1\r\n$4\r\nPING\r\n"; $protocol = new TextProtocol(); $command = $this->getMock('Predis\Command\CommandInterface'); $command->expects($this->once()) ->method('getId') ->will($this->returnValue('PING')); $command->expects($this->once()) ->method('getArguments') ->will($this->returnValue(array())); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->once()) ->method('writeBytes') ->with($this->equalTo($serialized)); $protocol->write($connection, $command); } /** * @todo Improve test coverage * @group disconnected */ public function testConnectionRead() { $protocol = new TextProtocol(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->at(0)) ->method('readLine') ->will($this->returnValue("+OK")); $connection->expects($this->at(1)) ->method('readLine') ->will($this->returnValue("-ERR error message")); $connection->expects($this->at(2)) ->method('readLine') ->will($this->returnValue(":2")); $connection->expects($this->at(3)) ->method('readLine') ->will($this->returnValue("$-1")); $connection->expects($this->at(4)) ->method('readLine') ->will($this->returnValue("*-1")); $this->assertTrue($protocol->read($connection)); $this->assertEquals("ERR error message", $protocol->read($connection)); $this->assertSame(2, $protocol->read($connection)); $this->assertNull($protocol->read($connection)); $this->assertNull($protocol->read($connection)); } /** * @group disconnected */ public function testIterableMultibulkSupport() { $protocol = new TextProtocol(); $protocol->setOption('iterable_multibulk', true); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->once(4)) ->method('readLine') ->will($this->returnValue("*1")); $this->assertInstanceOf('Predis\Iterator\MultiBulkResponseSimple', $protocol->read($connection)); } /** * @group disconnected * @expectedException Predis\Protocol\ProtocolException * @expectedExceptionMessage Unknown prefix: '!' */ public function testUnknownResponsePrefix() { $protocol = new TextProtocol(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->once()) ->method('readLine') ->will($this->returnValue('!')); $protocol->read($connection); } } predis-0.8.3/tests/Predis/Protocol/Text/TextResponseReaderTest.php000066400000000000000000000073571211043230100252630ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Protocol\Text; use \PHPUnit_Framework_TestCase as StandardTestCase; /** * */ class TextResponseReaderTest extends StandardTestCase { /** * @group disconnected */ public function testDefaultHandlers() { $reader = new TextResponseReader(); $this->assertInstanceOf('Predis\Protocol\Text\ResponseStatusHandler', $reader->getHandler('+')); $this->assertInstanceOf('Predis\Protocol\Text\ResponseErrorHandler', $reader->getHandler('-')); $this->assertInstanceOf('Predis\Protocol\Text\ResponseIntegerHandler', $reader->getHandler(':')); $this->assertInstanceOf('Predis\Protocol\Text\ResponseBulkHandler', $reader->getHandler('$')); $this->assertInstanceOf('Predis\Protocol\Text\ResponseMultiBulkHandler', $reader->getHandler('*')); $this->assertNull($reader->getHandler('!')); } /** * @group disconnected */ public function testReplaceHandler() { $handler = $this->getMock('Predis\Protocol\ResponseHandlerInterface'); $reader = new TextResponseReader(); $reader->setHandler('+', $handler); $this->assertSame($handler, $reader->getHandler('+')); } /** * @group disconnected */ public function testReadResponse() { $reader = new TextResponseReader(); $protocol = new ComposableTextProtocol(); $protocol->setReader($reader); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->at(0)) ->method('readLine') ->will($this->returnValue("+OK")); $connection->expects($this->at(1)) ->method('readLine') ->will($this->returnValue("-ERR error message")); $connection->expects($this->at(2)) ->method('readLine') ->will($this->returnValue(":2")); $connection->expects($this->at(3)) ->method('readLine') ->will($this->returnValue("$-1")); $connection->expects($this->at(4)) ->method('readLine') ->will($this->returnValue("*-1")); $this->assertTrue($reader->read($connection)); $this->assertEquals("ERR error message", $reader->read($connection)); $this->assertSame(2, $reader->read($connection)); $this->assertNull($reader->read($connection)); $this->assertNull($reader->read($connection)); } /** * @group disconnected * @expectedException Predis\Protocol\ProtocolException * @expectedExceptionMessage Unexpected empty header */ public function testEmptyResponseHeader() { $reader = new TextResponseReader(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->once()) ->method('readLine') ->will($this->returnValue('')); $reader->read($connection); } /** * @group disconnected * @expectedException Predis\Protocol\ProtocolException * @expectedExceptionMessage Unknown prefix: '!' */ public function testUnknownResponsePrefix() { $reader = new TextResponseReader(); $connection = $this->getMock('Predis\Connection\ComposableConnectionInterface'); $connection->expects($this->once()) ->method('readLine') ->will($this->returnValue('!')); $reader->read($connection); } } predis-0.8.3/tests/Predis/PubSub/000077500000000000000000000000001211043230100165635ustar00rootroot00000000000000predis-0.8.3/tests/Predis/PubSub/DispatcherLoopTest.php000066400000000000000000000052321211043230100230560ustar00rootroot00000000000000 * * 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\Profile\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, ); $options = array('profile' => REDIS_SERVER_VERSION); $producer = new Client($parameters, $options); $producer->connect(); $consumer = new Client($parameters, $options); $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()); } } predis-0.8.3/tests/Predis/PubSub/PubSubContextTest.php000066400000000000000000000241471211043230100227110ustar00rootroot00000000000000 * * 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\Profile\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\Profile\ServerProfileInterface'); $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 when using aggregated connections */ public function testPubSubContextDoesNotWorkOnClusters() { $cluster = $this->getMock('Predis\Connection\ClusterConnectionInterface'); $client = new Client($cluster); $pubsub = new PubSubContext($client); } /** * @group disconnected */ public function testConstructorWithoutSubscriptionsDoesNotOpenContext() { $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $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\Connection\SingleConnectionInterface'); $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\Connection\SingleConnectionInterface'); $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\Connection\SingleConnectionInterface'); $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\Connection\SingleConnectionInterface'); $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\Connection\SingleConnectionInterface'); $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\Connection\SingleConnectionInterface'); $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\Connection\SingleConnectionInterface'); $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\Connection\SingleConnectionInterface'); $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\Connection\SingleConnectionInterface'); $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, ); $options = array('profile' => REDIS_SERVER_VERSION); $messages = array(); $producer = new Client($parameters, $options); $producer->connect(); $consumer = new Client($parameters, $options); $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()); } } predis-0.8.3/tests/Predis/Replication/000077500000000000000000000000001211043230100176345ustar00rootroot00000000000000predis-0.8.3/tests/Predis/Replication/ReplicationStrategyTest.php000066400000000000000000000320511211043230100252020ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis\Replication; use \PHPUnit_Framework_TestCase as StandardTestCase; use Predis\Command\CommandInterface; use Predis\Profile\ServerProfile; /** * */ class ReplicationStrategyTest extends StandardTestCase { /** * @group disconnected */ public function testReadCommands() { $profile = ServerProfile::getDevelopment(); $strategy = new ReplicationStrategy(); foreach ($this->getExpectedCommands('read') as $commandId) { $command = $profile->createCommand($commandId); $this->assertTrue($strategy->isReadOperation($command)); } } /** * @group disconnected */ public function testWriteCommands() { $profile = ServerProfile::getDevelopment(); $strategy = new ReplicationStrategy(); foreach ($this->getExpectedCommands('write') as $commandId) { $command = $profile->createCommand($commandId); $this->assertFalse($strategy->isReadOperation($command), $commandId); } } /** * @group disconnected */ public function testDisallowedCommands() { $profile = ServerProfile::getDevelopment(); $strategy = new ReplicationStrategy(); foreach ($this->getExpectedCommands('disallowed') as $commandId) { $command = $profile->createCommand($commandId); $this->assertTrue($strategy->isDisallowedOperation($command), $commandId); } } /** * @group disconnected */ public function testSortCommand() { $profile = ServerProfile::getDevelopment(); $strategy = new ReplicationStrategy(); $cmdReadSort = $profile->createCommand('SORT', array('key:list')); $this->assertTrue($strategy->isReadOperation($cmdReadSort), 'SORT [read-only]'); $cmdWriteSort = $profile->createCommand('SORT', array('key:list', array('store' => 'key:stored'))); $this->assertFalse($strategy->isReadOperation($cmdWriteSort), 'SORT [write with STORE]'); } /** * @group disconnected * @expectedException Predis\NotSupportedException * @expectedExceptionMessage The command INFO is not allowed in replication mode */ public function testUsingDisallowedCommandThrowsException() { $profile = ServerProfile::getDevelopment(); $strategy = new ReplicationStrategy(); $command = $profile->createCommand('INFO'); $strategy->isReadOperation($command); } /** * @group disconnected */ public function testDefaultIsWriteOperation() { $strategy = new ReplicationStrategy(); $command = $this->getMock('Predis\Command\CommandInterface'); $command->expects($this->any()) ->method('getId') ->will($this->returnValue('CMDTEST')); $this->assertFalse($strategy->isReadOperation($command)); } /** * @group disconnected */ public function testCanSetCommandAsReadOperation() { $strategy = new ReplicationStrategy(); $command = $this->getMock('Predis\Command\CommandInterface'); $command->expects($this->any()) ->method('getId') ->will($this->returnValue('CMDTEST')); $strategy->setCommandReadOnly('CMDTEST', true); $this->assertTrue($strategy->isReadOperation($command)); } /** * @group disconnected */ public function testCanSetCommandAsWriteOperation() { $strategy = new ReplicationStrategy(); $command = $this->getMock('Predis\Command\CommandInterface'); $command->expects($this->any()) ->method('getId') ->will($this->returnValue('CMDTEST')); $strategy->setCommandReadOnly('CMDTEST', false); $this->assertFalse($strategy->isReadOperation($command)); $strategy->setCommandReadOnly('GET', false); $this->assertFalse($strategy->isReadOperation($command)); } /** * @group disconnected */ public function testCanUseCallableToCheckCommand() { $strategy = new ReplicationStrategy(); $profile = ServerProfile::getDevelopment(); $strategy->setCommandReadOnly('SET', function ($command) { return $command->getArgument(1) === true; }); $command = $profile->createCommand('SET', array('trigger', false)); $this->assertFalse($strategy->isReadOperation($command)); $command = $profile->createCommand('SET', array('trigger', true)); $this->assertTrue($strategy->isReadOperation($command)); } /** * @group disconnected */ public function testSetLuaScriptAsReadOperation() { $strategy = new ReplicationStrategy(); $profile = ServerProfile::getDevelopment(); $writeScript = 'redis.call("set", "foo", "bar")'; $readScript = 'return true'; $strategy->setScriptReadOnly($readScript, true); $cmdEval = $profile->createCommand('EVAL', array($writeScript)); $cmdEvalSHA = $profile->createCommand('EVALSHA', array(sha1($writeScript))); $this->assertFalse($strategy->isReadOperation($cmdEval)); $this->assertFalse($strategy->isReadOperation($cmdEvalSHA)); $cmdEval = $profile->createCommand('EVAL', array($readScript)); $cmdEvalSHA = $profile->createCommand('EVALSHA', array(sha1($readScript))); $this->assertTrue($strategy->isReadOperation($cmdEval)); $this->assertTrue($strategy->isReadOperation($cmdEvalSHA)); } /** * @group disconnected */ public function testSetLuaScriptAsReadOperationWorksWithScriptedCommand() { $strategy = new ReplicationStrategy(); $command = $this->getMock('Predis\Command\ScriptedCommand', array('getScript')); $command->expects($this->any()) ->method('getScript') ->will($this->returnValue($script = 'return true')); $strategy->setScriptReadOnly($script, function ($command) { return $command->getArgument(2) === true; }); $command->setArguments(array(false)); $this->assertFalse($strategy->isReadOperation($command)); $command->setArguments(array(true)); $this->assertTrue($strategy->isReadOperation($command)); } /** * @group disconnected */ public function testSetLuaScriptAsReadOperationWorksWithScriptedCommandAndCallableCheck() { $strategy = new ReplicationStrategy(); $command = $this->getMock('Predis\Command\ScriptedCommand', array('getScript')); $command->expects($this->any()) ->method('getScript') ->will($this->returnValue($script = 'return true')); $command->setArguments(array('trigger', false)); $strategy->setScriptReadOnly($script, true); $this->assertTrue($strategy->isReadOperation($command)); } // ******************************************************************** // // ---- HELPER METHODS ------------------------------------------------ // // ******************************************************************** // /** * Returns the list of expected supported commands. * * @param string $type Optional type of command (based on its keys) * @return array */ protected function getExpectedCommands($type = null) { $commands = array( /* commands operating on the connection */ 'EXISTS' => 'read', 'AUTH' => 'read', 'SELECT' => 'read', 'ECHO' => 'read', 'QUIT' => 'read', 'OBJECT' => 'read', 'BITCOUNT' => 'read', 'TIME' => 'read', 'SHUTDOWN' => 'disallowed', 'INFO' => 'disallowed', 'DBSIZE' => 'disallowed', 'LASTSAVE' => 'disallowed', 'CONFIG' => 'disallowed', 'MONITOR' => 'disallowed', 'SLAVEOF' => 'disallowed', 'SAVE' => 'disallowed', 'BGSAVE' => 'disallowed', 'BGREWRITEAOF' => 'disallowed', 'SLOWLOG' => 'disallowed', /* commands operating on the key space */ 'EXISTS' => 'read', 'DEL' => 'write', 'TYPE' => 'read', 'EXPIRE' => 'write', 'EXPIREAT' => 'write', 'PERSIST' => 'write', 'PEXPIRE' => 'write', 'PEXPIREAT' => 'write', 'TTL' => 'read', 'PTTL' => 'write', 'SORT' => 'variable', 'KEYS' => 'read', 'RANDOMKEY' => 'read', /* commands operating on string values */ 'APPEND' => 'write', 'DECR' => 'write', 'DECRBY' => 'write', 'GET' => 'read', 'GETBIT' => 'read', 'MGET' => 'read', 'SET' => 'write', 'GETRANGE' => 'read', 'GETSET' => 'write', 'INCR' => 'write', 'INCRBY' => 'write', 'SETBIT' => 'write', 'SETEX' => 'write', 'MSET' => 'write', 'MSETNX' => 'write', 'SETNX' => 'write', 'SETRANGE' => 'write', 'STRLEN' => 'read', 'SUBSTR' => 'read', /* commands operating on lists */ 'LINSERT' => 'write', 'LINDEX' => 'read', 'LLEN' => 'read', 'LPOP' => 'write', 'RPOP' => 'write', 'BLPOP' => 'write', 'BRPOP' => 'write', 'LPUSH' => 'write', 'LPUSHX' => 'write', 'RPUSH' => 'write', 'RPUSHX' => 'write', 'LRANGE' => 'read', 'LREM' => 'write', 'LSET' => 'write', 'LTRIM' => 'write', /* commands operating on sets */ 'SADD' => 'write', 'SCARD' => 'read', 'SISMEMBER' => 'read', 'SMEMBERS' => 'read', 'SPOP' => 'write', 'SRANDMEMBER' => 'read', 'SREM' => 'write', 'SINTER' => 'read', 'SUNION' => 'read', 'SDIFF' => 'read', /* commands operating on sorted sets */ 'ZADD' => 'write', 'ZCARD' => 'read', 'ZCOUNT' => 'read', 'ZINCRBY' => 'write', 'ZRANGE' => 'read', 'ZRANGEBYSCORE' => 'read', 'ZRANK' => 'read', 'ZREM' => 'write', 'ZREMRANGEBYRANK' => 'write', 'ZREMRANGEBYSCORE' => 'write', 'ZREVRANGE' => 'read', 'ZREVRANGEBYSCORE' => 'read', 'ZREVRANK' => 'read', 'ZSCORE' => 'read', /* commands operating on hashes */ 'HDEL' => 'write', 'HEXISTS' => 'read', 'HGET' => 'read', 'HGETALL' => 'read', 'HMGET' => 'read', 'HINCRBY' => 'write', 'HINCRBYFLOAT' => 'write', 'HKEYS' => 'read', 'HLEN' => 'read', 'HSET' => 'write', 'HSETNX' => 'write', 'HVALS' => 'read', /* scripting */ 'EVAL' => 'write', 'EVALSHA' => 'write', ); if (isset($type)) { $commands = array_filter($commands, function ($expectedType) use ($type) { return $expectedType === $type; }); } return array_keys($commands); } } predis-0.8.3/tests/Predis/ResponseErrorTest.php000066400000000000000000000026751211043230100215560ustar00rootroot00000000000000 * * 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\ResponseErrorInterface', $error); $this->assertInstanceOf('Predis\ResponseObjectInterface', $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); } } predis-0.8.3/tests/Predis/ResponseQueuedTest.php000066400000000000000000000017731211043230100217130ustar00rootroot00000000000000 * * 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\ResponseObjectInterface', $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); } } predis-0.8.3/tests/Predis/ServerExceptionTest.php000066400000000000000000000034751211043230100220720ustar00rootroot00000000000000 * * 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\ResponseErrorInterface', $exception); $this->assertInstanceOf('Predis\ResponseObjectInterface', $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()); } } predis-0.8.3/tests/Predis/Transaction/000077500000000000000000000000001211043230100176505ustar00rootroot00000000000000predis-0.8.3/tests/Predis/Transaction/AbortedMultiExecExceptionTest.php000066400000000000000000000015701211043230100263030ustar00rootroot00000000000000 * * 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()); } } predis-0.8.3/tests/Predis/Transaction/MultiExecContextTest.php000066400000000000000000000573401211043230100244760ustar00rootroot00000000000000 * * 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\Command\CommandInterface; /** * @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\Connection\SingleConnectionInterface'); $client = new Client($connection, array('profile' => '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\Connection\SingleConnectionInterface'); $client = new Client($connection, array('profile' => '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 testIntegrationThrowsExceptionOnRedisErrorInBlock() { $client = $this->getClient(); $exception = null; $value = (string) rand(); try { $client->multiExec(function ($tx) use ($value) { $tx->set('foo', 'bar'); $tx->lpush('foo', 'bar'); $tx->set('foo', $value); }); } catch (ServerException $ex) { $exception = $ex; } $this->assertInstanceOf('Predis\ResponseErrorInterface', $exception); $this->assertSame($value, $client->get('foo')); } /** * @group connected */ public function testIntegrationReturnsErrorObjectOnRedisErrorInBlock() { $client = $this->getClient(array(), array('exceptions' => false)); $replies = $client->multiExec(function ($tx) { $tx->set('foo', 'bar'); $tx->lpush('foo', 'bar'); $tx->echo('foobar'); }); $this->assertTrue($replies[0]); $this->assertInstanceOf('Predis\ResponseErrorInterface', $replies[1]); $this->assertSame('foobar', $replies[2]); } /** * @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\Connection\SingleConnectionInterface * usingthe specified callback to return values from executeCommand(). * * @param \Closure $executeCallback * @return \Predis\Connection\SingleConnectionInterface */ protected function getMockedConnection($executeCallback) { $connection = $this->getMock('Predis\Connection\SingleConnectionInterface'); $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 (CommandInterface $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\Command\CommandInterface 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. * * @param array Additional connection parameters. * @param array Additional client options. * @return Client client instance. */ protected function getClient(Array $parameters = array(), Array $options = array()) { $parameters = array_merge(array( 'scheme' => 'tcp', 'host' => REDIS_SERVER_HOST, 'port' => REDIS_SERVER_PORT, 'database' => REDIS_SERVER_DBNUM, ), $parameters); $options = array_merge(array( 'profile' => REDIS_SERVER_VERSION ), $options); $client = new Client($parameters, $options); $client->connect(); $client->flushdb(); return $client; } } predis-0.8.3/tests/README.md000066400000000000000000000076421211043230100154250ustar00rootroot00000000000000# About testing Predis # __ATTENTION__: Do not ever 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 ahead 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 depending 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 `REDIS_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 `REDIS_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 completely disable integration tests 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 __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\Command` namespace (only classes in this namespace are considered valid). For example, to generate a test case for `SET` (represented by the `Predis\Command\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. predis-0.8.3/tests/bootstrap.php000066400000000000000000000010511211043230100166600ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require __DIR__.'/../autoload.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';