diff --git a/.travis.yml b/.travis.yml
index 3a474d9..37a4fce 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,18 +1,14 @@
language: php
-dist: trusty
php:
- 7.4
- 7.3
- 7.2
- 7.1
- - 7.0
- - 5.6
- - 5.5
- - 5.4
before_script:
- make install build
script:
- - make coverage cs-check
+ - make coverage
+ - make cs-check
diff --git a/Makefile b/Makefile
index ef50184..cf69f90 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ cs-check: vendor/bin/phpunit
coverage: vendor/bin/phpunit build
./vendor/bin/phpunit --coverage-clover build/logs/clover.xml
- ./vendor/bin/coveralls -v
+ ./vendor/bin/php-coveralls -v
composer.phar:
curl -s http://getcomposer.org/installer | php
diff --git a/README.md b/README.md
index 84973e2..476736d 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,8 @@ Preferred way to install is with [Composer](https://getcomposer.org/).
composer require textalk/websocket
```
-Currently support PHP versions `^5.4` and `^7.0`.
+Current version support PHP versions `^7.1`.
+For PHP `^5.4` and `^7.0` support use version `1.3`.
## Client
@@ -40,6 +41,7 @@ WebSocket\Client {
public setTimeout(int $seconds) : void
public setFragmentSize(int $fragment_size) : self
public getFragmentSize() : int
+ public setLogger(Psr\Log\LoggerInterface $logger = null) : void
}
```
@@ -82,6 +84,7 @@ The `$options` parameter in constructor accepts an associative array of options.
* `fragment_size` - Maximum payload size. Default 4096 chars.
* `context` - A stream context created using [stream_context_create](https://www.php.net/manual/en/function.stream-context-create).
* `headers` - Additional headers as associative array name => content.
+* `logger` - A [PSR-3](https://www.php-fig.org/psr/psr-3/) compatible logger.
* `persistent` - Connection is re-used between requests until time out is reached. Default false.
```php
@@ -131,6 +134,7 @@ WebSocket\Server {
public setTimeout(int $seconds) : void
public setFragmentSize(int $fragment_size) : self
public getFragmentSize() : int
+ public setLogger(Psr\Log\LoggerInterface $logger = null) : void
}
```
@@ -173,6 +177,7 @@ The `$options` parameter in constructor accepts an associative array of options.
* `timeout` - Time out in seconds. Default 5 seconds.
* `port` - The server port to listen to. Default 8000.
* `fragment_size` - Maximum payload size. Default 4096 chars.
+* `logger` - A [PSR-3](https://www.php-fig.org/psr/psr-3/) compatible logger.
```php
$server = new WebSocket\Server([
@@ -191,6 +196,11 @@ $server = new WebSocket\Server([
## Development and contribution
+Requirements on pull requests;
+* All tests **MUST** pass.
+* Code coverage **MUST** remain on 100%.
+* Code **MUST** adhere to PSR-1 and PSR-12 code standards.
+
Install or update dependencies using [Composer](https://getcomposer.org/).
```
# Install dependencies
@@ -233,11 +243,19 @@ See [Copying](COPYING).
Fredrik Liljegren, Armen Baghumian Sankbarani, Ruslan Bekenev,
Joshua Thijssen, Simon Lipp, Quentin Bellus, Patrick McCarren, swmcdonnell,
-Ignas Bernotas, Mark Herhold, Andreas Palm, Sören Jensen, pmaasz, Alexey Stavrov.
+Ignas Bernotas, Mark Herhold, Andreas Palm, Sören Jensen, pmaasz, Alexey Stavrov,
+Michael Slezak.
## Changelog
+1.4.0
+
+ * Dropped support of old PHP versions (@sirn-se)
+ * Added PSR-3 Logging support (@sirn-se)
+ * Persistent connection option (@slezakattack)
+ * TimeoutException on connection time out (@slezakattack)
+
1.3.1
* Allow control messages without payload (@Logioniz)
diff --git a/codestandard.xml b/codestandard.xml
index a354b81..bb1cd26 100644
--- a/codestandard.xml
+++ b/codestandard.xml
@@ -6,7 +6,5 @@
-
-
-
+
\ No newline at end of file
diff --git a/composer.json b/composer.json
index 582fba5..0373d7b 100644
--- a/composer.json
+++ b/composer.json
@@ -5,8 +5,7 @@
"type": "library",
"authors": [
{
- "name": "Fredrik Liljegren",
- "email": "fredrik.liljegren@textalk.se"
+ "name": "Fredrik Liljegren"
},
{
"name": "Sören Jensen",
@@ -24,11 +23,12 @@
}
},
"require": {
- "php": "^5.4|^7.0"
+ "php": "^7.1",
+ "psr/log": "^1.0"
},
"require-dev": {
- "phpunit/phpunit": "^4.1",
- "php-coveralls/php-coveralls": "^0.7",
+ "phpunit/phpunit": "^7.0|^8.0|^9.0",
+ "php-coveralls/php-coveralls": "^2.0",
"squizlabs/php_codesniffer": "^3.5"
}
}
diff --git a/lib/Base.php b/lib/Base.php
index 97a1674..4665622 100644
--- a/lib/Base.php
+++ b/lib/Base.php
@@ -9,13 +9,18 @@
namespace WebSocket;
-class Base
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
+
+class Base implements LoggerAwareInterface
{
protected $socket;
protected $options = [];
protected $is_closing = false;
protected $last_opcode = null;
protected $close_status = null;
+ protected $logger;
protected static $opcodes = array(
'continuation' => 0,
@@ -61,6 +66,11 @@ public function getFragmentSize()
return $this->options['fragment_size'];
}
+ public function setLogger(LoggerInterface $logger = null)
+ {
+ $this->logger = $logger ?: new NullLogger();
+ }
+
public function send($payload, $opcode = 'text', $masked = true)
{
if (!$this->isConnected()) {
@@ -68,20 +78,25 @@ public function send($payload, $opcode = 'text', $masked = true)
}
if (!in_array($opcode, array_keys(self::$opcodes))) {
- throw new BadOpcodeException("Bad opcode '$opcode'. Try 'text' or 'binary'.");
+ $warning = "Bad opcode '{$opcode}'. Try 'text' or 'binary'.";
+ $this->logger->warning($warning);
+ throw new BadOpcodeException($warning);
}
$payload_chunks = str_split($payload, $this->options['fragment_size']);
+ $frame_opcode = $opcode;
for ($index = 0; $index < count($payload_chunks); ++$index) {
$chunk = $payload_chunks[$index];
$final = $index == count($payload_chunks) - 1;
- $this->sendFragment($final, $chunk, $opcode, $masked);
+ $this->sendFragment($final, $chunk, $frame_opcode, $masked);
// all fragments after the first will be marked a continuation
- $opcode = 'continuation';
+ $frame_opcode = 'continuation';
}
+
+ $this->logger->info("Sent '{$opcode}' message");
}
protected function sendFragment($final, $payload, $opcode, $masked)
@@ -150,6 +165,7 @@ public function receive()
$payload .= $response[0];
} while (!$response[1]);
+ $this->logger->info("Received '{$this->last_opcode}' message");
return $payload;
}
@@ -170,10 +186,9 @@ protected function receiveFragment()
$opcode_int = ord($data[0]) & 31; // Bits 4-7
$opcode_ints = array_flip(self::$opcodes);
if (!array_key_exists($opcode_int, $opcode_ints)) {
- throw new ConnectionException(
- "Bad opcode in websocket frame: $opcode_int",
- ConnectionException::BAD_OPCODE
- );
+ $warning = "Bad opcode in websocket frame: {$opcode_int}";
+ $this->logger->warning($warning);
+ throw new ConnectionException($warning, ConnectionException::BAD_OPCODE);
}
$opcode = $opcode_ints[$opcode_int];
@@ -219,6 +234,7 @@ protected function receiveFragment()
// if we received a ping, send a pong
if ($opcode === 'ping') {
+ $this->logger->debug("Received 'ping', sending 'pong'.");
$this->send($payload, 'pong', true);
}
@@ -234,6 +250,8 @@ protected function receiveFragment()
$payload = substr($payload, 2);
}
+ $this->logger->debug("Received 'close', status: {$this->close_status}.");
+
if ($this->is_closing) {
$this->is_closing = false; // A close response, all done.
} else {
@@ -267,6 +285,7 @@ public function close($status = 1000, $message = 'ttfn')
$status_str .= chr(bindec($binstr));
}
$this->send($status_str . $message, 'close', true);
+ $this->logger->debug("Closing with status: {$status_str}.");
$this->is_closing = true;
$this->receive(); // Receiving a close frame will close the socket now.
@@ -274,18 +293,18 @@ public function close($status = 1000, $message = 'ttfn')
protected function write($data)
{
+ $length = strlen($data);
$written = fwrite($this->socket, $data);
if ($written === false) {
- $length = strlen($data);
fclose($this->socket);
- $this->throwException("Failed to write $length bytes.");
+ $this->throwException("Failed to write {$length} bytes.");
}
if ($written < strlen($data)) {
- $length = strlen($data);
fclose($this->socket);
- $this->throwException("Could only write $written out of $length bytes.");
+ $this->throwException("Could only write {$written} out of {$length} bytes.");
}
+ $this->logger->debug("Wrote {$written} of {$length} bytes.");
}
protected function read($length)
@@ -295,7 +314,7 @@ protected function read($length)
$buffer = fread($this->socket, $length - strlen($data));
if ($buffer === false) {
$read = strlen($data);
- $this->throwException("Broken frame, read $read of stated $length bytes.");
+ $this->throwException("Broken frame, read {$read} of stated {$length} bytes.");
}
if ($buffer === '') {
$this->throwException("Empty read; connection dead?");
@@ -311,12 +330,14 @@ protected function throwException($message, $code = 0)
$json_meta = json_encode($meta);
if (!empty($meta['timed_out'])) {
$code = ConnectionException::TIMED_OUT;
- throw new TimeoutException("$message Stream state: $json_meta", $code);
+ $this->logger->warning("{$message}", (array)$meta);
+ throw new TimeoutException("{$message} Stream state: {$json_meta}", $code);
}
if (!empty($meta['eof'])) {
$code = ConnectionException::EOF;
}
- throw new ConnectionException("$message Stream state: $json_meta", $code);
+ $this->logger->error("{$message}", (array)$meta);
+ throw new ConnectionException("{$message} Stream state: {$json_meta}", $code);
}
/**
diff --git a/lib/Client.php b/lib/Client.php
index 1375af7..5dec6bb 100644
--- a/lib/Client.php
+++ b/lib/Client.php
@@ -18,6 +18,7 @@ class Client extends Base
'fragment_size' => 4096,
'context' => null,
'headers' => null,
+ 'logger' => null,
'origin' => null, // @deprecated
];
@@ -36,6 +37,7 @@ public function __construct($uri, $options = array())
{
$this->options = array_merge(self::$default_options, $options);
$this->socket_uri = $uri;
+ $this->setLogger($this->options['logger']);
}
public function __destruct()
@@ -53,9 +55,9 @@ protected function connect()
{
$url_parts = parse_url($this->socket_uri);
if (empty($url_parts) || empty($url_parts['scheme']) || empty($url_parts['host'])) {
- throw new BadUriException(
- "Invalid url '$this->socket_uri' provided."
- );
+ $error = "Invalid url '{$this->socket_uri}' provided.";
+ $this->logger->error($error);
+ throw new BadUriException($error);
}
$scheme = $url_parts['scheme'];
$host = $url_parts['host'];
@@ -75,9 +77,9 @@ protected function connect()
}
if (!in_array($scheme, array('ws', 'wss'))) {
- throw new BadUriException(
- "Url should have scheme ws or wss, not '$scheme' from URI '$this->socket_uri' ."
- );
+ $error = "Url should have scheme ws or wss, not '{$scheme}' from URI '{$this->socket_uri}'.";
+ $this->logger->error($error);
+ throw new BadUriException($error);
}
$host_uri = ($scheme === 'wss' ? 'ssl' : 'tcp') . '://' . $host;
@@ -88,9 +90,9 @@ protected function connect()
if (@get_resource_type($this->options['context']) === 'stream-context') {
$context = $this->options['context'];
} else {
- throw new \InvalidArgumentException(
- "Stream context in \$options['context'] isn't a valid context"
- );
+ $error = "Stream context in \$options['context'] isn't a valid context.";
+ $this->logger->error($error);
+ throw new \InvalidArgumentException($error);
}
} else {
$context = stream_context_create();
@@ -110,9 +112,9 @@ protected function connect()
);
if (!$this->isConnected()) {
- throw new ConnectionException(
- "Could not open socket to \"$host:$port\": $errstr ($errno)."
- );
+ $error = "Could not open socket to \"{$host}:{$port}\": {$errstr} ({$errno}).";
+ $this->logger->error($error);
+ throw new ConnectionException($error);
}
// Set timeout on the stream as well.
@@ -165,13 +167,13 @@ function ($key, $value) {
/// @todo Handle version switching
+ $address = "{$scheme}://{$host}{$path_with_query}";
+
// Validate response.
if (!preg_match('#Sec-WebSocket-Accept:\s(.*)$#mUi', $response, $matches)) {
- $address = $scheme . '://' . $host . $path_with_query;
- throw new ConnectionException(
- "Connection to '{$address}' failed: Server sent invalid upgrade response:\n"
- . $response
- );
+ $error = "Connection to '{$address}' failed: Server sent invalid upgrade response: {$response}";
+ $this->logger->error($error);
+ throw new ConnectionException($error);
}
$keyAccept = trim($matches[1]);
@@ -179,8 +181,12 @@ function ($key, $value) {
= base64_encode(pack('H*', sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
if ($keyAccept !== $expectedResonse) {
- throw new ConnectionException('Server sent bad upgrade response.');
+ $error = 'Server sent bad upgrade response.';
+ $this->logger->error($error);
+ throw new ConnectionException($error);
}
+
+ $this->logger->info("Client connected to to {$address}");
}
/**
diff --git a/lib/ConnectionException.php b/lib/ConnectionException.php
index e8c2d03..b20932f 100644
--- a/lib/ConnectionException.php
+++ b/lib/ConnectionException.php
@@ -5,7 +5,7 @@
class ConnectionException extends Exception
{
// Native codes in interval 0-106
- const TIMED_OUT = 1024;
- const EOF = 1025;
- const BAD_OPCODE = 1026;
+ public const TIMED_OUT = 1024;
+ public const EOF = 1025;
+ public const BAD_OPCODE = 1026;
}
diff --git a/lib/Server.php b/lib/Server.php
index 8e0de40..6b23d6d 100644
--- a/lib/Server.php
+++ b/lib/Server.php
@@ -16,6 +16,7 @@ class Server extends Base
'timeout' => null,
'fragment_size' => 4096,
'port' => 8000,
+ 'logger' => null,
];
protected $addr;
@@ -35,14 +36,19 @@ public function __construct(array $options = array())
{
$this->options = array_merge(self::$default_options, $options);
$this->port = $this->options['port'];
+ $this->setLogger($this->options['logger']);
do {
$this->listening = @stream_socket_server("tcp://0.0.0.0:$this->port", $errno, $errstr);
} while ($this->listening === false && $this->port++ < 10000);
if (!$this->listening) {
- throw new ConnectionException("Could not open listening socket: $errstr", $errno);
+ $error = "Could not open listening socket: {$errstr} ({$errno})";
+ $this->logger->error($error);
+ throw new ConnectionException($error, $errno);
}
+
+ $this->logger->info("Server listening to port {$this->port}");
}
public function __destruct()
@@ -90,17 +96,22 @@ protected function connect()
if (empty($this->options['timeout'])) {
$this->socket = @stream_socket_accept($this->listening);
if (!$this->socket) {
- throw new ConnectionException('Server failed to connect.');
+ $error = 'Server failed to connect.';
+ $this->logger->error($error);
+ throw new ConnectionException($error);
}
} else {
$this->socket = @stream_socket_accept($this->listening, $this->options['timeout']);
if (!$this->socket) {
- throw new ConnectionException('Server failed to connect.');
+ $error = 'Server failed to connect.';
+ $this->logger->error($error);
+ throw new ConnectionException($error);
}
stream_set_timeout($this->socket, $this->options['timeout']);
}
$this->performHandshake();
+ $this->logger->info("Server connected to port {$this->port}");
}
protected function performHandshake()
@@ -113,7 +124,9 @@ protected function performHandshake()
} while (!feof($this->socket) && $metadata['unread_bytes'] > 0);
if (!preg_match('/GET (.*) HTTP\//mUi', $request, $matches)) {
- throw new ConnectionException("No GET in request:\n" . $request);
+ $error = "No GET in request: {$request}";
+ $this->logger->error($error);
+ throw new ConnectionException($error);
}
$get_uri = trim($matches[1]);
$uri_parts = parse_url($get_uri);
@@ -123,7 +136,9 @@ protected function performHandshake()
/// @todo Get query and fragment as well.
if (!preg_match('#Sec-WebSocket-Key:\s(.*)$#mUi', $request, $matches)) {
- throw new ConnectionException("Client had no Key in upgrade request:\n" . $request);
+ $error = "Client had no Key in upgrade request: {$request}";
+ $this->logger->error($error);
+ throw new ConnectionException($error);
}
$key = trim($matches[1]);
diff --git a/tests/ClientTest.php b/tests/ClientTest.php
index 076fb33..16dee9c 100644
--- a/tests/ClientTest.php
+++ b/tests/ClientTest.php
@@ -5,17 +5,21 @@
* Note that this test is performed by mocking socket/stream calls.
*/
+declare(strict_types=1);
+
namespace WebSocket;
-class ClientTest extends \PHPUnit_Framework_TestCase
+use PHPUnit\Framework\TestCase;
+
+class ClientTest extends TestCase
{
- public function setUp()
+ public function setUp(): void
{
error_reporting(-1);
}
- public function testClientMasked()
+ public function testClientMasked(): void
{
MockSocket::initialize('client.connect', $this);
$client = new Client('ws://localhost:8000/my/mock/path');
@@ -46,7 +50,7 @@ public function testClientMasked()
$this->assertTrue(MockSocket::isEmpty());
}
- public function testDestruct()
+ public function testDestruct(): void
{
MockSocket::initialize('client.connect', $this);
$client = new Client('ws://localhost:8000/my/mock/path');
@@ -56,7 +60,7 @@ public function testDestruct()
MockSocket::initialize('client.destruct', $this);
}
- public function testClienExtendedUrl()
+ public function testClienExtendedUrl(): void
{
MockSocket::initialize('client.connect-extended', $this);
$client = new Client('ws://localhost:8000/my/mock/path?my_query=yes#my_fragment');
@@ -64,7 +68,7 @@ public function testClienExtendedUrl()
$this->assertTrue(MockSocket::isEmpty());
}
- public function testClientWithTimeout()
+ public function testClientWithTimeout(): void
{
MockSocket::initialize('client.connect-timeout', $this);
$client = new Client('ws://localhost:8000/my/mock/path', ['timeout' => 300]);
@@ -72,7 +76,7 @@ public function testClientWithTimeout()
$this->assertTrue(MockSocket::isEmpty());
}
- public function testClientWithContext()
+ public function testClientWithContext(): void
{
MockSocket::initialize('client.connect-context', $this);
$client = new Client('ws://localhost:8000/my/mock/path', ['context' => '@mock-stream-context']);
@@ -80,7 +84,7 @@ public function testClientWithContext()
$this->assertTrue(MockSocket::isEmpty());
}
- public function testClientAuthed()
+ public function testClientAuthed(): void
{
MockSocket::initialize('client.connect-authed', $this);
$client = new Client('wss://usename:password@localhost:8000/my/mock/path');
@@ -88,7 +92,7 @@ public function testClientAuthed()
$this->assertTrue(MockSocket::isEmpty());
}
- public function testWithHeaders()
+ public function testWithHeaders(): void
{
MockSocket::initialize('client.connect-headers', $this);
$client = new Client('ws://localhost:8000/my/mock/path', [
@@ -99,7 +103,7 @@ public function testWithHeaders()
$this->assertTrue(MockSocket::isEmpty());
}
- public function testPayload128()
+ public function testPayload128(): void
{
MockSocket::initialize('client.connect', $this);
$client = new Client('ws://localhost:8000/my/mock/path');
@@ -115,7 +119,7 @@ public function testPayload128()
$this->assertTrue(MockSocket::isEmpty());
}
- public function testPayload65536()
+ public function testPayload65536(): void
{
MockSocket::initialize('client.connect', $this);
$client = new Client('ws://localhost:8000/my/mock/path');
@@ -133,7 +137,7 @@ public function testPayload65536()
$this->assertEquals(65540, $client->getFragmentSize());
}
- public function testMultiFragment()
+ public function testMultiFragment(): void
{
MockSocket::initialize('client.connect', $this);
$client = new Client('ws://localhost:8000/my/mock/path');
@@ -149,7 +153,7 @@ public function testMultiFragment()
$this->assertEquals(8, $client->getFragmentSize());
}
- public function testPingPong()
+ public function testPingPong(): void
{
MockSocket::initialize('client.connect', $this);
$client = new Client('ws://localhost:8000/my/mock/path');
@@ -173,7 +177,7 @@ public function testPingPong()
$this->assertEquals('ping', $client->getLastOpcode());
}
- public function testRemoteClose()
+ public function testRemoteClose(): void
{
MockSocket::initialize('client.connect', $this);
$client = new Client('ws://localhost:8000/my/mock/path');
@@ -191,7 +195,7 @@ public function testRemoteClose()
$this->assertTrue(MockSocket::isEmpty());
}
- public function testSetTimeout()
+ public function testSetTimeout(): void
{
MockSocket::initialize('client.connect', $this);
$client = new Client('ws://localhost:8000/my/mock/path');
@@ -204,7 +208,7 @@ public function testSetTimeout()
$this->assertTrue(MockSocket::isEmpty());
}
- public function testReconnect()
+ public function testReconnect(): void
{
MockSocket::initialize('client.connect', $this);
$client = new Client('ws://localhost:8000/my/mock/path');
@@ -226,7 +230,7 @@ public function testReconnect()
$this->assertTrue(MockSocket::isEmpty());
}
- public function testPersistentConnection()
+ public function testPersistentConnection(): void
{
MockSocket::initialize('client.connect-persistent', $this);
$client = new Client('ws://localhost:8000/my/mock/path', ['persistent' => true]);
@@ -234,156 +238,132 @@ public function testPersistentConnection()
$this->assertTrue(MockSocket::isEmpty());
}
- /**
- * @expectedException WebSocket\BadUriException
- * @expectedExceptionMessage Url should have scheme ws or wss
- */
- public function testBadScheme()
+ public function testBadScheme(): void
{
MockSocket::initialize('client.connect', $this);
$client = new Client('bad://localhost:8000/my/mock/path');
+ $this->expectException('WebSocket\BadUriException');
+ $this->expectExceptionMessage('Url should have scheme ws or wss');
$client->send('Connect');
}
- /**
- * @expectedException WebSocket\BadUriException
- * @expectedExceptionMessage Invalid url 'this is not an url' provided.
- */
- public function testBadUrl()
+ public function testBadUrl(): void
{
MockSocket::initialize('client.connect', $this);
$client = new Client('this is not an url');
+ $this->expectException('WebSocket\BadUriException');
+ $this->expectExceptionMessage('Invalid url \'this is not an url\' provided.');
$client->send('Connect');
}
- /**
- * @expectedException InvalidArgumentException
- * @expectedExceptionMessage Stream context in $options['context'] isn't a valid context
- */
- public function testBadStreamContext()
+ public function testBadStreamContext(): void
{
MockSocket::initialize('client.connect-bad-context', $this);
$client = new Client('ws://localhost:8000/my/mock/path', ['context' => 'BAD']);
+ $this->expectException('InvalidArgumentException');
+ $this->expectExceptionMessage('Stream context in $options[\'context\'] isn\'t a valid context');
$client->send('Connect');
}
- /**
- * @expectedException WebSocket\ConnectionException
- * @expectedExceptionCode 0
- * @expectedExceptionMessage Could not open socket to "localhost:8000"
- */
- public function testFailedConnection()
+ public function testFailedConnection(): void
{
MockSocket::initialize('client.connect-failed', $this);
$client = new Client('ws://localhost:8000/my/mock/path');
+ $this->expectException('WebSocket\ConnectionException');
+ $this->expectExceptionCode(0);
+ $this->expectExceptionMessage('Could not open socket to "localhost:8000"');
$client->send('Connect');
}
- /**
- * @expectedException WebSocket\ConnectionException
- * @expectedExceptionCode 0
- * @expectedExceptionMessage Connection to 'ws://localhost/my/mock/path' failed
- */
- public function testInvalidUpgrade()
+ public function testInvalidUpgrade(): void
{
MockSocket::initialize('client.connect-invalid-upgrade', $this);
$client = new Client('ws://localhost:8000/my/mock/path');
+ $this->expectException('WebSocket\ConnectionException');
+ $this->expectExceptionCode(0);
+ $this->expectExceptionMessage('Connection to \'ws://localhost/my/mock/path\' failed');
$client->send('Connect');
}
- /**
- * @expectedException WebSocket\ConnectionException
- * @expectedExceptionCode 0
- * @expectedExceptionMessage Server sent bad upgrade response
- */
- public function testInvalidKey()
+ public function testInvalidKey(): void
{
MockSocket::initialize('client.connect-invalid-key', $this);
$client = new Client('ws://localhost:8000/my/mock/path');
+ $this->expectException('WebSocket\ConnectionException');
+ $this->expectExceptionCode(0);
+ $this->expectExceptionMessage('Server sent bad upgrade response');
$client->send('Connect');
}
- /**
- * @expectedException WebSocket\BadOpcodeException
- * @expectedExceptionMessage Bad opcode 'bad'. Try 'text' or 'binary'.
- */
- public function testSendBadOpcode()
+ public function testSendBadOpcode(): void
{
MockSocket::initialize('client.connect', $this);
$client = new Client('ws://localhost:8000/my/mock/path');
$client->send('Connect');
MockSocket::initialize('send-bad-opcode', $this);
+ $this->expectException('WebSocket\BadOpcodeException');
+ $this->expectExceptionMessage('Bad opcode \'bad\'. Try \'text\' or \'binary\'.');
$client->send('Bad Opcode', 'bad');
}
- /**
- * @expectedException WebSocket\ConnectionException
- * @expectedExceptionCode 1026
- * @expectedExceptionMessage Bad opcode in websocket frame: 12
- */
- public function testRecieveBadOpcode()
+ public function testRecieveBadOpcode(): void
{
MockSocket::initialize('client.connect', $this);
$client = new Client('ws://localhost:8000/my/mock/path');
$client->send('Connect');
MockSocket::initialize('receive-bad-opcode', $this);
+ $this->expectException('WebSocket\ConnectionException');
+ $this->expectExceptionCode(1026);
+ $this->expectExceptionMessage('Bad opcode in websocket frame: 12');
$message = $client->receive();
}
- /**
- * @expectedException WebSocket\ConnectionException
- * @expectedExceptionCode 1025
- * @expectedExceptionMessage Could only write 18 out of 22 bytes.
- */
- public function testBrokenWrite()
+ public function testBrokenWrite(): void
{
MockSocket::initialize('client.connect', $this);
$client = new Client('ws://localhost:8000/my/mock/path');
$client->send('Connect');
MockSocket::initialize('send-broken-write', $this);
+ $this->expectException('WebSocket\ConnectionException');
+ $this->expectExceptionCode(1025);
+ $this->expectExceptionMessage('Could only write 18 out of 22 bytes.');
$client->send('Failing to write');
}
- /**
- * @expectedException WebSocket\TimeoutException
- * @expectedExceptionCode 1024
- * @expectedExceptionMessage Failed to write 22 bytes.
- */
- public function testFailedWrite()
+ public function testFailedWrite(): void
{
MockSocket::initialize('client.connect', $this);
$client = new Client('ws://localhost:8000/my/mock/path');
$client->send('Connect');
MockSocket::initialize('send-failed-write', $this);
+ $this->expectException('WebSocket\TimeoutException');
+ $this->expectExceptionCode(1024);
+ $this->expectExceptionMessage('Failed to write 22 bytes.');
$client->send('Failing to write');
}
- /**
- * @expectedException WebSocket\ConnectionException
- * @expectedExceptionCode 1025
- * @expectedExceptionMessage Broken frame, read 0 of stated 2 bytes.
- */
- public function testBrokenRead()
+ public function testBrokenRead(): void
{
MockSocket::initialize('client.connect', $this);
$client = new Client('ws://localhost:8000/my/mock/path');
$client->send('Connect');
MockSocket::initialize('receive-broken-read', $this);
+ $this->expectException('WebSocket\ConnectionException');
+ $this->expectExceptionCode(1025);
+ $this->expectExceptionMessage('Broken frame, read 0 of stated 2 bytes.');
$client->receive();
}
- /**
- * @expectedException WebSocket\TimeoutException
- * @expectedExceptionCode 1024
- * @expectedExceptionMessage Empty read; connection dead?
- */
- public function testEmptyRead()
+ public function testEmptyRead(): void
{
MockSocket::initialize('client.connect', $this);
$client = new Client('ws://localhost:8000/my/mock/path');
$client->send('Connect');
MockSocket::initialize('receive-empty-read', $this);
+ $this->expectException('WebSocket\TimeoutException');
+ $this->expectExceptionCode(1024);
+ $this->expectExceptionMessage('Empty read; connection dead?');
$client->receive();
}
}
diff --git a/tests/ServerTest.php b/tests/ServerTest.php
index 6a83649..a69b67a 100644
--- a/tests/ServerTest.php
+++ b/tests/ServerTest.php
@@ -5,17 +5,21 @@
* Note that this test is performed by mocking socket/stream calls.
*/
+declare(strict_types=1);
+
namespace WebSocket;
-class ServerTest extends \PHPUnit_Framework_TestCase
+use PHPUnit\Framework\TestCase;
+
+class ServerTest extends TestCase
{
- public function setUp()
+ public function setUp(): void
{
error_reporting(-1);
}
- public function testServerMasked()
+ public function testServerMasked(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server();
@@ -62,7 +66,7 @@ public function testServerMasked()
$server->close(); // Already closed
}
- public function testDestruct()
+ public function testDestruct(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server();
@@ -72,7 +76,7 @@ public function testDestruct()
$message = $server->receive();
}
- public function testServerWithTimeout()
+ public function testServerWithTimeout(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server(['timeout' => 300]);
@@ -84,7 +88,7 @@ public function testServerWithTimeout()
$this->assertTrue(MockSocket::isEmpty());
}
- public function testPayload128()
+ public function testPayload128(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server();
@@ -105,7 +109,7 @@ public function testPayload128()
$this->assertTrue(MockSocket::isEmpty());
}
- public function testPayload65536()
+ public function testPayload65536(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server();
@@ -127,7 +131,7 @@ public function testPayload65536()
$this->assertTrue(MockSocket::isEmpty());
}
- public function testMultiFragment()
+ public function testMultiFragment(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server();
@@ -147,7 +151,7 @@ public function testMultiFragment()
$this->assertTrue(MockSocket::isEmpty());
}
- public function testPingPong()
+ public function testPingPong(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server();
@@ -177,7 +181,7 @@ public function testPingPong()
$this->assertEquals('ping', $server->getLastOpcode());
}
- public function testRemoteClose()
+ public function testRemoteClose(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server();
@@ -200,7 +204,7 @@ public function testRemoteClose()
$this->assertEquals('close', $server->getLastOpcode());
}
- public function testSetTimeout()
+ public function testSetTimeout(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server();
@@ -218,96 +222,79 @@ public function testSetTimeout()
$this->assertTrue(MockSocket::isEmpty());
}
- /**
- * @expectedException WebSocket\ConnectionException
- * @expectedExceptionCode 0
- * @expectedExceptionMessage Could not open listening socket:
- */
- public function testFailedSocketServer()
+ public function testFailedSocketServer(): void
{
MockSocket::initialize('server.construct-failed-socket-server', $this);
+ $this->expectException('WebSocket\ConnectionException');
+ $this->expectExceptionCode(0);
+ $this->expectExceptionMessage('Could not open listening socket:');
$server = new Server(['port' => 9999]);
}
- /**
- * @expectedException WebSocket\ConnectionException
- * @expectedExceptionCode 0
- * @expectedExceptionMessage Server failed to connect
- */
- public function testFailedConnect()
+ public function testFailedConnect(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server();
MockSocket::initialize('server.accept-failed-connect', $this);
$server->accept();
+ $this->expectException('WebSocket\ConnectionException');
+ $this->expectExceptionCode(0);
+ $this->expectExceptionMessage('Server failed to connect');
$server->send('Connect');
}
- /**
- * @expectedException WebSocket\ConnectionException
- * @expectedExceptionCode 0
- * @expectedExceptionMessage Server failed to connect
- */
- public function testFailedConnectTimeout()
+ public function testFailedConnectTimeout(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server(['timeout' => 300]);
MockSocket::initialize('server.accept-failed-connect', $this);
$server->accept();
+ $this->expectException('WebSocket\ConnectionException');
+ $this->expectExceptionCode(0);
+ $this->expectExceptionMessage('Server failed to connect');
$server->send('Connect');
}
- /**
- * @expectedException WebSocket\ConnectionException
- * @expectedExceptionCode 0
- * @expectedExceptionMessage No GET in request
- */
- public function testFailedHttp()
+ public function testFailedHttp(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server();
MockSocket::initialize('server.accept-failed-http', $this);
$server->accept();
+ $this->expectException('WebSocket\ConnectionException');
+ $this->expectExceptionCode(0);
+ $this->expectExceptionMessage('No GET in request');
$server->send('Connect');
}
- /**
- * @expectedException WebSocket\ConnectionException
- * @expectedExceptionCode 0
- * @expectedExceptionMessage Client had no Key in upgrade request
- */
- public function testFailedWsKey()
+ public function testFailedWsKey(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server();
MockSocket::initialize('server.accept-failed-ws-key', $this);
$server->accept();
+ $this->expectException('WebSocket\ConnectionException');
+ $this->expectExceptionCode(0);
+ $this->expectExceptionMessage('Client had no Key in upgrade request');
$server->send('Connect');
}
- /**
- * @expectedException WebSocket\BadOpcodeException
- * @expectedExceptionCode 0
- * @expectedExceptionMessage Bad opcode 'bad'. Try 'text' or 'binary'.
- */
- public function testSendBadOpcode()
+ public function testSendBadOpcode(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server();
MockSocket::initialize('server.accept', $this);
$server->accept();
$server->send('Connect');
+ $this->expectException('WebSocket\BadOpcodeException');
+ $this->expectExceptionCode(0);
+ $this->expectExceptionMessage('Bad opcode \'bad\'. Try \'text\' or \'binary\'.');
$server->send('Bad Opcode', 'bad');
}
- /**
- * @expectedException WebSocket\ConnectionException
- * @expectedExceptionCode 1026
- * @expectedExceptionMessage Bad opcode in websocket frame: 12
- */
- public function testRecieveBadOpcode()
+ public function testRecieveBadOpcode(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server();
@@ -315,15 +302,13 @@ public function testRecieveBadOpcode()
$server->accept();
$server->send('Connect');
MockSocket::initialize('receive-bad-opcode', $this);
+ $this->expectException('WebSocket\ConnectionException');
+ $this->expectExceptionCode(1026);
+ $this->expectExceptionMessage('Bad opcode in websocket frame: 12');
$message = $server->receive();
}
- /**
- * @expectedException WebSocket\ConnectionException
- * @expectedExceptionCode 1025
- * @expectedExceptionMessage Could only write 18 out of 22 bytes.
- */
- public function testBrokenWrite()
+ public function testBrokenWrite(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server();
@@ -331,15 +316,13 @@ public function testBrokenWrite()
$server->accept();
$server->send('Connect');
MockSocket::initialize('send-broken-write', $this);
+ $this->expectException('WebSocket\ConnectionException');
+ $this->expectExceptionCode(1025);
+ $this->expectExceptionMessage('Could only write 18 out of 22 bytes.');
$server->send('Failing to write');
}
- /**
- * @expectedException WebSocket\ConnectionException
- * @expectedExceptionCode 1024
- * @expectedExceptionMessage Failed to write 22 bytes.
- */
- public function testFailedWrite()
+ public function testFailedWrite(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server();
@@ -347,15 +330,13 @@ public function testFailedWrite()
$server->accept();
$server->send('Connect');
MockSocket::initialize('send-failed-write', $this);
+ $this->expectException('WebSocket\TimeoutException');
+ $this->expectExceptionCode(1024);
+ $this->expectExceptionMessage('Failed to write 22 bytes.');
$server->send('Failing to write');
}
- /**
- * @expectedException WebSocket\ConnectionException
- * @expectedExceptionCode 1025
- * @expectedExceptionMessage Broken frame, read 0 of stated 2 bytes.
- */
- public function testBrokenRead()
+ public function testBrokenRead(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server();
@@ -363,15 +344,13 @@ public function testBrokenRead()
$server->accept();
$server->send('Connect');
MockSocket::initialize('receive-broken-read', $this);
+ $this->expectException('WebSocket\ConnectionException');
+ $this->expectExceptionCode(1025);
+ $this->expectExceptionMessage('Broken frame, read 0 of stated 2 bytes.');
$server->receive();
}
- /**
- * @expectedException WebSocket\ConnectionException
- * @expectedExceptionCode 1024
- * @expectedExceptionMessage Empty read; connection dead?
- */
- public function testEmptyRead()
+ public function testEmptyRead(): void
{
MockSocket::initialize('server.construct', $this);
$server = new Server();
@@ -379,6 +358,9 @@ public function testEmptyRead()
$server->accept();
$server->send('Connect');
MockSocket::initialize('receive-empty-read', $this);
+ $this->expectException('WebSocket\TimeoutException');
+ $this->expectExceptionCode(1024);
+ $this->expectExceptionMessage('Empty read; connection dead?');
$server->receive();
}
}