Skip to content

Commit 2977da1

Browse files
committed
ACP2E-3892: [Mainline] Unpopulated pages are cached due to search engine errors
1 parent d492d45 commit 2977da1

File tree

6 files changed

+446
-1
lines changed

6 files changed

+446
-1
lines changed

app/code/Magento/Catalog/Test/Unit/Block/Product/ListProductTest.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,20 @@
1616
use Magento\Catalog\Model\Product\Type\Simple;
1717
use Magento\Catalog\Model\ResourceModel\Category as CategoryResourceModel;
1818
use Magento\Catalog\Model\ResourceModel\Category\Collection;
19+
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
1920
use Magento\Checkout\Helper\Cart;
21+
use Magento\Framework\App\Config\ScopeConfigInterface;
2022
use Magento\Framework\Data\Helper\PostHelper;
2123
use Magento\Framework\Event\ManagerInterface;
2224
use Magento\Framework\Pricing\Render;
2325
use Magento\Framework\Registry;
2426
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
27+
use Magento\Framework\Translate\Inline\StateInterface;
2528
use Magento\Framework\Url\Helper\Data;
2629
use Magento\Framework\View\LayoutInterface;
2730
use Magento\Store\Api\Data\StoreInterface;
2831
use Magento\Store\Model\StoreManagerInterface;
32+
use PHPUnit\Framework\MockObject\Exception;
2933
use PHPUnit\Framework\MockObject\MockObject;
3034
use PHPUnit\Framework\TestCase;
3135

@@ -104,6 +108,11 @@ class ListProductTest extends TestCase
104108
*/
105109
private $renderer;
106110

111+
/**
112+
* @var CollectionFactory|MockObject
113+
*/
114+
private CollectionFactory $collectionFactory;
115+
107116
protected function setUp(): void
108117
{
109118
$objectManager = new ObjectManager($this);
@@ -145,6 +154,11 @@ protected function setUp(): void
145154
$store = $this->createMock(StoreInterface::class);
146155
$storeManager->expects($this->any())->method('getStore')->willReturn($store);
147156
$this->context->expects($this->any())->method('getStoreManager')->willReturn($storeManager);
157+
$scopeConfig = $this->createMock(ScopeConfigInterface::class);
158+
$this->context->expects($this->any())->method('getScopeConfig')->willReturn($scopeConfig);
159+
$inlineTranslation = $this->createMock(StateInterface::class);
160+
$this->context->expects($this->any())->method('getInlineTranslation')->willReturn($inlineTranslation);
161+
$this->collectionFactory = $this->createMock(CollectionFactory::class);
148162

149163
$this->block = $objectManager->getObject(
150164
ListProduct::class,
@@ -155,6 +169,7 @@ protected function setUp(): void
155169
'cartHelper' => $this->cartHelperMock,
156170
'postDataHelper' => $this->postDataHelperMock,
157171
'urlHelper' => $this->urlHelperMock,
172+
'collectionFactory' => $this->collectionFactory
158173
]
159174
);
160175
$this->block->setToolbarBlockName('mock');
@@ -165,6 +180,32 @@ protected function tearDown(): void
165180
$this->block = null;
166181
}
167182

183+
/**
184+
* @return void
185+
* @throws Exception
186+
*/
187+
public function testEmptyCollection(): void
188+
{
189+
$this->block->setData('translate_inline', true);
190+
$this->prodCollectionMock->expects($this->any())
191+
->method('getItems')
192+
->willThrowException(new \Exception('No items found.'));
193+
$this->layerMock->expects($this->once())
194+
->method('getProductCollection')
195+
->willReturn($this->prodCollectionMock);
196+
$collection = $this->createMock(Collection::class);
197+
$this->collectionFactory->expects($this->once())->method('create')->willReturn($collection);
198+
$collection->expects($this->once())->method('addFieldToFilter');
199+
$currentCategory = $this->createMock(\Magento\Catalog\Model\Category::class);
200+
$currentCategory->expects($this->any())
201+
->method('getId')
202+
->willReturn('1');
203+
$this->layerMock->expects($this->any())
204+
->method('getCurrentCategory')
205+
->willReturn($currentCategory);
206+
$this->block->toHtml();
207+
}
208+
168209
public function testGetIdentities()
169210
{
170211
$productTag = 'cat_p_1';

app/code/Magento/CatalogGraphQl/Test/Unit/Model/Resolver/Products/Query/SearchTest.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace Magento\CatalogGraphQl\Test\Unit\Model\Resolver\Products\Query;
99

10+
use Magento\AdvancedSearch\Model\Client\ClientException;
1011
use Magento\CatalogGraphQl\DataProvider\Product\SearchCriteriaBuilder;
1112
use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\ProductSearch;
1213
use Magento\CatalogGraphQl\Model\Resolver\Products\Query\FieldSelection;
@@ -16,10 +17,12 @@
1617
use Magento\CatalogGraphQl\Model\Resolver\Products\Query\Suggestions;
1718
use Magento\Framework\Api\Search\SearchCriteriaInterface;
1819
use Magento\Framework\Api\Search\SearchResultInterface;
20+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
1921
use Magento\Framework\GraphQl\Query\Resolver\ArgumentsProcessorInterface;
2022
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
2123
use Magento\GraphQl\Model\Query\ContextInterface;
2224
use Magento\Search\Api\SearchInterface;
25+
use PHPUnit\Framework\MockObject\Exception;
2326
use PHPUnit\Framework\MockObject\MockObject;
2427
use PHPUnit\Framework\TestCase;
2528

@@ -149,4 +152,50 @@ public function testPopulateSearchQueryStats(): void
149152

150153
$this->model->getResult($args, $resolveInfo, $context);
151154
}
155+
156+
/**
157+
* @param $exception
158+
* @return void
159+
* @throws Exception
160+
* @throws GraphQlInputException
161+
* @dataProvider exceptionDataProvider
162+
*/
163+
public function testEmptyResultException($exception): void
164+
{
165+
$args = ['search' => 'test', 'pageSize' => 10, 'currentPage' => 1];
166+
$context = $this->createMock(ContextInterface::class);
167+
$resolveInfo = $this->createMock(ResolveInfo::class);
168+
$this->search->expects($this->once())
169+
->method('search')
170+
->willThrowException(new $exception('Error'));
171+
$this->searchResultFactory->expects($this->once())
172+
->method('create')
173+
->with(
174+
[
175+
'totalCount' => 0,
176+
'productsSearchResult' => [],
177+
'searchAggregation' => null,
178+
'pageSize' => $args['pageSize'],
179+
'currentPage' => $args['currentPage'],
180+
'totalPages' => 0,
181+
'suggestions' => [],
182+
]
183+
);
184+
$this->model->getResult($args, $resolveInfo, $context);
185+
}
186+
187+
/**
188+
* @return \class-string[][]
189+
*/
190+
public static function exceptionDataProvider(): array
191+
{
192+
return [
193+
'invalid_argument_exception' => [
194+
'exception' => \InvalidArgumentException::class,
195+
],
196+
'client_exception' => [
197+
'exception' => ClientException::class,
198+
]
199+
];
200+
}
152201
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Unit\ElasticAdapter\SearchAdapter;
9+
10+
use Magento\AdvancedSearch\Model\Client\ClientException;
11+
use Magento\Elasticsearch\SearchAdapter\QueryContainer;
12+
use Magento\Elasticsearch8\Model\Client\Elasticsearch;
13+
use Magento\Elasticsearch\ElasticAdapter\SearchAdapter\Mapper;
14+
use Magento\Elasticsearch\SearchAdapter\Aggregation\Builder as AggregationBuilder;
15+
use Magento\Elasticsearch\SearchAdapter\ConnectionManager;
16+
use Magento\Elasticsearch\SearchAdapter\QueryContainerFactory;
17+
use Magento\Elasticsearch\SearchAdapter\ResponseFactory;
18+
use Magento\Framework\Search\RequestInterface;
19+
use PHPUnit\Framework\MockObject\MockObject;
20+
use PHPUnit\Framework\TestCase;
21+
use Psr\Log\LoggerInterface;
22+
use Magento\Elasticsearch\ElasticAdapter\SearchAdapter\Adapter;
23+
24+
class AdapterTest extends TestCase
25+
{
26+
/**
27+
* Mapper instance
28+
*
29+
* @var Mapper|MockObject
30+
*/
31+
private Mapper $mapper;
32+
33+
/**
34+
* @var ResponseFactory|MockObject
35+
*/
36+
private ResponseFactory $responseFactory;
37+
38+
/**
39+
* @var ConnectionManager|MockObject
40+
*/
41+
private ConnectionManager $connectionManager;
42+
43+
/**
44+
* @var AggregationBuilder|MockObject
45+
*/
46+
private AggregationBuilder $aggregationBuilder;
47+
48+
/**
49+
* @var QueryContainerFactory|MockObject
50+
*/
51+
private QueryContainerFactory $queryContainerFactory;
52+
53+
/**
54+
* @var LoggerInterface|MockObject
55+
*/
56+
private LoggerInterface $logger;
57+
58+
/**
59+
* @var Adapter
60+
*/
61+
private Adapter $adapter;
62+
63+
protected function setUp(): void
64+
{
65+
$this->mapper = $this->createMock(Mapper::class);
66+
$this->responseFactory = $this->createMock(ResponseFactory::class);
67+
$this->connectionManager = $this->createMock(ConnectionManager::class);
68+
$this->aggregationBuilder = $this->createMock(AggregationBuilder::class);
69+
$this->queryContainerFactory = $this->createMock(QueryContainerFactory::class);
70+
$this->logger = $this->createMock(LoggerInterface::class);
71+
72+
$this->adapter = new Adapter(
73+
$this->connectionManager,
74+
$this->mapper,
75+
$this->responseFactory,
76+
$this->aggregationBuilder,
77+
$this->queryContainerFactory,
78+
$this->logger
79+
);
80+
}
81+
82+
/**
83+
* @return void
84+
* @throws ClientException
85+
* @throws \PHPUnit\Framework\MockObject\Exception
86+
*/
87+
public function testQueryException(): void
88+
{
89+
$request = $this->createMock(RequestInterface::class);
90+
$query = ['query'];
91+
$this->mapper->expects($this->once())->method('buildQuery')->with($request)->willReturn($query);
92+
$this->aggregationBuilder->expects($this->once())->method('setQuery');
93+
$this->queryContainerFactory->expects($this->once())
94+
->method('create')
95+
->with(['query' => $query])
96+
->willReturn($this->createMock(QueryContainer::class));
97+
$client = $this->createMock(Elasticsearch::class);
98+
$exception = new \Exception('error');
99+
$client->expects($this->once())->method('query')->willThrowException($exception);
100+
$this->connectionManager->expects($this->once())->method('getConnection')->willReturn($client);
101+
$this->logger->expects($this->once())->method('critical')->with($exception);
102+
103+
$this->expectException(ClientException::class);
104+
$this->adapter->query($request);
105+
}
106+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Unit\SearchAdapter;
9+
10+
use Magento\AdvancedSearch\Model\Client\ClientException;
11+
use Magento\Elasticsearch\SearchAdapter\Aggregation\Builder as AggregationBuilder;
12+
use Magento\Elasticsearch\SearchAdapter\ConnectionManager;
13+
use Magento\Elasticsearch\SearchAdapter\QueryContainer;
14+
use Magento\Elasticsearch\SearchAdapter\QueryContainerFactory;
15+
use Magento\Elasticsearch\SearchAdapter\ResponseFactory;
16+
use Magento\Elasticsearch8\Model\Client\Elasticsearch;
17+
use Magento\Elasticsearch8\SearchAdapter\Adapter;
18+
use Magento\Elasticsearch8\SearchAdapter\Mapper;
19+
use Magento\Framework\Search\RequestInterface;
20+
use PHPUnit\Framework\MockObject\Exception;
21+
use PHPUnit\Framework\MockObject\MockObject;
22+
use PHPUnit\Framework\TestCase;
23+
use Psr\Log\LoggerInterface;
24+
25+
class AdapterTest extends TestCase
26+
{
27+
/**
28+
* Mapper instance
29+
*
30+
* @var Mapper|MockObject
31+
*/
32+
private Mapper $mapper;
33+
34+
/**
35+
* @var ResponseFactory|MockObject
36+
*/
37+
private ResponseFactory $responseFactory;
38+
39+
/**
40+
* @var ConnectionManager|MockObject
41+
*/
42+
private ConnectionManager $connectionManager;
43+
44+
/**
45+
* @var AggregationBuilder|MockObject
46+
*/
47+
private AggregationBuilder $aggregationBuilder;
48+
49+
/**
50+
* @var QueryContainerFactory|MockObject
51+
*/
52+
private QueryContainerFactory $queryContainerFactory;
53+
54+
/**
55+
* @var LoggerInterface|MockObject
56+
*/
57+
private LoggerInterface $logger;
58+
59+
/**
60+
* @var Adapter
61+
*/
62+
private Adapter $adapter;
63+
64+
protected function setUp(): void
65+
{
66+
$this->mapper = $this->createMock(Mapper::class);
67+
$this->responseFactory = $this->createMock(ResponseFactory::class);
68+
$this->connectionManager = $this->createMock(ConnectionManager::class);
69+
$this->aggregationBuilder = $this->createMock(AggregationBuilder::class);
70+
$this->queryContainerFactory = $this->createMock(QueryContainerFactory::class);
71+
$this->logger = $this->createMock(LoggerInterface::class);
72+
73+
$this->adapter = new Adapter(
74+
$this->connectionManager,
75+
$this->mapper,
76+
$this->responseFactory,
77+
$this->aggregationBuilder,
78+
$this->queryContainerFactory,
79+
$this->logger
80+
);
81+
}
82+
83+
/**
84+
* @return void
85+
* @throws ClientException
86+
* @throws Exception
87+
*/
88+
public function testQueryException(): void
89+
{
90+
$request = $this->createMock(RequestInterface::class);
91+
$query = ['query'];
92+
$this->mapper->expects($this->once())->method('buildQuery')->with($request)->willReturn($query);
93+
$this->aggregationBuilder->expects($this->once())->method('setQuery');
94+
$this->queryContainerFactory->expects($this->once())
95+
->method('create')
96+
->with(['query' => $query])
97+
->willReturn($this->createMock(QueryContainer::class));
98+
$client = $this->createMock(Elasticsearch::class);
99+
$exception = new \Exception('error');
100+
$client->expects($this->once())->method('query')->willThrowException($exception);
101+
$this->connectionManager->expects($this->once())->method('getConnection')->willReturn($client);
102+
$this->logger->expects($this->once())->method('critical')->with($exception);
103+
104+
$this->expectException(ClientException::class);
105+
$this->adapter->query($request);
106+
}
107+
}

0 commit comments

Comments
 (0)