MemcachedAdapterTest.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.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 Symfony\Component\Cache\Tests\Adapter;
  11. use Symfony\Component\Cache\Adapter\AbstractAdapter;
  12. use Symfony\Component\Cache\Adapter\MemcachedAdapter;
  13. class MemcachedAdapterTest extends AdapterTestCase
  14. {
  15. protected $skippedTests = [
  16. 'testHasItemReturnsFalseWhenDeferredItemIsExpired' => 'Testing expiration slows down the test suite',
  17. 'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
  18. ];
  19. protected static $client;
  20. public static function setUpBeforeClass(): void
  21. {
  22. if (!MemcachedAdapter::isSupported()) {
  23. self::markTestSkipped('Extension memcached >=2.2.0 required.');
  24. }
  25. self::$client = AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST'), ['binary_protocol' => false]);
  26. self::$client->get('foo');
  27. $code = self::$client->getResultCode();
  28. if (\Memcached::RES_SUCCESS !== $code && \Memcached::RES_NOTFOUND !== $code) {
  29. self::markTestSkipped('Memcached error: '.strtolower(self::$client->getResultMessage()));
  30. }
  31. }
  32. public function createCachePool($defaultLifetime = 0)
  33. {
  34. $client = $defaultLifetime ? AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST')) : self::$client;
  35. return new MemcachedAdapter($client, str_replace('\\', '.', __CLASS__), $defaultLifetime);
  36. }
  37. public function testOptions()
  38. {
  39. $client = MemcachedAdapter::createConnection([], [
  40. 'libketama_compatible' => false,
  41. 'distribution' => 'modula',
  42. 'compression' => true,
  43. 'serializer' => 'php',
  44. 'hash' => 'md5',
  45. ]);
  46. $this->assertSame(\Memcached::SERIALIZER_PHP, $client->getOption(\Memcached::OPT_SERIALIZER));
  47. $this->assertSame(\Memcached::HASH_MD5, $client->getOption(\Memcached::OPT_HASH));
  48. $this->assertTrue($client->getOption(\Memcached::OPT_COMPRESSION));
  49. $this->assertSame(0, $client->getOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE));
  50. $this->assertSame(\Memcached::DISTRIBUTION_MODULA, $client->getOption(\Memcached::OPT_DISTRIBUTION));
  51. }
  52. /**
  53. * @dataProvider provideBadOptions
  54. */
  55. public function testBadOptions($name, $value)
  56. {
  57. $this->expectException('ErrorException');
  58. $this->expectExceptionMessage('constant(): Couldn\'t find constant Memcached::');
  59. MemcachedAdapter::createConnection([], [$name => $value]);
  60. }
  61. public function provideBadOptions()
  62. {
  63. return [
  64. ['foo', 'bar'],
  65. ['hash', 'zyx'],
  66. ['serializer', 'zyx'],
  67. ['distribution', 'zyx'],
  68. ];
  69. }
  70. public function testDefaultOptions()
  71. {
  72. $this->assertTrue(MemcachedAdapter::isSupported());
  73. $client = MemcachedAdapter::createConnection([]);
  74. $this->assertTrue($client->getOption(\Memcached::OPT_COMPRESSION));
  75. $this->assertSame(1, $client->getOption(\Memcached::OPT_BINARY_PROTOCOL));
  76. $this->assertSame(1, $client->getOption(\Memcached::OPT_TCP_NODELAY));
  77. $this->assertSame(1, $client->getOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE));
  78. }
  79. public function testOptionSerializer()
  80. {
  81. $this->expectException('Symfony\Component\Cache\Exception\CacheException');
  82. $this->expectExceptionMessage('MemcachedAdapter: "serializer" option must be "php" or "igbinary".');
  83. if (!\Memcached::HAVE_JSON) {
  84. $this->markTestSkipped('Memcached::HAVE_JSON required');
  85. }
  86. new MemcachedAdapter(MemcachedAdapter::createConnection([], ['serializer' => 'json']));
  87. }
  88. /**
  89. * @dataProvider provideServersSetting
  90. */
  91. public function testServersSetting($dsn, $host, $port)
  92. {
  93. $client1 = MemcachedAdapter::createConnection($dsn);
  94. $client2 = MemcachedAdapter::createConnection([$dsn]);
  95. $client3 = MemcachedAdapter::createConnection([[$host, $port]]);
  96. $expect = [
  97. 'host' => $host,
  98. 'port' => $port,
  99. ];
  100. $f = function ($s) { return ['host' => $s['host'], 'port' => $s['port']]; };
  101. $this->assertSame([$expect], array_map($f, $client1->getServerList()));
  102. $this->assertSame([$expect], array_map($f, $client2->getServerList()));
  103. $this->assertSame([$expect], array_map($f, $client3->getServerList()));
  104. }
  105. public function provideServersSetting()
  106. {
  107. yield [
  108. 'memcached://127.0.0.1/50',
  109. '127.0.0.1',
  110. 11211,
  111. ];
  112. yield [
  113. 'memcached://localhost:11222?weight=25',
  114. 'localhost',
  115. 11222,
  116. ];
  117. if (filter_var(ini_get('memcached.use_sasl'), FILTER_VALIDATE_BOOLEAN)) {
  118. yield [
  119. 'memcached://user:password@127.0.0.1?weight=50',
  120. '127.0.0.1',
  121. 11211,
  122. ];
  123. }
  124. yield [
  125. 'memcached:///var/run/memcached.sock?weight=25',
  126. '/var/run/memcached.sock',
  127. 0,
  128. ];
  129. yield [
  130. 'memcached:///var/local/run/memcached.socket?weight=25',
  131. '/var/local/run/memcached.socket',
  132. 0,
  133. ];
  134. if (filter_var(ini_get('memcached.use_sasl'), FILTER_VALIDATE_BOOLEAN)) {
  135. yield [
  136. 'memcached://user:password@/var/local/run/memcached.socket?weight=25',
  137. '/var/local/run/memcached.socket',
  138. 0,
  139. ];
  140. }
  141. }
  142. /**
  143. * @dataProvider provideDsnWithOptions
  144. */
  145. public function testDsnWithOptions($dsn, array $options, array $expectedOptions)
  146. {
  147. $client = MemcachedAdapter::createConnection($dsn, $options);
  148. foreach ($expectedOptions as $option => $expect) {
  149. $this->assertSame($expect, $client->getOption($option));
  150. }
  151. }
  152. public function provideDsnWithOptions()
  153. {
  154. if (!class_exists('\Memcached')) {
  155. self::markTestSkipped('Extension memcached required.');
  156. }
  157. yield [
  158. 'memcached://localhost:11222?retry_timeout=10',
  159. [\Memcached::OPT_RETRY_TIMEOUT => 8],
  160. [\Memcached::OPT_RETRY_TIMEOUT => 10],
  161. ];
  162. yield [
  163. 'memcached://localhost:11222?socket_recv_size=1&socket_send_size=2',
  164. [\Memcached::OPT_RETRY_TIMEOUT => 8],
  165. [\Memcached::OPT_SOCKET_RECV_SIZE => 1, \Memcached::OPT_SOCKET_SEND_SIZE => 2, \Memcached::OPT_RETRY_TIMEOUT => 8],
  166. ];
  167. }
  168. public function testClear()
  169. {
  170. $this->assertTrue($this->createCachePool()->clear());
  171. }
  172. public function testMultiServerDsn()
  173. {
  174. $dsn = 'memcached:?host[localhost]&host[localhost:12345]&host[/some/memcached.sock:]=3';
  175. $client = MemcachedAdapter::createConnection($dsn);
  176. $expected = [
  177. 0 => [
  178. 'host' => 'localhost',
  179. 'port' => 11211,
  180. 'type' => 'TCP',
  181. ],
  182. 1 => [
  183. 'host' => 'localhost',
  184. 'port' => 12345,
  185. 'type' => 'TCP',
  186. ],
  187. 2 => [
  188. 'host' => '/some/memcached.sock',
  189. 'port' => 0,
  190. 'type' => 'SOCKET',
  191. ],
  192. ];
  193. $this->assertSame($expected, $client->getServerList());
  194. $dsn = 'memcached://localhost?host[foo.bar]=3';
  195. $client = MemcachedAdapter::createConnection($dsn);
  196. $expected = [
  197. 0 => [
  198. 'host' => 'localhost',
  199. 'port' => 11211,
  200. 'type' => 'TCP',
  201. ],
  202. 1 => [
  203. 'host' => 'foo.bar',
  204. 'port' => 11211,
  205. 'type' => 'TCP',
  206. ],
  207. ];
  208. $this->assertSame($expected, $client->getServerList());
  209. }
  210. }