james-patch-1 #1
24
src/MyWebSocketHandler.php
Normal file
24
src/MyWebSocketHandler.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App;
|
||||||
|
|
||||||
|
use Workerman\Worker;
|
||||||
|
use Workerman\Connection\TcpConnection;
|
||||||
|
|
||||||
|
class MyWebSocketHandler
|
||||||
|
{
|
||||||
|
public function onConnect(TcpConnection $connection): void
|
||||||
|
{
|
||||||
|
echo "New connection\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onMessage(TcpConnection $connection, string $data): void
|
||||||
|
{
|
||||||
|
$connection->send('Hello ' . $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onClose(TcpConnection $connection): void
|
||||||
|
{
|
||||||
|
echo "Connection closed\n";
|
||||||
|
}
|
||||||
|
}
|
@ -1,27 +1,19 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Workerman\Worker;
|
use Workerman\Worker;
|
||||||
|
use App\MyWebSocketHandler;
|
||||||
|
|
||||||
require_once __DIR__ . '/vendor/autoload.php';
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
// Create a Websocket server
|
$handler = new MyWebSocketHandler();
|
||||||
|
|
||||||
$ws_worker = new Worker('websocket://0.0.0.0:2346');
|
$ws_worker = new Worker('websocket://0.0.0.0:2346');
|
||||||
|
|
||||||
// Emitted when new connection come
|
$ws_worker->onConnect = [$handler, 'onConnect'];
|
||||||
$ws_worker->onConnect = function ($connection) {
|
$ws_worker->onMessage = [$handler, 'onMessage'];
|
||||||
echo "New connection\n";
|
$ws_worker->onClose = [$handler, 'onClose'];
|
||||||
};
|
|
||||||
|
|
||||||
// Emitted when data received
|
// 仅在非测试环境下运行
|
||||||
$ws_worker->onMessage = function ($connection, $data) {
|
if (!getenv('PHPUNIT_RUNNING')) {
|
||||||
// Send hello $data
|
|
||||||
$connection->send('Hello ' . $data);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Emitted when connection closed
|
|
||||||
$ws_worker->onClose = function ($connection) {
|
|
||||||
echo "Connection closed\n";
|
|
||||||
};
|
|
||||||
|
|
||||||
// Run worker
|
|
||||||
Worker::runAll();
|
Worker::runAll();
|
||||||
|
}
|
@ -1,110 +1,50 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use src\MyWebSocketHandler;
|
||||||
use Workerman\Connection\TcpConnection;
|
use Workerman\Connection\TcpConnection;
|
||||||
use Workerman\Protocols\Http;
|
use Workerman\Worker;
|
||||||
use Workerman\Protocols\Http\Request;
|
|
||||||
use Workerman\Protocols\Http\Response;
|
|
||||||
|
|
||||||
it('customizes request class', function () {
|
class MyWebSocketHandlerTest extends TestCase
|
||||||
//backup old request class
|
{
|
||||||
$oldRequestClass = Http::requestClass();
|
private $handler;
|
||||||
|
|
||||||
//actual test
|
protected function setUp(): void
|
||||||
$class = new class {
|
{
|
||||||
};
|
$this->handler = new MyWebSocketHandler();
|
||||||
Http::requestClass($class::class);
|
}
|
||||||
expect(Http::requestClass())->toBe($class::class);
|
|
||||||
|
|
||||||
//restore old request class
|
public function testOnConnect()
|
||||||
Http::requestClass($oldRequestClass);
|
{
|
||||||
});
|
$connection = $this->createMock(TcpConnection::class);
|
||||||
|
$worker = $this->createMock(Worker::class);
|
||||||
|
|
||||||
it('tests ::input', function () {
|
// 使用 ob_start + ob_get_clean 捕获输出
|
||||||
//test 413 payload too large
|
ob_start();
|
||||||
testWithConnectionClose(function (TcpConnection $tcpConnection) {
|
$this->handler->onConnect($connection);
|
||||||
expect(Http::input(str_repeat('jhdxr', 3333), $tcpConnection))
|
$output = ob_get_clean();
|
||||||
->toBe(0);
|
|
||||||
}, '413 Payload Too Large');
|
|
||||||
|
|
||||||
//example request from ChatGPT :)
|
$this->assertStringContainsString('New connection', $output);
|
||||||
$buffer = "POST /path/to/resource HTTP/1.1\r\n" .
|
}
|
||||||
"Host: example.com\r\n" .
|
|
||||||
"Content-Type: application/json\r\n" .
|
|
||||||
"Content-Length: 27\r\n" .
|
|
||||||
"\r\n" .
|
|
||||||
'{"key": "value", "foo": "bar"}';
|
|
||||||
|
|
||||||
//unrecognized method
|
public function testOnMessage()
|
||||||
testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) {
|
{
|
||||||
expect(Http::input(str_replace('POST', 'MIAOWU', $buffer), $tcpConnection))
|
$connection = $this->createMock(TcpConnection::class);
|
||||||
->toBe(0);
|
$connection->expects($this->once())
|
||||||
}, '400 Bad Request');
|
->method('send')
|
||||||
|
->with($this->equalTo('Hello world'));
|
||||||
|
|
||||||
//content-length exceeds connection max package size
|
$this->handler->onMessage($connection, 'world');
|
||||||
testWithConnectionClose(function (TcpConnection $tcpConnection) use ($buffer) {
|
}
|
||||||
$tcpConnection->maxPackageSize = 10;
|
|
||||||
expect(Http::input($buffer, $tcpConnection))
|
|
||||||
->toBe(0);
|
|
||||||
}, '413 Payload Too Large');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('tests ::encode for non-object response', function () {
|
public function testOnClose()
|
||||||
/** @var TcpConnection $tcpConnection */
|
{
|
||||||
$tcpConnection = Mockery::mock(TcpConnection::class);
|
$connection = $this->createMock(TcpConnection::class);
|
||||||
$tcpConnection->headers = [
|
|
||||||
'foo' => 'bar',
|
|
||||||
'jhdxr' => ['a', 'b'],
|
|
||||||
];
|
|
||||||
$extHeader = "foo: bar\r\n" .
|
|
||||||
"jhdxr: a\r\n" .
|
|
||||||
"jhdxr: b\r\n";
|
|
||||||
|
|
||||||
expect(Http::encode('xiami', $tcpConnection))
|
ob_start();
|
||||||
->toBe("HTTP/1.1 200 OK\r\n" .
|
$this->handler->onClose($connection);
|
||||||
"Server: workerman\r\n" .
|
$output = ob_get_clean();
|
||||||
"{$extHeader}Connection: keep-alive\r\n" .
|
|
||||||
"Content-Type: text/html;charset=utf-8\r\n" .
|
|
||||||
"Content-Length: 5\r\n\r\nxiami");
|
|
||||||
});
|
|
||||||
|
|
||||||
it('tests ::encode for ' . Response::class, function () {
|
$this->assertStringContainsString('Connection closed', $output);
|
||||||
/** @var TcpConnection $tcpConnection */
|
}
|
||||||
$tcpConnection = Mockery::mock(TcpConnection::class);
|
}
|
||||||
$tcpConnection->headers = [
|
|
||||||
'foo' => 'bar',
|
|
||||||
'jhdxr' => ['a', 'b'],
|
|
||||||
];
|
|
||||||
$extHeader = "foo: bar\r\n" .
|
|
||||||
"jhdxr: a\r\n" .
|
|
||||||
"jhdxr: b\r\n";
|
|
||||||
|
|
||||||
$response = new Response(body: 'xiami');
|
|
||||||
|
|
||||||
expect(Http::encode($response, $tcpConnection))
|
|
||||||
->toBe("HTTP/1.1 200 OK\r\n" .
|
|
||||||
"Server: workerman\r\n" .
|
|
||||||
"{$extHeader}Connection: keep-alive\r\n" .
|
|
||||||
"Content-Type: text/html;charset=utf-8\r\n" .
|
|
||||||
"Content-Length: 5\r\n\r\nxiami");
|
|
||||||
});
|
|
||||||
|
|
||||||
it('tests ::decode', function () {
|
|
||||||
/** @var TcpConnection $tcpConnection */
|
|
||||||
$tcpConnection = Mockery::mock(TcpConnection::class);
|
|
||||||
|
|
||||||
//example request from ChatGPT :)
|
|
||||||
$buffer = "POST /path/to/resource HTTP/1.1\r\n" .
|
|
||||||
"Host: example.com\r\n" .
|
|
||||||
"Content-Type: application/json\r\n" .
|
|
||||||
"Content-Length: 27\r\n" .
|
|
||||||
"\r\n" .
|
|
||||||
'{"key": "value", "foo": "bar"}';
|
|
||||||
|
|
||||||
$value = expect(Http::decode($buffer, $tcpConnection))
|
|
||||||
->toBeInstanceOf(Request::class)
|
|
||||||
->value;
|
|
||||||
|
|
||||||
//test cache
|
|
||||||
expect($value == Http::decode($buffer, $tcpConnection))
|
|
||||||
->toBeTrue();
|
|
||||||
});
|
|
Loading…
x
Reference in New Issue
Block a user