/** * */ public function testCasePromise_RejectsPromise_IfResolverThrowsException() { $exception = new Exception('foo'); $promise = new Promise(function () use($exception) { throw $exception; }); $mock = $this->createCallableMock(); $mock->expects($this->once())->method('__invoke')->with($this->identicalTo($exception)); $promise->then($this->expectCallableNever(), $mock); }
/** * @override * @inheritDoc */ protected function command($params = []) { $runtime = $this->runtime; $promise = new Promise(); $runtime->once('destroy', function () use($promise) { $promise->resolve('Runtime has been destroyed'); }); $runtime->destroy()->then(null, function ($ex) use($promise) { $promise->reject($ex); }, function ($ex) use($promise) { $promise->cancel($ex); }); return $promise; }
/** * */ public function testApiAll_RejectsPromise_IfAnyInputPromisesReject() { $test = $this->getTest(); $mock = $test->createCallableMock(); $mock->expects($test->once())->method('__invoke')->with($test->identicalTo(2)); Promise::all([Promise::doResolve(1), Promise::doReject(2), Promise::doResolve(3)])->then($test->expectCallableNever(), $mock); }
/** * @override * @inheritDoc */ public function execute($params = []) { $promise = Promise::doResolve($params); return $promise->then(function ($params) { return $this->command($params); }); }
/** * @override * @inheritDoc */ public function solve($ex, $params = []) { foreach ($this->requires as $require) { if (!isset($params[$require])) { return Promise::doReject(new IllegalCallException('Missing parameter [' . $require . '] for [' . get_class($this) . '].')); } } return Promise::doResolve($this->solver($ex, $params)); }
/** * Handler to be called when solver is requested. * * @param Error|Exception|string $ex * @param mixed[] $params * @return mixed * @throws RejectionException */ protected function solver($ex, $params = []) { $promise = Promise::doResolve(); foreach ($this->handlers as $handler) { $current = $handler; $promise = $promise->then(function () use($ex, $params, $current) { return Promise::doResolve($current->solve($ex, $params)); }); } return $promise; }
/** * @param Error|Exception $ex * @param mixed[] $params * @return mixed */ protected function solver($ex, $params = []) { $manager = $this->runtime->getManager(); $hash = isset($params['hash']) ? $params['hash'] : ''; $alias = $params['origin']; if ($manager->existsThread($alias)) { return $manager->createThread($alias, null, Runtime::CREATE_FORCE, ['hash' => $hash]); } else { if ($manager->existsProcess($alias)) { return $manager->createProcess($alias, null, Runtime::CREATE_FORCE, ['hash' => $hash]); } } return Promise::doReject(new RejectionException("Runtime [{$alias}] does not exists.")); }
/** * @override * @inheritDoc */ protected function command($params = []) { $runtime = $this->runtime; $channel = $this->channel; $promise = Promise::doResolve(); return $promise->then(function () use($runtime) { return $runtime->getManager()->getRuntimes(); })->then(function ($children) use($channel) { $promises = []; foreach ($children as $childAlias) { $req = $this->createRequest($channel, $childAlias, new RuntimeCommand('arch:status')); $promises[] = $req->call(); } return Promise::all($promises); })->then(function ($childrenData) use($runtime) { return ['parent' => $runtime->getParent(), 'alias' => $runtime->getAlias(), 'name' => $runtime->getName(), 'state' => $runtime->getState(), 'children' => $childrenData]; }); }
/** * @override * @inheritDoc */ protected function command($params = []) { $runtime = $this->runtime; $channel = $this->channel; $promise = $this->runtime->start(); return $promise->then(function () use($runtime) { return $runtime->getManager()->getRuntimes(); })->then(function ($children) use($channel) { $promises = []; foreach ($children as $childAlias) { $req = $this->createRequest($channel, $childAlias, new RuntimeCommand('arch:start')); $promises[] = $req->call(); } return Promise::all($promises); })->then(function () { return 'Part of architecture has been started.'; }, function () { throw new RejectionException('Part of architecture could not be started.'); }); }
/** * @override * @inheritDoc */ public function flushRuntimes($flags = Runtime::DESTROY_KEEP) { return Promise::all([$this->flushThreads($flags), $this->flushProcesses($flags)]); }
/** * @override * @inheritDoc */ public function always(callable $onFulfilledOrRejected) { return $this->then(null, function ($reason) use($onFulfilledOrRejected) { return Promise::doResolve($onFulfilledOrRejected())->then(function () use($reason) { return new static($reason); }); }); }
/** * */ public function testApiSolver_RejectsPromise_OnFirstRejection() { $ex1 = new Exception('Exception'); $ex2 = new Exception('Other Exception'); $params = ['params1' => 'value1']; $queue = ''; $solver1 = $this->getMock(SolverInterface::class, [], [], '', false); $solver1->expects($this->once())->method('solve')->with($ex1, $params)->will($this->returnCallback(function () use(&$queue, $ex2) { $queue .= 'A'; return Promise::doReject($ex2); })); $solver2 = $this->getMock(SolverInterface::class, [], [], '', false); $solver2->expects($this->never())->method('solve')->with($ex1, $params)->will($this->returnCallback(function () use(&$queue) { $queue .= 'B'; })); $solver3 = $this->getMock(SolverInterface::class, [], [], '', false); $solver3->expects($this->never())->method('solve')->with($ex1, $params)->will($this->returnCallback(function () use(&$queue) { $queue .= 'C'; })); $solver = $this->createSolver([$solver1, $solver2, $solver3]); $callable = $this->createCallableMock(); $callable->expects($this->once())->method('__invoke')->with($ex2); $result = $this->callProtectedMethod($solver, 'solver', [$ex1, $params]); $result->then(null, $callable); $this->assertSame('A', $queue); }
/** * */ public function testApiReduce_CancelsPromisedInputValues() { $test = $this->getTest(); $p1 = (new Deferred())->getPromise(); $p2 = (new Deferred())->getPromise(); $p1->then(null, null, $test->expectCallableOnce()); $p2->then(null, null, $test->expectCallableOnce()); Promise::reduce([$p1, $p2], $this->plus(), 1)->cancel(); }
/** * @override * @inheritDoc */ public function destroyProject($flags = Runtime::DESTROY_FORCE_SOFT) { if (!isset($this->data['pid'])) { return Promise::doResolve("Project was not needed to be destroyed, because it had not existed."); } $manager = $this; $pid = $this->data['pid']; $alias = $this->data['alias']; $name = $this->data['name']; if ($flags === Runtime::DESTROY_KEEP) { return Promise::doReject(new ResourceOccupiedException("Project could not be destroyed with force level=DESTROY_KEEP.")); } else { if ($flags === Runtime::DESTROY_FORCE_SOFT) { $req = $this->createRequest($this->channel, $alias, new RuntimeCommand('container:destroy')); return $req->call()->then(function ($value) use($manager) { usleep(1000.0); $manager->freeProject(); return $value; }); } else { if ($flags === Runtime::DESTROY_FORCE) { return $this->destroyProject(Runtime::DESTROY_FORCE_SOFT)->then(null, function () use($manager) { return $manager->destroyProject(Runtime::DESTROY_FORCE_HARD); }); } } } if (!$this->system->existsPid($pid)) { return Promise::doResolve()->then(function () use($manager) { $manager->freeProject(); return "Project was not needed to be destroyed, because it had not existed."; }); } else { if (!$this->system->kill($pid)) { return Promise::doReject(new ResourceOccupiedException("Project could not be killed forcefully.")); } } return Promise::doResolve()->then(function () use($manager) { $manager->freeProject(); return "Process has been destroyed!"; }); }
/** * @override * @inheritDoc */ public function stop() { $state = $this->getState(); if ($state === Runtime::STATE_CREATED || $state === Runtime::STATE_DESTROYED) { return Promise::doReject(new RejectionException("It is not possible to stop runtime from state [{$state}].")); } else { if ($state === Runtime::STATE_STOPPED) { return Promise::doResolve('Runtime has been already stopped.'); } } $this->setState(Runtime::STATE_STOPPED); $emitter = $this->getEventEmitter(); $emitter->emit('beforeStop'); $emitter->emit('stop'); $emitter->emit('afterStop'); return Promise::doResolve('Runtime has been stopped.'); }
/** * @override * @inheritDoc */ public function flushThreads($flags = Runtime::DESTROY_KEEP) { return Promise::doReject(new RejectionException('Threads storage cannot be flushed.')); }
/** * @param Error|Exception $ex * @param mixed[] $params * @return mixed */ protected function solver($ex, $params = []) { $this->runtime->fail($ex, $params); return Promise::doResolve('Runtime has handled failure.'); }
/** * @param InputInterface $input * @param OutputInterface $output * @return int|null|void */ protected function execute(InputInterface $input, OutputInterface $output) { $this->onStart(); $promise = Promise::doResolve($this->command($input, $output)); $promise->then(function ($value) { return $this->onSuccess($value); }, function ($ex) { return $this->onFailure($ex); }, function ($ex) { return $this->onCancel($ex); })->always(function () { $this->onStop(); }); }
/** * */ public function testApiRetryOrReset_RejectsPromiseInRetry_WhenRetriesLimitIsReached() { $req = $this->createRequest($name = 'name', $mssg = 'secret', ['retriesLimit' => 0]); $ex = new Exception(); $promise = new Promise(); $callable = $this->createCallableMock(); $callable->expects($this->once())->method('__invoke')->with($this->isInstanceOf(TimeoutException::class)); $promise->then(null, $callable); $this->callProtectedMethod($req, 'retryOrReset', [$promise, $ex]); }
/** * @override * @inheritDoc */ public function solve($ex, $params = [], &$try = 0) { $classBaseEx = get_class($ex); $classes = array_merge([$classBaseEx], class_parents($ex)); $indexMin = -1; $chosen = null; foreach ($classes as $class) { $indexCurrent = array_search($class, array_keys($this->rules), true); if ($indexCurrent !== false && ($indexMin === -1 || $indexCurrent < $indexMin)) { $indexMin = $indexCurrent; $chosen = $class; } } if ($chosen === null) { return Promise::doReject(new ExecutionException("SolverInterface for [{$classBaseEx}] is not registered.")); } $try++; $params = array_merge($this->params, $params); $valueOrPromise = $this->getSolver($chosen)->solve($ex, $params); return Promise::doResolve($valueOrPromise); }
/** * */ public function testApiDoReject_ReturnsPromise() { $test = $this->getTest(); $test->assertInstanceOf(PromiseInterface::class, Promise::doReject(1)); }
/** * @return callable */ protected function promiseMapper() { return function ($val) { return Promise::doResolve($val * 2); }; }
/** * */ public function testApiSpread_Returns_FromRejectionHandler_ForRejectedPromise() { $deferred = $this->createDeferred(); $test = $this->getTest(); $ex = new Exception('Error'); $mock = $test->createCallableMock(); $mock->expects($test->once())->method('__invoke')->with($test->identicalTo($ex)); $deferred->reject(); $deferred->getPromise()->spread(null, function () use($ex) { return Promise::doReject($ex); })->then(null, $mock); }
/** * @param string $command * @param mixed[] $params * @return PromiseInterface * @resolves mixed * @rejects Error|Exception|string|null * @cancels Error|Exception|string|null */ private function executeCommand($command, $params = []) { try { return $this->commander->execute($command, $params); } catch (Error $ex) { return Promise::doReject($ex); } catch (Exception $ex) { return Promise::doReject($ex); } }
/** * */ public function testApiResolve_Returns_FromFulfillmentHandler() { $deferred = $this->createDeferred(); $test = $this->getTest(); $value = 5; $mock = $test->createCallableMock(); $mock->expects($test->once())->method('__invoke')->with($test->identicalTo($value)); $deferred->getPromise()->spread(function () use($value) { return Promise::doResolve($value); })->then($mock); $deferred->resolve(); }
/** * */ public function testApiSome_CancelsPendingInputArrayPromises_IfEnoughPromisesReject() { $test = $this->getTest(); $mock = $test->createCallableMock(); $mock->expects($test->never())->method('__invoke'); $deferred = new Deferred($mock); $deferred->reject(); $mock2 = $test->getMock(PromiseInterface::class); $mock2->expects($test->once())->method('cancel'); Promise::some([$deferred->getPromise(), $mock2], 2); }
/** * @override * @inheritDoc */ public function flushProcesses($flags = Runtime::DESTROY_KEEP) { $promises = []; if ($flags === Runtime::DESTROY_KEEP) { return Promise::doReject(new RejectionException('Process storage could not be flushed because of force level set to DESTROY_KEEP.')); } foreach ($this->processes as $alias => $process) { $promises[] = $this->destroyProcess($alias, $flags); } return Promise::all($promises)->then(function () { $this->processes = []; $this->updateStorage(); return 'Processes storage has been flushed.'; }); }
/** * @override * @inheritDoc */ public function always(callable $onFulfilledOrRejected) { return $this->then(function ($value) use($onFulfilledOrRejected) { return Promise::doResolve($onFulfilledOrRejected())->then(function () use($value) { return $value; }); }); }
/** * */ public function testApiCancel_CancelsPendingInputArrayPromises_IfOnePromiseFulfills() { $test = $this->getTest(); $deferred = new Deferred(); $deferred->resolve(); $mock = $test->createCallableMock(); $mock->expects($test->never())->method('__invoke'); $promise = $deferred->getPromise(); $promise->then(null, null, $mock); $mock2 = $test->getMock(PromiseInterface::class); $mock2->expects($test->once())->method('cancel'); Promise::some([$promise, $mock2], 1)->cancel(); }
/** * @override * @inheritDoc */ public function flushProcesses($flags = Runtime::DESTROY_KEEP) { return Promise::doResolve("Processes have been flushed."); }