diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..b5758b7 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,24 @@ +language: php + +php: + - 5.4 + - 5.5 + - 5.6 + - 7 + - hhvm + +matrix: + allow_failures: + - php: hhvm + +before_install: + - export PATH=$HOME/.local/bin:$PATH + - pip install autobahntestsuite --user `whoami` + - pip list autobahntestsuite --user `whoami` + +before_script: + - composer install + - sh tests/ab/run_ab_tests.sh + +script: + - phpunit \ No newline at end of file diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..8f2e7d1 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,27 @@ + + + + + + tests + + test/ab + + + + + + + ./src/ + + + \ No newline at end of file diff --git a/tests/AbResultsTest.php b/tests/AbResultsTest.php new file mode 100644 index 0000000..22afcff --- /dev/null +++ b/tests/AbResultsTest.php @@ -0,0 +1,28 @@ +assertFileExists($fileName); + $resultsJson = file_get_contents($fileName); + $results = json_decode($resultsJson); + $agentName = array_keys(get_object_vars($results))[0]; + foreach ($results->$agentName as $name => $result) { + if ($result->behavior === "INFORMATIONAL") { + continue; + } + $this->assertTrue(in_array($result->behavior, ["OK", "NON-STRICT"]), "Autobahn test case " . $name . " in " . $fileName); + } + } + public function testAutobahnClientResults() + { + $this->verifyAutobahnResults(__DIR__ . '/ab/reports/clients/index.json'); + } + public function testAutobahnServerResults() + { + $this->verifyAutobahnResults(__DIR__ . '/ab/reports/servers/index.json'); + } +} \ No newline at end of file diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..92cb3c9 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,8 @@ +_conn = $connectionContext; - $this->maskPayload = $maskPayload; - } - - public function setFrame(\Ratchet\RFC6455\Messaging\Protocol\FrameInterface $frame = null) { - $this->_frame = $frame; - } - - public function getFrame() { - return $this->_frame; - } - - public function setMessage(\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $message = null) { - $this->_message = $message; - } - - public function getMessage() { - return $this->_message; - } - - public function onMessage(\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $msg) { - $frame = new \Ratchet\RFC6455\Messaging\Protocol\Frame($msg->getPayload(), true, $msg[0]->getOpcode()); - if ($this->maskPayload) { - $frame->maskPayload(); - } - $this->_conn->write($frame->getContents()); - } - - public function onPing(\Ratchet\RFC6455\Messaging\Protocol\FrameInterface $frame) { - $pong = new \Ratchet\RFC6455\Messaging\Protocol\Frame($frame->getPayload(), true, \Ratchet\RFC6455\Messaging\Protocol\Frame::OP_PONG); - if ($this->maskPayload) { - $pong->maskPayload(); - } - $this->_conn->write($pong->getContents()); - } - - public function onPong(\Ratchet\RFC6455\Messaging\Protocol\FrameInterface $msg) { - // TODO: Implement onPong() method. - } - - public function onClose($code = 1000) { - $frame = new \Ratchet\RFC6455\Messaging\Protocol\Frame( - pack('n', $code), - true, - \Ratchet\RFC6455\Messaging\Protocol\Frame::OP_CLOSE - ); - if ($this->maskPayload) { - $frame->maskPayload(); - } - - $this->_conn->end($frame->getContents()); - } -} \ No newline at end of file diff --git a/tests/ab/clientRunner.php b/tests/ab/clientRunner.php index 94109f2..8d5c24a 100644 --- a/tests/ab/clientRunner.php +++ b/tests/ab/clientRunner.php @@ -4,34 +4,11 @@ use Ratchet\RFC6455\Messaging\Protocol\Frame; use Ratchet\RFC6455\Messaging\Protocol\Message; require __DIR__ . '/../bootstrap.php'; -require __DIR__ . '/AbConnectionContext.php'; define('AGENT', 'RatchetRFC/0.0.0'); $testServer = "127.0.0.1"; - -class EmConnectionContext extends AbConnectionContext implements \Evenement\EventEmitterInterface, Ratchet\RFC6455\Messaging\Streaming\ContextInterface { - use \Evenement\EventEmitterTrait; - - public function onMessage(\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $msg) { - $this->emit('message', [$msg]); - } - - public function sendMessage(Frame $frame) { - if ($this->maskPayload) { - $frame->maskPayload(); - } - $this->_conn->write($frame->getContents()); - } - - public function close($closeCode = Frame::CLOSE_NORMAL) { - $closeFrame = new Frame(pack('n', $closeCode), true, Frame::OP_CLOSE); - $closeFrame->maskPayload(); - $this->_conn->end($closeFrame->getContents()); - } -} - $loop = React\EventLoop\Factory::create(); $dnsResolverFactory = new React\Dns\Resolver\Factory(); @@ -39,6 +16,32 @@ $dnsResolver = $dnsResolverFactory->createCached('8.8.8.8', $loop); $factory = new \React\SocketClient\Connector($loop, $dnsResolver); +function echoStreamerFactory($conn) +{ + return new \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer( + new \Ratchet\RFC6455\Encoding\Validator, + new \Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker, + function (\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $msg) use ($conn) { + /** @var Frame $frame */ + foreach ($msg as $frame) { + $frame->maskPayload(); + } + $conn->write($msg->getContents()); + }, + function (\Ratchet\RFC6455\Messaging\Protocol\FrameInterface $frame) use ($conn) { + switch ($frame->getOpcode()) { + case Frame::OP_PING: + return $conn->write((new Frame($frame->getPayload(), true, Frame::OP_PONG))->maskPayload()->getContents()); + break; + case Frame::OP_CLOSE: + return $conn->end((new Frame($frame->getPayload(), true, Frame::OP_CLOSE))->maskPayload()->getContents()); + break; + } + }, + false + ); +} + function getTestCases() { global $factory; global $testServer; @@ -52,12 +55,10 @@ function getTestCases() { $rawResponse = ""; $response = null; - $ms = new \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer(new \Ratchet\RFC6455\Encoding\Validator(), true); + /** @var \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer $ms */ + $ms = null; - /** @var EmConnectionContext $context */ - $context = null; - - $stream->on('data', function ($data) use ($stream, &$rawResponse, &$response, $ms, $cn, $deferred, &$context) { + $stream->on('data', function ($data) use ($stream, &$rawResponse, &$response, &$ms, $cn, $deferred, &$context) { if ($response === null) { $rawResponse .= $data; $pos = strpos($rawResponse, "\r\n\r\n"); @@ -70,19 +71,23 @@ function getTestCases() { $stream->end(); $deferred->reject(); } else { - $context = new EmConnectionContext($stream, true); - - $context->on('message', function (Message $msg) use ($stream, $deferred, $context) { - $deferred->resolve($msg->getPayload()); - $context->close(); - }); + $ms = new \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer( + new \Ratchet\RFC6455\Encoding\Validator, + new \Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker, + function (\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $msg) use ($deferred, $stream) { + $deferred->resolve($msg->getPayload()); + $stream->close(); + }, + null, + false + ); } } } // feed the message streamer - if ($response && $context) { - $ms->onData($data, $context); + if ($ms) { + $ms->onData($data); } }); @@ -108,12 +113,9 @@ function runTest($case) $rawResponse = ""; $response = null; - $ms = new \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer(new \Ratchet\RFC6455\Encoding\Validator(), true); + $ms = null; - /** @var AbConnectionContext $context */ - $context = null; - - $stream->on('data', function ($data) use ($stream, &$rawResponse, &$response, $ms, $cn, $deferred, &$context) { + $stream->on('data', function ($data) use ($stream, &$rawResponse, &$response, &$ms, $cn, $deferred, &$context) { if ($response === null) { $rawResponse .= $data; $pos = strpos($rawResponse, "\r\n\r\n"); @@ -126,14 +128,14 @@ function runTest($case) $stream->end(); $deferred->reject(); } else { - $context = new AbConnectionContext($stream, true); + $ms = echoStreamerFactory($stream); } } } // feed the message streamer - if ($response && $context) { - $ms->onData($data, $context); + if ($ms) { + $ms->onData($data); } }); @@ -154,18 +156,17 @@ function createReport() { $deferred = new Deferred(); $factory->create($testServer, 9001)->then(function (\React\Stream\Stream $stream) use ($deferred) { - $cn = new \Ratchet\RFC6455\Handshake\ClientNegotiator('/updateReports?agent=' . AGENT); + $reportPath = "/updateReports?agent=" . AGENT . "&shutdownOnComplete=true"; + $cn = new \Ratchet\RFC6455\Handshake\ClientNegotiator($reportPath); $cnRequest = $cn->getRequest(); $rawResponse = ""; $response = null; - $ms = new \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer(new \Ratchet\RFC6455\Encoding\Validator(), true); + /** @var \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer $ms */ + $ms = null; - /** @var EmConnectionContext $context */ - $context = null; - - $stream->on('data', function ($data) use ($stream, &$rawResponse, &$response, $ms, $cn, $deferred, &$context) { + $stream->on('data', function ($data) use ($stream, &$rawResponse, &$response, &$ms, $cn, $deferred, &$context) { if ($response === null) { $rawResponse .= $data; $pos = strpos($rawResponse, "\r\n\r\n"); @@ -178,19 +179,23 @@ function createReport() { $stream->end(); $deferred->reject(); } else { - $context = new EmConnectionContext($stream, true); - - $context->on('message', function (Message $msg) use ($stream, $deferred, $context) { - $deferred->resolve($msg->getPayload()); - $context->close(); - }); + $ms = new \Ratchet\RFC6455\Messaging\Streaming\MessageStreamer( + new \Ratchet\RFC6455\Encoding\Validator, + new \Ratchet\RFC6455\Messaging\Protocol\CloseFrameChecker, + function (\Ratchet\RFC6455\Messaging\Protocol\MessageInterface $msg) use ($deferred, $stream) { + $deferred->resolve($msg->getPayload()); + $stream->close(); + }, + null, + false + ); } } } // feed the message streamer - if ($response && $context) { - $ms->onData($data, $context); + if ($ms) { + $ms->onData($data); } }); diff --git a/tests/ab/fuzzingclient.travis.json b/tests/ab/fuzzingclient.travis.json new file mode 100644 index 0000000..d61bc6a --- /dev/null +++ b/tests/ab/fuzzingclient.travis.json @@ -0,0 +1,13 @@ +{ + "options": {"failByDrop": false}, + "outdir": "./reports/servers", + + "servers": [ + {"agent": "RatchetRFC/0.0.0", + "url": "ws://localhost:9001", + "options": {"version": 18}} + ], + "cases": ["1.*", "2.*", "3.*", "4.*", "5.*", "6.*", "7.*"], + "exclude-cases": [], + "exclude-agent-cases": {} +} diff --git a/tests/ab/fuzzingserver.travis.json b/tests/ab/fuzzingserver.travis.json new file mode 100644 index 0000000..4ef6af3 --- /dev/null +++ b/tests/ab/fuzzingserver.travis.json @@ -0,0 +1,10 @@ +{ + "url": "ws://127.0.0.1:9001" + , "options": { + "failByDrop": false +} + , "outdir": "./reports/clients" + , "cases": ["1.*", "2.*", "3.*", "4.*", "5.*", "6.*", "7.*"] + , "exclude-cases": [] + , "exclude-agent-cases": {} +} \ No newline at end of file diff --git a/tests/ab/run_ab_tests.sh b/tests/ab/run_ab_tests.sh new file mode 100644 index 0000000..9cd8467 --- /dev/null +++ b/tests/ab/run_ab_tests.sh @@ -0,0 +1,12 @@ +cd tests/ab + +wstest -m fuzzingserver -s fuzzingserver.travis.json & +sleep 5 +php clientRunner.php + +sleep 2 + +php startServer.php 25 & +sleep 3 +wstest -m fuzzingclient -s fuzzingclient.travis.json +sleep 2 \ No newline at end of file diff --git a/tests/ab/startServer.php b/tests/ab/startServer.php index 47a5316..f0f9d8d 100644 --- a/tests/ab/startServer.php +++ b/tests/ab/startServer.php @@ -6,6 +6,14 @@ use Ratchet\RFC6455\Messaging\Protocol\Frame; require_once __DIR__ . "/../bootstrap.php"; $loop = \React\EventLoop\Factory::create(); + +if ($argc > 1 && is_numeric($argv[1])) { + echo "Setting test server to stop in " . $argv[1] . " seconds.\n"; + $loop->addTimer($argv[1], function () { + exit; + }); +} + $socket = new \React\Socket\Server($loop); $server = new \React\Http\Server($socket); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 6fa5dc9..511b041 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -4,15 +4,16 @@ * Find the auto loader file */ $files = [ - __DIR__ . '/../../../../vendor/autoload.php', - __DIR__ . '/../../../vendor/autoload.php', - __DIR__ . '/../../vendor/autoload.php', __DIR__ . '/../vendor/autoload.php', + __DIR__ . '/../../vendor/autoload.php', + __DIR__ . '/../../../vendor/autoload.php', + __DIR__ . '/../../../../vendor/autoload.php', ]; foreach ($files as $file) { if (file_exists($file)) { - require $file; + $loader = require $file; + $loader->addPsr4('Ratchet\\RFC6455\\Test\\', __DIR__); break; } }