.../Core/Cache/DatabaseCacheTagsChecksum.php | 6 +++ .../modules/node/src/Tests/Views/FrontPageTest.php | 55 ++++++++++++++++++++-- .../src/Tests/Cache/AssertPageCacheTagsTrait.php | 23 +++++---- core/modules/views/src/Tests/ViewTestBase.php | 47 ++++++++++++++++++ 4 files changed, 118 insertions(+), 13 deletions(-) diff --git a/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php b/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php index b6d9161..2f627ad 100644 --- a/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php +++ b/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php @@ -52,6 +52,12 @@ public function __construct(Connection $connection) { * {@inheritdoc} */ public function invalidateTags(array $tags) { + // DEBUG 1: debug output to help figure out why Views caching isn't working + // for the "first page" test in FrontPageTest. + if (substr($tags[0], 0, 4) === 'node') { + debug('invalidating'); + debug($tags); + } try { foreach ($tags as $tag) { // Only invalidate tags once per request unless they are written again. diff --git a/core/modules/node/src/Tests/Views/FrontPageTest.php b/core/modules/node/src/Tests/Views/FrontPageTest.php index 0f43c3b..c02b6e3 100644 --- a/core/modules/node/src/Tests/Views/FrontPageTest.php +++ b/core/modules/node/src/Tests/Views/FrontPageTest.php @@ -7,6 +7,7 @@ namespace Drupal\node\Tests\Views; +use Drupal\Core\Cache\Cache; use Drupal\Core\Url; use Drupal\node\Entity\Node; use Drupal\system\Tests\Cache\AssertPageCacheTagsTrait; @@ -185,10 +186,42 @@ public function testAdminFrontPage() { /** * Tests the cache tags on the front page. + * + * @todo Assertions ensuring the proper cache tags are present on the rendered + * views even when it's not using the 'tag' Views cache plugin. */ public function testCacheTags() { $this->enablePageCaching(); + // Enable tag-based caching on the view. + $view = Views::getView('frontpage'); + $view->setDisplay('page_1'); + $view->display_handler->overrideOption('cache', [ + 'type' => 'tag', + ]); + $view->save(); + + // DEBUG 2: Uncommenting this causes even the "test before there are any + // nodes" views caching test below to fail! +// $view = Views::getView('frontpage'); + + // Test before there are any nodes. + // DEBUG 3: if you disable this assertion, then the next assertion (the one + // for the first page) will work correctly, and correctly demonstrate that + // the results cache item does have the right cache tags, but the output + // cache item doesn't +///* + $empty_node_listing_cache_tags = [ + 'config:views.view.frontpage', + 'node_list', + ]; + $this->assertViewsCacheTags( + $view, + $empty_node_listing_cache_tags, + $empty_node_listing_cache_tags + ); +//*/ + // Create some nodes on the frontpage view. Add more than 10 nodes in order // to enable paging. $this->drupalCreateContentType(['type' => 'article']); @@ -210,18 +243,30 @@ public function testCacheTags() { } // First page. - $this->assertPageCacheTags(Url::fromRoute('view.frontpage.page_1'), [ - 'config:filter.format.plain_text', + $first_page_result_cache_tags = [ 'config:views.view.frontpage', 'node_list', - 'node_view', 'node:6', 'node:7', 'node:8', 'node:9', 'node:10', 'node:11', 'node:12', 'node:13', 'node:14', 'node:15', + ]; + $first_page_output_cache_tags = Cache::mergeTags($first_page_result_cache_tags, [ + 'config:filter.format.plain_text', + 'node_view', 'user_view', 'user:0', - 'rendered', ]); - + $this->assertViewsCacheTags( + $view, + $first_page_result_cache_tags, + $first_page_output_cache_tags + ); + $this->assertPageCacheTags( + Url::fromRoute('view.frontpage.page_1'), + Cache::mergeTags($first_page_output_cache_tags, ['rendered']) + ); + + // DEBUG: commenting the rest, let's first get the above to work. +return; // Second page. $this->assertPageCacheTags(Url::fromRoute('view.frontpage.page_1', [], ['query' => ['page' => 1]]), [ // The cache tags for the listed nodes. diff --git a/core/modules/system/src/Tests/Cache/AssertPageCacheTagsTrait.php b/core/modules/system/src/Tests/Cache/AssertPageCacheTagsTrait.php index 86192ed..6fed903 100644 --- a/core/modules/system/src/Tests/Cache/AssertPageCacheTagsTrait.php +++ b/core/modules/system/src/Tests/Cache/AssertPageCacheTagsTrait.php @@ -6,6 +6,7 @@ */ namespace Drupal\system\Tests\Cache; + use Drupal\Core\Url; /** @@ -15,7 +16,6 @@ */ trait AssertPageCacheTagsTrait { - /** * Enables page caching. */ @@ -27,25 +27,32 @@ protected function enablePageCaching() { } /** - * Fills page cache for the given path, verify cache tags on page cache hit. + * Asserts page cache miss, then hit for the given URL; checks cache tags. * * @param \Drupal\Core\Url $url - * The url - * @param $expected_tags - * The expected cache tags for the page cache entry of the given $path. + * The URL to test. + * @param string[] $expected_tags + * The expected cache tags for the given URL. */ - protected function assertPageCacheTags(Url $url, $expected_tags) { + protected function assertPageCacheTags(Url $url, array $expected_tags) { + $absolute_url = $url->setAbsolute()->toString(); sort($expected_tags); - $this->drupalGet($url->setAbsolute()->toString()); + + // Assert cache miss + expected cache tags. + $this->drupalGet($absolute_url); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS'); $actual_tags = explode(' ', $this->drupalGetHeader('X-Drupal-Cache-Tags')); sort($actual_tags); $this->assertIdentical($actual_tags, $expected_tags); - $this->drupalGet($url->setAbsolute()->toString()); + + // Assert cache hit + expected cache tags. + $this->drupalGet($absolute_url); $actual_tags = explode(' ', $this->drupalGetHeader('X-Drupal-Cache-Tags')); sort($actual_tags); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT'); $this->assertIdentical($actual_tags, $expected_tags); + + // Assert page cache item + expected cache tags. $cid_parts = array($url->setAbsolute()->toString(), 'html'); $cid = implode(':', $cid_parts); $cache_entry = \Drupal::cache('render')->get($cid); diff --git a/core/modules/views/src/Tests/ViewTestBase.php b/core/modules/views/src/Tests/ViewTestBase.php index 042c5ce..2e80e00 100644 --- a/core/modules/views/src/Tests/ViewTestBase.php +++ b/core/modules/views/src/Tests/ViewTestBase.php @@ -156,4 +156,51 @@ protected function dataSet() { return ViewTestData::dataSet(); } + /** + * Asserts a view's result & output cache items' cache tags. + * + * @param \Drupal\views\ViewExecutable $view + * The view to test, must have caching enabled. + * @param null|string[] $expected_results_cache + * NULL when expecting no results cache item, a set of cache tags expected + * to be set on the results cache item otherwise. + * @param null|string[] $expected_output_cache + * NULL when expecting no output cache item, a set of cache tags expected to + * be set on the output cache item otherwise. + */ + protected function assertViewsCacheTags(ViewExecutable $view, $expected_results_cache, $expected_output_cache) { + $view->render(); + + /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache_plugin */ + $cache_plugin = $view->display_handler->getPlugin('cache'); + + // Results cache. + $results_cache_item = \Drupal::cache('data')->get($cache_plugin->generateResultsKey()); + if (is_array($expected_results_cache)) { + $this->assertTrue($results_cache_item, 'Results cache item found.'); + if ($results_cache_item) { + sort($expected_results_cache); + $this->assertEqual($results_cache_item->tags, $expected_results_cache); + } + } + else { + $this->assertFalse($results_cache_item, 'Results cache item not found.'); + } + + // Output cache. + $output_cache_item = \Drupal::cache('render')->get($cache_plugin->generateOutputKey()); + if (is_array($expected_output_cache)) { + $this->assertTrue($output_cache_item, 'Output cache item found.'); + if ($output_cache_item) { + sort($expected_output_cache); + $this->assertEqual($output_cache_item->tags, $expected_output_cache); + } + } + else { + $this->assertFalse($output_cache_item, 'Output cache item not found.'); + } + + $view->destroy(); + } + }