Skip to content

Commit 61c7b8e

Browse files
committed
B2B-2658: Implement GraphQL Resolver Cache for Customer query
- proper exception handling
1 parent 8a81f0c commit 61c7b8e

File tree

2 files changed

+230
-0
lines changed
  • app/code/Magento/GraphQlResolverCache/Model/Plugin/Resolver
  • dev/tests/integration/testsuite/Magento/GraphQlResolverCache/Model/Plugin/Resolver

2 files changed

+230
-0
lines changed

app/code/Magento/GraphQlResolverCache/Model/Plugin/Resolver/Cache.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ class Cache
7070
* @param ResolverIdentityClassProvider $resolverIdentityClassProvider
7171
* @param ValueProcessorInterface $valueProcessor
7272
* @param ProviderInterface $keyCalculatorProvider
73+
* @param LoggerInterface $logger
7374
*/
7475
public function __construct(
7576
GraphQlResolverCache $graphQlResolverCache,
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\GraphQlResolverCache\Model\Plugin\Resolver;
9+
10+
use Magento\Framework\App\Cache\State as CacheState;
11+
use Magento\GraphQl\Service\GraphQlRequest;
12+
use Magento\GraphQlResolverCache\Model\Plugin\Resolver\Cache as CachePlugin;
13+
use Magento\GraphQlResolverCache\Model\Resolver\Result\Cache\IdentityInterface;
14+
use Magento\GraphQlResolverCache\Model\Resolver\Result\CacheKey\Calculator;
15+
use Magento\GraphQlResolverCache\Model\Resolver\Result\CacheKey\GenericFactorProviderInterface;
16+
use Magento\GraphQlResolverCache\Model\Resolver\Result\ResolverIdentityClassProvider;
17+
use Magento\GraphQlResolverCache\Model\Resolver\Result\Type;
18+
use Magento\StoreGraphQl\Model\Resolver\StoreConfigResolver;
19+
use Magento\TestFramework\Helper\Bootstrap;
20+
use Magento\TestFramework\Interception\PluginList;
21+
use PHPUnit\Framework\TestCase;
22+
use Psr\Log\LoggerInterface;
23+
24+
/**
25+
* Test creating a customer through GraphQL
26+
*/
27+
class CacheTest extends TestCase
28+
{
29+
/**
30+
* @var \Magento\TestFramework\ObjectManager
31+
*/
32+
private $objectManager;
33+
34+
/**
35+
* @var GraphQlRequest
36+
*/
37+
private $graphQlRequest;
38+
39+
/**
40+
* @var CacheState
41+
*/
42+
private $cacheState;
43+
44+
/**
45+
* @var bool
46+
*/
47+
private $origCacheEnabled;
48+
49+
/**
50+
* @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject
51+
*/
52+
private $loggerMock;
53+
54+
/**
55+
* @var Type|\PHPUnit\Framework\MockObject\MockObject
56+
*/
57+
private $graphqlResolverCacheMock;
58+
59+
/**
60+
* @var Type
61+
*/
62+
private $graphQlResolverCache;
63+
64+
/**
65+
* @var GenericFactorProviderInterface|\PHPUnit\Framework\MockObject\MockObject
66+
*/
67+
private $keyFactorMock;
68+
69+
/**
70+
* @inheritdoc
71+
*/
72+
public function setUp(): void
73+
{
74+
$this->objectManager = Bootstrap::getObjectManager();
75+
$this->graphQlRequest = $this->objectManager->create(GraphQlRequest::class);
76+
$this->cacheState = $this->objectManager->get(CacheState::class);
77+
$this->origCacheEnabled = $this->cacheState->isEnabled(Type::TYPE_IDENTIFIER);
78+
if (!$this->origCacheEnabled) {
79+
$this->cacheState->setEnabled(Type::TYPE_IDENTIFIER, true);
80+
$this->cacheState->persist();
81+
}
82+
$this->graphQlResolverCache = $this->objectManager->get(Type::class);
83+
$this->graphQlResolverCache->clean();
84+
}
85+
86+
/**
87+
* @inheritdoc
88+
*/
89+
public function tearDown(): void
90+
{
91+
$this->cacheState->setEnabled(Type::TYPE_IDENTIFIER, $this->origCacheEnabled);
92+
$this->cacheState->persist();
93+
$this->graphQlResolverCache->clean();
94+
parent::tearDown();
95+
}
96+
97+
/**
98+
* @magentoAppArea graphql
99+
*/
100+
public function testCachingSkippedOnKeyCalculationFailure()
101+
{
102+
$this->preconfigureMocks();
103+
$this->configurePlugin();
104+
$this->keyFactorMock->expects($this->any())
105+
->method('getFactorValue')
106+
->willThrowException(new \Exception("Test key factor exception"));
107+
$this->loggerMock->expects($this->once())->method('warning');
108+
$this->graphqlResolverCacheMock->expects($this->never())
109+
->method('load');
110+
$this->graphqlResolverCacheMock->expects($this->never())
111+
->method('save');
112+
$this->graphQlRequest->send($this->getTestQuery());
113+
}
114+
115+
/**
116+
* @magentoAppArea graphql
117+
*/
118+
public function testCachingNotSkippedWhenKeysOk()
119+
{
120+
$this->preconfigureMocks();
121+
$this->configurePlugin();
122+
$this->loggerMock->expects($this->never())->method('warning');
123+
$this->graphqlResolverCacheMock->expects($this->once())
124+
->method('load')
125+
->willReturn(false);
126+
$this->graphqlResolverCacheMock->expects($this->once())
127+
->method('save');
128+
$this->graphQlRequest->send($this->getTestQuery());
129+
}
130+
131+
/**
132+
* Configure mocks and object manager for test.
133+
*
134+
* @return void
135+
*/
136+
private function preconfigureMocks()
137+
{
138+
$this->loggerMock = $this->getMockBuilder(LoggerInterface::class)
139+
->disableOriginalConstructor()
140+
->onlyMethods(['warning'])
141+
->setMockClassName('CacheLoggerMockForTest')
142+
->getMockForAbstractClass();
143+
144+
$this->graphqlResolverCacheMock = $this->getMockBuilder(Type::class)
145+
->disableOriginalConstructor()
146+
->onlyMethods(['load', 'save'])
147+
->setMockClassName('GraphqlResolverCacheMockForTest')
148+
->getMock();
149+
150+
$this->keyFactorMock = $this->getMockBuilder(GenericFactorProviderInterface::class)
151+
->disableOriginalConstructor()
152+
->onlyMethods(['getFactorValue', 'getFactorName'])
153+
->setMockClassName('TestFailingKeyFactor')
154+
->getMock();
155+
156+
$this->objectManager->addSharedInstance($this->keyFactorMock, 'TestFailingKeyFactor');
157+
158+
$this->objectManager->configure(
159+
[
160+
Calculator::class => [
161+
'arguments' => [
162+
'factorProviders' => [
163+
'test_failing' => 'TestFailingKeyFactor'
164+
]
165+
]
166+
]
167+
]
168+
);
169+
170+
$identityProviderMock = $this->getMockBuilder(IdentityInterface::class)
171+
->disableOriginalConstructor()
172+
->onlyMethods(['getIdentities'])
173+
->setMockClassName('TestIdentityProvider')
174+
->getMock();
175+
176+
$identityProviderMock->expects($this->any())
177+
->method('getIdentities')
178+
->willReturn(['test_identity']);
179+
180+
$this->objectManager->addSharedInstance($identityProviderMock, 'TestIdentityProvider');
181+
182+
$this->objectManager->configure(
183+
[
184+
ResolverIdentityClassProvider::class => [
185+
'arguments' => [
186+
'cacheableResolverClassNameIdentityMap' => [
187+
StoreConfigResolver::class => 'TestIdentityProvider'
188+
]
189+
]
190+
]
191+
]
192+
);
193+
}
194+
195+
private function getTestQuery()
196+
{
197+
return <<<QUERY
198+
{
199+
storeConfig {
200+
id,
201+
code,
202+
store_code,
203+
store_name
204+
}
205+
}
206+
QUERY;
207+
}
208+
209+
/**
210+
* Reset plugin for the resolver.
211+
*
212+
* @return void
213+
*/
214+
private function configurePlugin()
215+
{
216+
// need to reset plugins list to inject new plugin with mocks as it is cached at runtime
217+
/** @var PluginList $pluginList */
218+
$pluginList = $this->objectManager->get(PluginList::class);
219+
$pluginList->reset();
220+
$this->objectManager->removeSharedInstance(CachePlugin::class);
221+
$this->objectManager->addSharedInstance(
222+
$this->objectManager->create(CachePlugin::class, [
223+
'logger' => $this->loggerMock,
224+
'graphQlResolverCache' => $this->graphqlResolverCacheMock
225+
]),
226+
CachePlugin::class
227+
);
228+
}
229+
}

0 commit comments

Comments
 (0)