diff --git a/app/code/Magento/Catalog/Observer/FlushCategoryPagesCache.php b/app/code/Magento/Catalog/Observer/FlushCategoryPagesCache.php new file mode 100644 index 0000000000000..751fa3fdfad84 --- /dev/null +++ b/app/code/Magento/Catalog/Observer/FlushCategoryPagesCache.php @@ -0,0 +1,60 @@ +cacheConfig = $cacheConfig; + $this->pageCache = $pageCache; + } + + /** + * Clean the category page cache if built in cache page cache is used. + * + * The built in cache requires cleaning all pages that contain the top category navigation menu when a + * category is moved. This is because the built in cache does not support ESI blocks. + * + * @param Event $event + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function execute(Event $event) + { + if ($this->cacheConfig->getType() == CacheConfig::BUILT_IN && $this->cacheConfig->isEnabled()) { + $this->pageCache->clean(\Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG, [Category::CACHE_TAG]); + } + } +} diff --git a/app/code/Magento/Catalog/etc/adminhtml/events.xml b/app/code/Magento/Catalog/etc/adminhtml/events.xml index ad83f5898237a..ab1a8348d2904 100644 --- a/app/code/Magento/Catalog/etc/adminhtml/events.xml +++ b/app/code/Magento/Catalog/etc/adminhtml/events.xml @@ -12,4 +12,7 @@ + + + diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/Cache/Frontend/PoolTest.php b/dev/tests/integration/testsuite/Magento/Framework/App/Cache/Frontend/PoolTest.php new file mode 100644 index 0000000000000..3324da008a84a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/App/Cache/Frontend/PoolTest.php @@ -0,0 +1,55 @@ +get(ObjectManagerConfig::class); + $argumentConfig = $diConfig->getArguments(\Magento\Framework\App\Cache\Frontend\Pool::class); + + $pageCacheDir = $argumentConfig['frontendSettings']['page_cache']['backend_options']['cache_dir'] ?? null; + $defaultCacheDir = $argumentConfig['frontendSettings']['default']['backend_options']['cache_dir'] ?? null; + + $noPageCacheMessage = "No default page_cache directory set in di.xml: \n" . var_export($argumentConfig, true); + $this->assertNotEmpty($pageCacheDir, $noPageCacheMessage); + + $sameCacheDirMessage = 'The page_cache and default cache storages share the same cache directory'; + $this->assertNotSame($pageCacheDir, $defaultCacheDir, $sameCacheDirMessage); + } + + /** + * @covers \Magento\Framework\App\Cache\Frontend\Pool::_getCacheSettings + * @depends testPageCacheNotSameAsDefaultCacheDirectory + */ + public function testCleaningDefaultCachePreservesPageCache() + { + $testData = 'test data'; + $testKey = 'test-key'; + + /** @var \Magento\Framework\App\Cache\Frontend\Pool $cacheFrontendPool */ + $cacheFrontendPool = ObjectManager::getInstance()->get(\Magento\Framework\App\Cache\Frontend\Pool::class); + + $pageCache = $cacheFrontendPool->get('page_cache'); + $pageCache->save($testData, $testKey); + + $defaultCache = $cacheFrontendPool->get('default'); + $defaultCache->clean(); + + $this->assertSame($testData, $pageCache->load($testKey)); + } +} diff --git a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/AbstractGraphqlCacheTest.php b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/AbstractGraphqlCacheTest.php index f25144c308c68..862a924f65793 100644 --- a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/AbstractGraphqlCacheTest.php +++ b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/AbstractGraphqlCacheTest.php @@ -7,9 +7,15 @@ namespace Magento\GraphQlCache\Controller; -use PHPUnit\Framework\TestCase; -use Magento\TestFramework\ObjectManager; +use Magento\Framework\App\Request\Http as HttpRequest; +use Magento\Framework\App\Response\HttpInterface as HttpResponse; +use Magento\Framework\Registry; +use Magento\GraphQl\Controller\GraphQl as GraphQlController; +use Magento\GraphQlCache\Model\CacheableQuery; +use Magento\PageCache\Model\Cache\Type as PageCache; use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\ObjectManager; +use PHPUnit\Framework\TestCase; /** * Abstract test class for Graphql cache tests @@ -21,40 +27,114 @@ abstract class AbstractGraphqlCacheTest extends TestCase */ protected $objectManager; - /** - * @inheritdoc - */ protected function setUp(): void { $this->objectManager = Bootstrap::getObjectManager(); + $this->enablePageCachePlugin(); + $this->enableCachebleQueryTestProxy(); + } + + protected function tearDown(): void + { + $this->disableCacheableQueryTestProxy(); + $this->disablePageCachePlugin(); + $this->flushPageCache(); + } + + protected function enablePageCachePlugin(): void + { + /** @var $registry Registry */ + $registry = $this->objectManager->get(Registry::class); + $registry->register('use_page_cache_plugin', true, true); + } + + protected function disablePageCachePlugin(): void + { + /** @var $registry Registry */ + $registry = $this->objectManager->get(Registry::class); + $registry->unregister('use_page_cache_plugin'); + } + + protected function flushPageCache(): void + { + /** @var PageCache $fullPageCache */ + $fullPageCache = $this->objectManager->get(PageCache::class); + $fullPageCache->clean(); } /** - * Prepare a query and return a request to be used in the same test end to end + * Regarding the SuppressWarnings annotation below: the nested class below triggers a false rule match. * - * @param string $query - * @return \Magento\Framework\App\Request\Http + * @SuppressWarnings(PHPMD.UnusedLocalVariable) */ - protected function prepareRequest(string $query) : \Magento\Framework\App\Request\Http - { - $cacheableQuery = $this->objectManager->get(\Magento\GraphQlCache\Model\CacheableQuery::class); - $cacheableQueryReflection = new \ReflectionProperty( - $cacheableQuery, - 'cacheTags' - ); - $cacheableQueryReflection->setAccessible(true); - $cacheableQueryReflection->setValue($cacheableQuery, []); - - /** @var \Magento\Framework\UrlInterface $urlInterface */ - $urlInterface = $this->objectManager->create(\Magento\Framework\UrlInterface::class); - //set unique URL - $urlInterface->setQueryParam('query', $query); - - $request = $this->objectManager->get(\Magento\Framework\App\Request\Http::class); - $request->setUri($urlInterface->getUrl('graphql')); + private function enableCachebleQueryTestProxy(): void + { + $cacheableQueryProxy = new class($this->objectManager) extends CacheableQuery { + /** @var CacheableQuery */ + private $delegate; + + public function __construct(ObjectManager $objectManager) + { + $this->reset($objectManager); + } + + public function reset(ObjectManager $objectManager): void + { + $this->delegate = $objectManager->create(CacheableQuery::class); + } + + public function getCacheTags(): array + { + return $this->delegate->getCacheTags(); + } + + public function addCacheTags(array $cacheTags): void + { + $this->delegate->addCacheTags($cacheTags); + } + + public function isCacheable(): bool + { + return $this->delegate->isCacheable(); + } + + public function setCacheValidity(bool $cacheable): void + { + $this->delegate->setCacheValidity($cacheable); + } + + public function shouldPopulateCacheHeadersWithTags(): bool + { + return $this->delegate->shouldPopulateCacheHeadersWithTags(); + } + }; + $this->objectManager->addSharedInstance($cacheableQueryProxy, CacheableQuery::class); + } + + private function disableCacheableQueryTestProxy(): void + { + $this->resetQueryCacheTags(); + $this->objectManager->removeSharedInstance(CacheableQuery::class); + } + + protected function resetQueryCacheTags(): void + { + $this->objectManager->get(CacheableQuery::class)->reset($this->objectManager); + } + + protected function dispatchGraphQlGETRequest(array $queryParams): HttpResponse + { + $this->resetQueryCacheTags(); + + /** @var HttpRequest $request */ + $request = $this->objectManager->get(HttpRequest::class); + $request->setPathInfo('/graphql'); $request->setMethod('GET'); - //set the actual GET query - $request->setQueryValue('query', $query); - return $request; + $request->setParams($queryParams); + + // required for \Magento\Framework\App\PageCache\Identifier to generate the correct cache key + $request->setUri(implode('?', [$request->getPathInfo(), http_build_query($queryParams)])); + + return $this->objectManager->create(GraphQlController::class)->dispatch($request); } } diff --git a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoriesWithProductsCacheTest.php b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoriesWithProductsCacheTest.php index fd97399992c1c..287353bbd2b80 100644 --- a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoriesWithProductsCacheTest.php +++ b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoriesWithProductsCacheTest.php @@ -9,8 +9,6 @@ use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Api\ProductRepositoryInterface; -use Magento\Framework\App\Request\Http; -use Magento\GraphQl\Controller\GraphQl; use Magento\GraphQlCache\Controller\AbstractGraphqlCacheTest; /** @@ -22,31 +20,12 @@ */ class CategoriesWithProductsCacheTest extends AbstractGraphqlCacheTest { - /** - * @var GraphQl - */ - private $graphqlController; - - /** - * @var Http - */ - private $request; - - /** - * @inheritdoc - */ - protected function setUp(): void - { - parent::setUp(); - $this->graphqlController = $this->objectManager->get(\Magento\GraphQl\Controller\GraphQl::class); - $this->request = $this->objectManager->create(Http::class); - } /** * Test cache tags and debug header for category with products querying for products and category * * @magentoDataFixture Magento/Catalog/_files/category_product.php */ - public function testToCheckRequestCacheTagsForCategoryWithProducts(): void + public function testRequestCacheTagsForCategoryWithProducts(): void { /** @var ProductRepositoryInterface $productRepository */ $productRepository = $this->objectManager->get(ProductRepositoryInterface::class); @@ -91,17 +70,7 @@ public function testToCheckRequestCacheTagsForCategoryWithProducts(): void 'operationName' => 'GetCategoryWithProducts' ]; - /** @var \Magento\Framework\UrlInterface $urlInterface */ - $urlInterface = $this->objectManager->create(\Magento\Framework\UrlInterface::class); - //set unique URL - $urlInterface->setQueryParam('query', $queryParams['query']); - $urlInterface->setQueryParam('variables', $queryParams['variables']); - $urlInterface->setQueryParam('operationName', $queryParams['operationName']); - $this->request->setUri($urlInterface->getUrl('graphql')); - $this->request->setPathInfo('/graphql'); - $this->request->setMethod('GET'); - $this->request->setParams($queryParams); - $response = $this->graphqlController->dispatch($this->request); + $response = $this->dispatchGraphQlGETRequest($queryParams); $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); $expectedCacheTags = ['cat_c','cat_c_' . $categoryId,'cat_p','cat_p_' . $product->getId(),'FPC']; $actualCacheTags = explode(',', $response->getHeader('X-Magento-Tags')->getFieldValue()); diff --git a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoryCacheTest.php b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoryCacheTest.php index be920fb200ff3..90bdc4f75825a 100644 --- a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoryCacheTest.php +++ b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoryCacheTest.php @@ -7,8 +7,6 @@ namespace Magento\GraphQlCache\Controller\Catalog; -use Magento\Framework\App\Request\Http; -use Magento\GraphQl\Controller\GraphQl; use Magento\GraphQlCache\Controller\AbstractGraphqlCacheTest; /** @@ -20,25 +18,12 @@ */ class CategoryCacheTest extends AbstractGraphqlCacheTest { - /** - * @var GraphQl - */ - private $graphqlController; - - /** - * @inheritdoc - */ - protected function setUp(): void - { - parent::setUp(); - $this->graphqlController = $this->objectManager->get(\Magento\GraphQl\Controller\GraphQl::class); - } /** * Test cache tags and debug header for category and querying only for category * * @magentoDataFixture Magento/Catalog/_files/category_product.php */ - public function testToCheckRequestCacheTagsForForCategory(): void + public function testRequestCacheTagsForCategory(): void { $categoryId ='333'; $query @@ -53,11 +38,10 @@ public function testToCheckRequestCacheTagsForForCategory(): void } } QUERY; - $request = $this->prepareRequest($query); - $response = $this->graphqlController->dispatch($request); + $response = $this->dispatchGraphQlGETRequest(['query' => $query]); $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); $actualCacheTags = explode(',', $response->getHeader('X-Magento-Tags')->getFieldValue()); - $expectedCacheTags = ['cat_c','cat_c_' . $categoryId,'FPC']; + $expectedCacheTags = ['cat_c','cat_c_' . $categoryId, 'FPC']; $this->assertEquals($expectedCacheTags, $actualCacheTags); } } diff --git a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/DeepNestedCategoriesAndProductsTest.php b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/DeepNestedCategoriesAndProductsTest.php index 746b37a88770a..6228feae37c15 100644 --- a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/DeepNestedCategoriesAndProductsTest.php +++ b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/DeepNestedCategoriesAndProductsTest.php @@ -9,7 +9,6 @@ use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Api\CategoryRepositoryInterface; -use Magento\Framework\App\Request\Http; use Magento\GraphQlCache\Controller\AbstractGraphqlCacheTest; /** @@ -20,24 +19,11 @@ */ class DeepNestedCategoriesAndProductsTest extends AbstractGraphqlCacheTest { - /** @var \Magento\GraphQl\Controller\GraphQl */ - private $graphql; - - /** - * @inheritdoc - */ - protected function setUp(): void - { - parent::setUp(); - $this->graphql = $this->objectManager->get(\Magento\GraphQl\Controller\GraphQl::class); - } - /** * Test cache tags and debug header for deep nested queries involving category and products * * @magentoCache all enabled * @magentoDataFixture Magento/Catalog/_files/product_in_multiple_categories.php - * */ public function testDispatchForCacheHeadersOnDeepNestedQueries(): void { @@ -83,15 +69,18 @@ public function testDispatchForCacheHeadersOnDeepNestedQueries(): void $productIdsFromCategory = $category->getProductCollection()->getAllIds(); foreach ($productIdsFromCategory as $productId) { + // phpcs:ignore Magento2.Performance.ForeachArrayMerge $resolvedCategoryIds = array_merge( $resolvedCategoryIds, $productRepository->getById($productId)->getCategoryIds() ); } + // phpcs:ignore Magento2.Performance.ForeachArrayMerge $resolvedCategoryIds = array_merge($resolvedCategoryIds, [$baseCategoryId]); foreach ($resolvedCategoryIds as $categoryId) { $category = $categoryRepository->get($categoryId); + // phpcs:ignore Magento2.Performance.ForeachArrayMerge $productIdsFromCategory= array_merge( $productIdsFromCategory, $category->getProductCollection()->getAllIds() @@ -102,14 +91,15 @@ public function testDispatchForCacheHeadersOnDeepNestedQueries(): void $uniqueCategoryIds = array_unique($resolvedCategoryIds); $expectedCacheTags = ['cat_c', 'cat_p', 'FPC']; foreach ($uniqueProductIds as $uniqueProductId) { - $expectedCacheTags = array_merge($expectedCacheTags, ['cat_p_'.$uniqueProductId]); + // phpcs:ignore Magento2.Performance.ForeachArrayMerge + $expectedCacheTags = array_merge($expectedCacheTags, ['cat_p_' . $uniqueProductId]); } foreach ($uniqueCategoryIds as $uniqueCategoryId) { - $expectedCacheTags = array_merge($expectedCacheTags, ['cat_c_'.$uniqueCategoryId]); + // phpcs:ignore Magento2.Performance.ForeachArrayMerge + $expectedCacheTags = array_merge($expectedCacheTags, ['cat_c_' . $uniqueCategoryId]); } - $request = $this->prepareRequest($query); - $response = $this->graphql->dispatch($request); + $response = $this->dispatchGraphQlGETRequest(['query' => $query]); $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); $actualCacheTags = explode(',', $response->getHeader('X-Magento-Tags')->getFieldValue()); $this->assertEmpty( diff --git a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/ProductsCacheTest.php b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/ProductsCacheTest.php index 335067f8408df..038a8c7255815 100644 --- a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/ProductsCacheTest.php +++ b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/ProductsCacheTest.php @@ -8,7 +8,6 @@ namespace Magento\GraphQlCache\Controller\Catalog; use Magento\Catalog\Api\ProductRepositoryInterface; -use Magento\GraphQl\Controller\GraphQl; use Magento\GraphQlCache\Controller\AbstractGraphqlCacheTest; /** @@ -20,26 +19,12 @@ */ class ProductsCacheTest extends AbstractGraphqlCacheTest { - /** - * @var GraphQl - */ - private $graphqlController; - - /** - * @inheritdoc - */ - protected function setUp(): void - { - parent::setUp(); - $this->graphqlController = $this->objectManager->get(\Magento\GraphQl\Controller\GraphQl::class); - } - /** * Test request is dispatched and response is checked for debug headers and cache tags * * @magentoDataFixture Magento/Catalog/_files/product_simple_with_url_key.php */ - public function testToCheckRequestCacheTagsForProducts(): void + public function testRequestCacheTagsForProducts(): void { /** @var ProductRepositoryInterface $productRepository */ $productRepository = $this->objectManager->get(ProductRepositoryInterface::class); @@ -63,8 +48,7 @@ public function testToCheckRequestCacheTagsForProducts(): void } QUERY; - $request = $this->prepareRequest($query); - $response = $this->graphqlController->dispatch($request); + $response = $this->dispatchGraphQlGETRequest(['query' => $query]); $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); $actualCacheTags = explode(',', $response->getHeader('X-Magento-Tags')->getFieldValue()); $expectedCacheTags = ['cat_p', 'cat_p_' . $product->getId(), 'FPC']; @@ -74,7 +58,7 @@ public function testToCheckRequestCacheTagsForProducts(): void /** * Test request is checked for debug headers and no cache tags for not existing product */ - public function testToCheckRequestNoTagsForProducts(): void + public function testRequestNoTagsForNonExistingProducts(): void { $query = <<prepareRequest($query); - $response = $this->graphqlController->dispatch($request); + $response = $this->dispatchGraphQlGETRequest(['query' => $query]); $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); $actualCacheTags = explode(',', $response->getHeader('X-Magento-Tags')->getFieldValue()); $expectedCacheTags = ['FPC']; $this->assertEquals($expectedCacheTags, $actualCacheTags); } + + /** + * @magentoDataFixture Magento/Catalog/_files/product_simple_with_url_key.php + */ + public function testConsecutiveRequestsAreServedFromThePageCache(): void + { + $query + = <<dispatchGraphQlGETRequest(['query' => $query]); + $response2 = $this->dispatchGraphQlGETRequest(['query' => $query]); + + $this->assertEquals('MISS', $response1->getHeader('X-Magento-Cache-Debug')->getFieldValue()); + $this->assertEquals('HIT', $response2->getHeader('X-Magento-Cache-Debug')->getFieldValue()); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/product_simple_with_url_key.php + */ + public function testDifferentProductsRequestsUseDifferentPageCacheRecords(): void + { + $queryTemplate + = <<dispatchGraphQlGETRequest(['query' => sprintf($queryTemplate, 'simple1')]); + $responseProduct2 = $this->dispatchGraphQlGETRequest(['query' => sprintf($queryTemplate, 'simple2')]); + + $this->assertEquals('MISS', $responseProduct1->getHeader('X-Magento-Cache-Debug')->getFieldValue()); + $this->assertEquals('MISS', $responseProduct2->getHeader('X-Magento-Cache-Debug')->getFieldValue()); + } } diff --git a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Cms/BlockCacheTest.php b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Cms/BlockCacheTest.php index c9dca2a5a8372..bcc7c623eb18a 100644 --- a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Cms/BlockCacheTest.php +++ b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Cms/BlockCacheTest.php @@ -7,8 +7,9 @@ namespace Magento\GraphQlCache\Controller\Cms; +use Magento\Cms\Api\Data\BlockInterface; use Magento\Cms\Model\BlockRepository; -use Magento\GraphQl\Controller\GraphQl; +use Magento\Framework\App\Response\HttpInterface as HttpResponse; use Magento\GraphQlCache\Controller\AbstractGraphqlCacheTest; /** @@ -20,23 +21,27 @@ */ class BlockCacheTest extends AbstractGraphqlCacheTest { - /** - * @var GraphQl - */ - private $graphqlController; + private function assertPageCacheMissWithTagsForCmsBlock(HttpResponse $response, BlockInterface $block): void + { + $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); + $this->assertCmsBlockCacheTags($response, $block); + } - /** - * @inheritdoc - */ - protected function setUp(): void + private function assertPageCacheHitWithTagsForCmsBlock(HttpResponse $response, BlockInterface $block): void + { + $this->assertEquals('HIT', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); + $this->assertCmsBlockCacheTags($response, $block); + } + + private function assertCmsBlockCacheTags(HttpResponse $response, BlockInterface $block): void { - parent::setUp(); - $this->graphqlController = $this->objectManager->get(\Magento\GraphQl\Controller\GraphQl::class); + $expectedCacheTags = ['cms_b', 'cms_b_' . $block->getId(), 'cms_b_' . $block->getIdentifier(), 'FPC']; + $rawActualCacheTags = $response->getHeader('X-Magento-Tags')->getFieldValue(); + $actualCacheTags = explode(',', $rawActualCacheTags); + $this->assertEquals($expectedCacheTags, $actualCacheTags); } /** - * Test that the correct cache tags get added to request for cmsBlocks - * * @magentoDataFixture Magento/Cms/_files/block.php * @magentoDataFixture Magento/Cms/_files/blocks.php */ @@ -46,9 +51,9 @@ public function testCmsBlocksRequestHasCorrectTags(): void $blockRepository = $this->objectManager->get(BlockRepository::class); $block1Identifier = 'fixture_block'; - $block1 = $blockRepository->getById($block1Identifier); + $block1 = $blockRepository->getById($block1Identifier); $block2Identifier = 'enabled_block'; - $block2 = $blockRepository->getById($block2Identifier); + $block2 = $blockRepository->getById($block2Identifier); $queryBlock1 = <<prepareRequest($queryBlock1); - $response = $this->graphqlController->dispatch($request); - $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); - $expectedCacheTags = ['cms_b', 'cms_b_' . $block1->getId(), 'cms_b_' . $block1->getIdentifier(), 'FPC']; - $rawActualCacheTags = $response->getHeader('X-Magento-Tags')->getFieldValue(); - $actualCacheTags = explode(',', $rawActualCacheTags); - $this->assertEquals($expectedCacheTags, $actualCacheTags); + $response = $this->dispatchGraphQlGETRequest(['query' => $queryBlock1]); + $this->assertPageCacheMissWithTagsForCmsBlock($response, $block1); - // check to see that the second entity gets a miss when called the first time - $request = $this->prepareRequest($queryBlock2); - $response = $this->graphqlController->dispatch($request); - $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); - $expectedCacheTags = ['cms_b', 'cms_b_' . $block2->getId(), 'cms_b_' . $block2->getIdentifier(), 'FPC']; - $rawActualCacheTags = $response->getHeader('X-Magento-Tags')->getFieldValue(); - $actualCacheTags = explode(',', $rawActualCacheTags); - $this->assertEquals($expectedCacheTags, $actualCacheTags); + // check to see that the second entity gets a MISS when called the first time + $response = $this->dispatchGraphQlGETRequest(['query' => $queryBlock2]); + $this->assertPageCacheMissWithTagsForCmsBlock($response, $block2); // check to see that the first entity gets a HIT when called the second time - $request = $this->prepareRequest($queryBlock1); - $response = $this->graphqlController->dispatch($request); - $this->assertEquals('HIT', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); - $expectedCacheTags = ['cms_b', 'cms_b_' . $block1->getId(), 'cms_b_' . $block1->getIdentifier(), 'FPC']; - $rawActualCacheTags = $response->getHeader('X-Magento-Tags')->getFieldValue(); - $actualCacheTags = explode(',', $rawActualCacheTags); - $this->assertEquals($expectedCacheTags, $actualCacheTags); + $response = $this->dispatchGraphQlGETRequest(['query' => $queryBlock1]); + $this->assertPageCacheHitWithTagsForCmsBlock($response, $block1); // check to see that the second entity gets a HIT when called the second time - $request = $this->prepareRequest($queryBlock2); - $response = $this->graphqlController->dispatch($request); - $this->assertEquals('HIT', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); - $expectedCacheTags = ['cms_b', 'cms_b_' . $block2->getId(), 'cms_b_' . $block2->getIdentifier(), 'FPC']; - $rawActualCacheTags = $response->getHeader('X-Magento-Tags')->getFieldValue(); - $actualCacheTags = explode(',', $rawActualCacheTags); - $this->assertEquals($expectedCacheTags, $actualCacheTags); + $response = $this->dispatchGraphQlGETRequest(['query' => $queryBlock2]); + $this->assertPageCacheHitWithTagsForCmsBlock($response, $block2); $block1->setTitle('something else that causes invalidation'); $blockRepository->save($block1); // check to see that the first entity gets a MISS and it was invalidated - $request = $this->prepareRequest($queryBlock1); - $response = $this->graphqlController->dispatch($request); - $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); - $expectedCacheTags = ['cms_b', 'cms_b_' . $block1->getId(), 'cms_b_' . $block1->getIdentifier(), 'FPC']; - $rawActualCacheTags = $response->getHeader('X-Magento-Tags')->getFieldValue(); - $actualCacheTags = explode(',', $rawActualCacheTags); - $this->assertEquals($expectedCacheTags, $actualCacheTags); + $response = $this->dispatchGraphQlGETRequest(['query' => $queryBlock1]); + $this->assertPageCacheMissWithTagsForCmsBlock($response, $block1); // check to see that the first entity gets a HIT when called the second time - $request = $this->prepareRequest($queryBlock1); - $response = $this->graphqlController->dispatch($request); - $this->assertEquals('HIT', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); - $expectedCacheTags = ['cms_b', 'cms_b_' . $block1->getId(), 'cms_b_' . $block1->getIdentifier(), 'FPC']; - $rawActualCacheTags = $response->getHeader('X-Magento-Tags')->getFieldValue(); - $actualCacheTags = explode(',', $rawActualCacheTags); - $this->assertEquals($expectedCacheTags, $actualCacheTags); + $response = $this->dispatchGraphQlGETRequest(['query' => $queryBlock1]); + $this->assertPageCacheHitWithTagsForCmsBlock($response, $block1); } } diff --git a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Cms/CmsPageCacheTest.php b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Cms/CmsPageCacheTest.php index 0248f870a5f11..60d84947d87c8 100644 --- a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Cms/CmsPageCacheTest.php +++ b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Cms/CmsPageCacheTest.php @@ -7,13 +7,14 @@ namespace Magento\GraphQlCache\Controller\Cms; +use Magento\Cms\Api\Data\PageInterface; use Magento\Cms\Model\GetPageByIdentifier; use Magento\Cms\Model\PageRepository; -use Magento\GraphQl\Controller\GraphQl; +use Magento\Framework\App\Response\HttpInterface as HttpResponse; use Magento\GraphQlCache\Controller\AbstractGraphqlCacheTest; /** - * Test caching works for CMS page + * Test caching works for CMS pages * * @magentoAppArea graphql * @magentoCache full_page enabled @@ -22,123 +23,34 @@ */ class CmsPageCacheTest extends AbstractGraphqlCacheTest { - /** - * @var GraphQl - */ - private $graphqlController; - - /** - * @inheritdoc - */ - protected function setUp(): void - { - parent::setUp(); - $this->graphqlController = $this->objectManager->get(\Magento\GraphQl\Controller\GraphQl::class); - } - - /** - * Test that the correct cache tags get added to request for cmsPage query - * - * @magentoDataFixture Magento/Cms/_files/pages.php - */ - public function testToCheckCmsPageRequestCacheTags(): void + private function assertPageCacheMissWithTagsForCmsPage(string $pageId, string $name, HttpResponse $response): void { - $cmsPage100 = $this->objectManager->get(GetPageByIdentifier::class)->execute('page100', 0); - $pageId100 = $cmsPage100->getId(); - - $cmsPageBlank = $this->objectManager->get(GetPageByIdentifier::class)->execute('page_design_blank', 0); - $pageIdBlank = $cmsPageBlank->getId(); - - $queryCmsPage100 = $this->getQuery($pageId100); - $queryCmsPageBlank = $this->getQuery($pageIdBlank); - - // check to see that the first entity gets a MISS when called the first time - $request = $this->prepareRequest($queryCmsPage100); - $response = $this->graphqlController->dispatch($request); - $this->assertEquals( - 'MISS', - $response->getHeader('X-Magento-Cache-Debug')->getFieldValue(), - "expected MISS on page page100 id {$queryCmsPage100}" - ); - $requestedCacheTags = explode(',', $response->getHeader('X-Magento-Tags')->getFieldValue()); - $expectedCacheTags = ['cms_p', 'cms_p_' .$pageId100 , 'FPC']; - $this->assertEquals($expectedCacheTags, $requestedCacheTags); - - // check to see that the second entity gets a miss when called the first time - $request = $this->prepareRequest($queryCmsPageBlank); - $response = $this->graphqlController->dispatch($request); $this->assertEquals( 'MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue(), - "expected MISS on page pageBlank id {$pageIdBlank}" - ); - $requestedCacheTags = explode(',', $response->getHeader('X-Magento-Tags')->getFieldValue()); - $expectedCacheTags = ['cms_p', 'cms_p_' .$pageIdBlank , 'FPC']; - $this->assertEquals($expectedCacheTags, $requestedCacheTags); - - // check to see that the first entity gets a HIT when called the second time - $request = $this->prepareRequest($queryCmsPage100); - $response = $this->graphqlController->dispatch($request); - $this->assertEquals( - 'HIT', - $response->getHeader('X-Magento-Cache-Debug')->getFieldValue(), - "expected HIT on page page100 id {$queryCmsPage100}" - ); - $requestedCacheTags = explode(',', $response->getHeader('X-Magento-Tags')->getFieldValue()); - $expectedCacheTags = ['cms_p', 'cms_p_' .$pageId100 , 'FPC']; - $this->assertEquals($expectedCacheTags, $requestedCacheTags); - - // check to see that the second entity gets a HIT when called the second time - $request = $this->prepareRequest($queryCmsPageBlank); - $response = $this->graphqlController->dispatch($request); - $this->assertEquals( - 'HIT', - $response->getHeader('X-Magento-Cache-Debug')->getFieldValue(), - "expected HIT on page pageBlank id {$pageIdBlank}" + "expected MISS on page {$name} id {$pageId}" ); - $requestedCacheTags = explode(',', $response->getHeader('X-Magento-Tags')->getFieldValue()); - $expectedCacheTags = ['cms_p', 'cms_p_' .$pageIdBlank , 'FPC']; - $this->assertEquals($expectedCacheTags, $requestedCacheTags); - - /** @var PageRepository $pageRepository */ - $pageRepository = $this->objectManager->get(PageRepository::class); - - $page = $pageRepository->getById($pageId100); - $page->setTitle('something else that causes invalidation'); - $pageRepository->save($page); - - // check to see that the first entity gets a MISS and it was invalidated - $request = $this->prepareRequest($queryCmsPage100); - $response = $this->graphqlController->dispatch($request); - $this->assertEquals( - 'MISS', - $response->getHeader('X-Magento-Cache-Debug')->getFieldValue(), - "expected MISS on page page100 id {$queryCmsPage100}" - ); - $requestedCacheTags = explode(',', $response->getHeader('X-Magento-Tags')->getFieldValue()); - $expectedCacheTags = ['cms_p', 'cms_p_' .$pageId100 , 'FPC']; - $this->assertEquals($expectedCacheTags, $requestedCacheTags); + $this->assertCmsPageCacheTags($pageId, $response); + } - // check to see that the first entity gets a HIT when called the second time - $request = $this->prepareRequest($queryCmsPage100); - $response = $this->graphqlController->dispatch($request); + private function assertPageCacheHitWithTagsForCmsPage(string $pageId, string $name, HttpResponse $response): void + { $this->assertEquals( 'HIT', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue(), - "expected MISS on page page100 id {$queryCmsPage100}" + "expected HIT on page {$name} id {$pageId}" ); + $this->assertCmsPageCacheTags($pageId, $response); + } + + private function assertCmsPageCacheTags(string $pageId, HttpResponse $response): void + { $requestedCacheTags = explode(',', $response->getHeader('X-Magento-Tags')->getFieldValue()); - $expectedCacheTags = ['cms_p', 'cms_p_' .$pageId100 , 'FPC']; + $expectedCacheTags = ['cms_p', 'cms_p_' . $pageId, 'FPC']; $this->assertEquals($expectedCacheTags, $requestedCacheTags); } - /** - * Get cms query - * - * @param string $id - * @return string - */ - private function getQuery(string $id) : string + private function buildQuery(string $id): string { $queryCmsPage = <<objectManager->get(PageRepository::class); + $page = $pageRepository->getById($pageId100); + $page->setTitle($newTitle); + $pageRepository->save($page); + } + + /** + * @magentoDataFixture Magento/Cms/_files/pages.php + */ + public function testCmsPageRequestCacheTags(): void + { + /** @var PageInterface $cmsPage100 */ + $cmsPage100 = $this->objectManager->get(GetPageByIdentifier::class)->execute('page100', 0); + $pageId100 = (string) $cmsPage100->getId(); + + /** @var PageInterface $cmsPageBlank */ + $cmsPageBlank = $this->objectManager->get(GetPageByIdentifier::class)->execute('page_design_blank', 0); + $pageIdBlank = (string) $cmsPageBlank->getId(); + + $queryCmsPage100 = $this->buildQuery($pageId100); + $queryCmsPageBlank = $this->buildQuery($pageIdBlank); + + // check to see that the first entity gets a MISS when called the first time + $response = $this->dispatchGraphQlGETRequest(['query' => $queryCmsPage100]); + $this->assertPageCacheMissWithTagsForCmsPage($pageId100, 'page100', $response); + + // check to see that the second entity gets a MISS when called the first time + $response = $this->dispatchGraphQlGETRequest(['query' => $queryCmsPageBlank]); + $this->assertPageCacheMissWithTagsForCmsPage($pageIdBlank, 'pageBlank', $response); + + // check to see that the first entity gets a HIT when called the second time + $response = $this->dispatchGraphQlGETRequest(['query' => $queryCmsPage100]); + $this->assertPageCacheHitWithTagsForCmsPage($pageId100, 'page100', $response); + + // check to see that the second entity gets a HIT when called the second time + $response = $this->dispatchGraphQlGETRequest(['query' => $queryCmsPageBlank]); + $this->assertPageCacheHitWithTagsForCmsPage($pageIdBlank, 'pageBlank', $response); + + // invalidate first entity + $this->updateCmsPageTitle($pageId100, 'something else that causes invalidation'); + + // check to see that the second entity gets a HIT to confirm only the first was invalidated + $response = $this->dispatchGraphQlGETRequest(['query' => $queryCmsPageBlank]); + $this->assertPageCacheHitWithTagsForCmsPage($pageIdBlank, 'pageBlank', $response); + + // check to see that the first entity gets a MISS because it was invalidated + $response = $this->dispatchGraphQlGETRequest(['query' => $queryCmsPage100]); + $this->assertPageCacheMissWithTagsForCmsPage($pageId100, 'page100', $response); + } } diff --git a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/UrlRewrite/AllEntitiesUrlResolverCacheTest.php b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/UrlRewrite/AllEntitiesUrlResolverCacheTest.php index 7accb1d7d0b26..81a4988b81935 100644 --- a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/UrlRewrite/AllEntitiesUrlResolverCacheTest.php +++ b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/UrlRewrite/AllEntitiesUrlResolverCacheTest.php @@ -9,7 +9,7 @@ use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Product; -use Magento\GraphQl\Controller\GraphQl; +use Magento\Framework\App\Response\HttpInterface as HttpResponse; use Magento\GraphQlCache\Controller\AbstractGraphqlCacheTest; use Magento\UrlRewrite\Model\UrlFinderInterface; use Magento\Cms\Api\Data\PageInterface; @@ -24,155 +24,153 @@ */ class AllEntitiesUrlResolverCacheTest extends AbstractGraphqlCacheTest { - /** - * @var GraphQl - */ - private $graphqlController; + private function assertCacheMISSWithTagsForCategory(string $categoryId, HttpResponse $response): void + { + $this->assertCacheMISS($response); + $this->assertCacheTags($categoryId, 'cat_c', $response); + } - /** - * @inheritdoc - */ - protected function setUp(): void + private function assertCacheMISSWithTagsForProduct(string $productId, HttpResponse $response): void + { + $this->assertCacheMISS($response); + $this->assertCacheTags($productId, 'cat_p', $response); + } + + private function assertCacheMISSWithTagsForCmsPage(string $pageId, HttpResponse $response): void + { + $this->assertCacheMISS($response); + $this->assertCacheTags($pageId, 'cms_p', $response); + } + + private function assertCacheHITWithTagsForCategory(string $categoryId, HttpResponse $response): void { - parent::setUp(); - $this->graphqlController = $this->objectManager->get(GraphQl::class); + $this->assertCacheHIT($response); + $this->assertCacheTags($categoryId, 'cat_c', $response); + } + + private function assertCacheHITWithTagsForProduct(string $productId, HttpResponse $response): void + { + $this->assertCacheHIT($response); + $this->assertCacheTags($productId, 'cat_p', $response); + } + + private function assertCacheHITWithTagsForCmsPage(string $pageId, HttpResponse $response): void + { + $this->assertCacheHIT($response); + $this->assertCacheTags($pageId, 'cms_p', $response); + } + + private function assertCacheMISS(HttpResponse $response): void + { + $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); + } + + private function assertCacheHIT(HttpResponse $response): void + { + $this->assertEquals('HIT', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); + } + + private function assertCacheTags(string $entityId, string $entityCacheTag, HttpResponse $response) + { + $expectedCacheTags = [$entityCacheTag, $entityCacheTag . '_' . $entityId, 'FPC']; + $rawActualCacheTags = $response->getHeader('X-Magento-Tags')->getFieldValue(); + $actualCacheTags = explode(',', $rawActualCacheTags); + $this->assertEquals($expectedCacheTags, $actualCacheTags); + } + + private function buildQuery(string $requestPath): string + { + $resolverQuery = <<objectManager->get(ProductRepositoryInterface::class); /** @var Product $product */ $product = $productRepository->get($productSku, false, null, true); - $storeId = $product->getStoreId(); + $storeId = (string) $product->getStoreId(); /** @var UrlFinderInterface $urlFinder */ - $urlFinder = $this->objectManager->get(UrlFinderInterface::class); - $actualUrls = $urlFinder->findOneByData( + $urlFinder = $this->objectManager->get(UrlFinderInterface::class); + $actualUrls = $urlFinder->findOneByData( [ 'request_path' => $categoryUrlKey, 'store_id' => $storeId ] ); - $categoryId = $actualUrls->getEntityId(); - $categoryQuery = $this->getQuery($categoryUrlKey); + $categoryId = (string) $actualUrls->getEntityId(); + $categoryQuery = $this->buildQuery($categoryUrlKey); - $productQuery = $this->getQuery($productUrlKey); + $productQuery = $this->buildQuery($productUrlKey); /** @var GetPageByIdentifierInterface $page */ $page = $this->objectManager->get(GetPageByIdentifierInterface::class); /** @var PageInterface $cmsPage */ - $cmsPage = $page->execute('page100', 0); - $cmsPageId = $cmsPage->getId(); + $cmsPage = $page->execute('page100', 0); + $cmsPageId = (string) $cmsPage->getId(); $requestPath = $cmsPage->getIdentifier(); - $pageQuery = $this->getQuery($requestPath); + $pageQuery = $this->buildQuery($requestPath); // query category for MISS - $request = $this->prepareRequest($categoryQuery); - $response = $this->graphqlController->dispatch($request); - $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); - $expectedCacheTags = ['cat_c','cat_c_' . $categoryId, 'FPC']; - $rawActualCacheTags = $response->getHeader('X-Magento-Tags')->getFieldValue(); - $actualCacheTags = explode(',', $rawActualCacheTags); - $this->assertEquals($expectedCacheTags, $actualCacheTags); + $response = $this->dispatchGraphQlGETRequest(['query' => $categoryQuery]); + $this->assertCacheMISSWithTagsForCategory($categoryId, $response); // query product for MISS - $request = $this->prepareRequest($productQuery); - $response = $this->graphqlController->dispatch($request); - $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); - $expectedCacheTags = ['cat_p', 'cat_p_' . $product->getId(), 'FPC']; - $rawActualCacheTags = $response->getHeader('X-Magento-Tags')->getFieldValue(); - $actualCacheTags = explode(',', $rawActualCacheTags); - $this->assertEquals($expectedCacheTags, $actualCacheTags); + $response = $this->dispatchGraphQlGETRequest(['query' => $productQuery]); + $this->assertCacheMISSWithTagsForProduct((string) $product->getId(), $response); // query page for MISS - $request = $this->prepareRequest($pageQuery); - $response = $this->graphqlController->dispatch($request); - $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); - $expectedCacheTags = ['cms_p','cms_p_' . $cmsPageId,'FPC']; - $rawActualCacheTags = $response->getHeader('X-Magento-Tags')->getFieldValue(); - $actualCacheTags = explode(',', $rawActualCacheTags); - $this->assertEquals($expectedCacheTags, $actualCacheTags); + $response = $this->dispatchGraphQlGETRequest(['query' => $pageQuery]); + $this->assertCacheMISSWithTagsForCmsPage($cmsPageId, $response); // query category for HIT - $request = $this->prepareRequest($categoryQuery); - $response = $this->graphqlController->dispatch($request); - $this->assertEquals('HIT', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); - $expectedCacheTags = ['cat_c','cat_c_' . $categoryId, 'FPC']; - $rawActualCacheTags = $response->getHeader('X-Magento-Tags')->getFieldValue(); - $actualCacheTags = explode(',', $rawActualCacheTags); - $this->assertEquals($expectedCacheTags, $actualCacheTags); + $response = $this->dispatchGraphQlGETRequest(['query' => $categoryQuery]); + $this->assertCacheHITWithTagsForCategory($categoryId, $response); // query product for HIT - $request = $this->prepareRequest($productQuery); - $response = $this->graphqlController->dispatch($request); - $this->assertEquals('HIT', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); - $expectedCacheTags = ['cat_p', 'cat_p_' . $product->getId(), 'FPC']; - $rawActualCacheTags = $response->getHeader('X-Magento-Tags')->getFieldValue(); - $actualCacheTags = explode(',', $rawActualCacheTags); - $this->assertEquals($expectedCacheTags, $actualCacheTags); + $response = $this->dispatchGraphQlGETRequest(['query' => $productQuery]); + $this->assertCacheHITWithTagsForProduct((string) $product->getId(), $response); - // query product for HIT - $request = $this->prepareRequest($pageQuery); - $response = $this->graphqlController->dispatch($request); - $this->assertEquals('HIT', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); - $expectedCacheTags = ['cms_p','cms_p_' . $cmsPageId,'FPC']; - $rawActualCacheTags = $response->getHeader('X-Magento-Tags')->getFieldValue(); - $actualCacheTags = explode(',', $rawActualCacheTags); - $this->assertEquals($expectedCacheTags, $actualCacheTags); + // query page for HIT + $response = $this->dispatchGraphQlGETRequest(['query' => $pageQuery]); + $this->assertCacheHITWithTagsForCmsPage($cmsPageId, $response); $product->setUrlKey('something-else-that-invalidates-the-cache'); $productRepository->save($product); - $productQuery = $this->getQuery('something-else-that-invalidates-the-cache.html'); + $productQuery = $this->buildQuery('something-else-that-invalidates-the-cache.html'); // query category for MISS - $request = $this->prepareRequest($categoryQuery); - $response = $this->graphqlController->dispatch($request); - $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); - $expectedCacheTags = ['cat_c','cat_c_' . $categoryId, 'FPC']; - $rawActualCacheTags = $response->getHeader('X-Magento-Tags')->getFieldValue(); - $actualCacheTags = explode(',', $rawActualCacheTags); - $this->assertEquals($expectedCacheTags, $actualCacheTags); + $response = $this->dispatchGraphQlGETRequest(['query' => $categoryQuery]); + $this->assertCacheMISSWithTagsForCategory($categoryId, $response); - // query product for HIT - $request = $this->prepareRequest($productQuery); - $response = $this->graphqlController->dispatch($request); - $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); - $expectedCacheTags = ['cat_p', 'cat_p_' . $product->getId(), 'FPC']; - $rawActualCacheTags = $response->getHeader('X-Magento-Tags')->getFieldValue(); - $actualCacheTags = explode(',', $rawActualCacheTags); - $this->assertEquals($expectedCacheTags, $actualCacheTags); - } + // query product for MISS + $response = $this->dispatchGraphQlGETRequest(['query' => $productQuery]); + $this->assertCacheMISSWithTagsForProduct((string) $product->getId(), $response); - /** - * Get urlResolver query - * - * @param string $id - * @return string - */ - private function getQuery(string $requestPath) : string - { - $resolverQuery = <<dispatchGraphQlGETRequest(['query' => $pageQuery]); + $this->assertCacheHITWithTagsForCmsPage($cmsPageId, $response); } } diff --git a/lib/internal/Magento/Framework/App/Cache/Frontend/Pool.php b/lib/internal/Magento/Framework/App/Cache/Frontend/Pool.php index 30cb4a67b9edd..a4c9fb4380651 100644 --- a/lib/internal/Magento/Framework/App/Cache/Frontend/Pool.php +++ b/lib/internal/Magento/Framework/App/Cache/Frontend/Pool.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Framework\App\Cache\Frontend; use Magento\Framework\App\Cache\Type\FrontendPool; @@ -55,6 +56,7 @@ public function __construct( /** * Create instances of every cache frontend known to the system. + * * Method is to be used for delayed initialization of the iterator. * * @return void @@ -77,18 +79,21 @@ protected function _initialize() protected function _getCacheSettings() { /* - * Merging is intentionally implemented through array_merge() instead of array_replace_recursive() - * to avoid "inheritance" of the default settings that become irrelevant as soon as cache storage type changes + * Merging is intentionally implemented through array_replace_recursive() instead of array_merge(), because even + * though some settings may become irrelevant when the cache storage type is changed, they don't do any harm + * and can be overwritten when needed. + * Also array_merge leads to unexpected behavior, for for example by dropping the + * default cache_dir setting from di.xml when a cache id_prefix is configured in app/etc/env.php. */ $cacheInfo = $this->deploymentConfig->getConfigData(FrontendPool::KEY_CACHE); if (null !== $cacheInfo) { - return array_merge($this->_frontendSettings, $cacheInfo[FrontendPool::KEY_FRONTEND_CACHE]); + return array_replace_recursive($this->_frontendSettings, $cacheInfo[FrontendPool::KEY_FRONTEND_CACHE]); } return $this->_frontendSettings; } /** - * {@inheritdoc} + * @inheritdoc * * @return \Magento\Framework\Cache\FrontendInterface */ @@ -99,7 +104,7 @@ public function current() } /** - * {@inheritdoc} + * @inheritdoc */ public function key() { @@ -108,7 +113,7 @@ public function key() } /** - * {@inheritdoc} + * @inheritdoc */ public function next() { @@ -117,7 +122,7 @@ public function next() } /** - * {@inheritdoc} + * @inheritdoc */ public function rewind() { @@ -126,7 +131,7 @@ public function rewind() } /** - * {@inheritdoc} + * @inheritdoc */ public function valid() { diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Cache/Frontend/PoolTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Cache/Frontend/PoolTest.php index bfa37311884ba..5ec3dd658737b 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Cache/Frontend/PoolTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Cache/Frontend/PoolTest.php @@ -8,6 +8,9 @@ use Magento\Framework\App\Cache\Frontend\Pool; use Magento\Framework\App\Cache\Type\FrontendPool; +/** + * And another docblock to make the sniff shut up. + */ class PoolTest extends \PHPUnit\Framework\TestCase { /** @@ -111,25 +114,38 @@ public function testInitializationParams( public function initializationParamsDataProvider() { return [ - 'default frontend, default settings' => [ + 'no deployment config, default settings' => [ ['frontend' => []], [Pool::DEFAULT_FRONTEND_ID => ['default_option' => 'default_value']], ['default_option' => 'default_value'], ], - 'default frontend, overridden settings' => [ + 'deployment config, default settings' => [ + ['frontend' => [Pool::DEFAULT_FRONTEND_ID => ['configured_option' => 'configured_value']]], + [Pool::DEFAULT_FRONTEND_ID => ['default_option' => 'default_value']], + ['configured_option' => 'configured_value', 'default_option' => 'default_value'], + ], + 'deployment config, overridden settings' => [ ['frontend' => [Pool::DEFAULT_FRONTEND_ID => ['configured_option' => 'configured_value']]], - [Pool::DEFAULT_FRONTEND_ID => ['ignored_option' => 'ignored_value']], + [Pool::DEFAULT_FRONTEND_ID => ['configured_option' => 'default_value']], ['configured_option' => 'configured_value'], ], - 'custom frontend, default settings' => [ - ['frontend' => []], + 'deployment config, default settings, overridden settings' => [ + ['frontend' => [Pool::DEFAULT_FRONTEND_ID => ['configured_option' => 'configured_value']]], + [Pool::DEFAULT_FRONTEND_ID => [ + 'configured_option' => 'default_value', + 'default_setting' => 'default_value' + ]], + ['configured_option' => 'configured_value', 'default_setting' => 'default_value'], + ], + 'custom deployent config, default settings' => [ + ['frontend' => ['custom' => ['configured_option' => 'configured_value']]], ['custom' => ['default_option' => 'default_value']], - ['default_option' => 'default_value'], + ['configured_option' => 'configured_value', 'default_option' => 'default_value'], ], - 'custom frontend, overridden settings' => [ + 'custom deployent config, default settings, overridden settings' => [ ['frontend' => ['custom' => ['configured_option' => 'configured_value']]], - ['custom' => ['ignored_option' => 'ignored_value']], - ['configured_option' => 'configured_value'], + ['custom' => ['default_option' => 'default_value', 'configured_option' => 'default_value']], + ['configured_option' => 'configured_value', 'default_option' => 'default_value'], ] ]; }