15
15
use Magento \Store \Api \StoreRepositoryInterface ;
16
16
use Magento \Store \Api \StoreResolverInterface ;
17
17
use Magento \Store \Model \ScopeInterface ;
18
+ use Magento \TestFramework \App \ApiMutableScopeConfig ;
19
+ use Magento \TestFramework \Config \Model \ConfigStorage ;
18
20
use Magento \TestFramework \Helper \Bootstrap ;
19
- use Magento \TestFramework \ObjectManager ;
20
21
21
22
/**
22
23
* Test storeConfig query cache
23
24
*/
24
25
class StoreConfigCacheTest extends GraphQLPageCacheAbstract
25
26
{
26
-
27
- /** @var ObjectManager */
27
+ /**
28
+ * @var \Magento\Framework\ObjectManagerInterface
29
+ */
28
30
private $ objectManager ;
29
31
32
+ /**
33
+ * @var ApiMutableScopeConfig
34
+ */
35
+ private $ config ;
36
+
37
+ /**
38
+ * @var ConfigStorage
39
+ */
40
+ private $ configStorage ;
41
+
42
+ /**
43
+ * @var array
44
+ */
45
+ private $ origConfigs = [];
46
+
47
+ /**
48
+ * @var array
49
+ */
50
+ private $ notExistingOrigConfigs = [];
51
+
52
+ /**
53
+ * @var StoreConfigInterface
54
+ */
55
+ private $ defaultStoreConfig ;
56
+
30
57
/**
31
58
* @inheritDoc
32
59
*/
33
60
protected function setUp (): void
34
61
{
35
62
$ this ->objectManager = Bootstrap::getObjectManager ();
36
- }
63
+ $ this ->configStorage = $ this ->objectManager ->get (ConfigStorage::class);
64
+ $ this ->config = $ this ->objectManager ->get (ApiMutableScopeConfig::class);
37
65
38
- /**
39
- * @magentoConfigFixture default/system/full_page_cache/caching_application 2
40
- * @magentoApiDataFixture Magento/Store/_files/store.php
41
- * @throws NoSuchEntityException
42
- */
43
- public function testGetStoreConfig (): void
44
- {
45
66
/** @var StoreConfigManagerInterface $storeConfigManager */
46
67
$ storeConfigManager = $ this ->objectManager ->get (StoreConfigManagerInterface::class);
47
68
/** @var StoreResolverInterface $storeResolver */
@@ -52,15 +73,28 @@ public function testGetStoreConfig(): void
52
73
$ store = $ storeRepository ->getById ($ defaultStoreId );
53
74
$ defaultStoreCode = $ store ->getCode ();
54
75
/** @var StoreConfigInterface $storeConfig */
55
- $ storeConfig = current ($ storeConfigManager ->getStoreConfigs ([$ defaultStoreCode ]));
56
- $ defaultLocale = $ storeConfig ->getLocale ();
76
+ $ this ->defaultStoreConfig = current ($ storeConfigManager ->getStoreConfigs ([$ defaultStoreCode ]));
77
+ }
78
+
79
+ /**
80
+ * storeConfig query is cached.
81
+ *
82
+ * @magentoConfigFixture default/system/full_page_cache/caching_application 2
83
+ * @magentoApiDataFixture Magento/Store/_files/store.php
84
+ * @throws NoSuchEntityException
85
+ */
86
+ public function testGetStoreConfig (): void
87
+ {
88
+ $ defaultStoreId = $ this ->defaultStoreConfig ->getId ();
89
+ $ defaultStoreCode = $ this ->defaultStoreConfig ->getCode ();
90
+ $ defaultLocale = $ this ->defaultStoreConfig ->getLocale ();
57
91
$ query = $ this ->getQuery ();
58
92
59
93
// Query default store config
60
94
$ responseDefaultStore = $ this ->graphQlQueryWithResponseHeaders ($ query );
61
95
$ this ->assertArrayHasKey (CacheIdCalculator::CACHE_ID_HEADER , $ responseDefaultStore ['headers ' ]);
62
96
$ defaultStoreCacheId = $ responseDefaultStore ['headers ' ][CacheIdCalculator::CACHE_ID_HEADER ];
63
- // Verify we obtain a cache MISS the first time
97
+ // Verify we obtain a cache MISS the 1st time
64
98
$ defaultStoreResponse = $ this ->assertCacheMissAndReturnResponse (
65
99
$ query ,
66
100
[CacheIdCalculator::CACHE_ID_HEADER => $ defaultStoreCacheId ]
@@ -70,7 +104,7 @@ public function testGetStoreConfig(): void
70
104
$ this ->assertEquals ($ defaultStoreId , $ defaultStoreResponseResult ['id ' ]);
71
105
$ this ->assertEquals ($ defaultStoreCode , $ defaultStoreResponseResult ['code ' ]);
72
106
$ this ->assertEquals ($ defaultLocale , $ defaultStoreResponseResult ['locale ' ]);
73
- // Verify we obtain a cache HIT the second time
107
+ // Verify we obtain a cache HIT the 2nd time
74
108
$ defaultStoreResponseHit = $ this ->assertCacheHitAndReturnResponse (
75
109
$ query ,
76
110
[CacheIdCalculator::CACHE_ID_HEADER => $ defaultStoreCacheId ]
@@ -87,7 +121,7 @@ public function testGetStoreConfig(): void
87
121
$ this ->assertArrayHasKey (CacheIdCalculator::CACHE_ID_HEADER , $ responseTestStore ['headers ' ]);
88
122
$ testStoreCacheId = $ responseTestStore ['headers ' ][CacheIdCalculator::CACHE_ID_HEADER ];
89
123
$ this ->assertNotEquals ($ testStoreCacheId , $ defaultStoreCacheId );
90
- // Verify we obtain a cache MISS the first time
124
+ // Verify we obtain a cache MISS the 1st time
91
125
$ testStoreResponse = $ this ->assertCacheMissAndReturnResponse (
92
126
$ query ,
93
127
[
@@ -99,7 +133,7 @@ public function testGetStoreConfig(): void
99
133
$ testStoreResponseResult = $ testStoreResponse ['body ' ]['storeConfig ' ];
100
134
$ this ->assertEquals ($ testStoreCode , $ testStoreResponseResult ['code ' ]);
101
135
$ this ->assertEquals ($ defaultLocale , $ testStoreResponseResult ['locale ' ]);
102
- // Verify we obtain a cache HIT the second time
136
+ // Verify we obtain a cache HIT the 2nd time
103
137
$ testStoreResponseHit = $ this ->assertCacheHitAndReturnResponse (
104
138
$ query ,
105
139
[
@@ -111,13 +145,63 @@ public function testGetStoreConfig(): void
111
145
$ testStoreResponseHitResult = $ testStoreResponseHit ['body ' ]['storeConfig ' ];
112
146
$ this ->assertEquals ($ testStoreCode , $ testStoreResponseHitResult ['code ' ]);
113
147
$ this ->assertEquals ($ defaultLocale , $ testStoreResponseHitResult ['locale ' ]);
148
+ }
149
+
150
+ /**
151
+ * Store scoped config change triggers purging only the cache of the changed store.
152
+ *
153
+ * @magentoConfigFixture default/system/full_page_cache/caching_application 2
154
+ * @magentoApiDataFixture Magento/Store/_files/store.php
155
+ * @throws NoSuchEntityException
156
+ */
157
+ public function testCachePurgedWithStoreScopeConfigChange (): void
158
+ {
159
+ $ defaultStoreId = $ this ->defaultStoreConfig ->getId ();
160
+ $ defaultStoreCode = $ this ->defaultStoreConfig ->getCode ();
161
+ $ defaultLocale = $ this ->defaultStoreConfig ->getLocale ();
162
+ $ query = $ this ->getQuery ();
163
+
164
+ // Query default store config
165
+ $ responseDefaultStore = $ this ->graphQlQueryWithResponseHeaders ($ query );
166
+ $ this ->assertArrayHasKey (CacheIdCalculator::CACHE_ID_HEADER , $ responseDefaultStore ['headers ' ]);
167
+ $ defaultStoreCacheId = $ responseDefaultStore ['headers ' ][CacheIdCalculator::CACHE_ID_HEADER ];
168
+ // Verify we obtain a cache MISS the 1st time
169
+ $ defaultStoreResponse = $ this ->assertCacheMissAndReturnResponse (
170
+ $ query ,
171
+ [CacheIdCalculator::CACHE_ID_HEADER => $ defaultStoreCacheId ]
172
+ );
173
+ $ this ->assertArrayHasKey ('storeConfig ' , $ defaultStoreResponse ['body ' ]);
174
+ $ defaultStoreResponseResult = $ defaultStoreResponse ['body ' ]['storeConfig ' ];
175
+ $ this ->assertEquals ($ defaultStoreId , $ defaultStoreResponseResult ['id ' ]);
176
+ $ this ->assertEquals ($ defaultStoreCode , $ defaultStoreResponseResult ['code ' ]);
177
+ $ this ->assertEquals ($ defaultLocale , $ defaultStoreResponseResult ['locale ' ]);
178
+
179
+ // Query test store config
180
+ $ testStoreCode = 'test ' ;
181
+ $ responseTestStore = $ this ->graphQlQueryWithResponseHeaders ($ query , [], '' , ['Store ' => $ testStoreCode ]);
182
+ $ this ->assertArrayHasKey (CacheIdCalculator::CACHE_ID_HEADER , $ responseTestStore ['headers ' ]);
183
+ $ testStoreCacheId = $ responseTestStore ['headers ' ][CacheIdCalculator::CACHE_ID_HEADER ];
184
+ $ this ->assertNotEquals ($ testStoreCacheId , $ defaultStoreCacheId );
185
+ // Verify we obtain a cache MISS the 1st time
186
+ $ testStoreResponse = $ this ->assertCacheMissAndReturnResponse (
187
+ $ query ,
188
+ [
189
+ CacheIdCalculator::CACHE_ID_HEADER => $ testStoreCacheId ,
190
+ 'Store ' => $ testStoreCode
191
+ ]
192
+ );
193
+ $ this ->assertArrayHasKey ('storeConfig ' , $ testStoreResponse ['body ' ]);
194
+ $ testStoreResponseResult = $ testStoreResponse ['body ' ]['storeConfig ' ];
195
+ $ this ->assertEquals ($ testStoreCode , $ testStoreResponseResult ['code ' ]);
196
+ $ this ->assertEquals ($ defaultLocale , $ testStoreResponseResult ['locale ' ]);
114
197
115
198
// Change test store locale
199
+ $ localeConfigPath = 'general/locale/code ' ;
116
200
$ newLocale = 'de_DE ' ;
117
- $ this ->setConfig (' general/locale/code ' , $ newLocale , ScopeInterface::SCOPE_STORES , $ testStoreCode );
201
+ $ this ->setConfig ($ localeConfigPath , $ newLocale , ScopeInterface::SCOPE_STORE , $ testStoreCode );
118
202
119
203
// Query default store config after test store config change
120
- // Verify we obtain a cache HIT the 3rd time
204
+ // Verify we obtain a cache HIT the 2nd time, the cache is not purged
121
205
$ defaultStoreResponseHit2 = $ this ->assertCacheHitAndReturnResponse (
122
206
$ query ,
123
207
[CacheIdCalculator::CACHE_ID_HEADER => $ defaultStoreCacheId ]
@@ -129,7 +213,7 @@ public function testGetStoreConfig(): void
129
213
$ this ->assertEquals ($ defaultLocale , $ defaultStoreResponseHit2Result ['locale ' ]);
130
214
131
215
// Query test store config after test store config change
132
- // Verify we obtain a cache MISS the 3rd time
216
+ // Verify we obtain a cache MISS the 2nd time, the cache is purged
133
217
$ testStoreResponseMiss = $ this ->assertCacheMissAndReturnResponse (
134
218
$ query ,
135
219
[
@@ -141,7 +225,7 @@ public function testGetStoreConfig(): void
141
225
$ testStoreResponseMissResult = $ testStoreResponseMiss ['body ' ]['storeConfig ' ];
142
226
$ this ->assertEquals ($ testStoreCode , $ testStoreResponseMissResult ['code ' ]);
143
227
$ this ->assertEquals ($ newLocale , $ testStoreResponseMissResult ['locale ' ]);
144
- // Verify we obtain a cache HIT the 4th time
228
+ // Verify we obtain a cache HIT the 3rd time
145
229
$ testStoreResponseHit2 = $ this ->assertCacheHitAndReturnResponse (
146
230
$ query ,
147
231
[
@@ -198,25 +282,63 @@ private function getQuery(): string
198
282
return $ query ;
199
283
}
200
284
285
+ protected function tearDown (): void
286
+ {
287
+ $ this ->restoreConfig ();
288
+ parent ::tearDown ();
289
+ }
290
+
201
291
/**
202
292
* Set configuration
203
293
*
204
294
* @param string $path
205
295
* @param string $value
206
- * @param string|null $scope
296
+ * @param string $scopeType
207
297
* @param string|null $scopeCode
208
298
* @return void
209
- * @throws \Magento\Framework\Exception\LocalizedException
210
299
*/
211
- private function setConfig (string $ path , string $ value , ?string $ scope = null , ?string $ scopeCode = null ) : void
300
+ private function setConfig (
301
+ string $ path ,
302
+ string $ value ,
303
+ string $ scopeType ,
304
+ ?string $ scopeCode = null
305
+ ): void {
306
+ if ($ this ->configStorage ->checkIsRecordExist ($ path , $ scopeType , $ scopeCode )) {
307
+ $ this ->origConfigs [] = [
308
+ 'path ' => $ path ,
309
+ 'value ' => $ this ->configStorage ->getValueFromDb ($ path , $ scopeType , $ scopeCode ),
310
+ 'scopeType ' => $ scopeType ,
311
+ 'scopeCode ' => $ scopeCode
312
+ ];
313
+ } else {
314
+ $ this ->notExistingOrigConfigs [] = [
315
+ 'path ' => $ path ,
316
+ 'scopeType ' => $ scopeType ,
317
+ 'scopeCode ' => $ scopeCode
318
+ ];
319
+ }
320
+ $ this ->config ->setValue ($ path , $ value , $ scopeType , $ scopeCode );
321
+ }
322
+
323
+ private function restoreConfig ()
212
324
{
213
- $ options = '' ;
214
- $ options .= $ scope ? "--scope= $ scope " : '' ;
215
- $ options .= $ scopeCode ? "--scope-code= $ scopeCode " : '' ;
216
- $ options .= "$ path $ value " ;
217
- $ appDir = dirname (Bootstrap::getInstance ()->getAppTempDir ());
218
- $ out = '' ;
219
- // phpcs:ignore Magento2.Security.InsecureFunction
220
- exec ("php -f {$ appDir }/bin/magento config:set $ options " , $ out );
325
+ foreach ($ this ->origConfigs as $ origConfig ) {
326
+ $ this ->config ->setValue (
327
+ $ origConfig ['path ' ],
328
+ $ origConfig ['value ' ],
329
+ $ origConfig ['scopeType ' ],
330
+ $ origConfig ['scopeCode ' ]
331
+ );
332
+ }
333
+ $ this ->origConfigs = [];
334
+
335
+ foreach ($ this ->notExistingOrigConfigs as $ notExistingOrigConfig ) {
336
+ $ this ->configStorage ->deleteConfigFromDb (
337
+ $ notExistingOrigConfig ['path ' ],
338
+ $ notExistingOrigConfig ['scopeType ' ],
339
+ $ notExistingOrigConfig ['scopeCode ' ]
340
+ );
341
+ }
342
+ $ this ->notExistingOrigConfigs = [];
221
343
}
222
344
}
0 commit comments