Skip to content

Commit

Permalink
add async wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamie Hannaford committed Nov 24, 2015
1 parent 6bcf7ac commit 9715be7
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 0 deletions.
35 changes: 35 additions & 0 deletions src/Common/Api/Operator.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use function GuzzleHttp\uri_template;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Promise\Promise;
use OpenStack\Common\Resource\ResourceInterface;
use OpenStack\Common\Transport\RequestSerializer;
use Psr\Http\Message\ResponseInterface;
Expand Down Expand Up @@ -126,4 +127,38 @@ protected function getHttpBaseUrl()
{
return $this->client->getConfig('base_url');
}

/**
* Magic method which intercepts async calls, finds the sequential version, and wraps it in a
* {@see Promise} object. In order for this to happen, the called methods need to be in the
* following format: `createAsync`, where `create` is the sequential method being wrapped.
*
* @param $methodName The name of the method being invoked.
* @param $args The arguments to be passed to the sequential method.
*
* @return Promise
*/
public function __call($methodName, $args)
{
if (substr($methodName, -5) === 'Async') {
$realMethod = substr($methodName, 0, -5);
if (!method_exists($this, $realMethod)) {
throw new \InvalidArgumentException(sprintf(
'%s is not a defined method on %s', $realMethod, get_class($this)
));
}

$promise = new Promise(
function () use (&$promise, $realMethod, $args) {
$value = call_user_func_array([$this, $realMethod], $args);
$promise->resolve($value);
},
function ($e) use (&$promise) {
$promise->reject($e);
}
);

return $promise;
}
}
}
26 changes: 26 additions & 0 deletions tests/unit/Common/Api/OperatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace OpenStack\Test\Common\Api;

use GuzzleHttp\ClientInterface;
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use OpenStack\Common\Api\Operator;
Expand Down Expand Up @@ -62,8 +63,33 @@ public function test_it_populates_models_from_arrays()
$data = ['flavor' => [], 'image' => []];
$this->assertInstanceOf(ResourceInterface::class, $this->operator->model(Server::class, $data));
}

public function test_it_wraps_sequential_ops_in_promise_when_async_is_appended_to_method_name()
{
$promise = $this->operator->createAsync('something');

$this->assertInstanceOf(Promise::class, $promise);

$promise->then(function ($val) {
$this->assertEquals('Created something', $val);
});

$promise->wait();
}

/**
* @expectedException \InvalidArgumentException
*/
public function test_it_throws_exception_when_async_is_called_on_a_non_existent_method()
{
$this->operator->fooAsync();
}
}

class TestOperator extends Operator
{
public function create($str)
{
return 'Created ' . $str;
}
}

0 comments on commit 9715be7

Please sign in to comment.