Skip to content

Commit 4be0914

Browse files
committed
Add NullRunner stub for integration tests with X_EXPERIMENTAL_RUNNER
1 parent 5a98992 commit 4be0914

File tree

9 files changed

+121
-7
lines changed

9 files changed

+121
-7
lines changed

phpstan.neon.dist

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@ parameters:
55
- src/
66
- tests/
77

8+
fileExtensions:
9+
- php
10+
- phpt
11+
812
reportUnmatchedIgnoredErrors: false

phpunit.xml.dist

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
<testsuites>
1212
<testsuite name="Framework X test suite">
1313
<directory>./tests/</directory>
14-
<exclude>./tests/integration/</exclude>
14+
<directory suffix=".phpt">./tests/</directory>
15+
<exclude>./tests/integration/vendor/</exclude>
1516
</testsuite>
1617
</testsuites>
1718
<coverage>

phpunit.xml.legacy

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
<testsuites>
1010
<testsuite name="Framework X test suite">
1111
<directory>./tests/</directory>
12-
<exclude>./tests/install-as-dep/</exclude>
12+
<directory suffix=".phpt">./tests/</directory>
13+
<exclude>./tests/integration/vendor/</exclude>
1314
</testsuite>
1415
</testsuites>
1516
<filter>

src/App.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
use FrameworkX\Io\MiddlewareHandler;
66
use FrameworkX\Io\RedirectHandler;
77
use FrameworkX\Io\RouteHandler;
8-
use FrameworkX\Runner\HttpServerRunner;
9-
use FrameworkX\Runner\SapiRunner;
108
use Psr\Http\Message\ResponseInterface;
119
use Psr\Http\Message\ServerRequestInterface;
1210
use React\Http\Message\Response;
@@ -22,7 +20,7 @@ class App
2220
/** @var RouteHandler */
2321
private $router;
2422

25-
/** @var HttpServerRunner|SapiRunner|callable(callable(ServerRequestInterface):(ResponseInterface|PromiseInterface<ResponseInterface>)):void */
23+
/** @var callable(callable(ServerRequestInterface):(ResponseInterface|PromiseInterface<ResponseInterface>)):void */
2624
private $runner;
2725

2826
/**
@@ -257,8 +255,8 @@ public function redirect(string $route, string $target, int $code = Response::ST
257255
* the `X_EXPERIMENTAL_RUNNER` environment variable to the desired runner
258256
* class name ({@see Container::getRunner()}).
259257
*
260-
* @see HttpServerRunner::__invoke()
261-
* @see SapiRunner::__invoke()
258+
* @see \FrameworkX\Runner\HttpServerRunner::__invoke()
259+
* @see \FrameworkX\Runner\SapiRunner::__invoke()
262260
* @see Container::getRunner()
263261
*/
264262
public function run(): void

src/Runner/NullRunner.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
namespace FrameworkX\Runner;
4+
5+
/**
6+
* Application runner stub that does nothing when invoked.
7+
*
8+
* This experimental application runner can be used in environments where the
9+
* application lifecycle is managed externally. It can be useful for integration
10+
* testing or when embedding the application in other systems.
11+
*
12+
* Note that this runnner is not intended for production use and is not loaded
13+
* by default. You need to explicitly configure your application to use this
14+
* runner through the `X_EXPERIMENTAL_RUNNER` environment variable:
15+
*
16+
* ```php
17+
* $container = new Container([
18+
* // 'X_EXPERIMENTAL_RUNNER' => fn(?string $X_EXPERIMENTAL_RUNNER = null): ?string => $X_EXPERIMENTAL_RUNNER,
19+
* // 'X_EXPERIMENTAL_RUNNER' => fn(bool|string $ACME = false): ?string => $ACME ? NullRunner::class : null,
20+
* 'X_EXPERIMENTAL_RUNNER' => NullRunner::class
21+
* ]);
22+
*
23+
* $app = new App($container);
24+
* ```
25+
*
26+
* Likewise, you may pass this runner through an environment variable from your
27+
* integration tests, see also included PHPT test files for examples.
28+
*
29+
* @see \FrameworkX\Container::getRunner()
30+
*/
31+
class NullRunner
32+
{
33+
/**
34+
* @param callable(\Psr\Http\Message\ServerRequestInterface):(\Psr\Http\Message\ResponseInterface|\React\Promise\PromiseInterface<\Psr\Http\Message\ResponseInterface>) $handler
35+
* @return void
36+
*/
37+
public function __invoke(callable $handler): void
38+
{
39+
// NO-OP
40+
}
41+
}

tests/AppTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use FrameworkX\Io\MiddlewareHandler;
1010
use FrameworkX\Io\RouteHandler;
1111
use FrameworkX\Runner\HttpServerRunner;
12+
use FrameworkX\Runner\NullRunner;
1213
use FrameworkX\Tests\Fixtures\InvalidAbstract;
1314
use FrameworkX\Tests\Fixtures\InvalidConstructorInt;
1415
use FrameworkX\Tests\Fixtures\InvalidConstructorIntersection;
@@ -949,6 +950,18 @@ public function testRunWillInvokeCustomRunnerFromContainerEnvironmentVariable():
949950
$app->run();
950951
}
951952

953+
public function testRunReturnsImmediatelyWithNullRunnerFromContainerEnvironmentVariable(): void
954+
{
955+
$container = new Container([
956+
'X_EXPERIMENTAL_RUNNER' => NullRunner::class
957+
]);
958+
959+
$app = new App($container);
960+
961+
$this->expectOutputString('');
962+
$app->run();
963+
}
964+
952965
public function testGetMethodAddsGetRouteOnRouter(): void
953966
{
954967
$router = $this->createMock(RouteHandler::class);

tests/Runner/NullRunnerTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace FrameworkX\Tests\Runner;
4+
5+
use FrameworkX\Runner\NullRunner;
6+
use PHPUnit\Framework\TestCase;
7+
8+
class NullRunnerTest extends TestCase
9+
{
10+
public function testInvokeReturnsImmediately(): void
11+
{
12+
$runner = new NullRunner();
13+
14+
$this->expectOutputString('');
15+
$runner(function () {
16+
throw new \BadFunctionCallException('Should not be called');
17+
});
18+
}
19+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--TEST--
2+
Loading index file with NullRunner allows invoking the app
3+
--INI--
4+
# suppress legacy PHPUnit 7 warning for Xdebug 3
5+
xdebug.default_enable=
6+
--ENV--
7+
X_EXPERIMENTAL_RUNNER=FrameworkX\Runner\NullRunner
8+
--FILE--
9+
<?php
10+
11+
require __DIR__ . '/../../../vendor/autoload.php';
12+
require __DIR__ . '/../public/index.php';
13+
14+
/** @var FrameworkX\App $app */
15+
assert($app instanceof FrameworkX\App);
16+
17+
$request = new React\Http\Message\ServerRequest('GET', '/');
18+
$response = $app($request);
19+
assert($response instanceof Psr\Http\Message\ResponseInterface);
20+
21+
echo $response->getBody();
22+
23+
?>
24+
--EXPECTF--
25+
%s - "GET / HTTP/1.1" 200 13 0.%d%d%d
26+
Hello world!
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
--TEST--
2+
Loading index file with NullRunner stops immediately without output
3+
--INI--
4+
# suppress legacy PHPUnit 7 warning for Xdebug 3
5+
xdebug.default_enable=
6+
--ENV--
7+
X_EXPERIMENTAL_RUNNER=FrameworkX\Runner\NullRunner
8+
--FILE_EXTERNAL--
9+
../public/index.php
10+
--EXPECTREGEX--
11+
^$

0 commit comments

Comments
 (0)