PredisClientFeatures.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. <?php
  2. define('I_AM_AWARE_OF_THE_DESTRUCTIVE_POWER_OF_THIS_TEST_SUITE', false);
  3. require_once 'PHPUnit/Framework.php';
  4. require_once 'PredisShared.php';
  5. require_once '../lib/Predis_Compatibility.php';
  6. Predis\Compatibility::loadRedis_v1_0();
  7. class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
  8. public $redis;
  9. protected function setUp() {
  10. $this->redis = RC::getConnection();
  11. $this->redis->flushdb();
  12. }
  13. protected function tearDown() {
  14. }
  15. protected function onNotSuccessfulTest(Exception $exception) {
  16. // drops and reconnect to a redis server on uncaught exceptions
  17. RC::resetConnection();
  18. parent::onNotSuccessfulTest($exception);
  19. }
  20. /* ConnectionParameters */
  21. function testConnectionParametersDefaultValues() {
  22. $params = new \Predis\ConnectionParameters();
  23. $this->assertEquals(\Predis\ConnectionParameters::DEFAULT_HOST, $params->host);
  24. $this->assertEquals(\Predis\ConnectionParameters::DEFAULT_PORT, $params->port);
  25. $this->assertEquals(\Predis\ConnectionParameters::DEFAULT_TIMEOUT, $params->connection_timeout);
  26. $this->assertNull($params->read_write_timeout);
  27. $this->assertNull($params->database);
  28. $this->assertNull($params->password);
  29. $this->assertNull($params->alias);
  30. }
  31. function testConnectionParametersSetupValuesArray() {
  32. $paramsArray = RC::getConnectionParametersArgumentsArray();
  33. $params = new \Predis\ConnectionParameters($paramsArray);
  34. $this->assertEquals($paramsArray['host'], $params->host);
  35. $this->assertEquals($paramsArray['port'], $params->port);
  36. $this->assertEquals($paramsArray['connection_timeout'], $params->connection_timeout);
  37. $this->assertEquals($paramsArray['read_write_timeout'], $params->read_write_timeout);
  38. $this->assertEquals($paramsArray['database'], $params->database);
  39. $this->assertEquals($paramsArray['password'], $params->password);
  40. $this->assertEquals($paramsArray['alias'], $params->alias);
  41. }
  42. function testConnectionParametersSetupValuesString() {
  43. $paramsArray = RC::getConnectionParametersArgumentsArray();
  44. $paramsString = RC::getConnectionParametersArgumentsString($paramsArray);
  45. $params = new \Predis\ConnectionParameters($paramsArray);
  46. $this->assertEquals($paramsArray['host'], $params->host);
  47. $this->assertEquals($paramsArray['port'], $params->port);
  48. $this->assertEquals($paramsArray['connection_timeout'], $params->connection_timeout);
  49. $this->assertEquals($paramsArray['read_write_timeout'], $params->read_write_timeout);
  50. $this->assertEquals($paramsArray['database'], $params->database);
  51. $this->assertEquals($paramsArray['password'], $params->password);
  52. $this->assertEquals($paramsArray['alias'], $params->alias);
  53. }
  54. /* Command and derivates */
  55. function testCommand_TestArguments() {
  56. $cmdArgs = array('key1', 'key2', 'key3');
  57. $cmd = new \Predis\Commands\GetMultiple();
  58. $cmd->setArgumentsArray($cmdArgs);
  59. $this->assertEquals($cmdArgs[0], $cmd->getArgument(0));
  60. $this->assertEquals($cmdArgs[1], $cmd->getArgument(1));
  61. $this->assertEquals($cmdArgs[2], $cmd->getArgument(2));
  62. $cmd = new \Predis\Commands\GetMultiple();
  63. $cmd->setArguments('key1', 'key2', 'key3');
  64. $this->assertEquals($cmdArgs[0], $cmd->getArgument(0));
  65. $this->assertEquals($cmdArgs[1], $cmd->getArgument(1));
  66. $this->assertEquals($cmdArgs[2], $cmd->getArgument(2));
  67. $cmd = new \Predis\Commands\Ping();
  68. $this->assertNull($cmd->getArgument(0));
  69. }
  70. function testCommand_InlineWithNoArguments() {
  71. $cmd = new \Predis\Compatibility\v1_0\Commands\Ping();
  72. $this->assertType('\Predis\InlineCommand', $cmd);
  73. $this->assertEquals('PING', $cmd->getCommandId());
  74. $this->assertFalse($cmd->closesConnection());
  75. $this->assertFalse($cmd->canBeHashed());
  76. $this->assertNull($cmd->getHash(new \Predis\Distribution\HashRing()));
  77. $this->assertEquals("PING\r\n", $cmd());
  78. }
  79. function testCommand_InlineWithArguments() {
  80. $cmd = new \Predis\Compatibility\v1_0\Commands\Get();
  81. $cmd->setArgumentsArray(array('key'));
  82. $this->assertType('\Predis\InlineCommand', $cmd);
  83. $this->assertEquals('GET', $cmd->getCommandId());
  84. $this->assertFalse($cmd->closesConnection());
  85. $this->assertTrue($cmd->canBeHashed());
  86. $this->assertNotNull($cmd->getHash(new \Predis\Distribution\HashRing()));
  87. $this->assertEquals("GET key\r\n", $cmd());
  88. }
  89. function testCommand_BulkWithArguments() {
  90. $cmd = new \Predis\Compatibility\v1_0\Commands\Set();
  91. $cmd->setArgumentsArray(array('key', 'value'));
  92. $this->assertType('\Predis\BulkCommand', $cmd);
  93. $this->assertEquals('SET', $cmd->getCommandId());
  94. $this->assertFalse($cmd->closesConnection());
  95. $this->assertTrue($cmd->canBeHashed());
  96. $this->assertNotNull($cmd->getHash(new \Predis\Distribution\HashRing()));
  97. $this->assertEquals("SET key 5\r\nvalue\r\n", $cmd());
  98. }
  99. function testCommand_MultiBulkWithArguments() {
  100. $cmd = new \Predis\Commands\SetMultiple();
  101. $cmd->setArgumentsArray(array('key1', 'value1', 'key2', 'value2'));
  102. $this->assertType('\Predis\MultiBulkCommand', $cmd);
  103. $this->assertEquals('MSET', $cmd->getCommandId());
  104. $this->assertFalse($cmd->closesConnection());
  105. $this->assertFalse($cmd->canBeHashed());
  106. $this->assertNotNull($cmd->getHash(new \Predis\Distribution\HashRing()));
  107. $this->assertEquals("*5\r\n$4\r\nMSET\r\n$4\r\nkey1\r\n$6\r\nvalue1\r\n$4\r\nkey2\r\n$6\r\nvalue2\r\n", $cmd());
  108. }
  109. function testCommand_ParseResponse() {
  110. // default parser
  111. $cmd = new \Predis\Commands\Get();
  112. $this->assertEquals('test', $cmd->parseResponse('test'));
  113. // overridden parser (boolean)
  114. $cmd = new \Predis\Commands\Exists();
  115. $this->assertTrue($cmd->parseResponse('1'));
  116. $this->assertFalse($cmd->parseResponse('0'));
  117. // overridden parser (boolean)
  118. $cmd = new \Predis\Commands\Ping();
  119. $this->assertTrue($cmd->parseResponse('PONG'));
  120. // overridden parser (complex)
  121. // TODO: emulate a respons to INFO
  122. }
  123. /* RedisServerProfile and derivates */
  124. function testRedisServerProfile_GetSpecificVersions() {
  125. $this->assertType('\Predis\RedisServer_v1_0', \Predis\RedisServerProfile::get('1.0'));
  126. $this->assertType('\Predis\RedisServer_v1_2', \Predis\RedisServerProfile::get('1.2'));
  127. $this->assertType('\Predis\RedisServer_v2_0', \Predis\RedisServerProfile::get('2.0'));
  128. $this->assertType('\Predis\RedisServer_vNext', \Predis\RedisServerProfile::get('dev'));
  129. $this->assertType('\Predis\RedisServerProfile', \Predis\RedisServerProfile::get('default'));
  130. $this->assertEquals(\Predis\RedisServerProfile::get('default'), \Predis\RedisServerProfile::getDefault());
  131. }
  132. function testRedisServerProfile_SupportedCommands() {
  133. $profile_10 = \Predis\RedisServerProfile::get('1.0');
  134. $profile_12 = \Predis\RedisServerProfile::get('1.2');
  135. $this->assertTrue($profile_10->supportsCommand('info'));
  136. $this->assertTrue($profile_12->supportsCommand('info'));
  137. $this->assertFalse($profile_10->supportsCommand('mset'));
  138. $this->assertTrue($profile_12->supportsCommand('mset'));
  139. $this->assertFalse($profile_10->supportsCommand('multi'));
  140. $this->assertFalse($profile_12->supportsCommand('multi'));
  141. }
  142. function testRedisServerProfile_CommandsCreation() {
  143. $profile = \Predis\RedisServerProfile::get('1.0');
  144. $cmdNoArgs = $profile->createCommand('info');
  145. $this->assertType('\Predis\Compatibility\v1_0\Commands\Info', $cmdNoArgs);
  146. $this->assertNull($cmdNoArgs->getArgument());
  147. $args = array('key1', 'key2');
  148. $cmdWithArgs = $profile->createCommand('mget', $args);
  149. $this->assertType('\Predis\Compatibility\v1_0\Commands\GetMultiple', $cmdWithArgs);
  150. $this->assertEquals($args[0], $cmdWithArgs->getArgument()); // TODO: why?
  151. $this->assertEquals($args[0], $cmdWithArgs->getArgument(0));
  152. $this->assertEquals($args[1], $cmdWithArgs->getArgument(1));
  153. $bogusCommand = 'not_existing_command';
  154. $expectedMessage = "'$bogusCommand' is not a registered Redis command";
  155. RC::testForClientException($this, $expectedMessage, function()
  156. use($profile, $bogusCommand) {
  157. $profile->createCommand($bogusCommand);
  158. });
  159. }
  160. function testRedisServerProfile_CommandsRegistration() {
  161. $profile = \Predis\RedisServerProfile::get('1.0');
  162. $cmdId = 'mset';
  163. $cmdClass = '\Predis\Commands\SetMultiple';
  164. $this->assertFalse($profile->supportsCommand($cmdId));
  165. $profile->registerCommand(new $cmdClass(), $cmdId);
  166. $this->assertTrue($profile->supportsCommand($cmdId));
  167. $this->assertType($cmdClass, $profile->createCommand($cmdId));
  168. }
  169. /* ResponseQueued */
  170. function testResponseQueued() {
  171. $response = new \Predis\ResponseQueued();
  172. $this->assertTrue($response->queued);
  173. $this->assertEquals(\Predis\Protocol::QUEUED, (string)$response);
  174. }
  175. /* ResponseError */
  176. function testResponseError() {
  177. $errorMessage = 'ERROR MESSAGE';
  178. $response = new \Predis\ResponseError($errorMessage);
  179. $this->assertTrue($response->error);
  180. $this->assertEquals($errorMessage, $response->message);
  181. $this->assertEquals($errorMessage, (string)$response);
  182. }
  183. /* Connection */
  184. function testConnection_StringCastReturnsIPAndPort() {
  185. $connection = new \Predis\TcpConnection(RC::getConnectionParameters());
  186. $this->assertEquals(RC::SERVER_HOST . ':' . RC::SERVER_PORT, (string) $connection);
  187. }
  188. function testConnection_ConnectDisconnect() {
  189. $connection = new \Predis\TcpConnection(RC::getConnectionParameters());
  190. $this->assertFalse($connection->isConnected());
  191. $connection->connect();
  192. $this->assertTrue($connection->isConnected());
  193. $connection->disconnect();
  194. $this->assertFalse($connection->isConnected());
  195. }
  196. function testConnection_WriteAndReadCommand() {
  197. $cmd = \Predis\RedisServerProfile::getDefault()->createCommand('ping');
  198. $connection = new \Predis\TcpConnection(RC::getConnectionParameters());
  199. $connection->connect();
  200. $connection->writeCommand($cmd);
  201. $this->assertTrue($connection->readResponse($cmd));
  202. }
  203. function testConnection_WriteCommandAndCloseConnection() {
  204. $cmd = \Predis\RedisServerProfile::getDefault()->createCommand('quit');
  205. $connection = new \Predis\TcpConnection(RC::getConnectionParameters());
  206. $connection->connect();
  207. $this->assertTrue($connection->isConnected());
  208. $connection->writeCommand($cmd);
  209. $exceptionMessage = 'Error while reading line from the server';
  210. RC::testForCommunicationException($this, $exceptionMessage, function() use($connection, $cmd) {
  211. $connection->readResponse($cmd);
  212. });
  213. //$this->assertFalse($connection->isConnected());
  214. }
  215. function testConnection_GetSocketOpensConnection() {
  216. $connection = new \Predis\TcpConnection(RC::getConnectionParameters());
  217. $this->assertFalse($connection->isConnected());
  218. $this->assertType('resource', $connection->getSocket());
  219. $this->assertTrue($connection->isConnected());
  220. }
  221. function testConnection_LazyConnect() {
  222. $cmd = \Predis\RedisServerProfile::getDefault()->createCommand('ping');
  223. $connection = new \Predis\TcpConnection(RC::getConnectionParameters());
  224. $this->assertFalse($connection->isConnected());
  225. $connection->writeCommand($cmd);
  226. $this->assertTrue($connection->isConnected());
  227. $this->assertTrue($connection->readResponse($cmd));
  228. }
  229. function testConnection_RawCommand() {
  230. $connection = new \Predis\TcpConnection(RC::getConnectionParameters());
  231. $this->assertEquals('PONG', $connection->rawCommand("PING\r\n"));
  232. }
  233. function testConnection_Alias() {
  234. $connection1 = new \Predis\TcpConnection(RC::getConnectionParameters());
  235. $this->assertNull($connection1->getParameters()->alias);
  236. $args = array_merge(RC::getConnectionArguments(), array('alias' => 'servername'));
  237. $connection2 = new \Predis\TcpConnection(new \Predis\ConnectionParameters($args));
  238. $this->assertEquals('servername', $connection2->getParameters()->alias);
  239. }
  240. function testConnection_ConnectionTimeout() {
  241. $timeout = 3;
  242. $args = array('host' => '1.0.0.1', 'connection_timeout' => $timeout);
  243. $connection = new \Predis\TcpConnection(new \Predis\ConnectionParameters($args));
  244. $start = time();
  245. RC::testForCommunicationException($this, null, function() use($connection) {
  246. $connection->connect();
  247. });
  248. $this->assertEquals((float)(time() - $start), $timeout, '', 1);
  249. }
  250. function testConnection_ReadTimeout() {
  251. $timeout = 1;
  252. $args = array_merge(RC::getConnectionArguments(), array('read_write_timeout' => $timeout));
  253. $cmdFake = \Predis\RedisServerProfile::getDefault()->createCommand('ping');
  254. $connection = new \Predis\TcpConnection(new \Predis\ConnectionParameters($args));
  255. $expectedMessage = 'Error while reading line from the server';
  256. $start = time();
  257. RC::testForCommunicationException($this, $expectedMessage, function() use($connection, $cmdFake) {
  258. $connection->readResponse($cmdFake);
  259. });
  260. $this->assertEquals((float)(time() - $start), $timeout, '', 1);
  261. }
  262. /* ResponseReader */
  263. function testResponseReader_OptionIterableMultiBulkReplies() {
  264. $connection = new \Predis\TcpConnection(RC::getConnectionParameters());
  265. $responseReader = $connection->getResponseReader();
  266. $responseReader->setHandler(
  267. \Predis\Protocol::PREFIX_MULTI_BULK,
  268. new \Predis\ResponseMultiBulkHandler()
  269. );
  270. $this->assertType('array', $connection->rawCommand("KEYS *\r\n"));
  271. $responseReader->setHandler(
  272. \Predis\Protocol::PREFIX_MULTI_BULK,
  273. new \Predis\ResponseMultiBulkStreamHandler()
  274. );
  275. $this->assertType('\Iterator', $connection->rawCommand("KEYS *\r\n"));
  276. }
  277. function testResponseReader_OptionExceptionOnError() {
  278. $connection = new \Predis\TcpConnection(RC::getConnectionParameters());
  279. $responseReader = $connection->getResponseReader();
  280. $connection->rawCommand("SET key 5\r\nvalue\r\n");
  281. $rawCmdUnexpected = "LPUSH key 5\r\nvalue\r\n";
  282. $responseReader->setHandler(
  283. \Predis\Protocol::PREFIX_ERROR,
  284. new \Predis\ResponseErrorSilentHandler()
  285. );
  286. $errorReply = $connection->rawCommand($rawCmdUnexpected);
  287. $this->assertType('\Predis\ResponseError', $errorReply);
  288. $this->assertEquals(RC::EXCEPTION_WRONG_TYPE, $errorReply->message);
  289. $responseReader->setHandler(
  290. \Predis\Protocol::PREFIX_ERROR,
  291. new \Predis\ResponseErrorHandler()
  292. );
  293. RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, function()
  294. use ($connection, $rawCmdUnexpected) {
  295. $connection->rawCommand($rawCmdUnexpected);
  296. });
  297. }
  298. /* Client + CommandPipeline */
  299. function testCommandPipeline_Simple() {
  300. $client = RC::getConnection();
  301. $client->flushdb();
  302. $pipe = $client->pipeline();
  303. $this->assertType('\Predis\CommandPipeline', $pipe);
  304. $this->assertType('\Predis\CommandPipeline', $pipe->set('foo', 'bar'));
  305. $this->assertType('\Predis\CommandPipeline', $pipe->set('hoge', 'piyo'));
  306. $this->assertType('\Predis\CommandPipeline', $pipe->mset(array(
  307. 'foofoo' => 'barbar', 'hogehoge' => 'piyopiyo'
  308. )));
  309. $this->assertType('\Predis\CommandPipeline', $pipe->mget(array(
  310. 'foo', 'hoge', 'foofoo', 'hogehoge'
  311. )));
  312. $replies = $pipe->execute();
  313. $this->assertType('array', $replies);
  314. $this->assertEquals(4, count($replies));
  315. $this->assertEquals(4, count($replies[3]));
  316. $this->assertEquals('barbar', $replies[3][2]);
  317. }
  318. function testCommandPipeline_FluentInterface() {
  319. $client = RC::getConnection();
  320. $client->flushdb();
  321. $replies = $client->pipeline()->ping()->set('foo', 'bar')->get('foo')->execute();
  322. $this->assertType('array', $replies);
  323. $this->assertEquals('bar', $replies[2]);
  324. }
  325. function testCommandPipeline_CallableAnonymousBlock() {
  326. $client = RC::getConnection();
  327. $client->flushdb();
  328. $replies = $client->pipeline(function($pipe) {
  329. $pipe->ping();
  330. $pipe->set('foo', 'bar');
  331. $pipe->get('foo');
  332. });
  333. $this->assertType('array', $replies);
  334. $this->assertEquals('bar', $replies[2]);
  335. }
  336. function testCommandPipeline_ClientExceptionInCallableBlock() {
  337. $client = RC::getConnection();
  338. $client->flushdb();
  339. RC::testForClientException($this, 'TEST', function() use($client) {
  340. $client->pipeline(function($pipe) {
  341. $pipe->ping();
  342. $pipe->set('foo', 'bar');
  343. throw new \Predis\ClientException("TEST");
  344. });
  345. });
  346. $this->assertFalse($client->exists('foo'));
  347. }
  348. function testCommandPipeline_ServerExceptionInCallableBlock() {
  349. $client = RC::getConnection();
  350. $client->flushdb();
  351. $client->getResponseReader()->setHandler('-', new \Predis\ResponseErrorSilentHandler());
  352. $replies = $client->pipeline(function($pipe) {
  353. $pipe->set('foo', 'bar');
  354. $pipe->lpush('foo', 'piyo'); // LIST operation on STRING type returns an ERROR
  355. $pipe->set('hoge', 'piyo');
  356. });
  357. $this->assertType('array', $replies);
  358. $this->assertType('\Predis\ResponseError', $replies[1]);
  359. $this->assertTrue($client->exists('foo'));
  360. $this->assertTrue($client->exists('hoge'));
  361. }
  362. function testCommandPipeline_Flush() {
  363. $client = RC::getConnection();
  364. $client->flushdb();
  365. $pipe = $client->pipeline();
  366. $pipe->set('foo', 'bar')->set('hoge', 'piyo');
  367. $pipe->flushPipeline();
  368. $pipe->ping()->mget(array('foo', 'hoge'));
  369. $replies = $pipe->execute();
  370. $this->assertType('array', $replies);
  371. $this->assertEquals(4, count($replies));
  372. $this->assertEquals('bar', $replies[3][0]);
  373. $this->assertEquals('piyo', $replies[3][1]);
  374. }
  375. }
  376. ?>