laravel-webrtc/tests/SignalingHandlerTest.php

127 lines
4.9 KiB
PHP

<?php
declare(strict_types=1);
namespace Blax\WebRtc\Tests;
use Blax\WebRtc\Signaling\SignalingHandler;
use Blax\WebRtc\Tests\Fixtures\FakeMediaEngine;
use PHPUnit\Framework\TestCase;
final class SignalingHandlerTest extends TestCase
{
public function test_offer_returns_the_engine_answer(): void
{
$engine = new FakeMediaEngine;
$result = (new SignalingHandler($engine))->handle([
'type' => 'offer',
'peer' => 'p1',
'sdp' => 'OFFER-SDP',
]);
$this->assertSame(['type' => 'answer', 'peer' => 'p1', 'sdp' => 'answer-for-p1'], $result);
$this->assertSame(['offer', 'p1', 'OFFER-SDP'], $engine->calls[0]);
}
public function test_ice_is_forwarded_and_needs_no_reply(): void
{
$engine = new FakeMediaEngine;
$result = (new SignalingHandler($engine))->handle([
'type' => 'ice',
'peer' => 'p1',
'candidate' => ['candidate' => 'a=x'],
]);
$this->assertNull($result);
$this->assertSame(['ice', 'p1', ['candidate' => 'a=x']], $engine->calls[0]);
}
public function test_record_connect_bridge_close_are_acked_and_routed(): void
{
$engine = new FakeMediaEngine;
$handler = new SignalingHandler($engine);
$this->assertSame(['type' => 'ack', 'peer' => 'p1'], $handler->handle(['type' => 'record', 'peer' => 'p1', 'path' => '/tmp/a.opus']));
$this->assertSame(['type' => 'ack', 'peer' => 'p1'], $handler->handle(['type' => 'connect', 'peer' => 'p1', 'other' => 'p2']));
$this->assertSame(['type' => 'ack', 'peer' => 'p1'], $handler->handle(['type' => 'bridge', 'peer' => 'p1', 'options' => ['model' => 'gpt-realtime']]));
$this->assertSame(['type' => 'ack', 'peer' => 'p1'], $handler->handle(['type' => 'close', 'peer' => 'p1']));
$this->assertSame(['record', 'p1', '/tmp/a.opus'], $engine->calls[0]);
$this->assertSame(['connect', 'p1', 'p2'], $engine->calls[1]);
$this->assertSame(['bridge', 'p1', ['model' => 'gpt-realtime']], $engine->calls[2]);
$this->assertSame(['close', 'p1'], $engine->calls[3]);
}
public function test_a_missing_peer_is_an_error(): void
{
$result = (new SignalingHandler(new FakeMediaEngine))->handle(['type' => 'offer']);
$this->assertSame('error', $result['type']);
}
public function test_an_unknown_type_is_an_error(): void
{
$result = (new SignalingHandler(new FakeMediaEngine))->handle(['type' => 'wat', 'peer' => 'p1']);
$this->assertSame('error', $result['type']);
$this->assertStringContainsString('wat', $result['error']);
}
public function test_an_engine_exception_is_caught_as_an_error_reply(): void
{
$engine = new FakeMediaEngine;
$engine->throwOnOffer = new \RuntimeException('boom');
$result = (new SignalingHandler($engine))->handle(['type' => 'offer', 'peer' => 'p1', 'sdp' => 'x']);
$this->assertSame(['type' => 'error', 'peer' => 'p1', 'error' => 'boom'], $result);
}
public function test_join_meshes_a_new_peer_with_those_already_present(): void
{
$engine = new FakeMediaEngine;
$handler = new SignalingHandler($engine);
$this->assertSame(
['type' => 'joined', 'peer' => 'p1', 'room' => 'lobby', 'peers' => []],
$handler->handle(['type' => 'join', 'peer' => 'p1', 'room' => 'lobby']),
);
$this->assertSame(
['type' => 'joined', 'peer' => 'p2', 'room' => 'lobby', 'peers' => ['p1']],
$handler->handle(['type' => 'join', 'peer' => 'p2', 'room' => 'lobby']),
);
$this->assertContains(['connect', 'p2', 'p1'], $engine->calls);
}
public function test_join_without_a_room_is_an_error(): void
{
$result = (new SignalingHandler(new FakeMediaEngine))->handle(['type' => 'join', 'peer' => 'p1']);
$this->assertSame('error', $result['type']);
}
public function test_leave_reports_the_remaining_peers(): void
{
$handler = new SignalingHandler(new FakeMediaEngine);
$handler->handle(['type' => 'join', 'peer' => 'p1', 'room' => 'lobby']);
$handler->handle(['type' => 'join', 'peer' => 'p2', 'room' => 'lobby']);
$this->assertSame(
['type' => 'left', 'peer' => 'p2', 'peers' => ['p1']],
$handler->handle(['type' => 'leave', 'peer' => 'p2']),
);
}
public function test_close_also_removes_the_peer_from_its_room(): void
{
$engine = new FakeMediaEngine;
$handler = new SignalingHandler($engine);
$handler->handle(['type' => 'join', 'peer' => 'p1', 'room' => 'lobby']);
$this->assertSame(['type' => 'ack', 'peer' => 'p1'], $handler->handle(['type' => 'close', 'peer' => 'p1']));
$this->assertNull($handler->rooms()->roomOf('p1'));
$this->assertContains(['close', 'p1'], $engine->calls);
}
}