Issue #3225328 by mxr576, Berdir, longwave: Improve page performance by sorting cache contexts/tags on-demand

merge-requests/1141/head
catch 2021-08-27 12:36:31 +01:00
parent e4ce9936ea
commit 6951f4d77a
41 changed files with 176 additions and 151 deletions

View File

@ -28,8 +28,7 @@ class Cache {
*/
public static function mergeContexts(array ...$cache_contexts) {
$cache_contexts = array_unique(array_merge(...$cache_contexts));
assert(\Drupal::service('cache_contexts_manager')->assertValidTokens($cache_contexts));
sort($cache_contexts);
assert(\Drupal::service('cache_contexts_manager')->assertValidTokens($cache_contexts), sprintf('Failed to assert that "%s" are valid cache contexts.', implode(', ', $cache_contexts)));
return $cache_contexts;
}
@ -53,7 +52,6 @@ class Cache {
public static function mergeTags(array ...$cache_tags) {
$cache_tags = array_unique(array_merge(...$cache_tags));
assert(Inspector::assertAllStrings($cache_tags), 'Cache tags must be valid strings');
sort($cache_tags);
return $cache_tags;
}

View File

@ -23,6 +23,11 @@ class ContextCacheKeys extends CacheableMetadata {
* The cache context keys.
*/
public function __construct(array $keys) {
// Domain invariant: cache keys must be always sorted.
// Sorting keys warrants that different combination of the same keys
// generates the same cache cid.
// @see \Drupal\Core\Render\RenderCache::createCacheID()
sort($keys);
$this->keys = $keys;
}

View File

@ -159,8 +159,12 @@ class FinishResponseSubscriber implements EventSubscriberInterface {
// Expose the cache contexts and cache tags associated with this page in a
// X-Drupal-Cache-Contexts and X-Drupal-Cache-Tags header respectively.
$response_cacheability = $response->getCacheableMetadata();
$response->headers->set('X-Drupal-Cache-Tags', implode(' ', $response_cacheability->getCacheTags()));
$response->headers->set('X-Drupal-Cache-Contexts', implode(' ', $this->cacheContextsManager->optimizeTokens($response_cacheability->getCacheContexts())));
$cache_tags = $response_cacheability->getCacheTags();
sort($cache_tags);
$response->headers->set('X-Drupal-Cache-Tags', implode(' ', $cache_tags));
$cache_contexts = $this->cacheContextsManager->optimizeTokens($response_cacheability->getCacheContexts());
sort($cache_contexts);
$response->headers->set('X-Drupal-Cache-Contexts', implode(' ', $cache_contexts));
$max_age_message = $response_cacheability->getCacheMaxAge();
if ($max_age_message === 0) {
$max_age_message = '0 (Uncacheable)';

View File

@ -296,8 +296,8 @@ class BlockViewBuilderTest extends KernelTestBase {
// - the built render array;
$build = $this->getBlockRenderArray();
$this->assertSame($expected_keys, $build['#cache']['keys']);
$this->assertSame($expected_contexts, $build['#cache']['contexts']);
$this->assertSame($expected_tags, $build['#cache']['tags']);
$this->assertEqualsCanonicalizing($expected_contexts, $build['#cache']['contexts']);
$this->assertEqualsCanonicalizing($expected_tags, $build['#cache']['tags']);
$this->assertSame($expected_max_age, $build['#cache']['max-age']);
$this->assertFalse(isset($build['#create_placeholder']));
// - the rendered render array;
@ -307,9 +307,9 @@ class BlockViewBuilderTest extends KernelTestBase {
$cid = implode(':', $expected_keys) . ':' . implode(':', \Drupal::service('cache_contexts_manager')->convertTokensToKeys($final_cache_contexts)->getKeys());
$cache_item = $this->container->get('cache.render')->get($cid);
$this->assertNotEmpty($cache_item, 'The block render element has been cached with the expected cache ID.');
$this->assertSame(Cache::mergeTags($expected_tags, ['rendered']), $cache_item->tags);
$this->assertSame($final_cache_contexts, $cache_item->data['#cache']['contexts']);
$this->assertSame($expected_tags, $cache_item->data['#cache']['tags']);
$this->assertEqualsCanonicalizing(Cache::mergeTags($expected_tags, ['rendered']), $cache_item->tags);
$this->assertEqualsCanonicalizing($final_cache_contexts, $cache_item->data['#cache']['contexts']);
$this->assertEqualsCanonicalizing($expected_tags, $cache_item->data['#cache']['tags']);
$this->assertSame($expected_max_age, $cache_item->data['#cache']['max-age']);
$this->container->get('cache.render')->delete($cid);

View File

@ -92,8 +92,7 @@ class CommentDefaultFormatterCacheTagsTest extends EntityKernelTestBase {
'config:field.storage.comment.comment_body',
'config:user.settings',
];
sort($expected_cache_tags);
$this->assertEquals($expected_cache_tags, $build['#cache']['tags']);
$this->assertEqualsCanonicalizing($expected_cache_tags, $build['#cache']['tags']);
// Create a comment on that entity. Comment loading requires that the uid
// also exists in the {users} table.
@ -140,8 +139,7 @@ class CommentDefaultFormatterCacheTagsTest extends EntityKernelTestBase {
'config:field.storage.comment.comment_body',
'config:user.settings',
];
sort($expected_cache_tags);
$this->assertEquals($expected_cache_tags, $build['#cache']['tags']);
$this->assertEqualsCanonicalizing($expected_cache_tags, $build['#cache']['tags']);
// Build a render array with the entity in a sub-element so that lazy
// builder elements bubble up outside of the entity and we can check that

View File

@ -79,8 +79,8 @@ class ContentModerationAccessTest extends KernelTestBase {
$result = $node->access('update', $account, TRUE);
$this->assertFalse($result->isAllowed());
$this->assertEquals(['user.permissions'], $result->getCacheContexts());
$this->assertEquals(['config:workflows.workflow.editorial', 'node:' . $node->id()], $result->getCacheTags());
$this->assertEqualsCanonicalizing(['user.permissions'], $result->getCacheContexts());
$this->assertEqualsCanonicalizing(['config:workflows.workflow.editorial', 'node:' . $node->id()], $result->getCacheTags());
$this->assertEquals(CacheBackendInterface::CACHE_PERMANENT, $result->getCacheMaxAge());
$authenticated->grantPermission('use editorial transition create_new_draft');
@ -89,8 +89,8 @@ class ContentModerationAccessTest extends KernelTestBase {
\Drupal::entityTypeManager()->getAccessControlHandler('node')->resetCache();
$result = $node->access('update', $account, TRUE);
$this->assertTrue($result->isAllowed());
$this->assertEquals(['user.permissions'], $result->getCacheContexts());
$this->assertEquals(['config:workflows.workflow.editorial', 'node:' . $node->id()], $result->getCacheTags());
$this->assertEqualsCanonicalizing(['user.permissions'], $result->getCacheContexts());
$this->assertEqualsCanonicalizing(['config:workflows.workflow.editorial', 'node:' . $node->id()], $result->getCacheTags());
$this->assertEquals(CacheBackendInterface::CACHE_PERMANENT, $result->getCacheMaxAge());
}

View File

@ -298,7 +298,7 @@ class FilterAPITest extends EntityKernelTestBase {
// The cache tags set by the filter_test_cache_merge filter.
'merge:tag',
];
$this->assertEquals($expected_cache_tags, $build['#cache']['tags'], 'Expected cache tags present.');
$this->assertEqualsCanonicalizing($expected_cache_tags, $build['#cache']['tags'], 'Expected cache tags present.');
$expected_cache_contexts = [
// The cache context set by the filter_test_cache_contexts filter.
'languages:' . LanguageInterface::TYPE_CONTENT,
@ -308,7 +308,7 @@ class FilterAPITest extends EntityKernelTestBase {
// The cache tags set by the filter_test_cache_merge filter.
'user.permissions',
];
$this->assertEquals($expected_cache_contexts, $build['#cache']['contexts'], 'Expected cache contexts present.');
$this->assertEqualsCanonicalizing($expected_cache_contexts, $build['#cache']['contexts'], 'Expected cache contexts present.');
$expected_markup = '<p>Hello, world!</p><p>This is a dynamic llama.</p>';
$this->assertEquals($expected_markup, $build['#markup'], 'Expected #lazy_builder callback has been applied.');
}

View File

@ -214,9 +214,9 @@ class ForumListingBreadcrumbBuilderTest extends UnitTestCase {
];
$breadcrumb = $breadcrumb_builder->build($route_match);
$this->assertEquals($expected1, $breadcrumb->getLinks());
$this->assertEquals(['route'], $breadcrumb->getCacheContexts());
$this->assertEquals(['taxonomy_term:1', 'taxonomy_term:23', 'taxonomy_vocabulary:5'], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
$this->assertEqualsCanonicalizing(['route'], $breadcrumb->getCacheContexts());
$this->assertEqualsCanonicalizing(['taxonomy_term:1', 'taxonomy_term:23', 'taxonomy_vocabulary:5'], $breadcrumb->getCacheTags());
$this->assertEqualsCanonicalizing(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
// Second test.
$expected2 = [
@ -227,8 +227,8 @@ class ForumListingBreadcrumbBuilderTest extends UnitTestCase {
];
$breadcrumb = $breadcrumb_builder->build($route_match);
$this->assertEquals($expected2, $breadcrumb->getLinks());
$this->assertEquals(['route'], $breadcrumb->getCacheContexts());
$this->assertEquals(['taxonomy_term:1', 'taxonomy_term:2', 'taxonomy_term:23', 'taxonomy_vocabulary:5'], $breadcrumb->getCacheTags());
$this->assertEqualsCanonicalizing(['route'], $breadcrumb->getCacheContexts());
$this->assertEqualsCanonicalizing(['taxonomy_term:1', 'taxonomy_term:2', 'taxonomy_term:23', 'taxonomy_vocabulary:5'], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}

View File

@ -221,8 +221,8 @@ class ForumNodeBreadcrumbBuilderTest extends UnitTestCase {
];
$breadcrumb = $breadcrumb_builder->build($route_match);
$this->assertEquals($expected1, $breadcrumb->getLinks());
$this->assertEquals(['route'], $breadcrumb->getCacheContexts());
$this->assertEquals(['taxonomy_term:1', 'taxonomy_vocabulary:5'], $breadcrumb->getCacheTags());
$this->assertEqualsCanonicalizing(['route'], $breadcrumb->getCacheContexts());
$this->assertEqualsCanonicalizing(['taxonomy_term:1', 'taxonomy_vocabulary:5'], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
// Second test.
@ -234,8 +234,8 @@ class ForumNodeBreadcrumbBuilderTest extends UnitTestCase {
];
$breadcrumb = $breadcrumb_builder->build($route_match);
$this->assertEquals($expected2, $breadcrumb->getLinks());
$this->assertEquals(['route'], $breadcrumb->getCacheContexts());
$this->assertEquals(['taxonomy_term:1', 'taxonomy_term:2', 'taxonomy_vocabulary:5'], $breadcrumb->getCacheTags());
$this->assertEqualsCanonicalizing(['route'], $breadcrumb->getCacheContexts());
$this->assertEqualsCanonicalizing(['taxonomy_term:1', 'taxonomy_term:2', 'taxonomy_vocabulary:5'], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}

View File

@ -722,14 +722,14 @@ abstract class ResourceTestBase extends BrowserTestBase {
// Expected cache tags: X-Drupal-Cache-Tags header.
$this->assertSame($expected_cache_tags !== FALSE, $response->hasHeader('X-Drupal-Cache-Tags'));
if (is_array($expected_cache_tags)) {
$this->assertSame($expected_cache_tags, explode(' ', $response->getHeader('X-Drupal-Cache-Tags')[0]));
$this->assertEqualsCanonicalizing($expected_cache_tags, explode(' ', $response->getHeader('X-Drupal-Cache-Tags')[0]));
}
// Expected cache contexts: X-Drupal-Cache-Contexts header.
$this->assertSame($expected_cache_contexts !== FALSE, $response->hasHeader('X-Drupal-Cache-Contexts'));
if (is_array($expected_cache_contexts)) {
$optimized_expected_cache_contexts = \Drupal::service('cache_contexts_manager')->optimizeTokens($expected_cache_contexts);
$this->assertSame($optimized_expected_cache_contexts, explode(' ', $response->getHeader('X-Drupal-Cache-Contexts')[0]));
$this->assertEqualsCanonicalizing($optimized_expected_cache_contexts, explode(' ', $response->getHeader('X-Drupal-Cache-Contexts')[0]));
}
// Expected Page Cache header value: X-Drupal-Cache header.
@ -788,7 +788,7 @@ abstract class ResourceTestBase extends BrowserTestBase {
}
foreach ($expected_document as $member_name => $expected_member) {
$actual_member = $actual_document[$member_name];
$this->assertEquals($expected_member, $actual_member, "The '$member_name' member was not as expected.");
$this->assertEqualsCanonicalizing($expected_member, $actual_member, "The '$member_name' member was not as expected.");
}
}

View File

@ -207,7 +207,7 @@ class EntityResourceTest extends JsonapiKernelTestBase {
$data = $response->getResponseData()->getData();
$this->assertCount(1, $data);
$this->assertEquals($this->node2->uuid(), $data->toArray()[0]->getId());
$this->assertEquals(['node:2', 'node_list'], $response->getCacheableMetadata()->getCacheTags());
$this->assertEqualsCanonicalizing(['node:2', 'node_list'], $response->getCacheableMetadata()->getCacheTags());
}
/**

View File

@ -310,7 +310,7 @@ class JsonApiDocumentTopLevelNormalizerTest extends JsonapiKernelTestBase {
$this->assertTrue(!isset($normalized['included'][1]['attributes']['created']));
// Make sure that the cache tags for the includes and the requested entities
// are bubbling as expected.
$this->assertSame(
$this->assertEqualsCanonicalizing(
['file:1', 'node:1', 'taxonomy_term:1', 'taxonomy_term:2', 'user:1'],
$jsonapi_doc_object->getCacheTags()
);
@ -400,7 +400,7 @@ class JsonApiDocumentTopLevelNormalizerTest extends JsonapiKernelTestBase {
$this->assertCount(12, $normalized['included'][1]['attributes']);
// Make sure that the cache tags for the includes and the requested entities
// are bubbling as expected.
$this->assertSame(
$this->assertEqualsCanonicalizing(
['node:1', 'taxonomy_term:1', 'taxonomy_term:2', 'user:1'],
$jsonapi_doc_object->getCacheTags()
);

View File

@ -122,7 +122,7 @@ class BlockComponentRenderArrayTest extends UnitTestCase {
'content' => $block_content,
];
$expected_cache = $expected_build + [
$expected_build_with_expected_cache = $expected_build + [
'#cache' => [
'contexts' => [],
'tags' => [
@ -137,7 +137,7 @@ class BlockComponentRenderArrayTest extends UnitTestCase {
$result = $event->getBuild();
$this->assertEquals($expected_build, $result);
$event->getCacheableMetadata()->applyTo($result);
$this->assertEquals($expected_cache, $result);
$this->assertEqualsCanonicalizing($expected_build_with_expected_cache['#cache'], $result['#cache']);
}
/**
@ -443,7 +443,7 @@ class BlockComponentRenderArrayTest extends UnitTestCase {
$result = $event->getBuild();
$this->assertEquals($expected_build, $result);
$event->getCacheableMetadata()->applyTo($result);
$this->assertEquals($expected_cache, $result);
$this->assertEqualsCanonicalizing($expected_cache, $result);
}
/**
@ -488,7 +488,7 @@ class BlockComponentRenderArrayTest extends UnitTestCase {
$result = $event->getBuild();
$this->assertEquals($expected_build, $result);
$event->getCacheableMetadata()->applyTo($result);
$this->assertEquals($expected_cache, $result);
$this->assertEqualsCanonicalizing($expected_cache, $result);
}
/**

View File

@ -34,8 +34,8 @@ class MediaEmbedFilterTest extends MediaEmbedFilterTestBase {
$this->assertCount(1, $this->cssSelect('div[data-media-embed-test-view-mode="' . $expected_view_mode . '"]'));
$this->assertHasAttributes($this->cssSelect('div[data-media-embed-test-view-mode="' . $expected_view_mode . '"]')[0], $expected_attributes);
$this->assertSame($expected_cacheability->getCacheTags(), $result->getCacheTags());
$this->assertSame($expected_cacheability->getCacheContexts(), $result->getCacheContexts());
$this->assertEqualsCanonicalizing($expected_cacheability->getCacheTags(), $result->getCacheTags());
$this->assertEqualsCanonicalizing($expected_cacheability->getCacheContexts(), $result->getCacheContexts());
$this->assertSame($expected_cacheability->getCacheMaxAge(), $result->getCacheMaxAge());
$this->assertSame(['library'], array_keys($result->getAttachments()));
$this->assertSame(['media/filter.caption'], $result->getAttachments()['library']);
@ -152,8 +152,8 @@ class MediaEmbedFilterTest extends MediaEmbedFilterTestBase {
$this->assertCount(1, $this->cssSelect('div[data-media-embed-test-view-mode="default"]'));
}
$this->assertSame($expected_cacheability->getCacheTags(), $result->getCacheTags());
$this->assertSame($expected_cacheability->getCacheContexts(), $result->getCacheContexts());
$this->assertEqualsCanonicalizing($expected_cacheability->getCacheTags(), $result->getCacheTags());
$this->assertEqualsCanonicalizing($expected_cacheability->getCacheContexts(), $result->getCacheContexts());
$this->assertSame($expected_cacheability->getCacheMaxAge(), $result->getCacheMaxAge());
$this->assertSame($expected_attachments, $result->getAttachments());
}
@ -408,7 +408,7 @@ class MediaEmbedFilterTest extends MediaEmbedFilterTestBase {
$this->setRawContent($result->getProcessedText());
$this->assertCount($expected_verification_success ? 1 : 0, $this->cssSelect($verification_selector));
$this->assertCount(1, $this->cssSelect('div[data-media-embed-test-view-mode="default"]'));
$this->assertSame([
$this->assertEqualsCanonicalizing([
'_media_test_embed_filter_access:media:1',
'_media_test_embed_filter_access:user:2',
'config:image.style.thumbnail',
@ -417,7 +417,7 @@ class MediaEmbedFilterTest extends MediaEmbedFilterTestBase {
'media_view',
'user:2',
], $result->getCacheTags());
$this->assertSame(['timezone', 'user.permissions'], $result->getCacheContexts());
$this->assertEqualsCanonicalizing(['timezone', 'user.permissions'], $result->getCacheContexts());
$this->assertSame(Cache::PERMANENT, $result->getCacheMaxAge());
$this->assertSame(['library'], array_keys($result->getAttachments()));
$this->assertSame($expected_asset_libraries, $result->getAttachments()['library']);

View File

@ -62,7 +62,7 @@ class MediaEmbedFilterTranslationTest extends MediaEmbedFilterTestBase {
// based on the host entity's language, which should require a cache context
// to be associated. (The host entity's language may itself be selected
// based on the request context, but that is of no concern to this filter.)
$this->assertSame($result->getCacheContexts(), ['timezone', 'user.permissions']);
$this->assertEqualsCanonicalizing($result->getCacheContexts(), ['timezone', 'user.permissions']);
}
/**

View File

@ -417,8 +417,8 @@ class MediaLibraryAccessTest extends KernelTestBase {
if ($access_result instanceof AccessResultReasonInterface && isset($expected_reason)) {
$this->assertSame($expected_reason, $access_result->getReason());
}
$this->assertSame($expected_cache_tags, $access_result->getCacheTags());
$this->assertSame($expected_cache_contexts, $access_result->getCacheContexts());
$this->assertEqualsCanonicalizing($expected_cache_tags, $access_result->getCacheTags());
$this->assertEqualsCanonicalizing($expected_cache_contexts, $access_result->getCacheContexts());
}
}

View File

@ -124,7 +124,7 @@ class MenuLinkContentCacheabilityBubblingTest extends KernelTestBase {
$renderer->renderRoot($build);
$expected_cacheability = $default_menu_cacheability->merge($expectation['cacheability']);
$this->assertEquals($expected_cacheability, BubbleableMetadata::createFromRenderArray($build));
$this->assertEqualsCanonicalizing($expected_cacheability, BubbleableMetadata::createFromRenderArray($build));
$menu_link_content->delete();
}
@ -146,7 +146,7 @@ class MenuLinkContentCacheabilityBubblingTest extends KernelTestBase {
$build = $menu_tree->build($tree);
$renderer->renderRoot($build);
$expected_cacheability = $expected_cacheability->merge($default_menu_cacheability);
$this->assertEquals($expected_cacheability, BubbleableMetadata::createFromRenderArray($build));
$this->assertEqualsCanonicalizing($expected_cacheability, BubbleableMetadata::createFromRenderArray($build));
}
}

View File

@ -33,7 +33,7 @@ class NodeListBuilderTest extends KernelTestBase {
$build = $list_builder->render();
$this->container->get('renderer')->renderRoot($build);
$this->assertEquals(['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'url.query_args.pagers:0', 'user.node_grants:view', 'user.permissions'], $build['#cache']['contexts']);
$this->assertEqualsCanonicalizing(['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'url.query_args.pagers:0', 'user.node_grants:view', 'user.permissions'], $build['#cache']['contexts']);
}
}

View File

@ -565,7 +565,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
static::recursiveKSort($expected);
$actual = $this->serializer->decode((string) $response->getBody(), static::$format);
static::recursiveKSort($actual);
$this->assertSame($expected, $actual);
$this->assertEqualsCanonicalizing($expected, $actual);
// Not only assert the normalization, also assert deserialization of the
// response results in the expected object.

View File

@ -398,13 +398,13 @@ abstract class ResourceTestBase extends BrowserTestBase {
// Expected cache tags: X-Drupal-Cache-Tags header.
$this->assertSame($expected_cache_tags !== FALSE, $response->hasHeader('X-Drupal-Cache-Tags'));
if (is_array($expected_cache_tags)) {
$this->assertSame($expected_cache_tags, explode(' ', $response->getHeader('X-Drupal-Cache-Tags')[0]));
$this->assertEqualsCanonicalizing($expected_cache_tags, explode(' ', $response->getHeader('X-Drupal-Cache-Tags')[0]));
}
// Expected cache contexts: X-Drupal-Cache-Contexts header.
$this->assertSame($expected_cache_contexts !== FALSE, $response->hasHeader('X-Drupal-Cache-Contexts'));
if (is_array($expected_cache_contexts)) {
$this->assertSame($expected_cache_contexts, explode(' ', $response->getHeader('X-Drupal-Cache-Contexts')[0]));
$this->assertEqualsCanonicalizing($expected_cache_contexts, explode(' ', $response->getHeader('X-Drupal-Cache-Contexts')[0]));
}
// Expected Page Cache header value: X-Drupal-Cache header.

View File

@ -177,7 +177,7 @@ class EntityTestTextItemNormalizerTest extends EntityTestResourceTestBase {
$this->setUpAuthorization('GET');
$response = $this->request('GET', $url, $request_options);
$expected_cache_tags = Cache::mergeTags($expected_cache_tags, parent::getExpectedCacheTags());
$this->assertSame($expected_cache_tags, explode(' ', $response->getHeader('X-Drupal-Cache-Tags')[0]));
$this->assertEqualsCanonicalizing($expected_cache_tags, explode(' ', $response->getHeader('X-Drupal-Cache-Tags')[0]));
}
public function providerTestGetWithFormat() {

View File

@ -427,7 +427,7 @@ abstract class EntityCacheTagsTestBase extends PageCacheTagsTestBase {
$this->verifyPageCache($empty_entity_listing_url, 'HIT', $empty_entity_listing_cache_tags);
// Verify the entity type's list cache contexts are present.
$contexts_in_header = $this->getSession()->getResponseHeader('X-Drupal-Cache-Contexts');
$this->assertEquals(Cache::mergeContexts($page_cache_contexts, $this->getAdditionalCacheContextsForEntityListing()), empty($contexts_in_header) ? [] : explode(' ', $contexts_in_header));
$this->assertEqualsCanonicalizing(Cache::mergeContexts($page_cache_contexts, $this->getAdditionalCacheContextsForEntityListing()), empty($contexts_in_header) ? [] : explode(' ', $contexts_in_header));
// Prime the page cache for the listing containing the referenced entity.
$this->verifyPageCache($nonempty_entity_listing_url, 'MISS', $nonempty_entity_listing_cache_tags);
@ -435,7 +435,7 @@ abstract class EntityCacheTagsTestBase extends PageCacheTagsTestBase {
$this->verifyPageCache($nonempty_entity_listing_url, 'HIT', $nonempty_entity_listing_cache_tags);
// Verify the entity type's list cache contexts are present.
$contexts_in_header = $this->getSession()->getResponseHeader('X-Drupal-Cache-Contexts');
$this->assertEquals(Cache::mergeContexts($page_cache_contexts, $this->getAdditionalCacheContextsForEntityListing()), empty($contexts_in_header) ? [] : explode(' ', $contexts_in_header));
$this->assertEqualsCanonicalizing(Cache::mergeContexts($page_cache_contexts, $this->getAdditionalCacheContextsForEntityListing()), empty($contexts_in_header) ? [] : explode(' ', $contexts_in_header));
// Verify that after modifying the referenced entity, there is a cache miss
// for every route except the one for the non-referencing entity.

View File

@ -68,7 +68,7 @@ class EntityListBuilderTest extends BrowserTestBase {
$build = $list_builder->render();
$this->container->get('renderer')->renderRoot($build);
$this->assertEquals(['entity_test_view_grants', 'languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'url.query_args.pagers:0', 'user.permissions'], $build['#cache']['contexts']);
$this->assertEqualsCanonicalizing(['entity_test_view_grants', 'languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'url.query_args.pagers:0', 'user.permissions'], $build['#cache']['contexts']);
}
/**

View File

@ -34,6 +34,7 @@ class RouterTest extends BrowserTestBase {
public function testFinishResponseSubscriber() {
$renderer_required_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions'];
$expected_cache_contexts = Cache::mergeContexts($renderer_required_cache_contexts, ['url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT]);
sort($expected_cache_contexts);
// Confirm that the router can get to a controller.
$this->drupalGet('router_test/test1');
@ -65,12 +66,19 @@ class RouterTest extends BrowserTestBase {
// X-Drupal-Cache-Contexts and X-Drupal-Cache-Tags headers.
// 1. controller result: render array, globally cacheable route access.
$this->drupalGet('router_test/test18');
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache-Contexts', implode(' ', Cache::mergeContexts($renderer_required_cache_contexts, ['url'])));
$expected_cache_contexts = Cache::mergeContexts($renderer_required_cache_contexts, ['url']);
sort($expected_cache_contexts);
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache-Contexts', implode(' ', $expected_cache_contexts));
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache-Tags', 'config:user.role.anonymous foo http_response rendered');
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache-Max-Age', '60');
// 2. controller result: render array, per-role cacheable route access.
$this->drupalGet('router_test/test19');
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache-Contexts', implode(' ', Cache::mergeContexts($renderer_required_cache_contexts, ['url', 'user.roles'])));
$expected_cache_contexts = Cache::mergeContexts($renderer_required_cache_contexts, [
'url',
'user.roles',
]);
sort($expected_cache_contexts);
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache-Contexts', implode(' ', $expected_cache_contexts));
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache-Tags', 'config:user.role.anonymous foo http_response rendered');
// 3. controller result: Response object, globally cacheable route access.
$this->drupalGet('router_test/test1');

View File

@ -68,7 +68,7 @@ class UrlTest extends KernelTestBase {
'#url' => Url::fromUri($uri),
];
\Drupal::service('renderer')->renderRoot($link);
$this->assertEquals($expected_cacheability, $link['#cache']);
$this->assertEqualsCanonicalizing($expected_cacheability, $link['#cache']);
$this->assertEquals($expected_attachments, $link['#attached']);
}
}

View File

@ -151,8 +151,8 @@ class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
$breadcrumb = $this->builder->build($this->createMock('Drupal\Core\Routing\RouteMatchInterface'));
$this->assertEquals([], $breadcrumb->getLinks());
$this->assertEquals(['url.path.is_front', 'url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEqualsCanonicalizing(['url.path.is_front', 'url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEqualsCanonicalizing([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
@ -168,8 +168,8 @@ class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
$breadcrumb = $this->builder->build($this->createMock('Drupal\Core\Routing\RouteMatchInterface'));
$this->assertEquals([0 => new Link('Home', new Url('<front>'))], $breadcrumb->getLinks());
$this->assertEquals(['url.path.is_front', 'url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEqualsCanonicalizing(['url.path.is_front', 'url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEqualsCanonicalizing([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
@ -203,12 +203,12 @@ class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
$breadcrumb = $this->builder->build($this->createMock('Drupal\Core\Routing\RouteMatchInterface'));
$this->assertEquals([0 => new Link('Home', new Url('<front>')), 1 => new Link('Example', new Url('example'))], $breadcrumb->getLinks());
$this->assertEquals([
$this->assertEqualsCanonicalizing([
'url.path.is_front',
'url.path.parent',
'user.permissions',
], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEqualsCanonicalizing([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
@ -258,13 +258,13 @@ class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
new Link('Example', new Url('example')),
new Link('Bar', new Url('example_bar')),
], $breadcrumb->getLinks());
$this->assertEquals([
$this->assertEqualsCanonicalizing([
'bar',
'url.path.is_front',
'url.path.parent',
'user.permissions',
], $breadcrumb->getCacheContexts());
$this->assertEquals(['example'], $breadcrumb->getCacheTags());
$this->assertEqualsCanonicalizing(['example'], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
@ -290,8 +290,8 @@ class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
// No path matched, though at least the frontpage is displayed.
$this->assertEquals([0 => new Link('Home', new Url('<front>'))], $breadcrumb->getLinks());
$this->assertEquals(['url.path.is_front', 'url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEqualsCanonicalizing(['url.path.is_front', 'url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEqualsCanonicalizing([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
@ -334,8 +334,8 @@ class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
// No path matched, though at least the frontpage is displayed.
$this->assertEquals([0 => new Link('Home', new Url('<front>'))], $breadcrumb->getLinks());
$this->assertEquals(['url.path.is_front', 'url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEqualsCanonicalizing(['url.path.is_front', 'url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEqualsCanonicalizing([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
@ -382,12 +382,12 @@ class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
$breadcrumb = $this->builder->build($this->createMock('Drupal\Core\Routing\RouteMatchInterface'));
$this->assertEquals([0 => new Link('Home', new Url('<front>')), 1 => new Link('Admin', new Url('user_page'))], $breadcrumb->getLinks());
$this->assertEquals([
$this->assertEqualsCanonicalizing([
'url.path.is_front',
'url.path.parent',
'user.permissions',
], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEqualsCanonicalizing([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}

View File

@ -101,7 +101,6 @@ class MenuLinkTreeTest extends UnitTestCase {
$access->addCacheContexts($access_cache_contexts);
}
$build = $this->menuLinkTree->build($tree);
sort($expected_build['#cache']['contexts']);
$this->assertEquals($expected_build, $build, $description);
}

View File

@ -334,6 +334,8 @@ class View extends ConfigEntityBase implements ViewEntityInterface {
// Always include at least the 'languages:' context as there will most
// probably be translatable strings in the view output.
$display['cache_metadata']['contexts'] = Cache::mergeContexts($display['cache_metadata']['contexts'], ['languages:' . LanguageInterface::TYPE_INTERFACE]);
sort($display['cache_metadata']['tags']);
sort($display['cache_metadata']['contexts']);
}
// Restore the previous active display.
$executable->setDisplay($current_display);

View File

@ -52,7 +52,7 @@ trait AssertViewsCacheTagsTrait {
// Check render array cache tags.
sort($expected_render_array_cache_tags);
$this->assertEquals($expected_render_array_cache_tags, $build['#cache']['tags']);
$this->assertEqualsCanonicalizing($expected_render_array_cache_tags, $build['#cache']['tags']);
if ($views_caching_is_enabled) {
// Check Views render cache item cache tags.
@ -67,8 +67,7 @@ trait AssertViewsCacheTagsTrait {
if (is_array($expected_results_cache)) {
$this->assertNotEmpty($results_cache_item, 'Results cache item found.');
if ($results_cache_item) {
sort($expected_results_cache);
$this->assertEquals($expected_results_cache, $results_cache_item->tags);
$this->assertEqualsCanonicalizing($expected_results_cache, $results_cache_item->tags);
}
}
else {
@ -83,7 +82,7 @@ trait AssertViewsCacheTagsTrait {
if ($views_caching_is_enabled === TRUE) {
$this->assertNotEmpty($render_cache_item, 'Render cache item found.');
if ($render_cache_item) {
$this->assertEquals($expected_render_array_cache_tags, $render_cache_item['#cache']['tags']);
$this->assertEqualsCanonicalizing($expected_render_array_cache_tags, $render_cache_item['#cache']['tags']);
}
}
else {
@ -131,8 +130,7 @@ trait AssertViewsCacheTagsTrait {
$renderer->renderRoot($build);
// Check render array cache tags.
sort($expected_render_array_cache_tags);
$this->assertEquals($expected_render_array_cache_tags, $build['#cache']['tags']);
$this->assertEqualsCanonicalizing($expected_render_array_cache_tags, $build['#cache']['tags']);
// Check Views render cache item cache tags.
$original['#cache'] += ['contexts' => []];
@ -142,7 +140,7 @@ trait AssertViewsCacheTagsTrait {
if ($views_caching_is_enabled) {
$this->assertTrue(!empty($render_cache_item), 'Render cache item found.');
if ($render_cache_item) {
$this->assertEquals($expected_render_array_cache_tags, $render_cache_item['#cache']['tags']);
$this->assertEqualsCanonicalizing($expected_render_array_cache_tags, $render_cache_item['#cache']['tags']);
}
}
else {

View File

@ -144,7 +144,7 @@ class FieldRenderedEntityTest extends ViewsKernelTestBase {
* The render array
*/
protected function assertCacheabilityMetadata($build) {
$this->assertEquals([
$this->assertEqualsCanonicalizing([
'config:core.entity_view_display.entity_test.entity_test.foobar',
'config:views.view.test_field_entity_test_rendered',
'entity_test:1',
@ -154,7 +154,7 @@ class FieldRenderedEntityTest extends ViewsKernelTestBase {
'entity_test_view',
], $build['#cache']['tags']);
$this->assertEquals([
$this->assertEqualsCanonicalizing([
'entity_test_view_grants',
'languages:language_interface',
'theme',

View File

@ -285,7 +285,7 @@ class RenderCacheIntegrationTest extends ViewsKernelTestBase {
$view = View::load('test_display');
$view->save();
$this->assertEquals(['languages:' . LanguageInterface::TYPE_CONTENT, 'languages:' . LanguageInterface::TYPE_INTERFACE, 'url.query_args', 'user.node_grants:view', 'user.permissions'], $view->getDisplay('default')['cache_metadata']['contexts']);
$this->assertEqualsCanonicalizing(['languages:' . LanguageInterface::TYPE_CONTENT, 'languages:' . LanguageInterface::TYPE_INTERFACE, 'url.query_args', 'user.node_grants:view', 'user.permissions'], $view->getDisplay('default')['cache_metadata']['contexts']);
}
}

View File

@ -69,7 +69,7 @@ class SqlTest extends UnitTestCase {
$result[] = $row;
$view->result = $result;
$this->assertEquals(['entity_test:123', 'entity_test:124', 'entity_test:125', 'entity_test:126'], $query->getCacheTags());
$this->assertEqualsCanonicalizing(['entity_test:123', 'entity_test:124', 'entity_test:125', 'entity_test:126'], $query->getCacheTags());
}
/**

View File

@ -404,8 +404,8 @@ class AccessResultTest extends UnitTestCase {
$this->assertFalse($access->isForbidden());
$this->assertTrue($access->isNeutral());
$this->assertSame(Cache::PERMANENT, $access->getCacheMaxAge());
$this->assertSame($contexts, $access->getCacheContexts());
$this->assertSame([], $access->getCacheTags());
$this->assertEqualsCanonicalizing($contexts, $access->getCacheContexts());
$this->assertEqualsCanonicalizing([], $access->getCacheTags());
};
$access = AccessResult::neutral()->addCacheContexts(['foo']);
@ -451,7 +451,7 @@ class AccessResultTest extends UnitTestCase {
$verify($b, $contexts);
$c = AccessResult::neutral()->cachePerUser()->cachePerPermissions();
$verify($c, $contexts);
$this->assertEquals($a, $b);
$this->assertEqualsCanonicalizing($a, $b);
$this->assertEquals($a, $c);
// ::allowIfHasPermission and ::allowedIfHasPermission convenience methods.
@ -480,8 +480,8 @@ class AccessResultTest extends UnitTestCase {
$this->assertFalse($access->isForbidden());
$this->assertTrue($access->isNeutral());
$this->assertSame($max_age, $access->getCacheMaxAge());
$this->assertSame($contexts, $access->getCacheContexts());
$this->assertSame($tags, $access->getCacheTags());
$this->assertEqualsCanonicalizing($contexts, $access->getCacheContexts());
$this->assertEqualsCanonicalizing($tags, $access->getCacheTags());
};
$access = AccessResult::neutral()->addCacheTags(['foo:bar']);

View File

@ -52,11 +52,11 @@ class CacheTest extends UnitTestCase {
return [
[[], [], []],
[['bar', 'foo'], ['bar'], ['foo']],
[['bar', 'foo'], ['foo'], ['bar']],
[['bar', 'foo'], ['foo'], ['bar', 'foo']],
[['bar', 'foo'], ['foo'], ['foo', 'bar']],
[['foo', 'bar'], ['foo'], ['bar']],
[['foo', 'bar'], ['foo'], ['bar', 'foo']],
[['foo', 'bar'], ['foo'], ['foo', 'bar']],
[['bar', 'foo'], ['bar', 'foo'], ['foo', 'bar']],
[['bar', 'foo'], ['foo', 'bar'], ['foo', 'bar']],
[['foo', 'bar'], ['foo', 'bar'], ['foo', 'bar']],
[['bar', 'foo', 'llama'], ['bar', 'foo'], ['foo', 'bar'], ['llama', 'foo']],
];
}
@ -67,7 +67,7 @@ class CacheTest extends UnitTestCase {
* @dataProvider mergeTagsProvider
*/
public function testMergeTags(array $expected, ...$cache_tags) {
$this->assertEquals($expected, Cache::mergeTags(...$cache_tags));
$this->assertEqualsCanonicalizing($expected, Cache::mergeTags(...$cache_tags));
}
/**
@ -145,7 +145,7 @@ class CacheTest extends UnitTestCase {
$container = $this->prophesize(Container::class);
$container->get('cache_contexts_manager')->willReturn($cache_contexts_manager->reveal());
\Drupal::setContainer($container->reveal());
$this->assertSame($expected, Cache::mergeContexts(...$contexts));
$this->assertEqualsCanonicalizing($expected, Cache::mergeContexts(...$contexts));
}
/**

View File

@ -35,7 +35,7 @@ class CacheableMetadataTest extends UnitTestCase {
$container->set('cache_contexts_manager', $cache_contexts_manager);
\Drupal::setContainer($container);
$this->assertEquals($expected, $a->merge($b));
$this->assertEqualsCanonicalizing($expected, $a->merge($b));
}
/**
@ -58,7 +58,7 @@ class CacheableMetadataTest extends UnitTestCase {
$container->set('cache_contexts_manager', $cache_contexts_manager);
\Drupal::setContainer($container);
$this->assertEquals($expected, $a->addCacheableDependency($b));
$this->assertEqualsCanonicalizing($expected, $a->addCacheableDependency($b));
}
/**
@ -73,7 +73,7 @@ class CacheableMetadataTest extends UnitTestCase {
// Cache contexts.
[(new CacheableMetadata())->setCacheContexts(['foo']), (new CacheableMetadata())->setCacheContexts(['bar']), (new CacheableMetadata())->setCacheContexts(['bar', 'foo'])],
// Cache tags.
[(new CacheableMetadata())->setCacheTags(['foo']), (new CacheableMetadata())->setCacheTags(['bar']), (new CacheableMetadata())->setCacheTags(['bar', 'foo'])],
[(new CacheableMetadata())->setCacheTags(['foo']), (new CacheableMetadata())->setCacheTags(['bar']), (new CacheableMetadata())->setCacheTags(['foo', 'bar'])],
// Cache max-ages.
[(new CacheableMetadata())->setCacheMaxAge(60), (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT), (new CacheableMetadata())->setCacheMaxAge(60)],
];
@ -90,15 +90,15 @@ class CacheableMetadataTest extends UnitTestCase {
[[], []],
[['foo:bar'], ['foo:bar']],
[['foo:baz'], ['foo:bar', 'foo:baz']],
[['axx:first', 'foo:baz'], ['axx:first', 'foo:bar', 'foo:baz']],
[[], ['axx:first', 'foo:bar', 'foo:baz']],
[['axx:first'], ['axx:first', 'foo:bar', 'foo:baz']],
[['axx:first', 'foo:baz'], ['foo:bar', 'foo:baz', 'axx:first']],
[[], ['foo:bar', 'foo:baz', 'axx:first']],
[['axx:first'], ['foo:bar', 'foo:baz', 'axx:first']],
];
foreach ($add_expected as $data) {
foreach ($add_expected as $row => $data) {
list($add, $expected) = $data;
$metadata->addCacheTags($add);
$this->assertEquals($expected, $metadata->getCacheTags());
$this->assertEquals($expected, $metadata->getCacheTags(), sprintf("Dataset in %d row failed on validation.", $row + 1));
}
}

View File

@ -406,10 +406,10 @@ class EntityUnitTest extends UnitTestCase {
],
[
[
// Own cache tag.
$this->entityTypeId . ':' . $this->values['id'],
// List cache tag.
$this->entityTypeId . '_list',
// Own cache tag.
$this->entityTypeId . ':' . $this->values['id'],
],
]);
@ -438,11 +438,11 @@ class EntityUnitTest extends UnitTestCase {
],
[
[
// Own cache tag.
$this->entityTypeId . ':' . $this->values['id'],
// List cache tag.
$this->entityTypeId . '_list',
$this->entityTypeId . '_list:' . $this->entity->bundle(),
// Own cache tag.
$this->entityTypeId . ':' . $this->values['id'],
],
]);
@ -500,8 +500,8 @@ class EntityUnitTest extends UnitTestCase {
$this->cacheTagsInvalidator->expects($this->once())
->method('invalidateTags')
->with([
$this->entityTypeId . ':' . $this->values['id'],
$this->entityTypeId . '_list',
$this->entityTypeId . ':' . $this->values['id'],
]);
$storage = $this->createMock('\Drupal\Core\Entity\EntityStorageInterface');
$storage->expects($this->once())
@ -518,11 +518,16 @@ class EntityUnitTest extends UnitTestCase {
public function testPostDeleteBundle() {
$this->cacheTagsInvalidator->expects($this->once())
->method('invalidateTags')
->with([
$this->entityTypeId . ':' . $this->values['id'],
$this->entityTypeId . '_list',
$this->entityTypeId . '_list:' . $this->entity->bundle(),
]);
// with() also asserts on the order of array values and array keys that
// is something we should avoid here.
->willReturnCallback(function (array $tags) {
self::assertEqualsCanonicalizing([
$this->entityTypeId . '_list',
$this->entityTypeId . ':' . $this->values['id'],
$this->entityTypeId . '_list:' . $this->entity->bundle(),
], $tags);
return NULL;
});
$this->entityType->expects($this->atLeastOnce())
->method('hasKey')
->with('bundle')
@ -561,8 +566,8 @@ class EntityUnitTest extends UnitTestCase {
*/
public function testCacheTags() {
// Ensure that both methods return the same by default.
$this->assertEquals([$this->entityTypeId . ':' . 1], $this->entity->getCacheTags());
$this->assertEquals([$this->entityTypeId . ':' . 1], $this->entity->getCacheTagsToInvalidate());
$this->assertEqualsCanonicalizing([$this->entityTypeId . ':' . 1], $this->entity->getCacheTags());
$this->assertEqualsCanonicalizing([$this->entityTypeId . ':' . 1], $this->entity->getCacheTagsToInvalidate());
// Add an additional cache tag and make sure only getCacheTags() returns
// that.
@ -570,10 +575,9 @@ class EntityUnitTest extends UnitTestCase {
// EntityTypeId is random so it can shift order. We need to duplicate the
// sort from \Drupal\Core\Cache\Cache::mergeTags().
$tags = ['additional_cache_tag', $this->entityTypeId . ':' . 1];
sort($tags);
$this->assertEquals($tags, $this->entity->getCacheTags());
$this->assertEquals([$this->entityTypeId . ':' . 1], $this->entity->getCacheTagsToInvalidate());
$tags = [$this->entityTypeId . ':' . 1, 'additional_cache_tag'];
$this->assertEqualsCanonicalizing($tags, $this->entity->getCacheTags());
$this->assertEqualsCanonicalizing([$this->entityTypeId . ':' . 1], $this->entity->getCacheTagsToInvalidate());
}
/**
@ -591,11 +595,11 @@ class EntityUnitTest extends UnitTestCase {
\Drupal::setContainer($container);
// There are no cache contexts by default.
$this->assertEquals([], $this->entity->getCacheContexts());
$this->assertEqualsCanonicalizing([], $this->entity->getCacheContexts());
// Add an additional cache context.
$this->entity->addCacheContexts(['user']);
$this->assertEquals(['user'], $this->entity->getCacheContexts());
$this->assertEqualsCanonicalizing(['user'], $this->entity->getCacheContexts());
}
/**

View File

@ -434,8 +434,8 @@ class LocalTaskManagerTest extends UnitTestCase {
$this->manager->getTasksBuild('menu_local_task_test_tasks_view', $cacheability);
// Ensure that all cacheability metadata is merged together.
$this->assertEquals(['tag.example1', 'tag.example2'], $cacheability->getCacheTags());
$this->assertEquals(['context.example1', 'context.example2', 'route', 'user.permissions'], $cacheability->getCacheContexts());
$this->assertEqualsCanonicalizing(['tag.example1', 'tag.example2'], $cacheability->getCacheTags());
$this->assertEqualsCanonicalizing(['context.example1', 'context.example2', 'route', 'user.permissions'], $cacheability->getCacheContexts());
}
protected function setupFactoryAndLocalTaskPlugins(array $definitions, $active_plugin_id) {
@ -476,7 +476,7 @@ class LocalTaskManagerTest extends UnitTestCase {
$cache_context_manager = $this->prophesize(CacheContextsManager::class);
foreach ([NULL, ['user.permissions'], ['route'], ['route', 'context.example1'], ['context.example1', 'route'], ['context.example1', 'route', 'context.example2'], ['context.example1', 'context.example2', 'route'], ['context.example1', 'context.example2', 'route', 'user.permissions']] as $argument) {
foreach ([NULL, ['user.permissions'], ['route'], ['route', 'context.example1'], ['context.example1', 'route'], ['route', 'context.example1', 'context.example2'], ['context.example1', 'context.example2', 'route'], ['route', 'context.example1', 'context.example2', 'user.permissions']] as $argument) {
$cache_context_manager->assertValidTokens($argument)->willReturn(TRUE);
}

View File

@ -60,7 +60,7 @@ class BubbleableMetadataTest extends UnitTestCase {
$container->set('renderer', $renderer);
\Drupal::setContainer($container);
$this->assertEquals($expected, $a->merge($b));
$this->assertEqualsCanonicalizing($expected, $a->merge($b));
}
/**
@ -76,7 +76,7 @@ class BubbleableMetadataTest extends UnitTestCase {
// Cache contexts.
[(new BubbleableMetadata())->setCacheContexts(['foo']), (new BubbleableMetadata())->setCacheContexts(['bar']), (new BubbleableMetadata())->setCacheContexts(['bar', 'foo'])],
// Cache tags.
[(new BubbleableMetadata())->setCacheTags(['foo']), (new BubbleableMetadata())->setCacheTags(['bar']), (new BubbleableMetadata())->setCacheTags(['bar', 'foo'])],
[(new BubbleableMetadata())->setCacheTags(['foo']), (new BubbleableMetadata())->setCacheTags(['bar']), (new BubbleableMetadata())->setCacheTags(['foo', 'bar'])],
// Cache max-ages.
[(new BubbleableMetadata())->setCacheMaxAge(60), (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT), (new BubbleableMetadata())->setCacheMaxAge(60)],
// Assets.
@ -90,7 +90,7 @@ class BubbleableMetadataTest extends UnitTestCase {
// Cache contexts.
[(new BubbleableMetadata())->setCacheContexts(['foo']), (new CacheableMetadata())->setCacheContexts(['bar']), (new BubbleableMetadata())->setCacheContexts(['bar', 'foo'])],
// Cache tags.
[(new BubbleableMetadata())->setCacheTags(['foo']), (new CacheableMetadata())->setCacheTags(['bar']), (new BubbleableMetadata())->setCacheTags(['bar', 'foo'])],
[(new BubbleableMetadata())->setCacheTags(['foo']), (new CacheableMetadata())->setCacheTags(['bar']), (new BubbleableMetadata())->setCacheTags(['foo', 'bar'])],
// Cache max-ages.
[(new BubbleableMetadata())->setCacheMaxAge(60), (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT), (new BubbleableMetadata())->setCacheMaxAge(60)],
];
@ -661,7 +661,7 @@ class BubbleableMetadataTest extends UnitTestCase {
$container->set('cache_contexts_manager', $cache_contexts_manager);
\Drupal::setContainer($container);
$this->assertEquals($expected, $a->addCacheableDependency($b));
$this->assertEqualsCanonicalizing($expected, $a->addCacheableDependency($b));
}
/**

View File

@ -119,7 +119,7 @@ class RendererBubblingTest extends RendererTestBase {
'#cache_redirect' => TRUE,
'#cache' => [
'keys' => ['parent'],
'contexts' => ['bar', 'foo'],
'contexts' => ['foo', 'bar'],
'tags' => [],
'bin' => $bin,
'max-age' => 3600,
@ -143,7 +143,7 @@ class RendererBubblingTest extends RendererTestBase {
$this->renderer->renderRoot($element);
$this->assertEquals($expected_top_level_contexts, $element['#cache']['contexts'], 'Expected cache contexts found.');
$this->assertEqualsCanonicalizing($expected_top_level_contexts, $element['#cache']['contexts'], 'Expected cache contexts found.');
foreach ($expected_cache_items as $cid => $expected_cache_item) {
$this->assertRenderCacheItem($cid, $expected_cache_item);
}
@ -211,7 +211,6 @@ class RendererBubblingTest extends RendererTestBase {
];
foreach ($context_orders as $context_order) {
$test_element['#cache']['contexts'] = $context_order;
sort($context_order);
$expected_cache_items['set_test:bar:baz:foo']['#cache']['contexts'] = $context_order;
$data[] = [$test_element, $context_order, $expected_cache_items];
}
@ -235,7 +234,7 @@ class RendererBubblingTest extends RendererTestBase {
'parent:bar:baz:foo' => [
'#attached' => [],
'#cache' => [
'contexts' => ['bar', 'baz', 'foo'],
'contexts' => ['foo', 'bar', 'baz'],
'tags' => [],
'max-age' => 3600,
],
@ -274,8 +273,8 @@ class RendererBubblingTest extends RendererTestBase {
'#cache' => [
// The keys + contexts this redirects to.
'keys' => ['parent'],
'contexts' => ['bar', 'foo'],
'tags' => ['dee', 'fiddle', 'har', 'yar'],
'contexts' => ['foo', 'bar'],
'tags' => ['yar', 'har', 'fiddle', 'dee'],
'bin' => 'render',
'max-age' => Cache::PERMANENT,
],
@ -283,8 +282,8 @@ class RendererBubblingTest extends RendererTestBase {
'parent:bar:foo' => [
'#attached' => [],
'#cache' => [
'contexts' => ['bar', 'foo'],
'tags' => ['dee', 'fiddle', 'har', 'yar'],
'contexts' => ['foo', 'bar'],
'tags' => ['yar', 'har', 'fiddle', 'dee'],
'max-age' => Cache::PERMANENT,
],
'#markup' => 'parent',
@ -320,7 +319,7 @@ class RendererBubblingTest extends RendererTestBase {
'#attached' => ['library' => ['foo/bar']],
'#cache' => [
'contexts' => ['foo'],
'tags' => ['dee', 'fiddle', 'har', 'yar'],
'tags' => ['yar', 'har', 'fiddle', 'dee'],
'max-age' => Cache::PERMANENT,
],
'#markup' => 'parent',
@ -412,7 +411,7 @@ class RendererBubblingTest extends RendererTestBase {
'#cache_redirect' => TRUE,
'#cache' => [
'keys' => ['parent'],
'contexts' => ['foo', 'user.roles'],
'contexts' => ['user.roles', 'foo'],
'tags' => ['a', 'b', 'c'],
'bin' => 'render',
'max-age' => 1800,
@ -421,7 +420,7 @@ class RendererBubblingTest extends RendererTestBase {
$this->assertRenderCacheItem('parent:foo:r.B', [
'#attached' => [],
'#cache' => [
'contexts' => ['foo', 'user.roles'],
'contexts' => ['user.roles', 'foo'],
'tags' => ['a', 'b', 'c'],
'max-age' => 1800,
],
@ -445,7 +444,7 @@ class RendererBubblingTest extends RendererTestBase {
'#cache_redirect' => TRUE,
'#cache' => [
'keys' => ['parent'],
'contexts' => ['foo', 'user.roles'],
'contexts' => ['user.roles', 'foo'],
'tags' => ['a', 'b', 'c'],
'bin' => 'render',
'max-age' => 1800,
@ -454,7 +453,7 @@ class RendererBubblingTest extends RendererTestBase {
$this->assertRenderCacheItem('parent:foo:r.A', [
'#attached' => [],
'#cache' => [
'contexts' => ['foo', 'user.roles'],
'contexts' => ['user.roles', 'foo'],
'tags' => ['a', 'b'],
// Note that the max-age here is unaffected. When role A, the grandchild
// is never rendered, so neither is its max-age of 1800 present here,
@ -474,7 +473,7 @@ class RendererBubblingTest extends RendererTestBase {
'#cache_redirect' => TRUE,
'#cache' => [
'keys' => ['parent'],
'contexts' => ['bar', 'foo', 'user.roles'],
'contexts' => ['user.roles', 'foo', 'bar'],
'tags' => ['a', 'b', 'c', 'd'],
'bin' => 'render',
'max-age' => 300,
@ -484,7 +483,7 @@ class RendererBubblingTest extends RendererTestBase {
$this->assertRenderCacheItem('parent:bar:foo:r.C', [
'#attached' => [],
'#cache' => [
'contexts' => ['bar', 'foo', 'user.roles'],
'contexts' => ['user.roles', 'foo', 'bar'],
'tags' => ['a', 'b', 'c', 'd'],
'max-age' => 300,
],
@ -499,7 +498,7 @@ class RendererBubblingTest extends RendererTestBase {
$this->assertRenderCacheItem('parent:bar:foo:r.A', [
'#attached' => [],
'#cache' => [
'contexts' => ['bar', 'foo', 'user.roles'],
'contexts' => ['user.roles', 'foo', 'bar'],
'tags' => ['a', 'b'],
// Note that the max-age here is unaffected. When role A, the grandchild
// is never rendered, so neither is its max-age of 1800 present here,
@ -518,7 +517,7 @@ class RendererBubblingTest extends RendererTestBase {
$this->assertRenderCacheItem('parent:bar:foo:r.B', [
'#attached' => [],
'#cache' => [
'contexts' => ['bar', 'foo', 'user.roles'],
'contexts' => ['user.roles', 'foo', 'bar'],
'tags' => ['a', 'b', 'c'],
// Note that the max-age here is unaffected. When role B, the
// grandgrandchild is never rendered, so neither is its max-age of 300

View File

@ -632,7 +632,7 @@ class RendererTest extends RendererTestBase {
$this->renderer->renderPlain($build);
$this->assertEquals(['languages:language_interface', 'theme', 'user'], $build['#cache']['contexts']);
$this->assertEqualsCanonicalizing(['languages:language_interface', 'theme', 'user'], $build['#cache']['contexts']);
}
/**

View File

@ -250,8 +250,18 @@ abstract class RendererTestBase extends UnitTestCase {
$cached = $cache_backend->get($cid);
$this->assertNotFalse($cached, sprintf('Expected cache item "%s" exists.', $cid));
if ($cached !== FALSE) {
$this->assertEquals($data, $cached->data, sprintf('Cache item "%s" has the expected data.', $cid));
$this->assertSame(Cache::mergeTags($data['#cache']['tags'], ['rendered']), $cached->tags, "The cache item's cache tags also has the 'rendered' cache tag.");
$this->assertEqualsCanonicalizing(array_keys($data), array_keys($cached->data), 'The cache item contains the same parent array keys.');
foreach ($data as $key => $value) {
// We do not want to assert on the order of cacheability information.
// @see https://www.drupal.org/project/drupal/issues/3225328
if ($key === '#cache') {
$this->assertEqualsCanonicalizing($value, $cached->data[$key], sprintf('Cache item "%s" has the expected data.', $cid));
}
else {
$this->assertEquals($value, $cached->data[$key], sprintf('Cache item "%s" has the expected data.', $cid));
}
}
$this->assertEqualsCanonicalizing(Cache::mergeTags($data['#cache']['tags'], ['rendered']), $cached->tags, "The cache item's cache tags also has the 'rendered' cache tag.");
}
}