6bea791e910b9f0640ae9cec52aa5b306ff5882a
[yaffs-website] / web / core / modules / system / src / Tests / Cache / AssertPageCacheContextsAndTagsTrait.php
1 <?php
2
3 namespace Drupal\system\Tests\Cache;
4
5 use Drupal\Core\Cache\Cache;
6 use Drupal\Core\Url;
7
8 /**
9  * Provides test assertions for testing page-level cache contexts & tags.
10  *
11  * Can be used by test classes that extend \Drupal\simpletest\WebTestBase.
12  */
13 trait AssertPageCacheContextsAndTagsTrait {
14
15   /**
16    * Enables page caching.
17    */
18   protected function enablePageCaching() {
19     $config = $this->config('system.performance');
20     $config->set('cache.page.max_age', 300);
21     $config->save();
22   }
23
24   /**
25    * Gets a specific header value as array.
26    *
27    * @param string $header_name
28    *   The header name.
29    *
30    * @return string[]
31    *   The header value, potentially exploded by spaces.
32    */
33   protected function getCacheHeaderValues($header_name) {
34     $header_value = $this->drupalGetHeader($header_name);
35     if (empty($header_value)) {
36       return [];
37     }
38     else {
39       return explode(' ', $header_value);
40     }
41   }
42
43   /**
44    * Asserts whether an expected cache context was present in the last response.
45    *
46    * @param string $expected_cache_context
47    *   The expected cache context.
48    */
49   protected function assertCacheContext($expected_cache_context) {
50     $cache_contexts = explode(' ', $this->drupalGetHeader('X-Drupal-Cache-Contexts'));
51     $this->assertTrue(in_array($expected_cache_context, $cache_contexts), "'" . $expected_cache_context . "' is present in the X-Drupal-Cache-Contexts header.");
52   }
53
54   /**
55    * Asserts that a cache context was not present in the last response.
56    *
57    * @param string $not_expected_cache_context
58    *   The expected cache context.
59    */
60   protected function assertNoCacheContext($not_expected_cache_context) {
61     $cache_contexts = explode(' ', $this->drupalGetHeader('X-Drupal-Cache-Contexts'));
62     $this->assertFalse(in_array($not_expected_cache_context, $cache_contexts), "'" . $not_expected_cache_context . "' is not present in the X-Drupal-Cache-Contexts header.");
63   }
64
65   /**
66    * Asserts page cache miss, then hit for the given URL; checks cache headers.
67    *
68    * @param \Drupal\Core\Url $url
69    *   The URL to test.
70    * @param string[] $expected_contexts
71    *   The expected cache contexts for the given URL.
72    * @param string[] $expected_tags
73    *   The expected cache tags for the given URL.
74    */
75   protected function assertPageCacheContextsAndTags(Url $url, array $expected_contexts, array $expected_tags) {
76     $absolute_url = $url->setAbsolute()->toString();
77     sort($expected_contexts);
78     sort($expected_tags);
79
80     // Assert cache miss + expected cache contexts + tags.
81     $this->drupalGet($absolute_url);
82     $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
83     $this->assertCacheTags($expected_tags);
84     $this->assertCacheContexts($expected_contexts);
85
86     // Assert cache hit + expected cache contexts + tags.
87     $this->drupalGet($absolute_url);
88     $this->assertCacheTags($expected_tags);
89     $this->assertCacheContexts($expected_contexts);
90
91     // Assert page cache item + expected cache tags.
92     $cid_parts = [$url->setAbsolute()->toString(), 'html'];
93     $cid = implode(':', $cid_parts);
94     $cache_entry = \Drupal::cache('render')->get($cid);
95     sort($cache_entry->tags);
96     $this->assertEqual($cache_entry->tags, $expected_tags);
97     $this->debugCacheTags($cache_entry->tags, $expected_tags);
98   }
99
100   /**
101    * Provides debug information for cache tags.
102    *
103    * @param string[] $actual_tags
104    *   The actual cache tags.
105    * @param string[] $expected_tags
106    *   The expected cache tags.
107    */
108   protected function debugCacheTags(array $actual_tags, array $expected_tags) {
109     if ($actual_tags !== $expected_tags) {
110       debug('Unwanted cache tags in response: ' . implode(',', array_diff($actual_tags, $expected_tags)));
111       debug('Missing cache tags in response: ' . implode(',', array_diff($expected_tags, $actual_tags)));
112     }
113   }
114
115   /**
116    * Ensures that some cache tags are present in the current response.
117    *
118    * @param string[] $expected_tags
119    *   The expected tags.
120    * @param bool $include_default_tags
121    *   (optional) Whether the default cache tags should be included.
122    */
123   protected function assertCacheTags(array $expected_tags, $include_default_tags = TRUE) {
124     // The anonymous role cache tag is only added if the user is anonymous.
125     if ($include_default_tags) {
126       if (\Drupal::currentUser()->isAnonymous()) {
127         $expected_tags = Cache::mergeTags($expected_tags, ['config:user.role.anonymous']);
128       }
129       $expected_tags[] = 'http_response';
130     }
131     $actual_tags = $this->getCacheHeaderValues('X-Drupal-Cache-Tags');
132     $expected_tags = array_unique($expected_tags);
133     sort($expected_tags);
134     sort($actual_tags);
135     $this->assertIdentical($actual_tags, $expected_tags);
136     $this->debugCacheTags($actual_tags, $expected_tags);
137   }
138
139   /**
140    * Ensures that some cache contexts are present in the current response.
141    *
142    * @param string[] $expected_contexts
143    *   The expected cache contexts.
144    * @param string $message
145    *   (optional) A verbose message to output.
146    * @param bool $include_default_contexts
147    *   (optional) Whether the default contexts should automatically be included.
148    *
149    * @return bool
150    *   TRUE if the assertion succeeded, FALSE otherwise.
151    */
152   protected function assertCacheContexts(array $expected_contexts, $message = NULL, $include_default_contexts = TRUE) {
153     if ($include_default_contexts) {
154       $default_contexts = ['languages:language_interface', 'theme'];
155       // Add the user.permission context to the list of default contexts except
156       // when user is already there.
157       if (!in_array('user', $expected_contexts)) {
158         $default_contexts[] = 'user.permissions';
159       }
160       $expected_contexts = Cache::mergeContexts($expected_contexts, $default_contexts);
161     }
162
163     $actual_contexts = $this->getCacheHeaderValues('X-Drupal-Cache-Contexts');
164     sort($expected_contexts);
165     sort($actual_contexts);
166     $match = $actual_contexts === $expected_contexts;
167     if (!$match) {
168       debug('Unwanted cache contexts in response: ' . implode(',', array_diff($actual_contexts, $expected_contexts)));
169       debug('Missing cache contexts in response: ' . implode(',', array_diff($expected_contexts, $actual_contexts)));
170     }
171
172     $this->assertIdentical($actual_contexts, $expected_contexts, $message);
173
174     // For compatibility with both BrowserTestBase and WebTestBase always return
175     // a boolean.
176     return $match;
177   }
178
179   /**
180    * Asserts the max age header.
181    *
182    * @param int $max_age
183    */
184   protected function assertCacheMaxAge($max_age) {
185     $cache_control_header = $this->drupalGetHeader('Cache-Control');
186     if (strpos($cache_control_header, 'max-age:' . $max_age) === FALSE) {
187       debug('Expected max-age:' . $max_age . '; Response max-age:' . $cache_control_header);
188     }
189     $this->assertTrue(strpos($cache_control_header, 'max-age:' . $max_age));
190   }
191
192 }