PredisTestCase.php 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  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. use Predis\Client;
  11. use Predis\Command;
  12. use Predis\Connection;
  13. /**
  14. * Base test case class for the Predis test suite.
  15. */
  16. abstract class PredisTestCase extends \PHPUnit_Framework_TestCase
  17. {
  18. protected $redisServerVersion = null;
  19. /**
  20. * Sleep the test case with microseconds resolution.
  21. *
  22. * @param float $seconds Seconds to sleep.
  23. */
  24. protected function sleep($seconds)
  25. {
  26. usleep($seconds * 1000000);
  27. }
  28. /**
  29. * Returns if the current runtime is HHVM.
  30. *
  31. * @return bool
  32. */
  33. protected function isHHVM()
  34. {
  35. return defined('HHVM_VERSION');
  36. }
  37. /**
  38. * Verifies that a Redis command is a valid Predis\Command\CommandInterface
  39. * instance with the specified ID and command arguments.
  40. *
  41. * @param string|Command\CommandInterface $command Expected command or command ID.
  42. * @param array $arguments Expected command arguments.
  43. *
  44. * @return RedisCommandConstraint
  45. */
  46. public function isRedisCommand($command = null, array $arguments = null)
  47. {
  48. return new RedisCommandConstraint($command, $arguments);
  49. }
  50. /**
  51. * Verifies that a Redis command is a valid Predis\Command\CommandInterface
  52. * instance with the specified ID and command arguments. The comparison does
  53. * not check for identity when passing a Predis\Command\CommandInterface
  54. * instance for $expected.
  55. *
  56. * @param array|string|Command\CommandInterface $expected Expected command.
  57. * @param mixed $actual Actual command.
  58. * @param string $message Optional assertion message.
  59. */
  60. public function assertRedisCommand($expected, $actual, $message = '')
  61. {
  62. if (is_array($expected)) {
  63. @list($command, $arguments) = $expected;
  64. } else {
  65. $command = $expected;
  66. $arguments = null;
  67. }
  68. $this->assertThat($actual, new RedisCommandConstraint($command, $arguments), $message);
  69. }
  70. /**
  71. * Asserts that two arrays have the same values, even if with different order.
  72. *
  73. * @param array $expected Expected array.
  74. * @param array $actual Actual array.
  75. * @param string $message Optional assertion message.
  76. */
  77. public function assertSameValues(array $expected, array $actual, $message = '')
  78. {
  79. $this->assertThat($actual, new ArrayHasSameValuesConstraint($expected), $message);
  80. }
  81. /**
  82. * Returns a named array with the default connection parameters and their values.
  83. *
  84. * @return array Default connection parameters.
  85. */
  86. protected function getDefaultParametersArray()
  87. {
  88. return array(
  89. 'scheme' => 'tcp',
  90. 'host' => REDIS_SERVER_HOST,
  91. 'port' => REDIS_SERVER_PORT,
  92. 'database' => REDIS_SERVER_DBNUM,
  93. );
  94. }
  95. /**
  96. * Returns a named array with the default client options and their values.
  97. *
  98. * @return array Default connection parameters.
  99. */
  100. protected function getDefaultOptionsArray()
  101. {
  102. return array(
  103. 'commands' => new Command\RedisFactory(),
  104. );
  105. }
  106. /**
  107. * Returns a named array with the default connection parameters merged with
  108. * the specified additional parameters.
  109. *
  110. * @param array $additional Additional connection parameters.
  111. *
  112. * @return array Connection parameters.
  113. */
  114. protected function getParametersArray(array $additional)
  115. {
  116. return array_merge($this->getDefaultParametersArray(), $additional);
  117. }
  118. /**
  119. * Returns a new instance of connection parameters.
  120. *
  121. * @param array $additional Additional connection parameters.
  122. *
  123. * @return Connection\Parameters
  124. */
  125. protected function getParameters($additional = array())
  126. {
  127. $parameters = array_merge($this->getDefaultParametersArray(), $additional);
  128. $parameters = new Connection\Parameters($parameters);
  129. return $parameters;
  130. }
  131. /**
  132. * Returns a new instance of command factory.
  133. *
  134. * @return Command\FactoryInterface
  135. */
  136. protected function getCommandFactory()
  137. {
  138. return new Command\RedisFactory();
  139. }
  140. /**
  141. * Returns a new client instance.
  142. *
  143. * @param array $parameters Additional connection parameters.
  144. * @param array $options Additional client options.
  145. * @param bool $flushdb Flush selected database before returning the client.
  146. *
  147. * @return Client
  148. */
  149. protected function createClient(array $parameters = null, array $options = null, $flushdb = true)
  150. {
  151. $parameters = array_merge(
  152. $this->getDefaultParametersArray(),
  153. $parameters ?: array()
  154. );
  155. $options = array_merge(
  156. array(
  157. 'commands' => $this->getCommandFactory(),
  158. ),
  159. $options ?: array()
  160. );
  161. $client = new Client($parameters, $options);
  162. $client->connect();
  163. if ($flushdb) {
  164. $client->flushdb();
  165. }
  166. return $client;
  167. }
  168. /**
  169. * Returns a basic mocked connection of the specified type.
  170. *
  171. * @param string $interface Connection type.
  172. * @param mixed $parameters Optional parameters.
  173. *
  174. * @return \Predis\Connection\NodeConnectionInterface
  175. */
  176. protected function getMockConnectionOfType($interface, $parameters = null)
  177. {
  178. $connection = $this->getMock($interface);
  179. if ($parameters) {
  180. $parameters = Connection\Parameters::create($parameters);
  181. $hash = "{$parameters->host}:{$parameters->port}";
  182. $connection
  183. ->expects($this->any())
  184. ->method('getParameters')
  185. ->will($this->returnValue($parameters));
  186. $connection
  187. ->expects($this->any())
  188. ->method('__toString')
  189. ->will($this->returnValue($hash));
  190. }
  191. return $connection;
  192. }
  193. /**
  194. * Returns a basic mocked connection of type Predis\Connection\NodeConnectionInterface.
  195. *
  196. * @param mixed $parameters Optional parameters.
  197. *
  198. * @return \Predis\Connection\NodeConnectionInterface
  199. */
  200. protected function getMockConnection($parameters = null)
  201. {
  202. return $this->getMockConnectionOfType('Predis\Connection\NodeConnectionInterface', $parameters);
  203. }
  204. /**
  205. * Returns the server version of the Redis instance used by the test suite.
  206. *
  207. * @throws RuntimeException When the client cannot retrieve the current server version
  208. *
  209. * @return string
  210. */
  211. protected function getRedisServerVersion()
  212. {
  213. if (isset($this->redisServerVersion)) {
  214. return $this->redisServerVersion;
  215. }
  216. $client = $this->createClient(null, null, true);
  217. $info = array_change_key_case($client->info());
  218. if (isset($info['server']['redis_version'])) {
  219. // Redis >= 2.6
  220. $version = $info['server']['redis_version'];
  221. } elseif (isset($info['redis_version'])) {
  222. // Redis < 2.6
  223. $version = $info['redis_version'];
  224. } else {
  225. throw new RuntimeException('Unable to retrieve server info');
  226. }
  227. $this->redisServerVersion = $version;
  228. return $version;
  229. }
  230. /**
  231. * Returns the Redis server version required to run a @connected test from
  232. * the @requiresRedisVersion annotation decorating a test method.
  233. *
  234. * @return string
  235. */
  236. protected function getRequiredRedisServerVersion()
  237. {
  238. $annotations = $this->getAnnotations();
  239. if (isset($annotations['method']['requiresRedisVersion'], $annotations['method']['group']) &&
  240. !empty($annotations['method']['requiresRedisVersion']) &&
  241. in_array('connected', $annotations['method']['group'])
  242. ) {
  243. return $annotations['method']['requiresRedisVersion'][0];
  244. }
  245. return;
  246. }
  247. /**
  248. * Compares the specified version string against the Redis server version in
  249. * use for integration tests.
  250. *
  251. * @param string $operator Comparison operator.
  252. * @param string $version Version to compare.
  253. *
  254. * @return bool
  255. */
  256. public function isRedisServerVersion($operator, $version)
  257. {
  258. $serverVersion = $this->getRedisServerVersion();
  259. $comparation = version_compare($serverVersion, $version);
  260. return (bool) eval("return $comparation $operator 0;");
  261. }
  262. /**
  263. * Checks that the Redis server version used to run integration tests mets
  264. * the requirements specified with the @requiresRedisVersion annotation.
  265. *
  266. * @throws \PHPUnit_Framework_SkippedTestError When expected Redis server version is not met.
  267. */
  268. protected function checkRequiredRedisServerVersion()
  269. {
  270. if (!$requiredVersion = $this->getRequiredRedisServerVersion()) {
  271. return;
  272. }
  273. $requiredVersion = explode(' ', $requiredVersion, 2);
  274. if (count($requiredVersion) === 1) {
  275. $reqOperator = '>=';
  276. $reqVersion = $requiredVersion[0];
  277. } else {
  278. $reqOperator = $requiredVersion[0];
  279. $reqVersion = $requiredVersion[1];
  280. }
  281. if (!$this->isRedisServerVersion($reqOperator, $reqVersion)) {
  282. $serverVersion = $this->getRedisServerVersion();
  283. $this->markTestSkipped(
  284. "This test requires Redis $reqOperator $reqVersion but the current version is $serverVersion."
  285. );
  286. }
  287. }
  288. /**
  289. * {@inheritdoc}
  290. */
  291. protected function checkRequirements()
  292. {
  293. parent::checkRequirements();
  294. $this->checkRequiredRedisServerVersion();
  295. }
  296. }