blob: 5e8948d7bdb0f0b9e84195a66753ee70c05fe903 [file] [log] [blame]
<?php
namespace apache\shindig\test\gadgets;
use apache\shindig\gadgets\MakeRequest;
use apache\shindig\gadgets\GadgetContext;
use apache\shindig\common\RemoteContentRequest;
use apache\shindig\gadgets\MakeRequestOptions;
use apache\shindig\common\RemoteContentFetcher;
use apache\shindig\common\sample\BasicSecurityToken;
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* Provides an implementation of RemoteContentFetcher which can be controlled
* by unit tests and does not actually make any external requests.
* RemoteContentRequest objects added to this class are added to an internal
* FIFO queue. Every time a request is sent to fetchRequest, the next
* RemoteContentRequest object in the queue is returned as a response.
* Requests sent to fetchRequest are also stored in a queue for later retrieval
* and examination.
*/
class MockMakeRequestFetcher extends RemoteContentFetcher {
private $responses;
private $requests;
/**
* Constructor.
*/
public function __construct() {
$_SERVER["HTTP_HOST"] = 'localhost';
date_default_timezone_set('GMT');
$this->responses = array();
$this->requests = array();
}
/**
* Adds a response object to an internal queue of responses.
* @param RemoteContentRequest $response The response to return.
*/
public function enqueueResponse(RemoteContentRequest $response) {
$this->responses[] = $response;
}
/**
* Returns a request object that was sent to fetchRequest. If multiple
* requests have been sent to fetchRequest, they are returned by this
* method in the order they were requested.
* @return RemoteContentRequest
*/
public function dequeueRequest() {
return array_shift($this->requests);
}
/**
* Fakes a content request to a remote server.
* @param RemoteContentRequest $request The external request information.
* @return RemoteContentRequest The next response which was enqueued by
* calling enqueueResponse.
*/
public function fetchRequest(RemoteContentRequest $request) {
$this->requests[] = $request;
return array_shift($this->responses);
}
/**
* Fakes multiple requests to a remote server. Calls fetchRequest for
* each request passed to this method.
* @param array $requests An array of RemoteContentRequests.
* @return An array of RemoteContentRequests corresponging to the responses
* returned for each of the request inputs.
*/
public function multiFetchRequest(Array $requests) {
$responses = array();
foreach ($requests as $key => $request) {
$responses[$key] = $this->fetchRequest($request);
}
return $responses;
}
}
/**
* Unit tests for the MakeRequest class.
*/
class MakeRequestTest extends \PHPUnit_Framework_TestCase {
private $fetcher;
private $makeRequest;
private $context;
private $response;
/**
* Prepares the environment before running a test.
*/
protected function setUp() {
parent::setUp();
$this->fetcher = new MockMakeRequestFetcher();
$this->makeRequest = new MakeRequest($this->fetcher);
$this->context = new GadgetContext('GADGET');
$this->response = new RemoteContentRequest('http://www.example.com');
$this->response->setHttpCode(200);
$this->response->setResponseContent("Basic response");
}
/**
* Cleans up the environment after running a test.
*/
protected function tearDown() {
parent::tearDown();
}
/**
* Executes a makeRequest call and returns the request object which would
* have been sent externally (as opposed to the response).
*
* @param MakeRequestOptions $params
* @param RemoteContentRequest $response The response to return for this
* request.
* @return RemoteContentRequest The request object.
*/
protected function catchRequest(MakeRequestOptions $params, RemoteContentRequest $response) {
$this->fetcher->enqueueResponse($response);
$result = $this->makeRequest->fetch($this->context, $params);
return $this->fetcher->dequeueRequest();
}
/**
* Tests that makeRequest calls with an invalid url throw an exception.
*/
public function testInvalidUrl() {
try {
$params = new MakeRequestOptions('invalidurl');
$this->makeRequest->fetch($params);
$this->fail("Calling makeRequest with an invalid url should throw an exception.");
} catch (\Exception $ex) { }
}
/**
* Tests that normal requests specify a GET to the supplied URL.
*/
public function testBasicRequest() {
$params = new MakeRequestOptions('http://www.example.com');
$params->setNoCache(true);
$request = $this->catchRequest($params, $this->response);
$this->assertContains($request->getUrl(), 'http://www.example.com');
$this->assertEquals('GET', $request->getMethod());
}
/**
* Tests that signed requests generate appropriate oauth_ and opensocial_
* parameters.
*/
public function testSignedRequest() {
$token = BasicSecurityToken::createFromValues('owner', 'viewer', 'app', 'domain', 'appUrl', '1', 'default');
$params = new MakeRequestOptions('http://www.example.com');
$params->setAuthz('SIGNED')
->setNoCache(true)
->setSecurityTokenString(urldecode($token->toSerialForm()));
$request = $this->catchRequest($params, $this->response);
$this->assertContains('oauth_signature', $request->getUrl());
$this->assertContains('oauth_signature_method=RSA-SHA1', $request->getUrl());
$this->assertContains('opensocial_app_url=appUrl', $request->getUrl());
$this->assertContains('opensocial_viewer_id=viewer', $request->getUrl());
$this->assertContains('opensocial_owner_id=owner', $request->getUrl());
$this->assertEquals('GET', $request->getMethod());
}
/**
* Tests that setting "sign_viewer" = false does not include viewer
* information in the request.
*/
public function testSignedNoViewerRequest() {
$token = BasicSecurityToken::createFromValues('owner', 'viewer', 'app', 'domain', 'appUrl', '1', 'default');
$params = new MakeRequestOptions('http://www.example.com');
$params->setAuthz('SIGNED')
->setNoCache(true)
->setSignViewer(false)
->setSecurityTokenString(urldecode($token->toSerialForm()));
$request = $this->catchRequest($params, $this->response);
$this->assertContains('oauth_signature', $request->getUrl());
$this->assertNotContains('opensocial_viewer_id=viewer', $request->getUrl());
$this->assertContains('opensocial_owner_id=owner', $request->getUrl());
}
/**
* Tests that setting "format" = "FEED" parses an atom feed into a JSON
* structure.
*/
public function testFeedRequest() {
$params = new MakeRequestOptions('http://www.example.com');
$params->setResponseFormat('FEED')
->setNoCache(true)
->setNumEntries(2);
$sampleAtomPath = realpath(dirname(__FILE__) . "/../misc/sampleAtomFeed.xml");
$sampleAtom = file_get_contents($sampleAtomPath);
$this->response->setResponseContent($sampleAtom);
$this->fetcher->enqueueResponse($this->response);
$result = $this->makeRequest->fetch($this->context, $params);
$feedJson = json_decode($result->getResponseContent(), true);
$this->assertArrayHasKey('Entry', $feedJson);
$this->assertEquals(2, count($feedJson['Entry']));
$this->assertArrayHasKey('Title', $feedJson['Entry'][0]);
$this->assertEquals("Atom-Powered Robots Run Amok", $feedJson['Entry'][0]['Title']);
}
/**
* Tests that setting request headers are passed in the outgoing request.
*/
public function testRequestHeaders(){
$params = new MakeRequestOptions('http://www.example.com');
$params->setRequestHeaders(array(
"Content-Type" => "application/json",
"Accept-Language" => "en-us"
));
$params->setNoCache(true);
$request = $this->catchRequest($params, $this->response);
$this->assertTrue($request->hasHeaders());
$this->assertEquals('application/json', $request->getHeader('Content-Type'));
$this->assertEquals('en-us', $request->getHeader('Accept-Language'));
}
/**
* Tests that setting invalid request headers are not passed in the outgoing
* request.
*/
public function testInvalidRequestHeaders(){
$params = new MakeRequestOptions('http://www.example.com');
$params->setRequestHeaders(array(
"Content-Type" => "application/json",
"Accept-Language" => "en-us",
"Host" => "http://www.evil.com",
"host" => "http://www.evil.com",
"HOST" => "http://www.evil.com",
"Accept" => "blah",
"Accept-Encoding" => "blah"
));
$params->setNoCache(true);
$request = $this->catchRequest($params, $this->response);
$this->assertTrue($request->hasHeaders());
$this->assertEquals('application/json', $request->getHeader('Content-Type'));
$this->assertEquals('en-us', $request->getHeader('Accept-Language'));
$this->assertNull($request->getHeader('Host'));
$this->assertNull($request->getHeader('Accept'));
$this->assertNull($request->getHeader('Accept-Encoding'));
}
/**
* Tests that setting request headers in a form urlencoded way are passed in the outgoing request.
*/
public function testFormEncodedRequestHeaders(){
$params = new MakeRequestOptions('http://www.example.com');
$params->setFormEncodedRequestHeaders("Content-Type=application%2Fx-www-form-urlencoded&Accept-Language=en-us");
$params->setNoCache(true);
$request = $this->catchRequest($params, $this->response);
$this->assertTrue($request->hasHeaders());
$this->assertEquals('application/x-www-form-urlencoded', $request->getHeader('Content-Type'));
}
public function testResponseHeaders() {
$params = new MakeRequestOptions('http://www.example.com');
$params->setNoCache(true);
$headers = array(
'Content-Type' => 'text/plain'
);
$this->response->setResponseHeaders($headers);
$this->fetcher->enqueueResponse($this->response);
$result = $this->makeRequest->fetch($this->context, $params);
$response_headers = $result->getResponseHeaders();
$this->assertArrayHasKey('Content-Type', $response_headers);
$this->assertEquals('text/plain', $response_headers['Content-Type']);
}
public function testCleanResponseHeaders() {
$response_headers = array(
'Content-Type' => 'text/plain',
'Set-Cookie' => 'blah',
'set-cookie' => 'blah',
'SET-COOKIE' => 'blah',
'sEt-cOoKiE' => 'blah',
'Accept-Ranges' => 'blah',
'Vary' => 'blah',
'Expires' => 'blah',
'Date' => 'blah',
'Pragma' => 'blah',
'Cache-Control' => 'blah',
'Transfer-Encoding' => 'blah',
'WWW-Authenticate' => 'blah'
);
$cleaned_headers = $this->makeRequest->cleanResponseHeaders($response_headers);
$this->assertArrayHasKey('Content-Type', $cleaned_headers);
$this->assertEquals('text/plain', $cleaned_headers['Content-Type']);
$this->assertArrayNotHasKey('Set-Cookie', $cleaned_headers);
$this->assertArrayNotHasKey('set-cookie', $cleaned_headers);
$this->assertArrayNotHasKey('SET-COOKIE', $cleaned_headers);
$this->assertArrayNotHasKey('sEt-cOoKiE', $cleaned_headers);
$this->assertArrayNotHasKey('Accept-Ranges', $cleaned_headers);
$this->assertArrayNotHasKey('Vary', $cleaned_headers);
$this->assertArrayNotHasKey('Expires', $cleaned_headers);
$this->assertArrayNotHasKey('Date', $cleaned_headers);
$this->assertArrayNotHasKey('Pragma', $cleaned_headers);
$this->assertArrayNotHasKey('Cache-Control', $cleaned_headers);
$this->assertArrayNotHasKey('Transfer-Encoding', $cleaned_headers);
$this->assertArrayNotHasKey('WWW-Authenticate', $cleaned_headers);
}
}