Skip to content

Commit 22dd903

Browse files
committed
MC-31304: [ElasticSearch] Exception on catalog search result page
1 parent b770454 commit 22dd903

File tree

2 files changed

+172
-49
lines changed

2 files changed

+172
-49
lines changed

app/code/Magento/Elasticsearch/Model/DataProvider/Base/Suggestions.php

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,23 @@
55
*/
66
namespace Magento\Elasticsearch\Model\DataProvider\Base;
77

8-
use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProviderInterface;
9-
use Magento\Store\Model\ScopeInterface;
10-
use Magento\Search\Model\QueryInterface;
8+
use Elasticsearch\Common\Exceptions\BadRequest400Exception;
119
use Magento\AdvancedSearch\Model\SuggestedQueriesInterface;
10+
use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProviderInterface;
1211
use Magento\Elasticsearch\Model\Config;
1312
use Magento\Elasticsearch\SearchAdapter\ConnectionManager;
14-
use Magento\Search\Model\QueryResultFactory;
15-
use Magento\Framework\App\Config\ScopeConfigInterface;
1613
use Magento\Elasticsearch\SearchAdapter\SearchIndexNameResolver;
14+
use Magento\Framework\App\Config\ScopeConfigInterface;
15+
use Magento\Framework\App\ObjectManager;
16+
use Magento\Search\Model\QueryInterface;
17+
use Magento\Search\Model\QueryResultFactory;
18+
use Magento\Store\Model\ScopeInterface;
1719
use Magento\Store\Model\StoreManagerInterface as StoreManager;
20+
use Psr\Log\LoggerInterface;
1821

1922
/**
2023
* Default implementation to provide suggestions mechanism for Elasticsearch
24+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
2125
*/
2226
class Suggestions implements SuggestedQueriesInterface
2327
{
@@ -56,6 +60,11 @@ class Suggestions implements SuggestedQueriesInterface
5660
*/
5761
private $fieldProvider;
5862

63+
/**
64+
* @var LoggerInterface
65+
*/
66+
private $logger;
67+
5968
/**
6069
* Suggestions constructor.
6170
*
@@ -66,6 +75,7 @@ class Suggestions implements SuggestedQueriesInterface
6675
* @param SearchIndexNameResolver $searchIndexNameResolver
6776
* @param StoreManager $storeManager
6877
* @param FieldProviderInterface $fieldProvider
78+
* @param LoggerInterface|null $logger
6979
*/
7080
public function __construct(
7181
ScopeConfigInterface $scopeConfig,
@@ -74,7 +84,8 @@ public function __construct(
7484
ConnectionManager $connectionManager,
7585
SearchIndexNameResolver $searchIndexNameResolver,
7686
StoreManager $storeManager,
77-
FieldProviderInterface $fieldProvider
87+
FieldProviderInterface $fieldProvider,
88+
LoggerInterface $logger = null
7889
) {
7990
$this->queryResultFactory = $queryResultFactory;
8091
$this->connectionManager = $connectionManager;
@@ -83,6 +94,7 @@ public function __construct(
8394
$this->searchIndexNameResolver = $searchIndexNameResolver;
8495
$this->storeManager = $storeManager;
8596
$this->fieldProvider = $fieldProvider;
97+
$this->logger = $logger ?: ObjectManager::getInstance()->get(LoggerInterface::class);
8698
}
8799

88100
/**
@@ -93,8 +105,14 @@ public function getItems(QueryInterface $query)
93105
$result = [];
94106
if ($this->isSuggestionsAllowed()) {
95107
$isResultsCountEnabled = $this->isResultsCountEnabled();
108+
try {
109+
$suggestions = $this->getSuggestions($query);
110+
} catch (BadRequest400Exception $e) {
111+
$this->logger->critical($e);
112+
$suggestions = [];
113+
}
96114

97-
foreach ($this->getSuggestions($query) as $suggestion) {
115+
foreach ($suggestions as $suggestion) {
98116
$count = null;
99117
if ($isResultsCountEnabled) {
100118
$count = isset($suggestion['freq']) ? $suggestion['freq'] : null;

app/code/Magento/Elasticsearch/Test/Unit/Model/DataProvider/Base/SuggestionsTest.php

Lines changed: 147 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77

88
namespace Magento\Elasticsearch\Test\Unit\Model\DataProvider\Base;
99

10+
use Elasticsearch\Common\Exceptions\BadRequest400Exception;
11+
use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProviderInterface;
1012
use Magento\Elasticsearch\Model\Config;
13+
use Magento\Elasticsearch\Model\DataProvider\Base\Suggestions;
1114
use Magento\Elasticsearch\Model\DataProvider\Suggestions as SuggestionsDataProvider;
1215
use Magento\Elasticsearch\SearchAdapter\ConnectionManager;
1316
use Magento\Elasticsearch\SearchAdapter\SearchIndexNameResolver;
@@ -21,6 +24,7 @@
2124
use Magento\Store\Model\StoreManagerInterface as StoreManager;
2225
use PHPUnit\Framework\MockObject\MockObject;
2326
use PHPUnit\Framework\TestCase;
27+
use Psr\Log\LoggerInterface;
2428

2529
/**
2630
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -62,6 +66,21 @@ class SuggestionsTest extends TestCase
6266
*/
6367
private $storeManager;
6468

69+
/**
70+
* @var FieldProviderInterface|MockObject
71+
*/
72+
private $fieldProvider;
73+
74+
/**
75+
* @var LoggerInterface|MockObject
76+
*/
77+
private $logger;
78+
79+
/**
80+
* @var Elasticsearch|MockObject
81+
*/
82+
private $client;
83+
6584
/**
6685
* @var QueryInterface|MockObject
6786
*/
@@ -99,7 +118,19 @@ protected function setUp(): void
99118
->setMethods(['getIndexName'])
100119
->getMock();
101120

102-
$this->storeManager = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class)
121+
$this->storeManager = $this->getMockBuilder(StoreManager::class)
122+
->disableOriginalConstructor()
123+
->getMockForAbstractClass();
124+
125+
$this->fieldProvider = $this->getMockBuilder(FieldProviderInterface::class)
126+
->disableOriginalConstructor()
127+
->getMockForAbstractClass();
128+
129+
$this->logger = $this->getMockBuilder(LoggerInterface::class)
130+
->disableOriginalConstructor()
131+
->getMockForAbstractClass();
132+
133+
$this->client = $this->getMockBuilder(Elasticsearch::class)
103134
->disableOriginalConstructor()
104135
->getMock();
105136

@@ -110,81 +141,155 @@ protected function setUp(): void
110141
$objectManager = new ObjectManagerHelper($this);
111142

112143
$this->model = $objectManager->getObject(
113-
\Magento\Elasticsearch\Model\DataProvider\Base\Suggestions::class,
144+
Suggestions::class,
114145
[
115146
'queryResultFactory' => $this->queryResultFactory,
116147
'connectionManager' => $this->connectionManager,
117148
'scopeConfig' => $this->scopeConfig,
118149
'config' => $this->config,
119150
'searchIndexNameResolver' => $this->searchIndexNameResolver,
120-
'storeManager' => $this->storeManager
151+
'storeManager' => $this->storeManager,
152+
'fieldProvider' => $this->fieldProvider,
153+
'logger' => $this->logger,
121154
]
122155
);
123156
}
124157

125158
/**
126-
* Test getItems() method
159+
* Test get items process with search suggestions disabled.
160+
* @return void
127161
*/
128-
public function testGetItems()
162+
public function testGetItemsWithDisabledSearchSuggestion(): void
129163
{
130-
$this->scopeConfig->expects($this->any())
131-
->method('getValue')
132-
->willReturn(1);
133-
134-
$this->config->expects($this->any())
135-
->method('isElasticsearchEnabled')
136-
->willReturn(1);
137-
138-
$store = $this->getMockBuilder(StoreInterface::class)
139-
->disableOriginalConstructor()
140-
->getMockForAbstractClass();
164+
$this->scopeConfig->expects($this->once())
165+
->method('isSetFlag')
166+
->willReturn(false);
141167

142-
$this->storeManager->expects($this->any())
143-
->method('getStore')
144-
->willReturn($store);
145-
146-
$store->expects($this->any())
147-
->method('getId')
148-
->willReturn(1);
168+
$this->scopeConfig->expects($this->never())
169+
->method('getValue');
149170

150-
$this->searchIndexNameResolver->expects($this->any())
151-
->method('getIndexName')
152-
->willReturn('magento2_product_1');
171+
$this->config->expects($this->once())
172+
->method('isElasticsearchEnabled')
173+
->willReturn(true);
153174

154-
$this->query->expects($this->any())
155-
->method('getQueryText')
156-
->willReturn('query');
175+
$this->logger->expects($this->never())
176+
->method('critical');
157177

158-
$client = $this->getMockBuilder(Elasticsearch::class)
159-
->disableOriginalConstructor()
160-
->getMock();
178+
$this->queryResultFactory->expects($this->never())
179+
->method('create');
161180

162-
$this->connectionManager->expects($this->any())
163-
->method('getConnection')
164-
->willReturn($client);
181+
$this->assertEmpty($this->model->getItems($this->query));
182+
}
165183

166-
$client->expects($this->any())
184+
/**
185+
* Test get items process with search suggestions enabled.
186+
* @return void
187+
*/
188+
public function testGetItemsWithEnabledSearchSuggestion(): void
189+
{
190+
$this->prepareSearchQuery();
191+
$this->client->expects($this->once())
167192
->method('query')
168193
->willReturn([
169194
'suggest' => [
170195
'phrase_field' => [
171-
'options' => [
172-
'text' => 'query',
173-
'score' => 1,
174-
'freq' => 1,
196+
[
197+
'options' => [
198+
'suggestion' => [
199+
'text' => 'query',
200+
'score' => 1,
201+
'freq' => 1,
202+
]
203+
]
175204
]
176205
],
177206
],
178207
]);
179208

209+
$this->logger->expects($this->never())
210+
->method('critical');
211+
180212
$query = $this->getMockBuilder(QueryResult::class)
181213
->disableOriginalConstructor()
182214
->getMock();
183215

184-
$this->queryResultFactory->expects($this->any())
216+
$this->queryResultFactory->expects($this->once())
185217
->method('create')
186218
->willReturn($query);
187219

188-
$this->assertIsArray($this->model->getItems($this->query));
220+
$this->assertEquals([$query], $this->model->getItems($this->query));
221+
}
222+
223+
/**
224+
* Test get items process when throwing an exception.
225+
* @return void
226+
*/
227+
public function testGetItemsException(): void
228+
{
229+
$this->prepareSearchQuery();
230+
$exception = new BadRequest400Exception();
231+
232+
$this->client->expects($this->once())
233+
->method('query')
234+
->willThrowException($exception);
235+
236+
$this->logger->expects($this->once())
237+
->method('critical')
238+
->with($exception);
239+
240+
$this->queryResultFactory->expects($this->never())
241+
->method('create');
242+
243+
$this->assertEmpty($this->model->getItems($this->query));
244+
}
245+
246+
/**
247+
* Prepare Mocks for default get items process.
248+
* @return void
249+
*/
250+
private function prepareSearchQuery(): void
251+
{
252+
$storeId = 1;
253+
254+
$this->scopeConfig->expects($this->exactly(2))
255+
->method('isSetFlag')
256+
->willReturn(true);
257+
258+
$this->scopeConfig->expects($this->once())
259+
->method('getValue')
260+
->willReturn(1);
261+
262+
$this->config->expects($this->once())
263+
->method('isElasticsearchEnabled')
264+
->willReturn(true);
265+
266+
$store = $this->getMockBuilder(StoreInterface::class)
267+
->disableOriginalConstructor()
268+
->getMockForAbstractClass();
269+
270+
$store->expects($this->once())
271+
->method('getId')
272+
->willReturn($storeId);
273+
274+
$this->storeManager->expects($this->once())
275+
->method('getStore')
276+
->willReturn($store);
277+
278+
$this->searchIndexNameResolver->expects($this->once())
279+
->method('getIndexName')
280+
->with($storeId, Config::ELASTICSEARCH_TYPE_DEFAULT)
281+
->willReturn('magento2_product_1');
282+
283+
$this->query->expects($this->once())
284+
->method('getQueryText')
285+
->willReturn('query');
286+
287+
$this->fieldProvider->expects($this->once())
288+
->method('getFields')
289+
->willReturn([]);
290+
291+
$this->connectionManager->expects($this->once())
292+
->method('getConnection')
293+
->willReturn($this->client);
189294
}
190295
}

0 commit comments

Comments
 (0)