From f33f9c9c0fd654963191a5c67775de8f6d1bb011 Mon Sep 17 00:00:00 2001 From: Joe Dixon Date: Mon, 27 Nov 2023 12:09:54 +0000 Subject: [PATCH] implement spec tests --- .github/workflows/spec-tests | 52 +++++++++++++++++++++++++++++++++ client-spec.json | 11 +++++++ echo.php | 41 ++++++++++++++++++++++++++ src/WebSockets/WsConnection.php | 16 ++++++---- 4 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/spec-tests create mode 100644 client-spec.json create mode 100644 echo.php diff --git a/.github/workflows/spec-tests b/.github/workflows/spec-tests new file mode 100644 index 00000000..e55e72a1 --- /dev/null +++ b/.github/workflows/spec-tests @@ -0,0 +1,52 @@ +name: Autobahn WebSocket Spec Tests + +on: [push] + +jobs: + test: + runs-on: ubuntu-latest + + strategy: + fail-fast: true + matrix: + php: [8.2, 8.3] + laravel: [10] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker + uses: actions/setup-docker@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: dom, curl, libxml, mbstring, zip + ini-values: error_reporting=E_ALL + tools: composer:v2 + coverage: none + + - name: Install dependencies + run: | + composer require "illuminate/contracts=^${{ matrix.laravel }}" --no-update + composer update --prefer-dist --no-interaction --no-progress + + - name: Pull Autobahn Docker image + run: docker pull crossbario/autobahn-testsuite + + - name: Start WebSocket server + run: php echo.php & + + - name: Run WebSocket specification tests + run: | + docker run -it --rm \ + -v $PWD:/mnt/autobahn \ + -v $PWD/reports:/mnt/autobahn/reports \ + crossbario/autobahn-testsuite \ + /usr/local/bin/docker-entrypoint.sh \ + wstest -m fuzzingclient -s /mnt/autobahn/client-spec.json + + - name: Set workflow status based on Autobahn exit status + run: exit $? diff --git a/client-spec.json b/client-spec.json new file mode 100644 index 00000000..7060a60b --- /dev/null +++ b/client-spec.json @@ -0,0 +1,11 @@ +{ + "options": { "failByDrop": false }, + "outdir": "/mnt/autobahn/reports", + "servers": [{ "agent": "Reverb", "url": "ws://host.docker.internal:8080", "options": { "version": 18 } }], + "cases": ["*"], + "exclude-cases": [ + "12.*", + "13.*" + ], + "exclude-agent-cases": {} + } \ No newline at end of file diff --git a/echo.php b/echo.php new file mode 100644 index 00000000..06b9cedf --- /dev/null +++ b/echo.php @@ -0,0 +1,41 @@ +start(); + +function routes() +{ + $routes = new RouteCollection; + $routes->add( + 'sockets', + Route::get('/', function (RequestInterface $request, WsConnection $connection) { + $connection->onMessage(function ($message) use ($connection) { + $connection->send($message); + }); + $connection->openBuffer(); + }) + ); + + return $routes; +} \ No newline at end of file diff --git a/src/WebSockets/WsConnection.php b/src/WebSockets/WsConnection.php index 28c5da39..20c0d189 100644 --- a/src/WebSockets/WsConnection.php +++ b/src/WebSockets/WsConnection.php @@ -5,6 +5,7 @@ use Evenement\EventEmitter; use Laravel\Reverb\Http\Connection; use Ratchet\RFC6455\Messaging\CloseFrameChecker; +use Ratchet\RFC6455\Messaging\DataInterface; use Ratchet\RFC6455\Messaging\Frame; use Ratchet\RFC6455\Messaging\FrameInterface; use Ratchet\RFC6455\Messaging\MessageBuffer; @@ -56,10 +57,12 @@ public function openBuffer(): void /** * Send a message to the connection. */ - public function send(string $message): void + public function send(mixed $message): void { $this->connection->send( - (new Frame($message))->getContents() + $message instanceof DataInterface ? + $message->getContents() : + (new Frame($message))->getContents() ); } @@ -69,8 +72,9 @@ public function send(string $message): void public function control(FrameInterface $message): void { match ($message->getOpcode()) { - Frame::OP_PING => $this->send(new Frame('pong', opcode: Frame::OP_PONG)), - Frame::OP_CLOSE => $this->close(), + Frame::OP_PING => $this->send(new Frame($message->getPayload(), opcode: Frame::OP_PONG)), + Frame::OP_PONG => fn () => null, + Frame::OP_CLOSE => $this->close($message), }; } @@ -93,8 +97,10 @@ public function onClose(callable $callback): void /** * Close the connection. */ - public function close(): void + public function close(FrameInterface $frame): void { + $this->send($frame); + $this->connection->close(); }