Permalink
Browse files

The OAuth2\Client class has now been fully tested and consequently so…

…me bugs were corrected during this test phase
  • Loading branch information...
1 parent 5df4410 commit 61d9ebc34e64465bf9b1d28f7aeb0013a883a7cf @keeguon committed Jan 12, 2012
Showing with 232 additions and 18 deletions.
  1. +0 −1 .gitignore
  2. +17 −9 src/OAuth2/Client.php
  3. +2 −1 src/OAuth2/Error.php
  4. +2 −2 src/OAuth2/Response.php
  5. +206 −5 tests/OAuth2/Tests/ClientTest.php
  6. +5 −0 tests/bootstrap.php
View
@@ -3,7 +3,6 @@
*.sw[a-z]
# Other files
-autoload.php
composer.phar
phpunit.xml
View
@@ -4,13 +4,10 @@
class Client
{
- protected
- $options = array()
- ;
-
public
$connection = null
, $id = ''
+ , $options = ''
, $secret = ''
, $site = ''
;
@@ -57,7 +54,8 @@ public function auth_code()
*/
public function authorize_url($params = array())
{
- return (strpos($this->options['authorize_url'], 'http') === 0) ? $this->options['authorize_url'].'?'.http_build_query($params) : $this->site.$this->options['authorize_url'].'?'.http_build_query($params);
+ $authorize_url = (strpos($this->options['authorize_url'], 'http') === 0) ? $this->options['authorize_url'] : $this->site.$this->options['authorize_url'];
+ return (count($params)) ? $authorize_url.'?'.http_build_query($params) : $authorize_url;
}
/**
@@ -153,15 +151,24 @@ public function request($verb, $url, $opts = array())
break;
}
- // Custom cURL options
- $request->getCurlOptions()->set(CURLOPT_MAXREDIRS, isset($this->options['max_redirects']) ? $this->options['max_redirects'] : 0);
-
// Send request and use the returned HttpMessage to create an \OAuth2\Response object
$response = new \OAuth2\Response($request->send(), array('parse' => $opts['parse']));
// Response handling
if (in_array($response->status(), range(200, 299))) {
return $response;
+ } else if (in_array($response->status(), range(300, 399))) {
+ $opts['redirect_count'] = $opts['redirect_count'] || 0;
+ $opts['redirect_count'] += 1;
+ if ($opts['redirect_count'] > $this->options['max_redirects']) {
+ return $response;
+ }
+ if ($response->status() === 303) {
+ $verb = 'GET';
+ $opts['body'] = '';
+ }
+ $headers = $response->headers();
+ $this->request($verb, $headers['location'], $opts);
} else if (in_array($response->status(), range(400, 599))) {
$e = new \OAuth2\Error($response);
if ($opts['raise_errors'] || $this->options['raise_errors']) {
@@ -182,6 +189,7 @@ public function request($verb, $url, $opts = array())
*/
public function token_url($params = array())
{
- return $this->options['token_url'].'?'.http_build_query($params);
+ $token_url = (strpos($this->options['token_url'], 'http') === 0) ? $this->options['token_url'] : $this->site.$this->options['token_url'];
+ return (count($params)) ? $token_url.'?'.http_build_query($params) : $token_url;
}
}
View
@@ -7,8 +7,9 @@ class Error extends \Exception
protected
$code = 0
, $message = ''
- , $response = null
;
+
+ public $response = null;
/**
* Construct the OAuth 2 error using a response object
View
@@ -19,12 +19,12 @@ public function __construct($response, $opts = array())
public function body()
{
- return $this->response->getBody();
+ return $this->response->getBody(true);
}
public function content_type()
{
- return $this->response->getContent-Type();
+ return $this->response->getContentType();
}
public function headers()
@@ -4,18 +4,219 @@
class ClientTest extends \PHPUnit_Framework_TestCase
{
- protected $client;
+ /**
+ * @var Client
+ */
+ protected
+ $client = null
+ , $error_value = 'invalid_token'
+ , $error_description_value = 'bad bad token'
+ ;
+ /**
+ * Sets up the fixture, here, creating a new client.
+ * This method is called before a test is executed.
+ */
protected function setUp()
{
- $this->client = new \OAuth2\Client('abc', 'def', array(
- 'redirect_uri' => 'http://multipass.local/callback'
- ));
+ // mock client object
+ $this->client = $this->getMock('\OAuth2\Client', array('request'), array('client_id' => 'abc', 'client_secret' => 'def', 'opts' => array('site' => 'https://api.example.com')));
+
+ // configure mocked client
+ $this->client->expects($this->any())
+ ->method('request')
+ ->will($this->returnCallback(array($this, 'mockRequest')));
}
- public function testConstructor()
+ protected function tearDown()
{
+ unset($this->client);
+ }
+
+ /**
+ * @covers OAuth2\Client::__construct()
+ */
+ public function testConstructorBuildsClient()
+ {
+ // client id and secret should be assigned
$this->assertEquals('abc', $this->client->id);
$this->assertEquals('def', $this->client->secret);
+
+ // client site should be assigned
+ $this->assertEquals('https://api.example.com', $this->client->site);
+
+ // connection baseUrl should be assigned
+ $this->assertEquals('https://api.example.com', $this->client->connection->getBaseUrl());
+
+ // raise_error option should be true
+ $this->assertTrue($this->client->options['raise_errors']);
+
+ // allows true/false for raise_error option
+ $client = new \OAuth2\Client('abc', 'def', array('site' => 'https://api.example.com', 'raise_errors' => false));
+ $this->assertFalse($client->options['raise_errors']);
+ $client = new \OAuth2\Client('abc', 'def', array('site' => 'https://api.example.com', 'raise_errors' => true));
+ $this->assertTrue($client->options['raise_errors']);
+
+ // allow GET/POST for token_method option
+ $client = new \OAuth2\Client('abc', 'def', array('site' => 'https://api.example.com', 'token_method' => 'GET'));
+ $this->assertEquals('GET', $client->options['token_method']);
+ $client = new \OAuth2\Client('abc', 'def', array('site' => 'https://api.example.com', 'token_method' => 'POST'));
+ $this->assertEquals('POST', $client->options['token_method']);
+ }
+
+ /**
+ * @covers OAuth2\Client::authorize_url()
+ * @covers OAuth2\Client::token_url()
+ */
+ public function testUrlsEnpoints()
+ {
+ foreach (array('authorize', 'token') as $url_type) {
+ // {$url_type}_url should default to /oauth/{$url_type}
+ $this->assertEquals("https://api.example.com/oauth/{$url_type}", call_user_func(array($this->client, "{$url_type}_url")));
+
+ // {$url_type}_url should be settable via the {$url_type}_url option
+ $this->client->options["{$url_type}_url"] = '/oauth/custom';
+ $this->assertEquals("https://api.example.com/oauth/custom", call_user_func(array($this->client, "{$url_type}_url")));
+
+ // allows a different host than the site
+ $this->client->options["{$url_type}_url"] = 'https://api.foo.com/oauth/custom';
+ $this->assertEquals("https://api.foo.com/oauth/custom", call_user_func(array($this->client, "{$url_type}_url")));
+ }
+ }
+
+ /**
+ * @covers OAuth2\Client::request()
+ */
+ public function testRequest()
+ {
+ // works with a null response body
+ $this->assertEmpty($this->client->request('GET', '/empty_get')->body());
+
+ // returns on a successful response body
+ $response = $this->client->request('GET', '/success');
+ $this->assertEquals('yay', $response->body());
+ $this->assertEquals(200, $response->status());
+ $this->assertEquals(array('Content-Type' => 'text/awesome'), $response->headers());
+
+ // posts a body
+ $response = $this->client->request('POST', '/reflect', array('body' => 'foo=bar'));
+ $this->assertEquals('foo=bar', $response->body());
+
+ // follows redirect properly
+ $response = $this->client->request('GET', '/redirect');
+ $this->assertEquals('yay', $response->body());
+ $this->assertEquals(200, $response->status());
+ $this->assertEquals(array('Content-Type' => 'text/awesome'), $response->headers());
+
+ // redirects using GET on a 303
+ $response = $this->client->request('POST', '/redirect', array('body' => 'foo=bar'));
+ $this->assertEmpty($response->body());
+ $this->assertEquals(200, $response->status());
+
+ // obeys the max_redirects option
+ $max_redirects = $this->client->options['max_redirects'];
+ $this->client->options['max_redirects'] = 0;
+ $response = $this->client->request('GET', '/redirect');
+ $this->assertEquals(302, $response->status());
+ $this->client->options['max_redirects'] = $max_redirects;
+
+ // returns if raise_errors is false
+ $this->client->options['raise_errors'] = false;
+ $response = $this->client->request('GET', '/unauthorized');
+ $this->assertEquals(401, $response->status());
+ $this->assertEquals(array('Content-Type' => 'application/json'), $response->headers());
+ $this->assertNotNull($response->error);
+
+ // test if exception are thrown when raise_errors is true
+ $this->client->options['raise_errors'] = true;
+ foreach (array('/unauthorized', '/conflict', '/error') as $error_path) {
+ // throw OAuth\Error on error response to path {$error_path}
+ $this->setExpectedException('\OAuth2\Error');
+ $this->client->request('GET', $error_path);
+ }
+
+ // parses OAuth2 standard error response
+ try {
+ $this->client->request('GET', '/error');
+ } catch (\OAuth2\Error $e) {
+ $this->assertEquals($this->error_value, $e->getCode());
+ $this->assertEquals($this->error_description_value, $e->getDescription());
+ }
+
+ // provides the response in the Exception
+ try {
+ $this->client->request('GET', '/error');
+ } catch (\OAuth2\Error $e) {
+ $this->assertNotNull($e->response);
+ }
+ }
+
+ /**
+ * @covers OAuth2\Client::auth_code()
+ */
+ public function testAuthCodeInstatiation()
+ {
+ // auth_code() should instantiate a AuthCode strategy with this client
+ $this->assertInstanceOf("\OAuth2\Strategy\AuthCode", $this->client->auth_code());
+ }
+
+ /**
+ * Callback method for mocked request
+ */
+ public function mockRequest()
+ {
+ // retrieve arguments
+ $args = func_get_args();
+
+ // default options
+ $opts = array_merge(array(
+ 'body' => ''
+ , 'headers' => array()
+ , 'raise_errors' => $this->client->options['raise_errors']
+ ), $args[2]);
+
+ // map routes
+ $map = array();
+ $map['GET']['/success'] = array('status' => 200, 'headers' => array('Content-Type' => 'text/awesome'), 'body' => 'yay');
+ $map['GET']['/reflect'] = array('status' => 200, 'headers' => array(), 'body' => $opts['body']);
+ $map['POST']['/reflect'] = array('status' => 200, 'headers' => array(), 'body' => $opts['body']);
+ $map['GET']['/unauthorized'] = array('status' => 401, 'headers' => array('Content-Type' => 'application/json'), 'body' => json_encode(array('error' => $this->error_value, 'error_description' => $this->error_description_value)));
+ $map['GET']['/conflict'] = array('status' => 409, 'headers' => array('Content-Type' => 'text/plain'), 'body' => 'not authorized');
+ $map['GET']['/redirect'] = array('status' => 302, 'headers' => array('Content-Type' => 'text/plain', 'location' => '/success'), 'body' => '');
+ $map['POST']['/redirect'] = array('status' => 303, 'headers' => array('Content-Type' => 'text/plain', 'location' => '/reflect'), 'body' => '');
+ $map['GET']['/error'] = array('status' => 500, 'headers' => array(), 'body' => '');
+ $map['GET']['/empty_get'] = array('status' => 200, 'headers' => array(), 'body' => '');
+
+ // match response
+ $response = $map[$args[0]][$args[1]];
+
+ // wrap response in an OAuth2\Response object
+ $response = new \OAuth2\Response(new \Guzzle\Http\Message\Response($response['status'], $response['headers'], $response['body']));
+
+ // handle response
+ if (in_array($response->status(), range(200, 299))) {
+ return $response;
+ } else if (in_array($response->status(), range(300, 399))) {
+ $opts['redirect_count'] = isset($opts['redirect_count']) ? $opts['redirect_count'] : 0;
+ $opts['redirect_count'] += 1;
+ if ($opts['redirect_count'] > $this->client->options['max_redirects']) {
+ return $response;
+ }
+ if ($response->status() === 303) {
+ $args[0] = 'GET';
+ $opts['body'] = '';
+ }
+ $headers = $response->headers();
+ return $this->client->request($args[0], $headers['location'], $opts);
+ } else if (in_array($response->status(), range(400, 599))) {
+ $e = new \OAuth2\Error($response);
+ if ($opts['raise_errors'] || $this->client->options['raise_errors']) {
+ throw $e;
+ }
+ $response->error = $e;
+ return $response;
+ } else {
+ throw new \OAuth2\Error($response);
+ }
}
}
View
@@ -1,3 +1,8 @@
<?php
+namespace OAuth2\Tests;
+
+error_reporting(E_ALL | E_STRICT);
+
+require_once 'PHPUnit/TextUI/TestRunner.php';
require_once __DIR__.'/../autoload.php';

0 comments on commit 61d9ebc

Please sign in to comment.