pool = new AsyncPool($fiberManager, maxConcurrency: 3); }); it('executes operations with limited concurrency', function () { $executedOperations = []; for ($i = 1; $i <= 10; $i++) { $this->pool->add(function () use ($i, &$executedOperations) { $executedOperations[] = $i; return "result-{$i}"; }, "op{$i}"); } $results = $this->pool->execute(); expect(count($results))->toBe(10); expect($results['op1'])->toBe('result-1'); expect($results['op10'])->toBe('result-10'); }); it('respects max concurrency limit', function () { $stats = $this->pool->getStats(); expect($stats['max_concurrency'])->toBe(3); expect($stats['pending'])->toBe(0); expect($stats['active'])->toBe(0); expect($stats['completed'])->toBe(0); }); it('tracks operation statistics', function () { $this->pool->add(fn() => 'test1', 'op1'); $this->pool->add(fn() => 'test2', 'op2'); $statsBefore = $this->pool->getStats(); expect($statsBefore['pending'])->toBe(2); $this->pool->execute(); $statsAfter = $this->pool->getStats(); expect($statsAfter['completed'])->toBe(2); expect($statsAfter['pending'])->toBe(0); }); it('awaits specific operation result', function () { $this->pool->add(fn() => 'result-1', 'op1'); $this->pool->add(fn() => 'result-2', 'op2'); // Start execution in background $this->pool->execute(); $result = $this->pool->await('op1'); expect($result)->toBe('result-1'); }); it('handles exceptions in operations', function () { // Test that exceptions during execution are caught and stored as results $this->pool->add(fn() => 'success', 'op1'); $this->pool->add(function () { throw new \RuntimeException('error'); }, 'op2'); // Execute all operations - exceptions are caught and stored as results $results = $this->pool->execute(); expect($results['op1'])->toBe('success'); expect($results['op2'])->toBeInstanceOf(\RuntimeException::class); expect($results['op2']->getMessage())->toBe('error'); }); it('generates unique IDs when not provided', function () { $id1 = $this->pool->add(fn() => 'test1'); $id2 = $this->pool->add(fn() => 'test2'); expect($id1)->not->toBe($id2); expect(str_starts_with($id1, 'pool_'))->toBeTrue(); expect(str_starts_with($id2, 'pool_'))->toBeTrue(); }); it('executes all operations eventually', function () { $completed = []; for ($i = 1; $i <= 50; $i++) { $this->pool->add(function () use ($i, &$completed) { usleep(1000); // 1ms delay $completed[] = $i; return $i; }); } $results = $this->pool->execute(); expect(count($results))->toBe(50); expect(count($completed))->toBe(50); }); it('maintains operation order in results', function () { $operations = [ 'first' => fn() => 'first-result', 'second' => fn() => 'second-result', 'third' => fn() => 'third-result', ]; foreach ($operations as $id => $operation) { $this->pool->add($operation, $id); } $results = $this->pool->execute(); expect($results['first'])->toBe('first-result'); expect($results['second'])->toBe('second-result'); expect($results['third'])->toBe('third-result'); }); });