diff --git a/src/Informer/Worker.php b/src/Informer/Worker.php new file mode 100644 index 0000000..2503ee4 --- /dev/null +++ b/src/Informer/Worker.php @@ -0,0 +1,29 @@ + $workers + */ + public function __construct( + public array $workers = [], + ) { + } + + public function count(): int + { + return \count($this->workers); + } +} diff --git a/src/WorkerPool.php b/src/WorkerPool.php index 9f2eca3..1d201c8 100644 --- a/src/WorkerPool.php +++ b/src/WorkerPool.php @@ -6,7 +6,21 @@ use Spiral\Goridge\RPC\Codec\JsonCodec; use Spiral\Goridge\RPC\RPCInterface; +use Spiral\RoadRunner\Informer\Workers; +use Spiral\RoadRunner\Informer\Worker as InformerWorker; +/** + * @psalm-type TInformerWorker = array{ + * pid: positive-int, + * status: int, + * numExecs: int, + * created: positive-int, + * memoryUsage: positive-int, + * CPUPercent: float, + * command: string, + * statusStr: string, + * } + */ final class WorkerPool { private readonly RPCInterface $rpc; @@ -27,6 +41,42 @@ public function addWorker(string $plugin): void $this->rpc->call('informer.AddWorker', $plugin); } + /** + * Get the number of workers for the pool. + * + * @param non-empty-string $plugin + */ + public function countWorkers(string $plugin): int + { + return \count($this->getWorkers($plugin)); + } + + /** + * Get the info about running workers for the pool. + * + * @param non-empty-string $plugin + */ + public function getWorkers(string $plugin): Workers + { + /** + * @var array{workers: list} $data + */ + $data = $this->rpc->call('informer.Workers', $plugin); + + return new Workers(\array_map(static function (array $worker): InformerWorker { + return new InformerWorker( + pid: $worker['pid'], + statusCode: $worker['status'], + executions: $worker['numExecs'], + createdAt: $worker['created'], + memoryUsage: $worker['memoryUsage'], + cpuUsage: $worker['CPUPercent'], + command: $worker['command'], + status: $worker['statusStr'], + ); + }, $data['workers'])); + } + /** * Remove worker from the pool. * diff --git a/tests/Unit/WorkerPoolTest.php b/tests/Unit/WorkerPoolTest.php index ea72bf2..16c4bbe 100644 --- a/tests/Unit/WorkerPoolTest.php +++ b/tests/Unit/WorkerPoolTest.php @@ -4,14 +4,28 @@ namespace Spiral\RoadRunner\Tests\Worker\Unit; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\Exception; use PHPUnit\Framework\TestCase; use Spiral\Goridge\RPC\Codec\JsonCodec; use Spiral\Goridge\RPC\RPCInterface; +use Spiral\RoadRunner\Informer\Worker; +use Spiral\RoadRunner\Informer\Workers; use Spiral\RoadRunner\WorkerPool; final class WorkerPoolTest extends TestCase { + private const EXAMPLE_WORKER = [ + 'pid' => 1, + 'status' => 1, + 'numExecs' => 1, + 'created' => 1, + 'memoryUsage' => 1, + 'CPUPercent' => 1.0, + 'command' => 'test', + 'statusStr' => 'test', + ]; + private \PHPUnit\Framework\MockObject\MockObject|RPCInterface $rpc; private WorkerPool $workerPool; @@ -23,7 +37,11 @@ protected function setUp(): void parent::setUp(); $this->rpc = $this->createMock(RPCInterface::class); - $this->rpc->expects($this->once())->method('withCodec')->with($this->isInstanceOf(JsonCodec::class))->willReturnSelf(); + $this->rpc + ->expects($this->once()) + ->method('withCodec') + ->with($this->isInstanceOf(JsonCodec::class)) + ->willReturnSelf(); $this->workerPool = new WorkerPool($this->rpc); } @@ -35,10 +53,63 @@ public function testAddWorker(): void $this->workerPool->addWorker('test'); } + #[DataProvider('countDataProvider')] + public function testCountWorkers(int $expected, array $workers): void + { + $this->rpc + ->expects($this->once()) + ->method('call') + ->with('informer.Workers', 'test') + ->willReturn(['workers' => $workers]); + + $this->assertSame($expected, $this->workerPool->countWorkers('test')); + } + + #[DataProvider('getWorkersDataProvider')] + public function testGetWorkers(array $expected, array $workers): void + { + $this->rpc + ->expects($this->once()) + ->method('call') + ->with('informer.Workers', 'test') + ->willReturn(['workers' => $workers]); + + $this->assertEquals(new Workers($expected), $this->workerPool->getWorkers('test')); + } + public function testRemoveWorker(): void { $this->rpc->expects($this->once())->method('call')->with('informer.RemoveWorker', 'test'); $this->workerPool->removeWorker('test'); } -} \ No newline at end of file + + public static function countDataProvider(): \Traversable + { + yield [0, []]; + yield [2, [self::EXAMPLE_WORKER, self::EXAMPLE_WORKER]]; + } + + public static function getWorkersDataProvider(): \Traversable + { + yield [[], []]; + + $workers = \array_map(static function (array $worker): Worker { + return new Worker( + pid: $worker['pid'], + statusCode: $worker['status'], + executions: $worker['numExecs'], + createdAt: $worker['created'], + memoryUsage: $worker['memoryUsage'], + cpuUsage: $worker['CPUPercent'], + command: $worker['command'], + status: $worker['statusStr'], + ); + }, [ + self::EXAMPLE_WORKER, + self::EXAMPLE_WORKER, + ]); + + yield [$workers, [self::EXAMPLE_WORKER, self::EXAMPLE_WORKER]]; + } +}