RedisConnectionTest.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. <?php
  2. namespace yiiunit\extensions\redis;
  3. use Yii;
  4. use yii\helpers\ArrayHelper;
  5. use yii\log\Logger;
  6. use yii\redis\Connection;
  7. use yii\redis\SocketException;
  8. /**
  9. * @group redis
  10. */
  11. class ConnectionTest extends TestCase
  12. {
  13. protected function tearDown()
  14. {
  15. $this->getConnection(false)->configSet('timeout', 0);
  16. parent::tearDown();
  17. }
  18. /**
  19. * test connection to redis and selection of db
  20. */
  21. public function testConnect()
  22. {
  23. $db = $this->getConnection(false);
  24. $database = $db->database;
  25. $db->open();
  26. $this->assertTrue($db->ping());
  27. $db->set('YIITESTKEY', 'YIITESTVALUE');
  28. $db->close();
  29. $db = $this->getConnection(false);
  30. $db->database = $database;
  31. $db->open();
  32. $this->assertEquals('YIITESTVALUE', $db->get('YIITESTKEY'));
  33. $db->close();
  34. $db = $this->getConnection(false);
  35. $db->database = 1;
  36. $db->open();
  37. $this->assertNull($db->get('YIITESTKEY'));
  38. $db->close();
  39. }
  40. /**
  41. * tests whether close cleans up correctly so that a new connect works
  42. */
  43. public function testReConnect()
  44. {
  45. $db = $this->getConnection(false);
  46. $db->open();
  47. $this->assertTrue($db->ping());
  48. $db->close();
  49. $db->open();
  50. $this->assertTrue($db->ping());
  51. $db->close();
  52. }
  53. /**
  54. * @return array
  55. */
  56. public function keyValueData()
  57. {
  58. return [
  59. [123],
  60. [-123],
  61. [0],
  62. ['test'],
  63. ["test\r\ntest"],
  64. [''],
  65. ];
  66. }
  67. /**
  68. * @dataProvider keyValueData
  69. * @param mixed $data
  70. */
  71. public function testStoreGet($data)
  72. {
  73. $db = $this->getConnection(true);
  74. $db->set('hi', $data);
  75. $this->assertEquals($data, $db->get('hi'));
  76. }
  77. public function testSerialize()
  78. {
  79. $db = $this->getConnection(false);
  80. $db->open();
  81. $this->assertTrue($db->ping());
  82. $s = serialize($db);
  83. $this->assertTrue($db->ping());
  84. $db2 = unserialize($s);
  85. $this->assertTrue($db->ping());
  86. $this->assertTrue($db2->ping());
  87. }
  88. public function testConnectionTimeout()
  89. {
  90. $db = $this->getConnection(false);
  91. $db->configSet('timeout', 1);
  92. $this->assertTrue($db->ping());
  93. sleep(1);
  94. $this->assertTrue($db->ping());
  95. sleep(2);
  96. if (method_exists($this, 'setExpectedException')) {
  97. $this->setExpectedException('\yii\redis\SocketException');
  98. } else {
  99. $this->expectException('\yii\redis\SocketException');
  100. }
  101. $this->assertTrue($db->ping());
  102. }
  103. public function testConnectionTimeoutRetry()
  104. {
  105. $logger = new Logger();
  106. Yii::setLogger($logger);
  107. $db = $this->getConnection(false);
  108. $db->retries = 1;
  109. $db->configSet('timeout', 1);
  110. $this->assertCount(3, $logger->messages, 'log of connection and init commands.');
  111. $this->assertTrue($db->ping());
  112. $this->assertCount(4, $logger->messages, 'log +1 ping command.');
  113. usleep(500000); // 500ms
  114. $this->assertTrue($db->ping());
  115. $this->assertCount(5, $logger->messages, 'log +1 ping command.');
  116. sleep(2);
  117. // reconnect should happen here
  118. $this->assertTrue($db->ping());
  119. $this->assertCount(11, $logger->messages, 'log +1 ping command, and reconnection.'
  120. . print_r(array_map(function($s) { return (string) $s; }, ArrayHelper::getColumn($logger->messages, 0)), true));
  121. }
  122. /**
  123. * Retry connecting 2 times
  124. */
  125. public function testConnectionTimeoutRetryCount()
  126. {
  127. $logger = new Logger();
  128. Yii::setLogger($logger);
  129. $db = $this->getConnection(false);
  130. $db->retries = 2;
  131. $db->configSet('timeout', 1);
  132. $db->on(Connection::EVENT_AFTER_OPEN, function() {
  133. // sleep 2 seconds after connect to make every command time out
  134. sleep(2);
  135. });
  136. $this->assertCount(3, $logger->messages, 'log of connection and init commands.');
  137. $exception = false;
  138. try {
  139. // should try to reconnect 2 times, before finally failing
  140. // results in 3 times sending the PING command to redis
  141. sleep(2);
  142. $db->ping();
  143. } catch (SocketException $e) {
  144. $exception = true;
  145. }
  146. $this->assertTrue($exception, 'SocketException should have been thrown.');
  147. $this->assertCount(14, $logger->messages, 'log +1 ping command, and reconnection.'
  148. . print_r(array_map(function($s) { return (string) $s; }, ArrayHelper::getColumn($logger->messages, 0)), true));
  149. }
  150. /**
  151. * https://github.com/yiisoft/yii2/issues/4745
  152. */
  153. public function testReturnType()
  154. {
  155. $redis = $this->getConnection();
  156. $redis->executeCommand('SET', ['key1', 'val1']);
  157. $redis->executeCommand('HMSET', ['hash1', 'hk3', 'hv3', 'hk4', 'hv4']);
  158. $redis->executeCommand('RPUSH', ['newlist2', 'tgtgt', 'tgtt', '44', 11]);
  159. $redis->executeCommand('SADD', ['newset2', 'segtggttval', 'sv1', 'sv2', 'sv3']);
  160. $redis->executeCommand('ZADD', ['newz2', 2, 'ss', 3, 'pfpf']);
  161. $allKeys = $redis->executeCommand('KEYS', ['*']);
  162. sort($allKeys);
  163. $this->assertEquals(['hash1', 'key1', 'newlist2', 'newset2', 'newz2'], $allKeys);
  164. $expected = [
  165. 'hash1' => 'hash',
  166. 'key1' => 'string',
  167. 'newlist2' => 'list',
  168. 'newset2' => 'set',
  169. 'newz2' => 'zset',
  170. ];
  171. foreach ($allKeys as $key) {
  172. $this->assertEquals($expected[$key], $redis->executeCommand('TYPE', [$key]));
  173. }
  174. }
  175. public function testTwoWordCommands()
  176. {
  177. $redis = $this->getConnection();
  178. $this->assertTrue(is_array($redis->executeCommand('CONFIG GET', ['port'])));
  179. $this->assertTrue(is_string($redis->clientList()));
  180. $this->assertTrue(is_string($redis->executeCommand('CLIENT LIST')));
  181. }
  182. /**
  183. * @return array
  184. */
  185. public function zRangeByScoreData()
  186. {
  187. return [
  188. [
  189. 'members' => [
  190. ['foo', 1],
  191. ['bar', 2],
  192. ],
  193. 'cases' => [
  194. // without both scores and limit
  195. ['0', '(1', null, null, null, null, []],
  196. ['1', '(2', null, null, null, null, ['foo']],
  197. ['2', '(3', null, null, null, null, ['bar']],
  198. ['(0', '2', null, null, null, null, ['foo', 'bar']],
  199. // with scores, but no limit
  200. ['0', '(1', 'WITHSCORES', null, null, null, []],
  201. ['1', '(2', 'WITHSCORES', null, null, null, ['foo', 1]],
  202. ['2', '(3', 'WITHSCORES', null, null, null, ['bar', 2]],
  203. ['(0', '2', 'WITHSCORES', null, null, null, ['foo', 1, 'bar', 2]],
  204. // with limit, but no scores
  205. ['0', '(1', null, 'LIMIT', 0, 1, []],
  206. ['1', '(2', null, 'LIMIT', 0, 1, ['foo']],
  207. ['2', '(3', null, 'LIMIT', 0, 1, ['bar']],
  208. ['(0', '2', null, 'LIMIT', 0, 1, ['foo']],
  209. // with both scores and limit
  210. ['0', '(1', 'WITHSCORES', 'LIMIT', 0, 1, []],
  211. ['1', '(2', 'WITHSCORES', 'LIMIT', 0, 1, ['foo', 1]],
  212. ['2', '(3', 'WITHSCORES', 'LIMIT', 0, 1, ['bar', 2]],
  213. ['(0', '2', 'WITHSCORES', 'LIMIT', 0, 1, ['foo', 1]],
  214. ],
  215. ],
  216. ];
  217. }
  218. /**
  219. * @dataProvider zRangeByScoreData
  220. * @param $members
  221. * @param $cases
  222. */
  223. public function testZRangeByScore($members, $cases)
  224. {
  225. $redis = $this->getConnection();
  226. $set = 'zrangebyscore';
  227. foreach ($members as $member) {
  228. list($name, $score) = $member;
  229. $this->assertEquals(1, $redis->zadd($set, $score, $name));
  230. }
  231. foreach ($cases as $case) {
  232. list($min, $max, $withScores, $limit, $offset, $count, $expectedRows) = $case;
  233. $rows = $redis->zrangebyscore($set, $min, $max, $withScores, $limit, $offset, $count);
  234. $this->assertTrue(is_array($rows));
  235. $this->assertEquals(count($expectedRows), count($rows));
  236. for ($i = 0; $i < count($expectedRows); $i++) {
  237. $this->assertEquals($expectedRows[$i], $rows[$i]);
  238. }
  239. }
  240. }
  241. }