/Tests/CacheWarmer/AnnotationsCacheWarmerTest.php

https://github.com/symfony/FrameworkBundle · PHP · 175 lines · 127 code · 30 blank · 18 comment · 2 complexity · 2eba7da3850737e74b0691f622c60760 MD5 · raw file

  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Bundle\FrameworkBundle\Tests\CacheWarmer;
  11. use Doctrine\Common\Annotations\AnnotationReader;
  12. use Doctrine\Common\Annotations\PsrCachedReader;
  13. use Doctrine\Common\Annotations\Reader;
  14. use PHPUnit\Framework\MockObject\MockObject;
  15. use Symfony\Bundle\FrameworkBundle\CacheWarmer\AnnotationsCacheWarmer;
  16. use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
  17. use Symfony\Component\Cache\Adapter\ArrayAdapter;
  18. use Symfony\Component\Cache\Adapter\NullAdapter;
  19. use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
  20. use Symfony\Component\Filesystem\Filesystem;
  21. class AnnotationsCacheWarmerTest extends TestCase
  22. {
  23. private $cacheDir;
  24. protected function setUp(): void
  25. {
  26. $this->cacheDir = sys_get_temp_dir().'/'.uniqid();
  27. $fs = new Filesystem();
  28. $fs->mkdir($this->cacheDir);
  29. parent::setUp();
  30. }
  31. protected function tearDown(): void
  32. {
  33. $fs = new Filesystem();
  34. $fs->remove($this->cacheDir);
  35. parent::tearDown();
  36. }
  37. public function testAnnotationsCacheWarmerWithDebugDisabled()
  38. {
  39. file_put_contents($this->cacheDir.'/annotations.map', sprintf('<?php return %s;', var_export([__CLASS__], true)));
  40. $cacheFile = tempnam($this->cacheDir, __FUNCTION__);
  41. $reader = new AnnotationReader();
  42. $warmer = new AnnotationsCacheWarmer($reader, $cacheFile);
  43. $warmer->warmUp($this->cacheDir);
  44. $this->assertFileExists($cacheFile);
  45. // Assert cache is valid
  46. $reader = new PsrCachedReader(
  47. $this->getReadOnlyReader(),
  48. new PhpArrayAdapter($cacheFile, new NullAdapter())
  49. );
  50. $refClass = new \ReflectionClass($this);
  51. $reader->getClassAnnotations($refClass);
  52. $reader->getMethodAnnotations($refClass->getMethod(__FUNCTION__));
  53. $reader->getPropertyAnnotations($refClass->getProperty('cacheDir'));
  54. }
  55. public function testAnnotationsCacheWarmerWithDebugEnabled()
  56. {
  57. file_put_contents($this->cacheDir.'/annotations.map', sprintf('<?php return %s;', var_export([__CLASS__], true)));
  58. $cacheFile = tempnam($this->cacheDir, __FUNCTION__);
  59. $reader = new AnnotationReader();
  60. $warmer = new AnnotationsCacheWarmer($reader, $cacheFile, null, true);
  61. $warmer->warmUp($this->cacheDir);
  62. $this->assertFileExists($cacheFile);
  63. // Assert cache is valid
  64. $phpArrayAdapter = new PhpArrayAdapter($cacheFile, new NullAdapter());
  65. $reader = new PsrCachedReader(
  66. $this->getReadOnlyReader(),
  67. $phpArrayAdapter,
  68. true
  69. );
  70. $refClass = new \ReflectionClass($this);
  71. $reader->getClassAnnotations($refClass);
  72. $reader->getMethodAnnotations($refClass->getMethod(__FUNCTION__));
  73. $reader->getPropertyAnnotations($refClass->getProperty('cacheDir'));
  74. }
  75. /**
  76. * Test that the cache warming process is not broken if a class loader
  77. * throws an exception (on class / file not found for example).
  78. */
  79. public function testClassAutoloadException()
  80. {
  81. $this->assertFalse(class_exists($annotatedClass = 'C\C\C', false));
  82. file_put_contents($this->cacheDir.'/annotations.map', sprintf('<?php return %s;', var_export([$annotatedClass], true)));
  83. $warmer = new AnnotationsCacheWarmer(new AnnotationReader(), tempnam($this->cacheDir, __FUNCTION__));
  84. spl_autoload_register($classLoader = function ($class) use ($annotatedClass) {
  85. if ($class === $annotatedClass) {
  86. throw new \DomainException('This exception should be caught by the warmer.');
  87. }
  88. }, true, true);
  89. $warmer->warmUp($this->cacheDir);
  90. spl_autoload_unregister($classLoader);
  91. }
  92. /**
  93. * Test that the cache warming process is broken if a class loader throws an
  94. * exception but that is unrelated to the class load.
  95. */
  96. public function testClassAutoloadExceptionWithUnrelatedException()
  97. {
  98. $this->expectException(\DomainException::class);
  99. $this->expectExceptionMessage('This exception should not be caught by the warmer.');
  100. $this->assertFalse(class_exists($annotatedClass = 'AClassThatDoesNotExist_FWB_CacheWarmer_AnnotationsCacheWarmerTest', false));
  101. file_put_contents($this->cacheDir.'/annotations.map', sprintf('<?php return %s;', var_export([$annotatedClass], true)));
  102. $warmer = new AnnotationsCacheWarmer(new AnnotationReader(), tempnam($this->cacheDir, __FUNCTION__));
  103. spl_autoload_register($classLoader = function ($class) use ($annotatedClass) {
  104. if ($class === $annotatedClass) {
  105. eval('class '.$annotatedClass.'{}');
  106. throw new \DomainException('This exception should not be caught by the warmer.');
  107. }
  108. }, true, true);
  109. $warmer->warmUp($this->cacheDir);
  110. spl_autoload_unregister($classLoader);
  111. }
  112. public function testWarmupRemoveCacheMisses()
  113. {
  114. $cacheFile = tempnam($this->cacheDir, __FUNCTION__);
  115. $warmer = $this->getMockBuilder(AnnotationsCacheWarmer::class)
  116. ->setConstructorArgs([new AnnotationReader(), $cacheFile])
  117. ->setMethods(['doWarmUp'])
  118. ->getMock();
  119. $warmer->method('doWarmUp')->willReturnCallback(function ($cacheDir, ArrayAdapter $arrayAdapter) {
  120. $arrayAdapter->getItem('foo_miss');
  121. $item = $arrayAdapter->getItem('bar_hit');
  122. $item->set('data');
  123. $arrayAdapter->save($item);
  124. $item = $arrayAdapter->getItem('baz_hit_null');
  125. $item->set(null);
  126. $arrayAdapter->save($item);
  127. return true;
  128. });
  129. $warmer->warmUp($this->cacheDir);
  130. $data = include $cacheFile;
  131. $this->assertCount(1, $data[0]);
  132. $this->assertTrue(isset($data[0]['bar_hit']));
  133. }
  134. private function getReadOnlyReader(): MockObject&Reader
  135. {
  136. $readerMock = $this->createMock(Reader::class);
  137. $readerMock->expects($this->exactly(0))->method('getClassAnnotations');
  138. $readerMock->expects($this->exactly(0))->method('getClassAnnotation');
  139. $readerMock->expects($this->exactly(0))->method('getMethodAnnotations');
  140. $readerMock->expects($this->exactly(0))->method('getMethodAnnotation');
  141. $readerMock->expects($this->exactly(0))->method('getPropertyAnnotations');
  142. $readerMock->expects($this->exactly(0))->method('getPropertyAnnotation');
  143. return $readerMock;
  144. }
  145. }