* Dariusz RumiƄski * * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. */ namespace PhpCsFixer\Tests\Runner\Parallel; use PhpCsFixer\Console\Command\FixCommand; use PhpCsFixer\Runner\Parallel\ParallelConfigFactory; use PhpCsFixer\Runner\Parallel\ParallelisationException; use PhpCsFixer\Runner\Parallel\Process; use PhpCsFixer\Runner\Parallel\ProcessFactory; use PhpCsFixer\Runner\Parallel\ProcessIdentifier; use PhpCsFixer\Runner\Parallel\ProcessPool; use PhpCsFixer\Runner\RunnerConfig; use PhpCsFixer\Tests\TestCase; use PhpCsFixer\ToolInfo; use React\EventLoop\StreamSelectLoop; use React\Socket\ServerInterface; use Symfony\Component\Console\Application; use Symfony\Component\Console\Input\ArrayInput; /** * @internal * * @covers \PhpCsFixer\Runner\Parallel\ProcessPool */ final class ProcessPoolTest extends TestCase { public bool $serverClosed = false; private ProcessFactory $processFactory; protected function setUp(): void { $fixCommand = new FixCommand(new ToolInfo()); $application = new Application(); $application->add($fixCommand); // In order to have full list of options supported by the command (e.g. `--verbose`) $fixCommand->mergeApplicationDefinition(false); $this->processFactory = new ProcessFactory(new ArrayInput([], $fixCommand->getDefinition())); } public function testGetProcessWithInvalidIdentifier(): void { self::expectException(ParallelisationException::class); $this->getProcessPool()->getProcess(ProcessIdentifier::create()); } public function testGetProcessWithValidIdentifier(): void { $identifier = ProcessIdentifier::create(); $processPool = $this->getProcessPool(); $process = $this->createProcess($identifier); $processPool->addProcess($identifier, $process); self::assertSame($process, $processPool->getProcess($identifier)); } public function testEndProcessIfKnownWithUnknownIdentifier(): void { $identifier1 = ProcessIdentifier::create(); $identifier2 = ProcessIdentifier::create(); $processPool = $this->getProcessPool(); $process = $this->createProcess($identifier1); $processPool->addProcess($identifier1, $process); // This is unregistered process, so it does nothing $processPool->endProcessIfKnown($identifier2); self::assertFalse($this->serverClosed); } public function testEndProcessIfKnownWithKnownIdentifier(): void { $identifier = ProcessIdentifier::create(); $processPool = $this->getProcessPool(); $process = $this->createProcess($identifier); $processPool->addProcess($identifier, $process); $processPool->endProcessIfKnown($identifier); self::assertTrue($this->serverClosed); } public function testEndAll(): void { $callbackExecuted = false; $processPool = $this->getProcessPool(static function () use (&$callbackExecuted): void { $callbackExecuted = true; }); $identifier1 = ProcessIdentifier::create(); $process1 = $this->createProcess($identifier1); $processPool->addProcess($identifier1, $process1); $identifier2 = ProcessIdentifier::create(); $process2 = $this->createProcess($identifier2); $processPool->addProcess($identifier2, $process2); $processPool->endAll(); self::assertTrue($this->serverClosed); self::assertTrue($callbackExecuted, 'Callback was not executed on server close.'); } private function createProcess(ProcessIdentifier $identifier): Process { return $this->processFactory->create( new StreamSelectLoop(), new RunnerConfig( true, false, ParallelConfigFactory::sequential() ), $identifier, 10_000 ); } private function getProcessPool(?callable $onServerClose = null): ProcessPool { $this->serverClosed = false; $test = $this; return new ProcessPool( new class($test) implements ServerInterface { private ProcessPoolTest $test; public function __construct(ProcessPoolTest $test) { $this->test = $test; } public function close(): void { $this->test->serverClosed = true; } public function getAddress(): ?string { return null; } public function pause(): void {} public function resume(): void {} /** @phpstan-ignore-next-line */ public function on($event, $listener): void {} /** @phpstan-ignore-next-line */ public function once($event, $listener): void {} /** @phpstan-ignore-next-line */ public function removeListener($event, $listener): void {} /** @phpstan-ignore-next-line */ public function removeAllListeners($event = null): void {} /** @phpstan-ignore-next-line */ public function listeners($event = null): void {} /** @phpstan-ignore-next-line */ public function emit($event, array $arguments = []): void {} }, $onServerClose ); } }