<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Elasticsearch\Test\Unit\Model\Adapter; use Magento\AdvancedSearch\Model\Client\ClientOptionsInterface; use Magento\Elasticsearch\Model\Adapter\Elasticsearch as ElasticsearchAdapter; use Magento\Elasticsearch\SearchAdapter\ConnectionManager; use Magento\Elasticsearch\Model\Adapter\BatchDataMapperInterface; use Magento\Elasticsearch\Model\Adapter\FieldMapperInterface; use Magento\Elasticsearch\Model\Adapter\Index\BuilderInterface; use Psr\Log\LoggerInterface; use Magento\Elasticsearch\Model\Client\Elasticsearch as ElasticsearchClient; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; use Magento\Elasticsearch\Model\Adapter\Index\IndexNameResolver; /** * Class ElasticsearchTest * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class ElasticsearchTest extends \PHPUnit\Framework\TestCase { /** * @var ElasticsearchAdapter */ protected $model; /** * @var ConnectionManager|\PHPUnit_Framework_MockObject_MockObject */ protected $connectionManager; /** * @var BatchDataMapperInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $batchDocumentDataMapper; /** * @var FieldMapperInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $fieldMapper; /** * @var ClientOptionsInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $clientConfig; /** * @var BuilderInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $indexBuilder; /** * @var LoggerInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $logger; /** * @var ElasticsearchClient|\PHPUnit_Framework_MockObject_MockObject */ protected $client; /** * @var ObjectManagerHelper */ protected $objectManager; /** * @var IndexNameResolver|\PHPUnit_Framework_MockObject_MockObject */ protected $indexNameResolver; /** * Setup * * @return void */ protected function setUp() { $this->objectManager = new ObjectManagerHelper($this); $this->connectionManager = $this->getMockBuilder(\Magento\Elasticsearch\SearchAdapter\ConnectionManager::class) ->disableOriginalConstructor() ->setMethods(['getConnection']) ->getMock(); $this->documentDataMapper = $this->getMockBuilder( \Magento\Elasticsearch\Model\Adapter\DataMapperInterface::class )->disableOriginalConstructor()->getMock(); $this->fieldMapper = $this->getMockBuilder(\Magento\Elasticsearch\Model\Adapter\FieldMapperInterface::class) ->disableOriginalConstructor() ->getMock(); $this->clientConfig = $this->getMockBuilder(\Magento\Elasticsearch\Model\Config::class) ->disableOriginalConstructor() ->setMethods([ 'getIndexPrefix', 'getEntityType', ])->getMock(); $this->indexBuilder = $this->getMockBuilder(\Magento\Elasticsearch\Model\Adapter\Index\BuilderInterface::class) ->disableOriginalConstructor() ->getMock(); $this->logger = $this->getMockBuilder(\Psr\Log\LoggerInterface::class) ->disableOriginalConstructor() ->getMock(); $elasticsearchClientMock = $this->getMockBuilder(\Elasticsearch\Client::class) ->setMethods([ 'indices', 'ping', 'bulk', 'search', ]) ->disableOriginalConstructor() ->getMock(); $indicesMock = $this->getMockBuilder(\Elasticsearch\Namespaces\IndicesNamespace::class) ->setMethods([ 'exists', 'getSettings', 'create', 'putMapping', 'deleteMapping', 'existsAlias', 'updateAliases', 'stats' ]) ->disableOriginalConstructor() ->getMock(); $elasticsearchClientMock->expects($this->any()) ->method('indices') ->willReturn($indicesMock); $this->client = $this->getMockBuilder(\Magento\Elasticsearch\Model\Client\Elasticsearch::class) ->setConstructorArgs([ 'options' => $this->getClientOptions(), 'elasticsearchClient' => $elasticsearchClientMock ]) ->getMock(); $this->connectionManager->expects($this->any()) ->method('getConnection') ->willReturn($this->client); $this->fieldMapper->expects($this->any()) ->method('getAllAttributesTypes') ->willReturn([ 'name' => 'string', ]); $this->clientConfig->expects($this->any()) ->method('getIndexPrefix') ->willReturn('indexName'); $this->clientConfig->expects($this->any()) ->method('getEntityType') ->willReturn('product'); $this->indexNameResolver = $this->getMockBuilder( \Magento\Elasticsearch\Model\Adapter\Index\IndexNameResolver::class ) ->setMethods([ 'getIndexName', 'getIndexNamespace', 'getIndexFromAlias', 'getIndexNameForAlias', ]) ->disableOriginalConstructor() ->getMock(); $this->batchDocumentDataMapper = $this->getMockBuilder( \Magento\Elasticsearch\Model\Adapter\BatchDataMapperInterface::class )->disableOriginalConstructor() ->getMock(); $this->model = $this->objectManager->getObject( \Magento\Elasticsearch\Model\Adapter\Elasticsearch::class, [ 'connectionManager' => $this->connectionManager, 'batchDocumentDataMapper' => $this->batchDocumentDataMapper, 'fieldMapper' => $this->fieldMapper, 'clientConfig' => $this->clientConfig, 'indexBuilder' => $this->indexBuilder, 'logger' => $this->logger, 'indexNameResolver' => $this->indexNameResolver, 'options' => [], ] ); } /** * Test ping() method */ public function testPing() { $this->client->expects($this->once()) ->method('ping') ->willReturn(true); $this->assertEquals(true, $this->model->ping()); } /** * Test ping() method * @expectedException \Magento\Framework\Exception\LocalizedException */ public function testPingFailure() { $this->client->expects($this->once()) ->method('ping') ->willThrowException(new \Exception('Something went wrong')); $this->model->ping(); } /** * Test prepareDocsPerStore() method */ public function testPrepareDocsPerStoreEmpty() { $this->assertEquals([], $this->model->prepareDocsPerStore([], 1)); } /** * Test prepareDocsPerStore() method */ public function testPrepareDocsPerStore() { $this->batchDocumentDataMapper->expects($this->once()) ->method('map') ->willReturn([ 'name' => 'Product Name', ]); $this->assertInternalType( 'array', $this->model->prepareDocsPerStore( [ '1' => [ 'name' => 'Product Name', ], ], 1 ) ); } /** * Test addDocs() method */ public function testAddDocs() { $this->client->expects($this->once()) ->method('bulkQuery'); $this->assertSame( $this->model, $this->model->addDocs( [ '1' => [ 'name' => 'Product Name', ], ], 1, 'product' ) ); } /** * Test addDocs() method * @expectedException \Exception */ public function testAddDocsFailure() { $this->client->expects($this->once()) ->method('bulkQuery') ->willThrowException(new \Exception('Something went wrong')); $this->model->addDocs( [ '1' => [ 'name' => 'Product Name', ], ], 1, 'product' ); } /** * Test cleanIndex() method */ public function testCleanIndex() { $this->indexNameResolver->expects($this->any()) ->method('getIndexName') ->with(1, 'product', []) ->willReturn('indexName_product_1_v'); $this->client->expects($this->once()) ->method('isEmptyIndex') ->with('indexName_product_1_v') ->willReturn(false); $this->client->expects($this->atLeastOnce()) ->method('indexExists') ->willReturn(true); $this->client->expects($this->once()) ->method('deleteIndex') ->with('_product_1_v1'); $this->assertSame( $this->model, $this->model->cleanIndex(1, 'product') ); } /** * Test cleanIndex() method isEmptyIndex is true */ public function testCleanIndexTrue() { $this->indexNameResolver->expects($this->any()) ->method('getIndexName') ->willReturn('indexName_product_1_v'); $this->client->expects($this->once()) ->method('isEmptyIndex') ->with('indexName_product_1_v') ->willReturn(true); $this->assertSame( $this->model, $this->model->cleanIndex(1, 'product') ); } /** * Test deleteDocs() method */ public function testDeleteDocs() { $this->client->expects($this->once()) ->method('bulkQuery'); $this->assertSame( $this->model, $this->model->deleteDocs(['1' => 1], 1, 'product') ); } /** * Test deleteDocs() method * @expectedException \Exception */ public function testDeleteDocsFailure() { $this->client->expects($this->once()) ->method('bulkQuery') ->willThrowException(new \Exception('Something went wrong')); $this->model->deleteDocs(['1' => 1], 1, 'product'); } /** * Test updateAlias() method */ public function testUpdateAliasEmpty() { $model = $this->objectManager->getObject( \Magento\Elasticsearch\Model\Adapter\Elasticsearch::class, [ 'connectionManager' => $this->connectionManager, 'batchDocumentDataMapper' => $this->batchDocumentDataMapper, 'fieldMapper' => $this->fieldMapper, 'clientConfig' => $this->clientConfig, 'indexBuilder' => $this->indexBuilder, 'logger' => $this->logger, 'indexNameResolver' => $this->indexNameResolver, 'options' => [] ] ); $this->client->expects($this->never()) ->method('updateAlias'); $this->assertEquals($model, $model->updateAlias(1, 'product')); } /** * @expectedException \Magento\Framework\Exception\LocalizedException */ public function testConnectException() { $connectionManager = $this->getMockBuilder(\Magento\Elasticsearch\SearchAdapter\ConnectionManager::class) ->disableOriginalConstructor() ->setMethods([ 'getConnection', ]) ->getMock(); $connectionManager->expects($this->any()) ->method('getConnection') ->willThrowException(new \Exception('Something went wrong')); $this->objectManager->getObject( \Magento\Elasticsearch\Model\Adapter\Elasticsearch::class, [ 'connectionManager' => $connectionManager, 'batchDocumentDataMapper' => $this->batchDocumentDataMapper, 'fieldMapper' => $this->fieldMapper, 'clientConfig' => $this->clientConfig, 'indexBuilder' => $this->indexBuilder, 'logger' => $this->logger, 'indexNameResolver' => $this->indexNameResolver, 'options' => [] ] ); } /** * Test updateAlias() method */ public function testUpdateAlias() { $this->client->expects($this->atLeastOnce()) ->method('updateAlias'); $this->indexNameResolver->expects($this->any()) ->method('getIndexFromAlias') ->willReturn('_product_1_v1'); $this->model->cleanIndex(1, 'product'); $this->assertEquals($this->model, $this->model->updateAlias(1, 'product')); } /** * Test updateAlias() method */ public function testUpdateAliasWithOldIndex() { $this->model->cleanIndex(1, 'product'); $this->indexNameResolver->expects($this->any()) ->method('getIndexFromAlias') ->willReturn('_product_1_v2'); $this->indexNameResolver->expects($this->any()) ->method('getIndexNameForAlias') ->willReturn('_product_1_v2'); $this->client->expects($this->any()) ->method('existsAlias') ->with('indexName') ->willReturn(true); $this->client->expects($this->any()) ->method('getAlias') ->with('indexName') ->willReturn(['indexName_product_1_v' => 'indexName_product_1_v']); $this->assertEquals($this->model, $this->model->updateAlias(1, 'product')); } /** * Test updateAlias() method */ public function testUpdateAliasWithoutOldIndex() { $this->model->cleanIndex(1, 'product'); $this->client->expects($this->any()) ->method('existsAlias') ->with('indexName') ->willReturn(true); $this->client->expects($this->any()) ->method('getAlias') ->with('indexName') ->willReturn(['indexName_product_1_v2' => 'indexName_product_1_v2']); $this->assertEquals($this->model, $this->model->updateAlias(1, 'product')); } /** * Get elasticsearch client options * * @return array */ protected function getClientOptions() { return [ 'hostname' => 'localhost', 'port' => '9200', 'timeout' => 15, 'index' => 'magento2', 'enableAuth' => 1, 'username' => 'user', 'password' => 'my-password', ]; } }