diff --git a/composer.json b/composer.json index fcc7a53..75ce20e 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,10 @@ "symfony/browser-kit": "^6.4", "symfony/framework-bundle": "^6.4", "symfony/http-kernel": "^6.4", - "symfony/stopwatch": "^6.4" + "symfony/stopwatch": "^6.4", + "phpstan/phpstan": "^1.11", + "phpstan/phpstan-symfony": "^1.4", + "symfony/runtime": "^6.4" }, "autoload": { "psr-4": { @@ -43,6 +46,8 @@ "ci": [ "composer validate", "@check-cs", + "tests/Symfony/console ca:cl -e test", + "@phpstan", "@phpunit" ], "check-cs": [ @@ -53,11 +58,17 @@ ], "phpunit": [ "phpunit" + ], + "phpstan": [ + "phpstan analyse -c phpstan.neon" ] }, "config": { "platform": { "php": "8.1" + }, + "allow-plugins": { + "symfony/runtime": true } } } diff --git a/composer.lock b/composer.lock index 467b327..b6f9464 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "288fafaa3ceabf8210ed9c794018e4c9", + "content-hash": "d800f3f145d9deb361165e67023f192d", "packages": [ { "name": "akondas/php-runtime", @@ -899,6 +899,136 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "phpstan/phpstan", + "version": "1.11.3", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "e64220a05c1209fc856d58e789c3b7a32c0bb9a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e64220a05c1209fc856d58e789c3b7a32c0bb9a5", + "reference": "e64220a05c1209fc856d58e789c3b7a32c0bb9a5", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2024-05-31T13:53:37+00:00" + }, + { + "name": "phpstan/phpstan-symfony", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-symfony.git", + "reference": "af6ae0f4b91bc080265e80776af26da3e5befb28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/af6ae0f4b91bc080265e80776af26da3e5befb28", + "reference": "af6ae0f4b91bc080265e80776af26da3e5befb28", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.11" + }, + "conflict": { + "symfony/framework-bundle": "<3.0" + }, + "require-dev": { + "nikic/php-parser": "^4.13.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-phpunit": "^1.3.11", + "phpstan/phpstan-strict-rules": "^1.5.1", + "phpunit/phpunit": "^8.5.29 || ^9.5", + "psr/container": "1.0 || 1.1.1", + "symfony/config": "^5.4 || ^6.1", + "symfony/console": "^5.4 || ^6.1", + "symfony/dependency-injection": "^5.4 || ^6.1", + "symfony/form": "^5.4 || ^6.1", + "symfony/framework-bundle": "^5.4 || ^6.1", + "symfony/http-foundation": "^5.4 || ^6.1", + "symfony/messenger": "^5.4", + "symfony/polyfill-php80": "^1.24", + "symfony/serializer": "^5.4", + "symfony/service-contracts": "^2.2.0" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon", + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lukáš Unger", + "email": "looky.msc@gmail.com", + "homepage": "https://lookyman.net" + } + ], + "description": "Symfony Framework extensions and rules for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-symfony/issues", + "source": "https://github.com/phpstan/phpstan-symfony/tree/1.4.3" + }, + "time": "2024-05-30T15:01:27+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "10.1.14", @@ -5053,6 +5183,85 @@ ], "time": "2024-04-18T09:22:46+00:00" }, + { + "name": "symfony/runtime", + "version": "v6.4.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/runtime.git", + "reference": "20c90eb66bbf82fdb3ef74f2ea4ecf08518cbb5e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/runtime/zipball/20c90eb66bbf82fdb3ef74f2ea4ecf08518cbb5e", + "reference": "20c90eb66bbf82fdb3ef74f2ea4ecf08518cbb5e", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0|^2.0", + "php": ">=8.1" + }, + "conflict": { + "symfony/dotenv": "<5.4" + }, + "require-dev": { + "composer/composer": "^1.0.2|^2.0", + "symfony/console": "^5.4.9|^6.0.9|^7.0", + "symfony/dotenv": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Symfony\\Component\\Runtime\\Internal\\ComposerPlugin" + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Runtime\\": "", + "Symfony\\Runtime\\Symfony\\Component\\": "Internal/" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Enables decoupling PHP applications from global state", + "homepage": "https://symfony.com", + "keywords": [ + "runtime" + ], + "support": { + "source": "https://github.com/symfony/runtime/tree/v6.4.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:22:46+00:00" + }, { "name": "symfony/service-contracts", "version": "v3.5.0", diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..26eb45e --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,13 @@ +includes: + - vendor/phpstan/phpstan/conf/bleedingEdge.neon + - vendor/phpstan/phpstan-symfony/extension.neon + - vendor/phpstan/phpstan-symfony/rules.neon + +parameters: + phpVersion: 80100 + level: max + paths: + - src + - tests + symfony: + containerXmlPath: var/cache/test/Chaos_Monkey_Symfony_Tests_Symfony_KernelTestDebugContainer.xml diff --git a/src/DependencyInjection/ChaosMonkeyExtension.php b/src/DependencyInjection/ChaosMonkeyExtension.php index 8f802c6..662462a 100644 --- a/src/DependencyInjection/ChaosMonkeyExtension.php +++ b/src/DependencyInjection/ChaosMonkeyExtension.php @@ -9,20 +9,42 @@ use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; +/** + * @phpstan-type ConfigArray array{ + * enabled: bool, + * probability: int, + * assaults: array{ + * latency: array{active: bool, minimum: int, maximum: int}, + * memory: array{active: bool, fill_fraction: float}, + * exception: array{active: bool, class: class-string<\Throwable>}, + * kill_app: array{active: bool} + * }, + * watchers: array{ + * request: array{enabled: bool, priority: int} + * } + * } + */ class ChaosMonkeyExtension extends Extension { - public function load(array $configs, ContainerBuilder $container) + /** + * @param array> $configs + */ + public function load(array $configs, ContainerBuilder $container): void { $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.xml'); $configuration = new Configuration(); + /** @var ConfigArray $config */ $config = $this->processConfiguration($configuration, $configs); $this->setChaosMonkeySettings($container, $config); $this->enableWatchers($container, $config); } + /** + * @param ConfigArray $config + */ private function setChaosMonkeySettings(ContainerBuilder $container, array $config): void { $definition = $container->getDefinition('chaos_monkey.settings'); @@ -42,6 +64,9 @@ private function setChaosMonkeySettings(ContainerBuilder $container, array $conf $definition->addMethodCall('setKillAppActive', [$config['assaults']['kill_app']['active']]); } + /** + * @param ConfigArray $config + */ private function enableWatchers(ContainerBuilder $container, array $config): void { if ($config['watchers']['request']['enabled'] === true) { diff --git a/tests/Controller/SymfonyControllerTest.php b/tests/Controller/SymfonyControllerTest.php index 2156843..d4fcdf8 100644 --- a/tests/Controller/SymfonyControllerTest.php +++ b/tests/Controller/SymfonyControllerTest.php @@ -5,16 +5,9 @@ namespace Chaos\Monkey\Symfony\Tests\Controller; use Chaos\Monkey\Settings; -use Chaos\Monkey\Symfony\ChaosMonkeyBundle; +use Chaos\Monkey\Symfony\Tests\Symfony\Kernel; use PHPUnit\Framework\TestCase; -use Psr\Log\NullLogger; -use Symfony\Bundle\FrameworkBundle\FrameworkBundle; -use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; use Symfony\Bundle\FrameworkBundle\KernelBrowser; -use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Kernel; -use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; use Symfony\Component\Stopwatch\Stopwatch; class SymfonyControllerTest extends TestCase @@ -23,7 +16,7 @@ class SymfonyControllerTest extends TestCase protected function setUp(): void { - $this->client = new KernelBrowser($kernel = new SymfonyControllerKernel('test', false)); + $this->client = new KernelBrowser($kernel = new Kernel('test', true)); $this->client->disableReboot(); $kernel->boot(); } @@ -92,35 +85,3 @@ private function chaosMonkeySettings(): Settings return $this->client->getContainer()->get('chaos_monkey')->settings(); } } - -class SymfonyControllerKernel extends Kernel -{ - use MicroKernelTrait; - - public function registerBundles(): iterable - { - return [ - new FrameworkBundle(), - new ChaosMonkeyBundle(), - ]; - } - - protected function configureContainer(ContainerConfigurator $c): void - { - $c->extension('framework', [ - 'secret' => 'S0ME_SECRET', - ]); - - $c->services()->set('logger', NullLogger::class); - } - - protected function configureRoutes(RoutingConfigurator $routes) - { - $routes->add('home', '/hello')->controller([$this, 'hello']); - } - - public function hello(): Response - { - return new Response('Hello world'); - } -} diff --git a/tests/Symfony/Kernel.php b/tests/Symfony/Kernel.php new file mode 100644 index 0000000..c2ba8ed --- /dev/null +++ b/tests/Symfony/Kernel.php @@ -0,0 +1,46 @@ +extension('framework', [ + 'secret' => 'S0ME_SECRET', + ]); + + $container->services()->set('logger', NullLogger::class); + } + + protected function configureRoutes(RoutingConfigurator $routes): void + { + $routes->add('home', '/hello')->controller([$this, 'hello']); + } + + public function hello(): Response + { + return new Response('Hello world'); + } +} diff --git a/tests/Symfony/console b/tests/Symfony/console new file mode 100755 index 0000000..df9c762 --- /dev/null +++ b/tests/Symfony/console @@ -0,0 +1,17 @@ +#!/usr/bin/env php +