From df4c02cb255b079c38561d0fcb898956dea69853 Mon Sep 17 00:00:00 2001 From: Aaron Gustavo Nieves <64917965+TavoNiievez@users.noreply.github.com> Date: Thu, 27 Jun 2024 23:14:16 -0500 Subject: [PATCH] Simplify module logic (#196) --- src/Codeception/Lib/Connector/Symfony.php | 35 +--- src/Codeception/Module/Symfony.php | 197 ++++++++-------------- 2 files changed, 84 insertions(+), 148 deletions(-) diff --git a/src/Codeception/Lib/Connector/Symfony.php b/src/Codeception/Lib/Connector/Symfony.php index 684add4..44d7595 100644 --- a/src/Codeception/Lib/Connector/Symfony.php +++ b/src/Codeception/Lib/Connector/Symfony.php @@ -21,15 +21,8 @@ class Symfony extends HttpKernelBrowser { private bool $hasPerformedRequest = false; - private ?ContainerInterface $container; - /** - * Constructor. - * - * @param Kernel $kernel A booted HttpKernel instance - * @param array $persistentServices An injected services - */ public function __construct( Kernel $kernel, public array $persistentServices = [], @@ -74,14 +67,12 @@ public function rebootKernel(): void $this->persistDoctrineConnections(); $this->kernel->reboot(null); - $this->container = $this->getContainer(); foreach ($this->persistentServices as $serviceName => $service) { try { $this->container->set($serviceName, $service); } catch (InvalidArgumentException $e) { - //Private services can't be set in Symfony 4 codecept_debug("[Symfony] Can't set persistent service {$serviceName}: " . $e->getMessage()); } } @@ -95,31 +86,23 @@ private function getContainer(): ?ContainerInterface { /** @var ContainerInterface $container */ $container = $this->kernel->getContainer(); - if ($container->has('test.service_container')) { - $container = $container->get('test.service_container'); - } - - return $container; + return $container->has('test.service_container') + ? $container->get('test.service_container') + : $container; } private function getProfiler(): ?Profiler { - if ($this->container->has('profiler')) { - /** @var Profiler $profiler */ - $profiler = $this->container->get('profiler'); - return $profiler; - } - - return null; + return $this->container->has('profiler') + ? $this->container->get('profiler') + : null; } private function getService(string $serviceName): ?object { - if ($this->container->has($serviceName)) { - return $this->container->get($serviceName); - } - - return null; + return $this->container->has($serviceName) + ? $this->container->get($serviceName) + : null; } private function persistDoctrineConnections(): void diff --git a/src/Codeception/Module/Symfony.php b/src/Codeception/Module/Symfony.php index 45b798d..b677c03 100644 --- a/src/Codeception/Module/Symfony.php +++ b/src/Codeception/Module/Symfony.php @@ -42,11 +42,9 @@ use Symfony\Component\HttpKernel\Profiler\Profile; use Symfony\Component\HttpKernel\Profiler\Profiler; use Symfony\Component\Mailer\DataCollector\MessageDataCollector; -use Symfony\Component\Routing\Route; use Symfony\Component\VarDumper\Cloner\Data; use function array_keys; use function array_map; -use function array_search; use function array_unique; use function class_exists; use function codecept_root_dir; @@ -55,7 +53,6 @@ use function implode; use function ini_get; use function ini_set; -use function is_null; use function iterator_to_array; use function number_format; use function sprintf; @@ -174,46 +171,34 @@ class Symfony extends Framework implements DoctrineProvider, PartedModule 'guard' => false ]; - /** - * @return string[] - */ - public function _parts(): array - { - return ['services']; - } - protected ?string $kernelClass = null; - /** * Services that should be persistent permanently for all tests - * - * @var array */ - protected $permanentServices = []; - + protected array $permanentServices = []; /** * Services that should be persistent during test execution between kernel reboots - * - * @var array */ - protected $persistentServices = []; + protected array $persistentServices = []; + + /** + * @return string[] + */ + public function _parts(): array + { + return ['services']; + } public function _initialize(): void { $this->kernelClass = $this->getKernelClass(); - $maxNestingLevel = 200; // Symfony may have very long nesting level - $xdebugMaxLevelKey = 'xdebug.max_nesting_level'; - if (ini_get($xdebugMaxLevelKey) < $maxNestingLevel) { - ini_set($xdebugMaxLevelKey, (string)$maxNestingLevel); - } - + $this->setXdebugMaxNestingLevel(200); $this->kernel = new $this->kernelClass($this->config['environment'], $this->config['debug']); - if($this->config['bootstrap']) { + if ($this->config['bootstrap']) { $this->bootstrapEnvironment(); } $this->kernel->boot(); - - if ($this->config['cache_router'] === true) { + if ($this->config['cache_router']) { $this->persistPermanentService('router'); } } @@ -223,7 +208,7 @@ public function _initialize(): void */ public function _before(TestInterface $test): void { - $this->persistentServices = [...$this->persistentServices, ...$this->permanentServices]; + $this->persistentServices = array_merge($this->persistentServices, $this->permanentServices); $this->client = new SymfonyConnector($this->kernel, $this->persistentServices, $this->config['rebootable_client']); } @@ -235,7 +220,6 @@ public function _after(TestInterface $test): void foreach (array_keys($this->permanentServices) as $serviceName) { $this->permanentServices[$serviceName] = $this->grabService($serviceName); } - parent::_after($test); } @@ -258,40 +242,24 @@ public function _getEntityManager(): EntityManagerInterface $emService = $this->config['em_service']; if (!isset($this->permanentServices[$emService])) { - // Try to persist configured entity manager $this->persistPermanentService($emService); $container = $this->_getContainer(); - if ($container->has('doctrine')) { - $this->persistPermanentService('doctrine'); - } - - if ($container->has('doctrine.orm.default_entity_manager')) { - $this->persistPermanentService('doctrine.orm.default_entity_manager'); - } - - if ($container->has('doctrine.dbal.default_connection')) { - $this->persistPermanentService('doctrine.dbal.default_connection'); + $services = ['doctrine', 'doctrine.orm.default_entity_manager', 'doctrine.dbal.default_connection']; + foreach ($services as $service) { + if ($container->has($service)) { + $this->persistPermanentService($service); + } } } return $this->permanentServices[$emService]; } - /** - * Return container. - */ public function _getContainer(): ContainerInterface { $container = $this->kernel->getContainer(); - if (!$container instanceof ContainerInterface) { - $this->fail('Could not get Symfony container'); - } - if ($container->has('test.service_container')) { - $container = $container->get('test.service_container'); - } - - return $container; + return $container->has('test.service_container') ? $container->get('test.service_container') : $container; } protected function getClient(): SymfonyConnector @@ -317,9 +285,10 @@ protected function getKernelClass(): string ); } + $this->requireAdditionalAutoloader(); + $finder = new Finder(); - $finder->name('*Kernel.php')->depth('0')->in($path); - $results = iterator_to_array($finder); + $results = iterator_to_array($finder->name('*Kernel.php')->depth('0')->in($path)); if ($results === []) { throw new ModuleRequireException( self::class, @@ -328,22 +297,17 @@ protected function getKernelClass(): string ); } - $this->requireAdditionalAutoloader(); - + $kernelClass = $this->config['kernel_class']; $filesRealPath = array_map(static function ($file) { require_once $file; return $file->getRealPath(); }, $results); - $kernelClass = $this->config['kernel_class']; - if (class_exists($kernelClass)) { $reflectionClass = new ReflectionClass($kernelClass); - if ($file = array_search($reflectionClass->getFileName(), $filesRealPath, true)) { + if (in_array($reflectionClass->getFileName(), $filesRealPath, true)) { return $kernelClass; } - - throw new ModuleRequireException(self::class, "Kernel class was not found in {$file}."); } throw new ModuleRequireException( @@ -356,13 +320,9 @@ protected function getKernelClass(): string protected function getProfile(): ?Profile { /** @var Profiler $profiler */ - if (!$profiler = $this->getService('profiler')) { - return null; - } - + $profiler = $this->getService('profiler'); try { - $response = $this->getClient()->getResponse(); - return $profiler->loadProfileFromResponse($response); + return $profiler?->loadProfileFromResponse($this->getClient()->getResponse()); } catch (BadMethodCallException) { $this->fail('You must perform a request before using this method.'); } catch (Exception $e) { @@ -377,20 +337,12 @@ protected function getProfile(): ?Profile */ protected function grabCollector(string $collector, string $function, string $message = null): DataCollectorInterface { - if (($profile = $this->getProfile()) === null) { - $this->fail( - sprintf("The Profile is needed to use the '%s' function.", $function) - ); + $profile = $this->getProfile(); + if ($profile === null) { + $this->fail(sprintf("The Profile is needed to use the '%s' function.", $function)); } - if (!$profile->hasCollector($collector)) { - if ($message) { - $this->fail($message); - } - - $this->fail( - sprintf("The '%s' collector is needed to use the '%s' function.", $collector, $function) - ); + $this->fail($message ?: "The '{$collector}' collector is needed to use the '{$function}' function."); } return $profile->getCollector($collector); @@ -399,49 +351,23 @@ protected function grabCollector(string $collector, string $function, string $me /** * Set the data that will be displayed when running a test with the `--debug` flag * - * @param $url + * @param mixed $url */ protected function debugResponse($url): void { parent::debugResponse($url); - - if (($profile = $this->getProfile()) === null) { - return; - } - - if ($profile->hasCollector('security')) { - /** @var SecurityDataCollector $security */ - $security = $profile->getCollector('security'); - if ($security->isAuthenticated()) { - $roles = $security->getRoles(); - - if ($roles instanceof Data) { - $roles = $roles->getValue(); + if ($profile = $this->getProfile()) { + $collectors = [ + 'security' => 'debugSecurityData', + 'mailer' => 'debugMailerData', + 'time' => 'debugTimeData', + ]; + foreach ($collectors as $collector => $method) { + if ($profile->hasCollector($collector)) { + $this->$method($profile->getCollector($collector)); } - - $this->debugSection( - 'User', - $security->getUser() - . ' [' . implode(',', $roles) . ']' - ); - } else { - $this->debugSection('User', 'Anonymous'); } } - - if ($profile->hasCollector('mailer')) { - /** @var MessageDataCollector $mailerCollector */ - $mailerCollector = $profile->getCollector('mailer'); - $emails = count($mailerCollector->getEvents()->getMessages()); - $this->debugSection('Emails', $emails . ' sent'); - } - - if ($profile->hasCollector('time')) { - /** @var TimeDataCollector $timeCollector */ - $timeCollector = $profile->getCollector('time'); - $duration = number_format($timeCollector->getDuration(), 2) . ' ms'; - $this->debugSection('Time', $duration); - } } /** @@ -450,15 +376,14 @@ protected function debugResponse($url): void protected function getInternalDomains(): array { $internalDomains = []; - $router = $this->grabRouterService(); $routes = $router->getRouteCollection(); - /* @var Route $route */ + foreach ($routes as $route) { - if (!is_null($route->getHost())) { - $compiled = $route->compile(); - if (!is_null($compiled->getHostRegex())) { - $internalDomains[] = $compiled->getHostRegex(); + if ($route->getHost() !== null) { + $compiledRoute = $route->compile(); + if ($compiledRoute->getHostRegex() !== null) { + $internalDomains[] = $compiledRoute->getHostRegex(); } } } @@ -466,10 +391,16 @@ protected function getInternalDomains(): array return array_unique($internalDomains); } + private function setXdebugMaxNestingLevel(int $maxNestingLevel): void + { + if (ini_get('xdebug.max_nesting_level') < $maxNestingLevel) { + ini_set('xdebug.max_nesting_level', (string)$maxNestingLevel); + } + } + private function bootstrapEnvironment(): void { $bootstrapFile = $this->kernel->getProjectDir() . '/tests/bootstrap.php'; - if (file_exists($bootstrapFile)) { require_once $bootstrapFile; } else { @@ -486,6 +417,28 @@ private function bootstrapEnvironment(): void } } + private function debugSecurityData(SecurityDataCollector $security): void + { + if ($security->isAuthenticated()) { + $roles = $security->getRoles(); + $rolesString = implode(',', $roles instanceof Data ? $roles->getValue() : $roles); + $userInfo = $security->getUser() . ' [' . $rolesString . ']'; + } else { + $userInfo = 'Anonymous'; + } + $this->debugSection('User', $userInfo); + } + + private function debugMailerData(MessageDataCollector $mailerCollector): void + { + $this->debugSection('Emails', count($mailerCollector->getEvents()->getMessages()) . ' sent'); + } + + private function debugTimeData(TimeDataCollector $timeCollector): void + { + $this->debugSection('Time', number_format($timeCollector->getDuration(), 2) . ' ms'); + } + /** * Ensures autoloader loading of additional directories. * It is only required for CI jobs to run correctly.