diff --git a/Tests/CacheWarmer/ConfigBuilderCacheWarmerTest.php b/Tests/CacheWarmer/ConfigBuilderCacheWarmerTest.php index a0e8fe834..294a3cd25 100644 --- a/Tests/CacheWarmer/ConfigBuilderCacheWarmerTest.php +++ b/Tests/CacheWarmer/ConfigBuilderCacheWarmerTest.php @@ -14,15 +14,26 @@ use Symfony\Bundle\FrameworkBundle\CacheWarmer\ConfigBuilderCacheWarmer; use Symfony\Bundle\FrameworkBundle\FrameworkBundle; use Symfony\Bundle\FrameworkBundle\Tests\TestCase; +use Symfony\Component\Config\Definition\Builder\NodeDefinition; +use Symfony\Component\Config\Definition\Builder\TreeBuilder; +use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\Extension\Extension; +use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Bundle\Bundle; +use Symfony\Component\HttpKernel\Bundle\BundleInterface; use Symfony\Component\HttpKernel\Kernel; +use Symfony\Component\HttpKernel\KernelInterface; class ConfigBuilderCacheWarmerTest extends TestCase { - private $varDir; + private string $varDir; protected function setUp(): void { @@ -40,21 +51,110 @@ protected function tearDown(): void public function testBuildDirIsUsedAsConfigBuilderOutputDir() { - $kernel = new class($this->varDir) extends Kernel implements CompilerPassInterface { + $kernel = new TestKernel($this->varDir); + $kernel->boot(); + + self::assertDirectoryDoesNotExist($kernel->getBuildDir().'/Symfony'); + self::assertDirectoryDoesNotExist($kernel->getCacheDir().'/Symfony'); + + $warmer = new ConfigBuilderCacheWarmer($kernel); + $warmer->warmUp($kernel->getCacheDir()); + + self::assertDirectoryDoesNotExist($kernel->getBuildDir().'/Symfony'); + self::assertDirectoryDoesNotExist($kernel->getCacheDir().'/Symfony'); + + $warmer->warmUp($kernel->getCacheDir(), $kernel->getBuildDir()); + + self::assertDirectoryExists($kernel->getBuildDir().'/Symfony'); + self::assertDirectoryDoesNotExist($kernel->getCacheDir().'/Symfony'); + } + + public function testWithCustomKernelImplementation() + { + $kernel = new class($this->varDir) implements KernelInterface { private $varDir; public function __construct(string $varDir) { - parent::__construct('test', false); - $this->varDir = $varDir; } + public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true): Response + { + return new Response(); + } + public function registerBundles(): iterable { yield new FrameworkBundle(); } + public function registerContainerConfiguration(LoaderInterface $loader): void + { + } + + public function boot(): void + { + } + + public function shutdown(): void + { + } + + public function getBundles(): array + { + $bundles = []; + foreach ($this->registerBundles() as $bundle) { + $bundles[$bundle->getName()] = $bundle; + } + + return $bundles; + } + + public function getBundle(string $name): BundleInterface + { + foreach ($this->getBundles() as $bundleName => $bundle) { + if ($bundleName === $name) { + return $bundle; + } + } + + throw new \InvalidArgumentException(); + } + + public function locateResource(string $name): string + { + return __DIR__; + } + + public function getEnvironment(): string + { + return 'test'; + } + + public function isDebug(): bool + { + return false; + } + + public function getProjectDir(): string + { + return __DIR__; + } + + public function getContainer(): ContainerInterface + { + $container = new ContainerBuilder(); + $container->setParameter('kernel.debug', $this->isDebug()); + + return $container; + } + + public function getStartTime(): float + { + return -\INF; + } + public function getBuildDir(): string { return $this->varDir.'/build'; @@ -65,37 +165,269 @@ public function getCacheDir(): string return $this->varDir.'/cache'; } - public function registerContainerConfiguration(LoaderInterface $loader): void + public function getLogDir(): string { - $loader->load(static function (ContainerBuilder $container) { - $container->loadFromExtension('framework', [ - 'annotations' => false, - 'handle_all_throwables' => true, - 'http_method_override' => false, - 'php_errors' => ['log' => true], - ]); - }); + return $this->varDir.'/log'; } - public function process(ContainerBuilder $container): void + public function getCharset(): string { - $container->removeDefinition('config_builder.warmer'); + return 'UTF-8'; } }; $kernel->boot(); - self::assertDirectoryDoesNotExist($kernel->getBuildDir().'/Symfony'); - self::assertDirectoryDoesNotExist($kernel->getCacheDir().'/Symfony'); + $warmer = new ConfigBuilderCacheWarmer($kernel); + $warmer->warmUp($kernel->getCacheDir(), $kernel->getBuildDir()); + + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/FrameworkConfig.php'); + } + + public function testExtensionAddedInKernel() + { + $kernel = new class($this->varDir) extends TestKernel { + protected function build(ContainerBuilder $container): void + { + $container->registerExtension(new class() extends Extension implements ConfigurationInterface { + public function load(array $configs, ContainerBuilder $container): void + { + } + + public function getConfigTreeBuilder(): TreeBuilder + { + $treeBuilder = new TreeBuilder('app'); + $rootNode = $treeBuilder->getRootNode(); + + $rootNode + ->children() + ->scalarNode('provider')->end() + ->end() + ; + + return $treeBuilder; + } + + public function getAlias(): string + { + return 'app'; + } + }); + } + }; + $kernel->boot(); $warmer = new ConfigBuilderCacheWarmer($kernel); - $warmer->warmUp($kernel->getCacheDir()); + $warmer->warmUp($kernel->getCacheDir(), $kernel->getBuildDir()); - self::assertDirectoryDoesNotExist($kernel->getBuildDir().'/Symfony'); - self::assertDirectoryDoesNotExist($kernel->getCacheDir().'/Symfony'); + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/FrameworkConfig.php'); + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/AppConfig.php'); + } + public function testKernelAsExtension() + { + $kernel = new class($this->varDir) extends TestKernel implements ExtensionInterface, ConfigurationInterface { + public function load(array $configs, ContainerBuilder $container): void + { + } + + public function getXsdValidationBasePath(): string|false + { + return false; + } + + public function getNamespace(): string + { + return 'http://www.example.com/schema/acme'; + } + + public function getAlias(): string + { + return 'kernel'; + } + + public function getConfigTreeBuilder(): TreeBuilder + { + $treeBuilder = new TreeBuilder('kernel'); + $rootNode = $treeBuilder->getRootNode(); + + $rootNode + ->children() + ->scalarNode('provider')->end() + ->end() + ; + + return $treeBuilder; + } + }; + $kernel->boot(); + + $warmer = new ConfigBuilderCacheWarmer($kernel); $warmer->warmUp($kernel->getCacheDir(), $kernel->getBuildDir()); - self::assertDirectoryExists($kernel->getBuildDir().'/Symfony'); - self::assertDirectoryDoesNotExist($kernel->getCacheDir().'/Symfony'); + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/FrameworkConfig.php'); + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/KernelConfig.php'); + } + + public function testExtensionsExtendedInBuildMethods() + { + $kernel = new class($this->varDir) extends TestKernel { + protected function build(ContainerBuilder $container): void + { + /** @var TestSecurityExtension $extension */ + $extension = $container->getExtension('test_security'); + $extension->addAuthenticatorFactory(new class() implements TestAuthenticatorFactoryInterface { + public function getKey(): string + { + return 'token'; + } + + public function addConfiguration(NodeDefinition $node): void + { + } + }); + } + + public function registerBundles(): iterable + { + yield from parent::registerBundles(); + + yield new class() extends Bundle { + public function getContainerExtension(): ExtensionInterface + { + return new TestSecurityExtension(); + } + }; + + yield new class() extends Bundle { + public function build(ContainerBuilder $container): void + { + /** @var TestSecurityExtension $extension */ + $extension = $container->getExtension('test_security'); + $extension->addAuthenticatorFactory(new class() implements TestAuthenticatorFactoryInterface { + public function getKey(): string + { + return 'form-login'; + } + + public function addConfiguration(NodeDefinition $node): void + { + $node + ->children() + ->scalarNode('provider')->end() + ->end() + ; + } + }); + } + }; + } + }; + $kernel->boot(); + + $warmer = new ConfigBuilderCacheWarmer($kernel); + $warmer->warmUp($kernel->getCacheDir(), $kernel->getBuildDir()); + + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/FrameworkConfig.php'); + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/SecurityConfig.php'); + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/Security/FirewallConfig.php'); + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/Security/FirewallConfig/FormLoginConfig.php'); + self::assertFileExists($kernel->getBuildDir().'/Symfony/Config/Security/FirewallConfig/TokenConfig.php'); + } +} + +class TestKernel extends Kernel implements CompilerPassInterface +{ + private $varDir; + + public function __construct(string $varDir) + { + parent::__construct('test', false); + + $this->varDir = $varDir; + } + + public function registerBundles(): iterable + { + yield new FrameworkBundle(); + } + + public function getBuildDir(): string + { + return $this->varDir.'/build'; + } + + public function getCacheDir(): string + { + return $this->varDir.'/cache'; + } + + public function registerContainerConfiguration(LoaderInterface $loader): void + { + $loader->load(static function (ContainerBuilder $container) { + $container->loadFromExtension('framework', [ + 'annotations' => false, + 'handle_all_throwables' => true, + 'http_method_override' => false, + 'php_errors' => ['log' => true], + ]); + }); + } + + public function process(ContainerBuilder $container): void + { + $container->removeDefinition('config_builder.warmer'); + } +} + +interface TestAuthenticatorFactoryInterface +{ + public function getKey(): string; + + public function addConfiguration(NodeDefinition $builder): void; +} + +class TestSecurityExtension extends Extension implements ConfigurationInterface +{ + /** @var TestAuthenticatorFactoryInterface[] */ + private $factories; + + public function load(array $configs, ContainerBuilder $container): void + { + } + + public function getConfiguration(array $config, ContainerBuilder $container): ConfigurationInterface + { + return $this; + } + + public function addAuthenticatorFactory(TestAuthenticatorFactoryInterface $factory): void + { + $this->factories[] = $factory; + } + + public function getConfigTreeBuilder(): TreeBuilder + { + $treeBuilder = new TreeBuilder('security'); + $rootNode = $treeBuilder->getRootNode(); + + $firewallNodeBuilder = $rootNode + ->fixXmlConfig('firewall') + ->children() + ->arrayNode('firewalls') + ->isRequired() + ->requiresAtLeastOneElement() + ->useAttributeAsKey('name') + ->prototype('array') + ->children() + ; + + foreach ($this->factories as $factory) { + $name = str_replace('-', '_', $factory->getKey()); + $factoryNode = $firewallNodeBuilder->arrayNode($name); + + $factory->addConfiguration($factoryNode); + } + + return $treeBuilder; } }