SearchBuilderTest.php 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-License-Identifier: AGPL-3.0-or-later
  5. */
  6. namespace Test\Files\Cache;
  7. use OC\DB\QueryBuilder\Literal;
  8. use OC\Files\Cache\SearchBuilder;
  9. use OC\Files\Search\SearchBinaryOperator;
  10. use OC\Files\Search\SearchComparison;
  11. use OCP\DB\QueryBuilder\IQueryBuilder;
  12. use OCP\Files\IMimeTypeLoader;
  13. use OCP\Files\Search\ISearchBinaryOperator;
  14. use OCP\Files\Search\ISearchComparison;
  15. use OCP\Files\Search\ISearchOperator;
  16. use Test\TestCase;
  17. /**
  18. * @group DB
  19. */
  20. class SearchBuilderTest extends TestCase {
  21. /** @var IQueryBuilder */
  22. private $builder;
  23. /** @var IMimeTypeLoader|\PHPUnit\Framework\MockObject\MockObject */
  24. private $mimetypeLoader;
  25. /** @var SearchBuilder */
  26. private $searchBuilder;
  27. /** @var integer */
  28. private $numericStorageId;
  29. protected function setUp(): void {
  30. parent::setUp();
  31. $this->builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
  32. $this->mimetypeLoader = $this->createMock(IMimeTypeLoader::class);
  33. $this->mimetypeLoader->expects($this->any())
  34. ->method('getId')
  35. ->willReturnMap([
  36. ['text', 1],
  37. ['text/plain', 2],
  38. ['text/xml', 3],
  39. ['image/jpg', 4],
  40. ['image/png', 5],
  41. ['image', 6],
  42. ]);
  43. $this->mimetypeLoader->expects($this->any())
  44. ->method('getMimetypeById')
  45. ->willReturnMap([
  46. [1, 'text'],
  47. [2, 'text/plain'],
  48. [3, 'text/xml'],
  49. [4, 'image/jpg'],
  50. [5, 'image/png'],
  51. [6, 'image']
  52. ]);
  53. $this->searchBuilder = new SearchBuilder($this->mimetypeLoader);
  54. $this->numericStorageId = 10000;
  55. $this->builder->select(['fileid'])
  56. ->from('filecache', 'file') // alias needed for QuerySearchHelper#getOperatorFieldAndValue
  57. ->where($this->builder->expr()->eq('storage', new Literal($this->numericStorageId)));
  58. }
  59. protected function tearDown(): void {
  60. parent::tearDown();
  61. $builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
  62. $builder->delete('filecache')
  63. ->where($builder->expr()->eq('storage', $builder->createNamedParameter($this->numericStorageId, IQueryBuilder::PARAM_INT)));
  64. $builder->execute();
  65. }
  66. private function addCacheEntry(array $data) {
  67. $data['storage'] = $this->numericStorageId;
  68. $data['etag'] = 'unimportant';
  69. $data['storage_mtime'] = $data['mtime'];
  70. if (!isset($data['path'])) {
  71. $data['path'] = 'random/' . $this->getUniqueID();
  72. }
  73. $data['path_hash'] = md5($data['path']);
  74. if (!isset($data['mtime'])) {
  75. $data['mtime'] = 100;
  76. }
  77. if (!isset($data['size'])) {
  78. $data['size'] = 100;
  79. }
  80. $data['name'] = basename($data['path']);
  81. $data['parent'] = -1;
  82. if (isset($data['mimetype'])) {
  83. [$mimepart,] = explode('/', $data['mimetype']);
  84. $data['mimepart'] = $this->mimetypeLoader->getId($mimepart);
  85. $data['mimetype'] = $this->mimetypeLoader->getId($data['mimetype']);
  86. } else {
  87. $data['mimepart'] = 1;
  88. $data['mimetype'] = 1;
  89. }
  90. $builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
  91. $values = [];
  92. foreach ($data as $key => $value) {
  93. $values[$key] = $builder->createNamedParameter($value);
  94. }
  95. $builder->insert('filecache')
  96. ->values($values)
  97. ->execute();
  98. return $builder->getLastInsertId();
  99. }
  100. private function search(ISearchOperator $operator) {
  101. $dbOperator = $this->searchBuilder->searchOperatorToDBExpr($this->builder, $operator);
  102. $this->builder->andWhere($dbOperator);
  103. $result = $this->builder->execute();
  104. $rows = $result->fetchAll(\PDO::FETCH_COLUMN);
  105. $result->closeCursor();
  106. return $rows;
  107. }
  108. public function comparisonProvider() {
  109. return [
  110. [new SearchComparison(ISearchComparison::COMPARE_GREATER_THAN, 'mtime', 125), [1]],
  111. [new SearchComparison(ISearchComparison::COMPARE_LESS_THAN, 'mtime', 125), [0]],
  112. [new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'size', 125), []],
  113. [new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'size', 50), [0, 1]],
  114. [new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'name', 'foobar'), [0]],
  115. [new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', 'foo%'), [0, 1]],
  116. [new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mimetype', 'image/jpg'), [0]],
  117. [new SearchComparison(ISearchComparison::COMPARE_LIKE, 'mimetype', 'image/%'), [0, 1]],
  118. [new SearchComparison(ISearchComparison::COMPARE_IN, 'mimetype', ['image/jpg', 'image/png']), [0, 1]],
  119. [new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_AND, [
  120. new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'size', 50),
  121. new SearchComparison(ISearchComparison::COMPARE_LESS_THAN, 'mtime', 125)
  122. ]), [0]],
  123. [new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_AND, [
  124. new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'size', 50),
  125. new SearchComparison(ISearchComparison::COMPARE_LESS_THAN, 'mtime', 125),
  126. new SearchComparison(ISearchComparison::COMPARE_LIKE, 'mimetype', 'text/%')
  127. ]), []],
  128. [new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_OR, [
  129. new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mtime', 100),
  130. new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mtime', 150),
  131. ]), [0, 1]],
  132. [new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_NOT, [
  133. new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mtime', 150),
  134. ]), [0]],
  135. [new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_NOT, [
  136. new SearchComparison(ISearchComparison::COMPARE_GREATER_THAN, 'mtime', 125),
  137. ]), [0]],
  138. [new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_NOT, [
  139. new SearchComparison(ISearchComparison::COMPARE_LESS_THAN, 'mtime', 125),
  140. ]), [1]],
  141. [new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_NOT, [
  142. new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', '%bar'),
  143. ]), [1]],
  144. ];
  145. }
  146. /**
  147. * @dataProvider comparisonProvider
  148. *
  149. * @param ISearchOperator $operator
  150. * @param array $fileIds
  151. */
  152. public function testComparison(ISearchOperator $operator, array $fileIds): void {
  153. $fileId = [];
  154. $fileId[] = $this->addCacheEntry([
  155. 'path' => 'foobar',
  156. 'mtime' => 100,
  157. 'size' => 50,
  158. 'mimetype' => 'image/jpg'
  159. ]);
  160. $fileId[] = $this->addCacheEntry([
  161. 'path' => 'fooasd',
  162. 'mtime' => 150,
  163. 'size' => 50,
  164. 'mimetype' => 'image/png'
  165. ]);
  166. $fileIds = array_map(function ($i) use ($fileId) {
  167. return $fileId[$i];
  168. }, $fileIds);
  169. $results = $this->search($operator);
  170. sort($fileIds);
  171. sort($results);
  172. $this->assertEquals($fileIds, $results);
  173. }
  174. }