MongoDbTest.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\Cache\Test\Unit\Backend;
  7. class MongoDbTest extends \PHPUnit\Framework\TestCase
  8. {
  9. /**
  10. * @var \Magento\Framework\Cache\Backend\MongoDb|null
  11. */
  12. protected $_model = null;
  13. /**
  14. * @var \PHPUnit_Framework_MockObject_MockObject
  15. */
  16. protected $_collection = null;
  17. protected function setUp()
  18. {
  19. $this->_collection = $this->getMockBuilder('MongoCollection')
  20. ->setMethods(['find', 'findOne', 'distinct', 'save', 'update', 'remove', 'drop'])
  21. ->getMock();
  22. $this->_model = $this->createPartialMock(\Magento\Framework\Cache\Backend\MongoDb::class, ['_getCollection']);
  23. $this->_model->expects($this->any())->method('_getCollection')->will($this->returnValue($this->_collection));
  24. }
  25. protected function tearDown()
  26. {
  27. $this->_model = null;
  28. $this->_collection = null;
  29. }
  30. /**
  31. * @param array $ids
  32. * @param array $expected
  33. * @dataProvider getIdsDataProvider
  34. */
  35. public function testGetIds(array $ids, array $expected)
  36. {
  37. $result = new \ArrayIterator($ids);
  38. $this->_collection->expects($this->once())->method('find')->will($this->returnValue($result));
  39. $actual = $this->_model->getIds();
  40. $this->assertEquals($expected, $actual);
  41. }
  42. /**
  43. * @return array
  44. */
  45. public function getIdsDataProvider()
  46. {
  47. return [
  48. 'empty db' => [[], []],
  49. 'multiple records' => [['id1' => 'id1', 'id2' => 'id2'], ['id1', 'id2']]
  50. ];
  51. }
  52. /**
  53. * @param array $tags
  54. * @dataProvider getTagsDataProvider
  55. */
  56. public function testGetTags(array $tags)
  57. {
  58. $this->_collection->expects($this->once())->method('distinct')->with('tags')->will($this->returnValue($tags));
  59. $actual = $this->_model->getTags();
  60. $this->assertEquals($tags, $actual);
  61. }
  62. /**
  63. * @return array
  64. */
  65. public function getTagsDataProvider()
  66. {
  67. return ['no tags' => [[]], 'multiple tags' => [['tag1', 'tag2']]];
  68. }
  69. /**
  70. * @covers \Magento\Framework\Cache\Backend\MongoDb::getIdsMatchingTags
  71. * @covers \Magento\Framework\Cache\Backend\MongoDb::getIdsNotMatchingTags
  72. * @covers \Magento\Framework\Cache\Backend\MongoDb::getIdsMatchingAnyTags
  73. * @dataProvider getIdsMatchingTagsDataProvider
  74. */
  75. public function testGetIdsMatchingTags($method, $tags, $expectedInput)
  76. {
  77. $expectedOutput = new \ArrayIterator(['test1' => 'test1', 'test2' => 'test2']);
  78. $expectedIds = ['test1', 'test2'];
  79. $this->_collection->expects(
  80. $this->once()
  81. )->method(
  82. 'find'
  83. )->with(
  84. $expectedInput
  85. )->will(
  86. $this->returnValue($expectedOutput)
  87. );
  88. $actualIds = $this->_model->{$method}($tags);
  89. $this->assertEquals($expectedIds, $actualIds);
  90. }
  91. /**
  92. * @return array
  93. */
  94. public function getIdsMatchingTagsDataProvider()
  95. {
  96. return [
  97. 'getIdsMatchingTags() - one tag' => [
  98. 'getIdsMatchingTags',
  99. ['tag1'],
  100. ['$and' => [['tags' => 'tag1']]],
  101. ],
  102. 'getIdsMatchingTags() - multiple tags' => [
  103. 'getIdsMatchingTags',
  104. ['tag1', 'tag2'],
  105. ['$and' => [['tags' => 'tag1'], ['tags' => 'tag2']]],
  106. ],
  107. 'getIdsNotMatchingTags() - one tag' => [
  108. 'getIdsNotMatchingTags',
  109. ['tag1'],
  110. ['$nor' => [['tags' => 'tag1']]],
  111. ],
  112. 'getIdsNotMatchingTags() - multiple tags' => [
  113. 'getIdsNotMatchingTags',
  114. ['tag1', 'tag2'],
  115. ['$nor' => [['tags' => 'tag1'], ['tags' => 'tag2']]],
  116. ],
  117. 'getIdsMatchingAnyTags() - one tag' => [
  118. 'getIdsMatchingAnyTags',
  119. ['tag1'],
  120. ['$or' => [['tags' => 'tag1']]],
  121. ],
  122. 'getIdsMatchingAnyTags() - multiple tags' => [
  123. 'getIdsMatchingAnyTags',
  124. ['tag1', 'tag2'],
  125. ['$or' => [['tags' => 'tag1'], ['tags' => 'tag2']]],
  126. ]
  127. ];
  128. }
  129. /**
  130. * @covers \Magento\Framework\Cache\Backend\MongoDb::getIdsMatchingTags
  131. * @covers \Magento\Framework\Cache\Backend\MongoDb::getIdsNotMatchingTags
  132. * @covers \Magento\Framework\Cache\Backend\MongoDb::getIdsMatchingAnyTags
  133. */
  134. public function testGetIdsMatchingTagsNoInputTags()
  135. {
  136. $this->_collection->expects($this->never())->method('find');
  137. $this->assertEquals([], $this->_model->getIdsMatchingTags([]));
  138. $this->assertEquals([], $this->_model->getIdsNotMatchingTags([]));
  139. $this->assertEquals([], $this->_model->getIdsMatchingAnyTags([]));
  140. }
  141. public function testGetFillingPercentage()
  142. {
  143. $actual = $this->_model->getFillingPercentage();
  144. $this->assertGreaterThan(0, $actual);
  145. $this->assertLessThan(100, $actual);
  146. }
  147. /**
  148. * @param mixed $cacheId
  149. * @param array $expectedInput
  150. * @param array|null $mongoOutput
  151. * @param array|bool $expected
  152. * @dataProvider getMetadatasDataProvider
  153. */
  154. public function testGetMetadatas($cacheId, $expectedInput, $mongoOutput, $expected)
  155. {
  156. $this->_collection->expects(
  157. $this->once()
  158. )->method(
  159. 'findOne'
  160. )->with(
  161. $expectedInput
  162. )->will(
  163. $this->returnValue($mongoOutput)
  164. );
  165. $actual = $this->_model->getMetadatas($cacheId);
  166. $this->assertEquals($expected, $actual);
  167. }
  168. /**
  169. * @return array
  170. */
  171. public function getMetadatasDataProvider()
  172. {
  173. $time = time();
  174. return [
  175. 'existing record' => [
  176. 'test_id',
  177. ['_id' => 'test_id'],
  178. ['_id' => 'test_id', 'data' => 'data', 'tags' => [], 'expire' => $time, 'mtime' => $time],
  179. ['_id' => 'test_id', 'data' => 'data', 'tags' => [], 'expire' => $time, 'mtime' => $time],
  180. ],
  181. 'non-existing record' => ['test_id', ['_id' => 'test_id'], null, false],
  182. 'non-string id' => [
  183. 10,
  184. ['_id' => '10'],
  185. ['_id' => 'test_id', 'data' => 'data', 'tags' => [], 'expire' => $time, 'mtime' => $time],
  186. ['_id' => 'test_id', 'data' => 'data', 'tags' => [], 'expire' => $time, 'mtime' => $time],
  187. ]
  188. ];
  189. }
  190. public function testTouch()
  191. {
  192. $cacheId = 'test';
  193. $this->_collection->expects($this->once())->method('update')->with($this->arrayHasKey('_id'));
  194. $this->_model->touch($cacheId, 100);
  195. }
  196. public function testGetCapabilities()
  197. {
  198. $capabilities = $this->_model->getCapabilities();
  199. $this->assertArrayHasKey('automatic_cleaning', $capabilities);
  200. $this->assertArrayHasKey('tags', $capabilities);
  201. $this->assertArrayHasKey('expired_read', $capabilities);
  202. $this->assertArrayHasKey('priority', $capabilities);
  203. $this->assertArrayHasKey('infinite_lifetime', $capabilities);
  204. $this->assertArrayHasKey('get_list', $capabilities);
  205. }
  206. /**
  207. * @param bool $doNotTestValidity
  208. * @dataProvider loadDataProvider
  209. */
  210. public function testLoad($doNotTestValidity)
  211. {
  212. include_once __DIR__ . '/_files/MongoBinData.txt';
  213. $cacheId = 'test_id';
  214. $expected = 'test_data';
  215. $validityCondition = $this->arrayHasKey('$or');
  216. if ($doNotTestValidity) {
  217. $validityCondition = $this->logicalNot($validityCondition);
  218. }
  219. $binData = new \MongoBinData($expected, \MongoBinData::BYTE_ARRAY);
  220. $binData->bin = $expected;
  221. $this->_collection->expects(
  222. $this->once()
  223. )->method(
  224. 'findOne'
  225. )->with(
  226. $this->logicalAnd($this->arrayHasKey('_id'), $validityCondition)
  227. )->will(
  228. $this->returnValue(['data' => $binData])
  229. );
  230. $actual = $this->_model->load($cacheId, $doNotTestValidity);
  231. $this->assertSame($expected, $actual);
  232. }
  233. /**
  234. * @return array
  235. */
  236. public function loadDataProvider()
  237. {
  238. return ['test validity' => [false], 'do not test validity' => [true]];
  239. }
  240. public function testLoadNoRecord()
  241. {
  242. $this->_collection->expects($this->once())->method('findOne')->will($this->returnValue(null));
  243. $this->assertFalse($this->_model->load('test_id'));
  244. }
  245. public function testTest()
  246. {
  247. $cacheId = 'test_id';
  248. $time = time();
  249. $this->_collection->expects(
  250. $this->once()
  251. )->method(
  252. 'findOne'
  253. )->with(
  254. $this->logicalAnd($this->arrayHasKey('_id'), $this->contains($cacheId))
  255. )->will(
  256. $this->returnValue(['mtime' => $time])
  257. );
  258. $this->assertSame($time, $this->_model->test($cacheId));
  259. }
  260. public function testTestNotFound()
  261. {
  262. $this->_collection->expects($this->once())->method('findOne')->will($this->returnValue(null));
  263. $this->assertFalse($this->_model->test('test_id'));
  264. }
  265. public function testSave()
  266. {
  267. include_once __DIR__ . '/_files/MongoBinData.txt';
  268. $inputAssertion = $this->logicalAnd(
  269. $this->arrayHasKey('_id'),
  270. $this->arrayHasKey('data'),
  271. $this->arrayHasKey('tags'),
  272. $this->arrayHasKey('mtime'),
  273. $this->arrayHasKey('expire')
  274. );
  275. $this->_collection->expects(
  276. $this->once()
  277. )->method(
  278. 'save'
  279. )->with(
  280. $inputAssertion
  281. )->will(
  282. $this->returnValue(true)
  283. );
  284. $this->assertTrue($this->_model->save('test data', 'test_id', ['tag1', 'tag2'], 100));
  285. }
  286. public function testRemove()
  287. {
  288. $cacheId = 'test';
  289. $this->_collection->expects(
  290. $this->once()
  291. )->method(
  292. 'remove'
  293. )->with(
  294. ['_id' => $cacheId]
  295. )->will(
  296. $this->returnValue(true)
  297. );
  298. $this->assertTrue($this->_model->remove($cacheId));
  299. }
  300. /**
  301. * @param string $mode
  302. * @param array $tags
  303. * @param array $expectedQuery
  304. * @dataProvider cleanDataProvider
  305. */
  306. public function testClean($mode, $tags, $expectedQuery)
  307. {
  308. $this->_collection->expects($this->once())->method('remove')->with($expectedQuery);
  309. $this->_model->clean($mode, $tags);
  310. }
  311. /**
  312. * @return array
  313. */
  314. public function cleanDataProvider()
  315. {
  316. return [
  317. 'clean expired' => [\Zend_Cache::CLEANING_MODE_OLD, [], $this->arrayHasKey('expire')],
  318. 'clean cache matching all tags (string)' => [
  319. \Zend_Cache::CLEANING_MODE_MATCHING_TAG,
  320. 'tag1',
  321. ['$and' => [['tags' => 'tag1']]],
  322. ],
  323. 'clean cache matching all tags (one tag)' => [
  324. \Zend_Cache::CLEANING_MODE_MATCHING_TAG,
  325. ['tag1'],
  326. ['$and' => [['tags' => 'tag1']]],
  327. ],
  328. 'clean cache matching all tags (multiple tags)' => [
  329. \Zend_Cache::CLEANING_MODE_MATCHING_TAG,
  330. ['tag1', 'tag2'],
  331. ['$and' => [['tags' => 'tag1'], ['tags' => 'tag2']]],
  332. ],
  333. 'clean cache not matching tags (string)' => [
  334. \Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG,
  335. 'tag1',
  336. ['$nor' => [['tags' => 'tag1']]],
  337. ],
  338. 'clean cache not matching tags (one tag)' => [
  339. \Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG,
  340. ['tag1'],
  341. ['$nor' => [['tags' => 'tag1']]],
  342. ],
  343. 'clean cache not matching tags (multiple tags)' => [
  344. \Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG,
  345. ['tag1', 'tag2'],
  346. ['$nor' => [['tags' => 'tag1'], ['tags' => 'tag2']]],
  347. ],
  348. 'clean cache matching any tags (string)' => [
  349. \Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG,
  350. 'tag1',
  351. ['$or' => [['tags' => 'tag1']]],
  352. ],
  353. 'clean cache matching any tags (one tag)' => [
  354. \Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG,
  355. ['tag1'],
  356. ['$or' => [['tags' => 'tag1']]],
  357. ],
  358. 'clean cache matching any tags (multiple tags)' => [
  359. \Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG,
  360. ['tag1', 'tag2'],
  361. ['$or' => [['tags' => 'tag1'], ['tags' => 'tag2']]],
  362. ]
  363. ];
  364. }
  365. public function cleanAll()
  366. {
  367. $this->_collection->expects($this->once())->method('drop')->will($this->returnValue(['ok' => true]));
  368. $this->assertTrue($this->_model->clean(\Zend_Cache::CLEANING_MODE_ALL));
  369. }
  370. public function cleanNoTags()
  371. {
  372. $this->_collection->expects($this->never())->method('remove');
  373. $modes = [
  374. \Zend_Cache::CLEANING_MODE_MATCHING_TAG,
  375. \Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG,
  376. \Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG,
  377. ];
  378. foreach ($modes as $mode) {
  379. $this->assertFalse($this->_model->clean($mode));
  380. }
  381. }
  382. /**
  383. * @expectedException \Zend_Cache_Exception
  384. * @expectedExceptionMessage Unsupported cleaning mode: invalid_mode
  385. */
  386. public function testCleanInvalidMode()
  387. {
  388. $this->_model->clean('invalid_mode');
  389. }
  390. }