1515use Magento \Store \Api \StoreRepositoryInterface ;
1616use Magento \Store \Api \StoreResolverInterface ;
1717use Magento \Store \Model \ScopeInterface ;
18+ use Magento \TestFramework \App \ApiMutableScopeConfig ;
19+ use Magento \TestFramework \Config \Model \ConfigStorage ;
1820use Magento \TestFramework \Helper \Bootstrap ;
19- use Magento \TestFramework \ObjectManager ;
2021
2122/**
2223 * Test storeConfig query cache
2324 */
2425class StoreConfigCacheTest extends GraphQLPageCacheAbstract
2526{
26-
27- /** @var ObjectManager */
27+ /**
28+ * @var \Magento\Framework\ObjectManagerInterface
29+ */
2830 private $ objectManager ;
2931
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+
3057 /**
3158 * @inheritDoc
3259 */
3360 protected function setUp (): void
3461 {
3562 $ this ->objectManager = Bootstrap::getObjectManager ();
36- }
63+ $ this ->configStorage = $ this ->objectManager ->get (ConfigStorage::class);
64+ $ this ->config = $ this ->objectManager ->get (ApiMutableScopeConfig::class);
3765
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- {
4566 /** @var StoreConfigManagerInterface $storeConfigManager */
4667 $ storeConfigManager = $ this ->objectManager ->get (StoreConfigManagerInterface::class);
4768 /** @var StoreResolverInterface $storeResolver */
@@ -52,15 +73,28 @@ public function testGetStoreConfig(): void
5273 $ store = $ storeRepository ->getById ($ defaultStoreId );
5374 $ defaultStoreCode = $ store ->getCode ();
5475 /** @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 ();
5791 $ query = $ this ->getQuery ();
5892
5993 // Query default store config
6094 $ responseDefaultStore = $ this ->graphQlQueryWithResponseHeaders ($ query );
6195 $ this ->assertArrayHasKey (CacheIdCalculator::CACHE_ID_HEADER , $ responseDefaultStore ['headers ' ]);
6296 $ 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
6498 $ defaultStoreResponse = $ this ->assertCacheMissAndReturnResponse (
6599 $ query ,
66100 [CacheIdCalculator::CACHE_ID_HEADER => $ defaultStoreCacheId ]
@@ -70,7 +104,7 @@ public function testGetStoreConfig(): void
70104 $ this ->assertEquals ($ defaultStoreId , $ defaultStoreResponseResult ['id ' ]);
71105 $ this ->assertEquals ($ defaultStoreCode , $ defaultStoreResponseResult ['code ' ]);
72106 $ 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
74108 $ defaultStoreResponseHit = $ this ->assertCacheHitAndReturnResponse (
75109 $ query ,
76110 [CacheIdCalculator::CACHE_ID_HEADER => $ defaultStoreCacheId ]
@@ -87,7 +121,7 @@ public function testGetStoreConfig(): void
87121 $ this ->assertArrayHasKey (CacheIdCalculator::CACHE_ID_HEADER , $ responseTestStore ['headers ' ]);
88122 $ testStoreCacheId = $ responseTestStore ['headers ' ][CacheIdCalculator::CACHE_ID_HEADER ];
89123 $ this ->assertNotEquals ($ testStoreCacheId , $ defaultStoreCacheId );
90- // Verify we obtain a cache MISS the first time
124+ // Verify we obtain a cache MISS the 1st time
91125 $ testStoreResponse = $ this ->assertCacheMissAndReturnResponse (
92126 $ query ,
93127 [
@@ -99,7 +133,7 @@ public function testGetStoreConfig(): void
99133 $ testStoreResponseResult = $ testStoreResponse ['body ' ]['storeConfig ' ];
100134 $ this ->assertEquals ($ testStoreCode , $ testStoreResponseResult ['code ' ]);
101135 $ 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
103137 $ testStoreResponseHit = $ this ->assertCacheHitAndReturnResponse (
104138 $ query ,
105139 [
@@ -111,13 +145,63 @@ public function testGetStoreConfig(): void
111145 $ testStoreResponseHitResult = $ testStoreResponseHit ['body ' ]['storeConfig ' ];
112146 $ this ->assertEquals ($ testStoreCode , $ testStoreResponseHitResult ['code ' ]);
113147 $ 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 ' ]);
114197
115198 // Change test store locale
199+ $ localeConfigPath = 'general/locale/code ' ;
116200 $ newLocale = 'de_DE ' ;
117- $ this ->setConfig (' general/locale/code ' , $ newLocale , ScopeInterface::SCOPE_STORES , $ testStoreCode );
201+ $ this ->setConfig ($ localeConfigPath , $ newLocale , ScopeInterface::SCOPE_STORE , $ testStoreCode );
118202
119203 // 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
121205 $ defaultStoreResponseHit2 = $ this ->assertCacheHitAndReturnResponse (
122206 $ query ,
123207 [CacheIdCalculator::CACHE_ID_HEADER => $ defaultStoreCacheId ]
@@ -129,7 +213,7 @@ public function testGetStoreConfig(): void
129213 $ this ->assertEquals ($ defaultLocale , $ defaultStoreResponseHit2Result ['locale ' ]);
130214
131215 // 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
133217 $ testStoreResponseMiss = $ this ->assertCacheMissAndReturnResponse (
134218 $ query ,
135219 [
@@ -141,7 +225,7 @@ public function testGetStoreConfig(): void
141225 $ testStoreResponseMissResult = $ testStoreResponseMiss ['body ' ]['storeConfig ' ];
142226 $ this ->assertEquals ($ testStoreCode , $ testStoreResponseMissResult ['code ' ]);
143227 $ 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
145229 $ testStoreResponseHit2 = $ this ->assertCacheHitAndReturnResponse (
146230 $ query ,
147231 [
@@ -198,25 +282,63 @@ private function getQuery(): string
198282 return $ query ;
199283 }
200284
285+ protected function tearDown (): void
286+ {
287+ $ this ->restoreConfig ();
288+ parent ::tearDown ();
289+ }
290+
201291 /**
202292 * Set configuration
203293 *
204294 * @param string $path
205295 * @param string $value
206- * @param string|null $scope
296+ * @param string $scopeType
207297 * @param string|null $scopeCode
208298 * @return void
209- * @throws \Magento\Framework\Exception\LocalizedException
210299 */
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 ()
212324 {
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 = [];
221343 }
222344}
0 commit comments