Files
michaelschiemer/tests/Unit/Framework/Async/AsyncPromiseTest.php
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- 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.
2025-10-25 19:18:37 +02:00

191 lines
5.4 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Unit\Framework\Async;
use App\Framework\Async\AsyncPromise;
use App\Framework\Async\FiberManager;
use App\Framework\DateTime\SystemClock;
use App\Framework\DateTime\SystemTimer;
describe('AsyncPromise', function () {
beforeEach(function () {
$this->clock = new SystemClock();
$this->timer = new SystemTimer($this->clock);
$this->fiberManager = new FiberManager($this->clock, $this->timer);
});
it('creates a resolved promise', function () {
$promise = AsyncPromise::resolve('test-value', $this->fiberManager);
expect($promise->isResolved())->toBeTrue();
expect($promise->await())->toBe('test-value');
});
it('creates a rejected promise', function () {
$exception = new \RuntimeException('test error');
$promise = AsyncPromise::reject($exception, $this->fiberManager);
expect($promise->isResolved())->toBeTrue();
try {
$promise->await();
throw new \Exception('Should have thrown');
} catch (\RuntimeException $e) {
expect($e->getMessage())->toBe('test error');
}
});
it('creates a promise from callable', function () {
$promise = AsyncPromise::create(
fn() => 'computed-value',
$this->fiberManager
);
// Give fiber time to execute
usleep(10000); // 10ms
expect($promise->await())->toBe('computed-value');
});
it('chains then callbacks', function () {
$promise = AsyncPromise::resolve(5, $this->fiberManager)
->then(fn($value) => $value * 2)
->then(fn($value) => $value + 3);
usleep(10000); // Give time for chaining
expect($promise->await())->toBe(13);
});
it('catches exceptions', function () {
$promise = AsyncPromise::create(
fn() => throw new \RuntimeException('error'),
$this->fiberManager
)->catch(fn($e) => 'caught: ' . $e->getMessage());
usleep(10000);
expect($promise->await())->toBe('caught: error');
});
it('executes finally callback', function () {
$finallyCalled = false;
$promise = AsyncPromise::resolve('value', $this->fiberManager)
->finally(function () use (&$finallyCalled) {
$finallyCalled = true;
});
usleep(10000);
$promise->await();
expect($finallyCalled)->toBeTrue();
});
it('waits for all promises', function () {
$promise1 = AsyncPromise::resolve(1, $this->fiberManager);
$promise2 = AsyncPromise::resolve(2, $this->fiberManager);
$promise3 = AsyncPromise::resolve(3, $this->fiberManager);
$allPromise = AsyncPromise::all(
[$promise1, $promise2, $promise3],
$this->fiberManager
);
usleep(10000);
$results = $allPromise->await();
expect($results)->toBe([1, 2, 3]);
});
it('races promises and returns first', function () {
$slowPromise = AsyncPromise::create(function () {
usleep(100000); // 100ms
return 'slow';
}, $this->fiberManager);
$fastPromise = AsyncPromise::create(function () {
// No sleep - immediate return
return 'fast';
}, $this->fiberManager);
$racePromise = AsyncPromise::race(
[$slowPromise, $fastPromise],
$this->fiberManager
);
usleep(20000); // Wait a bit for fast to complete
$result = $racePromise->await();
// Either fast wins or first to complete
expect(['fast', 'slow'])->toContain($result);
});
it('handles promise rejection in all', function () {
$promise1 = AsyncPromise::resolve(1, $this->fiberManager);
$promise2 = AsyncPromise::reject(
new \RuntimeException('failed'),
$this->fiberManager
);
$allPromise = AsyncPromise::all(
[$promise1, $promise2],
$this->fiberManager
);
usleep(10000);
try {
$allPromise->await();
throw new \Exception('Should have thrown');
} catch (\RuntimeException $e) {
expect($e->getMessage())->toBe('failed');
}
});
it('provides promise statistics', function () {
$promise = AsyncPromise::create(
fn() => 'value',
$this->fiberManager
);
usleep(10000);
$stats = $promise->getStats();
expect($stats)->toHaveKey('resolved');
expect($stats)->toHaveKey('has_result');
expect($stats)->toHaveKey('has_exception');
});
it('chains multiple then callbacks with different return types', function () {
$promise = AsyncPromise::resolve(10, $this->fiberManager)
->then(fn($x) => $x * 2) // 20
->then(fn($x) => (string) $x) // "20"
->then(fn($x) => $x . '!') // "20!"
->then(fn($x) => strlen($x)); // 3
usleep(10000);
expect($promise->await())->toBe(3);
});
it('handles nested promises', function () {
$innerPromise = AsyncPromise::create(
fn() => 'inner',
$this->fiberManager
);
$outerPromise = AsyncPromise::create(
fn() => $innerPromise->await() . '-outer',
$this->fiberManager
);
usleep(20000);
expect($outerPromise->await())->toBe('inner-outer');
});
});