ratchetphp / Ratchet

Asynchronous WebSocket server
http://socketo.me
MIT License
6.24k stars 727 forks source link

Unit test for WebSocket server? #795

Open patrickbussmann opened 4 years ago

patrickbussmann commented 4 years ago

I find the IoSocket Server tests here: https://github.com/ratchetphp/Ratchet/tree/master/tests/unit/Server

But there are no WebSocket Server tests. So I tried to work on but its a bit complicated.

So this is the test case from the original test file above. (tests/unit/Server)

Original constructor:

        $this->app = $this->getMockBuilder('\\Ratchet\\MessageComponentInterface')->getMock();
//      $this->app = new ChatServer();

//      $this->server  = new WsServer();

        $loop = new StreamSelectLoop();
        $this->reactor = new Server(0, $loop);

        $uri = $this->reactor->getAddress();
        $this->port   = parse_url((strpos($uri, '://') === false ? 'tcp://' : '') . $uri, PHP_URL_PORT);

        $this->server = new IoServer($this->app, $this->reactor, $loop);
//      $this->server = new WebSocket($this->app, $this->reactor, $loop);

And when I change something:

//      $this->app = $this->getMockBuilder(MessageComponentInterface::class)->getMock();
        $this->app = self::$container->get(ChatServer::class);

//      $this->app = $this->getMockBuilder('\\Ratchet\\MessageComponentInterface')->getMock();
//      $ConnectionInterface = $this->getMockBuilder('\\Ratchet\\ConnectionInterface')->getMock();
        $ResponseInterface = $this->getMockBuilder(ResponseInterface::class)->getMock();
        $RequestInterface = $this->getMockBuilder(RequestInterface::class)->getMock();
//      $this->app = new ChatServer();

//      $this->server  = new WsServer();

        $loop = new StreamSelectLoop();
        $this->reactor = new Server(0, $loop);

        $uri = $this->reactor->getAddress();
        $this->port   = parse_url((strpos($uri, '://') === false ? 'tcp://' : '') . $uri, PHP_URL_PORT);

        var_dump($this->port);
        fwrite(STDERR, $uri);
//      $this->server = new IoServer($this->app, $this->reactor, $loop);
        $a = new WsServer($this->app);
        $b = new HttpServer($a);
        $this->server = new IoServer($b, $this->reactor, $loop);
//      $this->server->run();

Then the server can start (last line outcommented)

And with JavaScript I'm able to connect.

new WebSocket('ws://127.0.0.1:27464')

But with my test method its not working.

    public function testOnData() {
        $msg = 'Hello World!';

//      $this->app->expects($this->once())->method('onMessage')->with(
//          $this->isInstanceOf('\\Ratchet\\ConnectionInterface')
//          , $msg
//      );

//      $client = \socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
//      \socket_set_option($client, SOL_SOCKET, SO_REUSEADDR, 1);
//      \socket_set_option($client, SOL_SOCKET, SO_SNDBUF, 4096);
//      \socket_set_block($client);
//      \socket_connect($client, 'localhost', $this->port);

        $this->tickLoop($this->server->loop);

//      echo 123;
//      sleep(10);

//      $data = '{"id": 2,"command": "server_info"}';
        $sock = fsockopen('127.0.0.1', $this->port, $errno, $errstr);
        $head = "GET / HTTP/1.1\r\n"
            ."Host: localhost\r\n"
            ."Origin: localhost\r\n"
            ."Pragma: no-cache\r\n"
            ."Cache-Control: no-cache\r\n"
            ."Upgrade: websocket\r\n"
            ."Connection: Upgrade\r\n"
            ."Sec-WebSocket-Key: " . base64_encode(openssl_random_pseudo_bytes(16)) . "\r\n"
            ."Sec-WebSocket-Version: 13\r\n"
            ."\r\n";
        $this->tickLoop($this->server->loop);
        fwrite($sock, $head) or die('error:'.$errno.':'.$errstr);
        $this->tickLoop($this->server->loop);
//      $headers = fread($sock, 2000);
//      fwrite($sock, "\x00$data\xff" ) or die('error:'.$errno.':'.$errstr);
////        $wsdata = fread($sock, 2000);  //receives the data included in the websocket package "\x00DATA\xff"
////        $retdata = trim($wsdata,"\x00\xff"); //extracts data
//////WebSocket handshake
        fclose($sock);

//      $this->server->handleData('asd', $this->getMockBuilder(ConnectionInterface::class)->getMock());

//      socket_write($client, $msg);
//      $this->tickLoop($this->server->loop);
//
//      socket_shutdown($client, 1);
//      socket_shutdown($client, 0);
//      socket_close($client);
//
//      $this->tickLoop($this->server->loop);
    }

Its hanging in an endless loop. Without ->run() its not getting a connection.

Do someone know how to test WebSockets on Ratchet? ☺

cboden commented 4 years ago

its a bit complicated

Indeed! 😅

The reason there aren't any PHPUnit tests for the WebSocket server is because that's pretty well covered by the Autobahn Testsuite.

patrickbussmann commented 4 years ago

Okay. So for now I can use both. But for me its more pretty to focus on one test type now.

Maybe you can help me with small thing - but for my its very big. I was able to set up the server in theory - with the IoServer test case. (instead websockets)

    public function setUp() {
//      $this->markTestSkipped();
        self::bootKernel();
        $this->_app  = $this->getMockBuilder(WsServer::class)
            ->setConstructorArgs([
                self::$container->get(ChatServer::class)
            ])
            ->getMock();
        $this->_app = new WsServer(self::$container->get(ChatServer::class));
        $decorator   = $this->getDecoratorClassString();
        $this->_serv = IoServer::factory(new $decorator($this->_app), 12312);
        $this->_serv->run();
        $this->_conn = $this->getMockBuilder('\Ratchet\ConnectionInterface')->getMock();

        $this->doOpen($this->_conn);

        $this->_conn->httpHeadersReceived = true;
    }

And then my test is always failing.

    public function testMessage() {
//      $headers = "GET / HTTP/1.1\r\nHost: socketo.me\r\n\r\n";
//      $this->_conn->httpHeadersReceived = false;
//      $this->_serv->onMessage($this->_conn, $headers);

        $message = "Hello World!";
//      $this->_app->expects($this->once())->method('onMessage')->with($this->isExpectedConnection(), $message);
        $this->_serv->onOpen($this->_conn);
        $this->_serv->onMessage($this->_conn, 'invalid json');
        $this->assertTrue('asd' == true);
//      sleep(20);
    }

I never got a connected client. Maybe because I place the ticks wrong?

But I go to Autobahn then.