diff --git a/src/Transport/JsonRpc/ProcessJsonRpcClient.php b/src/Transport/JsonRpc/ProcessJsonRpcClient.php index 2be07f3..26e5188 100644 --- a/src/Transport/JsonRpc/ProcessJsonRpcClient.php +++ b/src/Transport/JsonRpc/ProcessJsonRpcClient.php @@ -124,11 +124,13 @@ private function waitForResponse(int|string $requestId, ?float $deadline): array private function readProcessOutput(): void { $stdout = $this->process->getIncrementalOutput(); + $this->process->clearOutput(); if ('' !== $stdout) { $this->outputBuffer .= $stdout; } $stderr = $this->process->getIncrementalErrorOutput(); + $this->process->clearErrorOutput(); if ('' !== $stderr) { $this->logger->warning('Process stderr', ['stderr' => $stderr]); } diff --git a/tests/Unit/Transport/JsonRpc/ProcessJsonRpcClientTest.php b/tests/Unit/Transport/JsonRpc/ProcessJsonRpcClientTest.php index 4ab1016..d1378b4 100644 --- a/tests/Unit/Transport/JsonRpc/ProcessJsonRpcClientTest.php +++ b/tests/Unit/Transport/JsonRpc/ProcessJsonRpcClientTest.php @@ -144,4 +144,56 @@ public function testInputStreamWriteFailureThrowsNetworkException(): void $client->send('test.method'); } + + public function testReadProcessOutputClearsBothProcessBuffers(): void + { + $mockProcess = $this->createMock(Process::class); + $mockProcessLauncher = $this->createMock(ProcessLauncherInterface::class); + + $mockProcess->method('isRunning')->willReturn(true); + $mockProcess->method('getPid')->willReturn(12345); + $mockProcess->method('getIncrementalOutput')->willReturn(''); + $mockProcess->method('getIncrementalErrorOutput')->willReturn(''); + $mockProcess->expects($this->once())->method('clearOutput'); + $mockProcess->expects($this->once())->method('clearErrorOutput'); + $mockProcessLauncher->method('getInputStream')->willReturn($this->mockInputStream); + $mockProcessLauncher->method('ensureRunning'); + + $client = new ProcessJsonRpcClient( + process: $mockProcess, + processLauncher: $mockProcessLauncher, + clock: $this->clock, + logger: $this->logger + ); + + $readProcessOutput = new \ReflectionMethod($client, 'readProcessOutput'); + $readProcessOutput->invoke($client); + } + + public function testReadProcessOutputClearsBuffersAcrossMultiplePolls(): void + { + $mockProcess = $this->createMock(Process::class); + $mockProcessLauncher = $this->createMock(ProcessLauncherInterface::class); + + $mockProcess->method('isRunning')->willReturn(true); + $mockProcess->method('getPid')->willReturn(12345); + $mockProcess->method('getIncrementalOutput')->willReturn(''); + $mockProcess->method('getIncrementalErrorOutput')->willReturn(''); + $mockProcess->expects($this->exactly(3))->method('clearOutput'); + $mockProcess->expects($this->exactly(3))->method('clearErrorOutput'); + $mockProcessLauncher->method('getInputStream')->willReturn($this->mockInputStream); + $mockProcessLauncher->method('ensureRunning'); + + $client = new ProcessJsonRpcClient( + process: $mockProcess, + processLauncher: $mockProcessLauncher, + clock: $this->clock, + logger: $this->logger + ); + + $readProcessOutput = new \ReflectionMethod($client, 'readProcessOutput'); + $readProcessOutput->invoke($client); + $readProcessOutput->invoke($client); + $readProcessOutput->invoke($client); + } }