133 lines
4.6 KiB
PHP
133 lines
4.6 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
namespace Blax\WebRtc\Tests;
|
||
|
|
|
||
|
|
use Blax\WebRtc\Signaling\RelaySignalingHandler;
|
||
|
|
use Blax\WebRtc\Tests\Fixtures\FakePeer;
|
||
|
|
use PHPUnit\Framework\TestCase;
|
||
|
|
|
||
|
|
final class RelaySignalingHandlerTest extends TestCase
|
||
|
|
{
|
||
|
|
public function test_welcomes_a_peer_on_connect_with_its_id(): void
|
||
|
|
{
|
||
|
|
$handler = new RelaySignalingHandler;
|
||
|
|
$a = new FakePeer('a');
|
||
|
|
|
||
|
|
$handler->onOpen($a);
|
||
|
|
|
||
|
|
$this->assertSame(['type' => 'welcome', 'peer' => 'a'], $a->lastJson());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_join_returns_existing_peers_and_notifies_them(): void
|
||
|
|
{
|
||
|
|
$handler = new RelaySignalingHandler;
|
||
|
|
$a = new FakePeer('a');
|
||
|
|
$b = new FakePeer('b');
|
||
|
|
$handler->onOpen($a);
|
||
|
|
$handler->onOpen($b);
|
||
|
|
|
||
|
|
$handler->onMessage($a, $this->json(['type' => 'join', 'room' => 'lobby']));
|
||
|
|
$handler->onMessage($b, $this->json(['type' => 'join', 'room' => 'lobby']));
|
||
|
|
|
||
|
|
// b learns 'a' is already there
|
||
|
|
$this->assertSame(['type' => 'joined', 'room' => 'lobby', 'peers' => ['a']], $b->lastJson());
|
||
|
|
// a is told b joined
|
||
|
|
$this->assertContains(['type' => 'peer-joined', 'room' => 'lobby', 'peer' => 'b'], $a->jsonMessages());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_relay_forwards_the_payload_to_the_target_with_the_sender(): void
|
||
|
|
{
|
||
|
|
$handler = new RelaySignalingHandler;
|
||
|
|
$a = new FakePeer('a');
|
||
|
|
$b = new FakePeer('b');
|
||
|
|
$handler->onOpen($a);
|
||
|
|
$handler->onOpen($b);
|
||
|
|
|
||
|
|
$handler->onMessage($a, $this->json(['type' => 'relay', 'to' => 'b', 'data' => ['sdp' => 'OFFER']]));
|
||
|
|
|
||
|
|
$this->assertSame(['type' => 'relay', 'from' => 'a', 'data' => ['sdp' => 'OFFER']], $b->lastJson());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_relay_to_an_unknown_peer_errors_the_sender(): void
|
||
|
|
{
|
||
|
|
$handler = new RelaySignalingHandler;
|
||
|
|
$a = new FakePeer('a');
|
||
|
|
$handler->onOpen($a);
|
||
|
|
|
||
|
|
$handler->onMessage($a, $this->json(['type' => 'relay', 'to' => 'ghost', 'data' => []]));
|
||
|
|
|
||
|
|
$this->assertSame('error', $a->lastJson()['type']);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_leave_notifies_the_remaining_peers(): void
|
||
|
|
{
|
||
|
|
$handler = new RelaySignalingHandler;
|
||
|
|
$a = new FakePeer('a');
|
||
|
|
$b = new FakePeer('b');
|
||
|
|
$handler->onOpen($a);
|
||
|
|
$handler->onOpen($b);
|
||
|
|
$handler->onMessage($a, $this->json(['type' => 'join', 'room' => 'lobby']));
|
||
|
|
$handler->onMessage($b, $this->json(['type' => 'join', 'room' => 'lobby']));
|
||
|
|
|
||
|
|
$handler->onMessage($b, $this->json(['type' => 'leave']));
|
||
|
|
|
||
|
|
$this->assertContains(['type' => 'peer-left', 'peer' => 'b'], $a->jsonMessages());
|
||
|
|
$this->assertSame(['type' => 'left'], $b->lastJson());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_disconnect_leaves_the_room_and_forgets_the_peer(): void
|
||
|
|
{
|
||
|
|
$handler = new RelaySignalingHandler;
|
||
|
|
$a = new FakePeer('a');
|
||
|
|
$b = new FakePeer('b');
|
||
|
|
$handler->onOpen($a);
|
||
|
|
$handler->onOpen($b);
|
||
|
|
$handler->onMessage($a, $this->json(['type' => 'join', 'room' => 'lobby']));
|
||
|
|
$handler->onMessage($b, $this->json(['type' => 'join', 'room' => 'lobby']));
|
||
|
|
|
||
|
|
$handler->onClose($b);
|
||
|
|
|
||
|
|
$this->assertContains(['type' => 'peer-left', 'peer' => 'b'], $a->jsonMessages());
|
||
|
|
$this->assertFalse($handler->peers()->has('b'));
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_broadcast_reaches_the_rest_of_the_room_only(): void
|
||
|
|
{
|
||
|
|
$handler = new RelaySignalingHandler;
|
||
|
|
$peers = [new FakePeer('a'), new FakePeer('b'), new FakePeer('c')];
|
||
|
|
foreach ($peers as $p) {
|
||
|
|
$handler->onOpen($p);
|
||
|
|
$handler->onMessage($p, $this->json(['type' => 'join', 'room' => 'r']));
|
||
|
|
}
|
||
|
|
[$a, $b, $c] = $peers;
|
||
|
|
|
||
|
|
$handler->onMessage($a, $this->json(['type' => 'broadcast', 'data' => ['x' => 1]]));
|
||
|
|
|
||
|
|
$expected = ['type' => 'broadcast', 'from' => 'a', 'data' => ['x' => 1]];
|
||
|
|
$this->assertContains($expected, $b->jsonMessages());
|
||
|
|
$this->assertContains($expected, $c->jsonMessages());
|
||
|
|
$this->assertNotContains($expected, $a->jsonMessages());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_invalid_json_and_unknown_type_are_errors(): void
|
||
|
|
{
|
||
|
|
$handler = new RelaySignalingHandler;
|
||
|
|
$a = new FakePeer('a');
|
||
|
|
$handler->onOpen($a);
|
||
|
|
|
||
|
|
$handler->onMessage($a, 'not json');
|
||
|
|
$this->assertSame('error', $a->lastJson()['type']);
|
||
|
|
|
||
|
|
$handler->onMessage($a, $this->json(['type' => 'wat']));
|
||
|
|
$this->assertSame('error', $a->lastJson()['type']);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @param array<string,mixed> $data */
|
||
|
|
private function json(array $data): string
|
||
|
|
{
|
||
|
|
return (string) json_encode($data);
|
||
|
|
}
|
||
|
|
}
|