getProductQuery($productSku); // Obtain the X-Magento-Cache-Id from the response which will be used as the cache key $response = $this->graphQlQueryWithResponseHeaders($query); $this->assertArrayHasKey(CacheIdCalculator::CACHE_ID_HEADER, $response['headers']); $cacheId = $response['headers'][CacheIdCalculator::CACHE_ID_HEADER]; // Verify we obtain a cache MISS the first time we search the cache using this X-Magento-Cache-Id $this->assertCacheMissAndReturnResponse($query, [CacheIdCalculator::CACHE_ID_HEADER => $cacheId]); // Verify we obtain a cache HIT the second time around for this X-Magento-Cache-Id $this->assertCacheHitAndReturnResponse($query, [CacheIdCalculator::CACHE_ID_HEADER => $cacheId]); } /** * Test that changing the Store header returns different cache results. * * @magentoConfigFixture default/system/full_page_cache/caching_application 2 * @magentoApiDataFixture Magento/Store/_files/second_store.php * @magentoApiDataFixture Magento/Catalog/_files/multiple_products.php */ public function testCacheResultForGuestWithStoreHeader() { $productSku = 'simple2'; $query = $this->getProductQuery($productSku); // Verify caching works as expected without a Store header $response = $this->graphQlQueryWithResponseHeaders($query); $this->assertArrayHasKey(CacheIdCalculator::CACHE_ID_HEADER, $response['headers']); $defaultStoreCacheId = $response['headers'][CacheIdCalculator::CACHE_ID_HEADER]; // Verify we obtain a cache MISS the first time we search the cache using this X-Magento-Cache-Id $this->assertCacheMissAndReturnResponse($query, [CacheIdCalculator::CACHE_ID_HEADER => $defaultStoreCacheId]); // Verify we obtain a cache HIT the second time we search the cache using this X-Magento-Cache-Id $this->assertCacheHitAndReturnResponse($query, [CacheIdCalculator::CACHE_ID_HEADER => $defaultStoreCacheId]); // Obtain a new X-Magento-Cache-Id using after updating the Store header $secondStoreResponse = $this->graphQlQueryWithResponseHeaders( $query, [], '', [ CacheIdCalculator::CACHE_ID_HEADER => $defaultStoreCacheId, 'Store' => 'fixture_second_store' ] ); $secondStoreCacheId = $secondStoreResponse['headers'][CacheIdCalculator::CACHE_ID_HEADER]; // Verify we obtain a cache MISS the first time we search by this X-Magento-Cache-Id $this->assertCacheMissAndReturnResponse($query, [ CacheIdCalculator::CACHE_ID_HEADER => $secondStoreCacheId, 'Store' => 'fixture_second_store' ]); // Verify we obtain a cache HIT the second time around with the Store header $this->assertCacheHitAndReturnResponse($query, [ CacheIdCalculator::CACHE_ID_HEADER => $secondStoreCacheId, 'Store' => 'fixture_second_store' ]); // Verify we still obtain a cache HIT for the default store $this->assertCacheHitAndReturnResponse($query, [CacheIdCalculator::CACHE_ID_HEADER => $defaultStoreCacheId]); } /** * Test that changing the Content-Currency header returns different cache results. * * @magentoConfigFixture default/system/full_page_cache/caching_application 2 * @magentoApiDataFixture Magento/Store/_files/multiple_currencies.php * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php */ public function testCacheResultForGuestWithCurrencyHeader() { $productSku = 'simple_product'; $query = $this->getProductQuery($productSku); // Verify caching works as expected without a Content-Currency header $response = $this->graphQlQueryWithResponseHeaders($query); $this->assertArrayHasKey(CacheIdCalculator::CACHE_ID_HEADER, $response['headers']); $defaultCurrencyCacheId = $response['headers'][CacheIdCalculator::CACHE_ID_HEADER]; // Verify we obtain a cache MISS the first time we search the cache using this X-Magento-Cache-Id $this->assertCacheMissAndReturnResponse( $query, [CacheIdCalculator::CACHE_ID_HEADER => $defaultCurrencyCacheId] ); // Verify we obtain a cache HIT the second time we search the cache using this X-Magento-Cache-Id $this->assertCacheHitAndReturnResponse($query, [CacheIdCalculator::CACHE_ID_HEADER => $defaultCurrencyCacheId]); // Obtain a new X-Magento-Cache-Id using after updating the Content-Currency header $secondCurrencyResponse = $this->graphQlQueryWithResponseHeaders( $query, [], '', [ CacheIdCalculator::CACHE_ID_HEADER => $defaultCurrencyCacheId, 'Content-Currency' => 'EUR' ] ); $secondCurrencyCacheId = $secondCurrencyResponse['headers'][CacheIdCalculator::CACHE_ID_HEADER]; // Verify we obtain a cache MISS the first time we search by this X-Magento-Cache-Id $this->assertCacheMissAndReturnResponse($query, [ CacheIdCalculator::CACHE_ID_HEADER => $secondCurrencyCacheId, 'Content-Currency' => 'EUR' ]); // Verify we obtain a cache HIT the second time around with the changed currency header $this->assertCacheHitAndReturnResponse($query, [ CacheIdCalculator::CACHE_ID_HEADER => $secondCurrencyCacheId, 'Content-Currency' => 'EUR' ]); // Verify we still obtain a cache HIT for the default currency ( no Content-Currency header) $this->assertCacheHitAndReturnResponse($query, [CacheIdCalculator::CACHE_ID_HEADER => $defaultCurrencyCacheId]); } /** * Test that a request with a cache id which differs from the one returned by the response is not cacheable. * * @magentoConfigFixture default/system/full_page_cache/caching_application 2 * @magentoApiDataFixture Magento/Store/_files/second_store.php * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php */ public function testCacheResultForGuestWithOutdatedCacheId() { $productSku = 'simple_product'; $query = $this->getProductQuery($productSku); // Verify caching with no headers in the request $response = $this->graphQlQueryWithResponseHeaders($query); $this->assertArrayHasKey(CacheIdCalculator::CACHE_ID_HEADER, $response['headers']); $defaultCacheId = $response['headers'][CacheIdCalculator::CACHE_ID_HEADER]; $this->assertCacheMissAndReturnResponse($query, [CacheIdCalculator::CACHE_ID_HEADER => $defaultCacheId]); $this->assertCacheHitAndReturnResponse($query, [CacheIdCalculator::CACHE_ID_HEADER => $defaultCacheId]); // Obtain a new X-Magento-Cache-Id using after updating the request with Store header $responseWithStore = $this->graphQlQueryWithResponseHeaders( $query, [], '', [ CacheIdCalculator::CACHE_ID_HEADER => $defaultCacheId, 'Store' => 'fixture_second_store' ] ); $storeCacheId = $responseWithStore['headers'][CacheIdCalculator::CACHE_ID_HEADER]; // Verify we still get a cache MISS since the cache id in the request doesn't match the cache id from response $this->assertCacheMissAndReturnResponse($query, [ CacheIdCalculator::CACHE_ID_HEADER => $defaultCacheId, 'Store' => 'fixture_second_store' ]); // Verify we get a cache MISS first time with the updated cache id $this->assertCacheMissAndReturnResponse($query, [ CacheIdCalculator::CACHE_ID_HEADER => $storeCacheId, 'Store' => 'fixture_second_store' ]); // Verify we obtain a cache HIT second time around with the updated cache id $this->assertCacheHitAndReturnResponse($query, [ CacheIdCalculator::CACHE_ID_HEADER => $storeCacheId, 'Store' => 'fixture_second_store' ]); } /** * Test that we obtain cache MISS/HIT when expected for a customer. * * @magentoConfigFixture default/system/full_page_cache/caching_application 2 * @magentoApiDataFixture Magento/Customer/_files/customer.php * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php */ public function testCacheResultForCustomer() { $productSku = 'simple_product'; $query = $this->getProductQuery($productSku); $email = 'customer@example.com'; $password = 'password'; $generateToken = $this->generateCustomerToken($email, $password); $tokenResponse = $this->graphQlMutationWithResponseHeaders($generateToken); // Obtain the X-Magento-Cache-id from the response and authorization token - customer logs in $this->assertArrayHasKey(CacheIdCalculator::CACHE_ID_HEADER, $tokenResponse['headers']); $cacheIdCustomer = $tokenResponse['headers'][CacheIdCalculator::CACHE_ID_HEADER]; $customerToken = $tokenResponse['body']['generateCustomerToken']['token']; // Verify we obtain cache MISS the first time we search by this X-Magento-Cache-Id $this->assertCacheMissAndReturnResponse($query, [ CacheIdCalculator::CACHE_ID_HEADER => $cacheIdCustomer, 'Authorization' => 'Bearer ' . $customerToken ]); // Verify we obtain cache HIT second time using the same X-Magento-Cache-Id $this->assertCacheHitAndReturnResponse($query, [ CacheIdCalculator::CACHE_ID_HEADER => $cacheIdCustomer, 'Authorization' => 'Bearer ' . $customerToken ]); $revokeTokenQuery = $this->revokeCustomerToken(); // Verify that once customer logs out, X-Magento-Cache-Id will be that of an unregistered user $revokeTokenResponse = $this->graphQlMutationWithResponseHeaders( $revokeTokenQuery, [], '', [ CacheIdCalculator::CACHE_ID_HEADER => $cacheIdCustomer, 'Authorization' => 'Bearer ' . $customerToken ] ); $cacheIdGuest = $revokeTokenResponse['headers'][CacheIdCalculator::CACHE_ID_HEADER]; $this->assertNotEquals($cacheIdCustomer, $cacheIdGuest); //Verify that omitting the Auth token doesn't send cached content for a logged-in customer $this->assertCacheMissAndReturnResponse($query, [CacheIdCalculator::CACHE_ID_HEADER => $cacheIdCustomer]); $this->assertCacheMissAndReturnResponse($query, [CacheIdCalculator::CACHE_ID_HEADER => $cacheIdCustomer]); } /** * Get product query * * @param string $productSku * @return string */ private function getProductQuery(string $productSku): string { $productQuery = <<