- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
131 lines
4.0 KiB
PHP
131 lines
4.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Unit\Framework\Async;
|
|
|
|
use App\Framework\Async\AsyncPool;
|
|
use App\Framework\Async\FiberManager;
|
|
use App\Framework\DateTime\SystemClock;
|
|
use App\Framework\DateTime\SystemTimer;
|
|
|
|
describe('AsyncPool', function () {
|
|
beforeEach(function () {
|
|
$clock = new SystemClock();
|
|
$timer = new SystemTimer();
|
|
$fiberManager = new FiberManager($clock, $timer);
|
|
|
|
$this->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');
|
|
});
|
|
});
|