sys_get_temp_dir() . '/xcvm-cfg-' . getmypid() . '/', 'SERVER_ID' => 1] as $k => $v) { if (!defined($k)) { define($k, $v); } } } protected function setUp(): void { $this->rCfg = CONFIG_PATH . 'cluster/'; @mkdir($this->rCfg, 0o777, true); @unlink($this->rCfg . 'serve_only'); } protected function tearDown(): void { @unlink($this->rCfg . 'serve_only'); StreamSource::useLoader(null); } public function testNodeServeOnlyFalseWithoutTheMarker(): void { $this->assertFalse(StreamProcess::nodeServeOnly(), 'no marker → a normal node'); } public function testNodeServeOnlyTrueWithTheMarker(): void { file_put_contents($this->rCfg . 'serve_only', '2'); $this->assertTrue(StreamProcess::nodeServeOnly(), 'the Part A marker present → serve-only'); } public function testStartMonitorHandsServeOnlyLoopbackToTheAgent(): void { // Serve-only node + a loopback stream (parent_id > 0): startMonitor returns // MONITOR_FANOUT before superviseStream / the PHP monitor spawn, so cron:streams // never PHP-feeds it. Delete the gate and this returns MONITOR_PHP instead. file_put_contents($this->rCfg . 'serve_only', '2'); StreamSource::useLoader(fn(string $rWhat, int $rID, array $rOpts) => $rWhat === 'server' ? ['parent_id' => 3, 'server_id' => 1] : []); $this->assertSame(StreamProcess::MONITOR_FANOUT, StreamProcess::startMonitor(7)); } }