298 lines
9.9 KiB
PHP
Executable File
298 lines
9.9 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* Copyright © Magento, Inc. All rights reserved.
|
|
* See COPYING.txt for license details.
|
|
*/
|
|
namespace Magento\Elasticsearch\Model\Indexer;
|
|
|
|
use Magento\AdvancedSearch\Model\Client\ClientInterface;
|
|
use Magento\Catalog\Model\Product\Action as ProductAction;
|
|
use Magento\Catalog\Api\ProductRepositoryInterface;
|
|
use Magento\CatalogInventory\Api\StockRegistryInterface;
|
|
use Magento\CatalogInventory\Api\StockItemRepositoryInterface;
|
|
use Magento\CatalogSearch\Model\Indexer\Fulltext as CatalogSearchFulltextIndexer;
|
|
use Magento\TestFramework\Helper\Bootstrap;
|
|
use Magento\Store\Model\StoreManagerInterface;
|
|
use Magento\Elasticsearch\SearchAdapter\ConnectionManager;
|
|
use Magento\Elasticsearch\Model\Config;
|
|
use Magento\Elasticsearch\SearchAdapter\SearchIndexNameResolver;
|
|
use Magento\Indexer\Model\Indexer;
|
|
use Magento\Framework\Search\EngineResolverInterface;
|
|
use Magento\TestModuleCatalogSearch\Model\SearchEngineVersionReader;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
/**
|
|
* Important: Please make sure that each integration test file works with unique search index. In order to
|
|
* achieve this, use @magentoConfigFixture to pass unique value for index_prefix for every test
|
|
* method. E.g. '@magentoConfigFixture current_store catalog/search/elasticsearch7_index_prefix indexerhandlertest'
|
|
*
|
|
* @magentoDbIsolation disabled
|
|
* @magentoDataFixture Magento/Elasticsearch/_files/indexer.php
|
|
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
|
*/
|
|
class IndexHandlerTest extends TestCase
|
|
{
|
|
/**
|
|
* @var ProductRepositoryInterface
|
|
*/
|
|
private $productRepository;
|
|
|
|
/**
|
|
* @var ClientInterface
|
|
*/
|
|
private $client;
|
|
|
|
/**
|
|
* @var StoreManagerInterface
|
|
*/
|
|
private $storeManager;
|
|
|
|
/**
|
|
* @var int[]
|
|
*/
|
|
private $storeIds;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
private $entityType;
|
|
|
|
/**
|
|
* @var Indexer
|
|
*/
|
|
private $indexer;
|
|
|
|
/**
|
|
* @var SearchIndexNameResolver
|
|
*/
|
|
private $searchIndexNameResolver;
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
protected function setUp(): void
|
|
{
|
|
$connectionManager = Bootstrap::getObjectManager()->create(ConnectionManager::class);
|
|
$this->client = $connectionManager->getConnection();
|
|
|
|
$this->storeManager = Bootstrap::getObjectManager()->create(StoreManagerInterface::class);
|
|
$this->storeIds = array_keys($this->storeManager->getStores());
|
|
|
|
$clientConfig = Bootstrap::getObjectManager()->create(Config::class);
|
|
$this->entityType = $clientConfig->getEntityType();
|
|
|
|
$this->indexer = Bootstrap::getObjectManager()->create(Indexer::class);
|
|
$this->indexer->load(CatalogSearchFulltextIndexer::INDEXER_ID);
|
|
$this->indexer->reindexAll();
|
|
|
|
$this->searchIndexNameResolver = Bootstrap::getObjectManager()->create(SearchIndexNameResolver::class);
|
|
$this->productRepository = Bootstrap::getObjectManager()->create(ProductRepositoryInterface::class);
|
|
}
|
|
|
|
/**
|
|
* Make sure that correct engine is set
|
|
*/
|
|
protected function assertPreConditions(): void
|
|
{
|
|
$objectManager = Bootstrap::getObjectManager();
|
|
$currentEngine = $objectManager->get(EngineResolverInterface::class)->getCurrentSearchEngine();
|
|
$installedEngine = $objectManager->get(SearchEngineVersionReader::class)->getFullVersion();
|
|
$this->assertEquals(
|
|
$installedEngine,
|
|
$currentEngine,
|
|
sprintf(
|
|
'Search engine configuration "%s" is not compatible with the installed version',
|
|
$currentEngine
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testReindexAll(): void
|
|
{
|
|
$productApple = $this->productRepository->get('fulltext-1');
|
|
foreach ($this->storeIds as $storeId) {
|
|
$products = $this->searchByName('Apple', $storeId);
|
|
$this->assertCount(1, $products);
|
|
$this->assertEquals($productApple->getId(), $products[0]['_id']);
|
|
|
|
$products = $this->searchByName('Simple Product', $storeId);
|
|
$this->assertCount(5, $products);
|
|
|
|
$this->assertCount(2, $this->searchByBoolAttribute(0, $storeId));
|
|
$this->assertCount(3, $this->searchByBoolAttribute(1, $storeId));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @magentoAppIsolation enabled
|
|
* @return void
|
|
*/
|
|
public function testReindexRowAfterEdit(): void
|
|
{
|
|
$this->storeManager->setCurrentStore('admin');
|
|
$productApple = $this->productRepository->get('fulltext-1');
|
|
$productApple->setName('Simple Product Cucumber');
|
|
$this->productRepository->save($productApple);
|
|
|
|
foreach ($this->storeIds as $storeId) {
|
|
$products = $this->searchByName('Apple', $storeId);
|
|
$this->assertCount(0, $products);
|
|
|
|
$products = $this->searchByName('Cucumber', $storeId);
|
|
$this->assertCount(1, $products);
|
|
$this->assertEquals($productApple->getId(), $products[0]['_id']);
|
|
|
|
$products = $this->searchByName('Simple Product', $storeId);
|
|
$this->assertCount(5, $products);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testReindexRowAfterMassAction(): void
|
|
{
|
|
$productApple = $this->productRepository->get('fulltext-1');
|
|
$productBanana = $this->productRepository->get('fulltext-2');
|
|
$productIds = [
|
|
$productApple->getId(),
|
|
$productBanana->getId(),
|
|
];
|
|
$attrData = [
|
|
'name' => 'Simple Product Common',
|
|
];
|
|
/** @var ProductAction $action */
|
|
$action = Bootstrap::getObjectManager()->get(ProductAction::class);
|
|
|
|
foreach ($this->storeIds as $storeId) {
|
|
$action->updateAttributes($productIds, $attrData, $storeId);
|
|
|
|
$products = $this->searchByName('Apple', $storeId);
|
|
$this->assertCount(0, $products);
|
|
|
|
$products = $this->searchByName('Banana', $storeId);
|
|
$this->assertCount(0, $products);
|
|
|
|
$products = $this->searchByName('Unknown', $storeId);
|
|
$this->assertCount(0, $products);
|
|
|
|
$products = $this->searchByName('Common', $storeId);
|
|
$this->assertCount(2, $products);
|
|
|
|
$products = $this->searchByName('Simple Product', $storeId);
|
|
$this->assertCount(5, $products);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @magentoAppArea adminhtml
|
|
* @return void
|
|
*/
|
|
public function testReindexRowAfterDelete(): void
|
|
{
|
|
$productBanana = $this->productRepository->get('fulltext-2');
|
|
$this->productRepository->delete($productBanana);
|
|
|
|
foreach ($this->storeIds as $storeId) {
|
|
$products = $this->searchByName('Banana', $storeId);
|
|
$this->assertEmpty($products);
|
|
|
|
$products = $this->searchByName('Simple Product', $storeId);
|
|
$this->assertCount(4, $products);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @magentoDbIsolation enabled
|
|
* @magentoAppArea adminhtml
|
|
* @magentoDataFixture Magento/Elasticsearch/_files/configurable_products.php
|
|
* @return void
|
|
*/
|
|
public function testReindexRowAfterUpdateStockStatus(): void
|
|
{
|
|
foreach ($this->storeIds as $storeId) {
|
|
$products = $this->searchByName('ProductOption1', $storeId);
|
|
$this->assertNotEmpty($products);
|
|
}
|
|
$product = $this->productRepository->get('simple_10');
|
|
/** @var StockRegistryInterface $stockRegistry */
|
|
$stockRegistry = Bootstrap::getObjectManager()->create(StockRegistryInterface::class);
|
|
$stockItem = $stockRegistry->getStockItem($product->getId());
|
|
$stockItem->setIsInStock(false);
|
|
/** @var StockItemRepositoryInterface $stockRepository */
|
|
$stockRepository = Bootstrap::getObjectManager()->create(StockItemRepositoryInterface::class);
|
|
$stockRepository->save($stockItem);
|
|
|
|
foreach ($this->storeIds as $storeId) {
|
|
$products = $this->searchByName('ProductOption1', $storeId);
|
|
$this->assertEmpty($products);
|
|
|
|
$products = $this->searchByName('Configurable', $storeId);
|
|
$this->assertNotEmpty($products);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Search docs in search engine by name.
|
|
*
|
|
* @param string $text
|
|
* @param int $storeId
|
|
* @return array
|
|
*/
|
|
private function searchByName(string $text, int $storeId): array
|
|
{
|
|
$index = $this->searchIndexNameResolver->getIndexName($storeId, $this->indexer->getId());
|
|
$searchQuery = [
|
|
'index' => $index,
|
|
'type' => $this->entityType,
|
|
'body' => [
|
|
'query' => [
|
|
'bool' => [
|
|
'minimum_should_match' => 1,
|
|
'should' => [
|
|
[
|
|
'match' => [
|
|
'name' => $text,
|
|
],
|
|
],
|
|
],
|
|
],
|
|
],
|
|
],
|
|
];
|
|
$queryResult = $this->client->query($searchQuery);
|
|
$products = isset($queryResult['hits']['hits']) ? $queryResult['hits']['hits'] : [];
|
|
|
|
return $products;
|
|
}
|
|
|
|
/**
|
|
* Search docs in search engine by boolean attribute.
|
|
*
|
|
* @param int $value
|
|
* @param int $storeId
|
|
* @return array
|
|
*/
|
|
private function searchByBoolAttribute(int $value, int $storeId): array
|
|
{
|
|
$index = $this->searchIndexNameResolver->getIndexName($storeId, $this->indexer->getId());
|
|
$searchQuery = [
|
|
'index' => $index,
|
|
'type' => $this->entityType,
|
|
'body' => [
|
|
'query' => [
|
|
'query_string' => [
|
|
'query' => $value,
|
|
'default_field' => 'boolean_attribute',
|
|
],
|
|
],
|
|
],
|
|
];
|
|
$queryResult = $this->client->query($searchQuery);
|
|
return isset($queryResult['hits']['hits']) ? $queryResult['hits']['hits'] : [];
|
|
}
|
|
}
|