ClientTest.php 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971
  1. <?php
  2. /*
  3. * This file is part of the Predis package.
  4. *
  5. * (c) Daniele Alessandri <suppakilla@gmail.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Predis;
  11. use PredisTestCase;
  12. /**
  13. *
  14. */
  15. class ClientTest extends PredisTestCase
  16. {
  17. /**
  18. * @group disconnected
  19. */
  20. public function testConstructorWithoutArguments()
  21. {
  22. $client = new Client();
  23. $connection = $client->getConnection();
  24. $this->assertInstanceOf('Predis\Connection\NodeConnectionInterface', $connection);
  25. $parameters = $connection->getParameters();
  26. $this->assertSame($parameters->host, '127.0.0.1');
  27. $this->assertSame($parameters->port, 6379);
  28. $options = $client->getOptions();
  29. $this->assertSame($options->commands, $client->getCommandFactory());
  30. $this->assertFalse($client->isConnected());
  31. }
  32. /**
  33. * @group disconnected
  34. */
  35. public function testConstructorWithNullArgument()
  36. {
  37. $client = new Client(null);
  38. $connection = $client->getConnection();
  39. $this->assertInstanceOf('Predis\Connection\NodeConnectionInterface', $connection);
  40. $parameters = $connection->getParameters();
  41. $this->assertSame($parameters->host, '127.0.0.1');
  42. $this->assertSame($parameters->port, 6379);
  43. $options = $client->getOptions();
  44. $this->assertSame($options->commands, $client->getCommandFactory());
  45. $this->assertFalse($client->isConnected());
  46. }
  47. /**
  48. * @group disconnected
  49. */
  50. public function testConstructorWithNullAndNullArguments()
  51. {
  52. $client = new Client(null, null);
  53. $connection = $client->getConnection();
  54. $this->assertInstanceOf('Predis\Connection\NodeConnectionInterface', $connection);
  55. $parameters = $connection->getParameters();
  56. $this->assertSame($parameters->host, '127.0.0.1');
  57. $this->assertSame($parameters->port, 6379);
  58. $options = $client->getOptions();
  59. $this->assertSame($options->commands, $client->getCommandFactory());
  60. $this->assertFalse($client->isConnected());
  61. }
  62. /**
  63. * @group disconnected
  64. */
  65. public function testConstructorWithArrayArgument()
  66. {
  67. $client = new Client($arg1 = array('host' => 'localhost', 'port' => 7000));
  68. $parameters = $client->getConnection()->getParameters();
  69. $this->assertSame($parameters->host, $arg1['host']);
  70. $this->assertSame($parameters->port, $arg1['port']);
  71. }
  72. /**
  73. * @group disconnected
  74. * @expectedException \InvalidArgumentException
  75. * @expectedExceptionMessage Array of connection parameters requires `cluster`, `replication` or `aggregate` client option
  76. */
  77. public function testConstructorThrowsExceptionWithArrayOfParametersArgumentAndMissingOption()
  78. {
  79. $arg1 = array(
  80. array('host' => 'localhost', 'port' => 7000),
  81. array('host' => 'localhost', 'port' => 7001),
  82. );
  83. $client = new Client($arg1);
  84. }
  85. /**
  86. * @group disconnected
  87. */
  88. public function testConstructorWithArrayOfArrayArgumentAndClusterOption()
  89. {
  90. $arg1 = array(
  91. array('host' => 'localhost', 'port' => 7000),
  92. array('host' => 'localhost', 'port' => 7001),
  93. );
  94. $client = new Client($arg1, array(
  95. 'aggregate' => $this->getAggregateInitializer($arg1),
  96. ));
  97. $this->assertInstanceOf('Predis\Connection\AggregateConnectionInterface', $client->getConnection());
  98. }
  99. /**
  100. * @group disconnected
  101. */
  102. public function testConstructorWithStringArgument()
  103. {
  104. $client = new Client('tcp://localhost:7000');
  105. $parameters = $client->getConnection()->getParameters();
  106. $this->assertSame($parameters->host, 'localhost');
  107. $this->assertSame($parameters->port, 7000);
  108. }
  109. /**
  110. * @group disconnected
  111. */
  112. public function testConstructorWithArrayOfStringArgument()
  113. {
  114. $arg1 = array('tcp://localhost:7000', 'tcp://localhost:7001');
  115. $client = new Client($arg1, array(
  116. 'aggregate' => $this->getAggregateInitializer($arg1),
  117. ));
  118. $this->assertInstanceOf('Predis\Connection\AggregateConnectionInterface', $client->getConnection());
  119. }
  120. /**
  121. * @group disconnected
  122. */
  123. public function testConstructorWithArrayOfConnectionsArgument()
  124. {
  125. $arg1 = array(
  126. $this->getMock('Predis\Connection\NodeConnectionInterface'),
  127. $this->getMock('Predis\Connection\NodeConnectionInterface'),
  128. );
  129. $client = new Client($arg1, array(
  130. 'aggregate' => $this->getAggregateInitializer($arg1),
  131. ));
  132. $this->assertInstanceOf('Predis\Connection\AggregateConnectionInterface', $client->getConnection());
  133. }
  134. /**
  135. * @group disconnected
  136. */
  137. public function testConstructorWithConnectionArgument()
  138. {
  139. $factory = new Connection\Factory();
  140. $connection = $factory->create('tcp://localhost:7000');
  141. $client = new Client($connection);
  142. $this->assertInstanceOf('Predis\Connection\NodeConnectionInterface', $client->getConnection());
  143. $this->assertSame($connection, $client->getConnection());
  144. $parameters = $client->getConnection()->getParameters();
  145. $this->assertSame($parameters->host, 'localhost');
  146. $this->assertSame($parameters->port, 7000);
  147. }
  148. /**
  149. * @group disconnected
  150. */
  151. public function testConstructorWithClusterArgument()
  152. {
  153. $cluster = new Connection\Cluster\PredisCluster();
  154. $factory = new Connection\Factory();
  155. $factory->aggregate($cluster, array('tcp://localhost:7000', 'tcp://localhost:7001'));
  156. $client = new Client($cluster);
  157. $this->assertInstanceOf('Predis\Connection\Cluster\ClusterInterface', $client->getConnection());
  158. $this->assertSame($cluster, $client->getConnection());
  159. }
  160. /**
  161. * @group disconnected
  162. */
  163. public function testConstructorWithReplicationArgument()
  164. {
  165. $replication = new Connection\Replication\MasterSlaveReplication();
  166. $factory = new Connection\Factory();
  167. $factory->aggregate($replication, array('tcp://host1?alias=master', 'tcp://host2?alias=slave'));
  168. $client = new Client($replication);
  169. $this->assertInstanceOf('Predis\Connection\Replication\ReplicationInterface', $client->getConnection());
  170. $this->assertSame($replication, $client->getConnection());
  171. }
  172. /**
  173. * @group disconnected
  174. */
  175. public function testConstructorWithCallableArgument()
  176. {
  177. $connection = $this->getMock('Predis\Connection\ConnectionInterface');
  178. $callable = $this->getMock('stdClass', array('__invoke'));
  179. $callable->expects($this->once())
  180. ->method('__invoke')
  181. ->with($this->isInstanceOf('Predis\Configuration\OptionsInterface'))
  182. ->will($this->returnValue($connection));
  183. $client = new Client($callable);
  184. $this->assertSame($connection, $client->getConnection());
  185. }
  186. /**
  187. * @group disconnected
  188. * @expectedException \InvalidArgumentException
  189. * @expectedExceptionMessage Callable parameters must return a valid connection
  190. */
  191. public function testConstructorWithCallableConnectionInitializerThrowsExceptionOnInvalidReturnType()
  192. {
  193. $wrongType = $this->getMock('stdClass');
  194. $callable = $this->getMock('stdClass', array('__invoke'));
  195. $callable->expects($this->once())
  196. ->method('__invoke')
  197. ->with($this->isInstanceOf('Predis\Configuration\OptionsInterface'))
  198. ->will($this->returnValue($wrongType));
  199. new Client($callable);
  200. }
  201. /**
  202. * @group disconnected
  203. */
  204. public function testConstructorWithNullAndArrayArgument()
  205. {
  206. $connections = $this->getMock('Predis\Connection\FactoryInterface');
  207. $arg2 = array('prefix' => 'prefix:', 'connections' => $connections);
  208. $client = new Client(null, $arg2);
  209. $this->assertInstanceOf('Predis\Command\FactoryInterface', $commands = $client->getCommandFactory());
  210. $this->assertInstanceOf('Predis\Command\Processor\KeyPrefixProcessor', $commands->getProcessor());
  211. $this->assertSame('prefix:', $commands->getProcessor()->getPrefix());
  212. }
  213. /**
  214. * @group disconnected
  215. */
  216. public function testConstructorWithArrayAndOptionReplication()
  217. {
  218. $arg1 = array('tcp://host1?alias=master', 'tcp://host2?alias=slave');
  219. $arg2 = array('replication' => 'predis');
  220. $client = new Client($arg1, $arg2);
  221. $this->assertInstanceOf('Predis\Connection\Replication\ReplicationInterface', $connection = $client->getConnection());
  222. $this->assertSame('host1', $connection->getConnectionById('master')->getParameters()->host);
  223. $this->assertSame('host2', $connection->getConnectionById('slave')->getParameters()->host);
  224. }
  225. /**
  226. * @group disconnected
  227. */
  228. public function testClusterOptionHasPrecedenceOverReplicationOptionAndAggregateOption()
  229. {
  230. $arg1 = array('tcp://host1', 'tcp://host2');
  231. $connection = $this->getMock('Predis\Connection\AggregateConnectionInterface');
  232. $fncluster = $this->getMock('stdClass', array('__invoke'));
  233. $fncluster->expects($this->once())
  234. ->method('__invoke')
  235. ->with($this->isInstanceOf('Predis\Configuration\OptionsInterface'), $arg1)
  236. ->will($this->returnValue($connection));
  237. $fnreplication = $this->getMock('stdClass', array('__invoke'));
  238. $fnreplication->expects($this->never())->method('__invoke');
  239. $fnaggregate = $this->getMock('stdClass', array('__invoke'));
  240. $fnaggregate->expects($this->never())->method('__invoke');
  241. $arg2 = array(
  242. 'cluster' => $fncluster,
  243. 'replication' => $fnreplication,
  244. 'aggregate' => $fnaggregate,
  245. );
  246. $client = new Client($arg1, $arg2);
  247. $this->assertSame($connection, $client->getConnection());
  248. }
  249. /**
  250. * @group disconnected
  251. */
  252. public function testReplicationOptionHasPrecedenceOverAggregateOption()
  253. {
  254. $arg1 = array('tcp://host1', 'tcp://host2');
  255. $connection = $this->getMock('Predis\Connection\AggregateConnectionInterface');
  256. $fnreplication = $this->getMock('stdClass', array('__invoke'));
  257. $fnreplication->expects($this->once())
  258. ->method('__invoke')
  259. ->with($this->isInstanceOf('Predis\Configuration\OptionsInterface'), $arg1)
  260. ->will($this->returnValue($connection));
  261. $fnaggregate = $this->getMock('stdClass', array('__invoke'));
  262. $fnaggregate->expects($this->never())->method('__invoke');
  263. $arg2 = array(
  264. 'replication' => $fnreplication,
  265. 'aggregate' => $fnaggregate,
  266. );
  267. $client = new Client($arg1, $arg2);
  268. $this->assertSame($connection, $client->getConnection());
  269. }
  270. /**
  271. * @group disconnected
  272. */
  273. public function testAggregateOptionDoesNotTriggerAggregationInClient()
  274. {
  275. $arg1 = array('tcp://host1', 'tcp://host2');
  276. $connection = $this->getMock('Predis\Connection\AggregateConnectionInterface');
  277. $fnaggregate = $this->getMock('stdClass', array('__invoke'));
  278. $fnaggregate->expects($this->once())
  279. ->method('__invoke')
  280. ->with($this->isInstanceOf('Predis\Configuration\OptionsInterface'), $arg1)
  281. ->will($this->returnValue($connection));
  282. $connections = $this->getMock('Predis\Connection\FactoryInterface');
  283. $connections->expects($this->never())
  284. ->method('aggregate');
  285. $arg2 = array('aggregate' => $fnaggregate, 'connections' => $connections);
  286. $client = new Client($arg1, $arg2);
  287. $this->assertSame($connection, $client->getConnection());
  288. }
  289. /**
  290. * @group disconnected
  291. */
  292. public function testConnectAndDisconnect()
  293. {
  294. $connection = $this->getMock('Predis\Connection\ConnectionInterface');
  295. $connection->expects($this->once())->method('connect');
  296. $connection->expects($this->once())->method('disconnect');
  297. $client = new Client($connection);
  298. $client->connect();
  299. $client->disconnect();
  300. }
  301. /**
  302. * @group disconnected
  303. */
  304. public function testIsConnectedChecksConnectionState()
  305. {
  306. $connection = $this->getMock('Predis\Connection\ConnectionInterface');
  307. $connection->expects($this->once())->method('isConnected');
  308. $client = new Client($connection);
  309. $client->isConnected();
  310. }
  311. /**
  312. * @group disconnected
  313. */
  314. public function testQuitIsAliasForDisconnect()
  315. {
  316. $connection = $this->getMock('Predis\Connection\ConnectionInterface');
  317. $connection->expects($this->once())->method('disconnect');
  318. $client = new Client($connection);
  319. $client->quit();
  320. }
  321. /**
  322. * @group disconnected
  323. */
  324. public function testCreatesNewCommandUsingSpecifiedCommandFactory()
  325. {
  326. $ping = $this->getCommandFactory()->createCommand('ping', array());
  327. $commands = $this->getMock('Predis\Command\FactoryInterface');
  328. $commands->expects($this->once())
  329. ->method('createCommand')
  330. ->with('ping', array())
  331. ->will($this->returnValue($ping));
  332. $client = new Client(null, array('commands' => $commands));
  333. $this->assertSame($ping, $client->createCommand('ping', array()));
  334. }
  335. /**
  336. * @group disconnected
  337. */
  338. public function testExecuteCommandReturnsParsedResponses()
  339. {
  340. $commands = $this->getCommandFactory();
  341. $ping = $commands->createCommand('ping', array());
  342. $hgetall = $commands->createCommand('hgetall', array('metavars', 'foo', 'hoge'));
  343. $connection = $this->getMock('Predis\Connection\ConnectionInterface');
  344. $connection->expects($this->at(0))
  345. ->method('executeCommand')
  346. ->with($ping)
  347. ->will($this->returnValue(new Response\Status('PONG')));
  348. $connection->expects($this->at(1))
  349. ->method('executeCommand')
  350. ->with($hgetall)
  351. ->will($this->returnValue(array('foo', 'bar', 'hoge', 'piyo')));
  352. $client = new Client($connection);
  353. $this->assertEquals('PONG', $client->executeCommand($ping));
  354. $this->assertSame(array('foo' => 'bar', 'hoge' => 'piyo'), $client->executeCommand($hgetall));
  355. }
  356. /**
  357. * @group disconnected
  358. * @expectedException \Predis\Response\ServerException
  359. * @expectedExceptionMessage Operation against a key holding the wrong kind of value
  360. */
  361. public function testExecuteCommandThrowsExceptionOnRedisError()
  362. {
  363. $ping = $this->getCommandFactory()->createCommand('ping', array());
  364. $expectedResponse = new Response\Error('ERR Operation against a key holding the wrong kind of value');
  365. $connection = $this->getMock('Predis\Connection\ConnectionInterface');
  366. $connection->expects($this->once())
  367. ->method('executeCommand')
  368. ->will($this->returnValue($expectedResponse));
  369. $client = new Client($connection);
  370. $client->executeCommand($ping);
  371. }
  372. /**
  373. * @group disconnected
  374. */
  375. public function testExecuteCommandReturnsErrorResponseOnRedisError()
  376. {
  377. $ping = $this->getCommandFactory()->createCommand('ping', array());
  378. $expectedResponse = new Response\Error('ERR Operation against a key holding the wrong kind of value');
  379. $connection = $this->getMock('Predis\Connection\ConnectionInterface');
  380. $connection->expects($this->once())
  381. ->method('executeCommand')
  382. ->will($this->returnValue($expectedResponse));
  383. $client = new Client($connection, array('exceptions' => false));
  384. $response = $client->executeCommand($ping);
  385. $this->assertSame($response, $expectedResponse);
  386. }
  387. /**
  388. * @group disconnected
  389. */
  390. public function testCallingRedisCommandExecutesInstanceOfCommand()
  391. {
  392. $ping = $this->getCommandFactory()->createCommand('ping', array());
  393. $connection = $this->getMock('Predis\Connection\ConnectionInterface');
  394. $connection->expects($this->once())
  395. ->method('executeCommand')
  396. ->with($this->isInstanceOf('Predis\Command\Redis\PING'))
  397. ->will($this->returnValue('PONG'));
  398. $commands = $this->getMock('Predis\Command\FactoryInterface');
  399. $commands->expects($this->once())
  400. ->method('createCommand')
  401. ->with('ping', array())
  402. ->will($this->returnValue($ping));
  403. $options = array('commands' => $commands);
  404. $client = $this->getMock('Predis\Client', null, array($connection, $options));
  405. $this->assertEquals('PONG', $client->ping());
  406. }
  407. /**
  408. * @group disconnected
  409. * @expectedException \Predis\Response\ServerException
  410. * @expectedExceptionMessage Operation against a key holding the wrong kind of value
  411. */
  412. public function testCallingRedisCommandThrowsExceptionOnServerError()
  413. {
  414. $expectedResponse = new Response\Error('ERR Operation against a key holding the wrong kind of value');
  415. $connection = $this->getMock('Predis\Connection\ConnectionInterface');
  416. $connection->expects($this->once())
  417. ->method('executeCommand')
  418. ->with($this->isRedisCommand('PING'))
  419. ->will($this->returnValue($expectedResponse));
  420. $client = new Client($connection);
  421. $client->ping();
  422. }
  423. /**
  424. * @group disconnected
  425. */
  426. public function testCallingRedisCommandReturnsErrorResponseOnRedisError()
  427. {
  428. $expectedResponse = new Response\Error('ERR Operation against a key holding the wrong kind of value');
  429. $connection = $this->getMock('Predis\Connection\ConnectionInterface');
  430. $connection->expects($this->once())
  431. ->method('executeCommand')
  432. ->with($this->isRedisCommand('PING'))
  433. ->will($this->returnValue($expectedResponse));
  434. $client = new Client($connection, array('exceptions' => false));
  435. $response = $client->ping();
  436. $this->assertSame($response, $expectedResponse);
  437. }
  438. /**
  439. * @group disconnected
  440. */
  441. public function testRawCommand()
  442. {
  443. $connection = $this->getMock('Predis\Connection\ConnectionInterface');
  444. $connection->expects($this->at(0))
  445. ->method('executeCommand')
  446. ->with($this->isRedisCommand('SET', array('foo', 'bar')))
  447. ->will($this->returnValue(new Response\Status('OK')));
  448. $connection->expects($this->at(1))
  449. ->method('executeCommand')
  450. ->with($this->isRedisCommand('GET', array('foo')))
  451. ->will($this->returnValue('bar'));
  452. $connection->expects($this->at(2))
  453. ->method('executeCommand')
  454. ->with($this->isRedisCommand('PING'))
  455. ->will($this->returnValue('PONG'));
  456. $client = new Client($connection);
  457. $this->assertSame('OK', $client->executeRaw(array('SET', 'foo', 'bar')));
  458. $this->assertSame('bar', $client->executeRaw(array('GET', 'foo')));
  459. $error = true; // $error is always populated by reference.
  460. $this->assertSame('PONG', $client->executeRaw(array('PING'), $error));
  461. $this->assertFalse($error);
  462. }
  463. /**
  464. * @group disconnected
  465. */
  466. public function testRawCommandNeverAppliesPrefix()
  467. {
  468. $connection = $this->getMock('Predis\Connection\ConnectionInterface');
  469. $connection->expects($this->at(0))
  470. ->method('executeCommand')
  471. ->with($this->isRedisCommand('SET', array('foo', 'bar')))
  472. ->will($this->returnValue(new Response\Status('OK')));
  473. $connection->expects($this->at(1))
  474. ->method('executeCommand')
  475. ->with($this->isRedisCommand('GET', array('foo')))
  476. ->will($this->returnValue('bar'));
  477. $client = new Client($connection, array('prefix' => 'predis:'));
  478. $this->assertSame('OK', $client->executeRaw(array('SET', 'foo', 'bar')));
  479. $this->assertSame('bar', $client->executeRaw(array('GET', 'foo')));
  480. }
  481. /**
  482. * @group disconnected
  483. */
  484. public function testRawCommandNeverThrowsExceptions()
  485. {
  486. $message = 'ERR Mock error response';
  487. $response = new Response\Error($message);
  488. $connection = $this->getMock('Predis\Connection\ConnectionInterface');
  489. $connection->expects($this->once())
  490. ->method('executeCommand')
  491. ->with($this->isRedisCommand('PING'))
  492. ->will($this->returnValue($response));
  493. $client = new Client($connection, array('exceptions' => true));
  494. $this->assertSame($message, $client->executeRaw(array('PING'), $error));
  495. $this->assertTrue($error);
  496. }
  497. /**
  498. * @group disconnected
  499. * @expectedException \Predis\ClientException
  500. * @expectedExceptionMessage Command 'INVALIDCOMMAND' is not a registered Redis command.
  501. */
  502. public function testThrowsExceptionOnNonRegisteredRedisCommand()
  503. {
  504. $client = new Client();
  505. $client->invalidCommand();
  506. }
  507. /**
  508. * @group disconnected
  509. */
  510. public function testGetConnectionFromAggregateConnectionWithAlias()
  511. {
  512. $client = new Client(array('tcp://host1?alias=node01', 'tcp://host2?alias=node02'), array('cluster' => 'predis'));
  513. $this->assertInstanceOf('Predis\Connection\Cluster\ClusterInterface', $cluster = $client->getConnection());
  514. $this->assertInstanceOf('Predis\Connection\NodeConnectionInterface', $node01 = $client->getConnectionById('node01'));
  515. $this->assertInstanceOf('Predis\Connection\NodeConnectionInterface', $node02 = $client->getConnectionById('node02'));
  516. $this->assertSame('host1', $node01->getParameters()->host);
  517. $this->assertSame('host2', $node02->getParameters()->host);
  518. }
  519. /**
  520. * @group disconnected
  521. * @expectedException \Predis\NotSupportedException
  522. * @expectedExceptionMessage Retrieving connections by ID is supported only by aggregate connections.
  523. */
  524. public function testGetConnectionByIdWorksOnlyWithAggregateConnections()
  525. {
  526. $client = new Client();
  527. $client->getConnectionById('node01');
  528. }
  529. /**
  530. * @group disconnected
  531. */
  532. public function testCreateClientWithConnectionFromAggregateConnection()
  533. {
  534. $client = new Client(array('tcp://host1?alias=node01', 'tcp://host2?alias=node02'), array('prefix' => 'pfx:', 'cluster' => 'predis'));
  535. $this->assertInstanceOf('Predis\Connection\Cluster\ClusterInterface', $cluster = $client->getConnection());
  536. $this->assertInstanceOf('Predis\Connection\NodeConnectionInterface', $node01 = $client->getConnectionById('node01'));
  537. $this->assertInstanceOf('Predis\Connection\NodeConnectionInterface', $node02 = $client->getConnectionById('node02'));
  538. $clientNode02 = $client->getClientFor('node02');
  539. $this->assertInstanceOf('Predis\Client', $clientNode02);
  540. $this->assertSame($node02, $clientNode02->getConnection());
  541. $this->assertSame($client->getOptions(), $clientNode02->getOptions());
  542. }
  543. /**
  544. * @group disconnected
  545. */
  546. public function testGetClientForReturnsInstanceOfSubclass()
  547. {
  548. $nodes = array('tcp://host1?alias=node01', 'tcp://host2?alias=node02');
  549. $client = $this->getMock('Predis\Client', array('dummy'), array($nodes, array('cluster' => 'predis')), 'SubclassedClient');
  550. $this->assertInstanceOf('SubclassedClient', $client->getClientFor('node02'));
  551. }
  552. /**
  553. * @group disconnected
  554. */
  555. public function testPipelineWithoutArgumentsReturnsPipeline()
  556. {
  557. $client = new Client();
  558. $this->assertInstanceOf('Predis\Pipeline\Pipeline', $client->pipeline());
  559. }
  560. /**
  561. * @group disconnected
  562. */
  563. public function testPipelineWithArrayReturnsPipeline()
  564. {
  565. $client = new Client();
  566. $this->assertInstanceOf('Predis\Pipeline\Pipeline', $client->pipeline(array()));
  567. $this->assertInstanceOf('Predis\Pipeline\Atomic', $client->pipeline(array('atomic' => true)));
  568. $this->assertInstanceOf('Predis\Pipeline\FireAndForget', $client->pipeline(array('fire-and-forget' => true)));
  569. }
  570. /**
  571. * @group disconnected
  572. */
  573. public function testPipelineWithCallableExecutesPipeline()
  574. {
  575. $callable = $this->getMock('stdClass', array('__invoke'));
  576. $callable->expects($this->once())
  577. ->method('__invoke')
  578. ->with($this->isInstanceOf('Predis\Pipeline\Pipeline'));
  579. $client = new Client();
  580. $client->pipeline($callable);
  581. }
  582. /**
  583. * @group disconnected
  584. */
  585. public function testPubSubLoopWithoutArgumentsReturnsPubSubConsumer()
  586. {
  587. $client = new Client();
  588. $this->assertInstanceOf('Predis\PubSub\Consumer', $client->pubSubLoop());
  589. }
  590. /**
  591. * @group disconnected
  592. */
  593. public function testPubSubLoopWithArrayReturnsPubSubConsumerWithOptions()
  594. {
  595. $connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
  596. $options = array('subscribe' => 'channel');
  597. $client = new Client($connection);
  598. $this->assertInstanceOf('Predis\PubSub\Consumer', $pubsub = $client->pubSubLoop($options));
  599. $reflection = new \ReflectionProperty($pubsub, 'options');
  600. $reflection->setAccessible(true);
  601. $this->assertSame($options, $reflection->getValue($pubsub));
  602. }
  603. /**
  604. * @group disconnected
  605. */
  606. public function testPubSubLoopWithArrayAndCallableExecutesPubSub()
  607. {
  608. // NOTE: we use a subscribe count of 0 in the fake message to trick
  609. // the context and to make it think that it can be closed
  610. // since there are no more subscriptions active.
  611. $message = array('subscribe', 'channel', 0);
  612. $options = array('subscribe' => 'channel');
  613. $connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
  614. $connection->expects($this->once())
  615. ->method('read')
  616. ->will($this->returnValue($message));
  617. $callable = $this->getMock('stdClass', array('__invoke'));
  618. $callable->expects($this->once())
  619. ->method('__invoke');
  620. $client = new Client($connection);
  621. $client->pubSubLoop($options, $callable);
  622. }
  623. /**
  624. * @group disconnected
  625. */
  626. public function testTransactionWithoutArgumentsReturnsMultiExec()
  627. {
  628. $client = new Client();
  629. $this->assertInstanceOf('Predis\Transaction\MultiExec', $client->transaction());
  630. }
  631. /**
  632. * @group disconnected
  633. */
  634. public function testTransactionWithArrayReturnsMultiExecTransactionWithOptions()
  635. {
  636. $options = array('cas' => true, 'retry' => 3);
  637. $client = new Client();
  638. $this->assertInstanceOf('Predis\Transaction\MultiExec', $tx = $client->transaction($options));
  639. // I hate this part but reflection is the easiest way in this case.
  640. $property = new \ReflectionProperty($tx, 'modeCAS');
  641. $property->setAccessible(true);
  642. $this->assertSame($options['cas'], $property->getValue($tx));
  643. $property = new \ReflectionProperty($tx, 'attempts');
  644. $property->setAccessible(true);
  645. $this->assertSame($options['retry'], $property->getValue($tx));
  646. }
  647. /**
  648. * @group disconnected
  649. */
  650. public function testTransactionWithArrayAndCallableExecutesMultiExec()
  651. {
  652. // We use CAS here as we don't care about the actual MULTI/EXEC context.
  653. $options = array('cas' => true, 'retry' => 3);
  654. $connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
  655. $connection->expects($this->once())
  656. ->method('executeCommand')
  657. ->will($this->returnValue(new Response\Status('QUEUED')));
  658. $txCallback = function ($tx) {
  659. $tx->ping();
  660. };
  661. $callable = $this->getMock('stdClass', array('__invoke'));
  662. $callable->expects($this->once())
  663. ->method('__invoke')
  664. ->will($this->returnCallback($txCallback));
  665. $client = new Client($connection);
  666. $client->transaction($options, $callable);
  667. }
  668. /**
  669. * @group disconnected
  670. */
  671. public function testMonitorReturnsMonitorConsumer()
  672. {
  673. $connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
  674. $client = new Client($connection);
  675. $this->assertInstanceOf('Predis\Monitor\Consumer', $monitor = $client->monitor());
  676. }
  677. /**
  678. * @group disconnected
  679. */
  680. public function testClientResendScriptCommandUsingEvalOnNoScriptErrors()
  681. {
  682. $command = $this->getMockForAbstractClass('Predis\Command\ScriptCommand', array(), '', true, true, true, array('parseResponse'));
  683. $command->expects($this->once())
  684. ->method('getScript')
  685. ->will($this->returnValue('return redis.call(\'exists\', KEYS[1])'));
  686. $command->expects($this->once())
  687. ->method('parseResponse')
  688. ->with('OK')
  689. ->will($this->returnValue(true));
  690. $connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
  691. $connection->expects($this->at(0))
  692. ->method('executeCommand')
  693. ->with($command)
  694. ->will($this->returnValue(new Response\Error('NOSCRIPT')));
  695. $connection->expects($this->at(1))
  696. ->method('executeCommand')
  697. ->with($this->isRedisCommand('EVAL'))
  698. ->will($this->returnValue('OK'));
  699. $client = new Client($connection);
  700. $this->assertTrue($client->executeCommand($command));
  701. }
  702. /**
  703. * @group disconnected
  704. */
  705. public function testGetIteratorWithTraversableConnections()
  706. {
  707. $connection1 = $this->getMockConnection('tcp://127.0.0.1:6381');
  708. $connection2 = $this->getMockConnection('tcp://127.0.0.1:6382');
  709. $connection3 = $this->getMockConnection('tcp://127.0.0.1:6383');
  710. $aggregate = new \Predis\Connection\Cluster\PredisCluster();
  711. $aggregate->add($connection1);
  712. $aggregate->add($connection2);
  713. $aggregate->add($connection3);
  714. $client = new Client($aggregate);
  715. $iterator = $client->getIterator();
  716. $this->assertInstanceOf('\Predis\Client', $nodeClient = $iterator->current());
  717. $this->assertSame($connection1, $nodeClient->getConnection());
  718. $this->assertSame('127.0.0.1:6381', $iterator->key());
  719. $iterator->next();
  720. $this->assertInstanceOf('\Predis\Client', $nodeClient = $iterator->current());
  721. $this->assertSame($connection2, $nodeClient->getConnection());
  722. $this->assertSame('127.0.0.1:6382', $iterator->key());
  723. $iterator->next();
  724. $this->assertInstanceOf('\Predis\Client', $nodeClient = $iterator->current());
  725. $this->assertSame($connection3, $nodeClient->getConnection());
  726. $this->assertSame('127.0.0.1:6383', $iterator->key());
  727. }
  728. /**
  729. * @group disconnected
  730. * @expectedException \Predis\ClientException
  731. * @expectedExceptionMessage The underlying connection is not traversable
  732. */
  733. public function testGetIteratorWithNonTraversableConnectionThrowsException()
  734. {
  735. $connection = $this->getMock('Predis\Connection\NodeConnectionInterface');
  736. $client = new Client($connection);
  737. $client->getIterator();
  738. }
  739. // ******************************************************************** //
  740. // ---- HELPER METHODS ------------------------------------------------ //
  741. // ******************************************************************** //
  742. /**
  743. * Returns an URI string representation of the specified connection parameters.
  744. *
  745. * @param array $parameters Array of connection parameters.
  746. *
  747. * @return string URI string.
  748. */
  749. protected function getParametersString(array $parameters)
  750. {
  751. $defaults = $this->getDefaultParametersArray();
  752. $scheme = isset($parameters['scheme']) ? $parameters['scheme'] : $defaults['scheme'];
  753. $host = isset($parameters['host']) ? $parameters['host'] : $defaults['host'];
  754. $port = isset($parameters['port']) ? $parameters['port'] : $defaults['port'];
  755. unset($parameters['scheme'], $parameters['host'], $parameters['port']);
  756. $uriString = "$scheme://$host:$port/?";
  757. foreach ($parameters as $k => $v) {
  758. $uriString .= "$k=$v&";
  759. }
  760. return $uriString;
  761. }
  762. /**
  763. * Returns a mock callable simulating an aggregate connection initializer.
  764. *
  765. * @param mixed $parameters Expected connection parameters
  766. *
  767. * @return callable
  768. */
  769. protected function getAggregateInitializer($parameters)
  770. {
  771. $connection = $this->getMock('Predis\Connection\AggregateConnectionInterface');
  772. $callable = $this->getMock('stdClass', array('__invoke'));
  773. $callable->expects($this->once())
  774. ->method('__invoke')
  775. ->with($this->isInstanceOf('Predis\Configuration\OptionsInterface'), $parameters)
  776. ->will($this->returnValue($connection));
  777. return $callable;
  778. }
  779. }