* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Predis; use PredisTestCase; /** * */ class ClientTest extends PredisTestCase { /** * @group disconnected */ public function testConstructorWithoutArguments() { $client = new Client(); $connection = $client->getConnection(); $this->assertInstanceOf('Predis\Connection\NodeConnectionInterface', $connection); $parameters = $connection->getParameters(); $this->assertSame($parameters->host, '127.0.0.1'); $this->assertSame($parameters->port, 6379); $options = $client->getOptions(); $this->assertSame($options->commands, $client->getCommandFactory()); $this->assertFalse($client->isConnected()); } /** * @group disconnected */ public function testConstructorWithNullArgument() { $client = new Client(null); $connection = $client->getConnection(); $this->assertInstanceOf('Predis\Connection\NodeConnectionInterface', $connection); $parameters = $connection->getParameters(); $this->assertSame($parameters->host, '127.0.0.1'); $this->assertSame($parameters->port, 6379); $options = $client->getOptions(); $this->assertSame($options->commands, $client->getCommandFactory()); $this->assertFalse($client->isConnected()); } /** * @group disconnected */ public function testConstructorWithNullAndNullArguments() { $client = new Client(null, null); $connection = $client->getConnection(); $this->assertInstanceOf('Predis\Connection\NodeConnectionInterface', $connection); $parameters = $connection->getParameters(); $this->assertSame($parameters->host, '127.0.0.1'); $this->assertSame($parameters->port, 6379); $options = $client->getOptions(); $this->assertSame($options->commands, $client->getCommandFactory()); $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 * @expectedException \InvalidArgumentException * @expectedExceptionMessage Array of connection parameters requires `cluster`, `replication` or `aggregate` client option */ public function testConstructorThrowsExceptionWithArrayOfParametersArgumentAndMissingOption() { $arg1 = array( array('host' => 'localhost', 'port' => 7000), array('host' => 'localhost', 'port' => 7001), ); $client = new Client($arg1); } /** * @group disconnected */ public function testConstructorWithArrayOfArrayArgumentAndClusterOption() { $arg1 = array( array('host' => 'localhost', 'port' => 7000), array('host' => 'localhost', 'port' => 7001), ); $client = new Client($arg1, array( 'aggregate' => $this->getAggregateInitializer($arg1), )); $this->assertInstanceOf('Predis\Connection\AggregateConnectionInterface', $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() { $arg1 = array('tcp://localhost:7000', 'tcp://localhost:7001'); $client = new Client($arg1, array( 'aggregate' => $this->getAggregateInitializer($arg1), )); $this->assertInstanceOf('Predis\Connection\AggregateConnectionInterface', $client->getConnection()); } /** * @group disconnected */ public function testConstructorWithArrayOfConnectionsArgument() { $arg1 = array( $this->getMock('Predis\Connection\NodeConnectionInterface'), $this->getMock('Predis\Connection\NodeConnectionInterface'), ); $client = new Client($arg1, array( 'aggregate' => $this->getAggregateInitializer($arg1), )); $this->assertInstanceOf('Predis\Connection\AggregateConnectionInterface', $client->getConnection()); } /** * @group disconnected */ public function testConstructorWithConnectionArgument() { $factory = new Connection\Factory(); $connection = $factory->create('tcp://localhost:7000'); $client = new Client($connection); $this->assertInstanceOf('Predis\Connection\NodeConnectionInterface', $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 Connection\Cluster\PredisCluster(); $factory = new Connection\Factory(); $factory->aggregate($cluster, array('tcp://localhost:7000', 'tcp://localhost:7001')); $client = new Client($cluster); $this->assertInstanceOf('Predis\Connection\Cluster\ClusterInterface', $client->getConnection()); $this->assertSame($cluster, $client->getConnection()); } /** * @group disconnected */ public function testConstructorWithReplicationArgument() { $replication = new Connection\Replication\MasterSlaveReplication(); $factory = new Connection\Factory(); $factory->aggregate($replication, array('tcp://host1?alias=master', 'tcp://host2?alias=slave')); $client = new Client($replication); $this->assertInstanceOf('Predis\Connection\Replication\ReplicationInterface', $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\Configuration\OptionsInterface')) ->will($this->returnValue($connection)); $client = new Client($callable); $this->assertSame($connection, $client->getConnection()); } /** * @group disconnected * @expectedException \InvalidArgumentException * @expectedExceptionMessage Callable parameters must return a valid connection */ public function testConstructorWithCallableConnectionInitializerThrowsExceptionOnInvalidReturnType() { $wrongType = $this->getMock('stdClass'); $callable = $this->getMock('stdClass', array('__invoke')); $callable ->expects($this->once()) ->method('__invoke') ->with($this->isInstanceOf('Predis\Configuration\OptionsInterface')) ->will($this->returnValue($wrongType)); new Client($callable); } /** * @group disconnected */ public function testConstructorWithNullAndArrayArgument() { $connections = $this->getMock('Predis\Connection\FactoryInterface'); $arg2 = array('prefix' => 'prefix:', 'connections' => $connections); $client = new Client(null, $arg2); $this->assertInstanceOf('Predis\Command\FactoryInterface', $commands = $client->getCommandFactory()); $this->assertInstanceOf('Predis\Command\Processor\KeyPrefixProcessor', $commands->getProcessor()); $this->assertSame('prefix:', $commands->getProcessor()->getPrefix()); } /** * @group disconnected */ public function testConstructorWithArrayAndOptionReplication() { $arg1 = array('tcp://127.0.0.1:6379?role=master', 'tcp://127.0.0.1:6380?role=slave'); $arg2 = array('replication' => 'predis'); $client = new Client($arg1, $arg2); $this->assertInstanceOf('Predis\Connection\Replication\ReplicationInterface', $connection = $client->getConnection()); $this->assertSame('127.0.0.1:6379', (string) $connection->getConnectionByRole('master')); $this->assertSame('127.0.0.1:6380', (string) $connection->getConnectionByRole('slave')); } /** * @group disconnected */ public function testClusterOptionHasPrecedenceOverReplicationOptionAndAggregateOption() { $arg1 = array('tcp://host1', 'tcp://host2'); $connection = $this->getMock('Predis\Connection\AggregateConnectionInterface'); $fncluster = $this->getMock('stdClass', array('__invoke')); $fncluster ->expects($this->once()) ->method('__invoke') ->with($this->isInstanceOf('Predis\Configuration\OptionsInterface'), $arg1) ->will($this->returnValue($connection)); $fnreplication = $this->getMock('stdClass', array('__invoke')); $fnreplication ->expects($this->never()) ->method('__invoke'); $fnaggregate = $this->getMock('stdClass', array('__invoke')); $fnaggregate ->expects($this->never()) ->method('__invoke'); $arg2 = array( 'cluster' => $fncluster, 'replication' => $fnreplication, 'aggregate' => $fnaggregate, ); $client = new Client($arg1, $arg2); $this->assertSame($connection, $client->getConnection()); } /** * @group disconnected */ public function testReplicationOptionHasPrecedenceOverAggregateOption() { $arg1 = array('tcp://host1', 'tcp://host2'); $connection = $this->getMock('Predis\Connection\AggregateConnectionInterface'); $fnreplication = $this->getMock('stdClass', array('__invoke')); $fnreplication ->expects($this->once()) ->method('__invoke') ->with($this->isInstanceOf('Predis\Configuration\OptionsInterface'), $arg1) ->will($this->returnValue($connection)); $fnaggregate = $this->getMock('stdClass', array('__invoke')); $fnaggregate->expects($this->never())->method('__invoke'); $arg2 = array( 'replication' => $fnreplication, 'aggregate' => $fnaggregate, ); $client = new Client($arg1, $arg2); $this->assertSame($connection, $client->getConnection()); } /** * @group disconnected */ public function testAggregateOptionDoesNotTriggerAggregationInClient() { $arg1 = array('tcp://host1', 'tcp://host2'); $connection = $this->getMock('Predis\Connection\AggregateConnectionInterface'); $fnaggregate = $this->getMock('stdClass', array('__invoke')); $fnaggregate ->expects($this->once()) ->method('__invoke') ->with($this->isInstanceOf('Predis\Configuration\OptionsInterface'), $arg1) ->will($this->returnValue($connection)); $connections = $this->getMock('Predis\Connection\FactoryInterface'); $connections ->expects($this->never()) ->method('aggregate'); $arg2 = array('aggregate' => $fnaggregate, 'connections' => $connections); $client = new Client($arg1, $arg2); $this->assertSame($connection, $client->getConnection()); } /** * @group disconnected * @expectedException \InvalidArgumentException * @expectedExceptionMessage Invalid type for connection parameters */ public function testConstructorWithInvalidArgumentType() { $client = new Client(new \stdClass()); } /** * @group disconnected * @expectedException \InvalidArgumentException * @expectedExceptionMessage Invalid type for client options */ public function testConstructorWithInvalidOptionType() { $client = new Client('tcp://host1', new \stdClass()); } /** * @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 testCreatesNewCommandUsingSpecifiedCommandFactory() { $ping = $this->getCommandFactory()->createCommand('ping', array()); $commands = $this->getMock('Predis\Command\FactoryInterface'); $commands ->expects($this->once()) ->method('createCommand') ->with('ping', array()) ->will($this->returnValue($ping)); $client = new Client(null, array('commands' => $commands)); $this->assertSame($ping, $client->createCommand('ping', array())); } /** * @group disconnected */ public function testExecuteCommandReturnsParsedResponses() { $commands = $this->getCommandFactory(); $ping = $commands->createCommand('ping', array()); $hgetall = $commands->createCommand('hgetall', array('metavars', 'foo', 'hoge')); $connection = $this->getMock('Predis\Connection\ConnectionInterface'); $connection ->expects($this->at(0)) ->method('executeCommand') ->with($ping) ->will($this->returnValue(new Response\Status('PONG'))); $connection ->expects($this->at(1)) ->method('executeCommand') ->with($hgetall) ->will($this->returnValue(array('foo', 'bar', 'hoge', 'piyo'))); $client = new Client($connection); $this->assertEquals('PONG', $client->executeCommand($ping)); $this->assertSame(array('foo' => 'bar', 'hoge' => 'piyo'), $client->executeCommand($hgetall)); } /** * @group disconnected * @expectedException \Predis\Response\ServerException * @expectedExceptionMessage Operation against a key holding the wrong kind of value */ public function testExecuteCommandThrowsExceptionOnRedisError() { $ping = $this->getCommandFactory()->createCommand('ping', array()); $expectedResponse = new Response\Error('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 = $this->getCommandFactory()->createCommand('ping', array()); $expectedResponse = new Response\Error('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 = $this->getCommandFactory()->createCommand('ping', array()); $connection = $this->getMock('Predis\Connection\ConnectionInterface'); $connection ->expects($this->once()) ->method('executeCommand') ->with($this->isInstanceOf('Predis\Command\Redis\PING')) ->will($this->returnValue('PONG')); $commands = $this->getMock('Predis\Command\FactoryInterface'); $commands ->expects($this->once()) ->method('createCommand') ->with('ping', array()) ->will($this->returnValue($ping)); $options = array('commands' => $commands); $client = $this->getMock('Predis\Client', null, array($connection, $options)); $this->assertEquals('PONG', $client->ping()); } /** * @group disconnected * @expectedException \Predis\Response\ServerException * @expectedExceptionMessage Operation against a key holding the wrong kind of value */ public function testCallingRedisCommandThrowsExceptionOnServerError() { $expectedResponse = new Response\Error('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->isRedisCommand('PING')) ->will($this->returnValue($expectedResponse)); $client = new Client($connection); $client->ping(); } /** * @group disconnected */ public function testCallingRedisCommandReturnsErrorResponseOnRedisError() { $expectedResponse = new Response\Error('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->isRedisCommand('PING')) ->will($this->returnValue($expectedResponse)); $client = new Client($connection, array('exceptions' => false)); $response = $client->ping(); $this->assertSame($response, $expectedResponse); } /** * @group disconnected */ public function testRawCommand() { $connection = $this->getMock('Predis\Connection\ConnectionInterface'); $connection ->expects($this->at(0)) ->method('executeCommand') ->with($this->isRedisCommand('SET', array('foo', 'bar'))) ->will($this->returnValue(new Response\Status('OK'))); $connection ->expects($this->at(1)) ->method('executeCommand') ->with($this->isRedisCommand('GET', array('foo'))) ->will($this->returnValue('bar')); $connection ->expects($this->at(2)) ->method('executeCommand') ->with($this->isRedisCommand('PING')) ->will($this->returnValue('PONG')); $client = new Client($connection); $this->assertSame('OK', $client->executeRaw(array('SET', 'foo', 'bar'))); $this->assertSame('bar', $client->executeRaw(array('GET', 'foo'))); $error = true; // $error is always populated by reference. $this->assertSame('PONG', $client->executeRaw(array('PING'), $error)); $this->assertFalse($error); } /** * @group disconnected */ public function testRawCommandNeverAppliesPrefix() { $connection = $this->getMock('Predis\Connection\ConnectionInterface'); $connection ->expects($this->at(0)) ->method('executeCommand') ->with($this->isRedisCommand('SET', array('foo', 'bar'))) ->will($this->returnValue(new Response\Status('OK'))); $connection ->expects($this->at(1)) ->method('executeCommand') ->with($this->isRedisCommand('GET', array('foo'))) ->will($this->returnValue('bar')); $client = new Client($connection, array('prefix' => 'predis:')); $this->assertSame('OK', $client->executeRaw(array('SET', 'foo', 'bar'))); $this->assertSame('bar', $client->executeRaw(array('GET', 'foo'))); } /** * @group disconnected */ public function testRawCommandNeverThrowsExceptions() { $message = 'ERR Mock error response'; $response = new Response\Error($message); $connection = $this->getMock('Predis\Connection\ConnectionInterface'); $connection ->expects($this->once()) ->method('executeCommand') ->with($this->isRedisCommand('PING')) ->will($this->returnValue($response)); $client = new Client($connection, array('exceptions' => true)); $this->assertSame($message, $client->executeRaw(array('PING'), $error)); $this->assertTrue($error); } /** * @group disconnected * @expectedException \Predis\ClientException * @expectedExceptionMessage Command 'INVALIDCOMMAND' is not a registered Redis command. */ public function testThrowsExceptionOnNonRegisteredRedisCommand() { $client = new Client(); $client->invalidCommand(); } /** * @group disconnected */ public function testGetClientByMethodReturnsInstanceOfSubclass() { $nodes = array('tcp://host1?alias=node01', 'tcp://host2?alias=node02'); $client = $this->getMock('Predis\Client', array('dummy'), array($nodes, array('cluster' => 'predis')), 'SubclassedClient'); $this->assertInstanceOf('SubclassedClient', $client->getClientBy('alias', 'node02')); } /** * @group disconnected */ public function testGetClientByMethodInvokesCallableInSecondArgumentAndReturnsItsReturnValue() { $test = $this; $client = new Client(array('tcp://host1?alias=node01', 'tcp://host2?alias=node02'), array('cluster' => 'predis')); $callable = $this->getMock('stdClass', array('__invoke')); $callable ->expects($this->once()) ->method('__invoke') ->with($this->callback(function ($clientNode) use ($test, $client) { $test->isInstanceOf('Predis\ClientInterface', $clientNode); $test->assertNotSame($client, $clientNode); $test->assertInstanceOf('Predis\Connection\NodeConnectionInterface', $connection = $clientNode->getConnection()); $test->assertSame('node02', $connection->getParameters()->alias); return true; })) ->will($this->returnValue('value')); $this->assertSame('value', $client->getClientBy('alias', 'node02', $callable)); } /** * @group disconnected */ public function testGetClientByMethodSupportsSelectingConnectionById() { $connection = $this->getMock('Predis\Connection\NodeConnectionInterface'); $aggregate = $this->getMockBuilder('Predis\Connection\AggregateConnectionInterface') ->setMethods(array('getConnectionById')) ->getMockForAbstractClass(); $aggregate ->expects($this->once()) ->method('getConnectionById') ->with('127.0.0.1:6379') ->will($this->returnValue($connection)); $client = new Client($aggregate); $nodeClient = $client->getClientBy('id', '127.0.0.1:6379'); $this->assertSame($connection, $nodeClient->getConnection()); $this->assertSame($client->getOptions(), $nodeClient->getOptions()); } /** * @group disconnected * @expectedException \InvalidArgumentException * @expectedExceptionMessage Cannot find a connection by id matching `127.0.0.1:7000` */ public function testGetClientByMethodThrowsExceptionSelectingConnectionByUnknownId() { $aggregate = $this->getMock('Predis\Connection\AggregateConnectionInterface'); $aggregate ->expects($this->once()) ->method('getConnectionById') ->with('127.0.0.1:7000') ->will($this->returnValue(null)); $client = new Client($aggregate); $client->getClientBy('id', '127.0.0.1:7000'); } /** * @group disconnected */ public function testGetClientByMethodSupportsSelectingConnectionByAlias() { $connection = $this->getMock('Predis\Connection\NodeConnectionInterface'); $aggregate = $this->getMockBuilder('Predis\Connection\AggregateConnectionInterface') ->setMethods(array('getConnectionByAlias')) ->getMockForAbstractClass(); $aggregate ->expects($this->once()) ->method('getConnectionByAlias') ->with('myalias') ->will($this->returnValue($connection)); $client = new Client($aggregate); $nodeClient = $client->getClientBy('alias', 'myalias'); $this->assertSame($connection, $nodeClient->getConnection()); $this->assertSame($client->getOptions(), $nodeClient->getOptions()); } /** * @group disconnected */ public function testGetClientByMethodSupportsSelectingConnectionByKey() { $connection = $this->getMock('Predis\Connection\NodeConnectionInterface'); $aggregate = $this->getMockBuilder('Predis\Connection\AggregateConnectionInterface') ->setMethods(array('getConnectionByKey')) ->getMockForAbstractClass(); $aggregate ->expects($this->once()) ->method('getConnectionByKey') ->with('key:1') ->will($this->returnValue($connection)); $client = new Client($aggregate); $nodeClient = $client->getClientBy('key', 'key:1'); $this->assertSame($connection, $nodeClient->getConnection()); $this->assertSame($client->getOptions(), $nodeClient->getOptions()); } /** * @group disconnected */ public function testGetClientByMethodSupportsSelectingConnectionBySlot() { $connection = $this->getMock('Predis\Connection\NodeConnectionInterface'); $aggregate = $this->getMockBuilder('Predis\Connection\AggregateConnectionInterface') ->setMethods(array('getConnectionBySlot')) ->getMockForAbstractClass(); $aggregate ->expects($this->once()) ->method('getConnectionBySlot') ->with(5460) ->will($this->returnValue($connection)); $client = new Client($aggregate); $nodeClient = $client->getClientBy('slot', 5460); $this->assertSame($connection, $nodeClient->getConnection()); $this->assertSame($client->getOptions(), $nodeClient->getOptions()); } /** * @group disconnected */ public function testGetClientByMethodSupportsSelectingConnectionByRole() { $connection = $this->getMock('Predis\Connection\NodeConnectionInterface'); $aggregate = $this->getMockBuilder('Predis\Connection\AggregateConnectionInterface') ->setMethods(array('getConnectionByRole')) ->getMockForAbstractClass(); $aggregate ->expects($this->once()) ->method('getConnectionByRole') ->with('master') ->will($this->returnValue($connection)); $client = new Client($aggregate); $nodeClient = $client->getClientBy('role', 'master'); $this->assertSame($connection, $nodeClient->getConnection()); $this->assertSame($client->getOptions(), $nodeClient->getOptions()); } /** * @group disconnected */ public function testGetClientByMethodSupportsSelectingConnectionByCommand() { $command = \Predis\Command\RawCommand::create('GET', 'key'); $connection = $this->getMock('Predis\Connection\NodeConnectionInterface'); $aggregate = $this->getMockBuilder('Predis\Connection\AggregateConnectionInterface') ->setMethods(array('getConnectionByCommand')) ->getMockForAbstractClass(); $aggregate ->expects($this->once()) ->method('getConnectionByCommand') ->with($command) ->will($this->returnValue($connection)); $client = new Client($aggregate); $nodeClient = $client->getClientBy('command', $command); $this->assertSame($connection, $nodeClient->getConnection()); $this->assertSame($client->getOptions(), $nodeClient->getOptions()); } /** * @group disconnected * @expectedException \InvalidArgumentException * @expectedExceptionMessage Invalid selector type: `unknown` */ public function testGetClientByMethodThrowsExceptionWhenSelectingConnectionByUnknownType() { $client = new Client('tcp://127.0.0.1?alias=node01'); $client->getClientBy('unknown', 'test'); } /** * @group disconnected * @expectedException \InvalidArgumentException * @expectedExceptionMessage Selecting connection by id is not supported by Predis\Connection\StreamConnection */ public function testGetClientByMethodThrowsExceptionWhenConnectionDoesNotSupportSelectorType() { $client = new Client('tcp://127.0.0.1?alias=node01'); $client->getClientBy('id', 'node01'); } /** * @group disconnected */ public function testPipelineWithoutArgumentsReturnsPipeline() { $client = new Client(); $this->assertInstanceOf('Predis\Pipeline\Pipeline', $client->pipeline()); } /** * @group disconnected */ public function testPipelineWithArrayReturnsPipeline() { $client = new Client(); $this->assertInstanceOf('Predis\Pipeline\Pipeline', $client->pipeline(array())); $this->assertInstanceOf('Predis\Pipeline\Atomic', $client->pipeline(array('atomic' => true))); $this->assertInstanceOf('Predis\Pipeline\FireAndForget', $client->pipeline(array('fire-and-forget' => true))); } /** * @group disconnected */ public function testPipelineWithCallableExecutesPipeline() { $callable = $this->getMock('stdClass', array('__invoke')); $callable ->expects($this->once()) ->method('__invoke') ->with($this->isInstanceOf('Predis\Pipeline\Pipeline')); $client = new Client(); $client->pipeline($callable); } /** * @group disconnected */ public function testPubSubLoopWithoutArgumentsReturnsPubSubConsumer() { $client = new Client(); $this->assertInstanceOf('Predis\PubSub\Consumer', $client->pubSubLoop()); } /** * @group disconnected */ public function testPubSubLoopWithArrayReturnsPubSubConsumerWithOptions() { $connection = $this->getMock('Predis\Connection\NodeConnectionInterface'); $options = array('subscribe' => 'channel'); $client = new Client($connection); $this->assertInstanceOf('Predis\PubSub\Consumer', $pubsub = $client->pubSubLoop($options)); $reflection = new \ReflectionProperty($pubsub, 'options'); $reflection->setAccessible(true); $this->assertSame($options, $reflection->getValue($pubsub)); } /** * @group disconnected */ public function testPubSubLoopWithArrayAndCallableExecutesPubSub() { // NOTE: we use a subscribe count of 0 in the message payload to trick // the context and forcing it to be closed since there are no more // active subscriptions. $connection = $this->getMock('Predis\Connection\NodeConnectionInterface'); $connection ->expects($this->once()) ->method('read') ->will($this->returnValue(array('subscribe', 'channel', 0))); $callable = $this->getMock('stdClass', array('__invoke')); $callable ->expects($this->once()) ->method('__invoke'); $client = new Client($connection); $this->assertNull($client->pubSubLoop(array('subscribe' => 'channel'), $callable)); } /** * @group disconnected */ public function testPubSubLoopWithCallableReturningFalseStopsPubSubConsumer() { $connection = $this->getMock('Predis\Connection\NodeConnectionInterface'); $connection ->expects($this->at(1)) ->method('read') ->will($this->returnValue(array('subscribe', 'channel', 1))); $connection ->expects($this->at(2)) ->method('writeRequest') ->with($this->isRedisCommand('UNSUBSCRIBE')); $connection ->expects($this->at(3)) ->method('read') ->will($this->returnValue(array('unsubscribe', 'channel', 0))); $callable = $this->getMock('stdClass', array('__invoke')); $callable ->expects($this->at(0)) ->method('__invoke') ->will($this->returnValue(false)); $client = new Client($connection); $this->assertNull($client->pubSubLoop(array('subscribe' => 'channel'), $callable)); } /** * @group disconnected */ public function testTransactionWithoutArgumentsReturnsMultiExec() { $client = new Client(); $this->assertInstanceOf('Predis\Transaction\MultiExec', $client->transaction()); } /** * @group disconnected */ public function testTransactionWithArrayReturnsMultiExecTransactionWithOptions() { $options = array('cas' => true, 'retry' => 3); $client = new Client(); $this->assertInstanceOf('Predis\Transaction\MultiExec', $tx = $client->transaction($options)); // I hate this part but reflection is the easiest way in this case. $property = new \ReflectionProperty($tx, 'modeCAS'); $property->setAccessible(true); $this->assertSame($options['cas'], $property->getValue($tx)); $property = new \ReflectionProperty($tx, 'attempts'); $property->setAccessible(true); $this->assertSame($options['retry'], $property->getValue($tx)); } /** * @group disconnected */ public function testTransactionWithArrayAndCallableExecutesMultiExec() { // We use CAS here as we don't care about the actual MULTI/EXEC context. $options = array('cas' => true, 'retry' => 3); $connection = $this->getMock('Predis\Connection\NodeConnectionInterface'); $connection ->expects($this->once()) ->method('executeCommand') ->will($this->returnValue(new Response\Status('QUEUED'))); $callable = $this->getMock('stdClass', array('__invoke')); $callable ->expects($this->once()) ->method('__invoke') ->will($this->returnCallback(function ($tx) { $tx->ping(); })); $client = new Client($connection); $client->transaction($options, $callable); } /** * @group disconnected */ public function testMonitorReturnsMonitorConsumer() { $connection = $this->getMock('Predis\Connection\NodeConnectionInterface'); $client = new Client($connection); $this->assertInstanceOf('Predis\Monitor\Consumer', $monitor = $client->monitor()); } /** * @group disconnected */ public function testClientResendScriptCommandUsingEvalOnNoScriptErrors() { $command = $this->getMockForAbstractClass('Predis\Command\ScriptCommand', 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\NodeConnectionInterface'); $connection ->expects($this->at(0)) ->method('executeCommand') ->with($command) ->will($this->returnValue(new Response\Error('NOSCRIPT'))); $connection ->expects($this->at(1)) ->method('executeCommand') ->with($this->isRedisCommand('EVAL')) ->will($this->returnValue('OK')); $client = new Client($connection); $this->assertTrue($client->executeCommand($command)); } /** * @group disconnected */ public function testGetIteratorWithTraversableConnections() { $connection1 = $this->getMockConnection('tcp://127.0.0.1:6381'); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6382'); $connection3 = $this->getMockConnection('tcp://127.0.0.1:6383'); $aggregate = new \Predis\Connection\Cluster\PredisCluster(); $aggregate->add($connection1); $aggregate->add($connection2); $aggregate->add($connection3); $client = new Client($aggregate); $iterator = $client->getIterator(); $this->assertInstanceOf('\Predis\Client', $nodeClient = $iterator->current()); $this->assertSame($connection1, $nodeClient->getConnection()); $this->assertSame('127.0.0.1:6381', $iterator->key()); $iterator->next(); $this->assertInstanceOf('\Predis\Client', $nodeClient = $iterator->current()); $this->assertSame($connection2, $nodeClient->getConnection()); $this->assertSame('127.0.0.1:6382', $iterator->key()); $iterator->next(); $this->assertInstanceOf('\Predis\Client', $nodeClient = $iterator->current()); $this->assertSame($connection3, $nodeClient->getConnection()); $this->assertSame('127.0.0.1:6383', $iterator->key()); } /** * @group disconnected * @expectedException \Predis\ClientException * @expectedExceptionMessage The underlying connection is not traversable */ public function testGetIteratorWithNonTraversableConnectionThrowsException() { $connection = $this->getMock('Predis\Connection\NodeConnectionInterface'); $client = new Client($connection); $client->getIterator(); } // ******************************************************************** // // ---- HELPER METHODS ------------------------------------------------ // // ******************************************************************** // /** * 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; } /** * Returns a mock callable simulating an aggregate connection initializer. * * @param mixed $parameters Expected connection parameters * * @return callable */ protected function getAggregateInitializer($parameters) { $connection = $this->getMock('Predis\Connection\AggregateConnectionInterface'); $callable = $this->getMock('stdClass', array('__invoke')); $callable ->expects($this->once()) ->method('__invoke') ->with($this->isInstanceOf('Predis\Configuration\OptionsInterface'), $parameters) ->will($this->returnValue($connection)); return $callable; } }