Commit d2ebb7ad authored by alexpott's avatar alexpott

Issue #2493047 by Wim Leers: Cache redirects should be stored in the same cache bin

parent f6b2354f
......@@ -237,6 +237,8 @@ public function set(array &$elements, array $pre_bubbling_elements) {
'contexts' => $merged_cache_contexts,
// The union of the current element's and stored cache tags.
'tags' => Cache::mergeTags($stored_cache_tags, $data['#cache']['tags']),
// The same cache bin as the one for the actual render cache items.
'bin' => $bin,
],
];
$cache->set($pre_bubbling_cid, $redirect_data, $expire, Cache::mergeTags($redirect_data['#cache']['tags'], ['rendered']));
......
......@@ -7,6 +7,7 @@
namespace Drupal\Tests\Core\Render;
use Drupal\Core\Cache\MemoryBackend;
use Drupal\Core\KeyValueStore\KeyValueMemoryFactory;
use Drupal\Core\Render\Element;
use Drupal\Core\Render\Renderer;
......@@ -28,15 +29,15 @@ protected function setUp() {
$this->rendererConfig['required_cache_contexts'] = [];
parent::setUp();
$this->setUpRequest();
$this->setupMemoryCache();
}
/**
* Tests bubbling of assets when NOT using #pre_render callbacks.
*/
public function testBubblingWithoutPreRender() {
$this->setUpRequest();
$this->setupMemoryCache();
$this->elementInfo->expects($this->any())
->method('getInfo')
->willReturn([]);
......@@ -76,6 +77,58 @@ public function testBubblingWithoutPreRender() {
$this->assertEquals($element['#attached']['library'], $expected_libraries, 'The element, child and subchild #attached libraries are included.');
}
/**
* Tests cache context bubbling with a custom cache bin.
*/
public function testContextBubblingCustomCacheBin() {
$bin = $this->randomMachineName();
$this->setUpRequest();
$this->memoryCache = new MemoryBackend('render');
$custom_cache = new MemoryBackend($bin);
$this->cacheFactory->expects($this->atLeastOnce())
->method('get')
->with($bin)
->willReturnCallback(function($requested_bin) use ($bin, $custom_cache) {
if ($requested_bin === $bin) {
return $custom_cache;
}
else {
throw new \Exception();
}
});
$this->cacheContextsManager->expects($this->any())
->method('convertTokensToKeys')
->willReturnArgument(0);
$build = [
'#cache' => [
'keys' => ['parent'],
'contexts' => ['foo'],
'bin' => $bin,
],
'#markup' => 'parent',
'child' => [
'#cache' => [
'contexts' => ['bar'],
'max-age' => 3600,
],
],
];
$this->renderer->render($build);
$this->assertRenderCacheItem('parent:foo', [
'#cache_redirect' => TRUE,
'#cache' => [
'keys' => ['parent'],
'contexts' => ['bar', 'foo'],
'tags' => [],
'bin' => $bin,
],
], $bin);
}
/**
* Tests cache context bubbling in edge cases, because it affects the CID.
*
......@@ -228,6 +281,7 @@ public function providerTestContextBubblingEdgeCases() {
'keys' => ['parent'],
'contexts' => ['bar', 'foo'],
'tags' => ['dee', 'fiddle', 'har', 'yar'],
'bin' => 'render',
],
],
'parent:bar:foo' => [
......@@ -302,6 +356,7 @@ public function testConditionalCacheContextBubblingSelfHealing() {
'keys' => ['parent'],
'contexts' => ['user.roles'],
'tags' => ['a', 'b'],
'bin' => 'render',
],
]);
$this->assertRenderCacheItem('parent:r.A', [
......@@ -326,6 +381,7 @@ public function testConditionalCacheContextBubblingSelfHealing() {
'keys' => ['parent'],
'contexts' => ['foo', 'user.roles'],
'tags' => ['a', 'b', 'c'],
'bin' => 'render',
],
]);
$this->assertRenderCacheItem('parent:foo:r.B', [
......@@ -358,6 +414,7 @@ public function testConditionalCacheContextBubblingSelfHealing() {
'keys' => ['parent'],
'contexts' => ['foo', 'user.roles'],
'tags' => ['a', 'b', 'c'],
'bin' => 'render',
],
]);
$this->assertRenderCacheItem('parent:foo:r.A', [
......@@ -382,6 +439,7 @@ public function testConditionalCacheContextBubblingSelfHealing() {
'keys' => ['parent'],
'contexts' => ['bar', 'foo', 'user.roles'],
'tags' => ['a', 'b', 'c', 'd'],
'bin' => 'render',
],
];
$this->assertRenderCacheItem('parent', $final_parent_cache_item);
......@@ -435,6 +493,9 @@ public function testConditionalCacheContextBubblingSelfHealing() {
* @dataProvider providerTestBubblingWithPrerender
*/
public function testBubblingWithPrerender($test_element) {
$this->setUpRequest();
$this->setupMemoryCache();
// Mock the State service.
$memory_state = new State(new KeyValueMemoryFactory());;
\Drupal::getContainer()->set('state', $memory_state);
......
......@@ -172,6 +172,7 @@ protected function setupMemoryCache() {
$this->cacheFactory->expects($this->atLeastOnce())
->method('get')
->with('render')
->willReturn($this->memoryCache);
}
......@@ -195,9 +196,12 @@ protected function setUpRequest($method = 'GET') {
* The expected cache ID.
* @param mixed $data
* The expected data for that cache ID.
* @param string $bin
* The expected cache bin.
*/
protected function assertRenderCacheItem($cid, $data) {
$cached = $this->memoryCache->get($cid);
protected function assertRenderCacheItem($cid, $data, $bin = 'render') {
$cache_backend = $this->cacheFactory->get($bin);
$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));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment