laravel-webrtc/tests/SidecarSupervisorTest.php

108 lines
3.7 KiB
PHP
Raw Permalink Normal View History

<?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');
}
}