From 866cb0598b00aa7f2bb8145c3b5bee1468f015d2 Mon Sep 17 00:00:00 2001 From: Aleksej Tikhanovich Date: Fri, 21 Jun 2024 16:56:05 +0200 Subject: [PATCH 01/11] feat: update elasticsearch with v8 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 00a3b99..4f32eae 100755 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ "oat-sa/extension-tao-outcome": ">=13.0.0", "oat-sa/extension-tao-test": ">=15.15.1", "oat-sa/extension-tao-mediamanager": ">=12.32.1", - "oat-sa/lib-tao-elasticsearch": ">=2.5.2" + "oat-sa/lib-tao-elasticsearch": "dev-feat/FUN-1740/update-elastic-lib" }, "autoload": { "psr-4": { From 0465c5320733be57330a72a4a41bd82b0d7d121a Mon Sep 17 00:00:00 2001 From: Aleksej Tikhanovich Date: Mon, 24 Jun 2024 16:51:27 +0200 Subject: [PATCH 02/11] feat: update elasticsearch with v8 --- .../Driver/Elasticsearch/ElasticSearch.php | 10 +++---- .../ElasticSearchClientFactory.php | 5 ++-- .../Elasticsearch/ElasticSearchConfig.php | 30 ++++++++++++++++++- .../Elasticsearch/ElasticSearchIndexer.php | 2 +- .../Driver/Elasticsearch/IndexUpdater.php | 2 +- .../ServiceProvider/SearchEngineProvider.php | 2 +- scripts/tools/Activate.php | 2 +- .../ElasticSearchIndexerTest.php | 2 +- .../Elasticsearch/ElasticSearchTest.php | 6 ++-- .../Driver/Elasticsearch/IndexUpdaterTest.php | 4 +-- 10 files changed, 47 insertions(+), 18 deletions(-) diff --git a/model/SearchEngine/Driver/Elasticsearch/ElasticSearch.php b/model/SearchEngine/Driver/Elasticsearch/ElasticSearch.php index 14b72d4..b49295c 100644 --- a/model/SearchEngine/Driver/Elasticsearch/ElasticSearch.php +++ b/model/SearchEngine/Driver/Elasticsearch/ElasticSearch.php @@ -23,7 +23,7 @@ namespace oat\taoAdvancedSearch\model\SearchEngine\Driver\Elasticsearch; use ArrayIterator; -use Elasticsearch\Client; +use Elastic\Elasticsearch\Client; use Exception; use Iterator; use oat\tao\model\search\SearchInterface as TaoSearchInterface; @@ -111,7 +111,7 @@ public function search(Query $query): SearchResult ) ]; - return $this->buildResultSet($this->client->search($query)); + return $this->buildResultSet($this->client->search($query)->asArray()); } public function query($queryString, $type, $start = 0, $count = 10, $order = '_id', $dir = 'DESC'): ResultSet @@ -125,7 +125,7 @@ public function query($queryString, $type, $start = 0, $count = 10, $order = '_i $this->logger->debug(sprintf('Elasticsearch Query %s', json_encode($query))); return $this->searchResultNormalizer->normalizeByByResultSet( - $this->buildResultSet($this->client->search($query)) + $this->buildResultSet($this->client->search($query)->asArray()) ); } catch (Exception $exception) { switch ($exception->getCode()) { @@ -193,12 +193,12 @@ public function flush(): array 'ignore' => 404 ] ] - ); + )->asArray(); } public function ping(): bool { - return $this->client->ping(); + return $this->client->ping()->asBool(); } private function buildResultSet(array $elasticResult = []): SearchResult diff --git a/model/SearchEngine/Driver/Elasticsearch/ElasticSearchClientFactory.php b/model/SearchEngine/Driver/Elasticsearch/ElasticSearchClientFactory.php index f08ccdc..e0c94dd 100644 --- a/model/SearchEngine/Driver/Elasticsearch/ElasticSearchClientFactory.php +++ b/model/SearchEngine/Driver/Elasticsearch/ElasticSearchClientFactory.php @@ -24,8 +24,8 @@ namespace oat\taoAdvancedSearch\model\SearchEngine\Driver\Elasticsearch; -use Elasticsearch\Client; -use Elasticsearch\ClientBuilder; +use Elastic\Elasticsearch\Client; +use Elastic\Elasticsearch\ClientBuilder; class ElasticSearchClientFactory { @@ -48,6 +48,7 @@ public function create(): Client return ClientBuilder::create() ->setHosts($this->config->getHosts()) + ->setBasicAuthentication($this->config->getUsername(), $this->config->getPassword()) ->build(); } } diff --git a/model/SearchEngine/Driver/Elasticsearch/ElasticSearchConfig.php b/model/SearchEngine/Driver/Elasticsearch/ElasticSearchConfig.php index 85b20b7..1e9b94d 100644 --- a/model/SearchEngine/Driver/Elasticsearch/ElasticSearchConfig.php +++ b/model/SearchEngine/Driver/Elasticsearch/ElasticSearchConfig.php @@ -44,7 +44,35 @@ public function __construct(ServiceOptionsInterface $serviceOptions) public function getHosts(): array { - return $this->serviceOptions->get(self::class, self::OPTION_HOSTS); + $hosts = []; + foreach ($this->serviceOptions->get(self::class, self::OPTION_HOSTS) as $host) { + if (is_array($host) && isset($host['host'])){ + $hosts[] = ($host['scheme'] ?? 'http') . '://' . $host['host'] . ':' . ($host['port'] ?? 9200); + } else { + $hosts[] = $host; + } + } + return $hosts; + } + + public function getUsername(): ?string + { + foreach ($this->serviceOptions->get(self::class, self::OPTION_HOSTS) as $host) { + if (is_array($host) && isset($host['user'])){ + return $host['user']; + } + } + return ''; + } + + public function getPassword(): ?string + { + foreach ($this->serviceOptions->get(self::class, self::OPTION_HOSTS) as $host) { + if (is_array($host) && isset($host['pass'])){ + return $host['pass']; + } + } + return ''; } public function getIndexPrefix(): ?string diff --git a/model/SearchEngine/Driver/Elasticsearch/ElasticSearchIndexer.php b/model/SearchEngine/Driver/Elasticsearch/ElasticSearchIndexer.php index 564004e..25bb080 100644 --- a/model/SearchEngine/Driver/Elasticsearch/ElasticSearchIndexer.php +++ b/model/SearchEngine/Driver/Elasticsearch/ElasticSearchIndexer.php @@ -23,7 +23,7 @@ namespace oat\taoAdvancedSearch\model\SearchEngine\Driver\Elasticsearch; use oat\tao\model\search\index\IndexDocument; -use Elasticsearch\Client; +use Elastic\Elasticsearch\Client; use oat\taoAdvancedSearch\model\SearchEngine\Contract\IndexerInterface; use oat\taoAdvancedSearch\model\SearchEngine\Service\IndexPrefixer; use Psr\Log\LoggerInterface; diff --git a/model/SearchEngine/Driver/Elasticsearch/IndexUpdater.php b/model/SearchEngine/Driver/Elasticsearch/IndexUpdater.php index 107c0ab..67667b9 100644 --- a/model/SearchEngine/Driver/Elasticsearch/IndexUpdater.php +++ b/model/SearchEngine/Driver/Elasticsearch/IndexUpdater.php @@ -22,7 +22,7 @@ namespace oat\taoAdvancedSearch\model\SearchEngine\Driver\Elasticsearch; -use Elasticsearch\Client; +use Elastic\Elasticsearch\Client; use oat\oatbox\service\ConfigurableService; use oat\tao\model\search\index\IndexUpdaterInterface; use oat\taoAdvancedSearch\model\SearchEngine\Contract\IndexerInterface; diff --git a/model/SearchEngine/ServiceProvider/SearchEngineProvider.php b/model/SearchEngine/ServiceProvider/SearchEngineProvider.php index fd5773a..d8e0881 100644 --- a/model/SearchEngine/ServiceProvider/SearchEngineProvider.php +++ b/model/SearchEngine/ServiceProvider/SearchEngineProvider.php @@ -24,7 +24,7 @@ namespace oat\taoAdvancedSearch\model\SearchEngine\ServiceProvider; -use Elasticsearch\Client; +use Elastic\Elasticsearch\Client; use oat\generis\model\data\permission\PermissionInterface; use oat\generis\model\DependencyInjection\ContainerServiceProviderInterface; use oat\generis\model\DependencyInjection\ServiceOptions; diff --git a/scripts/tools/Activate.php b/scripts/tools/Activate.php index e465b3d..6b2f4a2 100644 --- a/scripts/tools/Activate.php +++ b/scripts/tools/Activate.php @@ -24,7 +24,7 @@ namespace oat\taoAdvancedSearch\scripts\tools; -use Elasticsearch\Common\Exceptions\BadRequest400Exception; +use BadRequest400Exception; use Exception; use oat\generis\model\DependencyInjection\ServiceOptions; use oat\oatbox\extension\script\ScriptAction; diff --git a/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchIndexerTest.php b/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchIndexerTest.php index ef2d2c7..70a6e25 100644 --- a/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchIndexerTest.php +++ b/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchIndexerTest.php @@ -25,7 +25,7 @@ use oat\oatbox\log\LoggerService; use oat\tao\model\search\index\IndexDocument; use oat\tao\model\TaoOntology; -use Elasticsearch\Client; +use Elastic\Elasticsearch\Client; use oat\taoAdvancedSearch\model\SearchEngine\Contract\IndexerInterface; use oat\taoAdvancedSearch\model\SearchEngine\Driver\Elasticsearch\ElasticSearchIndexer; use oat\taoAdvancedSearch\model\SearchEngine\Service\IndexPrefixer; diff --git a/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchTest.php b/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchTest.php index 04ff86a..b63d67b 100644 --- a/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchTest.php +++ b/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchTest.php @@ -22,8 +22,8 @@ namespace oat\taoAdvancedSearch\tests\Unit\SearchEngine\Driver\Elasticsearch; -use Elasticsearch\Client; -use Elasticsearch\Namespaces\IndicesNamespace; +use Elastic\Elasticsearch\Client; +use Elastic\Elasticsearch\Endpoints\Indices; use Exception; use oat\tao\model\search\ResultSet; use oat\tao\model\search\strategy\GenerisSearch; @@ -241,7 +241,7 @@ public function testQuery_callElasticSearch400Error(): void public function testCreateIndexes_callIndexCreationBasedOnIndexOption(): void { - $indexMock = $this->createMock(IndicesNamespace::class); + $indexMock = $this->createMock(Indices::class); $indexMock->expects($this->at(0)) ->method('create') ->with( diff --git a/tests/Unit/SearchEngine/Driver/Elasticsearch/IndexUpdaterTest.php b/tests/Unit/SearchEngine/Driver/Elasticsearch/IndexUpdaterTest.php index 2821d7f..b30fa21 100644 --- a/tests/Unit/SearchEngine/Driver/Elasticsearch/IndexUpdaterTest.php +++ b/tests/Unit/SearchEngine/Driver/Elasticsearch/IndexUpdaterTest.php @@ -22,8 +22,8 @@ namespace oat\taoAdvancedSearch\tests\Unit\SearchEngine\Driver\Elasticsearch; -use Elasticsearch\Client; -use Elasticsearch\Common\Exceptions\BadMethodCallException; +use Elastic\Elasticsearch\Client; +use Elastic\Elasticsearch\Exception\BadMethodCallException; use oat\generis\test\TestCase; use oat\oatbox\log\LoggerService; use oat\tao\model\TaoOntology; From fdc569e62521ab369a10acd322336000d6d36780 Mon Sep 17 00:00:00 2001 From: Aleksej Tikhanovich Date: Mon, 24 Jun 2024 17:26:02 +0200 Subject: [PATCH 03/11] feat: delete lib-tao-elasticsearch --- README.md | 8 +------- composer.json | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index a3775e9..b306353 100644 --- a/README.md +++ b/README.md @@ -10,16 +10,10 @@ > Extension required to advanced search integration with TAO platform `oat-sa/extension-tao-advanced-search` -# WARNING - -The library `oat-sa/lib-tao-elasticsearch` is **deprecated** and this presence in the [composer.json](composer.json) -is maintained only for backward compatibility purposes with already installed applications. - -Please, do not use this classes anymore! Use only classes from this very extension. ## Requirements -- ElasticSearch 7.10+ installed. +- ElasticSearch 8+ installed. - Have this extension installed in TAO. ## Installation instructions diff --git a/composer.json b/composer.json index 4f32eae..f5dda6f 100755 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ "oat-sa/extension-tao-outcome": ">=13.0.0", "oat-sa/extension-tao-test": ">=15.15.1", "oat-sa/extension-tao-mediamanager": ">=12.32.1", - "oat-sa/lib-tao-elasticsearch": "dev-feat/FUN-1740/update-elastic-lib" + "elasticsearch/elasticsearch": "~8.13" }, "autoload": { "psr-4": { From c3011b4a701a989ede05824c19ff53a0bc8aee55 Mon Sep 17 00:00:00 2001 From: Aleksej Tikhanovich Date: Tue, 25 Jun 2024 09:16:31 +0200 Subject: [PATCH 04/11] fix: code style changes --- .../ElasticSearchClientFactory.php | 14 +++++++++----- .../Elasticsearch/ElasticSearchConfig.php | 19 +++++++------------ 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/model/SearchEngine/Driver/Elasticsearch/ElasticSearchClientFactory.php b/model/SearchEngine/Driver/Elasticsearch/ElasticSearchClientFactory.php index e0c94dd..be4e3f8 100644 --- a/model/SearchEngine/Driver/Elasticsearch/ElasticSearchClientFactory.php +++ b/model/SearchEngine/Driver/Elasticsearch/ElasticSearchClientFactory.php @@ -39,16 +39,20 @@ public function __construct(ElasticSearchConfig $config) public function create(): Client { + $clientBuilder = ClientBuilder::create(); + if ($this->config->getElasticCloudId()) { - return ClientBuilder::create() + return $clientBuilder ->setElasticCloudId($this->config->getElasticCloudId()) ->setApiKey($this->config->getElasticCloudApiKeyId(), $this->config->getElasticCloudApiKey()) ->build(); } + + $clientBuilder->setHosts($this->config->getHosts()); + if ($this->config->getUsername() && $this->config->getPassword()) { + $clientBuilder->setBasicAuthentication($this->config->getUsername(), $this->config->getPassword()); + } - return ClientBuilder::create() - ->setHosts($this->config->getHosts()) - ->setBasicAuthentication($this->config->getUsername(), $this->config->getPassword()) - ->build(); + return $clientBuilder->build(); } } diff --git a/model/SearchEngine/Driver/Elasticsearch/ElasticSearchConfig.php b/model/SearchEngine/Driver/Elasticsearch/ElasticSearchConfig.php index 1e9b94d..5a130fd 100644 --- a/model/SearchEngine/Driver/Elasticsearch/ElasticSearchConfig.php +++ b/model/SearchEngine/Driver/Elasticsearch/ElasticSearchConfig.php @@ -57,22 +57,12 @@ public function getHosts(): array public function getUsername(): ?string { - foreach ($this->serviceOptions->get(self::class, self::OPTION_HOSTS) as $host) { - if (is_array($host) && isset($host['user'])){ - return $host['user']; - } - } - return ''; + return $this->getFirstHost()['user'] ?? null; } public function getPassword(): ?string { - foreach ($this->serviceOptions->get(self::class, self::OPTION_HOSTS) as $host) { - if (is_array($host) && isset($host['pass'])){ - return $host['pass']; - } - } - return ''; + return $this->getFirstHost()['pass'] ?? null; } public function getIndexPrefix(): ?string @@ -94,4 +84,9 @@ public function getElasticCloudApiKeyId(): ?string { return $this->serviceOptions->get(self::class, self::OPTION_ELASTIC_CLOUD_API_KEY_ID); } + + private function getFirstHost(): ?array + { + return current($this->serviceOptions->get(self::class, self::OPTION_HOSTS)) ?: null; + } } From 70e1039f4670328527f5c6ea0250db1f70e4dd0a Mon Sep 17 00:00:00 2001 From: Aleksej Tikhanovich Date: Tue, 25 Jun 2024 12:55:37 +0200 Subject: [PATCH 05/11] feat: add aliases for indexes --- README.md | 8 ++- config/aliases.conf.php | 36 +++++++++++ config/assets.conf.php | 3 + config/deliveries.conf.php | 3 + config/delivery-results.conf.php | 3 + config/groups.conf.php | 3 + config/items.conf.php | 3 + config/property-list.conf.php | 3 + config/test-takers.conf.php | 3 + config/tests.conf.php | 3 + .../Driver/Elasticsearch/ElasticSearch.php | 60 +++++++++++++++++++ .../Elasticsearch/ElasticSearchConfig.php | 6 +- scripts/tools/AliasesUpdater.php | 59 ++++++++++++++++++ scripts/tools/IndexCreator.php | 1 + .../Elasticsearch/ElasticSearchConfigTest.php | 10 ++++ 15 files changed, 201 insertions(+), 3 deletions(-) create mode 100644 config/aliases.conf.php create mode 100644 scripts/tools/AliasesUpdater.php diff --git a/README.md b/README.md index b306353..1af15b3 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ ## Requirements -- ElasticSearch 8+ installed. +- ElasticSearch 8.13+ installed. - Have this extension installed in TAO. ## Installation instructions @@ -51,6 +51,12 @@ you can delete the indexes by running the command bellow: php index.php 'oat\taoAdvancedSearch\scripts\tools\IndexDeleter' ``` +### Create/Update aliases for indexes + +```shell +php index.php 'oat\taoAdvancedSearch\scripts\tools\AliasesUpdater' +``` + ## Indexation ### Warmup cache diff --git a/config/aliases.conf.php b/config/aliases.conf.php new file mode 100644 index 0000000..079963e --- /dev/null +++ b/config/aliases.conf.php @@ -0,0 +1,36 @@ + [ + 'actions' => [ + ['add' => ['index' => 'tests', 'alias' => 'resources_alias']], + ['add' => ['index' => 'items', 'alias' => 'resources_alias']], + ['add' => ['index' => 'deliveries', 'alias' => 'resources_alias']], + ['add' => ['index' => 'test-takers', 'alias' => 'resources_alias']], + ['add' => ['index' => 'groups', 'alias' => 'resources_alias']], + ['add' => ['index' => 'delivery-results', 'alias' => 'resources_alias']], + ['add' => ['index' => 'assets', 'alias' => 'resources_alias']], + ['add' => ['index' => 'property-list', 'alias' => 'resources_alias']], + ] + ] +]; \ No newline at end of file diff --git a/config/assets.conf.php b/config/assets.conf.php index 1bcf8f6..92e39a0 100644 --- a/config/assets.conf.php +++ b/config/assets.conf.php @@ -74,5 +74,8 @@ 'number_of_replicas' => '1', ], ], + 'aliases' => [ + 'assets_alias' => (object)[] + ], ], ]; diff --git a/config/deliveries.conf.php b/config/deliveries.conf.php index 8673c7c..0343ec4 100644 --- a/config/deliveries.conf.php +++ b/config/deliveries.conf.php @@ -72,5 +72,8 @@ 'number_of_replicas' => '1', ], ], + 'aliases' => [ + 'deliveries_alias' => (object)[] + ], ], ]; diff --git a/config/delivery-results.conf.php b/config/delivery-results.conf.php index 82f3fd0..2c96afc 100644 --- a/config/delivery-results.conf.php +++ b/config/delivery-results.conf.php @@ -141,5 +141,8 @@ 'number_of_replicas' => '1', ], ], + 'aliases' => [ + 'delivery-results_alias' => (object)[] + ], ], ]; diff --git a/config/groups.conf.php b/config/groups.conf.php index fe32a59..6df8aff 100644 --- a/config/groups.conf.php +++ b/config/groups.conf.php @@ -70,5 +70,8 @@ 'number_of_replicas' => '1', ], ], + 'aliases' => [ + 'groups_alias' => (object)[] + ], ], ]; diff --git a/config/items.conf.php b/config/items.conf.php index 18b6bec..7d7c61e 100644 --- a/config/items.conf.php +++ b/config/items.conf.php @@ -89,5 +89,8 @@ 'number_of_replicas' => '1', ], ], + 'aliases' => [ + 'items_alias' => (object)[] + ], ], ]; diff --git a/config/property-list.conf.php b/config/property-list.conf.php index eed20ae..204a7cb 100644 --- a/config/property-list.conf.php +++ b/config/property-list.conf.php @@ -29,5 +29,8 @@ 'number_of_replicas' => '1', ], ], + 'aliases' => [ + 'property-list_alias' => (object)[] + ], ], ]; diff --git a/config/test-takers.conf.php b/config/test-takers.conf.php index f9f92de..90c5224 100644 --- a/config/test-takers.conf.php +++ b/config/test-takers.conf.php @@ -78,5 +78,8 @@ 'number_of_replicas' => '1', ], ], + 'aliases' => [ + 'test-takers_alias' => (object)[] + ], ], ]; diff --git a/config/tests.conf.php b/config/tests.conf.php index 801a6bd..e9ed0f1 100644 --- a/config/tests.conf.php +++ b/config/tests.conf.php @@ -85,5 +85,8 @@ 'number_of_replicas' => '1', ], ], + 'aliases' => [ + 'tests_alias' => (object)[] + ], ], ]; diff --git a/model/SearchEngine/Driver/Elasticsearch/ElasticSearch.php b/model/SearchEngine/Driver/Elasticsearch/ElasticSearch.php index b49295c..eb29144 100644 --- a/model/SearchEngine/Driver/Elasticsearch/ElasticSearch.php +++ b/model/SearchEngine/Driver/Elasticsearch/ElasticSearch.php @@ -181,6 +181,49 @@ public function createIndexes(): void } } + public function updateAliases(): void + { + $indexFile = $this->getIndexFile(); + $aliasFile = $this->getAliasesFile(); + + $indexes = []; + + if ($indexFile && is_readable($indexFile)) { + $indexes = require $indexFile; + } + + $aliases = []; + + foreach ($indexes as $index) { + $aliases[$index['index']] = current(array_keys($index['body']['aliases'])); + } + $this->client->indices()->updateAliases( + [ + 'body' => [ + 'actions' => array_map( + function ($index, $alias) { + return [ + 'add' => [ + 'index' => $index, + 'alias' => $alias + ] + ]; + }, + array_keys($aliases), + $aliases + ) + ] + ] + ); + + if ($aliasFile && is_readable($aliasFile)) { + $mainAliases = require $aliasFile; + } + + // Add the main alias for all resources + $this->client->indices()->updateAliases($mainAliases); + } + public function flush(): array { return $this->client->indices()->delete( @@ -241,4 +284,21 @@ private function getIndexFile(): string DIRECTORY_SEPARATOR . 'index.conf.php'; } + + private function getAliasesFile(): string + { + return $this->indexFile ?? __DIR__ . + DIRECTORY_SEPARATOR . + '..' . + DIRECTORY_SEPARATOR . + '..' . + DIRECTORY_SEPARATOR . + '..' . + DIRECTORY_SEPARATOR . + '..' . + DIRECTORY_SEPARATOR . + 'config' . + DIRECTORY_SEPARATOR . + 'aliases.conf.php'; + } } diff --git a/model/SearchEngine/Driver/Elasticsearch/ElasticSearchConfig.php b/model/SearchEngine/Driver/Elasticsearch/ElasticSearchConfig.php index 5a130fd..fcfc326 100644 --- a/model/SearchEngine/Driver/Elasticsearch/ElasticSearchConfig.php +++ b/model/SearchEngine/Driver/Elasticsearch/ElasticSearchConfig.php @@ -33,6 +33,8 @@ class ElasticSearchConfig public const OPTION_ELASTIC_CLOUD_API_KEY_ID = 'elastic_cloud_api_key_id'; public const OPTION_ELASTIC_CLOUD_API_KEY = 'elastic_cloud_api_key'; public const OPTION_HOSTS = 'hosts'; + public const OPTION_USERNAME = 'user'; + public const OPTION_PASSWORD = 'pass'; /** @var ServiceOptionsInterface */ private $serviceOptions; @@ -57,12 +59,12 @@ public function getHosts(): array public function getUsername(): ?string { - return $this->getFirstHost()['user'] ?? null; + return $this->getFirstHost()[self::OPTION_USERNAME] ?? null; } public function getPassword(): ?string { - return $this->getFirstHost()['pass'] ?? null; + return $this->getFirstHost()[self::OPTION_PASSWORD] ?? null; } public function getIndexPrefix(): ?string diff --git a/scripts/tools/AliasesUpdater.php b/scripts/tools/AliasesUpdater.php new file mode 100644 index 0000000..f052fee --- /dev/null +++ b/scripts/tools/AliasesUpdater.php @@ -0,0 +1,59 @@ +getServiceManager()->get(SearchProxy::SERVICE_ID); + + /** @var ElasticSearch|null $elasticService */ + $elasticService = $searchProxy->getAdvancedSearch(); + $elasticService->updateAliases(); + + return Report::createSuccess('Elastic aliases updated successfully'); + } catch (Exception $exception) { + return Report::createError(sprintf('Error while alias creation: %s', $exception->getMessage())); + } + } +} diff --git a/scripts/tools/IndexCreator.php b/scripts/tools/IndexCreator.php index 9742ff6..24d7eb9 100644 --- a/scripts/tools/IndexCreator.php +++ b/scripts/tools/IndexCreator.php @@ -51,6 +51,7 @@ protected function run() /** @var ElasticSearch|null $elasticService */ $elasticService = $searchProxy->getAdvancedSearch(); $elasticService->createIndexes(); + $elasticService->updateAliases(); return Report::createSuccess('Elastic indices created successfully'); } catch (Exception $exception) { diff --git a/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchConfigTest.php b/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchConfigTest.php index 3ca37be..0762f23 100644 --- a/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchConfigTest.php +++ b/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchConfigTest.php @@ -69,6 +69,14 @@ static function (string $class, string $option) { return 'elasticCloudId'; } + if ($option === ElasticSearchConfig::OPTION_USERNAME) { + return 'username'; + } + + if ($option === ElasticSearchConfig::OPTION_PASSWORD) { + return 'password'; + } + return null; } ); @@ -78,5 +86,7 @@ static function (string $class, string $option) { $this->assertSame('elasticCloudApiKeyId', $this->sut->getElasticCloudApiKeyId()); $this->assertSame('elasticCloudApiKey', $this->sut->getElasticCloudApiKey()); $this->assertSame('elasticCloudId', $this->sut->getElasticCloudId()); + $this->assertSame('username', $this->sut->getUsername()); + $this->assertSame('password', $this->sut->getPassword()); } } From faf04086d80810c845c589beb7166571387869d0 Mon Sep 17 00:00:00 2001 From: Aleksej Tikhanovich Date: Tue, 25 Jun 2024 13:05:12 +0200 Subject: [PATCH 06/11] fix: update unit tests --- .../Driver/Elasticsearch/ElasticSearchConfigTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchConfigTest.php b/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchConfigTest.php index 0762f23..ec3a30c 100644 --- a/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchConfigTest.php +++ b/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchConfigTest.php @@ -54,7 +54,7 @@ static function (string $class, string $option) { } if ($option === ElasticSearchConfig::OPTION_HOSTS) { - return ['hosts']; + return [['host' => 'host', 'port' => 'port', 'scheme' => 'scheme', 'user'=> 'username', 'pass' => 'password']]; } if ($option === ElasticSearchConfig::OPTION_ELASTIC_CLOUD_API_KEY_ID) { @@ -82,7 +82,7 @@ static function (string $class, string $option) { ); $this->assertSame('p', $this->sut->getIndexPrefix()); - $this->assertSame(['hosts'], $this->sut->getHosts()); + $this->assertSame(['scheme://host:port'], $this->sut->getHosts()); $this->assertSame('elasticCloudApiKeyId', $this->sut->getElasticCloudApiKeyId()); $this->assertSame('elasticCloudApiKey', $this->sut->getElasticCloudApiKey()); $this->assertSame('elasticCloudId', $this->sut->getElasticCloudId()); From af08bd9293e9b631d718c5d379a82a7f49bc779b Mon Sep 17 00:00:00 2001 From: Aleksej Tikhanovich Date: Tue, 25 Jun 2024 14:37:23 +0200 Subject: [PATCH 07/11] feat: search by aliases --- config/aliases.conf.php | 2 +- model/SearchEngine/Contract/IndexerInterface.php | 16 ++++++++-------- .../Driver/Elasticsearch/QueryBuilderTest.php | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/config/aliases.conf.php b/config/aliases.conf.php index 079963e..db4d494 100644 --- a/config/aliases.conf.php +++ b/config/aliases.conf.php @@ -33,4 +33,4 @@ ['add' => ['index' => 'property-list', 'alias' => 'resources_alias']], ] ] -]; \ No newline at end of file +]; diff --git a/model/SearchEngine/Contract/IndexerInterface.php b/model/SearchEngine/Contract/IndexerInterface.php index 490b45e..fd618e9 100644 --- a/model/SearchEngine/Contract/IndexerInterface.php +++ b/model/SearchEngine/Contract/IndexerInterface.php @@ -29,14 +29,14 @@ interface IndexerInterface { - public const ITEMS_INDEX = 'items'; - public const TESTS_INDEX = 'tests'; - public const TEST_TAKERS_INDEX = 'test-takers'; - public const DELIVERIES_INDEX = 'deliveries'; - public const DELIVERY_RESULTS_INDEX = 'delivery-results'; - public const GROUPS_INDEX = 'groups'; - public const ASSETS_INDEX = 'assets'; - public const PROPERTY_LIST = 'property-list'; + public const ITEMS_INDEX = 'items_alias'; + public const TESTS_INDEX = 'tests_alias'; + public const TEST_TAKERS_INDEX = 'test-takers_alias'; + public const DELIVERIES_INDEX = 'deliveries_alias'; + public const DELIVERY_RESULTS_INDEX = 'delivery-results_alias'; + public const GROUPS_INDEX = 'groups_alias'; + public const ASSETS_INDEX = 'assets_alias'; + public const PROPERTY_LIST = 'property-list_alias'; public const UNCLASSIFIEDS_DOCUMENTS_INDEX = 'unclassifieds'; public const MEDIA_CLASS_URI = 'http://www.tao.lu/Ontologies/TAOMedia.rdf#Media'; diff --git a/tests/Unit/SearchEngine/Driver/Elasticsearch/QueryBuilderTest.php b/tests/Unit/SearchEngine/Driver/Elasticsearch/QueryBuilderTest.php index ad22329..b72de13 100644 --- a/tests/Unit/SearchEngine/Driver/Elasticsearch/QueryBuilderTest.php +++ b/tests/Unit/SearchEngine/Driver/Elasticsearch/QueryBuilderTest.php @@ -91,7 +91,7 @@ public function testGetSearchParamsWithAccessControl(string $queryString, string $this->assertSame( [ - 'index' => 'items', + 'index' => 'items_alias', 'size' => 10, 'from' => 0, 'client' => [ @@ -99,7 +99,7 @@ public function testGetSearchParamsWithAccessControl(string $queryString, string ], 'body' => $body, ], - $this->subject->getSearchParams($queryString, IndexerInterface::ITEMS_INDEX, 0, 10, '_id', 'DESC') + $this->subject->getSearchParams($queryString, 'items', 0, 10, '_id', 'DESC') ); } @@ -170,7 +170,7 @@ public function testGetSearchParamsWithoutAccessControl(string $queryString, str $this->assertSame( [ - 'index' => 'items', + 'index' => 'items_alias', 'size' => 10, 'from' => 0, 'client' => [ @@ -178,7 +178,7 @@ public function testGetSearchParamsWithoutAccessControl(string $queryString, str ], 'body' => $body, ], - $this->subject->getSearchParams($queryString, IndexerInterface::ITEMS_INDEX, 0, 10, '_id', 'DESC') + $this->subject->getSearchParams($queryString, 'items', 0, 10, '_id', 'DESC') ); } From 4f2bcc981dc127ecb7d11124fa0a549bd800b207 Mon Sep 17 00:00:00 2001 From: Aleksej Tikhanovich Date: Fri, 12 Jul 2024 17:08:57 +0200 Subject: [PATCH 08/11] fix: code styles, fix unit tests --- composer.json | 9 +- config/aliases.conf.php | 36 --- .../Driver/Elasticsearch/ElasticSearch.php | 27 +-- .../ElasticSearchClientFactory.php | 2 +- .../Elasticsearch/ElasticSearchConfig.php | 8 +- .../Elasticsearch/ElasticSearchConfigTest.php | 10 +- .../ElasticSearchIndexerTest.php | 12 +- .../Elasticsearch/ElasticSearchTest.php | 94 ++++---- .../Driver/Elasticsearch/IndexUpdaterTest.php | 22 +- .../Driver/Elasticsearch/QueryBuilderTest.php | 224 ++++++++++++++++-- 10 files changed, 295 insertions(+), 149 deletions(-) delete mode 100644 config/aliases.conf.php diff --git a/composer.json b/composer.json index f5dda6f..a951233 100755 --- a/composer.json +++ b/composer.json @@ -27,12 +27,17 @@ "oat-sa/oatbox-extension-installer": "~1.1||dev-master", "ext-json": "*", "oat-sa/generis": ">=15.22", - "oat-sa/tao-core": ">=53.7.1", + "oat-sa/tao-core": "dev-feat/FUN-1740/update-guzzle-client as 99.99.99", + "oat-sa/extension-tao-testqti": "dev-feat/FUN-1740/update-guzzle-client as 99.99.99", "oat-sa/extension-tao-delivery": ">=14.10.1", "oat-sa/extension-tao-outcome": ">=13.0.0", "oat-sa/extension-tao-test": ">=15.15.1", "oat-sa/extension-tao-mediamanager": ">=12.32.1", - "elasticsearch/elasticsearch": "~8.13" + "elasticsearch/elasticsearch": "^7.2|^8.0" + }, + "require-dev": { + "php-http/mock-client": "^1.6", + "dg/bypass-finals": "^1.7" }, "autoload": { "psr-4": { diff --git a/config/aliases.conf.php b/config/aliases.conf.php deleted file mode 100644 index db4d494..0000000 --- a/config/aliases.conf.php +++ /dev/null @@ -1,36 +0,0 @@ - [ - 'actions' => [ - ['add' => ['index' => 'tests', 'alias' => 'resources_alias']], - ['add' => ['index' => 'items', 'alias' => 'resources_alias']], - ['add' => ['index' => 'deliveries', 'alias' => 'resources_alias']], - ['add' => ['index' => 'test-takers', 'alias' => 'resources_alias']], - ['add' => ['index' => 'groups', 'alias' => 'resources_alias']], - ['add' => ['index' => 'delivery-results', 'alias' => 'resources_alias']], - ['add' => ['index' => 'assets', 'alias' => 'resources_alias']], - ['add' => ['index' => 'property-list', 'alias' => 'resources_alias']], - ] - ] -]; diff --git a/model/SearchEngine/Driver/Elasticsearch/ElasticSearch.php b/model/SearchEngine/Driver/Elasticsearch/ElasticSearch.php index eb29144..d38ab11 100644 --- a/model/SearchEngine/Driver/Elasticsearch/ElasticSearch.php +++ b/model/SearchEngine/Driver/Elasticsearch/ElasticSearch.php @@ -184,7 +184,6 @@ public function createIndexes(): void public function updateAliases(): void { $indexFile = $this->getIndexFile(); - $aliasFile = $this->getAliasesFile(); $indexes = []; @@ -215,15 +214,8 @@ function ($index, $alias) { ] ] ); - - if ($aliasFile && is_readable($aliasFile)) { - $mainAliases = require $aliasFile; - } - - // Add the main alias for all resources - $this->client->indices()->updateAliases($mainAliases); } - + public function flush(): array { return $this->client->indices()->delete( @@ -284,21 +276,4 @@ private function getIndexFile(): string DIRECTORY_SEPARATOR . 'index.conf.php'; } - - private function getAliasesFile(): string - { - return $this->indexFile ?? __DIR__ . - DIRECTORY_SEPARATOR . - '..' . - DIRECTORY_SEPARATOR . - '..' . - DIRECTORY_SEPARATOR . - '..' . - DIRECTORY_SEPARATOR . - '..' . - DIRECTORY_SEPARATOR . - 'config' . - DIRECTORY_SEPARATOR . - 'aliases.conf.php'; - } } diff --git a/model/SearchEngine/Driver/Elasticsearch/ElasticSearchClientFactory.php b/model/SearchEngine/Driver/Elasticsearch/ElasticSearchClientFactory.php index be4e3f8..2cd2c65 100644 --- a/model/SearchEngine/Driver/Elasticsearch/ElasticSearchClientFactory.php +++ b/model/SearchEngine/Driver/Elasticsearch/ElasticSearchClientFactory.php @@ -47,7 +47,7 @@ public function create(): Client ->setApiKey($this->config->getElasticCloudApiKeyId(), $this->config->getElasticCloudApiKey()) ->build(); } - + $clientBuilder->setHosts($this->config->getHosts()); if ($this->config->getUsername() && $this->config->getPassword()) { $clientBuilder->setBasicAuthentication($this->config->getUsername(), $this->config->getPassword()); diff --git a/model/SearchEngine/Driver/Elasticsearch/ElasticSearchConfig.php b/model/SearchEngine/Driver/Elasticsearch/ElasticSearchConfig.php index fcfc326..a0398f8 100644 --- a/model/SearchEngine/Driver/Elasticsearch/ElasticSearchConfig.php +++ b/model/SearchEngine/Driver/Elasticsearch/ElasticSearchConfig.php @@ -48,7 +48,7 @@ public function getHosts(): array { $hosts = []; foreach ($this->serviceOptions->get(self::class, self::OPTION_HOSTS) as $host) { - if (is_array($host) && isset($host['host'])){ + if (is_array($host) && isset($host['host'])) { $hosts[] = ($host['scheme'] ?? 'http') . '://' . $host['host'] . ':' . ($host['port'] ?? 9200); } else { $hosts[] = $host; @@ -87,8 +87,8 @@ public function getElasticCloudApiKeyId(): ?string return $this->serviceOptions->get(self::class, self::OPTION_ELASTIC_CLOUD_API_KEY_ID); } - private function getFirstHost(): ?array - { - return current($this->serviceOptions->get(self::class, self::OPTION_HOSTS)) ?: null; + private function getFirstHost(): ?array + { + return current($this->serviceOptions->get(self::class, self::OPTION_HOSTS)) ?: null; } } diff --git a/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchConfigTest.php b/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchConfigTest.php index ec3a30c..7eb0801 100644 --- a/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchConfigTest.php +++ b/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchConfigTest.php @@ -54,7 +54,15 @@ static function (string $class, string $option) { } if ($option === ElasticSearchConfig::OPTION_HOSTS) { - return [['host' => 'host', 'port' => 'port', 'scheme' => 'scheme', 'user'=> 'username', 'pass' => 'password']]; + return [ + [ + 'host' => 'host', + 'port' => 'port', + 'scheme' => 'scheme', + 'user' => 'username', + 'pass' => 'password' + ] + ]; } if ($option === ElasticSearchConfig::OPTION_ELASTIC_CLOUD_API_KEY_ID) { diff --git a/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchIndexerTest.php b/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchIndexerTest.php index 70a6e25..9fa9393 100644 --- a/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchIndexerTest.php +++ b/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchIndexerTest.php @@ -31,6 +31,7 @@ use oat\taoAdvancedSearch\model\SearchEngine\Service\IndexPrefixer; use PHPUnit\Framework\MockObject\MockObject; use ArrayIterator; +use DG\BypassFinals; use PHPUnit\Framework\TestCase; class ElasticSearchIndexerTest extends TestCase @@ -44,8 +45,12 @@ class ElasticSearchIndexerTest extends TestCase /** @var ElasticSearchIndexer $sut */ private $sut; + /** @var IndexPrefixer|MockObject */ + private $prefixer; + protected function setUp(): void { + BypassFinals::enable(); $this->client = $this->createMock(Client::class); $this->logger = $this->createMock(LoggerService::class); $this->prefixer = $this->createMock(IndexPrefixer::class); @@ -111,18 +116,19 @@ public function testBuildIndex(): void $this->logger->expects($this->at(0)) ->method('info') ->with( - '[documentId: "some_id"] Queuing document with types '. - 'http://www.tao.lu/Ontologies/TAOItem.rdf#Item '. + '[documentId: "some_id"] Queuing document with types ' . + 'http://www.tao.lu/Ontologies/TAOItem.rdf#Item ' . sprintf('into index "%s"', IndexerInterface::ITEMS_INDEX) ); $this->logger->expects($this->at(1)) ->method('debug') ->with( - ElasticSearchIndexer::class . '::buildIndex'. + ElasticSearchIndexer::class . '::buildIndex' . ': Flushing batch with 1 operations' ); + /** @var ArrayIterator|MockObject $iterator */ $iterator = $this->createIterator([$document]); $iterator->expects($this->once()) ->method('next'); diff --git a/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchTest.php b/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchTest.php index b63d67b..34186b3 100644 --- a/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchTest.php +++ b/tests/Unit/SearchEngine/Driver/Elasticsearch/ElasticSearchTest.php @@ -22,8 +22,10 @@ namespace oat\taoAdvancedSearch\tests\Unit\SearchEngine\Driver\Elasticsearch; +use DG\BypassFinals; use Elastic\Elasticsearch\Client; use Elastic\Elasticsearch\Endpoints\Indices; +use Elastic\Elasticsearch\Response\Elasticsearch as ResponseElasticsearch; use Exception; use oat\tao\model\search\ResultSet; use oat\tao\model\search\strategy\GenerisSearch; @@ -63,8 +65,13 @@ class ElasticSearchTest extends TestCase /** @var SearchResultNormalizer|MockObject */ private $searchResultNormalizer; + /** @var IndexPrefixer|MockObject */ + private $prefixer; + protected function setUp(): void { + BypassFinals::enable(); + parent::setUp(); $this->generisSearch = $this->createMock(GenerisSearch::class); $this->queryBuilder = $this->createMock(QueryBuilder::class); $this->client = $this->createMock(Client::class); @@ -122,10 +129,13 @@ public function testSearch(): void ) ]; + $responseMock = $this->createMock(ResponseElasticsearch::class); + $responseMock->method('asArray') + ->willReturn([]); $this->client ->method('search') ->with($query) - ->willReturn([]); + ->willReturn($responseMock); $query = (new Query('indexName')) ->setOffset(7) @@ -153,7 +163,7 @@ public function testCountDocuments(): void $this->assertEquals(777, $this->sut->countDocuments('indexName')); } - public function testQuery_callElasticSearchCaseClassIsSupported(): void + public function testQueryCallElasticSearchCaseClassIsSupported(): void { $validType = 'http://www.tao.lu/Ontologies/TAOItem.rdf#Item'; @@ -164,27 +174,29 @@ public function testQuery_callElasticSearchCaseClassIsSupported(): void $documentUri = 'https://tao.docker.localhost/ontologies/tao.rdf#i5ef45f413088c8e7901a84708e84ec'; - $this->client->expects($this->once()) - ->method('search') - ->willReturn( - [ + $responseMock = $this->createMock(ResponseElasticsearch::class); + $responseMock->method('asArray') + ->willReturn([ + 'hits' => [ 'hits' => [ - 'hits' => [ - [ - '_id' => $documentUri, - '_source' => [ - 'attr1' => 'attr1 Value', - 'attr2' => 'attr2 Value', - 'attr3' => 'attr3 Value', - ], - ] - ], - 'total' => [ - 'value' => 1 + [ + '_id' => $documentUri, + '_source' => [ + 'attr1' => 'attr1 Value', + 'attr2' => 'attr2 Value', + 'attr3' => 'attr3 Value', + ], ] + ], + 'total' => [ + 'value' => 1 ] ] - ); + ]); + + $this->client->expects($this->once()) + ->method('search') + ->willReturn($responseMock); $resultSet = $this->sut->query('item', $validType); @@ -193,7 +205,7 @@ public function testQuery_callElasticSearchCaseClassIsSupported(): void $this->assertCount(4, $resultSet->getArrayCopy()[0]); } - public function testQuery_callElasticSearchGenericError(): void + public function testQueryCallElasticSearchGenericError(): void { $this->expectException(SyntaxException::class); $validType = 'http://www.tao.lu/Ontologies/TAOItem.rdf#Item'; @@ -216,7 +228,7 @@ public function testQuery_callElasticSearchGenericError(): void $resultSet = $this->sut->query('item', $validType); } - public function testQuery_callElasticSearch400Error(): void + public function testQueryCallElasticSearch400Error(): void { $this->expectException(SyntaxException::class); $validType = 'http://www.tao.lu/Ontologies/TAOItem.rdf#Item'; @@ -228,7 +240,8 @@ public function testQuery_callElasticSearch400Error(): void $this->logger->expects($this->once()) ->method('error') - ->with('Elasticsearch: There is an error in your search query, system returned: Error {"error":{"reason": "Error"}}'); + ->with('Elasticsearch: There is an error in your search query, system returned: ' . + 'Error {"error":{"reason": "Error"}}'); $documentUri = 'https://tao.docker.localhost/ontologies/tao.rdf#i5ef45f413088c8e7901a84708e84ec'; @@ -239,7 +252,7 @@ public function testQuery_callElasticSearch400Error(): void $resultSet = $this->sut->query('item', $validType); } - public function testCreateIndexes_callIndexCreationBasedOnIndexOption(): void + public function testCreateIndexesCallIndexCreationBasedOnIndexOption(): void { $indexMock = $this->createMock(Indices::class); $indexMock->expects($this->at(0)) @@ -282,31 +295,29 @@ public function testCreateIndexes_callIndexCreationBasedOnIndexOption(): void $this->sut->createIndexes(); } - /** - * @dataProvider pingProvider - */ - public function testPing(bool $clientPing, bool $expected): void + + public function testPingTrue(): void { + $responseMock = $this->createMock(ResponseElasticsearch::class); + $responseMock->method('asBool')->willReturn(true); $this->client ->expects($this->once()) ->method('ping') - ->willReturn($clientPing); + ->willReturn($responseMock); - $this->assertEquals($expected, $this->sut->ping()); + $this->assertEquals(true, $this->sut->ping()); } - public function pingProvider(): array + public function testPingFalse(): void { - return [ - 'True' => [ - 'clientPing' => true, - 'expected' => true, - ], - 'False' => [ - 'clientPing' => false, - 'expected' => false, - ], - ]; + $responseMock = $this->createMock(ResponseElasticsearch::class); + $responseMock->method('asBool')->willReturn(false); + $this->client + ->expects($this->once()) + ->method('ping') + ->willReturn($responseMock); + + $this->assertEquals(false, $this->sut->ping()); } private function mockDebugLogger(): void @@ -319,7 +330,8 @@ private function mockDebugLogger(): void [ 'ignore' => 404, ], - 'body' => '{"query":{"query_string":{"default_operator":"AND","query":"(\\"item\\")"}},"sort":{"_id":{"order":"DESC"}}}', + 'body' => '{"query":{"query_string":{"default_operator":"AND","query":"(\\"item\\")"}},' . + '"sort":{"_id":{"order":"DESC"}}}', ]; $this->queryBuilder->expects($this->once()) diff --git a/tests/Unit/SearchEngine/Driver/Elasticsearch/IndexUpdaterTest.php b/tests/Unit/SearchEngine/Driver/Elasticsearch/IndexUpdaterTest.php index b30fa21..ed99ada 100644 --- a/tests/Unit/SearchEngine/Driver/Elasticsearch/IndexUpdaterTest.php +++ b/tests/Unit/SearchEngine/Driver/Elasticsearch/IndexUpdaterTest.php @@ -22,8 +22,8 @@ namespace oat\taoAdvancedSearch\tests\Unit\SearchEngine\Driver\Elasticsearch; +use DG\BypassFinals; use Elastic\Elasticsearch\Client; -use Elastic\Elasticsearch\Exception\BadMethodCallException; use oat\generis\test\TestCase; use oat\oatbox\log\LoggerService; use oat\tao\model\TaoOntology; @@ -38,7 +38,7 @@ class IndexUpdaterTest extends TestCase /** @var IndexUpdater */ private $sut; - /** @var Client */ + /** @var Client|MockObject */ private $client; /** @var IndexPrefixer|MockObject */ @@ -46,6 +46,7 @@ class IndexUpdaterTest extends TestCase protected function setUp(): void { + BypassFinals::enable(); $this->sut = new IndexUpdater(); $this->client = $this->createMock(Client::class); $this->prefixer = $this->createMock(IndexPrefixer::class); @@ -75,7 +76,7 @@ public function testUpdatePropertiesSuccessfully(array $properties, string $sour ->method('updateByQuery') ->with( [ - 'index' => 'items', + 'index' => 'items_alias', 'type' => '_doc', 'conflicts' => 'proceed', 'wait_for_completion' => true, @@ -102,7 +103,7 @@ public function testExceptionWhenUpdatingProperties(): void $this->client->expects($this->once()) ->method('updateByQuery') - ->willThrowException(new BadMethodCallException()); + ->willThrowException(new \BadMethodCallException()); $this->sut->updatePropertiesName( [ @@ -136,7 +137,7 @@ public function testRemovePropertySuccessfully(array $property, string $source): ->method('updateByQuery') ->with( [ - 'index' => 'items', + 'index' => 'items_alias', 'type' => '_doc', 'conflicts' => 'proceed', 'wait_for_completion' => true, @@ -163,7 +164,7 @@ public function testExceptionWhenRemovingProperty(): void $this->client->expects($this->once()) ->method('updateByQuery') - ->willThrowException(new BadMethodCallException()); + ->willThrowException(new \BadMethodCallException()); $this->sut->deleteProperty( [ @@ -195,7 +196,7 @@ public function testUpdatePropertyValueSuccessfuly() ->method('updateByQuery') ->with( [ - 'index' => 'items', + 'index' => 'items_alias', 'type' => '_doc', 'conflicts' => 'proceed', 'wait_for_completion' => true, @@ -244,7 +245,7 @@ public function testExceptionWhenUpdatingPropertyValue() $this->client->expects($this->once()) ->method('updateByQuery') - ->willThrowException(new BadMethodCallException()); + ->willThrowException(new \BadMethodCallException()); $documentUri = 'https://tao.docker.localhost/ontologies/tao.rdf#i5ef45f413088c8e7901a84708e84ec'; $validType = 'http://www.tao.lu/Ontologies/TAOItem.rdf#Item'; @@ -289,7 +290,10 @@ public function provideValidPropertiesForUpdate(): array 'type' => TaoOntology::CLASS_URI_ITEM ], ], - 'source' => 'ctx._source[\'test\'] = ctx._source[\'devel\']; ctx._source[\'CheckBox_property-6\'] = ctx._source[\'TextArea_devel\']; ctx._source.remove(\'devel\'); ctx._source.remove(\'TextArea_devel\');' + 'source' => "ctx._source['test'] = ctx._source['devel']; " . + "ctx._source['CheckBox_property-6'] = ctx._source['TextArea_devel']; " . + "ctx._source.remove('devel'); " . + "ctx._source.remove('TextArea_devel');" ], ]; } diff --git a/tests/Unit/SearchEngine/Driver/Elasticsearch/QueryBuilderTest.php b/tests/Unit/SearchEngine/Driver/Elasticsearch/QueryBuilderTest.php index b72de13..021e2ce 100644 --- a/tests/Unit/SearchEngine/Driver/Elasticsearch/QueryBuilderTest.php +++ b/tests/Unit/SearchEngine/Driver/Elasticsearch/QueryBuilderTest.php @@ -28,13 +28,13 @@ use oat\oatbox\log\LoggerService; use oat\oatbox\session\SessionService; use oat\oatbox\user\User; -use oat\taoAdvancedSearch\model\SearchEngine\Contract\IndexerInterface; use oat\taoAdvancedSearch\model\SearchEngine\Driver\Elasticsearch\QueryBuilder; use oat\taoAdvancedSearch\model\SearchEngine\Service\IndexPrefixer; use oat\taoAdvancedSearch\model\SearchEngine\Specification\UseAclSpecification; use PHPUnit\Framework\TestCase; -interface PermissionMock extends PermissionInterface, ReverseRightLookupInterface { +interface PermissionMock extends PermissionInterface, ReverseRightLookupInterface +{ } class QueryBuilderTest extends TestCase @@ -54,6 +54,12 @@ class QueryBuilderTest extends TestCase /** @var UseAclSpecification|MockObject */ private $useAclSpecification; + /** @var IndexPrefixer|MockObject */ + private $prefixer; + + /** @var User|MockObject */ + private $user; + protected function setUp(): void { $this->sessionServiceMock = $this->createMock(SessionService::class); @@ -108,55 +114,168 @@ public function queryResultsWithAccessControl(): array return [ 'with user access control and role access control' => [ 'test', - '{"query":{"query_string":{"default_operator":"AND","query":"(\"test\") AND (read_access:(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf#i5f64514f1c36110793759fc28c0105b\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#ItemsManagerRole\"))"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' + '{"query":{"query_string":{"default_operator":"AND","query":' . + '"(\\"test\\") AND (read_access:(\\"https:\\/\\/tao.docker.localhost\\/' . + 'ontologies\\/tao.rdf#i5f64514f1c36110793759fc28c0105b\\" OR' . + ' \\"http:\\/\\/www.tao.lu\\/Ontologies\\/TAOItem.rdf#BackOfficeRole\\" OR ' . + '\\"http:\\/\\/www.tao.lu\\/Ontologies\\/TAOItem.rdf#ItemsManagerRole\\"))"}},' . + '"sort":{"_id":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"},"label.raw":{"order":"DESC","missing":' . + '"_last","unmapped_type":"long"}}}' ], 'Simple query' => [ 'test', - '{"query":{"query_string":{"default_operator":"AND","query":"(\"test\") AND (read_access:(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf#i5f64514f1c36110793759fc28c0105b\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#ItemsManagerRole\"))"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' + '{"query":{"query_string":{"default_operator":"AND","query":"(\\"test\\") AND ' . + '(read_access:(\\"https:\\/\\/tao.docker.localhost\\/' . + 'ontologies\\/tao.rdf#i5f64514f1c36110793759fc28c0105b\\" OR ' . + '\\"http:\\/\\/www.tao.lu\\/Ontologies\\/TAOItem.rdf#BackOfficeRole\\" OR ' . + '\\"http:\\/\\/www.tao.lu\\/Ontologies\\/TAOItem.rdf#ItemsManagerRole\\"))"}},' . + '"sort":{"_id":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"}}}' ], 'Query specific field' => [ 'label:test', - '{"query":{"query_string":{"default_operator":"AND","query":"(label:\"test\") AND (read_access:(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf#i5f64514f1c36110793759fc28c0105b\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#ItemsManagerRole\"))"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' + '{"query":{"query_string":{"default_operator":"AND","query":"(label:\\"test\\") ' . + 'AND (read_access:(\\"https:\\/\\/tao.docker.localhost\\/' . + 'ontologies\\/tao.rdf#i5f64514f1c36110793759fc28c0105b\\" OR ' . + '\\"http:\\/\\/www.tao.lu\\/Ontologies\\/TAOItem.rdf#BackOfficeRole\\" OR ' . + '\\"http:\\/\\/www.tao.lu\\/Ontologies\\/TAOItem.rdf#ItemsManagerRole\\"))"}},' . + '"sort":{"_id":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' ], 'Query specific field (variating case)' => [ 'LaBeL:test', - '{"query":{"query_string":{"default_operator":"AND","query":"(label:\"test\") AND (read_access:(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf#i5f64514f1c36110793759fc28c0105b\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#ItemsManagerRole\"))"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' + '{"query":{"query_string":{"default_operator":"AND","query":"(label:\\"test\\") ' . + 'AND (read_access:(\\"https:\\/\\/tao.docker.localhost\\/' . + 'ontologies\\/tao.rdf#i5f64514f1c36110793759fc28c0105b\\" OR ' . + '\\"http:\\/\\/www.tao.lu\\/Ontologies\\/TAOItem.rdf#BackOfficeRole\\" OR ' . + '\\"http:\\/\\/www.tao.lu\\/Ontologies\\/TAOItem.rdf#ItemsManagerRole\\"))"}},' . + '"sort":{"_id":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' ], 'Query custom field (using underscore)' => [ 'custom_field:test', - 'body' => '{"query":{"query_string":{"default_operator":"AND","query":"(HTMLArea_custom_field:\"test\" OR TextArea_custom_field:\"test\" OR TextBox_custom_field:\"test\" OR ComboBox_custom_field:\"test\" OR CheckBox_custom_field:\"test\" OR RadioBox_custom_field:\"test\" OR SearchTextBox_custom_field:\"test\" OR SearchDropdown_custom_field:\"test\") AND (read_access:(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf#i5f64514f1c36110793759fc28c0105b\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#ItemsManagerRole\"))"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}', + '{"query":{"query_string":{"default_operator":"AND","query":"(HTMLArea_custom_field:' . + '\\"test\\" OR TextArea_custom_field:\\"test\\" OR ' . + 'TextBox_custom_field:\\"test\\" OR ComboBox_custom_field:\\"test\\" ' . + 'OR CheckBox_custom_field:\\"test\\" OR RadioBox_custom_field:\\"test\\" ' . + 'OR SearchTextBox_custom_field:\\"test\\" OR SearchDropdown_custom_field:\\"test\\")' . + ' AND (read_access:(\\"https:\\/\\/tao.docker.localhost\\/' . + 'ontologies\\/tao.rdf#i5f64514f1c36110793759fc28c0105b\\" OR \\"http:\\/\\/www.tao.lu\\/Ontologies\\/' . + 'TAOItem.rdf#BackOfficeRole\\" OR ' . + '\\"http:\\/\\/www.tao.lu\\/Ontologies\\/TAOItem.rdf#ItemsManagerRole\\"))"}},' . + '"sort":{"_id":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' ], 'Query custom field (using dash)' => [ 'custom_field:test', - 'body' => '{"query":{"query_string":{"default_operator":"AND","query":"(HTMLArea_custom_field:\"test\" OR TextArea_custom_field:\"test\" OR TextBox_custom_field:\"test\" OR ComboBox_custom_field:\"test\" OR CheckBox_custom_field:\"test\" OR RadioBox_custom_field:\"test\" OR SearchTextBox_custom_field:\"test\" OR SearchDropdown_custom_field:\"test\") AND (read_access:(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf#i5f64514f1c36110793759fc28c0105b\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#ItemsManagerRole\"))"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}', + '{"query":{"query_string":{"default_operator":"AND","query":"' . + '(HTMLArea_custom_field:\\"test\\" OR TextArea_custom_field:\\"test\\" OR ' . + 'TextBox_custom_field:\\"test\\" OR ComboBox_custom_field:\\"test\\"' . + ' OR CheckBox_custom_field:\\"test\\" OR RadioBox_custom_field:\\"test\\" ' . + 'OR SearchTextBox_custom_field:\\"test\\" OR SearchDropdown_custom_field:\\' . + '"test\\") AND (read_access:(\\"https:\\/\\/tao.docker.localhost\\/' . + 'ontologies\\/tao.rdf#i5f64514f1c36110793759fc28c0105b\\" OR ' . + '\\"http:\\/\\/www.tao.lu\\/Ontologies\\/TAOItem.rdf#BackOfficeRole\\" OR ' . + '\\"http:\\/\\/www.tao.lu\\/Ontologies\\/TAOItem.rdf#ItemsManagerRole\\"))"}},' . + '"sort":{"_id":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"}}}' ], 'Query custom field (using space)' => [ 'custom field:test', - 'body' => '{"query":{"query_string":{"default_operator":"AND","query":"(HTMLArea_custom field:\"test\" OR TextArea_custom field:\"test\" OR TextBox_custom field:\"test\" OR ComboBox_custom field:\"test\" OR CheckBox_custom field:\"test\" OR RadioBox_custom field:\"test\" OR SearchTextBox_custom field:\"test\" OR SearchDropdown_custom field:\"test\") AND (read_access:(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf#i5f64514f1c36110793759fc28c0105b\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#ItemsManagerRole\"))"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}', + 'body' => '{"query":{"query_string":{"default_operator":"AND",' . + '"query":"(HTMLArea_custom field:\"test\" ' . + 'OR TextArea_custom field:\"test\" OR TextBox_custom ' . + 'field:\"test\" OR ComboBox_custom field:\"test\" ' . + 'OR CheckBox_custom field:\"test\" OR RadioBox_custom ' . + 'field:\"test\" OR SearchTextBox_custom field:\"test\" ' . + 'OR SearchDropdown_custom field:\"test\") AND ' . + '(read_access:(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf' . + '#i5f64514f1c36110793759fc28c0105b\" OR ' . + '\"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" ' . + 'OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#ItemsManagerRole\"))"}},' . + '"sort":{"_id":{"order":"DESC",' . + '"missing":"_last","unmapped_type":"long"},"label.raw":' . + '{"order":"DESC","missing":"_last","unmapped_type":"long"}}}', ], 'Query logic operator (Uppercase)' => [ 'label:test AND custom_field:test', - '{"query":{"query_string":{"default_operator":"AND","query":"(label:\"test\") AND (HTMLArea_custom_field:\"test\" OR TextArea_custom_field:\"test\" OR TextBox_custom_field:\"test\" OR ComboBox_custom_field:\"test\" OR CheckBox_custom_field:\"test\" OR RadioBox_custom_field:\"test\" OR SearchTextBox_custom_field:\"test\" OR SearchDropdown_custom_field:\"test\") AND (read_access:(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf#i5f64514f1c36110793759fc28c0105b\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#ItemsManagerRole\"))"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}', + '{"query":{"query_string":{"default_operator":"AND","query":' . + '"(label:\\"test\\") AND (HTMLArea_custom_field:\\"test\\" OR TextArea_custom_' . + 'field:\\"test\\" OR TextBox_custom_field:\\"test\\" OR ' . + 'ComboBox_custom_field:\\"test\\" OR CheckBox_custom_field:\\"test\\" OR RadioBox_' . + 'custom_field:\\"test\\" OR SearchTextBox_custom_field:\\"test\\" ' . + 'OR SearchDropdown_custom_field:\\"test\\") AND (read_access:(\\"https:\\/' . + '\\/tao.docker.localhost\\/ontologies\\/tao.rdf#i5f64514f1c36110793759fc28c0105b\\"' . + ' OR \\"http:\\/\\/www.tao.lu\\/Ontologies\\/TAOItem.rdf#' . + 'BackOfficeRole\\" OR \\"http:\\/\\/www.tao.lu\\/Ontologies\\/TAOItem.rdf#ItemsManagerRole\\"))"}}' . + ',"sort":{"_id":{"order":"DESC",' . + '"missing":"_last","unmapped_type":"long"},"label.raw":' . + '{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' ], 'Query logic operator (Lowercase)' => [ 'label:test and custom_field:test', - '{"query":{"query_string":{"default_operator":"AND","query":"(label:\"test\") AND (HTMLArea_custom_field:\"test\" OR TextArea_custom_field:\"test\" OR TextBox_custom_field:\"test\" OR ComboBox_custom_field:\"test\" OR CheckBox_custom_field:\"test\" OR RadioBox_custom_field:\"test\" OR SearchTextBox_custom_field:\"test\" OR SearchDropdown_custom_field:\"test\") AND (read_access:(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf#i5f64514f1c36110793759fc28c0105b\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#ItemsManagerRole\"))"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}', + '{"query":{"query_string":{"default_operator":"AND","query":"(label:\"test\") AND ' . + '(HTMLArea_custom_field:\"test\" OR TextArea_custom_field:\"test\" OR TextBox_custom_field:\"test\" ' . + 'OR ComboBox_custom_field:\"test\" OR CheckBox_custom_field:\"test\" ' . + 'OR RadioBox_custom_field:\"test\" ' . + 'OR SearchTextBox_custom_field:\"test\" OR SearchDropdown_custom_field:\"test\") AND (read_access:' . + '(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf#i5f64514f1c36110793759fc28c0105b\" OR ' . + '\"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" OR ' . + '\"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#ItemsManagerRole\"))"}},' . + '"sort":{"_id":{"order":"DESC",' . + '"missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"}}}' ], 'Query logic operator (Mixed)' => [ 'label:test aNd custom_field:test', - '{"query":{"query_string":{"default_operator":"AND","query":"(label:\"test\") AND (HTMLArea_custom_field:\"test\" OR TextArea_custom_field:\"test\" OR TextBox_custom_field:\"test\" OR ComboBox_custom_field:\"test\" OR CheckBox_custom_field:\"test\" OR RadioBox_custom_field:\"test\" OR SearchTextBox_custom_field:\"test\" OR SearchDropdown_custom_field:\"test\") AND (read_access:(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf#i5f64514f1c36110793759fc28c0105b\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#ItemsManagerRole\"))"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}', + '{"query":{"query_string":{"default_operator":"AND","query":"(label:\"test\") AND ' . + '(HTMLArea_custom_field:\"test\" OR TextArea_custom_field:\"test\" OR TextBox_custom_field:\"test\" ' . + 'OR ComboBox_custom_field:\"test\" OR CheckBox_custom_field:\"test\"' . + ' OR RadioBox_custom_field:\"test\" ' . + 'OR SearchTextBox_custom_field:\"test\" OR SearchDropdown_custom_field:\"test\") AND (read_access:' . + '(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf#i5f64514f1c36110793759fc28c0105b\" OR ' . + '\"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" OR ' . + '\"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#ItemsManagerRole\"))"}},' . + '"sort":{"_id":{"order":"DESC",' . + '"missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"}}}' ], 'Query URIs' => [ 'https://test-act.docker.localhost/ontologies/tao.rdf#i5f200ed20e80a8c259ebe410db7f6a', - '{"query":{"query_string":{"default_operator":"AND","query":"(\"https:\/\/test-act.docker.localhost\/ontologies\/tao.rdf#i5f200ed20e80a8c259ebe410db7f6a\") AND (read_access:(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf#i5f64514f1c36110793759fc28c0105b\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#ItemsManagerRole\"))"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' + '{"query":{"query_string":{"default_operator":"AND","query":"(\"https:\/\/test-act.docker.localhost\/' . + 'ontologies\/tao.rdf#i5f200ed20e80a8c259ebe410db7f6a\") AND (read_access:' . + '(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf#i5f64514f1c36110793759fc28c0105b\" OR ' . + '\"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" OR ' . + '\"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#' . + 'ItemsManagerRole\"))"}},"sort":{"_id":{"order":"DESC",' . + '"missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"}}}' ], 'Query Field with URI' => [ 'delivery: https://test-act.docker.localhost/ontologies/tao.rdf#i5f200ed20e80a8c259ebe410db7f6a', - '{"query":{"query_string":{"default_operator":"AND","query":"(delivery:\"https:\/\/test-act.docker.localhost\/ontologies\/tao.rdf#i5f200ed20e80a8c259ebe410db7f6a\") AND (read_access:(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf#i5f64514f1c36110793759fc28c0105b\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#ItemsManagerRole\"))"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' + '{"query":{"query_string":{"default_operator":"AND","query"' . + ':"(delivery:\"https:\/\/test-act.docker.localhost\/' . + 'ontologies\/tao.rdf#i5f200ed20e80a8c259ebe410db7f6a\") AND (read_access:' . + '(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf#i5f64514f1c36110793759fc28c0105b\" OR ' . + '\"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" OR ' . + '\"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#' . + 'ItemsManagerRole\"))"}},"sort":{"_id":{"order":"DESC",' . + '"missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"}}}' ], 'Query term with a backslash' => [ 'some\ term', - '{"query":{"query_string":{"default_operator":"AND","query":"(\"some\\\\\\\\ term\") AND (read_access:(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf#i5f64514f1c36110793759fc28c0105b\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" OR \"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#ItemsManagerRole\"))"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' + '{"query":{"query_string":{"default_operator":"AND","query":' . + '"(\"some\\\\\\\\ term\") AND (read_access:' . + '(\"https:\/\/tao.docker.localhost\/ontologies\/tao.rdf#i5f64514f1c36110793759fc28c0105b\" OR ' . + '\"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#BackOfficeRole\" OR ' . + '\"http:\/\/www.tao.lu\/Ontologies\/TAOItem.rdf#ItemsManagerRole\"))"}},' . + '"sort":{"_id":{"order":"DESC",' . + '"missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"}}}' ], ]; } @@ -187,47 +306,100 @@ public function queryResultsWithoutAccessControl(): array return [ 'Simple query' => [ 'test', - '{"query":{"query_string":{"default_operator":"AND","query":"(\"test\")"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' + '{"query":{"query_string":{"default_operator":"AND","query":"(\"test\")"}},' . + '"sort":{"_id":{"order":"DESC",' . + '"missing":"_last","unmapped_type":"long"},"label.raw":' . + '{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"}}}' ], 'Query specific field' => [ 'label:test', - '{"query":{"query_string":{"default_operator":"AND","query":"(label:\"test\")"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' + '{"query":{"query_string":{"default_operator":"AND","query":' . + '"(label:\"test\")"}},"sort":{"_id":{"order":"DESC",' . + '"missing":"_last","unmapped_type":"long"},"label.raw":' . + '{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"}}}' ], 'Query specific field (variating case)' => [ 'LaBeL:test', - '{"query":{"query_string":{"default_operator":"AND","query":"(label:\"test\")"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' + '{"query":{"query_string":{"default_operator":"AND","query"' . + ':"(label:\"test\")"}},"sort":{"_id":{"order":"DESC",' . + '"missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"}}}' ], 'Query custom field (using underscore)' => [ 'custom_field:test', - 'body' => '{"query":{"query_string":{"default_operator":"AND","query":"(HTMLArea_custom_field:\"test\" OR TextArea_custom_field:\"test\" OR TextBox_custom_field:\"test\" OR ComboBox_custom_field:\"test\" OR CheckBox_custom_field:\"test\" OR RadioBox_custom_field:\"test\" OR SearchTextBox_custom_field:\"test\" OR SearchDropdown_custom_field:\"test\")"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}', + '{"query":{"query_string":{"default_operator":"AND",' . + '"query":"(HTMLArea_custom_field:\"test\" OR ' . + 'TextArea_custom_field:\"test\" OR TextBox_custom_field' . + ':\"test\" OR ComboBox_custom_field:\"test\" ' . + 'OR CheckBox_custom_field:\"test\" OR RadioBox_custom_field:' . + '\"test\" OR SearchTextBox_custom_field:\"test\" ' . + 'OR SearchDropdown_custom_field:\"test\")"}},' . + '"sort":{"_id":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"},"label.raw":{"order":' . + '"DESC","missing":"_last","unmapped_type":"long"}}}' ], 'Query custom field (using dash)' => [ 'custom_field:test', - 'body' => '{"query":{"query_string":{"default_operator":"AND","query":"(HTMLArea_custom_field:\"test\" OR TextArea_custom_field:\"test\" OR TextBox_custom_field:\"test\" OR ComboBox_custom_field:\"test\" OR CheckBox_custom_field:\"test\" OR RadioBox_custom_field:\"test\" OR SearchTextBox_custom_field:\"test\" OR SearchDropdown_custom_field:\"test\")"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}', + '{"query":{"query_string":{"default_operator":"AND","query":"(HTMLArea_custom_field:\"test\" OR ' . + 'TextArea_custom_field:\"test\" OR TextBox_custom_field:\"test\" OR ComboBox_custom_field:\"test\" ' . + 'OR CheckBox_custom_field:\"test\" OR RadioBox_custom_field:' . + '\"test\" OR SearchTextBox_custom_field:\"test\" ' . + 'OR SearchDropdown_custom_field:\"test\")"}},"sort":{"_id":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' ], 'Query custom field (using space)' => [ 'custom field:test', - 'body' => '{"query":{"query_string":{"default_operator":"AND","query":"(HTMLArea_custom field:\"test\" OR TextArea_custom field:\"test\" OR TextBox_custom field:\"test\" OR ComboBox_custom field:\"test\" OR CheckBox_custom field:\"test\" OR RadioBox_custom field:\"test\" OR SearchTextBox_custom field:\"test\" OR SearchDropdown_custom field:\"test\")"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}', + 'body' => '{"query":{"query_string":{"default_operator":"AND","query":"(HTMLArea_custom ' . + 'field:\"test\" OR TextArea_custom field:\"test\" OR TextBox_custom field:\"test\" ' . + 'OR ComboBox_custom field:\"test\" OR CheckBox_custom field:\"test\" OR RadioBox_custom ' . + 'field:\"test\" OR SearchTextBox_custom field:\"test\" OR SearchDropdown_custom field:' . + '\"test\")"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},' . + '"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}', ], 'Query logic operator (Uppercase)' => [ 'label:test AND custom_field:test', - '{"query":{"query_string":{"default_operator":"AND","query":"(label:\"test\") AND (HTMLArea_custom_field:\"test\" OR TextArea_custom_field:\"test\" OR TextBox_custom_field:\"test\" OR ComboBox_custom_field:\"test\" OR CheckBox_custom_field:\"test\" OR RadioBox_custom_field:\"test\" OR SearchTextBox_custom_field:\"test\" OR SearchDropdown_custom_field:\"test\")"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}', + '{"query":{"query_string":{"default_operator":"AND","query":"(label:\"test\") ' . + 'AND (HTMLArea_custom_field:\"test\" OR TextArea_custom_field:\"test\" OR ' . + 'TextBox_custom_field:\"test\" OR ComboBox_custom_field:\"test\" OR CheckBox_custom_field:' . + '\"test\" OR RadioBox_custom_field:\"test\" OR SearchTextBox_custom_field:\"test\" OR ' . + 'SearchDropdown_custom_field:\"test\")"}},"sort":{"_id":{"order":"DESC","missing":"_last"' . + ',"unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}', ], 'Query logic operator (Lowercase)' => [ 'label:test and custom_field:test', - '{"query":{"query_string":{"default_operator":"AND","query":"(label:\"test\") AND (HTMLArea_custom_field:\"test\" OR TextArea_custom_field:\"test\" OR TextBox_custom_field:\"test\" OR ComboBox_custom_field:\"test\" OR CheckBox_custom_field:\"test\" OR RadioBox_custom_field:\"test\" OR SearchTextBox_custom_field:\"test\" OR SearchDropdown_custom_field:\"test\")"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}', + '{"query":{"query_string":{"default_operator":"AND","query":"(label:\"test\") AND ' . + '(HTMLArea_custom_field:\"test\" OR TextArea_custom_field:\"test\" OR TextBox_custom_field:' . + '\"test\" OR ComboBox_custom_field:\"test\" OR CheckBox_custom_field:\"test\" OR ' . + 'RadioBox_custom_field:\"test\" OR SearchTextBox_custom_field:\"test\" OR ' . + 'SearchDropdown_custom_field:\"test\")"}},"sort":{"_id":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}', ], 'Query logic operator (Mixed)' => [ 'label:test aNd custom_field:test', - '{"query":{"query_string":{"default_operator":"AND","query":"(label:\"test\") AND (HTMLArea_custom_field:\"test\" OR TextArea_custom_field:\"test\" OR TextBox_custom_field:\"test\" OR ComboBox_custom_field:\"test\" OR CheckBox_custom_field:\"test\" OR RadioBox_custom_field:\"test\" OR SearchTextBox_custom_field:\"test\" OR SearchDropdown_custom_field:\"test\")"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}', + '{"query":{"query_string":{"default_operator":"AND","query":"(label:\"test\") AND ' . + '(HTMLArea_custom_field:\"test\" OR TextArea_custom_field:\"test\" OR TextBox_custom_field:\"test\" ' . + 'OR ComboBox_custom_field:\"test\" OR CheckBox_custom_field:\"test\"' . + ' OR RadioBox_custom_field:\"test\" ' . + 'OR SearchTextBox_custom_field:\"test\" OR SearchDropdown_custom_field:\"test\")"}},"sort":{"_id":' . + '{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing"' . + ':"_last","unmapped_type":"long"}}}', ], 'Query URIs' => [ 'https://test-act.docker.localhost/ontologies/tao.rdf#i5f200ed20e80a8c259ebe410db7f6a', - '{"query":{"query_string":{"default_operator":"AND","query":"(\"https:\/\/test-act.docker.localhost\/ontologies\/tao.rdf#i5f200ed20e80a8c259ebe410db7f6a\")"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' + '{"query":{"query_string":{"default_operator":"AND","query":"(\"https:\/\/test-act.docker.localhost' . + '\/ontologies\/tao.rdf#i5f200ed20e80a8c259ebe410db7f6a\")"}},' . + '"sort":{"_id":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' ], 'Query Field with URI' => [ 'delivery: https://test-act.docker.localhost/ontologies/tao.rdf#i5f200ed20e80a8c259ebe410db7f6a', - '{"query":{"query_string":{"default_operator":"AND","query":"(delivery:\"https:\/\/test-act.docker.localhost\/ontologies\/tao.rdf#i5f200ed20e80a8c259ebe410db7f6a\")"}},"sort":{"_id":{"order":"DESC","missing":"_last","unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' + '{"query":{"query_string":{"default_operator":"AND","query":' . + '"(delivery:\"https:\/\/test-act.docker.localhost' . + '\/ontologies\/tao.rdf#i5f200ed20e80a8c259ebe410db7f6a\")"}},' . + '"sort":{"_id":{"order":"DESC","missing":"_last",' . + '"unmapped_type":"long"},"label.raw":{"order":"DESC","missing":"_last","unmapped_type":"long"}}}' ], ]; } From 27c5e868445958216c5155898c1f9f32c46132c3 Mon Sep 17 00:00:00 2001 From: Aleksej Tikhanovich Date: Wed, 7 Aug 2024 09:42:08 +0200 Subject: [PATCH 09/11] fix: indexing properties and resources --- model/SearchEngine/Contract/IndexerInterface.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/model/SearchEngine/Contract/IndexerInterface.php b/model/SearchEngine/Contract/IndexerInterface.php index fd618e9..490b45e 100644 --- a/model/SearchEngine/Contract/IndexerInterface.php +++ b/model/SearchEngine/Contract/IndexerInterface.php @@ -29,14 +29,14 @@ interface IndexerInterface { - public const ITEMS_INDEX = 'items_alias'; - public const TESTS_INDEX = 'tests_alias'; - public const TEST_TAKERS_INDEX = 'test-takers_alias'; - public const DELIVERIES_INDEX = 'deliveries_alias'; - public const DELIVERY_RESULTS_INDEX = 'delivery-results_alias'; - public const GROUPS_INDEX = 'groups_alias'; - public const ASSETS_INDEX = 'assets_alias'; - public const PROPERTY_LIST = 'property-list_alias'; + public const ITEMS_INDEX = 'items'; + public const TESTS_INDEX = 'tests'; + public const TEST_TAKERS_INDEX = 'test-takers'; + public const DELIVERIES_INDEX = 'deliveries'; + public const DELIVERY_RESULTS_INDEX = 'delivery-results'; + public const GROUPS_INDEX = 'groups'; + public const ASSETS_INDEX = 'assets'; + public const PROPERTY_LIST = 'property-list'; public const UNCLASSIFIEDS_DOCUMENTS_INDEX = 'unclassifieds'; public const MEDIA_CLASS_URI = 'http://www.tao.lu/Ontologies/TAOMedia.rdf#Media'; From 134688ed3da54e1dbdd17f28c342306052eb4505 Mon Sep 17 00:00:00 2001 From: Aleksej Tikhanovich Date: Wed, 7 Aug 2024 09:44:53 +0200 Subject: [PATCH 10/11] fix: unit tests --- .../SearchEngine/Driver/Elasticsearch/IndexUpdaterTest.php | 6 +++--- .../SearchEngine/Driver/Elasticsearch/QueryBuilderTest.php | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/Unit/SearchEngine/Driver/Elasticsearch/IndexUpdaterTest.php b/tests/Unit/SearchEngine/Driver/Elasticsearch/IndexUpdaterTest.php index ed99ada..3f98b2e 100644 --- a/tests/Unit/SearchEngine/Driver/Elasticsearch/IndexUpdaterTest.php +++ b/tests/Unit/SearchEngine/Driver/Elasticsearch/IndexUpdaterTest.php @@ -76,7 +76,7 @@ public function testUpdatePropertiesSuccessfully(array $properties, string $sour ->method('updateByQuery') ->with( [ - 'index' => 'items_alias', + 'index' => 'items', 'type' => '_doc', 'conflicts' => 'proceed', 'wait_for_completion' => true, @@ -137,7 +137,7 @@ public function testRemovePropertySuccessfully(array $property, string $source): ->method('updateByQuery') ->with( [ - 'index' => 'items_alias', + 'index' => 'items', 'type' => '_doc', 'conflicts' => 'proceed', 'wait_for_completion' => true, @@ -196,7 +196,7 @@ public function testUpdatePropertyValueSuccessfuly() ->method('updateByQuery') ->with( [ - 'index' => 'items_alias', + 'index' => 'items', 'type' => '_doc', 'conflicts' => 'proceed', 'wait_for_completion' => true, diff --git a/tests/Unit/SearchEngine/Driver/Elasticsearch/QueryBuilderTest.php b/tests/Unit/SearchEngine/Driver/Elasticsearch/QueryBuilderTest.php index 021e2ce..d04ea5b 100644 --- a/tests/Unit/SearchEngine/Driver/Elasticsearch/QueryBuilderTest.php +++ b/tests/Unit/SearchEngine/Driver/Elasticsearch/QueryBuilderTest.php @@ -97,7 +97,7 @@ public function testGetSearchParamsWithAccessControl(string $queryString, string $this->assertSame( [ - 'index' => 'items_alias', + 'index' => 'items', 'size' => 10, 'from' => 0, 'client' => [ @@ -289,7 +289,7 @@ public function testGetSearchParamsWithoutAccessControl(string $queryString, str $this->assertSame( [ - 'index' => 'items_alias', + 'index' => 'items', 'size' => 10, 'from' => 0, 'client' => [ From 0855077d25926ccaf88121383ce65c0dfce780f6 Mon Sep 17 00:00:00 2001 From: Aleksej Tikhanovich Date: Thu, 8 Aug 2024 12:35:47 +0200 Subject: [PATCH 11/11] feat: update tao-core and test-qti with the proper versions Signed-off-by: Aleksej Tikhanovich --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index a951233..4a0dbee 100755 --- a/composer.json +++ b/composer.json @@ -27,8 +27,8 @@ "oat-sa/oatbox-extension-installer": "~1.1||dev-master", "ext-json": "*", "oat-sa/generis": ">=15.22", - "oat-sa/tao-core": "dev-feat/FUN-1740/update-guzzle-client as 99.99.99", - "oat-sa/extension-tao-testqti": "dev-feat/FUN-1740/update-guzzle-client as 99.99.99", + "oat-sa/tao-core": ">=54.21.0", + "oat-sa/extension-tao-testqti": ">=48.11.0", "oat-sa/extension-tao-delivery": ">=14.10.1", "oat-sa/extension-tao-outcome": ">=13.0.0", "oat-sa/extension-tao-test": ">=15.15.1",