add HttpEventListener test (#200)

This commit is contained in:
sunxyw 2022-12-25 19:29:44 +08:00 committed by GitHub
parent ca430123c9
commit ed5a9c6c12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 161 additions and 21 deletions

View File

@ -35,7 +35,7 @@
"jangregor/phpstan-prophecy": "^1.0",
"jetbrains/phpstorm-attributes": "^1.0",
"mikey179/vfsstream": "^1.6",
"phpspec/prophecy": "1.x-dev",
"phpspec/prophecy-phpunit": "^2.0",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.1",
"phpstan/phpstan-deprecation-rules": "^1.0",

View File

@ -10,6 +10,9 @@ parameters:
- '#Unsafe usage of new static#'
- '#Call to method initTableList\(\) of deprecated class ZM\\DB\\DB#'
- '#class Fiber#'
- # Ignore Prophesize deprecation bug: https://github.com/phpstan/phpstan-deprecation-rules/issues/76
message: '#^Call to deprecated method prophesize\(\) of class Tests\\TestCase#'
path: tests
dynamicConstantNames:
- SWOOLE_VERSION
- ZM_TEST_LOG_DEBUG

View File

@ -4,24 +4,12 @@ declare(strict_types=1);
namespace Tests;
use Prophecy\Prophet;
use Prophecy\PhpUnit\ProphecyTrait;
/**
* @internal
*/
class TestCase extends \PHPUnit\Framework\TestCase
{
protected Prophet $prophet;
protected function setUp(): void
{
parent::setUp();
$this->prophet = new Prophet();
}
protected function tearDown(): void
{
parent::tearDown();
$this->prophet->checkPredictions();
}
use ProphecyTrait;
}

View File

@ -5,13 +5,11 @@ declare(strict_types=1);
namespace Tests\Trait;
use Prophecy\Argument;
use Prophecy\Prophet;
use Psr\Log\AbstractLogger;
use Psr\Log\LogLevel;
/**
* 模拟 Logger 行为
* @property Prophet $prophet
*/
trait HasLogger
{
@ -37,7 +35,7 @@ trait HasLogger
private function startMockLogger(): void
{
$logger = $this->prophet->prophesize(AbstractLogger::class);
$logger = $this->prophesize(AbstractLogger::class);
$levels = [
LogLevel::EMERGENCY,
LogLevel::ALERT,
@ -50,9 +48,11 @@ trait HasLogger
];
$log_it = fn (...$args) => $this->mockLog(...$args);
foreach ($levels as $level) {
$logger->{$level}(Argument::type('string'), Argument::any())->will(fn ($args) => $log_it($level, ...$args));
$logger->{$level}(Argument::type('string'), Argument::any())
->will(fn ($args) => $log_it($level, ...$args));
}
$logger->log(Argument::in($levels), Argument::type('string'), Argument::any())->will(fn ($args) => $log_it(...$args));
$logger->log(Argument::in($levels), Argument::type('string'), Argument::any())
->will(fn ($args) => $log_it(...$args));
ob_logger_register($logger->reveal());
}
}

View File

@ -0,0 +1,112 @@
<?php
declare(strict_types=1);
namespace Tests\ZM\Event\Listener;
use Choir\Http\ServerRequest;
use Prophecy\Argument;
use Psr\Http\Message\ResponseInterface;
use Symfony\Component\Routing\Route;
use Tests\TestCase;
use Tests\Trait\HasVirtualFileSystem;
use ZM\Event\Listener\HttpEventListener;
use ZM\Utils\HttpUtil;
/**
* @internal
*/
class HttpEventListenerTest extends TestCase
{
use HasVirtualFileSystem;
public function fakeHandler(): ?string
{
return 'I am here to greet';
}
public function testHandleNotAllowedRoute(): void
{
$this->addRoute($this->mockHandler(false), 'fakeHandler');
$event = $this->mockRequestEvent(new ServerRequest('DELETE', '/test/get'), true);
HttpEventListener::getInstance()->onRequest999($event);
}
public function testHandleNotFoundRoute(): void
{
$this->addRoute($this->mockHandler(false), 'fakeHandler');
$event = $this->mockRequestEvent(new ServerRequest('GET', '/test/not-found'), false);
HttpEventListener::getInstance()->onRequest999($event);
}
public function testHandleFoundRoute(): void
{
$this->addRoute('', [$this->mockHandler(true), 'fakeHandler']);
$event = $this->mockRequestEvent(new ServerRequest('GET', '/test/get'), true);
HttpEventListener::getInstance()->onRequest999($event);
}
public function testHandleFoundRouteWithException(): void
{
$this->addRoute('', [$this->mockHandler(true, fn () => null), 'fakeHandler']);
$event = $this->mockRequestEvent(new ServerRequest('GET', '/test/get'), true);
HttpEventListener::getInstance()->onRequest999($event);
}
public function testHandleStaticFile(): void
{
$this->setUpVfs('static', [
'test.txt' => 'Hello, world!',
]);
$event = $this->mockRequestEvent(new ServerRequest('GET', '/test.txt'), true);
$old_conf = config('global.file_server.document_root');
config(['global.file_server.document_root' => $this->vfs->url()]);
HttpEventListener::getInstance()->onRequest1($event);
config(['global.file_server.document_root' => $old_conf]);
}
private function addRoute($class, $method): void
{
HttpUtil::getRouteCollection()->remove('test.get');
$route = new Route('/test/get', ['_class' => $class, '_method' => $method], methods: ['GET']);
HttpUtil::getRouteCollection()->add('test.get', $route);
}
private function mockRequestEvent(ServerRequest $request, bool $should_have_response): \HttpRequestEvent
{
$event = $this->prophesize(\HttpRequestEvent::class);
$event->getRequest()->willReturn($request);
$event->getResponse()->willReturn(null);
if ($should_have_response) {
$event->withResponse(Argument::type(ResponseInterface::class))
->will(function ($args) use ($event) {
$event->getResponse()->willReturn($args[0]);
return $event->reveal();
})
->shouldBeCalledOnce();
} else {
$event->withResponse(Argument::type(ResponseInterface::class))->shouldNotBeCalled();
}
return $event->reveal();
}
private function mockHandler(bool $should_be_called, callable $callback = null): self
{
$handler = $this->prophesize(self::class);
if ($should_be_called) {
$handler->fakeHandler(
Argument::type('array'),
Argument::type(ServerRequest::class),
Argument::type(\HttpRequestEvent::class)
)->will(fn () => $callback ? $callback() : 'OK!')->shouldBeCalledOnce();
} else {
$handler->fakeHandler(Argument::cetera())->shouldNotBeCalled();
}
return $handler->reveal();
}
}

View File

@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace Tests\ZM\Event\Listener;
use Tests\TestCase;
use Tests\Trait\HasLogger;
use ZM\Event\Listener\SignalListener;
/**
* @internal
*/
class SignalListenerTest extends TestCase
{
use HasLogger;
protected function setUp(): void
{
parent::setUp();
$this->startMockLogger();
}
/**
* @requires extension pcntl
*/
public function testListenWorkerSignal(): void
{
$l = new SignalListener();
$l->signalWorker();
// 检查信号处理器是否被设置
/** @noinspection PhpComposerExtensionStubsInspection */
$h = pcntl_signal_get_handler(SIGINT);
$this->assertIsCallable($h);
$this->assertEquals([$l, 'onWorkerInt'], $h);
}
}

View File

@ -190,7 +190,7 @@ class ZMResultPrinter extends CliTestDoxPrinter
$out = '';
if ($message) {
$out .= $this->prefixLines($prefix['message'], strtolower($message) . PHP_EOL) . PHP_EOL;
$out .= $this->prefixLines($prefix['message'], $message . PHP_EOL) . PHP_EOL;
}
if ($diff) {