Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / tests / Drupal / Tests / Core / Path / AliasManagerTest.php
1 <?php
2
3 namespace Drupal\Tests\Core\Path;
4
5 use Drupal\Core\Language\Language;
6 use Drupal\Core\Language\LanguageInterface;
7 use Drupal\Core\Path\AliasManager;
8 use Drupal\Tests\UnitTestCase;
9
10 /**
11  * @coversDefaultClass \Drupal\Core\Path\AliasManager
12  * @group Path
13  */
14 class AliasManagerTest extends UnitTestCase {
15
16   /**
17    * The alias manager.
18    *
19    * @var \Drupal\Core\Path\AliasManager
20    */
21   protected $aliasManager;
22
23   /**
24    * Alias storage.
25    *
26    * @var \Drupal\Core\Path\AliasStorageInterface|\PHPUnit_Framework_MockObject_MockObject
27    */
28   protected $aliasStorage;
29
30   /**
31    * Alias whitelist.
32    *
33    * @var \Drupal\Core\Path\AliasWhitelistInterface|\PHPUnit_Framework_MockObject_MockObject
34    */
35   protected $aliasWhitelist;
36
37   /**
38    * Language manager.
39    *
40    * @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit_Framework_MockObject_MockObject
41    */
42   protected $languageManager;
43
44   /**
45    * Cache backend.
46    *
47    * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject
48    */
49   protected $cache;
50
51   /**
52    * The internal cache key used by the alias manager.
53    *
54    * @var string
55    */
56   protected $cacheKey = 'preload-paths:key';
57
58   /**
59    * The cache key passed to the alias manager.
60    *
61    * @var string
62    */
63   protected $path = 'key';
64
65   /**
66    * {@inheritdoc}
67    */
68   protected function setUp() {
69     parent::setUp();
70
71     $this->aliasStorage = $this->getMock('Drupal\Core\Path\AliasStorageInterface');
72     $this->aliasWhitelist = $this->getMock('Drupal\Core\Path\AliasWhitelistInterface');
73     $this->languageManager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
74     $this->cache = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
75
76     $this->aliasManager = new AliasManager($this->aliasStorage, $this->aliasWhitelist, $this->languageManager, $this->cache);
77
78   }
79
80   /**
81    * Tests the getPathByAlias method for an alias that have no matching path.
82    *
83    * @covers ::getPathByAlias
84    */
85   public function testGetPathByAliasNoMatch() {
86     $alias = '/' . $this->randomMachineName();
87
88     $language = new Language(['id' => 'en']);
89
90     $this->languageManager->expects($this->any())
91       ->method('getCurrentLanguage')
92       ->with(LanguageInterface::TYPE_URL)
93       ->will($this->returnValue($language));
94
95     $this->aliasStorage->expects($this->once())
96       ->method('lookupPathSource')
97       ->with($alias, $language->getId())
98       ->will($this->returnValue(NULL));
99
100     $this->assertEquals($alias, $this->aliasManager->getPathByAlias($alias));
101     // Call it twice to test the static cache.
102     $this->assertEquals($alias, $this->aliasManager->getPathByAlias($alias));
103   }
104
105   /**
106    * Tests the getPathByAlias method for an alias that have a matching path.
107    *
108    * @covers ::getPathByAlias
109    */
110   public function testGetPathByAliasNatch() {
111     $alias = $this->randomMachineName();
112     $path = $this->randomMachineName();
113
114     $language = $this->setUpCurrentLanguage();
115
116     $this->aliasStorage->expects($this->once())
117       ->method('lookupPathSource')
118       ->with($alias, $language->getId())
119       ->will($this->returnValue($path));
120
121     $this->assertEquals($path, $this->aliasManager->getPathByAlias($alias));
122     // Call it twice to test the static cache.
123     $this->assertEquals($path, $this->aliasManager->getPathByAlias($alias));
124   }
125
126   /**
127    * Tests the getPathByAlias method when a langcode is passed explicitly.
128    *
129    * @covers ::getPathByAlias
130    */
131   public function testGetPathByAliasLangcode() {
132     $alias = $this->randomMachineName();
133     $path = $this->randomMachineName();
134
135     $this->languageManager->expects($this->never())
136       ->method('getCurrentLanguage');
137
138     $this->aliasStorage->expects($this->once())
139       ->method('lookupPathSource')
140       ->with($alias, 'de')
141       ->will($this->returnValue($path));
142
143     $this->assertEquals($path, $this->aliasManager->getPathByAlias($alias, 'de'));
144     // Call it twice to test the static cache.
145     $this->assertEquals($path, $this->aliasManager->getPathByAlias($alias, 'de'));
146   }
147
148   /**
149    * Tests the getAliasByPath method for a path that is not in the whitelist.
150    *
151    * @covers ::getAliasByPath
152    */
153   public function testGetAliasByPathWhitelist() {
154     $path_part1 = $this->randomMachineName();
155     $path_part2 = $this->randomMachineName();
156     $path = '/' . $path_part1 . '/' . $path_part2;
157
158     $this->setUpCurrentLanguage();
159
160     $this->aliasWhitelist->expects($this->any())
161       ->method('get')
162       ->with($path_part1)
163       ->will($this->returnValue(FALSE));
164
165     // The whitelist returns FALSE for that path part, so the storage should
166     // never be called.
167     $this->aliasStorage->expects($this->never())
168       ->method('lookupPathAlias');
169
170     $this->assertEquals($path, $this->aliasManager->getAliasByPath($path));
171   }
172
173   /**
174    * Tests the getAliasByPath method for a path that has no matching alias.
175    *
176    * @covers ::getAliasByPath
177    */
178   public function testGetAliasByPathNoMatch() {
179     $path_part1 = $this->randomMachineName();
180     $path_part2 = $this->randomMachineName();
181     $path = '/' . $path_part1 . '/' . $path_part2;
182
183     $language = $this->setUpCurrentLanguage();
184
185     $this->aliasManager->setCacheKey($this->path);
186
187     $this->aliasWhitelist->expects($this->any())
188       ->method('get')
189       ->with($path_part1)
190       ->will($this->returnValue(TRUE));
191
192     $this->aliasStorage->expects($this->once())
193       ->method('lookupPathAlias')
194       ->with($path, $language->getId())
195       ->will($this->returnValue(NULL));
196
197     $this->assertEquals($path, $this->aliasManager->getAliasByPath($path));
198     // Call it twice to test the static cache.
199     $this->assertEquals($path, $this->aliasManager->getAliasByPath($path));
200
201     // This needs to write out the cache.
202     $this->cache->expects($this->once())
203       ->method('set')
204       ->with($this->cacheKey, [$language->getId() => [$path]], (int) $_SERVER['REQUEST_TIME'] + (60 * 60 * 24));
205
206     $this->aliasManager->writeCache();
207   }
208
209   /**
210    * Tests the getAliasByPath method for a path that has a matching alias.
211    *
212    * @covers ::getAliasByPath
213    * @covers ::writeCache
214    */
215   public function testGetAliasByPathMatch() {
216     $path_part1 = $this->randomMachineName();
217     $path_part2 = $this->randomMachineName();
218     $path = '/' . $path_part1 . '/' . $path_part2;
219     $alias = $this->randomMachineName();
220
221     $language = $this->setUpCurrentLanguage();
222
223     $this->aliasManager->setCacheKey($this->path);
224
225     $this->aliasWhitelist->expects($this->any())
226       ->method('get')
227       ->with($path_part1)
228       ->will($this->returnValue(TRUE));
229
230     $this->aliasStorage->expects($this->once())
231       ->method('lookupPathAlias')
232       ->with($path, $language->getId())
233       ->will($this->returnValue($alias));
234
235     $this->assertEquals($alias, $this->aliasManager->getAliasByPath($path));
236     // Call it twice to test the static cache.
237     $this->assertEquals($alias, $this->aliasManager->getAliasByPath($path));
238
239     // This needs to write out the cache.
240     $this->cache->expects($this->once())
241       ->method('set')
242       ->with($this->cacheKey, [$language->getId() => [$path]], (int) $_SERVER['REQUEST_TIME'] + (60 * 60 * 24));
243
244     $this->aliasManager->writeCache();
245   }
246
247   /**
248    * Tests the getAliasByPath method for a path that is preloaded.
249    *
250    * @covers ::getAliasByPath
251    * @covers ::writeCache
252    */
253   public function testGetAliasByPathCachedMatch() {
254     $path_part1 = $this->randomMachineName();
255     $path_part2 = $this->randomMachineName();
256     $path = '/' . $path_part1 . '/' . $path_part2;
257     $alias = $this->randomMachineName();
258
259     $language = $this->setUpCurrentLanguage();
260
261     $cached_paths = [$language->getId() => [$path]];
262     $this->cache->expects($this->once())
263       ->method('get')
264       ->with($this->cacheKey)
265       ->will($this->returnValue((object) ['data' => $cached_paths]));
266
267     // Simulate a request so that the preloaded paths are fetched.
268     $this->aliasManager->setCacheKey($this->path);
269
270     $this->aliasWhitelist->expects($this->any())
271       ->method('get')
272       ->with($path_part1)
273       ->will($this->returnValue(TRUE));
274
275     $this->aliasStorage->expects($this->once())
276       ->method('preloadPathAlias')
277       ->with($cached_paths[$language->getId()], $language->getId())
278       ->will($this->returnValue([$path => $alias]));
279
280     // LookupPathAlias should not be called.
281     $this->aliasStorage->expects($this->never())
282       ->method('lookupPathAlias');
283
284     $this->assertEquals($alias, $this->aliasManager->getAliasByPath($path));
285     // Call it twice to test the static cache.
286     $this->assertEquals($alias, $this->aliasManager->getAliasByPath($path));
287
288     // This must not write to the cache again.
289     $this->cache->expects($this->never())
290       ->method('set');
291     $this->aliasManager->writeCache();
292   }
293
294   /**
295    * Tests the getAliasByPath cache when a different language is requested.
296    *
297    * @covers ::getAliasByPath
298    * @covers ::writeCache
299    */
300   public function testGetAliasByPathCachedMissLanguage() {
301     $path_part1 = $this->randomMachineName();
302     $path_part2 = $this->randomMachineName();
303     $path = '/' . $path_part1 . '/' . $path_part2;
304     $alias = $this->randomMachineName();
305
306     $language = $this->setUpCurrentLanguage();
307     $cached_language = new Language(['id' => 'de']);
308
309     $cached_paths = [$cached_language->getId() => [$path]];
310     $this->cache->expects($this->once())
311       ->method('get')
312       ->with($this->cacheKey)
313       ->will($this->returnValue((object) ['data' => $cached_paths]));
314
315     // Simulate a request so that the preloaded paths are fetched.
316     $this->aliasManager->setCacheKey($this->path);
317
318     $this->aliasWhitelist->expects($this->any())
319       ->method('get')
320       ->with($path_part1)
321       ->will($this->returnValue(TRUE));
322
323     // The requested language is different than the cached, so this will
324     // need to load.
325     $this->aliasStorage->expects($this->never())
326       ->method('preloadPathAlias');
327     $this->aliasStorage->expects($this->once())
328       ->method('lookupPathAlias')
329       ->with($path, $language->getId())
330       ->will($this->returnValue($alias));
331
332     $this->assertEquals($alias, $this->aliasManager->getAliasByPath($path));
333     // Call it twice to test the static cache.
334     $this->assertEquals($alias, $this->aliasManager->getAliasByPath($path));
335
336     // There is already a cache entry, so this should not write out to the
337     // cache.
338     $this->cache->expects($this->never())
339       ->method('set');
340     $this->aliasManager->writeCache();
341   }
342
343   /**
344    * Tests the getAliasByPath cache with a preloaded path without alias.
345    *
346    * @covers ::getAliasByPath
347    * @covers ::writeCache
348    */
349   public function testGetAliasByPathCachedMissNoAlias() {
350     $path_part1 = $this->randomMachineName();
351     $path_part2 = $this->randomMachineName();
352     $path = '/' . $path_part1 . '/' . $path_part2;
353     $cached_path = $this->randomMachineName();
354     $cached_alias = $this->randomMachineName();
355
356     $language = $this->setUpCurrentLanguage();
357
358     $cached_paths = [$language->getId() => [$cached_path, $path]];
359     $this->cache->expects($this->once())
360       ->method('get')
361       ->with($this->cacheKey)
362       ->will($this->returnValue((object) ['data' => $cached_paths]));
363
364     // Simulate a request so that the preloaded paths are fetched.
365     $this->aliasManager->setCacheKey($this->path);
366
367     $this->aliasWhitelist->expects($this->any())
368       ->method('get')
369       ->with($path_part1)
370       ->will($this->returnValue(TRUE));
371
372     $this->aliasStorage->expects($this->once())
373       ->method('preloadPathAlias')
374       ->with($cached_paths[$language->getId()], $language->getId())
375       ->will($this->returnValue([$cached_path => $cached_alias]));
376
377     // LookupPathAlias() should not be called.
378     $this->aliasStorage->expects($this->never())
379       ->method('lookupPathAlias');
380
381     $this->assertEquals($path, $this->aliasManager->getAliasByPath($path));
382     // Call it twice to test the static cache.
383     $this->assertEquals($path, $this->aliasManager->getAliasByPath($path));
384
385     // This must not write to the cache again.
386     $this->cache->expects($this->never())
387       ->method('set');
388     $this->aliasManager->writeCache();
389   }
390
391   /**
392    * Tests the getAliasByPath cache with an unpreloaded path without alias.
393    *
394    * @covers ::getAliasByPath
395    * @covers ::writeCache
396    */
397   public function testGetAliasByPathUncachedMissNoAlias() {
398     $path_part1 = $this->randomMachineName();
399     $path_part2 = $this->randomMachineName();
400     $path = '/' . $path_part1 . '/' . $path_part2;
401     $cached_path = $this->randomMachineName();
402     $cached_alias = $this->randomMachineName();
403
404     $language = $this->setUpCurrentLanguage();
405
406     $cached_paths = [$language->getId() => [$cached_path]];
407     $this->cache->expects($this->once())
408       ->method('get')
409       ->with($this->cacheKey)
410       ->will($this->returnValue((object) ['data' => $cached_paths]));
411
412     // Simulate a request so that the preloaded paths are fetched.
413     $this->aliasManager->setCacheKey($this->path);
414
415     $this->aliasWhitelist->expects($this->any())
416       ->method('get')
417       ->with($path_part1)
418       ->will($this->returnValue(TRUE));
419
420     $this->aliasStorage->expects($this->once())
421       ->method('preloadPathAlias')
422       ->with($cached_paths[$language->getId()], $language->getId())
423       ->will($this->returnValue([$cached_path => $cached_alias]));
424
425     $this->aliasStorage->expects($this->once())
426       ->method('lookupPathAlias')
427       ->with($path, $language->getId())
428       ->will($this->returnValue(NULL));
429
430     $this->assertEquals($path, $this->aliasManager->getAliasByPath($path));
431     // Call it twice to test the static cache.
432     $this->assertEquals($path, $this->aliasManager->getAliasByPath($path));
433
434     // There is already a cache entry, so this should not write out to the
435     // cache.
436     $this->cache->expects($this->never())
437       ->method('set');
438     $this->aliasManager->writeCache();
439   }
440
441   /**
442    * @covers ::cacheClear
443    */
444   public function testCacheClear() {
445     $path = '/path';
446     $alias = '/alias';
447     $language = $this->setUpCurrentLanguage();
448     $this->aliasStorage->expects($this->exactly(2))
449       ->method('lookupPathAlias')
450       ->with($path, $language->getId())
451       ->willReturn($alias);
452     $this->aliasWhitelist->expects($this->any())
453       ->method('get')
454       ->willReturn(TRUE);
455
456     // Populate the lookup map.
457     $this->assertEquals($alias, $this->aliasManager->getAliasByPath($path, $language->getId()));
458
459     // Check that the cache is populated.
460     $original_storage = clone $this->aliasStorage;
461     $this->aliasStorage->expects($this->never())
462       ->method('lookupPathSource');
463     $this->assertEquals($path, $this->aliasManager->getPathByAlias($alias, $language->getId()));
464
465     // Clear specific source.
466     $this->cache->expects($this->exactly(2))
467       ->method('delete');
468     $this->aliasManager->cacheClear($path);
469
470     // Ensure cache has been cleared (this will be the 2nd call to
471     // `lookupPathAlias` if cache is cleared).
472     $this->assertEquals($alias, $this->aliasManager->getAliasByPath($path, $language->getId()));
473
474     // Clear non-existent source.
475     $this->aliasManager->cacheClear('non-existent');
476   }
477
478   /**
479    * Tests the getAliasByPath cache with an unpreloaded path with alias.
480    *
481    * @covers ::getAliasByPath
482    * @covers ::writeCache
483    */
484   public function testGetAliasByPathUncachedMissWithAlias() {
485     $path_part1 = $this->randomMachineName();
486     $path_part2 = $this->randomMachineName();
487     $path = '/' . $path_part1 . '/' . $path_part2;
488     $cached_path = $this->randomMachineName();
489     $cached_no_alias_path = $this->randomMachineName();
490     $cached_alias = $this->randomMachineName();
491     $new_alias = $this->randomMachineName();
492
493     $language = $this->setUpCurrentLanguage();
494
495     $cached_paths = [$language->getId() => [$cached_path, $cached_no_alias_path]];
496     $this->cache->expects($this->once())
497       ->method('get')
498       ->with($this->cacheKey)
499       ->will($this->returnValue((object) ['data' => $cached_paths]));
500
501     // Simulate a request so that the preloaded paths are fetched.
502     $this->aliasManager->setCacheKey($this->path);
503
504     $this->aliasWhitelist->expects($this->any())
505       ->method('get')
506       ->with($path_part1)
507       ->will($this->returnValue(TRUE));
508
509     $this->aliasStorage->expects($this->once())
510       ->method('preloadPathAlias')
511       ->with($cached_paths[$language->getId()], $language->getId())
512       ->will($this->returnValue([$cached_path => $cached_alias]));
513
514     $this->aliasStorage->expects($this->once())
515       ->method('lookupPathAlias')
516       ->with($path, $language->getId())
517       ->will($this->returnValue($new_alias));
518
519     $this->assertEquals($new_alias, $this->aliasManager->getAliasByPath($path));
520     // Call it twice to test the static cache.
521     $this->assertEquals($new_alias, $this->aliasManager->getAliasByPath($path));
522
523     // There is already a cache entry, so this should not write out to the
524     // cache.
525     $this->cache->expects($this->never())
526       ->method('set');
527     $this->aliasManager->writeCache();
528   }
529
530   /**
531    * Sets up the current language.
532    *
533    * @return \Drupal\Core\Language\LanguageInterface
534    *   The current language object.
535    */
536   protected function setUpCurrentLanguage() {
537     $language = new Language(['id' => 'en']);
538
539     $this->languageManager->expects($this->any())
540       ->method('getCurrentLanguage')
541       ->with(LanguageInterface::TYPE_URL)
542       ->will($this->returnValue($language));
543
544     return $language;
545   }
546
547 }