diff --git a/.circleci/config.yml b/.circleci/config.yml index 9ecb35c..e83d340 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -17,8 +17,33 @@ jobs: name: Run tests / Symfony 5^0 command: | rm -Rf var/* + composer require seregazhuk/php-watcher:^0.5.2 --no-update + composer require drift/event-bus-bundle:^0.1 --no-update composer update -n --prefer-dist - php vendor/bin/phpunit + php vendor/bin/phpunit --testsuite=all --exclude-group=without-filesystem-message + + test-php74-with-filesystem: + docker: + - image: circleci/php:7.4-cli + + working_directory: ~/project + steps: + - checkout + + - run: + name: Install PHP dependencies + command: | + sudo docker-php-ext-install pcntl + + - run: + name: Run tests / Symfony 5^0 + command: | + rm -Rf var/* + composer require react/filesystem --no-update + composer require seregazhuk/php-watcher:^0.5.2 --no-update + composer require drift/event-bus-bundle:^0.1 --no-update + composer update -n --prefer-dist + php vendor/bin/phpunit --testsuite=all --exclude-group=with-filesystem-message test-php80: docker: @@ -37,12 +62,13 @@ jobs: name: Run tests / Symfony 5^0 command: | rm -Rf var/* - composer update -n --prefer-dist --ignore-platform-req=php - php vendor/bin/phpunit + composer update -n --prefer-dist + php vendor/bin/phpunit --testsuite=no-watcher --exclude-group=without-filesystem-message workflows: version: 2 test: jobs: - test-php74 + - test-php74-with-filesystem - test-php80 \ No newline at end of file diff --git a/.phpunit.result.cache b/.phpunit.result.cache new file mode 100644 index 0000000..be278d5 --- /dev/null +++ b/.phpunit.result.cache @@ -0,0 +1 @@ +C:37:"PHPUnit\Runner\DefaultTestResultCache":1489:{a:2:{s:7:"defects";a:2:{s:65:"Drift\Server\Tests\ApplicationStaticFolderTest::testFilesNotFound";i:3;s:49:"Drift\Server\Tests\UploadingFileTest::testRegular";i:3;}s:5:"times";a:18:{s:47:"Drift\Server\Tests\ApplicationTest::testRegular";d:1.017;s:51:"Drift\Server\Tests\ApplicationTest::testDefaultHost";d:1.034;s:49:"Drift\Server\Tests\ApplicationTest::testEmptyHost";d:1.018;s:52:"Drift\Server\Tests\ApplicationTest::testSilentServer";d:1.026;s:53:"Drift\Server\Tests\ApplicationTest::testRouteNotFound";d:1.016;s:47:"Drift\Server\Tests\ApplicationTest::testNonAnsi";d:1.033;s:65:"Drift\Server\Tests\ApplicationTest::testAnotherPSR7Implementation";d:1.019;s:52:"Drift\Server\Tests\ApplicationTest::testServerValues";d:1.014;s:56:"Drift\Server\Tests\ApplicationTest::testBasicAuthHeaders";d:1.02;s:54:"Drift\Server\Tests\ApplicationTest::testSymfonyAdapter";d:1.024;s:59:"Drift\Server\Tests\ApplicationStaticFolderTest::testRegular";d:0.83;s:72:"Drift\Server\Tests\ApplicationStaticFolderTest::testDisabledStaticFolder";d:0.813;s:70:"Drift\Server\Tests\ApplicationStaticFolderTest::testCustomStaticFolder";d:0.829;s:69:"Drift\Server\Tests\ApplicationStaticFolderTest::testStaticFolderAlias";d:0.834;s:65:"Drift\Server\Tests\ApplicationStaticFolderTest::testFilesNotFound";d:0.32;s:49:"Drift\Server\Tests\UploadingFileTest::testRegular";d:0.677;s:51:"Drift\Server\Tests\UploadingFileTest::testEmptyFile";d:0.322;s:60:"Drift\Server\Tests\UploadingFileTest::testDisableFileUploads";d:0.325;}}} \ No newline at end of file diff --git a/README.md b/README.md index 1840095..2ec6009 100644 --- a/README.md +++ b/README.md @@ -80,12 +80,12 @@ designed for the watcher feature. interface KernelAdapter extends ObservableKernel { /** - * @param LoopInterface $loop - * @param string $rootPath - * @param ServerContext $serverContext - * @param FilesystemInterface $filesystem - * @param OutputPrinter $outputPrinter - * @param MimeTypeChecker $mimeTypeChecker + * @param LoopInterface $loop + * @param string $rootPath + * @param ServerContext $serverContext + * @param OutputPrinter $outputPrinter + * @param MimeTypeChecker $mimeTypeChecker + * @param FilesystemInterface|null $filesystem * * @return PromiseInterface * @@ -95,9 +95,9 @@ interface KernelAdapter extends ObservableKernel LoopInterface $loop, string $rootPath, ServerContext $serverContext, - FilesystemInterface $filesystem, OutputPrinter $outputPrinter, - MimeTypeChecker $mimeTypeChecker + MimeTypeChecker $mimeTypeChecker, + ?FilesystemInterface $filesystem ): PromiseInterface; /** @@ -192,6 +192,14 @@ In this example, a file named `app.js` located under `/internal/public/path/` folder will be accessible at `http://localhost:8000/public/app.js`. By default, this feature is disabled. +### Important + +By default, this package will not install the `react/filesystem` package. This +means that, if you don't install it by hand in your project, all the disk +operations will be blocking. These operations done synchronously will be much +faster and efficient, but by using large size files could slow down the entire +process. + ## Symfony bridge In order to help you from migrating an application from Symfony to DriftPHP, diff --git a/composer.json b/composer.json index 5cbb1b8..3857e7c 100644 --- a/composer.json +++ b/composer.json @@ -20,25 +20,24 @@ "react/event-loop": "^1.0", "react/socket": "^1.0", "react/promise": "^2.7", - "react/filesystem": "dev-master as 0.1.3", "clue/zlib-react": "^0.2.2", "drift/console-bridge": "0.1.*", "drift/event-loop-utils": "0.1.*" }, "require-dev": { - "phpunit/phpunit": "7.5.17", - "seregazhuk/php-watcher": "^0.5.2", - "drift/event-bus-bundle": "0.1.*, >=0.1.2", + "phpunit/phpunit": "^9", "symfony/framework-bundle": "^5.0", "symfony/process": "^5.0", "symfony/config": "^5.0", - "drift/http-kernel": "0.1.*, >=0.1.13", + "drift/http-kernel": "0.1.*, >=0.1.15", "laminas/laminas-diactoros": "^2", "vimeo/psalm": "^4", "ext-fileinfo": "*" }, "suggest": { - "seregazhuk/php-watcher": "^0.5.2" + "react/filesystem": "*", + "drift/event-bus-bundle": "*", + "seregazhuk/php-watcher": "*" }, "autoload": { "psr-4": { diff --git a/phpunit.xml b/phpunit.xml index dc3aeaf..5d30712 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -11,9 +11,15 @@ bootstrap="vendor/autoload.php" > - + ./tests + + + ./tests + ./tests/WatcherTest.php + ./tests/ExchangesTest.php + \ No newline at end of file diff --git a/src/Adapter/DriftKernel/DriftKernelAdapter.php b/src/Adapter/DriftKernel/DriftKernelAdapter.php index 89a2d6e..11708c8 100644 --- a/src/Adapter/DriftKernel/DriftKernelAdapter.php +++ b/src/Adapter/DriftKernel/DriftKernelAdapter.php @@ -15,6 +15,7 @@ namespace Drift\Server\Adapter\DriftKernel; +use Drift\EventBus\Subscriber\EventBusSubscriber; use Drift\HttpKernel\AsyncKernel; use Drift\Kernel as ApplicationKernel; use Drift\Server\Adapter\SymfonyKernelBasedAdapter; @@ -44,15 +45,41 @@ protected function checkKernel($kernel) * @param string $environment * @param bool $debug * - * @return AsyncKernel + * @return Kernel */ protected static function createKernelByEnvironmentAndDebug( string $environment, bool $debug - ): AsyncKernel { + ): Kernel { return new ApplicationKernel($environment, $debug); } + /** + * @return PromiseInterface + */ + protected function preload(): PromiseInterface + { + return $this + ->kernel + ->preload() + ->then(function () { + $container = $this->kernel->getContainer(); + $serverContext = $this->serverContext; + + if ( + class_exists(EventBusSubscriber::class) && + $serverContext->hasExchanges() && + $container->has(EventBusSubscriber::class) + ) { + $eventBusSubscriber = $container->get(EventBusSubscriber::class); + $eventBusSubscriber->subscribeToExchanges( + $serverContext->getExchanges(), + $this->outputPrinter + ); + } + }); + } + /** * @param Kernel|AsyncKernel $kernel * @param Request $request diff --git a/src/Adapter/KernelAdapter.php b/src/Adapter/KernelAdapter.php index c1a67f6..95dad7d 100644 --- a/src/Adapter/KernelAdapter.php +++ b/src/Adapter/KernelAdapter.php @@ -32,12 +32,12 @@ interface KernelAdapter extends ObservableKernel { /** - * @param LoopInterface $loop - * @param string $rootPath - * @param ServerContext $serverContext - * @param FilesystemInterface $filesystem - * @param OutputPrinter $outputPrinter - * @param MimeTypeChecker $mimeTypeChecker + * @param LoopInterface $loop + * @param string $rootPath + * @param ServerContext $serverContext + * @param OutputPrinter $outputPrinter + * @param MimeTypeChecker $mimeTypeChecker + * @param FilesystemInterface|null $filesystem * * @return PromiseInterface * @@ -47,9 +47,9 @@ public static function create( LoopInterface $loop, string $rootPath, ServerContext $serverContext, - FilesystemInterface $filesystem, OutputPrinter $outputPrinter, - MimeTypeChecker $mimeTypeChecker + MimeTypeChecker $mimeTypeChecker, + ?FilesystemInterface $filesystem ): PromiseInterface; /** diff --git a/src/Adapter/SymfonyKernel/SymfonyKernelAdapter.php b/src/Adapter/SymfonyKernel/SymfonyKernelAdapter.php index 9744337..62fe9dc 100644 --- a/src/Adapter/SymfonyKernel/SymfonyKernelAdapter.php +++ b/src/Adapter/SymfonyKernel/SymfonyKernelAdapter.php @@ -43,12 +43,12 @@ protected function checkKernel($kernel) * @param string $environment * @param bool $debug * - * @return AsyncKernel + * @return Kernel */ protected static function createKernelByEnvironmentAndDebug( string $environment, bool $debug - ): AsyncKernel { + ): Kernel { return new ApplicationKernel($environment, $debug); } diff --git a/src/Adapter/SymfonyKernelBasedAdapter.php b/src/Adapter/SymfonyKernelBasedAdapter.php index 32cd910..85f74f7 100644 --- a/src/Adapter/SymfonyKernelBasedAdapter.php +++ b/src/Adapter/SymfonyKernelBasedAdapter.php @@ -16,8 +16,6 @@ namespace Drift\Server\Adapter; use Drift\Console\OutputPrinter; -use Drift\EventBus\Subscriber\EventBusSubscriber; -use Drift\HttpKernel\AsyncKernel; use Drift\Server\Context\ServerContext; use Drift\Server\Exception\KernelException; use Drift\Server\Exception\RouteNotFoundException; @@ -45,21 +43,22 @@ abstract class SymfonyKernelBasedAdapter implements KernelAdapter { protected Kernel $kernel; - private FilesystemInterface $filesystem; - private ServerContext $serverContext; - private MimeTypeChecker $mimeTypeChecker; - private string $rootPath; + protected ?FilesystemInterface $filesystem; + protected ServerContext $serverContext; + protected MimeTypeChecker $mimeTypeChecker; + protected OutputPrinter $outputPrinter; + protected string $rootPath; /** * @param string $environment * @param bool $debug * - * @return AsyncKernel + * @return Kernel */ abstract protected static function createKernelByEnvironmentAndDebug( string $environment, bool $debug - ): AsyncKernel; + ): Kernel; /** * @param $kernel @@ -80,12 +79,12 @@ abstract protected function kernelHandle( ): PromiseInterface; /** - * @param LoopInterface $loop - * @param string $rootPath - * @param ServerContext $serverContext - * @param FilesystemInterface $filesystem - * @param OutputPrinter $outputPrinter - * @param MimeTypeChecker $mimeTypeChecker + * @param LoopInterface $loop + * @param string $rootPath + * @param ServerContext $serverContext + * @param OutputPrinter $outputPrinter + * @param MimeTypeChecker $mimeTypeChecker + * @param FilesystemInterface|null $filesystem * * @return PromiseInterface * @@ -95,9 +94,9 @@ public static function create( LoopInterface $loop, string $rootPath, ServerContext $serverContext, - FilesystemInterface $filesystem, OutputPrinter $outputPrinter, - MimeTypeChecker $mimeTypeChecker + MimeTypeChecker $mimeTypeChecker, + ?FilesystemInterface $filesystem ): PromiseInterface { $adapter = new static(); $kernel = static::createKernelByEnvironmentAndDebug($serverContext->getEnvironment(), $serverContext->isDebug()); @@ -111,30 +110,24 @@ public static function create( $adapter->serverContext = $serverContext; $adapter->filesystem = $filesystem; $adapter->mimeTypeChecker = $mimeTypeChecker; + $adapter->outputPrinter = $outputPrinter; $adapter->rootPath = $rootPath; - return $kernel + return $adapter ->preload() - ->then(function () use ($adapter, $outputPrinter) { - $container = $adapter->kernel->getContainer(); - $serverContext = $adapter->serverContext; - - if ( - $serverContext->hasExchanges() && - $container->has(EventBusSubscriber::class) - ) { - $eventBusSubscriber = $container->get(EventBusSubscriber::class); - $eventBusSubscriber->subscribeToExchanges( - $serverContext->getExchanges(), - $outputPrinter - ); - } - }) ->then(function () use ($adapter) { return $adapter; }); } + /** + * @return PromiseInterface + */ + protected function preload(): PromiseInterface + { + return resolve(); + } + /** * @param ServerRequestInterface $request * @@ -292,10 +285,14 @@ private function toSymfonyUploadedFile(PsrUploadedFile $file): PromiseInterface } $promise = (UPLOAD_ERR_OK == $file->getError()) - ? $this - ->filesystem - ->file($tmpFilename) - ->putContents($content) + ? ( + is_null($this->filesystem) + ? resolve(file_put_contents($tmpFilename, $content)) + : $this + ->filesystem + ->file($tmpFilename) + ->putContents($content) + ) : resolve(); return $promise @@ -318,10 +315,14 @@ private function toSymfonyUploadedFile(PsrUploadedFile $file): PromiseInterface private function cleanTemporaryUploadedFiles(Request $request): array { return array_map(function (SymfonyUploadedFile $file) { - return $this - ->filesystem - ->file($file->getPath().'/'.$file->getFilename()) - ->remove(); + $filePath = $file->getPath().'/'.$file->getFilename(); + + return (is_null($this->filesystem)) + ? resolve(unlink($filePath)) + : $this + ->filesystem + ->file($filePath) + ->remove(); }, $request->files->all()); } diff --git a/src/Application.php b/src/Application.php index b83f4d0..5e53b56 100644 --- a/src/Application.php +++ b/src/Application.php @@ -37,6 +37,7 @@ use React\Http\Server as HttpServer; use React\Promise\Promise; use React\Promise\PromiseInterface; +use function React\Promise\reject; use function React\Promise\resolve; use React\Socket\Server as SocketServer; use React\Stream\ReadableStreamInterface; @@ -98,13 +99,13 @@ public function getKernelAdapter(): string } /** - * @param KernelAdapter $kernelAdapter - * @param FilesystemInterface $filesystem - * @param bool $forceShutdownReference + * @param KernelAdapter $kernelAdapter + * @param ?FilesystemInterface $filesystem + * @param bool $forceShutdownReference */ public function runServer( KernelAdapter $kernelAdapter, - FilesystemInterface $filesystem, + ?FilesystemInterface $filesystem, bool &$forceShutdownReference ) { $socket = new SocketServer( @@ -308,27 +309,41 @@ private function compressResponse( } /** - * @param ServerRequestInterface $request - * @param FilesystemInterface $filesystem - * @param string $rootPath - * @param string $resourcePath + * @param ServerRequestInterface $request + * @param FilesystemInterface|null $filesystem + * @param string $rootPath + * @param string $resourcePath * * @return PromiseInterface */ public function handleStaticResource( ServerRequestInterface $request, - FilesystemInterface $filesystem, + ?FilesystemInterface $filesystem, string $rootPath, string $resourcePath ): PromiseInterface { $from = microtime(true); - $file = $filesystem->file($rootPath.$resourcePath); + $fileFullPath = $rootPath.$resourcePath; + + if (is_null($filesystem)) { + try { + $content = file_get_contents($fileFullPath); + $content = false === $content + ? reject(new Exception('File not found')) + : resolve(file_get_contents($fileFullPath)); + } catch (Exception $exception) { + $content = reject($exception); + } + } else { + $file = $filesystem->file($rootPath.$resourcePath); + $content = $file + ->exists() + ->then(function () use ($file) { + return $file->getContents(); + }); + } - return $file - ->exists() - ->then(function () use ($file) { - return $file->getContents(); - }) + return $content ->then(function (string $content) use ($rootPath, $resourcePath, $from, $request) { $mimeType = $this ->mimeTypeChecker diff --git a/src/Console/RunServerCommand.php b/src/Console/RunServerCommand.php index 1b22e1a..0f52bbb 100644 --- a/src/Console/RunServerCommand.php +++ b/src/Console/RunServerCommand.php @@ -45,7 +45,10 @@ protected function executeServerCommand( bool &$forceShutdownReference ) { $rootPath = getcwd(); - $filesystem = Filesystem::create($loop); + $filesystem = class_exists(Filesystem::class) + ? Filesystem::create($loop) + : null; + $mimeTypeChecker = new MimeTypeChecker(); $application = new Application( $loop, @@ -61,9 +64,9 @@ protected function executeServerCommand( $loop, $rootPath, $serverContext, - $filesystem, $outputPrinter, - $mimeTypeChecker + $mimeTypeChecker, + $filesystem ) ->then(function (KernelAdapter $kernelAdapter) use ($application, $outputPrinter, $serverContext, $filesystem, &$forceShutdownReference) { (new ConsoleServerMessage('Kernel built.', '~', true))->print($outputPrinter); diff --git a/src/ServerHeaderPrinter.php b/src/ServerHeaderPrinter.php index 99a4b7c..d85eb7b 100644 --- a/src/ServerHeaderPrinter.php +++ b/src/ServerHeaderPrinter.php @@ -17,6 +17,7 @@ use Drift\Console\OutputPrinter; use Drift\Server\Context\ServerContext; +use React\Filesystem\Filesystem; /** * Class ServerHeaderPrinter. @@ -49,6 +50,10 @@ public static function print( $outputPrinter->printHeaderLine("Environment: {$serverContext->getEnvironment()}"); $outputPrinter->printHeaderLine('Debug: '.($serverContext->isDebug() ? 'enabled' : 'disabled')); $outputPrinter->printHeaderLine('Static Folder: '.$serverContext->getStaticFolderAsString()); + if (!class_exists(Filesystem::class)) { + $outputPrinter->printHeaderLine('Static Folder: Attention! You should install the dependency `react/filesystem` to serve static content in a non-blocking way.'); + $outputPrinter->printHeaderLine('Static Folder: Serving the content with blocking PHP functions.'); + } $outputPrinter->printHeaderLine("Adapter: {$serverContext->getAdapter()}"); $outputPrinter->printHeaderLine("Workers: {$serverContext->getWorkers()}"); $outputPrinter->printHeaderLine('Exchanges subscribed: '.($serverContext->hasExchanges() diff --git a/tests/ApplicationTest.php b/tests/ApplicationTest.php index 2483700..9f07eea 100644 --- a/tests/ApplicationTest.php +++ b/tests/ApplicationTest.php @@ -43,12 +43,12 @@ public function testRegular() usleep(500000); Utils::curl("http://127.0.0.1:$port/query?code=200"); usleep(500000); - $this->assertContains( + $this->assertStringContainsString( '200 GET', $process->getOutput() ); - $this->assertContains( + $this->assertStringContainsString( '/query', $process->getOutput() ); @@ -76,12 +76,12 @@ public function testDefaultHost() usleep(500000); Utils::curl("http://127.0.0.1:$port/query?code=200"); usleep(500000); - $this->assertContains( + $this->assertStringContainsString( '200 GET', $process->getOutput() ); - $this->assertContains( + $this->assertStringContainsString( '/query', $process->getOutput() ); @@ -109,12 +109,12 @@ public function testEmptyHost() usleep(500000); Utils::curl("http://127.0.0.1:$port/query?code=200"); usleep(500000); - $this->assertContains( + $this->assertStringContainsString( '200 GET', $process->getOutput() ); - $this->assertContains( + $this->assertStringContainsString( '/query', $process->getOutput() ); @@ -172,7 +172,7 @@ public function testRouteNotFound() Utils::curl("http://127.0.0.1:$port/another/route?code=200"); usleep(500000); - $this->assertContains( + $this->assertStringContainsString( '404 GET', $process->getOutput() ); @@ -245,8 +245,6 @@ public function testAnotherPSR7Implementation() /** * Test server values. - * - * @group lol */ public function testServerValues() { @@ -261,7 +259,7 @@ public function testServerValues() $process->start(); usleep(500000); - list($_, $_, $code) = Utils::curl("http://127.0.0.1:$port/check-server-vars?port=$port"); + list($_, $_, $code) = Utils::curl("http://127.0.0.1:$port/check-srv-vars?port=$port"); $this->assertEquals(200, $code); usleep(500000); @@ -316,12 +314,12 @@ public function testSymfonyAdapter() usleep(500000); Utils::curl("http://127.0.0.1:$port/query?code=200"); usleep(500000); - $this->assertContains( + $this->assertStringContainsString( '200 GET', $process->getOutput() ); - $this->assertContains( + $this->assertStringContainsString( '/query', $process->getOutput() ); diff --git a/tests/ExchangesTest.php b/tests/ExchangesTest.php index 9aa8851..ca0ffb5 100644 --- a/tests/ExchangesTest.php +++ b/tests/ExchangesTest.php @@ -43,15 +43,15 @@ public function testRegular() sleep(1); $output = $process->getOutput(); $process->stop(); - $this->assertContains( + $this->assertStringContainsString( 'Exchanges subscribed: exchange1, exchange2:queue2', $output ); - $this->assertContains( + $this->assertStringContainsString( 'Subscribed to exchange exchange1 and temporary queue', $output ); - $this->assertContains( + $this->assertStringContainsString( 'Subscribed to exchange exchange2 and queue queue2', $output ); diff --git a/tests/FakeAdapter.php b/tests/FakeAdapter.php index 3346d54..aefb947 100644 --- a/tests/FakeAdapter.php +++ b/tests/FakeAdapter.php @@ -15,8 +15,8 @@ namespace Drift\Server\Tests; -use Drift\HttpKernel\AsyncKernel; use Drift\Server\Adapter\DriftKernel\DriftKernelAdapter; +use Symfony\Component\HttpKernel\Kernel; /** * Class FakeAdapter. @@ -27,12 +27,12 @@ class FakeAdapter extends DriftKernelAdapter * @param string $environment * @param bool $debug * - * @return AsyncKernel + * @return Kernel */ protected static function createKernelByEnvironmentAndDebug( string $environment, bool $debug - ): AsyncKernel { + ): Kernel { return new FakeKernel($environment, $debug); } diff --git a/tests/FakeExchangesAdapter.php b/tests/FakeExchangesAdapter.php index 624171a..1d7953f 100644 --- a/tests/FakeExchangesAdapter.php +++ b/tests/FakeExchangesAdapter.php @@ -15,7 +15,7 @@ namespace Drift\Server\Tests; -use Drift\HttpKernel\AsyncKernel; +use Symfony\Component\HttpKernel\Kernel; /** * Class FakeExchangesAdapter. @@ -26,12 +26,12 @@ class FakeExchangesAdapter extends FakeAdapter * @param string $environment * @param bool $debug * - * @return AsyncKernel + * @return Kernel */ protected static function createKernelByEnvironmentAndDebug( string $environment, bool $debug - ): AsyncKernel { + ): Kernel { return new FakeExchangesKernel($environment, $debug); } } diff --git a/tests/FakeKernel.php b/tests/FakeKernel.php index cf404c2..e1f30a9 100644 --- a/tests/FakeKernel.php +++ b/tests/FakeKernel.php @@ -113,6 +113,7 @@ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQ $loop = $this->getContainer()->get('reactphp.event_loop'); $code = \intval($request->query->get('code', '200')); $pathInfo = $request->getPathInfo(); + if (400 === $code) { throw new \Exception('Bad Request'); } @@ -207,11 +208,11 @@ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQ }); } - if ('/check-server-vars' === $pathInfo) { + if ('/check-srv-vars' === $pathInfo) { $server = $request->server; $code = ( - '/check-server-vars' === $server->get('REQUEST_URI') && + '/check-srv-vars' === $server->get('REQUEST_URI') && '127.0.0.1' === $server->get('REMOTE_ADDR') && \intval($server->get('SERVER_PORT')) === \intval($request->query->get('port')) ) ? 200 : 500; diff --git a/tests/FakeLaminasKernel.php b/tests/FakeLaminasKernel.php index 0186435..fe81e8a 100644 --- a/tests/FakeLaminasKernel.php +++ b/tests/FakeLaminasKernel.php @@ -34,12 +34,12 @@ class FakeLaminasKernel implements KernelAdapter { /** - * @param LoopInterface $loop - * @param string $rootPath - * @param ServerContext $serverContext - * @param FilesystemInterface $filesystem - * @param OutputPrinter $outputPrinter - * @param MimeTypeChecker $mimeTypeChecker + * @param LoopInterface $loop + * @param string $rootPath + * @param ServerContext $serverContext + * @param OutputPrinter $outputPrinter + * @param MimeTypeChecker $mimeTypeChecker + * @param FilesystemInterface|null $filesystem * * @return PromiseInterface * @@ -49,9 +49,9 @@ public static function create( LoopInterface $loop, string $rootPath, ServerContext $serverContext, - FilesystemInterface $filesystem, OutputPrinter $outputPrinter, - MimeTypeChecker $mimeTypeChecker + MimeTypeChecker $mimeTypeChecker, + ?FilesystemInterface $filesystem ): PromiseInterface { return resolve(new self()); } diff --git a/tests/FakeSymfonyAdapter.php b/tests/FakeSymfonyAdapter.php index 326caac..5400a63 100644 --- a/tests/FakeSymfonyAdapter.php +++ b/tests/FakeSymfonyAdapter.php @@ -15,8 +15,8 @@ namespace Drift\Server\Tests; -use Drift\HttpKernel\AsyncKernel; use Drift\Server\Adapter\SymfonyKernel\SymfonyKernelAdapter; +use Symfony\Component\HttpKernel\Kernel; /** * Class FakeSymfonyAdapter. @@ -27,12 +27,12 @@ class FakeSymfonyAdapter extends SymfonyKernelAdapter * @param string $environment * @param bool $debug * - * @return AsyncKernel + * @return Kernel */ protected static function createKernelByEnvironmentAndDebug( string $environment, bool $debug - ): AsyncKernel { + ): Kernel { return new FakeKernel($environment, $debug); } } diff --git a/tests/FilesystemMessageTest.php b/tests/FilesystemMessageTest.php new file mode 100644 index 0000000..dca89a7 --- /dev/null +++ b/tests/FilesystemMessageTest.php @@ -0,0 +1,83 @@ + + */ + +declare(strict_types=1); + +namespace Drift\Server\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Process\Process; + +/** + * Class FilesystemMessageTest. + */ +class FilesystemMessageTest extends TestCase +{ + /** + * Test non blocking server. + * + * @group with-filesystem-message + */ + public function testAttentionFilesystemMessageAppears() + { + $port = rand(2000, 9999); + $process = new Process([ + 'php', + dirname(__FILE__).'/../bin/server', + 'run', + "0.0.0.0:$port", + '--adapter='.FakeAdapter::class, + '--dev', + ]); + + $process->start(); + usleep(500000); + Utils::curl("http://127.0.0.1:$port/query?code=200"); + usleep(500000); + $this->assertStringContainsString( + 'react/filesystem', + $process->getOutput() + ); + + $process->stop(); + } + + /** + * Test non blocking server. + * + * @group without-filesystem-message + */ + public function testAttentionFilesystemMessageNotAppears() + { + $port = rand(2000, 9999); + $process = new Process([ + 'php', + dirname(__FILE__).'/../bin/server', + 'run', + "0.0.0.0:$port", + '--adapter='.FakeAdapter::class, + '--dev', + ]); + + $process->start(); + usleep(500000); + Utils::curl("http://127.0.0.1:$port/query?code=200"); + usleep(500000); + $this->assertStringNotContainsString( + 'react/filesystem', + $process->getOutput() + ); + + $process->stop(); + } +} diff --git a/tests/KernelEventsTest.php b/tests/KernelEventsTest.php index 00b85ed..124bc6e 100644 --- a/tests/KernelEventsTest.php +++ b/tests/KernelEventsTest.php @@ -40,8 +40,8 @@ public function testPreload() $process->start(); usleep(300000); - $this->assertContains('Kernel preloaded', $process->getOutput()); - $this->assertContains('[Preloaded]', $process->getOutput()); + $this->assertStringContainsString('Kernel preloaded', $process->getOutput()); + $this->assertStringContainsString('[Preloaded]', $process->getOutput()); $this->assertFalse($process->isTerminated()); } @@ -71,8 +71,8 @@ public function testShutdown() $process->signal(SIGTERM); sleep(1); - $this->assertContains('Loop forced to stop', $process->getOutput()); - $this->assertContains('[Shutdown]', $process->getOutput()); + $this->assertStringContainsString('Loop forced to stop', $process->getOutput()); + $this->assertStringContainsString('[Shutdown]', $process->getOutput()); $this->assertTrue($process->isTerminated()); } @@ -100,13 +100,13 @@ public function testShutdownIsForced() $process->start(); usleep(300000); $this->assertFalse($process->isTerminated()); - $this->assertContains('Allowed number of loop stops: 10', $process->getOutput()); + $this->assertStringContainsString('Allowed number of loop stops: 10', $process->getOutput()); $process->signal(SIGINT); usleep(300000); - $this->assertContains('Loop forced to stop', $process->getOutput()); - $this->assertContains('[Shutdown]', $process->getOutput()); - $this->assertNotContains('9 retries missing', $process->getOutput()); + $this->assertStringContainsString('Loop forced to stop', $process->getOutput()); + $this->assertStringContainsString('[Shutdown]', $process->getOutput()); + $this->assertStringNotContainsString('9 retries missing', $process->getOutput()); $this->assertTrue($process->isTerminated()); } } diff --git a/tests/ServerOptionsTest.php b/tests/ServerOptionsTest.php index f404d22..fea1aac 100644 --- a/tests/ServerOptionsTest.php +++ b/tests/ServerOptionsTest.php @@ -45,7 +45,7 @@ public function testMultipleOptionsAreWorking() Utils::curl("http://127.0.0.1:$port/query?code=200"); usleep(500000); - $this->assertContains( + $this->assertStringContainsString( '200 GET', $process->getOutput() ); @@ -73,7 +73,7 @@ public function test0Concurrency() Utils::curl("http://127.0.0.1:$port/query?code=200"); usleep(500000); - $this->assertContains( + $this->assertStringContainsString( '500 EXC', $process->getOutput() ); diff --git a/tests/WatcherTest.php b/tests/WatcherTest.php index 6e231a6..6629bb2 100644 --- a/tests/WatcherTest.php +++ b/tests/WatcherTest.php @@ -42,7 +42,7 @@ public function testRegular() sleep(2); Utils::curl("http://127.0.0.1:$port/query?code=200"); $output = $process->getOutput(); - $this->assertContains('Workers: 1', $output); + $this->assertStringContainsString('Workers: 1', $output); $this->assertNotFalse( strpos( $output, @@ -79,7 +79,7 @@ public function testFileWatching() $process->start(); sleep(2); $output = $process->getOutput(); - $this->assertContains('Workers: 1', $output); + $this->assertStringContainsString('Workers: 1', $output); $this->assertFalse( strpos( $output, diff --git a/tests/WorkersTest.php b/tests/WorkersTest.php index b1340ba..9ece369 100644 --- a/tests/WorkersTest.php +++ b/tests/WorkersTest.php @@ -41,11 +41,11 @@ public function testOneWorker() sleep(1); $output = $process->getOutput(); - $this->assertContains('Workers: 1', $output); - $this->assertContains('200 GET', $output); - $this->assertNotContains('[00] ', $output); - $this->assertNotContains('[01] ', $output); - $this->assertNotContains('[02] ', $output); + $this->assertStringContainsString('Workers: 1', $output); + $this->assertStringContainsString('200 GET', $output); + $this->assertStringNotContainsString('[00] ', $output); + $this->assertStringNotContainsString('[01] ', $output); + $this->assertStringNotContainsString('[02] ', $output); $process->stop(); } @@ -67,11 +67,11 @@ public function testNoWorkerDefault() sleep(1); $output = $process->getOutput(); - $this->assertContains('Workers: 1', $output); - $this->assertContains('200 GET', $output); - $this->assertNotContains('[00] ', $output); - $this->assertNotContains('[01] ', $output); - $this->assertNotContains('[02] ', $output); + $this->assertStringContainsString('Workers: 1', $output); + $this->assertStringContainsString('200 GET', $output); + $this->assertStringNotContainsString('[00] ', $output); + $this->assertStringNotContainsString('[01] ', $output); + $this->assertStringNotContainsString('[02] ', $output); $process->stop(); } @@ -103,10 +103,10 @@ public function testSeveralWorkers() Utils::curl("http://127.0.0.1:$port/text"); $output = $process->getOutput(); - $this->assertContains('Workers: 2', $output); - $this->assertContains('[00] ', $output); - $this->assertContains('[01] ', $output); - $this->assertNotContains('[02] ', $output); + $this->assertStringContainsString('Workers: 2', $output); + $this->assertStringContainsString('[00] ', $output); + $this->assertStringContainsString('[01] ', $output); + $this->assertStringNotContainsString('[02] ', $output); $process->stop(); } @@ -134,10 +134,10 @@ public function testWorkersOptimized() $output = $process->getOutput(); sleep(2); - $this->assertContains("Workers: $numberOfProcs", $output); + $this->assertStringContainsString("Workers: $numberOfProcs", $output); for ($i = 0; $i < $numberOfProcs; ++$i) { $iWithTrailingZeros = str_pad(\strval($i), 2, '0', STR_PAD_LEFT); - $this->assertContains("[$iWithTrailingZeros] ", $output); + $this->assertStringContainsString("[$iWithTrailingZeros] ", $output); } } }