MultiExecContextTest.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  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\Transaction;
  11. use \PHPUnit_Framework_TestCase as StandardTestCase;
  12. use Predis\Client;
  13. use Predis\ResponseQueued;
  14. use Predis\ServerException;
  15. use Predis\Commands\ICommand;
  16. /**
  17. * @group realm-transaction
  18. */
  19. class MultiExecContextTest extends StandardTestCase
  20. {
  21. /**
  22. * @group disconnected
  23. * @expectedException Predis\NotSupportedException
  24. * @expectedExceptionMessage The current profile does not support MULTI, EXEC and DISCARD
  25. */
  26. public function testThrowsExceptionOnUnsupportedMultiExecInProfile()
  27. {
  28. $connection = $this->getMock('Predis\Network\IConnectionSingle');
  29. $client = new Client($connection, '1.2');
  30. $tx = new MultiExecContext($client);
  31. }
  32. /**
  33. * @group disconnected
  34. * @expectedException Predis\NotSupportedException
  35. * @expectedExceptionMessage The current profile does not support WATCH and UNWATCH
  36. */
  37. public function testThrowsExceptionOnUnsupportedWatchUnwatchInProfile()
  38. {
  39. $connection = $this->getMock('Predis\Network\IConnectionSingle');
  40. $client = new Client($connection, '2.0');
  41. $tx = new MultiExecContext($client, array('options' => 'cas'));
  42. $tx->watch('foo');
  43. }
  44. /**
  45. * @group disconnected
  46. */
  47. public function testExecutionWithFluentInterface()
  48. {
  49. $commands = array();
  50. $expected = array('one', 'two', 'three');
  51. $callback = $this->getExecuteCallback($expected, $commands);
  52. $tx = $this->getMockedTransaction($callback);
  53. $this->assertSame($expected, $tx->echo('one')->echo('two')->echo('three')->execute());
  54. $this->assertSame(array('MULTI', 'ECHO', 'ECHO', 'ECHO', 'EXEC'), self::commandsToIDs($commands));
  55. }
  56. /**
  57. * @group disconnected
  58. */
  59. public function testExecutionWithCallable()
  60. {
  61. $commands = array();
  62. $expected = array('one', 'two', 'three');
  63. $callback = $this->getExecuteCallback($expected, $commands);
  64. $tx = $this->getMockedTransaction($callback);
  65. $replies = $tx->execute(function($tx) {
  66. $tx->echo('one');
  67. $tx->echo('two');
  68. $tx->echo('three');
  69. });
  70. $this->assertSame($expected, $replies);
  71. $this->assertSame(array('MULTI', 'ECHO', 'ECHO', 'ECHO', 'EXEC'), self::commandsToIDs($commands));
  72. }
  73. /**
  74. * @group disconnected
  75. */
  76. public function testCannotMixExecutionWithFluentInterfaceAndCallable()
  77. {
  78. $commands = array();
  79. $callback = $this->getExecuteCallback(null, $commands);
  80. $tx = $this->getMockedTransaction($callback);
  81. $exception = null;
  82. try {
  83. $tx->echo('foo')->execute(function($tx) { $tx->echo('bar'); });
  84. }
  85. catch (\Exception $ex) {
  86. $exception = $ex;
  87. }
  88. $this->assertInstanceOf('Predis\ClientException', $exception);
  89. $this->assertSame(array('MULTI', 'ECHO', 'DISCARD'), self::commandsToIDs($commands));
  90. }
  91. /**
  92. * @group disconnected
  93. */
  94. public function testEmptyTransactionDoesNotSendMultiExecCommands()
  95. {
  96. $commands = array();
  97. $callback = $this->getExecuteCallback(null, $commands);
  98. $tx = $this->getMockedTransaction($callback);
  99. $replies = $tx->execute(function($tx) {
  100. // NOOP
  101. });
  102. $this->assertNull($replies);
  103. $this->assertSame(array(), self::commandsToIDs($commands));
  104. }
  105. /**
  106. * @group disconnected
  107. * @expectedException Predis\ClientException
  108. * @expectedExceptionMessage Cannot invoke 'execute' or 'exec' inside an active client transaction block
  109. */
  110. public function testThrowsExceptionOnExecInsideTransactionBlock()
  111. {
  112. $commands = array();
  113. $callback = $this->getExecuteCallback(null, $commands);
  114. $tx = $this->getMockedTransaction($callback);
  115. $replies = $tx->execute(function($tx) {
  116. $tx->exec();
  117. });
  118. $this->assertNull($replies);
  119. $this->assertSame(array(), self::commandsToIDs($commands));
  120. }
  121. /**
  122. * @group disconnected
  123. */
  124. public function testEmptyTransactionIgnoresDiscard()
  125. {
  126. $commands = array();
  127. $callback = $this->getExecuteCallback(null, $commands);
  128. $tx = $this->getMockedTransaction($callback);
  129. $replies = $tx->execute(function($tx) {
  130. $tx->discard();
  131. });
  132. $this->assertNull($replies);
  133. $this->assertSame(array(), self::commandsToIDs($commands));
  134. }
  135. /**
  136. * @group disconnected
  137. */
  138. public function testTransactionWithCommandsSendsDiscard()
  139. {
  140. $commands = array();
  141. $callback = $this->getExecuteCallback(null, $commands);
  142. $tx = $this->getMockedTransaction($callback);
  143. $replies = $tx->execute(function($tx) {
  144. $tx->set('foo', 'bar');
  145. $tx->get('foo');
  146. $tx->discard();
  147. });
  148. $this->assertNull($replies);
  149. $this->assertSame(array('MULTI', 'SET', 'GET', 'DISCARD'), self::commandsToIDs($commands));
  150. }
  151. /**
  152. * @group disconnected
  153. */
  154. public function testSendMultiOnCommandsFollowingDiscard()
  155. {
  156. $commands = array();
  157. $expected = array('after DISCARD');
  158. $callback = $this->getExecuteCallback($expected, $commands);
  159. $tx = $this->getMockedTransaction($callback);
  160. $replies = $tx->execute(function($tx) {
  161. $tx->echo('before DISCARD');
  162. $tx->discard();
  163. $tx->echo('after DISCARD');
  164. });
  165. $this->assertSame($replies, $expected);
  166. $this->assertSame(array('MULTI', 'ECHO', 'DISCARD', 'MULTI', 'ECHO', 'EXEC'), self::commandsToIDs($commands));
  167. }
  168. /**
  169. * @group disconnected
  170. * @expectedException Predis\ClientException
  171. */
  172. public function testThrowsExceptionOnWatchInsideMulti()
  173. {
  174. $callback = $this->getExecuteCallback();
  175. $tx = $this->getMockedTransaction($callback);
  176. $tx->echo('foobar')->watch('foo')->execute();
  177. }
  178. /**
  179. * @group disconnected
  180. */
  181. public function testUnwatchInsideMulti()
  182. {
  183. $commands = array();
  184. $expected = array('foobar', true);
  185. $callback = $this->getExecuteCallback($expected, $commands);
  186. $tx = $this->getMockedTransaction($callback);
  187. $replies = $tx->echo('foobar')->unwatch('foo')->execute();
  188. $this->assertSame($replies, $expected);
  189. $this->assertSame(array('MULTI', 'ECHO', 'UNWATCH', 'EXEC'), self::commandsToIDs($commands));
  190. }
  191. /**
  192. * @group disconnected
  193. */
  194. public function testAutomaticWatchInOptions()
  195. {
  196. $txCommands = $casCommands = array();
  197. $expected = array('bar', 'piyo');
  198. $options = array('watch' => array('foo', 'hoge'));
  199. $callback = $this->getExecuteCallback($expected, $txCommands, $casCommands);
  200. $tx = $this->getMockedTransaction($callback, $options);
  201. $replies = $tx->execute(function($tx) {
  202. $tx->get('foo');
  203. $tx->get('hoge');
  204. });
  205. $this->assertSame($replies, $expected);
  206. $this->assertSame(array('WATCH'), self::commandsToIDs($casCommands));
  207. $this->assertSame(array('foo', 'hoge'), $casCommands[0]->getArguments());
  208. $this->assertSame(array('MULTI', 'GET', 'GET', 'EXEC'), self::commandsToIDs($txCommands));
  209. }
  210. /**
  211. * @group disconnected
  212. */
  213. public function testCheckAndSetWithFluentInterface()
  214. {
  215. $txCommands = $casCommands = array();
  216. $expected = array('bar', 'piyo');
  217. $options = array('cas' => true, 'watch' => array('foo', 'hoge'));
  218. $callback = $this->getExecuteCallback($expected, $txCommands, $casCommands);
  219. $tx = $this->getMockedTransaction($callback, $options);
  220. $tx->watch('foobar');
  221. $this->assertSame('DUMMY_REPLY', $tx->get('foo'));
  222. $this->assertSame('DUMMY_REPLY', $tx->get('hoge'));
  223. $replies = $tx->multi()
  224. ->get('foo')
  225. ->get('hoge')
  226. ->execute();
  227. $this->assertSame($replies, $expected);
  228. $this->assertSame(array('WATCH', 'WATCH', 'GET', 'GET'), self::commandsToIDs($casCommands));
  229. $this->assertSame(array('MULTI', 'GET', 'GET', 'EXEC'), self::commandsToIDs($txCommands));
  230. }
  231. /**
  232. * @group disconnected
  233. */
  234. public function testCheckAndSetWithBlock()
  235. {
  236. $txCommands = $casCommands = array();
  237. $expected = array('bar', 'piyo');
  238. $options = array('cas' => true, 'watch' => array('foo', 'hoge'));
  239. $callback = $this->getExecuteCallback($expected, $txCommands, $casCommands);
  240. $tx = $this->getMockedTransaction($callback, $options);
  241. $test = $this;
  242. $replies = $tx->execute(function($tx) use($test) {
  243. $tx->watch('foobar');
  244. $reply1 = $tx->get('foo');
  245. $reply2 = $tx->get('hoge');
  246. $test->assertSame('DUMMY_REPLY', $reply1);
  247. $test->assertSame('DUMMY_REPLY', $reply2);
  248. $tx->multi();
  249. $tx->get('foo');
  250. $tx->get('hoge');
  251. });
  252. $this->assertSame($replies, $expected);
  253. $this->assertSame(array('WATCH', 'WATCH', 'GET', 'GET'), self::commandsToIDs($casCommands));
  254. $this->assertSame(array('MULTI', 'GET', 'GET', 'EXEC'), self::commandsToIDs($txCommands));
  255. }
  256. /**
  257. * @group disconnected
  258. */
  259. public function testCheckAndSetWithEmptyBlock()
  260. {
  261. $txCommands = $casCommands = array();
  262. $options = array('cas' => true);
  263. $callback = $this->getExecuteCallback(array(), $txCommands, $casCommands);
  264. $tx = $this->getMockedTransaction($callback, $options);
  265. $tx->execute(function($tx) {
  266. $tx->multi();
  267. });
  268. $this->assertSame(array(), self::commandsToIDs($casCommands));
  269. $this->assertSame(array(), self::commandsToIDs($txCommands));
  270. }
  271. /**
  272. * @group disconnected
  273. */
  274. public function testCheckAndSetWithoutExec()
  275. {
  276. $txCommands = $casCommands = array();
  277. $options = array('cas' => true);
  278. $callback = $this->getExecuteCallback(array(), $txCommands, $casCommands);
  279. $tx = $this->getMockedTransaction($callback, $options);
  280. $tx->execute(function($tx) {
  281. $bar = $tx->get('foo');
  282. $tx->set('hoge', 'piyo');
  283. });
  284. $this->assertSame(array('GET', 'SET'), self::commandsToIDs($casCommands));
  285. $this->assertSame(array(), self::commandsToIDs($txCommands));
  286. }
  287. /**
  288. * @group disconnected
  289. * @expectedException InvalidArgumentException
  290. * @expectedExceptionMessage Automatic retries can be used only when a transaction block is provided
  291. */
  292. public function testThrowsExceptionOnAutomaticRetriesWithFluentInterface()
  293. {
  294. $options = array('retry' => 1);
  295. $callback = $this->getExecuteCallback();
  296. $tx = $this->getMockedTransaction($callback, $options);
  297. $tx->echo('message')->execute();
  298. }
  299. /**
  300. * @group disconnected
  301. */
  302. public function testAutomaticRetryOnServerSideTransactionAbort()
  303. {
  304. $casCommands = $txCommands = array();
  305. $expected = array('bar');
  306. $options = array('watch' => array('foo', 'bar'), 'retry' => ($attempts = 2) + 1);
  307. $sentinel = $this->getMock('stdClass', array('signal'));
  308. $sentinel->expects($this->exactly($attempts))->method('signal');
  309. $callback = $this->getExecuteCallback($expected, $txCommands, $casCommands);
  310. $tx = $this->getMockedTransaction($callback, $options);
  311. $replies = $tx->execute(function($tx) use($sentinel, &$attempts) {
  312. $tx->get('foo');
  313. if ($attempts > 0) {
  314. $attempts -= 1;
  315. $sentinel->signal();
  316. $tx->echo('!!ABORT!!');
  317. }
  318. });
  319. $this->assertSame($replies, $expected);
  320. $this->assertSame(array('WATCH'), self::commandsToIDs($casCommands));
  321. $this->assertSame(array('foo', 'bar'), $casCommands[0]->getArguments());
  322. $this->assertSame(array('MULTI', 'GET', 'EXEC'), self::commandsToIDs($txCommands));
  323. }
  324. /**
  325. * @group disconnected
  326. * @expectedException Predis\Transaction\AbortedMultiExecException
  327. */
  328. public function testThrowsExceptionOnServerSideTransactionAbort()
  329. {
  330. $callback = $this->getExecuteCallback();
  331. $tx = $this->getMockedTransaction($callback);
  332. $replies = $tx->execute(function($tx) {
  333. $tx->echo('!!ABORT!!');
  334. });
  335. }
  336. /**
  337. * @group disconnected
  338. */
  339. public function testHandlesStandardExceptionsInBlock()
  340. {
  341. $commands = array();
  342. $expected = array('foobar', true);
  343. $callback = $this->getExecuteCallback($expected, $commands);
  344. $tx = $this->getMockedTransaction($callback);
  345. $replies = null;
  346. try {
  347. $replies = $tx->execute(function($tx) {
  348. $tx->set('foo', 'bar');
  349. $tx->get('foo');
  350. throw new \RuntimeException('TEST');
  351. });
  352. }
  353. catch (\Exception $ex) {
  354. // NOOP
  355. }
  356. $this->assertNull($replies, $expected);
  357. $this->assertSame(array('MULTI', 'SET', 'GET', 'DISCARD'), self::commandsToIDs($commands));
  358. }
  359. /**
  360. * @group disconnected
  361. */
  362. public function testHandlesServerExceptionsInBlock()
  363. {
  364. $commands = array();
  365. $expected = array('foobar', true);
  366. $callback = $this->getExecuteCallback($expected, $commands);
  367. $tx = $this->getMockedTransaction($callback);
  368. $replies = null;
  369. try {
  370. $replies = $tx->execute(function($tx) {
  371. $tx->set('foo', 'bar');
  372. $tx->echo('ERR Invalid operation');
  373. $tx->get('foo');
  374. });
  375. }
  376. catch (ServerException $ex) {
  377. $tx->discard();
  378. }
  379. $this->assertNull($replies);
  380. $this->assertSame(array('MULTI', 'SET', 'ECHO', 'DISCARD'), self::commandsToIDs($commands));
  381. }
  382. // ******************************************************************** //
  383. // ---- INTEGRATION TESTS --------------------------------------------- //
  384. // ******************************************************************** //
  385. /**
  386. * @group connected
  387. */
  388. public function testIntegrationHandlesStandardExceptionsInBlock()
  389. {
  390. $client = $this->getClient();
  391. $exception = null;
  392. try {
  393. $client->multiExec(function($tx) {
  394. $tx->set('foo', 'bar');
  395. throw new \RuntimeException("TEST");
  396. });
  397. }
  398. catch (\Exception $ex) {
  399. $exception = $ex;
  400. }
  401. $this->assertInstanceOf('RuntimeException', $exception);
  402. $this->assertFalse($client->exists('foo'));
  403. }
  404. /**
  405. * @group connected
  406. */
  407. public function testIntegrationSendMultiOnCommandsAfterDiscard()
  408. {
  409. $client = $this->getClient();
  410. $replies = $client->multiExec(function($tx) {
  411. $tx->set('foo', 'bar');
  412. $tx->discard();
  413. $tx->set('hoge', 'piyo');
  414. });
  415. $this->assertSame(1, count($replies));
  416. $this->assertFalse($client->exists('foo'));
  417. $this->assertTrue($client->exists('hoge'));
  418. }
  419. /**
  420. * @group connected
  421. */
  422. public function testIntegrationWritesOnWatchedKeysAbortTransaction()
  423. {
  424. $exception = null;
  425. $client1 = $this->getClient();
  426. $client2 = $this->getClient();
  427. try {
  428. $client1->multiExec(array('watch' => 'sentinel'), function($tx) use($client2) {
  429. $tx->set('sentinel', 'client1');
  430. $tx->get('sentinel');
  431. $client2->set('sentinel', 'client2');
  432. });
  433. }
  434. catch (AbortedMultiExecException $ex) {
  435. $exception = $ex;
  436. }
  437. $this->assertInstanceOf('Predis\Transaction\AbortedMultiExecException', $exception);
  438. $this->assertSame('client2', $client1->get('sentinel'));
  439. }
  440. /**
  441. * @group connected
  442. */
  443. public function testIntegrationCheckAndSetWithDiscardAndRetry()
  444. {
  445. $client = $this->getClient();
  446. $client->set('foo', 'bar');
  447. $options = array('watch' => 'foo', 'cas' => true);
  448. $replies = $client->multiExec($options, function($tx) {
  449. $tx->watch('foobar');
  450. $foo = $tx->get('foo');
  451. $tx->multi();
  452. $tx->set('foobar', $foo);
  453. $tx->discard();
  454. $tx->mget('foo', 'foobar');
  455. });
  456. $this->assertInternalType('array', $replies);
  457. $this->assertSame(array(array('bar', null)), $replies);
  458. $hijack = true;
  459. $client2 = $this->getClient();
  460. $client->set('foo', 'bar');
  461. $options = array('watch' => 'foo', 'cas' => true, 'retry' => 1);
  462. $replies = $client->multiExec($options, function($tx) use($client2, &$hijack) {
  463. $foo = $tx->get('foo');
  464. $tx->multi();
  465. $tx->set('foobar', $foo);
  466. $tx->discard();
  467. if ($hijack) {
  468. $hijack = false;
  469. $client2->set('foo', 'hijacked!');
  470. }
  471. $tx->mget('foo', 'foobar');
  472. });
  473. $this->assertInternalType('array', $replies);
  474. $this->assertSame(array(array('hijacked!', null)), $replies);
  475. }
  476. // ******************************************************************** //
  477. // ---- HELPER METHODS ------------------------------------------------ //
  478. // ******************************************************************** //
  479. /**
  480. * Returns a mocked instance of Predis\Network\IConnectionSingle using
  481. * the specified callback to return values from the executeCommand method.
  482. *
  483. * @param \Closure $executeCallback
  484. * @return \Predis\Network\IConnectionSingle
  485. */
  486. protected function getMockedConnection($executeCallback)
  487. {
  488. $connection = $this->getMock('Predis\Network\IConnectionSingle');
  489. $connection->expects($this->any())
  490. ->method('executeCommand')
  491. ->will($this->returnCallback($executeCallback));
  492. return $connection;
  493. }
  494. /**
  495. * Returns a mocked instance of Predis\Transaction\MultiExecContext using
  496. * the specified callback to return values from the executeCommand method
  497. * of the underlying connection.
  498. *
  499. * @param \Closure $executeCallback
  500. * @return MultiExecContext
  501. */
  502. protected function getMockedTransaction($executeCallback, $options = array())
  503. {
  504. $connection = $this->getMockedConnection($executeCallback);
  505. $client = new Client($connection);
  506. $transaction = new MultiExecContext($client, $options);
  507. return $transaction;
  508. }
  509. /**
  510. * Returns a callback that emulates a server-side MULTI/EXEC transaction context.
  511. *
  512. * @param array $expected Expected replies.
  513. * @param array $commands Reference to an array that stores the whole flow of commands.
  514. * @return \Closure
  515. */
  516. protected function getExecuteCallback($expected = array(), &$commands = array(), &$cas = array())
  517. {
  518. $multi = $watch = $abort = false;
  519. return function(ICommand $command) use(&$expected, &$commands, &$cas, &$multi, &$watch, &$abort) {
  520. $cmd = $command->getId();
  521. if ($multi || $cmd === 'MULTI') {
  522. $commands[] = $command;
  523. }
  524. else {
  525. $cas[] = $command;
  526. }
  527. switch ($cmd) {
  528. case 'WATCH':
  529. if ($multi) {
  530. throw new ServerException("ERR $cmd inside MULTI is not allowed");
  531. }
  532. return $watch = true;
  533. case 'MULTI':
  534. if ($multi) {
  535. throw new ServerException("ERR MULTI calls can not be nested");
  536. }
  537. return $multi = true;
  538. case 'EXEC':
  539. if (!$multi) {
  540. throw new ServerException("ERR $cmd without MULTI");
  541. }
  542. $watch = $multi = false;
  543. if ($abort) {
  544. $commands = $cas = array();
  545. $abort = false;
  546. return null;
  547. }
  548. return $expected;
  549. case 'DISCARD':
  550. if (!$multi) {
  551. throw new ServerException("ERR $cmd without MULTI");
  552. }
  553. $watch = $multi = false;
  554. return true;
  555. case 'ECHO':
  556. @list($trigger) = $command->getArguments();
  557. if (strpos($trigger, 'ERR ') === 0) {
  558. throw new ServerException($trigger);
  559. }
  560. if ($trigger === '!!ABORT!!' && $multi) {
  561. $abort = true;
  562. }
  563. return new ResponseQueued();
  564. case 'UNWATCH':
  565. $watch = false;
  566. default:
  567. return $multi ? new ResponseQueued() : 'DUMMY_REPLY';
  568. }
  569. };
  570. }
  571. /**
  572. * Converts an array of instances of Predis\Commands\ICommand and
  573. * returns an array containing their IDs.
  574. *
  575. * @param array $commands List of commands instances.
  576. * @return array
  577. */
  578. protected static function commandsToIDs($commands) {
  579. return array_map(function($cmd) { return $cmd->getId(); }, $commands);
  580. }
  581. /**
  582. * Returns a client instance connected to the specified Redis
  583. * server instance to perform integration tests.
  584. *
  585. * @return array Additional connection parameters.
  586. * @return Client client instance.
  587. */
  588. protected function getClient(Array $parameters = array())
  589. {
  590. $parameters = array_merge(array(
  591. 'scheme' => 'tcp',
  592. 'host' => REDIS_SERVER_HOST,
  593. 'port' => REDIS_SERVER_PORT,
  594. 'database' => REDIS_SERVER_DBNUM,
  595. ), $parameters);
  596. $client = new Client($parameters, array('profile' => REDIS_SERVER_VERSION));
  597. $client->connect();
  598. $client->flushdb();
  599. return $client;
  600. }
  601. }