SearchBuilderTest.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
  4. *
  5. * @license GNU AGPL version 3 or any later version
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Affero General Public License as
  9. * published by the Free Software Foundation, either version 3 of the
  10. * License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Affero General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. */
  21. namespace Test\Files\Cache;
  22. use OC\DB\QueryBuilder\Literal;
  23. use OC\Files\Cache\SearchBuilder;
  24. use OC\Files\Search\SearchBinaryOperator;
  25. use OC\Files\Search\SearchComparison;
  26. use OCP\DB\QueryBuilder\IQueryBuilder;
  27. use OCP\Files\IMimeTypeLoader;
  28. use OCP\Files\Search\ISearchBinaryOperator;
  29. use OCP\Files\Search\ISearchComparison;
  30. use OCP\Files\Search\ISearchOperator;
  31. use Test\TestCase;
  32. /**
  33. * @group DB
  34. */
  35. class SearchBuilderTest extends TestCase {
  36. /** @var IQueryBuilder */
  37. private $builder;
  38. /** @var IMimeTypeLoader|\PHPUnit\Framework\MockObject\MockObject */
  39. private $mimetypeLoader;
  40. /** @var SearchBuilder */
  41. private $searchBuilder;
  42. /** @var integer */
  43. private $numericStorageId;
  44. protected function setUp(): void {
  45. parent::setUp();
  46. $this->builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
  47. $this->mimetypeLoader = $this->createMock(IMimeTypeLoader::class);
  48. $this->mimetypeLoader->expects($this->any())
  49. ->method('getId')
  50. ->willReturnMap([
  51. ['text', 1],
  52. ['text/plain', 2],
  53. ['text/xml', 3],
  54. ['image/jpg', 4],
  55. ['image/png', 5],
  56. ['image', 6],
  57. ]);
  58. $this->mimetypeLoader->expects($this->any())
  59. ->method('getMimetypeById')
  60. ->willReturnMap([
  61. [1, 'text'],
  62. [2, 'text/plain'],
  63. [3, 'text/xml'],
  64. [4, 'image/jpg'],
  65. [5, 'image/png'],
  66. [6, 'image']
  67. ]);
  68. $this->searchBuilder = new SearchBuilder($this->mimetypeLoader);
  69. $this->numericStorageId = 10000;
  70. $this->builder->select(['fileid'])
  71. ->from('filecache', 'file') // alias needed for QuerySearchHelper#getOperatorFieldAndValue
  72. ->where($this->builder->expr()->eq('storage', new Literal($this->numericStorageId)));
  73. }
  74. protected function tearDown(): void {
  75. parent::tearDown();
  76. $builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
  77. $builder->delete('filecache')
  78. ->where($builder->expr()->eq('storage', $builder->createNamedParameter($this->numericStorageId, IQueryBuilder::PARAM_INT)));
  79. $builder->execute();
  80. }
  81. private function addCacheEntry(array $data) {
  82. $data['storage'] = $this->numericStorageId;
  83. $data['etag'] = 'unimportant';
  84. $data['storage_mtime'] = $data['mtime'];
  85. if (!isset($data['path'])) {
  86. $data['path'] = 'random/' . $this->getUniqueID();
  87. }
  88. $data['path_hash'] = md5($data['path']);
  89. if (!isset($data['mtime'])) {
  90. $data['mtime'] = 100;
  91. }
  92. if (!isset($data['size'])) {
  93. $data['size'] = 100;
  94. }
  95. $data['name'] = basename($data['path']);
  96. $data['parent'] = -1;
  97. if (isset($data['mimetype'])) {
  98. [$mimepart,] = explode('/', $data['mimetype']);
  99. $data['mimepart'] = $this->mimetypeLoader->getId($mimepart);
  100. $data['mimetype'] = $this->mimetypeLoader->getId($data['mimetype']);
  101. } else {
  102. $data['mimepart'] = 1;
  103. $data['mimetype'] = 1;
  104. }
  105. $builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
  106. $values = [];
  107. foreach ($data as $key => $value) {
  108. $values[$key] = $builder->createNamedParameter($value);
  109. }
  110. $builder->insert('filecache')
  111. ->values($values)
  112. ->execute();
  113. return $builder->getLastInsertId();
  114. }
  115. private function search(ISearchOperator $operator) {
  116. $dbOperator = $this->searchBuilder->searchOperatorToDBExpr($this->builder, $operator);
  117. $this->builder->andWhere($dbOperator);
  118. $result = $this->builder->execute();
  119. $rows = $result->fetchAll(\PDO::FETCH_COLUMN);
  120. $result->closeCursor();
  121. return $rows;
  122. }
  123. public function comparisonProvider() {
  124. return [
  125. [new SearchComparison(ISearchComparison::COMPARE_GREATER_THAN, 'mtime', 125), [1]],
  126. [new SearchComparison(ISearchComparison::COMPARE_LESS_THAN, 'mtime', 125), [0]],
  127. [new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'size', 125), []],
  128. [new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'size', 50), [0, 1]],
  129. [new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'name', 'foobar'), [0]],
  130. [new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', 'foo%'), [0, 1]],
  131. [new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mimetype', 'image/jpg'), [0]],
  132. [new SearchComparison(ISearchComparison::COMPARE_LIKE, 'mimetype', 'image/%'), [0, 1]],
  133. [new SearchComparison(ISearchComparison::COMPARE_IN, 'mimetype', ['image/jpg', 'image/png']), [0, 1]],
  134. [new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_AND, [
  135. new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'size', 50),
  136. new SearchComparison(ISearchComparison::COMPARE_LESS_THAN, 'mtime', 125)
  137. ]), [0]],
  138. [new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_AND, [
  139. new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'size', 50),
  140. new SearchComparison(ISearchComparison::COMPARE_LESS_THAN, 'mtime', 125),
  141. new SearchComparison(ISearchComparison::COMPARE_LIKE, 'mimetype', 'text/%')
  142. ]), []],
  143. [new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_OR, [
  144. new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mtime', 100),
  145. new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mtime', 150),
  146. ]), [0, 1]],
  147. [new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_NOT, [
  148. new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mtime', 150),
  149. ]), [0]],
  150. [new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_NOT, [
  151. new SearchComparison(ISearchComparison::COMPARE_GREATER_THAN, 'mtime', 125),
  152. ]), [0]],
  153. [new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_NOT, [
  154. new SearchComparison(ISearchComparison::COMPARE_LESS_THAN, 'mtime', 125),
  155. ]), [1]],
  156. [new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_NOT, [
  157. new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', '%bar'),
  158. ]), [1]],
  159. ];
  160. }
  161. /**
  162. * @dataProvider comparisonProvider
  163. *
  164. * @param ISearchOperator $operator
  165. * @param array $fileIds
  166. */
  167. public function testComparison(ISearchOperator $operator, array $fileIds) {
  168. $fileId = [];
  169. $fileId[] = $this->addCacheEntry([
  170. 'path' => 'foobar',
  171. 'mtime' => 100,
  172. 'size' => 50,
  173. 'mimetype' => 'image/jpg'
  174. ]);
  175. $fileId[] = $this->addCacheEntry([
  176. 'path' => 'fooasd',
  177. 'mtime' => 150,
  178. 'size' => 50,
  179. 'mimetype' => 'image/png'
  180. ]);
  181. $fileIds = array_map(function ($i) use ($fileId) {
  182. return $fileId[$i];
  183. }, $fileIds);
  184. $results = $this->search($operator);
  185. sort($fileIds);
  186. sort($results);
  187. $this->assertEquals($fileIds, $results);
  188. }
  189. }