108 lines
3.7 KiB
PHP
108 lines
3.7 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
namespace Blax\WebRtc\Tests;
|
||
|
|
|
||
|
|
use Blax\WebRtc\Media\Rust\BinaryManager;
|
||
|
|
use Blax\WebRtc\Media\Rust\SidecarException;
|
||
|
|
use Blax\WebRtc\Media\Rust\SidecarSupervisor;
|
||
|
|
use Blax\WebRtc\Media\RustMediaEngine;
|
||
|
|
use PHPUnit\Framework\TestCase;
|
||
|
|
|
||
|
|
final class SidecarSupervisorTest extends TestCase
|
||
|
|
{
|
||
|
|
public function test_auto_spawn_disabled_fails_with_actionable_guidance(): void
|
||
|
|
{
|
||
|
|
$supervisor = new SidecarSupervisor(new BinaryManager([]), [
|
||
|
|
'socket' => sys_get_temp_dir().'/blax-sfu-never-'.getmypid().'.sock',
|
||
|
|
'auto_spawn' => false,
|
||
|
|
]);
|
||
|
|
|
||
|
|
$this->assertFalse($supervisor->running());
|
||
|
|
|
||
|
|
$this->expectException(SidecarException::class);
|
||
|
|
$this->expectExceptionMessage('webrtc:sidecar');
|
||
|
|
|
||
|
|
$supervisor->ensureRunning();
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_args_mirror_the_config(): void
|
||
|
|
{
|
||
|
|
$supervisor = new SidecarSupervisor(new BinaryManager([]), [
|
||
|
|
'socket' => '/run/sfu.sock',
|
||
|
|
'udp_ip' => '10.0.0.5',
|
||
|
|
'udp_port' => 41000,
|
||
|
|
'public_ip' => '203.0.113.9',
|
||
|
|
]);
|
||
|
|
|
||
|
|
$this->assertSame(
|
||
|
|
['--socket', '/run/sfu.sock', '--udp-ip', '10.0.0.5', '--udp-port', '41000', '--public-ip', '203.0.113.9'],
|
||
|
|
$supervisor->args(),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* REAL cross-language round-trip: plug-and-play spawn of the actual Rust
|
||
|
|
* sidecar (local cargo build), the full control protocol through
|
||
|
|
* RustMediaEngine, and a graceful stop. Skipped until rust/ is built.
|
||
|
|
*/
|
||
|
|
public function test_spawns_and_drives_the_real_sidecar(): void
|
||
|
|
{
|
||
|
|
$binary = \dirname(__DIR__).'/rust/target/debug/blax-webrtc-sfu';
|
||
|
|
if (! is_file($binary)) {
|
||
|
|
$this->markTestSkipped('rust sidecar not built — run `cargo build` in rust/');
|
||
|
|
}
|
||
|
|
|
||
|
|
$socket = sys_get_temp_dir().'/blax-sfu-e2e-'.getmypid().'.sock';
|
||
|
|
$config = [
|
||
|
|
'socket' => $socket,
|
||
|
|
'binary' => $binary,
|
||
|
|
'auto_install' => false,
|
||
|
|
'udp_ip' => '127.0.0.1',
|
||
|
|
'log' => sys_get_temp_dir().'/blax-sfu-e2e-'.getmypid().'.log',
|
||
|
|
'spawn_timeout' => 15.0,
|
||
|
|
];
|
||
|
|
$supervisor = new SidecarSupervisor(new BinaryManager($config), $config);
|
||
|
|
|
||
|
|
try {
|
||
|
|
$this->assertFalse($supervisor->running());
|
||
|
|
|
||
|
|
$supervisor->ensureRunning(); // finds the binary + spawns detached
|
||
|
|
$this->assertTrue($supervisor->running());
|
||
|
|
|
||
|
|
$engine = new RustMediaEngine($supervisor);
|
||
|
|
|
||
|
|
// Empty stats on a fresh sidecar.
|
||
|
|
$this->assertSame([], $engine->stats());
|
||
|
|
|
||
|
|
// A garbage offer must come back as a clean protocol error.
|
||
|
|
try {
|
||
|
|
$engine->addPeer('lobby', 'alice', 'this is not sdp');
|
||
|
|
$this->fail('expected the sidecar to reject a garbage offer');
|
||
|
|
} catch (SidecarException $e) {
|
||
|
|
$this->assertStringContainsString('offer', $e->getMessage());
|
||
|
|
}
|
||
|
|
|
||
|
|
// Unknown peers error cleanly too.
|
||
|
|
try {
|
||
|
|
$engine->mutePeer('lobby', 'ghost', true);
|
||
|
|
$this->fail('expected a no-such-peer error');
|
||
|
|
} catch (SidecarException $e) {
|
||
|
|
$this->assertStringContainsString('no such peer', $e->getMessage());
|
||
|
|
}
|
||
|
|
|
||
|
|
// ensureRunning is idempotent while it lives.
|
||
|
|
$supervisor->ensureRunning();
|
||
|
|
$this->assertTrue($supervisor->running());
|
||
|
|
} finally {
|
||
|
|
$supervisor->stop();
|
||
|
|
@unlink($socket);
|
||
|
|
@unlink($socket.'.lock');
|
||
|
|
@unlink($config['log']);
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->assertFalse($supervisor->running(), 'graceful shutdown via the control socket');
|
||
|
|
}
|
||
|
|
}
|