Compare commits

...

3 Commits

Author SHA1 Message Date
4533291324 更新 tests/CalculatorTest.php
Some checks failed
Run Unit Tests / test (pull_request) Failing after 12s
2025-06-03 14:47:09 +08:00
db32f06578 更新 src/start.php 2025-06-03 14:46:27 +08:00
56d77aafcb 添加 src/MyWebSocketHandler.php 2025-06-03 14:45:54 +08:00
3 changed files with 71 additions and 115 deletions

View 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";
}
}

View File

@ -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();
}

View File

@ -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();
});