Browse Source

Fix MONITOR and Predis\MonitorContext with Redis 2.6.

Starting with 2.6, Redis uses a slightly different format for the payload
returned by MONITOR for each command. Predis can now adapt to this difference
and returns a new `client` field in the payload object. This new field is
always defined but is set to NULL when connected to Redis < 2.6.

Please note that Redis 2.6 now does not echo the `MONITOR` command as the
first payload when opening a new MONITOR context.
Daniele Alessandri 13 years ago
parent
commit
f0f3d7814c

+ 12 - 4
lib/Predis/MonitorContext.php

@@ -132,21 +132,29 @@ class MonitorContext implements \Iterator
     private function getValue()
     {
         $database = 0;
+        $client = null;
         $event = $this->client->getConnection()->read();
 
-        $callback = function($matches) use (&$database) {
-            if (isset($matches[1])) {
+        $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+)\) /', $callback, $event, 1);
-        @list($timestamp, $command, $arguments) = split(' ', $event, 3);
+        $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,
         );

+ 6 - 4
tests/Predis/Commands/ServerMonitorTest.php

@@ -64,9 +64,11 @@ class ServerMonitorTest extends CommandTestCase
         $command = $this->getCommand();
 
         $this->assertTrue($connection->executeCommand($command));
-        // TODO: this test currently fails with the unstable branch of Redis, but
-        //       I still have to find the reason since at first sight the reply
-        //       format has not changed.
-        $this->assertRegExp('/\d+.\d+(\s?\(db \d+\))? "MONITOR"/', $connection->read());
+
+        // 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());
+        }
     }
 }

+ 25 - 1
tests/Predis/MonitorContextTest.php

@@ -105,7 +105,7 @@ class MonitorContextTest extends StandardTestCase
     /**
      * @group disconnected
      */
-    public function testCurrentReadsMessageFromConnection()
+    public function testReadsMessageFromConnectionToRedis24()
     {
         $message = '1323367530.939137 (db 15) "MONITOR"';
 
@@ -120,6 +120,30 @@ class MonitorContextTest extends StandardTestCase
         $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\Network\IConnectionSingle');
+        $connection->expects($this->once())
+                   ->method('read')
+                   ->will($this->returnValue($message));
+
+        $client = new Client($connection);
+        $monitor = new MonitorContext($client);
+
+        $payload = $monitor->current();
+        $this->assertSame(1323367530, (int) $payload->timestamp);
+        $this->assertSame(15, $payload->database);
+        $this->assertSame('127.0.0.1:37265', $payload->client);
         $this->assertSame('MONITOR', $payload->command);
         $this->assertNull($payload->arguments);
     }