You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

210 lines
6.6 KiB

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