3 namespace Drupal\Tests\Core\Cache;
5 use Drupal\Core\Cache\Cache;
6 use Drupal\Tests\UnitTestCase;
9 * @coversDefaultClass \Drupal\Core\Cache\CacheCollector
12 class CacheCollectorTest extends UnitTestCase {
15 * The cache backend that should be used.
17 * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject
19 protected $cacheBackend;
22 * The cache tags invalidator.
24 * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface|\PHPUnit_Framework_MockObject_MockObject
26 protected $cacheTagsInvalidator;
29 * The lock backend that should be used.
31 * @var \PHPUnit_Framework_MockObject_MockObject
36 * The cache id used for the test.
43 * Cache collector implementation to test.
45 * @var \Drupal\Tests\Core\Cache\CacheCollectorHelper
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);
59 $this->getContainerWithCacheTagsInvalidator($this->cacheTagsInvalidator);
64 * Tests the resolve cache miss function.
66 public function testResolveCacheMiss() {
67 $key = $this->randomMachineName();
68 $value = $this->randomMachineName();
69 $this->collector->setCacheMissData($key, $value);
71 $this->assertEquals($value, $this->collector->get($key));
75 * Tests setting and getting values when the cache is empty.
77 public function testSetAndGet() {
78 $key = $this->randomMachineName();
79 $value = $this->randomMachineName();
81 $this->assertNull($this->collector->get($key));
83 $this->collector->set($key, $value);
84 $this->assertTrue($this->collector->has($key));
85 $this->assertEquals($value, $this->collector->get($key));
90 * Makes sure that NULL is a valid value and is collected.
92 public function testSetAndGetNull() {
93 $key = $this->randomMachineName();
96 $this->cacheBackend->expects($this->once())
97 ->method('invalidate')
99 $this->collector->set($key, $value);
100 $this->assertTrue($this->collector->has($key));
101 $this->assertEquals($value, $this->collector->get($key));
103 // Ensure that getting a value that isn't set does not mark it as
105 $non_existing_key = $this->randomMachineName(7);
106 $this->collector->get($non_existing_key);
107 $this->assertFalse($this->collector->has($non_existing_key));
111 * Tests returning value from the collected cache.
113 public function testGetFromCache() {
114 $key = $this->randomMachineName();
115 $value = $this->randomMachineName();
118 'data' => [$key => $value],
119 'created' => (int) $_SERVER['REQUEST_TIME'],
121 $this->cacheBackend->expects($this->once())
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());
131 * Tests setting and deleting values.
133 public function testDelete() {
134 $key = $this->randomMachineName();
135 $value = $this->randomMachineName();
137 $this->assertNull($this->collector->get($key));
139 $this->collector->set($key, $value);
140 $this->assertTrue($this->collector->has($key));
141 $this->assertEquals($value, $this->collector->get($key));
143 $this->cacheBackend->expects($this->once())
144 ->method('invalidate')
146 $this->collector->delete($key);
147 $this->assertFalse($this->collector->has($key));
148 $this->assertEquals(NULL, $this->collector->get($key));
152 * Tests updating the cache when no changes were made.
154 public function testUpdateCacheNoChanges() {
155 $this->lock->expects($this->never())
157 $this->cacheBackend->expects($this->never())
160 // Destruct the object to trigger the update data process.
161 $this->collector->destruct();
165 * Tests updating the cache after a set.
167 public function testUpdateCache() {
168 $key = $this->randomMachineName();
169 $value = $this->randomMachineName();
171 $this->collector->setCacheMissData($key, $value);
172 $this->collector->get($key);
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())
179 ->with($this->cid . ':Drupal\Core\Cache\CacheCollector')
180 ->will($this->returnValue(TRUE));
181 $this->cacheBackend->expects($this->once())
183 ->with($this->cid, FALSE);
184 $this->cacheBackend->expects($this->once())
186 ->with($this->cid, [$key => $value], Cache::PERMANENT, []);
187 $this->lock->expects($this->once())
189 ->with($this->cid . ':Drupal\Core\Cache\CacheCollector');
191 // Destruct the object to trigger the update data process.
192 $this->collector->destruct();
197 * Tests updating the cache when the lock acquire fails.
199 public function testUpdateCacheLockFail() {
200 $key = $this->randomMachineName();
201 $value = $this->randomMachineName();
203 $this->collector->setCacheMissData($key, $value);
204 $this->collector->get($key);
206 // The lock acquire returns false, so the method should abort.
207 $this->lock->expects($this->once())
209 ->with($this->cid . ':Drupal\Core\Cache\CacheCollector')
210 ->will($this->returnValue(FALSE));
211 $this->cacheBackend->expects($this->never())
214 // Destruct the object to trigger the update data process.
215 $this->collector->destruct();
219 * Tests updating the cache when there is a conflict after cache invalidation.
221 public function testUpdateCacheInvalidatedConflict() {
222 $key = $this->randomMachineName();
223 $value = $this->randomMachineName();
226 'data' => [$key => $value],
227 'created' => (int) $_SERVER['REQUEST_TIME'],
229 $this->cacheBackend->expects($this->at(0))
232 ->will($this->returnValue($cache));
234 $this->cacheBackend->expects($this->at(1))
235 ->method('invalidate')
237 $this->collector->set($key, 'new value');
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())
244 ->with($this->cid . ':Drupal\Core\Cache\CacheCollector')
245 ->will($this->returnValue(TRUE));
247 'data' => [$key => $value],
248 'created' => (int) $_SERVER['REQUEST_TIME'] + 1,
250 $this->cacheBackend->expects($this->at(0))
253 ->will($this->returnValue($cache));
254 $this->cacheBackend->expects($this->once())
257 $this->lock->expects($this->once())
259 ->with($this->cid . ':Drupal\Core\Cache\CacheCollector');
261 // Destruct the object to trigger the update data process.
262 $this->collector->destruct();
266 * Tests updating the cache when a different request
268 public function testUpdateCacheMerge() {
269 $key = $this->randomMachineName();
270 $value = $this->randomMachineName();
272 $this->collector->setCacheMissData($key, $value);
273 $this->collector->get($key);
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())
280 ->with($this->cid . ':Drupal\Core\Cache\CacheCollector')
281 ->will($this->returnValue(TRUE));
283 'data' => ['other key' => 'other value'],
284 'created' => (int) $_SERVER['REQUEST_TIME'] + 1,
286 $this->cacheBackend->expects($this->at(0))
289 ->will($this->returnValue($cache));
290 $this->cacheBackend->expects($this->once())
292 ->with($this->cid, ['other key' => 'other value', $key => $value], Cache::PERMANENT, []);
293 $this->lock->expects($this->once())
295 ->with($this->cid . ':Drupal\Core\Cache\CacheCollector');
297 // Destruct the object to trigger the update data process.
298 $this->collector->destruct();
302 * Tests updating the cache after a delete.
304 public function testUpdateCacheDelete() {
305 $key = $this->randomMachineName();
306 $value = $this->randomMachineName();
309 'data' => [$key => $value],
310 'created' => (int) $_SERVER['REQUEST_TIME'],
312 $this->cacheBackend->expects($this->at(0))
315 ->will($this->returnValue($cache));
317 $this->collector->delete($key);
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())
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
328 $this->cacheBackend->expects($this->at(0))
330 ->with($this->cid, TRUE);
331 $this->cacheBackend->expects($this->once())
333 ->with($this->cid, [], Cache::PERMANENT, []);
334 $this->lock->expects($this->once())
336 ->with($this->cid . ':Drupal\Core\Cache\CacheCollector');
338 // Destruct the object to trigger the update data process.
339 $this->collector->destruct();
343 * Tests a reset of the cache collector.
345 public function testUpdateCacheReset() {
346 $key = $this->randomMachineName();
347 $value = $this->randomMachineName();
349 // Set the data and request it.
350 $this->collector->setCacheMissData($key, $value);
351 $this->assertEquals($value, $this->collector->get($key));
352 $this->assertEquals($value, $this->collector->get($key));
354 // Should have been added to the storage and only be requested once.
355 $this->assertEquals(1, $this->collector->getCacheMisses());
357 // Reset the collected cache, should call it again.
358 $this->collector->reset();
359 $this->assertEquals($value, $this->collector->get($key));
360 $this->assertEquals(2, $this->collector->getCacheMisses());
364 * Tests a clear of the cache collector.
366 public function testUpdateCacheClear() {
367 $key = $this->randomMachineName();
368 $value = $this->randomMachineName();
370 // Set the data and request it.
371 $this->collector->setCacheMissData($key, $value);
372 $this->assertEquals($value, $this->collector->get($key));
373 $this->assertEquals($value, $this->collector->get($key));
375 // Should have been added to the storage and only be requested once.
376 $this->assertEquals(1, $this->collector->getCacheMisses());
378 // Clear the collected cache, should call it again.
379 $this->cacheBackend->expects($this->once())
382 $this->cacheTagsInvalidator->expects($this->never())
383 ->method('invalidateTags');
384 $this->collector->clear();
385 $this->assertEquals($value, $this->collector->get($key));
386 $this->assertEquals(2, $this->collector->getCacheMisses());
390 * Tests a clear of the cache collector using tags.
392 public function testUpdateCacheClearTags() {
393 $key = $this->randomMachineName();
394 $value = $this->randomMachineName();
395 $tags = [$this->randomMachineName()];
396 $this->collector = new CacheCollectorHelper($this->cid, $this->cacheBackend, $this->lock, $tags);
398 // Set the data and request it.
399 $this->collector->setCacheMissData($key, $value);
400 $this->assertEquals($value, $this->collector->get($key));
401 $this->assertEquals($value, $this->collector->get($key));
403 // Should have been added to the storage and only be requested once.
404 $this->assertEquals(1, $this->collector->getCacheMisses());
406 // Clear the collected cache using the tags, should call it again.
407 $this->cacheBackend->expects($this->never())
409 $this->cacheTagsInvalidator->expects($this->once())
410 ->method('invalidateTags')
412 $this->collector->clear();
413 $this->assertEquals($value, $this->collector->get($key));
414 $this->assertEquals(2, $this->collector->getCacheMisses());