Compare commits

..

26 Commits

Author SHA1 Message Date
Daniele Alessandri 8be2418f01 Update CHANGELOG and bump VERSION (v1.1.4) 2020-08-30 00:15:08 +02:00
Daniele Alessandri b9ebe8a376 [tests] Fix mistype in TODO comments.
... and yay for copypasting it too!
2020-08-30 23:26:42 +02:00
Daniele Alessandri e2d26926d2 Update README. 2020-08-30 21:33:14 +02:00
Daniele Alessandri 309248042f Update .gitignore
Removing annoying .phpunit.result.cache left around when switching back
and forth branches from main to v1.1 for development.
2020-08-30 10:38:47 +02:00
Daniele Alessandri 87452e62d0 Fix authentication to support ACL with Redis 6.0.
When passing both "username" and "password" to connection parameters the
client now uses the extended AUTH command to support ACL authentication
with Redis 6.0.

The plain old authentication method is still supported like usual simply
by passing only "password" to connection parameters.
2020-08-29 14:11:55 +02:00
Daniele Alessandri 31baa9b241 Do not push AUTH and SELECT on empty "password" and "database".
NULL or zero-length string values passed to "password" and "database" in
the connection parameters list do not trigger spurious AUTH and SELECT
commands anymore when connecting to Redis.

Fixes #436.
2020-08-29 13:39:12 +02:00
Daniele Alessandri 6f942400a1 [tests] Skip integration tests for PUB/SUB consumer on CI.
Changes backported from the main branch (ref. 04d5c10, 5afadb5).

This is just a temporary solution, we will revert this change as soon as
the actual cause for the spurious failures is identified.
2020-08-27 17:44:23 +02:00
Daniele Alessandri 5e220a0b57 Update CHANGELOG. 2020-08-25 15:57:51 +02:00
Daniele Alessandri 0eb2633348 Merge remote-tracking branch 'github/pr/554' into v1.1 2020-08-25 15:42:13 +02:00
Daniele Alessandri cbbd6bba88 Update CHANGELOG.
[ci skip]
2020-08-24 22:33:48 +02:00
Daniele Alessandri 3702f24efc Fix more @method tags in interfaces. 2020-08-24 22:27:21 +02:00
Daniele Alessandri 82fefe057b Merge remote-tracking branch 'github/pr/456' into v1.1-annotations 2020-08-24 21:56:13 +02:00
Daniele Alessandri 42336537dc Merge remote-tracking branch 'github/pr/497' into v1.1 2020-08-24 17:10:28 +02:00
Daniele Alessandri 802abac55e Fix pear builder script to generate UTF-8 encoded package.xml.
Fixes issue #531.

[ci skip]
2020-08-24 16:20:06 +02:00
Daniele Alessandri 61e75816ce Apply few changes in .gitattributes file.
Remove .github from directories exported in our release packages and fix
to ignore .php_cs.dist (the actual file commited) instead of .php_cs.

[ci skip]
2020-08-24 14:04:10 +02:00
Daniele Alessandri 17f0c08cb6 [tests] Fix expected response for COMMAND INFO (Redis >= 6.0).
Starting with Redis 6.0 and the introduction of Access Control Lists,
COMMAND INFO returns an additional array for each specified command in
the request with a list of the ACL categories associated to a command.
2020-08-24 11:45:20 +02:00
Daniele Alessandri 2b8af1eef2 Update CHANGELOG. 2020-08-23 18:38:07 +02:00
Daniele Alessandri c5f2b441b4 Merge branch 'github/pr/545' into v1.1 2020-08-23 18:11:49 +02:00
GITSRC 2440a61cba Fix HashRing to use method defined by HashGeneratorInterface. 2020-08-23 18:09:09 +02:00
Daniele Alessandri 7100884201 Update CHANGELOG. 2020-08-23 17:48:38 +02:00
Daniele Alessandri 2a932d7292 Merge remote-tracking branch 'github/pr/556' into v1.1 2020-08-23 17:47:26 +02:00
Daniele Alessandri 0a6306b73e Back to development. 2020-08-23 17:46:12 +02:00
Peter Gribanov 4363345f7c iterate not iterable connections #552 2020-08-23 15:00:22 +03:00
Mark Fettig 39ff616e86 update sort command to be a write operation 2019-03-18 12:10:26 -04:00
Geoffrey Hoffman 738ec0c50f Correcting the return type hint for BRPOPLPUSH method 2018-04-10 18:09:42 -07:00
Teoh Han Hui 1828222e27 Add null return value to PHPDoc 2017-08-14 19:36:11 +08:00
19 changed files with 384 additions and 224 deletions
+2 -1
View File
@@ -3,10 +3,11 @@
/tests/PHPUnit export-ignore
/tests/Predis export-ignore
/tests/bootstrap.php export-ignore
/.github export-ignore
/.editorconfig export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/.php_cs export-ignore
/.php_cs.dist export-ignore
/.travis.yml export-ignore
/phpunit.xml.dist export-ignore
/phpunit.xml.travisci export-ignore
+1
View File
@@ -2,6 +2,7 @@
*.phar
.php-version
.php_cs.cache
.phpunit.result.cache
phpunit.xml
package.xml
composer.lock
+34
View File
@@ -1,3 +1,37 @@
v1.1.4 (2020-08-31)
================================================================================
- Improved @method annotations for methods responding to Redis commands defined
by `Predis\ClientInterface` and `Predis\ClientContextInterface`. (PR #456 and
PR #497, other fixes applied after further analysys).
- __FIX__: the client can now handle ACL authentication when connecting to Redis
6.x simply by passing both `username` and `password` to connection parameters.
See [the Redis docs](https://redis.io/topics/acl) for details on this topic.
- __FIX__: NULL or zero-length string values passed to `password` and `database`
in the connection parameters list do not trigger spurious `AUTH` and `SELECT`
commands anymore when connecting to Redis (ISSUE #436).
- __FIX__: initializing an iteration over a client instance when it is connected
to a standalone Redis server will not throw an exception anymore, instead it
will return an iterator that will run for just one loop returning a new client
instance using the underlying single-node connection (ISSUE #552, PR #556).
- __FIX__: `Predis\Cluster\Distributor\HashRingaddNodeToRing()` was calculating
the hash required for distribution by using `crc32()` directly instead of the
method `Predis\Cluster\Hash\HashGeneratorInterface::hash()` implemented by the
class itself. This bug fix does not have any impact on existing clusters that
use client-side sharding based on this distributor simply because it does not
take any external hash generators so distribution is not going to be affected.
- __FIX__: `SORT` now always trigger a switch to the master node in replication
configurations instead of just when the `STORE` modifier is specified, this is
because `SORT` is always considered to be a write operation and actually fails
with a `-READONLY` error response when executed against a replica node. (ISSUE
#554).
v1.1.3 (2020-08-18)
================================================================================
+3
View File
@@ -87,6 +87,9 @@ $client = new Predis\Client([
$client = new Predis\Client('tcp://10.0.0.1:6379');
```
Password protected servers can be accessed by adding `password` to the parameters set. When ACLs are
enabled on Redis >= 6.0, both `username` and `password` are required for user authentication.
It is also possible to connect to local instances of Redis using UNIX domain sockets, in this case
the parameters must use the `unix` scheme and specify a path for the socket file:
+1 -1
View File
@@ -1 +1 @@
1.1.3
1.1.4
+2 -2
View File
@@ -115,7 +115,7 @@ function addPackageFile($pkg, $fileinfo, $role, $baseDir = '')
function generatePackageXml($packageINI)
{
$XML = <<<XML
<?xml version="1.0"?>
<?xml version="1.0" encoding="UTF-8"?>
<package packagerversion="1.4.10" version="2.0"
xmlns="http://pear.php.net/dtd/package-2.0"
xmlns:tasks="http://pear.php.net/dtd/tasks-1.0"
@@ -197,7 +197,7 @@ function rewritePackageInstallAs($pkg)
function savePackageXml($xml)
{
$dom = new DOMDocument("1.0");
$dom = new DOMDocument("1.0", "UTF-8");
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($xml->asXML());
+1 -1
View File
@@ -10,7 +10,7 @@ name = "Predis"
desc = "Flexible and feature-complete Redis client for PHP and HHVM"
homepage = "http://github.com/nrk/predis"
license = "MIT"
version = "1.1.3"
version = "1.1.4"
stability = "stable"
channel = "pear.nrk.io"
+4 -2
View File
@@ -40,7 +40,7 @@ use Predis\Transaction\MultiExec as MultiExecTransaction;
*/
class Client implements ClientInterface, \IteratorAggregate
{
const VERSION = '1.1.3';
const VERSION = '1.1.4';
protected $connection;
protected $options;
@@ -535,7 +535,9 @@ class Client implements ClientInterface, \IteratorAggregate
$connection = $this->getConnection();
if (!$connection instanceof \Traversable) {
throw new ClientException('The underlying connection is not traversable');
return new \ArrayIterator(array(
(string) $connection => new static($connection, $this->getOptions())
));
}
foreach ($connection as $node) {
+3 -2
View File
@@ -39,6 +39,7 @@ use Predis\Command\CommandInterface;
* @method $this bitcount($key, $start = null, $end = null)
* @method $this bitop($operation, $destkey, $key)
* @method $this bitfield($key, $subcommand, ...$subcommandArg)
* @method $this bitpos($key, $bit, $start = null, $end = null)
* @method $this decr($key)
* @method $this decrby($key, $decrement)
* @method $this get($key)
@@ -81,7 +82,7 @@ use Predis\Command\CommandInterface;
* @method $this llen($key)
* @method $this lpop($key)
* @method $this lpush($key, array $values)
* @method $this lpushx($key, $value)
* @method $this lpushx($key, array $values)
* @method $this lrange($key, $start, $stop)
* @method $this lrem($key, $count, $value)
* @method $this lset($key, $index, $value)
@@ -89,7 +90,7 @@ use Predis\Command\CommandInterface;
* @method $this rpop($key)
* @method $this rpoplpush($source, $destination)
* @method $this rpush($key, array $values)
* @method $this rpushx($key, $value)
* @method $this rpushx($key, array $values)
* @method $this sadd($key, array $members)
* @method $this scard($key)
* @method $this sdiff(array|string $keys)
+148 -147
View File
@@ -24,153 +24,154 @@ use Predis\Profile\ProfileInterface;
* and more friendly interface to ease programming which is described in the
* following list of methods:
*
* @method int del(array|string $keys)
* @method string dump($key)
* @method int exists($key)
* @method int expire($key, $seconds)
* @method int expireat($key, $timestamp)
* @method array keys($pattern)
* @method int move($key, $db)
* @method mixed object($subcommand, $key)
* @method int persist($key)
* @method int pexpire($key, $milliseconds)
* @method int pexpireat($key, $timestamp)
* @method int pttl($key)
* @method string randomkey()
* @method mixed rename($key, $target)
* @method int renamenx($key, $target)
* @method array scan($cursor, array $options = null)
* @method array sort($key, array $options = null)
* @method int ttl($key)
* @method mixed type($key)
* @method int append($key, $value)
* @method int bitcount($key, $start = null, $end = null)
* @method int bitop($operation, $destkey, $key)
* @method array bitfield($key, $subcommand, ...$subcommandArg)
* @method int decr($key)
* @method int decrby($key, $decrement)
* @method string get($key)
* @method int getbit($key, $offset)
* @method string getrange($key, $start, $end)
* @method string getset($key, $value)
* @method int incr($key)
* @method int incrby($key, $increment)
* @method string incrbyfloat($key, $increment)
* @method array mget(array $keys)
* @method mixed mset(array $dictionary)
* @method int msetnx(array $dictionary)
* @method mixed psetex($key, $milliseconds, $value)
* @method mixed set($key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
* @method int setbit($key, $offset, $value)
* @method int setex($key, $seconds, $value)
* @method int setnx($key, $value)
* @method int setrange($key, $offset, $value)
* @method int strlen($key)
* @method int hdel($key, array $fields)
* @method int hexists($key, $field)
* @method string hget($key, $field)
* @method array hgetall($key)
* @method int hincrby($key, $field, $increment)
* @method string hincrbyfloat($key, $field, $increment)
* @method array hkeys($key)
* @method int hlen($key)
* @method array hmget($key, array $fields)
* @method mixed hmset($key, array $dictionary)
* @method array hscan($key, $cursor, array $options = null)
* @method int hset($key, $field, $value)
* @method int hsetnx($key, $field, $value)
* @method array hvals($key)
* @method int hstrlen($key, $field)
* @method array blpop(array|string $keys, $timeout)
* @method array brpop(array|string $keys, $timeout)
* @method array brpoplpush($source, $destination, $timeout)
* @method string lindex($key, $index)
* @method int linsert($key, $whence, $pivot, $value)
* @method int llen($key)
* @method string lpop($key)
* @method int lpush($key, array $values)
* @method int lpushx($key, $value)
* @method array lrange($key, $start, $stop)
* @method int lrem($key, $count, $value)
* @method mixed lset($key, $index, $value)
* @method mixed ltrim($key, $start, $stop)
* @method string rpop($key)
* @method string rpoplpush($source, $destination)
* @method int rpush($key, array $values)
* @method int rpushx($key, $value)
* @method int sadd($key, array $members)
* @method int scard($key)
* @method array sdiff(array|string $keys)
* @method int sdiffstore($destination, array|string $keys)
* @method array sinter(array|string $keys)
* @method int sinterstore($destination, array|string $keys)
* @method int sismember($key, $member)
* @method array smembers($key)
* @method int smove($source, $destination, $member)
* @method array spop($key, $count = null)
* @method string srandmember($key, $count = null)
* @method int srem($key, $member)
* @method array sscan($key, $cursor, array $options = null)
* @method array sunion(array|string $keys)
* @method int sunionstore($destination, array|string $keys)
* @method int zadd($key, array $membersAndScoresDictionary)
* @method int zcard($key)
* @method string zcount($key, $min, $max)
* @method string zincrby($key, $increment, $member)
* @method int zinterstore($destination, array|string $keys, array $options = null)
* @method array zrange($key, $start, $stop, array $options = null)
* @method array zrangebyscore($key, $min, $max, array $options = null)
* @method int zrank($key, $member)
* @method int zrem($key, $member)
* @method int zremrangebyrank($key, $start, $stop)
* @method int zremrangebyscore($key, $min, $max)
* @method array zrevrange($key, $start, $stop, array $options = null)
* @method array zrevrangebyscore($key, $max, $min, array $options = null)
* @method int zrevrank($key, $member)
* @method int zunionstore($destination, array|string $keys, array $options = null)
* @method string zscore($key, $member)
* @method array zscan($key, $cursor, array $options = null)
* @method array zrangebylex($key, $start, $stop, array $options = null)
* @method array zrevrangebylex($key, $start, $stop, array $options = null)
* @method int zremrangebylex($key, $min, $max)
* @method int zlexcount($key, $min, $max)
* @method int pfadd($key, array $elements)
* @method mixed pfmerge($destinationKey, array|string $sourceKeys)
* @method int pfcount(array|string $keys)
* @method mixed pubsub($subcommand, $argument)
* @method int publish($channel, $message)
* @method mixed discard()
* @method array exec()
* @method mixed multi()
* @method mixed unwatch()
* @method mixed watch($key)
* @method mixed eval($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
* @method mixed evalsha($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
* @method mixed script($subcommand, $argument = null)
* @method mixed auth($password)
* @method string echo($message)
* @method mixed ping($message = null)
* @method mixed select($database)
* @method mixed bgrewriteaof()
* @method mixed bgsave()
* @method mixed client($subcommand, $argument = null)
* @method mixed config($subcommand, $argument = null)
* @method int dbsize()
* @method mixed flushall()
* @method mixed flushdb()
* @method array info($section = null)
* @method int lastsave()
* @method mixed save()
* @method mixed slaveof($host, $port)
* @method mixed slowlog($subcommand, $argument = null)
* @method array time()
* @method array command()
* @method int geoadd($key, $longitude, $latitude, $member)
* @method array geohash($key, array $members)
* @method array geopos($key, array $members)
* @method string geodist($key, $member1, $member2, $unit = null)
* @method array georadius($key, $longitude, $latitude, $radius, $unit, array $options = null)
* @method array georadiusbymember($key, $member, $radius, $unit, array $options = null)
* @method int del(array|string $keys)
* @method string|null dump($key)
* @method int exists($key)
* @method int expire($key, $seconds)
* @method int expireat($key, $timestamp)
* @method array keys($pattern)
* @method int move($key, $db)
* @method mixed object($subcommand, $key)
* @method int persist($key)
* @method int pexpire($key, $milliseconds)
* @method int pexpireat($key, $timestamp)
* @method int pttl($key)
* @method string|null randomkey()
* @method mixed rename($key, $target)
* @method int renamenx($key, $target)
* @method array scan($cursor, array $options = null)
* @method array sort($key, array $options = null)
* @method int ttl($key)
* @method mixed type($key)
* @method int append($key, $value)
* @method int bitcount($key, $start = null, $end = null)
* @method int bitop($operation, $destkey, $key)
* @method array|null bitfield($key, $subcommand, ...$subcommandArg)
* @method int bitpos($key, $bit, $start = null, $end = null)
* @method int decr($key)
* @method int decrby($key, $decrement)
* @method string|null get($key)
* @method int getbit($key, $offset)
* @method string getrange($key, $start, $end)
* @method string|null getset($key, $value)
* @method int incr($key)
* @method int incrby($key, $increment)
* @method string incrbyfloat($key, $increment)
* @method array mget(array $keys)
* @method mixed mset(array $dictionary)
* @method int msetnx(array $dictionary)
* @method mixed psetex($key, $milliseconds, $value)
* @method mixed set($key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
* @method int setbit($key, $offset, $value)
* @method int setex($key, $seconds, $value)
* @method int setnx($key, $value)
* @method int setrange($key, $offset, $value)
* @method int strlen($key)
* @method int hdel($key, array $fields)
* @method int hexists($key, $field)
* @method string|null hget($key, $field)
* @method array hgetall($key)
* @method int hincrby($key, $field, $increment)
* @method string hincrbyfloat($key, $field, $increment)
* @method array hkeys($key)
* @method int hlen($key)
* @method array hmget($key, array $fields)
* @method mixed hmset($key, array $dictionary)
* @method array hscan($key, $cursor, array $options = null)
* @method int hset($key, $field, $value)
* @method int hsetnx($key, $field, $value)
* @method array hvals($key)
* @method int hstrlen($key, $field)
* @method array|null blpop(array|string $keys, $timeout)
* @method array|null brpop(array|string $keys, $timeout)
* @method string|null brpoplpush($source, $destination, $timeout)
* @method string|null lindex($key, $index)
* @method int linsert($key, $whence, $pivot, $value)
* @method int llen($key)
* @method string|null lpop($key)
* @method int lpush($key, array $values)
* @method int lpushx($key, array $values)
* @method array lrange($key, $start, $stop)
* @method int lrem($key, $count, $value)
* @method mixed lset($key, $index, $value)
* @method mixed ltrim($key, $start, $stop)
* @method string|null rpop($key)
* @method string|null rpoplpush($source, $destination)
* @method int rpush($key, array $values)
* @method int rpushx($key, array $values)
* @method int sadd($key, array $members)
* @method int scard($key)
* @method array sdiff(array|string $keys)
* @method int sdiffstore($destination, array|string $keys)
* @method array sinter(array|string $keys)
* @method int sinterstore($destination, array|string $keys)
* @method int sismember($key, $member)
* @method array smembers($key)
* @method int smove($source, $destination, $member)
* @method string|null spop($key, $count = null)
* @method string|null srandmember($key, $count = null)
* @method int srem($key, $member)
* @method array sscan($key, $cursor, array $options = null)
* @method array sunion(array|string $keys)
* @method int sunionstore($destination, array|string $keys)
* @method int zadd($key, array $membersAndScoresDictionary)
* @method int zcard($key)
* @method string zcount($key, $min, $max)
* @method string zincrby($key, $increment, $member)
* @method int zinterstore($destination, array|string $keys, array $options = null)
* @method array zrange($key, $start, $stop, array $options = null)
* @method array zrangebyscore($key, $min, $max, array $options = null)
* @method int|null zrank($key, $member)
* @method int zrem($key, $member)
* @method int zremrangebyrank($key, $start, $stop)
* @method int zremrangebyscore($key, $min, $max)
* @method array zrevrange($key, $start, $stop, array $options = null)
* @method array zrevrangebyscore($key, $max, $min, array $options = null)
* @method int|null zrevrank($key, $member)
* @method int zunionstore($destination, array|string $keys, array $options = null)
* @method string|null zscore($key, $member)
* @method array zscan($key, $cursor, array $options = null)
* @method array zrangebylex($key, $start, $stop, array $options = null)
* @method array zrevrangebylex($key, $start, $stop, array $options = null)
* @method int zremrangebylex($key, $min, $max)
* @method int zlexcount($key, $min, $max)
* @method int pfadd($key, array $elements)
* @method mixed pfmerge($destinationKey, array|string $sourceKeys)
* @method int pfcount(array|string $keys)
* @method mixed pubsub($subcommand, $argument)
* @method int publish($channel, $message)
* @method mixed discard()
* @method array|null exec()
* @method mixed multi()
* @method mixed unwatch()
* @method mixed watch($key)
* @method mixed eval($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
* @method mixed evalsha($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
* @method mixed script($subcommand, $argument = null)
* @method mixed auth($password)
* @method string echo($message)
* @method mixed ping($message = null)
* @method mixed select($database)
* @method mixed bgrewriteaof()
* @method mixed bgsave()
* @method mixed client($subcommand, $argument = null)
* @method mixed config($subcommand, $argument = null)
* @method int dbsize()
* @method mixed flushall()
* @method mixed flushdb()
* @method array info($section = null)
* @method int lastsave()
* @method mixed save()
* @method mixed slaveof($host, $port)
* @method mixed slowlog($subcommand, $argument = null)
* @method array time()
* @method array command()
* @method int geoadd($key, $longitude, $latitude, $member)
* @method array geohash($key, array $members)
* @method array geopos($key, array $members)
* @method string|null geodist($key, $member1, $member2, $unit = null)
* @method array georadius($key, $longitude, $latitude, $radius, $unit, array $options = null)
* @method array georadiusbymember($key, $member, $radius, $unit, array $options = null)
*
* @author Daniele Alessandri <suppakilla@gmail.com>
*/
+1 -1
View File
@@ -161,7 +161,7 @@ class HashRing implements DistributorInterface, HashGeneratorInterface
$replicas = (int) round($weightRatio * $totalNodes * $replicas);
for ($i = 0; $i < $replicas; ++$i) {
$key = crc32("$nodeHash:$i");
$key = $this->hash("$nodeHash:$i");
$ring[$key] = $nodeObject;
}
}
+7 -3
View File
@@ -173,13 +173,17 @@ class Factory implements FactoryInterface
{
$parameters = $connection->getParameters();
if (isset($parameters->password)) {
if (isset($parameters->password) && strlen($parameters->password)) {
$cmdAuthArgs = isset($parameters->username) && strlen($parameters->username)
? array('AUTH', $parameters->username, $parameters->password)
: array('AUTH', $parameters->password);
$connection->addConnectCommand(
new RawCommand(array('AUTH', $parameters->password))
new RawCommand($cmdAuthArgs)
);
}
if (isset($parameters->database)) {
if (isset($parameters->database) && strlen($parameters->database)) {
$connection->addConnectCommand(
new RawCommand(array('SELECT', $parameters->database))
);
-26
View File
@@ -89,31 +89,6 @@ class ReplicationStrategy
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 Command instance.
*
* @return bool
*/
protected function isSortReadOnly(CommandInterface $command)
{
$arguments = $command->getArguments();
$argc = count($arguments);
if ($argc > 1) {
for ($i = 1; $i < $argc; ++$i) {
$argument = strtoupper($arguments[$i]);
if ($argument === 'STORE') {
return false;
}
}
}
return true;
}
/**
* Checks if BITFIELD performs a read-only operation by looking for certain
* SET and INCRYBY modifiers in the arguments array of the command.
@@ -292,7 +267,6 @@ class ReplicationStrategy
'BITPOS' => true,
'TIME' => true,
'PFCOUNT' => true,
'SORT' => array($this, 'isSortReadOnly'),
'BITFIELD' => array($this, 'isBitfieldReadOnly'),
'GEOHASH' => true,
'GEOPOS' => true,
+7 -5
View File
@@ -853,15 +853,17 @@ class ClientTest extends PredisTestCase
/**
* @group disconnected
* @expectedException \Predis\ClientException
* @expectedExceptionMessage The underlying connection is not traversable
*/
public function testGetIteratorWithNonTraversableConnectionThrowsException()
public function testGetIteratorWithNonTraversableConnectionNoException()
{
$connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
$connection = $this->getMockConnection('tcp://127.0.0.1:6381');
$client = new Client($connection);
$client->getIterator();
$iterator = $client->getIterator();
$this->assertInstanceOf('\Predis\Client', $nodeClient = $iterator->current());
$this->assertSame($connection, $nodeClient->getConnection());
$this->assertSame('127.0.0.1:6381', $iterator->key());
}
// ******************************************************************** //
+13 -2
View File
@@ -102,13 +102,24 @@ class ServerCommandTest extends PredisCommandTestCase
{
$redis = $this->getClient();
$expected = array(array('get', 2, array('readonly', 'fast'), 1, 1, 1));
// NOTE: starting with Redis 6.0 and the introduction of Access Control
// Lists, COMMAND INFO returns an additional array for each specified
// command in yhe request with a list of the ACL categories associated
// to a command. We simply append this additional array in the expected
// response if the test suite is executed against Redis >= 6.0.
if ($this->isRedisServerVersion('>=', '6.0')) {
$expected[0][] = array('@read', '@string', '@fast');
}
$this->assertCount(1, $response = $redis->command('INFO', 'GET'));
// NOTE: we use assertEquals instead of assertSame because Redis returns
// flags as +STATUS responses, represented by Predis with instances of
// Predis\Response\Status instead of plain strings. This class responds
// to __toString() so the string conversion is implicit, but assertSame
// checks for strict equality while assertEquals is loose.
$expected = array(array('get', 2, array('readonly', 'fast'), 1, 1, 1));
$this->assertCount(1, $response = $redis->command('INFO', 'GET'));
$this->assertEquals($expected, $response);
}
@@ -541,29 +541,6 @@ class MasterSlaveReplicationTest extends PredisTestCase
$replication->executeCommand($cmdEval);
}
/**
* @group disconnected
*/
public function testSortTriggersSwitchToMasterConnectionOnStoreModifier()
{
$profile = Profile\Factory::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
*/
+129 -2
View File
@@ -280,8 +280,6 @@ class FactoryTest extends PredisTestCase
/**
* @group disconnected
*
* @todo This test smells but there's no other way around it right now.
*/
public function testCreateConnectionWithInitializationCommands()
{
@@ -303,6 +301,111 @@ class FactoryTest extends PredisTestCase
$factory = new Factory();
// TODO: using reflection to make a protected method accessible :facepalm:
$reflection = new \ReflectionObject($factory);
$prepareConnection = $reflection->getMethod('prepareConnection');
$prepareConnection->setAccessible(true);
$prepareConnection->invoke($factory, $connection);
}
/**
* @group disconnected
*/
public function testCreateConnectionWithPasswordAndNoUsernameAddsInitializationCommandAuthWithOneArgument()
{
$parameters = new Parameters(array(
'password' => 'foobar',
));
$connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
$connection->expects($this->once())
->method('getParameters')
->will($this->returnValue($parameters));
$connection->expects($this->once(1))
->method('addConnectCommand')
->with($this->isRedisCommand('AUTH', array('foobar')));
$factory = new Factory();
// TODO: using reflection to make a protected method accessible :facepalm:
$reflection = new \ReflectionObject($factory);
$prepareConnection = $reflection->getMethod('prepareConnection');
$prepareConnection->setAccessible(true);
$prepareConnection->invoke($factory, $connection);
}
/**
* @group disconnected
*/
public function testCreateConnectionWithPasswordAndUsernameAddsInitializationCommandAuthWithTwoArguments()
{
$parameters = new Parameters(array(
'username' => 'myusername',
'password' => 'foobar',
));
$connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
$connection->expects($this->once())
->method('getParameters')
->will($this->returnValue($parameters));
$connection->expects($this->once(1))
->method('addConnectCommand')
->with($this->isRedisCommand('AUTH', array('myusername', 'foobar')));
$factory = new Factory();
// TODO: using reflection to make a protected method accessible :facepalm:
$reflection = new \ReflectionObject($factory);
$prepareConnection = $reflection->getMethod('prepareConnection');
$prepareConnection->setAccessible(true);
$prepareConnection->invoke($factory, $connection);
}
/**
* @group disconnected
*/
public function testCreateConnectionWithUsernameAndNoPasswordDoesNotAddInitializationCommands()
{
$parameters = new Parameters(array(
'username' => 'myusername',
));
$connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
$connection->expects($this->once())
->method('getParameters')
->will($this->returnValue($parameters));
$connection->expects($this->never())
->method('addConnectCommand');
$factory = new Factory();
// TODO: using reflection to make a protected method accessible :facepalm:
$reflection = new \ReflectionObject($factory);
$prepareConnection = $reflection->getMethod('prepareConnection');
$prepareConnection->setAccessible(true);
$prepareConnection->invoke($factory, $connection);
}
/**
* @group disconnected
* @dataProvider provideEmptyParametersForInitializationCommands
*/
public function testCreateConnectionWithEmptyParametersDoesNotAddInitializationCommands($parameter, $value)
{
$parameters = new Parameters(array(
$parameter => $value,
));
$connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
$connection->expects($this->once())
->method('getParameters')
->will($this->returnValue($parameters));
$connection->expects($this->never())
->method('addConnectCommand');
$factory = new Factory();
// TODO: using reflection to make a protected method accessible :facepalm:
$reflection = new \ReflectionObject($factory);
$prepareConnection = $reflection->getMethod('prepareConnection');
$prepareConnection->setAccessible(true);
@@ -487,4 +590,28 @@ class FactoryTest extends PredisTestCase
return array($connection, get_class($connection));
}
/**
* Provides empty values for specific parameters.
*
* These parameters usually trigger the addition of initializatin commands
* to connection instances like `password` => AUTH and `database` => SELECT,
* but they should not be added when their values are NULL or empty strings.
*
* @return array
*/
public function provideEmptyParametersForInitializationCommands()
{
return array(
// AUTH
array('username', ''),
array('username', null),
array('password', ''),
array('password', null),
// SELECT
array('database', ''),
array('database', null),
);
}
}
+22
View File
@@ -297,11 +297,27 @@ class ConsumerTest extends PredisTestCase
// ---- INTEGRATION TESTS --------------------------------------------- //
// ******************************************************************** //
// NOTE: the following 2 tests fail at random without any apparent reason
// when executed on our CI environments and these failures are not tied
// to a particular version of PHP or Redis. It is most likely some weird
// timing issue on busy systems as it is really rare to get it triggered
// locally. The chances it is a bug in the library are pretty low so for
// now we just mark this test skipped on our CI environments (but still
// enabled for local test runs) and "debug" this issue using a separate
// branch to avoid having spurious failures on main development branches
// which is utterly annoying.
/**
* @group connected
*/
public function testPubSubAgainstRedisServer()
{
if (getenv('GITHUB_ACTIONS') || getenv('TRAVIS')) {
$this->markTestSkipped(
'Test temporarily skipped on CI environments, see note in the body of the test'
);
}
$parameters = array(
'host' => REDIS_SERVER_HOST,
'port' => REDIS_SERVER_PORT,
@@ -347,6 +363,12 @@ class ConsumerTest extends PredisTestCase
*/
public function testPubSubAgainstRedisServerBlocking()
{
if (getenv('GITHUB_ACTIONS') || getenv('TRAVIS')) {
$this->markTestSkipped(
'Test temporarily skipped on CI environments, see note in the body of the test'
);
}
$parameters = array(
'host' => REDIS_SERVER_HOST,
'port' => REDIS_SERVER_PORT,
@@ -81,15 +81,15 @@ class ReplicationStrategyTest extends PredisTestCase
$profile = Profile\Factory::getDevelopment();
$strategy = new ReplicationStrategy();
$cmdReadSort = $profile->createCommand('SORT', array('key:list'));
$this->assertTrue(
$strategy->isReadOperation($cmdReadSort),
'SORT is expected to be a read operation.'
$cmdReturnSort = $profile->createCommand('SORT', array('key:list'));
$this->assertFalse(
$strategy->isReadOperation($cmdReturnSort),
'SORT is expected to be a write operation.'
);
$cmdWriteSort = $profile->createCommand('SORT', array('key:list', array('store' => 'key:stored')));
$cmdStoreSort = $profile->createCommand('SORT', array('key:list', array('store' => 'key:stored')));
$this->assertFalse(
$strategy->isReadOperation($cmdWriteSort),
$strategy->isReadOperation($cmdStoreSort),
'SORT with STORE is expected to be a write operation.'
);
}