diff --git a/src/App.php b/src/App.php index 3b7f3c1..4fcb4c8 100644 --- a/src/App.php +++ b/src/App.php @@ -2,12 +2,11 @@ namespace FrameworkX; -use FrameworkX\Io\LogStreamHandler; use FrameworkX\Io\MiddlewareHandler; -use FrameworkX\Io\ReactiveHandler; use FrameworkX\Io\RedirectHandler; use FrameworkX\Io\RouteHandler; -use FrameworkX\Io\SapiHandler; +use FrameworkX\Runner\HttpServerRunner; +use FrameworkX\Runner\SapiRunner; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use React\Http\Message\Response; @@ -23,8 +22,8 @@ class App /** @var RouteHandler */ private $router; - /** @var ReactiveHandler|SapiHandler */ - private $sapi; + /** @var HttpServerRunner|SapiRunner */ + private $runner; /** * Instantiate new X application @@ -127,7 +126,7 @@ public function __construct(...$middleware) $this->router = $router; $this->handler = new MiddlewareHandler($handlers); - $this->sapi = $container->getSapi(); + $this->runner = $container->getRunner(); } /** @@ -241,7 +240,7 @@ public function redirect(string $route, string $target, int $code = Response::ST * Runs the app to handle HTTP requests according to any registered routes and middleware. * * This is where the magic happens: When executed on the command line (CLI), - * this will run the powerful reactive request handler built on top of + * this will run the powerful reactive application runner built on top of * ReactPHP. This works by running the efficient built-in HTTP web server to * handle incoming HTTP requests through ReactPHP's HTTP and socket server. * This async execution mode is usually recommended as it can efficiently @@ -252,14 +251,14 @@ public function redirect(string $route, string $target, int $code = Response::ST * When executed behind traditional PHP SAPIs (PHP-FPM, FastCGI, Apache, etc.), * this will handle a single request and run until a single response is sent. * This is particularly useful because it allows you to run the exact same - * app in any environment. + * application code in any environment. * - * @see ReactiveHandler::run() - * @see SapiHandler::run() + * @see HttpServerRunner::__invoke() + * @see SapiRunner::__invoke() */ public function run(): void { - $this->sapi->run(\Closure::fromCallable([$this, 'handleRequest'])); + ($this->runner)(\Closure::fromCallable([$this, 'handleRequest'])); } /** diff --git a/src/Container.php b/src/Container.php index 507a20f..da97d50 100644 --- a/src/Container.php +++ b/src/Container.php @@ -3,9 +3,9 @@ namespace FrameworkX; use FrameworkX\Io\LogStreamHandler; -use FrameworkX\Io\ReactiveHandler; use FrameworkX\Io\RouteHandler; -use FrameworkX\Io\SapiHandler; +use FrameworkX\Runner\HttpServerRunner; +use FrameworkX\Runner\SapiRunner; use Psr\Container\ContainerInterface; use Psr\Http\Message\ServerRequestInterface; @@ -169,8 +169,8 @@ public function getObject(string $class) /*: object (PHP 7.2+) */ return $this; // @phpstan-ignore-line returns instanceof `T` } elseif ($class === RouteHandler::class) { return new RouteHandler($this); // @phpstan-ignore-line returns instanceof `T` - } elseif ($class === ReactiveHandler::class) { - return new ReactiveHandler(new LogStreamHandler('php://output'), $this->getEnv('X_LISTEN')); // @phpstan-ignore-line returns instanceof `T` + } elseif ($class === HttpServerRunner::class) { + return new HttpServerRunner(new LogStreamHandler('php://output'), $this->getEnv('X_LISTEN')); // @phpstan-ignore-line returns instanceof `T` } return new $class(); } @@ -179,16 +179,16 @@ public function getObject(string $class) /*: object (PHP 7.2+) */ } /** - * [Internal] Get SAPI handler from container + * [Internal] Get the app runner appropriate for this environment from container * - * @return ReactiveHandler|SapiHandler + * @return HttpServerRunner|SapiRunner * @throws \TypeError if container config or factory returns an unexpected type * @throws \Throwable if container factory function throws unexpected exception * @internal */ - public function getSapi() /*: ReactiveHandler|SapiHandler (PHP 8.0+) */ + public function getRunner() /*: HttpServerRunner|SapiRunner (PHP 8.0+) */ { - return $this->getObject(\PHP_SAPI === 'cli' ? ReactiveHandler::class : SapiHandler::class); + return $this->getObject(\PHP_SAPI === 'cli' ? HttpServerRunner::class : SapiRunner::class); } /** @@ -204,10 +204,10 @@ private function loadObject(string $name, int $depth = 64) /*: object (PHP 7.2+) { \assert(\is_array($this->container)); - if ($name === ReactiveHandler::class && !\array_key_exists(ReactiveHandler::class, $this->container)) { - // special case: create ReactiveHandler with X_LISTEN environment variable - $this->container[ReactiveHandler::class] = static function (?string $X_LISTEN = null): ReactiveHandler { - return new ReactiveHandler(new LogStreamHandler('php://output'), $X_LISTEN); + if ($name === HttpServerRunner::class && !\array_key_exists(HttpServerRunner::class, $this->container)) { + // special case: create HttpServerRunner with X_LISTEN environment variable + $this->container[HttpServerRunner::class] = static function (?string $X_LISTEN = null): HttpServerRunner { + return new HttpServerRunner(new LogStreamHandler('php://output'), $X_LISTEN); }; } diff --git a/src/Io/ReactiveHandler.php b/src/Runner/HttpServerRunner.php similarity index 85% rename from src/Io/ReactiveHandler.php rename to src/Runner/HttpServerRunner.php index 2f26939..f3aa15f 100644 --- a/src/Io/ReactiveHandler.php +++ b/src/Runner/HttpServerRunner.php @@ -1,13 +1,15 @@ listenAddress = $listenAddress ?? '127.0.0.1:8080'; } - public function run(callable $handler): void + /** + * @param callable(\Psr\Http\Message\ServerRequestInterface):(\Psr\Http\Message\ResponseInterface|\React\Promise\PromiseInterface<\Psr\Http\Message\ResponseInterface>) $handler + * @return void + */ + public function __invoke(callable $handler): void { $socket = new SocketServer($this->listenAddress); diff --git a/src/Io/SapiHandler.php b/src/Runner/SapiRunner.php similarity index 91% rename from src/Io/SapiHandler.php rename to src/Runner/SapiRunner.php index 4f38426..c515d3d 100644 --- a/src/Io/SapiHandler.php +++ b/src/Runner/SapiRunner.php @@ -1,6 +1,6 @@ ) $handler + * @return void + */ + public function __invoke(callable $handler): void { $request = $this->requestFromGlobals(); diff --git a/tests/AppTest.php b/tests/AppTest.php index b46f840..2efac15 100644 --- a/tests/AppTest.php +++ b/tests/AppTest.php @@ -7,8 +7,8 @@ use FrameworkX\Container; use FrameworkX\ErrorHandler; use FrameworkX\Io\MiddlewareHandler; -use FrameworkX\Io\ReactiveHandler; use FrameworkX\Io\RouteHandler; +use FrameworkX\Runner\HttpServerRunner; use FrameworkX\Tests\Fixtures\InvalidAbstract; use FrameworkX\Tests\Fixtures\InvalidConstructorInt; use FrameworkX\Tests\Fixtures\InvalidConstructorIntersection; @@ -92,7 +92,7 @@ public function testConstructWithContainerMockAssignsDefaultHandlersFromContaine $errorHandler = new ErrorHandler(); $routeHandler = $this->createMock(RouteHandler::class); - $sapi = $this->createMock(ReactiveHandler::class); + $runner = $this->createMock(HttpServerRunner::class); $container = $this->createMock(Container::class); $container->expects($this->exactly(3))->method('getObject')->willReturnMap([ @@ -100,18 +100,18 @@ public function testConstructWithContainerMockAssignsDefaultHandlersFromContaine [ErrorHandler::class, $errorHandler], [RouteHandler::class, $routeHandler], ]); - $container->expects($this->once())->method('getSapi')->willReturn($sapi); + $container->expects($this->once())->method('getRunner')->willReturn($runner); assert($container instanceof Container); $app = new App($container); - $ref = new \ReflectionProperty($app, 'sapi'); + $ref = new \ReflectionProperty($app, 'runner'); if (PHP_VERSION_ID < 80100) { $ref->setAccessible(true); } $ret = $ref->getValue($app); - $this->assertSame($sapi, $ret); + $this->assertSame($runner, $ret); $ref = new ReflectionProperty($app, 'handler'); if (PHP_VERSION_ID < 80100) { @@ -138,13 +138,13 @@ public function testConstructWithContainerInstanceAssignsDefaultHandlersAndConta $container = new Container([]); $app = new App($container); - $ref = new \ReflectionProperty($app, 'sapi'); + $ref = new \ReflectionProperty($app, 'runner'); if (PHP_VERSION_ID < 80100) { $ref->setAccessible(true); } $ret = $ref->getValue($app); - $this->assertSame($container->getSapi(), $ret); + $this->assertSame($container->getRunner(), $ret); $ref = new ReflectionProperty($app, 'handler'); if (PHP_VERSION_ID < 80100) { @@ -893,7 +893,7 @@ public function testConstructWithRouteHandlerClassNameFollowedByMiddlewareThrows new App(RouteHandler::class, $middleware); } - public function testConstructWithContainerWithListenAddressWillPassListenAddressToReactiveHandler(): void + public function testConstructWithContainerWithListenAddressWillPassListenAddressToHttpServerRunner(): void { $container = new Container([ 'X_LISTEN' => '0.0.0.0:8081' @@ -901,31 +901,31 @@ public function testConstructWithContainerWithListenAddressWillPassListenAddress $app = new App($container); - // $sapi = $app->sapi; - $ref = new \ReflectionProperty($app, 'sapi'); + // $runner = $app->runner; + $ref = new \ReflectionProperty($app, 'runner'); if (PHP_VERSION_ID < 80100) { $ref->setAccessible(true); } - $sapi = $ref->getValue($app); - assert($sapi instanceof ReactiveHandler); + $runner = $ref->getValue($app); + assert($runner instanceof HttpServerRunner); - // $listenAddress = $sapi->listenAddress; - $ref = new \ReflectionProperty($sapi, 'listenAddress'); + // $listenAddress = $runner->listenAddress; + $ref = new \ReflectionProperty($runner, 'listenAddress'); if (PHP_VERSION_ID < 80100) { $ref->setAccessible(true); } - $listenAddress = $ref->getValue($sapi); + $listenAddress = $ref->getValue($runner); $this->assertEquals('0.0.0.0:8081', $listenAddress); } - public function testRunWillExecuteRunOnSapiHandlerFromContainer(): void + public function testRunWillInvokeRunnerFromContainer(): void { - $sapi = $this->createMock(ReactiveHandler::class); - $sapi->expects($this->once())->method('run'); + $runner = $this->createMock(HttpServerRunner::class); + $runner->expects($this->once())->method('__invoke'); $container = new Container([ - ReactiveHandler::class => $sapi + HttpServerRunner::class => $runner ]); $app = new App($container); diff --git a/tests/ContainerTest.php b/tests/ContainerTest.php index f4b01a4..da0374c 100644 --- a/tests/ContainerTest.php +++ b/tests/ContainerTest.php @@ -6,8 +6,8 @@ use FrameworkX\Container; use FrameworkX\ErrorHandler; use FrameworkX\Io\LogStreamHandler; -use FrameworkX\Io\ReactiveHandler; use FrameworkX\Io\RouteHandler; +use FrameworkX\Runner\HttpServerRunner; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; use Psr\Container\NotFoundExceptionInterface; @@ -2825,85 +2825,85 @@ public function testGetObjectThrowsIfPsrContainerReturnsWrongType(): void $container->getObject(AccessLogHandler::class); } - public function testGetSapiReturnsDefaultReactiveHandlerInstance(): void + public function testGetRunnerReturnsDefaultHttpServerRunnerInstance(): void { $container = new Container([]); - $sapi = $container->getSapi(); + $runner = $container->getRunner(); - $this->assertInstanceOf(ReactiveHandler::class, $sapi); + $this->assertInstanceOf(HttpServerRunner::class, $runner); - $ref = new \ReflectionProperty($sapi, 'listenAddress'); + $ref = new \ReflectionProperty($runner, 'listenAddress'); if (PHP_VERSION_ID < 80100) { $ref->setAccessible(true); } - $listenAddress = $ref->getValue($sapi); + $listenAddress = $ref->getValue($runner); $this->assertEquals('127.0.0.1:8080', $listenAddress); } - public function testGetSapiReturnsDefaultReactiveHandlerInstanceWithCustomListenAddress(): void + public function testGetRunnerReturnsDefaultHttpServerRunnerInstanceWithCustomListenAddress(): void { $container = new Container([ 'X_LISTEN' => '127.0.0.1:8081' ]); - $sapi = $container->getSapi(); + $runner = $container->getRunner(); - $this->assertInstanceOf(ReactiveHandler::class, $sapi); + $this->assertInstanceOf(HttpServerRunner::class, $runner); - $ref = new \ReflectionProperty($sapi, 'listenAddress'); + $ref = new \ReflectionProperty($runner, 'listenAddress'); if (PHP_VERSION_ID < 80100) { $ref->setAccessible(true); } - $listenAddress = $ref->getValue($sapi); + $listenAddress = $ref->getValue($runner); $this->assertEquals('127.0.0.1:8081', $listenAddress); } - public function testGetSapiTwiceReturnsSameReactiveHandlerInstance(): void + public function testGetRunnerTwiceReturnsSameHttpServerRunnerInstance(): void { $container = new Container([]); - $sapi = $container->getSapi(); + $runner = $container->getRunner(); - $this->assertSame($sapi, $container->getSapi()); + $this->assertSame($runner, $container->getRunner()); } - public function testGetSapiReturnsReactiveHandlerInstanceFromConfig(): void + public function testGetRunnerReturnsHttpServerRunnerInstanceFromConfig(): void { - $sapi = new ReactiveHandler(new LogStreamHandler('php://output'), null); + $runner = new HttpServerRunner(new LogStreamHandler('php://output'), null); $container = new Container([ - ReactiveHandler::class => $sapi + HttpServerRunner::class => $runner ]); - $ret = $container->getSapi(); + $ret = $container->getRunner(); - $this->assertSame($sapi, $ret); + $this->assertSame($runner, $ret); } - public function testGetSapiReturnsReactiveHandlerInstanceFromPsrContainer(): void + public function testGetRunnerReturnsHttpServerRunnerInstanceFromPsrContainer(): void { - $sapi = new ReactiveHandler(new LogStreamHandler('php://output'), null); + $runner = new HttpServerRunner(new LogStreamHandler('php://output'), null); $psr = $this->createMock(ContainerInterface::class); - $psr->expects($this->once())->method('has')->with(ReactiveHandler::class)->willReturn(true); - $psr->expects($this->once())->method('get')->with(ReactiveHandler::class)->willReturn($sapi); + $psr->expects($this->once())->method('has')->with(HttpServerRunner::class)->willReturn(true); + $psr->expects($this->once())->method('get')->with(HttpServerRunner::class)->willReturn($runner); assert($psr instanceof ContainerInterface); $container = new Container($psr); - $ret = $container->getSapi(); + $ret = $container->getRunner(); - $this->assertSame($sapi, $ret); + $this->assertSame($runner, $ret); } - public function testGetSapiReturnsDefaultReactiveHandlerInstanceWithDefaultListenAddressIfPsrContainerHasNoEntry(): void + public function testGetRunnerReturnsDefaultHttpServerRunnerInstanceWithDefaultListenAddressIfPsrContainerHasNoEntry(): void { $psr = $this->createMock(ContainerInterface::class); $psr->expects($this->exactly(2))->method('has')->willReturnMap([ - [ReactiveHandler::class, false], + [HttpServerRunner::class, false], ['X_LISTEN', false], ]); $psr->expects($this->never())->method('get'); @@ -2911,24 +2911,24 @@ public function testGetSapiReturnsDefaultReactiveHandlerInstanceWithDefaultListe assert($psr instanceof ContainerInterface); $container = new Container($psr); - $sapi = $container->getSapi(); + $runner = $container->getRunner(); - $this->assertInstanceOf(ReactiveHandler::class, $sapi); + $this->assertInstanceOf(HttpServerRunner::class, $runner); - $ref = new \ReflectionProperty($sapi, 'listenAddress'); + $ref = new \ReflectionProperty($runner, 'listenAddress'); if (PHP_VERSION_ID < 80100) { $ref->setAccessible(true); } - $listenAddress = $ref->getValue($sapi); + $listenAddress = $ref->getValue($runner); $this->assertEquals('127.0.0.1:8080', $listenAddress); } - public function testGetSapiReturnsDefaultReactiveHandlerInstanceWithCustomListenAddressIfPsrContainerHasNoEntryButCustomListenAddress(): void + public function testGetRunnerReturnsDefaultHttpServerRunnerInstanceWithCustomListenAddressIfPsrContainerHasNoEntryButCustomListenAddress(): void { $psr = $this->createMock(ContainerInterface::class); $psr->expects($this->exactly(2))->method('has')->willReturnMap([ - [ReactiveHandler::class, false], + [HttpServerRunner::class, false], ['X_LISTEN', true], ]); $psr->expects($this->once())->method('get')->with('X_LISTEN')->willReturn('127.0.0.1:8081'); @@ -2936,15 +2936,15 @@ public function testGetSapiReturnsDefaultReactiveHandlerInstanceWithCustomListen assert($psr instanceof ContainerInterface); $container = new Container($psr); - $sapi = $container->getSapi(); + $runner = $container->getRunner(); - $this->assertInstanceOf(ReactiveHandler::class, $sapi); + $this->assertInstanceOf(HttpServerRunner::class, $runner); - $ref = new \ReflectionProperty($sapi, 'listenAddress'); + $ref = new \ReflectionProperty($runner, 'listenAddress'); if (PHP_VERSION_ID < 80100) { $ref->setAccessible(true); } - $listenAddress = $ref->getValue($sapi); + $listenAddress = $ref->getValue($runner); $this->assertEquals('127.0.0.1:8081', $listenAddress); } diff --git a/tests/Io/ReactiveHandlerTest.php b/tests/Runner/HttpServerRunnerTest.php similarity index 78% rename from tests/Io/ReactiveHandlerTest.php rename to tests/Runner/HttpServerRunnerTest.php index b63da1e..65a82ca 100644 --- a/tests/Io/ReactiveHandlerTest.php +++ b/tests/Runner/HttpServerRunnerTest.php @@ -1,9 +1,9 @@ expects($this->atLeastOnce())->method('log')->withConsecutive(['Listening on http://127.0.0.1:8080']); assert($logger instanceof LogStreamHandler); - $handler = new ReactiveHandler($logger, null); + $runner = new HttpServerRunner($logger, null); // lovely: remove socket server on next tick to terminate loop Loop::futureTick(function () { @@ -41,10 +41,12 @@ public function testRunWillReportDefaultListeningAddressAndRunLoop(): void Loop::stop(); }); - $handler->run(function (): void { }); + $runner(function (): void { + throw new \BadFunctionCallException('Should not be reached'); + }); } - public function testRunWillReportGivenListeningAddressAndRunLoop(): void + public function testInvokeWillReportGivenListeningAddressAndRunLoop(): void { $socket = stream_socket_server('127.0.0.1:0'); assert(is_resource($socket)); @@ -56,7 +58,7 @@ public function testRunWillReportGivenListeningAddressAndRunLoop(): void $logger->expects($this->atLeastOnce())->method('log')->withConsecutive(['Listening on http://' . $addr]); assert($logger instanceof LogStreamHandler); - $handler = new ReactiveHandler($logger, $addr); + $runner = new HttpServerRunner($logger, $addr); // lovely: remove socket server on next tick to terminate loop Loop::futureTick(function () { @@ -70,16 +72,18 @@ public function testRunWillReportGivenListeningAddressAndRunLoop(): void Loop::stop(); }); - $handler->run(function (): void { }); + $runner(function (): void { + throw new \BadFunctionCallException('Should not be reached'); + }); } - public function testRunWillReportGivenListeningAddressWithRandomPortAndRunLoop(): void + public function testInvokeWillReportGivenListeningAddressWithRandomPortAndRunLoop(): void { $logger = $this->createMock(LogStreamHandler::class); $logger->expects($this->atLeastOnce())->method('log')->withConsecutive([$this->matches('Listening on http://127.0.0.1:%d')]); assert($logger instanceof LogStreamHandler); - $handler = new ReactiveHandler($logger, '127.0.0.1:0'); + $runner = new HttpServerRunner($logger, '127.0.0.1:0'); // lovely: remove socket server on next tick to terminate loop Loop::futureTick(function () { @@ -93,15 +97,17 @@ public function testRunWillReportGivenListeningAddressWithRandomPortAndRunLoop() Loop::stop(); }); - $handler->run(function (): void { }); + $runner(function (): void { + throw new \BadFunctionCallException('Should not be reached'); + }); } - public function testRunWillRestartLoopUntilSocketIsClosed(): void + public function testInvokeWillRestartLoopUntilSocketIsClosed(): void { $logger = $this->createMock(LogStreamHandler::class); assert($logger instanceof LogStreamHandler); - $handler = new ReactiveHandler($logger, '127.0.0.1:0'); + $runner = new HttpServerRunner($logger, '127.0.0.1:0'); // lovely: remove socket server on next tick to terminate loop Loop::futureTick(function () use ($logger) { @@ -120,10 +126,12 @@ public function testRunWillRestartLoopUntilSocketIsClosed(): void Loop::stop(); }); - $handler->run(function (): void { }); + $runner(function (): void { + throw new \BadFunctionCallException('Should not be reached'); + }); } - public function testRunWillListenForHttpRequestAndSendBackHttpResponseOverSocket(): void + public function testInvokeWillListenForHttpRequestAndSendBackHttpResponseOverSocket(): void { $socket = stream_socket_server('127.0.0.1:0'); assert(is_resource($socket)); @@ -134,7 +142,7 @@ public function testRunWillListenForHttpRequestAndSendBackHttpResponseOverSocket $logger = $this->createMock(LogStreamHandler::class); assert($logger instanceof LogStreamHandler); - $handler = new ReactiveHandler($logger, $addr); + $runner = new HttpServerRunner($logger, $addr); Loop::futureTick(function () use ($addr): void { $connector = new Connector(); @@ -163,12 +171,12 @@ public function testRunWillListenForHttpRequestAndSendBackHttpResponseOverSocket }); }); - $handler->run(function (): Response { + $runner(function (): Response { return new Response(200, ['Date' => '', 'Server' => ''], "OK\n"); }); } - public function testRunWillOnlyRestartLoopAfterAwaitingWhenFibersAreNotAvailable(): void + public function testInvokeWillOnlyRestartLoopAfterAwaitingWhenFibersAreNotAvailable(): void { $socket = stream_socket_server('127.0.0.1:0'); assert(is_resource($socket)); @@ -179,7 +187,7 @@ public function testRunWillOnlyRestartLoopAfterAwaitingWhenFibersAreNotAvailable $logger = $this->createMock(LogStreamHandler::class); assert($logger instanceof LogStreamHandler); - $handler = new ReactiveHandler($logger, $addr); + $runner = new HttpServerRunner($logger, $addr); Loop::futureTick(function () use ($addr, $logger): void { $connector = new Connector(); @@ -216,7 +224,7 @@ public function testRunWillOnlyRestartLoopAfterAwaitingWhenFibersAreNotAvailable }); $done = false; - $handler->run(function () use (&$done): Response { + $runner(function () use (&$done): Response { $promise = new Promise(function (callable $resolve) use (&$done): void { Loop::futureTick(function () use ($resolve, &$done): void { $resolve(null); @@ -232,7 +240,7 @@ public function testRunWillOnlyRestartLoopAfterAwaitingWhenFibersAreNotAvailable $this->assertTrue($done); } - public function testRunWillReportHttpErrorForInvalidClientRequest(): void + public function testInvokeWillReportHttpErrorForInvalidClientRequest(): void { $socket = stream_socket_server('127.0.0.1:0'); assert(is_resource($socket)); @@ -243,7 +251,7 @@ public function testRunWillReportHttpErrorForInvalidClientRequest(): void $logger = $this->createMock(LogStreamHandler::class); assert($logger instanceof LogStreamHandler); - $handler = new ReactiveHandler($logger, $addr); + $runner = new HttpServerRunner($logger, $addr); Loop::futureTick(function () use ($addr, $logger): void { $connector = new Connector(); @@ -269,20 +277,22 @@ public function testRunWillReportHttpErrorForInvalidClientRequest(): void }); }); - $handler->run(function (): void { }); + $runner(function (): void { + throw new \BadFunctionCallException('Should not be reached'); + }); } /** * @requires function pcntl_signal * @requires function posix_kill */ - public function testRunWillStopWhenReceivingSigint(): void + public function testInvokeWillStopWhenReceivingSigint(): void { $logger = $this->createMock(LogStreamHandler::class); $logger->expects($this->exactly(2))->method('log'); assert($logger instanceof LogStreamHandler); - $handler = new ReactiveHandler($logger, '127.0.0.1:0'); + $runner = new HttpServerRunner($logger, '127.0.0.1:0'); Loop::futureTick(function () use ($logger) { $logger->expects($this->once())->method('log')->with('Received SIGINT, stopping loop'); @@ -293,19 +303,21 @@ public function testRunWillStopWhenReceivingSigint(): void }); $this->expectOutputRegex("#^\r?$#"); - $handler->run(function (): void { }); + $runner(function (): void { + throw new \BadFunctionCallException('Should not be reached'); + }); } /** * @requires function pcntl_signal * @requires function posix_kill */ - public function testRunWillStopWhenReceivingSigterm(): void + public function testInvokeWillStopWhenReceivingSigterm(): void { $logger = $this->createMock(LogStreamHandler::class); assert($logger instanceof LogStreamHandler); - $handler = new ReactiveHandler($logger, '127.0.0.1:0'); + $runner = new HttpServerRunner($logger, '127.0.0.1:0'); Loop::futureTick(function () use ($logger) { $logger->expects($this->once())->method('log')->with('Received SIGTERM, stopping loop'); @@ -315,21 +327,25 @@ public function testRunWillStopWhenReceivingSigterm(): void posix_kill($pid, defined('SIGTERM') ? SIGTERM : 15); }); - $handler->run(function (): void { }); + $runner(function (): void { + throw new \BadFunctionCallException('Should not be reached'); + }); } - public function testRunWithEmptyAddressThrows(): void + public function testInvokeWithEmptyAddressThrows(): void { $logger = $this->createMock(LogStreamHandler::class); assert($logger instanceof LogStreamHandler); - $handler = new ReactiveHandler($logger, ''); + $runner = new HttpServerRunner($logger, ''); $this->expectException(\InvalidArgumentException::class); - $handler->run(function (): void { }); + $runner(function (): void { + throw new \BadFunctionCallException('Should not be reached'); + }); } - public function testRunWithBusyPortThrows(): void + public function testInvokeWithBusyPortThrows(): void { $socket = stream_socket_server('127.0.0.1:0'); assert(is_resource($socket)); @@ -343,10 +359,12 @@ public function testRunWithBusyPortThrows(): void $logger = $this->createMock(LogStreamHandler::class); assert($logger instanceof LogStreamHandler); - $handler = new ReactiveHandler($logger, $addr); + $runner = new HttpServerRunner($logger, $addr); $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('Failed to listen on'); - $handler->run(function (): void { }); + $runner(function (): void { + throw new \BadFunctionCallException('Should not be reached'); + }); } } diff --git a/tests/Io/SapiHandlerTest.php b/tests/Runner/SapiRunnerTest.php similarity index 93% rename from tests/Io/SapiHandlerTest.php rename to tests/Runner/SapiRunnerTest.php index 8afd89e..a70048b 100644 --- a/tests/Io/SapiHandlerTest.php +++ b/tests/Runner/SapiRunnerTest.php @@ -1,18 +1,18 @@ requestFromGlobals(); $this->assertEquals('GET', $request->getMethod()); @@ -31,7 +31,7 @@ public function testRequestFromGlobalsWithHeadRequest(): void $_SERVER['SERVER_PROTOCOL'] = 'http/1.0'; $_SERVER['HTTP_HOST'] = 'example.com'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $request = $sapi->requestFromGlobals(); $this->assertEquals('HEAD', $request->getMethod()); @@ -50,7 +50,7 @@ public function testRequestFromGlobalsWithGetRequestOverCustomPort(): void $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; $_SERVER['HTTP_HOST'] = 'localhost:8080'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $request = $sapi->requestFromGlobals(); $this->assertEquals('GET', $request->getMethod()); @@ -70,7 +70,7 @@ public function testRequestFromGlobalsWithGetRequestOverHttps(): void $_SERVER['HTTP_HOST'] = 'localhost'; $_SERVER['HTTPS'] = 'on'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $request = $sapi->requestFromGlobals(); $this->assertEquals('GET', $request->getMethod()); @@ -89,7 +89,7 @@ public function testRequestFromGlobalsWithOptionsAsterisk(): void $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; $_SERVER['HTTP_HOST'] = 'localhost'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $request = $sapi->requestFromGlobals(); $this->assertEquals('OPTIONS', $request->getMethod()); @@ -109,7 +109,7 @@ public function testRequestFromGlobalsWithGetProxy(): void $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; $_SERVER['HTTP_HOST'] = 'example.com'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $request = $sapi->requestFromGlobals(); $this->assertEquals('GET', $request->getMethod()); @@ -129,7 +129,7 @@ public function testRequestFromGlobalsWithConnectProxy(): void $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; $_SERVER['HTTP_HOST'] = 'example.com:443'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $request = $sapi->requestFromGlobals(); $this->assertEquals('CONNECT', $request->getMethod()); @@ -149,7 +149,7 @@ public function testRequestFromGlobalsWithConnectProxyWithDefaultHttpPort(): voi $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; $_SERVER['HTTP_HOST'] = 'example.com'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $request = $sapi->requestFromGlobals(); $this->assertEquals('CONNECT', $request->getMethod()); @@ -168,7 +168,7 @@ public function testRequestFromGlobalsWithConnectProxyWithoutHostHeader(): void $_SERVER['REQUEST_URI'] = 'example.com:8080'; $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $request = $sapi->requestFromGlobals(); $this->assertEquals('CONNECT', $request->getMethod()); @@ -189,7 +189,7 @@ public function testRequestFromGlobalsWithConnectProxyOverHttps(): void $_SERVER['HTTP_HOST'] = 'example.com:443'; $_SERVER['HTTPS'] = 'on'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $request = $sapi->requestFromGlobals(); $this->assertEquals('CONNECT', $request->getMethod()); @@ -206,7 +206,7 @@ public function testSendResponseSendsEmptyResponseWithNoHeadersAndEmptyBodyAndAs { header_remove(); $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $response = new Response(200, [], ''); $this->expectOutputString(''); @@ -226,7 +226,7 @@ public function testSendResponseSendsJsonResponseWithGivenHeadersAndBodyAndAssig { header_remove(); $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $response = new Response(200, ['Content-Type' => 'application/json'], '{}'); $this->expectOutputString('{}'); @@ -247,7 +247,7 @@ public function testSendResponseSendsJsonResponseWithGivenHeadersAndMatchingCont header_remove(); $_SERVER['REQUEST_METHOD'] = 'HEAD'; $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $response = new Response(200, ['Content-Type' => 'application/json'], '{}'); $this->expectOutputString(''); @@ -267,7 +267,7 @@ public function testSendResponseSendsEmptyBodyWithGivenHeadersAndAssignsNoConten { header_remove(); $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $response = new Response(204, ['Content-Type' => 'application/json'], '{}'); $this->expectOutputString(''); @@ -287,7 +287,7 @@ public function testSendResponseSendsEmptyBodyWithGivenHeadersButWithoutExplicit { header_remove(); $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $response = new Response(204, ['Content-Type' => 'application/json', 'Content-Length' => '2'], '{}'); $this->expectOutputString(''); @@ -307,7 +307,7 @@ public function testSendResponseSendsEmptyBodyWithGivenHeadersAndAssignsContentL { header_remove(); $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $response = new Response(304, ['Content-Type' => 'application/json'], 'null'); $this->expectOutputString(''); @@ -327,7 +327,7 @@ public function testSendResponseSendsEmptyBodyWithGivenHeadersAndExplicitContent { header_remove(); $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $response = new Response(304, ['Content-Type' => 'application/json', 'Content-Length' => '2'], ''); $this->expectOutputString(''); @@ -347,7 +347,7 @@ public function testSendResponseSendsStreamingResponseWithNoHeadersAndBodyFromSt { header_remove(); $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $body = new ThroughStream(); $response = new Response(200, [], $body); @@ -371,7 +371,7 @@ public function testSendResponseClosesStreamingResponseAndSendsResponseWithNoHea header_remove(); $_SERVER['REQUEST_METHOD'] = 'HEAD'; $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $body = new ThroughStream(); $response = new Response(200, [], $body); @@ -394,7 +394,7 @@ public function testSendResponseClosesStreamingResponseAndSendsResponseWithNoHea { header_remove(); $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $body = new ThroughStream(); $response = new Response(304, [], $body); @@ -417,7 +417,7 @@ public function testSendResponseClosesStreamingResponseAndSendsResponseWithNoHea { header_remove(); $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $body = new ThroughStream(); $response = new Response(204, [], $body); @@ -441,7 +441,7 @@ public function testSendResponseSendsStreamingResponseWithNoHeadersAndBodyFromSt header_remove(); $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; $_SERVER['SERVER_SOFTWARE'] = 'nginx/1'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $body = new ThroughStream(); $response = new Response(200, [], $body); @@ -464,7 +464,7 @@ public function testSendResponseSetsMultipleCookieHeaders(): void { header_remove(); $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); $response = new Response(204, ['Set-Cookie' => ['1=1', '2=2']], ''); $this->expectOutputString(''); @@ -480,15 +480,15 @@ public function testSendResponseSetsMultipleCookieHeaders(): void /** * @runInSeparateProcess */ - public function testRunWillSendResponseHeadersFromHandler(): void + public function testInvokeWillSendResponseHeadersFromHandler(): void { - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); header_remove(); $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; $this->expectOutputString(''); - $sapi->run(function () { + $sapi(function () { return new Response(); }); @@ -502,15 +502,15 @@ public function testRunWillSendResponseHeadersFromHandler(): void /** * @runInSeparateProcess */ - public function testRunWillSendResponseHeadersFromDeferredHandler(): void + public function testInvokeWillSendResponseHeadersFromDeferredHandler(): void { - $sapi = new SapiHandler(); + $sapi = new SapiRunner(); header_remove(); $_SERVER['SERVER_PROTOCOL'] = 'http/1.1'; $this->expectOutputString(''); - $sapi->run(function () { + $sapi(function () { return resolve(new Response()); });