magento2-docker/dev/tests/integration/testsuite/Magento/Elasticsearch/Model/Adapter/ElasticsearchTest.php

257 lines
8.3 KiB
PHP
Executable File

<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Elasticsearch\Model\Adapter;
use Magento\AdvancedSearch\Model\Client\ClientInterface;
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
use Magento\Catalog\Setup\CategorySetup;
use Magento\CatalogSearch\Model\Indexer\IndexerHandlerFactory;
use Magento\Eav\Model\Entity\Attribute\Backend\ArrayBackend;
use Magento\Elasticsearch\Model\Adapter\Index\BuilderInterface;
use Magento\Elasticsearch\Model\Adapter\Index\IndexNameResolver;
use Magento\Elasticsearch\Model\Indexer\IndexerHandler;
use Magento\Elasticsearch\SearchAdapter\ConnectionManager;
use Magento\Framework\Indexer\DimensionFactory;
use Magento\Framework\ObjectManagerInterface;
use Magento\Framework\Stdlib\ArrayManager;
use Magento\Indexer\Model\Indexer;
use Magento\Store\Model\StoreDimensionProvider;
use Magento\Store\Model\StoreManagerInterface;
use Magento\TestFramework\Helper\Bootstrap;
use PHPUnit\Framework\TestCase;
/**
* Elasticsearch adapter model test class
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class ElasticsearchTest extends TestCase
{
/**
* @var ObjectManagerInterface
*/
private $objectManager;
/**
* @var IndexNameResolver
*/
private $indexNameResolver;
/**
* @var ClientInterface
*/
private $client;
/**
* @var StoreManagerInterface
*/
private $storeManager;
/**
* @var Elasticsearch
*/
private $adapter;
/**
* @var BuilderInterface
*/
private $indexBuilder;
/**
* @var ArrayManager
*/
private $arrayManager;
/**
* @var string
*/
private $newIndex;
/**
* @inheritdoc
*/
protected function setUp(): void
{
$this->objectManager = Bootstrap::getObjectManager();
$this->indexNameResolver = $this->objectManager->get(IndexNameResolver::class);
$this->adapter = $this->objectManager->get(Elasticsearch::class);
$this->storeManager = $this->objectManager->create(StoreManagerInterface::class);
$connectionManager = $this->objectManager->create(ConnectionManager::class);
$this->client = $connectionManager->getConnection();
$this->indexBuilder = $this->objectManager->get(BuilderInterface::class);
$this->arrayManager = $this->objectManager->get(ArrayManager::class);
}
/**
* @inheritdoc
*/
public function tearDown(): void
{
if ($this->newIndex) {
$this->deleteIndex($this->newIndex);
}
}
/**
* Tests possibility to create mapping if adapter has obsolete index name in cache
*
* @magentoDataFixture Magento/Elasticsearch/_files/select_attribute.php
* @return void
*/
public function testRetryOnIndexNotFoundException(): void
{
$this->reindex();
$this->updateElasticsearchIndex();
$this->createNewAttribute();
$mapping = $this->client->getMapping(['index' => $this->newIndex]);
$pathField = $this->arrayManager->findPath('properties', $mapping);
$attributes = $this->arrayManager->get($pathField, $mapping, []);
$this->assertArrayHasKey('multiselect_attribute', $attributes);
}
/**
* Test that new fields are not added during document indexing that were not explicitly defined in the mapping
*
* @magentoDataFixture Magento/Catalog/_files/product_simple.php
* @magentoDataFixture Magento/Store/_files/second_store.php
* @magentoDbIsolation disabled
*/
public function testMappingShouldNotChangeAfterReindex(): void
{
$index = 'catalogsearch_fulltext';
$storeId = (int) $this->storeManager->getStore('fixture_second_store')->getId();
// Create empty index and save the initial mapping
$dimensionFactory = $this->objectManager->get(DimensionFactory::class);
$dimensions = [
StoreDimensionProvider::DIMENSION_NAME => $dimensionFactory->create(
StoreDimensionProvider::DIMENSION_NAME,
(string) $storeId
)
];
$indexHandlerFactory = $this->objectManager->get(IndexerHandlerFactory::class);
/** @var IndexerHandler $indexHandler */
$indexHandler = $indexHandlerFactory->create(
[
'data' => [
'indexer_id' => $index
]
]
);
$indexHandler->cleanIndex($dimensions);
$indexHandler->saveIndex($dimensions, new \ArrayIterator([]));
$propertiesBefore = $this->getIndexMapping($storeId);
$this->reindex();
$propertiesAfter = $this->getIndexMapping($storeId);
$this->assertEquals($propertiesBefore, $propertiesAfter);
}
/**
* Prepare and save new attribute
*
* @return void
*/
public function createNewAttribute(): void
{
/** @var CategorySetup $installer */
$installer = $this->objectManager->get(CategorySetup::class);
/** @var Attribute $attribute */
$multiselectAttribute = $this->objectManager->get(Attribute::class);
$multiselectAttribute->setData(
[
'attribute_code' => 'multiselect_attribute',
'entity_type_id' => $installer->getEntityTypeId('catalog_product'),
'is_global' => 1,
'is_user_defined' => 1,
'frontend_input' => 'multiselect',
'is_unique' => 0,
'is_required' => 0,
'is_searchable' => 1,
'is_visible_in_advanced_search' => 0,
'is_comparable' => 0,
'is_filterable' => 1,
'is_filterable_in_search' => 0,
'is_used_for_promo_rules' => 0,
'is_html_allowed_on_front' => 1,
'is_visible_on_front' => 0,
'used_in_product_listing' => 0,
'used_for_sort_by' => 0,
'frontend_label' => ['Multiselect Attribute'],
'backend_type' => 'text',
'backend_model' => ArrayBackend::class,
'option' => [
'value' => [
'dog' => ['Dog'],
'cat' => ['Cat'],
],
'order' => [
'dog' => 1,
'cat' => 2,
],
],
]
);
$multiselectAttribute->save();
}
/**
* Prepare new index and delete old. Keep cache alive.
*
* @return void
*/
private function updateElasticsearchIndex(): void
{
$storeId = (int)$this->storeManager->getDefaultStoreView()->getId();
$mappedIndexerId = 'product';
$this->adapter->updateIndexMapping($storeId, $mappedIndexerId, 'select_attribute');
$oldIndex = $this->indexNameResolver->getIndexFromAlias($storeId, $mappedIndexerId);
$this->newIndex = $oldIndex . '1';
$this->deleteIndex($this->newIndex);
$this->indexBuilder->setStoreId($storeId);
$this->client->createIndex($this->newIndex, ['settings' => $this->indexBuilder->build()]);
$this->client->updateAlias(
$this->indexNameResolver->getIndexNameForAlias($storeId, $mappedIndexerId),
$this->newIndex,
$oldIndex
);
$this->client->deleteIndex($oldIndex);
}
/**
* Delete index by name if exists
*
* @param $newIndex
*/
private function deleteIndex($newIndex): void
{
if ($this->client->indexExists($newIndex)) {
$this->client->deleteIndex($newIndex);
}
}
/**
* @return void
*/
private function reindex(): void
{
$indexer = $this->objectManager->create(Indexer::class);
$indexer->load('catalogsearch_fulltext');
$indexer->reindexAll();
}
/**
* @param int $storeId
* @return array
*/
private function getIndexMapping(int $storeId): array
{
$indexName = $this->indexNameResolver->getIndexName($storeId, 'product', []);
$mapping = $this->client->getMapping(['index' => $indexName]);
$pathField = $this->arrayManager->findPath('properties', $mapping);
return $this->arrayManager->get($pathField, $mapping, []);
}
}