Upgraded drupal core with security updates
[yaffs-website] / web / core / tests / Drupal / Tests / Core / Cache / CacheCollectorTest.php
1 <?php
2
3 namespace Drupal\Tests\Core\Cache;
4
5 use Drupal\Core\Cache\Cache;
6 use Drupal\Tests\UnitTestCase;
7
8 /**
9  * @coversDefaultClass \Drupal\Core\Cache\CacheCollector
10  * @group Cache
11  */
12 class CacheCollectorTest extends UnitTestCase {
13
14   /**
15    * The cache backend that should be used.
16    *
17    * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject
18    */
19   protected $cacheBackend;
20
21   /**
22    * The cache tags invalidator.
23    *
24    * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface|\PHPUnit_Framework_MockObject_MockObject
25    */
26   protected $cacheTagsInvalidator;
27
28   /**
29    * The lock backend that should be used.
30    *
31    * @var \PHPUnit_Framework_MockObject_MockObject
32    */
33   protected $lock;
34
35   /**
36    * The cache id used for the test.
37    *
38    * @var string
39    */
40   protected $cid;
41
42   /**
43    * Cache collector implementation to test.
44    *
45    * @var \Drupal\Tests\Core\Cache\CacheCollectorHelper
46    */
47   protected $collector;
48
49   /**
50    * {@inheritdoc}
51    */
52   protected function setUp() {
53     $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
54     $this->cacheTagsInvalidator = $this->getMock('Drupal\Core\Cache\CacheTagsInvalidatorInterface');
55     $this->lock = $this->getMock('Drupal\Core\Lock\LockBackendInterface');
56     $this->cid = $this->randomMachineName();
57     $this->collector = new CacheCollectorHelper($this->cid, $this->cacheBackend, $this->lock);
58
59     $this->getContainerWithCacheTagsInvalidator($this->cacheTagsInvalidator);
60   }
61
62
63   /**
64    * Tests the resolve cache miss function.
65    */
66   public function testResolveCacheMiss() {
67     $key = $this->randomMachineName();
68     $value = $this->randomMachineName();
69     $this->collector->setCacheMissData($key, $value);
70
71     $this->assertEquals($value, $this->collector->get($key));
72   }
73
74   /**
75    * Tests setting and getting values when the cache is empty.
76    */
77   public function testSetAndGet() {
78     $key = $this->randomMachineName();
79     $value = $this->randomMachineName();
80
81     $this->assertNull($this->collector->get($key));
82
83     $this->collector->set($key, $value);
84     $this->assertTrue($this->collector->has($key));
85     $this->assertEquals($value, $this->collector->get($key));
86   }
87
88
89   /**
90    * Makes sure that NULL is a valid value and is collected.
91    */
92   public function testSetAndGetNull() {
93     $key = $this->randomMachineName();
94     $value = NULL;
95
96     $this->cacheBackend->expects($this->once())
97       ->method('invalidate')
98       ->with($this->cid);
99     $this->collector->set($key, $value);
100     $this->assertTrue($this->collector->has($key));
101     $this->assertEquals($value, $this->collector->get($key));
102
103     // Ensure that getting a value that isn't set does not mark it as
104     // existent.
105     $non_existing_key = $this->randomMachineName(7);
106     $this->collector->get($non_existing_key);
107     $this->assertFalse($this->collector->has($non_existing_key));
108   }
109
110   /**
111    * Tests returning value from the collected cache.
112    */
113   public function testGetFromCache() {
114     $key = $this->randomMachineName();
115     $value = $this->randomMachineName();
116
117     $cache = (object) [
118       'data' => [$key => $value],
119       'created' => (int) $_SERVER['REQUEST_TIME'],
120     ];
121     $this->cacheBackend->expects($this->once())
122       ->method('get')
123       ->with($this->cid)
124       ->will($this->returnValue($cache));
125     $this->assertTrue($this->collector->has($key));
126     $this->assertEquals($value, $this->collector->get($key));
127     $this->assertEquals(0, $this->collector->getCacheMisses());
128   }
129
130   /**
131    * Tests setting and deleting values.
132    */
133   public function testDelete() {
134     $key = $this->randomMachineName();
135     $value = $this->randomMachineName();
136
137     $this->assertNull($this->collector->get($key));
138
139     $this->collector->set($key, $value);
140     $this->assertTrue($this->collector->has($key));
141     $this->assertEquals($value, $this->collector->get($key));
142
143     $this->cacheBackend->expects($this->once())
144       ->method('invalidate')
145       ->with($this->cid);
146     $this->collector->delete($key);
147     $this->assertFalse($this->collector->has($key));
148     $this->assertEquals(NULL, $this->collector->get($key));
149   }
150
151   /**
152    * Tests updating the cache when no changes were made.
153    */
154   public function testUpdateCacheNoChanges() {
155     $this->lock->expects($this->never())
156       ->method('acquire');
157     $this->cacheBackend->expects($this->never())
158       ->method('set');
159
160     // Destruct the object to trigger the update data process.
161     $this->collector->destruct();
162   }
163
164   /**
165    * Tests updating the cache after a set.
166    */
167   public function testUpdateCache() {
168     $key = $this->randomMachineName();
169     $value = $this->randomMachineName();
170
171     $this->collector->setCacheMissData($key, $value);
172     $this->collector->get($key);
173
174     // Set up mock objects for the expected calls, first a lock acquire, then
175     // cache get to look for conflicting cache entries, then a cache set and
176     // finally the lock is released again.
177     $this->lock->expects($this->once())
178       ->method('acquire')
179       ->with($this->cid . ':Drupal\Core\Cache\CacheCollector')
180       ->will($this->returnValue(TRUE));
181     $this->cacheBackend->expects($this->once())
182       ->method('get')
183       ->with($this->cid, FALSE);
184     $this->cacheBackend->expects($this->once())
185       ->method('set')
186       ->with($this->cid, [$key => $value], Cache::PERMANENT, []);
187     $this->lock->expects($this->once())
188       ->method('release')
189       ->with($this->cid . ':Drupal\Core\Cache\CacheCollector');
190
191     // Destruct the object to trigger the update data process.
192     $this->collector->destruct();
193   }
194
195
196   /**
197    * Tests updating the cache when the lock acquire fails.
198    */
199   public function testUpdateCacheLockFail() {
200     $key = $this->randomMachineName();
201     $value = $this->randomMachineName();
202
203     $this->collector->setCacheMissData($key, $value);
204     $this->collector->get($key);
205
206     // The lock acquire returns false, so the method should abort.
207     $this->lock->expects($this->once())
208       ->method('acquire')
209       ->with($this->cid . ':Drupal\Core\Cache\CacheCollector')
210       ->will($this->returnValue(FALSE));
211     $this->cacheBackend->expects($this->never())
212       ->method('set');
213
214     // Destruct the object to trigger the update data process.
215     $this->collector->destruct();
216   }
217
218   /**
219    * Tests updating the cache when there is a conflict after cache invalidation.
220    */
221   public function testUpdateCacheInvalidatedConflict() {
222     $key = $this->randomMachineName();
223     $value = $this->randomMachineName();
224
225     $cache = (object) [
226       'data' => [$key => $value],
227       'created' => (int) $_SERVER['REQUEST_TIME'],
228     ];
229     $this->cacheBackend->expects($this->at(0))
230       ->method('get')
231       ->with($this->cid)
232       ->will($this->returnValue($cache));
233
234     $this->cacheBackend->expects($this->at(1))
235       ->method('invalidate')
236       ->with($this->cid);
237     $this->collector->set($key, 'new value');
238
239     // Set up mock objects for the expected calls, first a lock acquire, then
240     // cache get to look for conflicting cache entries, which does find
241     // and then it deletes the cache and aborts.
242     $this->lock->expects($this->once())
243       ->method('acquire')
244       ->with($this->cid . ':Drupal\Core\Cache\CacheCollector')
245       ->will($this->returnValue(TRUE));
246     $cache = (object) [
247       'data' => [$key => $value],
248       'created' => (int) $_SERVER['REQUEST_TIME'] + 1,
249     ];
250     $this->cacheBackend->expects($this->at(0))
251       ->method('get')
252       ->with($this->cid)
253       ->will($this->returnValue($cache));
254     $this->cacheBackend->expects($this->once())
255       ->method('delete')
256       ->with($this->cid);
257     $this->lock->expects($this->once())
258       ->method('release')
259       ->with($this->cid . ':Drupal\Core\Cache\CacheCollector');
260
261     // Destruct the object to trigger the update data process.
262     $this->collector->destruct();
263   }
264
265   /**
266    * Tests updating the cache when a different request
267    */
268   public function testUpdateCacheMerge() {
269     $key = $this->randomMachineName();
270     $value = $this->randomMachineName();
271
272     $this->collector->setCacheMissData($key, $value);
273     $this->collector->get($key);
274
275     // Set up mock objects for the expected calls, first a lock acquire, then
276     // cache get to look for existing cache entries, which does find
277     // and then it merges them.
278     $this->lock->expects($this->once())
279       ->method('acquire')
280       ->with($this->cid . ':Drupal\Core\Cache\CacheCollector')
281       ->will($this->returnValue(TRUE));
282     $cache = (object) [
283       'data' => ['other key' => 'other value'],
284       'created' => (int) $_SERVER['REQUEST_TIME'] + 1,
285     ];
286     $this->cacheBackend->expects($this->at(0))
287       ->method('get')
288       ->with($this->cid)
289       ->will($this->returnValue($cache));
290     $this->cacheBackend->expects($this->once())
291       ->method('set')
292       ->with($this->cid, ['other key' => 'other value', $key => $value], Cache::PERMANENT, []);
293     $this->lock->expects($this->once())
294       ->method('release')
295       ->with($this->cid . ':Drupal\Core\Cache\CacheCollector');
296
297     // Destruct the object to trigger the update data process.
298     $this->collector->destruct();
299   }
300
301   /**
302    * Tests updating the cache after a delete.
303    */
304   public function testUpdateCacheDelete() {
305     $key = $this->randomMachineName();
306     $value = $this->randomMachineName();
307
308     $cache = (object) [
309       'data' => [$key => $value],
310       'created' => (int) $_SERVER['REQUEST_TIME'],
311     ];
312     $this->cacheBackend->expects($this->at(0))
313       ->method('get')
314       ->with($this->cid)
315       ->will($this->returnValue($cache));
316
317     $this->collector->delete($key);
318
319     // Set up mock objects for the expected calls, first a lock acquire, then
320     // cache get to look for conflicting cache entries, then a cache set and
321     // finally the lock is released again.
322     $this->lock->expects($this->once())
323       ->method('acquire')
324       ->with($this->cid . ':Drupal\Core\Cache\CacheCollector')
325       ->will($this->returnValue(TRUE));
326     // The second argument is set to TRUE because we triggered a cache
327     // invalidation.
328     $this->cacheBackend->expects($this->at(0))
329       ->method('get')
330       ->with($this->cid, TRUE)
331       ->will($this->returnValue($cache));
332     $this->cacheBackend->expects($this->once())
333       ->method('set')
334       ->with($this->cid, [], Cache::PERMANENT, []);
335     $this->lock->expects($this->once())
336       ->method('release')
337       ->with($this->cid . ':Drupal\Core\Cache\CacheCollector');
338
339     // Destruct the object to trigger the update data process.
340     $this->collector->destruct();
341   }
342
343   /**
344    * Tests a reset of the cache collector.
345    */
346   public function testUpdateCacheReset() {
347     $key = $this->randomMachineName();
348     $value = $this->randomMachineName();
349
350     // Set the data and request it.
351     $this->collector->setCacheMissData($key, $value);
352     $this->assertEquals($value, $this->collector->get($key));
353     $this->assertEquals($value, $this->collector->get($key));
354
355     // Should have been added to the storage and only be requested once.
356     $this->assertEquals(1, $this->collector->getCacheMisses());
357
358     // Reset the collected cache, should call it again.
359     $this->collector->reset();
360     $this->assertEquals($value, $this->collector->get($key));
361     $this->assertEquals(2, $this->collector->getCacheMisses());
362   }
363
364   /**
365    * Tests a clear of the cache collector.
366    */
367   public function testUpdateCacheClear() {
368     $key = $this->randomMachineName();
369     $value = $this->randomMachineName();
370
371     // Set the data and request it.
372     $this->collector->setCacheMissData($key, $value);
373     $this->assertEquals($value, $this->collector->get($key));
374     $this->assertEquals($value, $this->collector->get($key));
375
376     // Should have been added to the storage and only be requested once.
377     $this->assertEquals(1, $this->collector->getCacheMisses());
378
379     // Clear the collected cache, should call it again.
380     $this->cacheBackend->expects($this->once())
381       ->method('delete')
382       ->with($this->cid);
383     $this->cacheTagsInvalidator->expects($this->never())
384       ->method('invalidateTags');
385     $this->collector->clear();
386     $this->assertEquals($value, $this->collector->get($key));
387     $this->assertEquals(2, $this->collector->getCacheMisses());
388   }
389
390   /**
391    * Tests a clear of the cache collector using tags.
392    */
393   public function testUpdateCacheClearTags() {
394     $key = $this->randomMachineName();
395     $value = $this->randomMachineName();
396     $tags = [$this->randomMachineName()];
397     $this->collector = new CacheCollectorHelper($this->cid, $this->cacheBackend, $this->lock, $tags);
398
399     // Set the data and request it.
400     $this->collector->setCacheMissData($key, $value);
401     $this->assertEquals($value, $this->collector->get($key));
402     $this->assertEquals($value, $this->collector->get($key));
403
404     // Should have been added to the storage and only be requested once.
405     $this->assertEquals(1, $this->collector->getCacheMisses());
406
407     // Clear the collected cache using the tags, should call it again.
408     $this->cacheBackend->expects($this->never())
409       ->method('delete');
410     $this->cacheTagsInvalidator->expects($this->once())
411       ->method('invalidateTags')
412       ->with($tags);
413     $this->collector->clear();
414     $this->assertEquals($value, $this->collector->get($key));
415     $this->assertEquals(2, $this->collector->getCacheMisses());
416   }
417
418 }