summaryrefslogtreecommitdiffstats
path: root/content/child/resource_dispatcher_unittest.cc
diff options
context:
space:
mode:
authormmenke@chromium.org <mmenke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-16 19:10:14 +0000
committermmenke@chromium.org <mmenke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-16 19:10:14 +0000
commit0a0e2c7bd89b164298c31eaa89853da10df0d3cf (patch)
treeb8362ead5b5065b5a21bcd695b6fb11225f3c7c9 /content/child/resource_dispatcher_unittest.cc
parentcef56eabc38047340ea3229e85506afcd187984e (diff)
downloadchromium_src-0a0e2c7bd89b164298c31eaa89853da10df0d3cf.zip
chromium_src-0a0e2c7bd89b164298c31eaa89853da10df0d3cf.tar.gz
chromium_src-0a0e2c7bd89b164298c31eaa89853da10df0d3cf.tar.bz2
Fix a potential file handle leak in ResourceDispatcher
when cancelling a request being downloaded to a file. Also add a bunch of ResourceDispatcher tests. BUG=384507 Review URL: https://codereview.chromium.org/330903003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@277514 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/child/resource_dispatcher_unittest.cc')
-rw-r--r--content/child/resource_dispatcher_unittest.cc727
1 files changed, 549 insertions, 178 deletions
diff --git a/content/child/resource_dispatcher_unittest.cc b/content/child/resource_dispatcher_unittest.cc
index 0cbd7d1..86dc17f 100644
--- a/content/child/resource_dispatcher_unittest.cc
+++ b/content/child/resource_dispatcher_unittest.cc
@@ -5,11 +5,14 @@
#include <string>
#include <vector>
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/shared_memory.h"
#include "base/message_loop/message_loop.h"
#include "base/process/process.h"
#include "base/process/process_handle.h"
#include "base/run_loop.h"
+#include "base/stl_util.h"
#include "content/child/request_extra_data.h"
#include "content/child/request_info.h"
#include "content/child/resource_dispatcher.h"
@@ -27,20 +30,30 @@ using webkit_glue::ResourceLoaderBridge;
namespace content {
-static const char test_page_url[] = "http://www.google.com/";
-static const char test_page_headers[] =
+static const char kTestPageUrl[] = "http://www.google.com/";
+static const char kTestPageHeaders[] =
"HTTP/1.1 200 OK\nContent-Type:text/html\n\n";
-static const char test_page_mime_type[] = "text/html";
-static const char test_page_charset[] = "";
-static const char test_page_contents[] =
+static const char kTestPageMimeType[] = "text/html";
+static const char kTestPageCharset[] = "";
+static const char kTestPageContents[] =
"<html><head><title>Google</title></head><body><h1>Google</h1></body></html>";
-static const uint32 test_page_contents_len = arraysize(test_page_contents) - 1;
+static const char kTestRedirectHeaders[] =
+ "HTTP/1.1 302 Found\nLocation:http://www.google.com/\n\n";
// Listens for request response data and stores it so that it can be compared
// to the reference data.
-class TestRequestCallback : public RequestPeer {
+class TestRequestPeer : public RequestPeer {
public:
- TestRequestCallback() : complete_(false) {
+ TestRequestPeer(ResourceLoaderBridge* bridge)
+ : follow_redirects_(true),
+ defer_on_redirect_(false),
+ seen_redirects_(0),
+ cancel_on_receive_response_(false),
+ received_response_(false),
+ total_encoded_data_length_(0),
+ total_downloaded_data_length_(0),
+ complete_(false),
+ bridge_(bridge) {
}
virtual void OnUploadProgress(uint64 position, uint64 size) OVERRIDE {
@@ -49,18 +62,28 @@ class TestRequestCallback : public RequestPeer {
virtual bool OnReceivedRedirect(const GURL& new_url,
const GURL& new_first_party_for_cookies,
const ResourceResponseInfo& info) OVERRIDE {
- return true;
+ ++seen_redirects_;
+ if (defer_on_redirect_)
+ bridge_->SetDefersLoading(true);
+ return follow_redirects_;
}
virtual void OnReceivedResponse(const ResourceResponseInfo& info) OVERRIDE {
+ EXPECT_FALSE(received_response_);
+ received_response_ = true;
+ if (cancel_on_receive_response_)
+ bridge_->Cancel();
}
virtual void OnDownloadedData(int len, int encoded_data_length) OVERRIDE {
+ total_downloaded_data_length_ += len;
+ total_encoded_data_length_ += encoded_data_length;
}
virtual void OnReceivedData(const char* data,
int data_length,
int encoded_data_length) OVERRIDE {
+ EXPECT_TRUE(received_response_);
EXPECT_FALSE(complete_);
data_.append(data, data_length);
total_encoded_data_length_ += encoded_data_length;
@@ -73,30 +96,75 @@ class TestRequestCallback : public RequestPeer {
const std::string& security_info,
const base::TimeTicks& completion_time,
int64 total_transfer_size) OVERRIDE {
+ EXPECT_TRUE(received_response_);
EXPECT_FALSE(complete_);
complete_ = true;
}
- bool complete() const {
- return complete_;
+ void set_follow_redirects(bool follow_redirects) {
+ follow_redirects_ = follow_redirects;
+ }
+
+ void set_defer_on_redirect(bool defer_on_redirect) {
+ defer_on_redirect_ = defer_on_redirect;
}
+
+ void set_cancel_on_receive_response(bool cancel_on_receive_response) {
+ cancel_on_receive_response_ = cancel_on_receive_response;
+ }
+
+ int seen_redirects() const { return seen_redirects_; }
+
+ bool received_response() const { return received_response_; }
+
const std::string& data() const {
return data_;
}
int total_encoded_data_length() const {
return total_encoded_data_length_;
}
+ int total_downloaded_data_length() const {
+ return total_downloaded_data_length_;
+ }
+
+ bool complete() const { return complete_; }
private:
- bool complete_;
+ // True if should follow redirects, false if should cancel them.
+ bool follow_redirects_;
+ // True if the request should be deferred on redirects.
+ bool defer_on_redirect_;
+ // Number of total redirects seen.
+ int seen_redirects_;
+
+ bool cancel_on_receive_response_;
+ bool received_response_;
+
+ // Data received. If downloading to file, remains empty.
std::string data_;
+ // Total encoded data length, regardless of whether downloading to a file or
+ // not.
int total_encoded_data_length_;
-};
+ // Total length when downloading to a file.
+ int total_downloaded_data_length_;
+
+ bool complete_;
+ ResourceLoaderBridge* bridge_;
-// Sets up the message sender override for the unit test
+ DISALLOW_COPY_AND_ASSIGN(TestRequestPeer);
+};
+
+// Sets up the message sender override for the unit test.
class ResourceDispatcherTest : public testing::Test, public IPC::Sender {
public:
+ ResourceDispatcherTest() : dispatcher_(this) {}
+
+ virtual ~ResourceDispatcherTest() {
+ STLDeleteContainerPairSecondPointers(shared_memory_map_.begin(),
+ shared_memory_map_.end());
+ }
+
// Emulates IPC send operations (IPC::Sender) by adding
// pending messages to the queue.
virtual bool Send(IPC::Message* msg) OVERRIDE {
@@ -105,68 +173,159 @@ class ResourceDispatcherTest : public testing::Test, public IPC::Sender {
return true;
}
- // Emulates the browser process and processes the pending IPC messages,
- // returning the hardcoded file contents.
- void ProcessMessages() {
- while (!message_queue_.empty()) {
- ResourceHostMsg_RequestResource::Param params;
- ASSERT_TRUE(ResourceHostMsg_RequestResource::Read(
- &message_queue_[0], &params));
- int request_id = params.b;
- ResourceHostMsg_Request request = params.c;
-
- // check values
- EXPECT_EQ(test_page_url, request.url.spec());
-
- // received response message
- ResourceResponseHead response;
- std::string raw_headers(test_page_headers);
- std::replace(raw_headers.begin(), raw_headers.end(), '\n', '\0');
- response.headers = new net::HttpResponseHeaders(raw_headers);
- response.mime_type = test_page_mime_type;
- response.charset = test_page_charset;
- dispatcher_->OnReceivedResponse(request_id, response);
-
- // received data message with the test contents
- base::SharedMemory shared_mem;
- EXPECT_TRUE(shared_mem.CreateAndMapAnonymous(test_page_contents_len));
- char* put_data_here = static_cast<char*>(shared_mem.memory());
- memcpy(put_data_here, test_page_contents, test_page_contents_len);
- base::SharedMemoryHandle dup_handle;
- EXPECT_TRUE(shared_mem.GiveToProcess(
- base::Process::Current().handle(), &dup_handle));
- dispatcher_->OnSetDataBuffer(request_id, dup_handle,
- test_page_contents_len, 0);
- dispatcher_->OnReceivedData(request_id, 0, test_page_contents_len,
- test_page_contents_len);
-
- message_queue_.erase(message_queue_.begin());
-
- // read the ack message.
- Tuple1<int> request_ack;
- ASSERT_TRUE(ResourceHostMsg_DataReceived_ACK::Read(
- &message_queue_[0], &request_ack));
-
- ASSERT_EQ(request_ack.a, request_id);
-
- message_queue_.erase(message_queue_.begin());
+ size_t queued_messages() const { return message_queue_.size(); }
+
+ // Returns the ID of the consumed request. Can't make assumptions about the
+ // ID, because numbering is based on a global.
+ int ConsumeRequestResource() {
+ if (message_queue_.empty()) {
+ ADD_FAILURE() << "Missing resource request message";
+ return -1;
+ }
+
+ ResourceHostMsg_RequestResource::Param params;
+ if (ResourceHostMsg_RequestResource::ID != message_queue_[0].type() ||
+ !ResourceHostMsg_RequestResource::Read(&message_queue_[0], &params)) {
+ ADD_FAILURE() << "Expected ResourceHostMsg_RequestResource message";
+ return -1;
}
+ ResourceHostMsg_Request request = params.c;
+ EXPECT_EQ(kTestPageUrl, request.url.spec());
+ message_queue_.erase(message_queue_.begin());
+ return params.b;
+ }
+
+ void ConsumeFollowRedirect(int expected_request_id) {
+ ASSERT_FALSE(message_queue_.empty());
+ Tuple1<int> args;
+ ASSERT_EQ(ResourceHostMsg_FollowRedirect::ID, message_queue_[0].type());
+ ASSERT_TRUE(ResourceHostMsg_FollowRedirect::Read(
+ &message_queue_[0], &args));
+ EXPECT_EQ(expected_request_id, args.a);
+ message_queue_.erase(message_queue_.begin());
+ }
+
+ void ConsumeDataReceived_ACK(int expected_request_id) {
+ ASSERT_FALSE(message_queue_.empty());
+ Tuple1<int> args;
+ ASSERT_EQ(ResourceHostMsg_DataReceived_ACK::ID, message_queue_[0].type());
+ ASSERT_TRUE(ResourceHostMsg_DataReceived_ACK::Read(
+ &message_queue_[0], &args));
+ EXPECT_EQ(expected_request_id, args.a);
+ message_queue_.erase(message_queue_.begin());
+ }
+
+ void ConsumeDataDownloaded_ACK(int expected_request_id) {
+ ASSERT_FALSE(message_queue_.empty());
+ Tuple1<int> args;
+ ASSERT_EQ(ResourceHostMsg_DataDownloaded_ACK::ID, message_queue_[0].type());
+ ASSERT_TRUE(ResourceHostMsg_DataDownloaded_ACK::Read(
+ &message_queue_[0], &args));
+ EXPECT_EQ(expected_request_id, args.a);
+ message_queue_.erase(message_queue_.begin());
+ }
+
+ void ConsumeReleaseDownloadedFile(int expected_request_id) {
+ ASSERT_FALSE(message_queue_.empty());
+ Tuple1<int> args;
+ ASSERT_EQ(ResourceHostMsg_ReleaseDownloadedFile::ID,
+ message_queue_[0].type());
+ ASSERT_TRUE(ResourceHostMsg_ReleaseDownloadedFile::Read(
+ &message_queue_[0], &args));
+ EXPECT_EQ(expected_request_id, args.a);
+ message_queue_.erase(message_queue_.begin());
+ }
+
+ void ConsumeCancelRequest(int expected_request_id) {
+ ASSERT_FALSE(message_queue_.empty());
+ Tuple1<int> args;
+ ASSERT_EQ(ResourceHostMsg_CancelRequest::ID, message_queue_[0].type());
+ ASSERT_TRUE(ResourceHostMsg_CancelRequest::Read(
+ &message_queue_[0], &args));
+ EXPECT_EQ(expected_request_id, args.a);
+ message_queue_.erase(message_queue_.begin());
+ }
+
+ void NotifyReceivedRedirect(int request_id) {
+ ResourceResponseHead head;
+ std::string raw_headers(kTestRedirectHeaders);
+ std::replace(raw_headers.begin(), raw_headers.end(), '\n', '\0');
+ head.headers = new net::HttpResponseHeaders(raw_headers);
+ head.error_code = net::OK;
+ EXPECT_EQ(true, dispatcher_.OnMessageReceived(
+ ResourceMsg_ReceivedRedirect(request_id, GURL(kTestPageUrl),
+ GURL(kTestPageUrl), head)));
+ }
+
+ void NotifyReceivedResponse(int request_id) {
+ ResourceResponseHead head;
+ std::string raw_headers(kTestPageHeaders);
+ std::replace(raw_headers.begin(), raw_headers.end(), '\n', '\0');
+ head.headers = new net::HttpResponseHeaders(raw_headers);
+ head.mime_type = kTestPageMimeType;
+ head.charset = kTestPageCharset;
+ head.error_code = net::OK;
+ EXPECT_EQ(true,
+ dispatcher_.OnMessageReceived(
+ ResourceMsg_ReceivedResponse(request_id, head)));
+ }
+
+ void NotifySetDataBuffer(int request_id, size_t buffer_size) {
+ base::SharedMemory* shared_memory = new base::SharedMemory();
+ ASSERT_FALSE(shared_memory_map_[request_id]);
+ shared_memory_map_[request_id] = shared_memory;
+ EXPECT_TRUE(shared_memory->CreateAndMapAnonymous(buffer_size));
+
+ base::SharedMemoryHandle duplicate_handle;
+ EXPECT_TRUE(shared_memory->ShareToProcess(
+ base::Process::Current().handle(), &duplicate_handle));
+ EXPECT_TRUE(dispatcher_.OnMessageReceived(
+ ResourceMsg_SetDataBuffer(request_id, duplicate_handle,
+ shared_memory->requested_size(), 0)));
+ }
+
+ void NotifyDataReceived(int request_id, std::string data) {
+ ASSERT_LE(data.length(), shared_memory_map_[request_id]->requested_size());
+ memcpy(shared_memory_map_[request_id]->memory(), data.c_str(),
+ data.length());
+
+ EXPECT_TRUE(dispatcher_.OnMessageReceived(
+ ResourceMsg_DataReceived(request_id, 0, data.length(), data.length())));
+ }
+
+ void NotifyDataDownloaded(int request_id, int decoded_length,
+ int encoded_length) {
+ EXPECT_TRUE(dispatcher_.OnMessageReceived(
+ ResourceMsg_DataDownloaded(request_id, decoded_length,
+ encoded_length)));
+ }
+
+ void NotifyRequestComplete(int request_id, size_t total_size) {
+ ResourceMsg_RequestCompleteData request_complete_data;
+ request_complete_data.error_code = net::OK;
+ request_complete_data.was_ignored_by_handler = false;
+ request_complete_data.exists_in_cache = false;
+ request_complete_data.encoded_data_length = total_size;
+ EXPECT_TRUE(dispatcher_.OnMessageReceived(
+ ResourceMsg_RequestComplete(request_id, request_complete_data)));
}
- protected:
- // testing::Test
- virtual void SetUp() OVERRIDE {
- dispatcher_.reset(new ResourceDispatcher(this));
+ ResourceLoaderBridge* CreateBridge() {
+ return CreateBridgeInternal(false);
}
- virtual void TearDown() OVERRIDE {
- dispatcher_.reset();
+
+ ResourceLoaderBridge* CreateBridgeForDownloadToFile() {
+ return CreateBridgeInternal(true);
}
- ResourceLoaderBridge* CreateBridge() {
+ ResourceDispatcher* dispatcher() { return &dispatcher_; }
+
+ private:
+ ResourceLoaderBridge* CreateBridgeInternal(bool download_to_file) {
RequestInfo request_info;
request_info.method = "GET";
- request_info.url = GURL(test_page_url);
- request_info.first_party_for_cookies = GURL(test_page_url);
+ request_info.url = GURL(kTestPageUrl);
+ request_info.first_party_for_cookies = GURL(kTestPageUrl);
request_info.referrer = GURL();
request_info.headers = std::string();
request_info.load_flags = 0;
@@ -174,161 +333,373 @@ class ResourceDispatcherTest : public testing::Test, public IPC::Sender {
request_info.request_type = ResourceType::SUB_RESOURCE;
request_info.appcache_host_id = appcache::kAppCacheNoHostId;
request_info.routing_id = 0;
+ request_info.download_to_file = download_to_file;
RequestExtraData extra_data;
request_info.extra_data = &extra_data;
- return dispatcher_->CreateBridge(request_info);
+ return dispatcher_.CreateBridge(request_info);
}
+ // Map of request IDs to shared memory.
+ std::map<int, base::SharedMemory*> shared_memory_map_;
+
std::vector<IPC::Message> message_queue_;
- static scoped_ptr<ResourceDispatcher> dispatcher_;
+ ResourceDispatcher dispatcher_;
+ base::MessageLoop message_loop_;
};
-/*static*/
-scoped_ptr<ResourceDispatcher> ResourceDispatcherTest::dispatcher_;
-
-// Does a simple request and tests that the correct data is received.
+// Does a simple request and tests that the correct data is received. Simulates
+// two reads.
TEST_F(ResourceDispatcherTest, RoundTrip) {
- TestRequestCallback callback;
+ // Number of bytes received in the first read.
+ const size_t kFirstReceiveSize = 2;
+ ASSERT_LT(kFirstReceiveSize, strlen(kTestPageContents));
+
scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
+ TestRequestPeer peer(bridge.get());
+
+ EXPECT_TRUE(bridge->Start(&peer));
+ int id = ConsumeRequestResource();
+ EXPECT_EQ(0u, queued_messages());
- bridge->Start(&callback);
+ NotifyReceivedResponse(id);
+ EXPECT_EQ(0u, queued_messages());
+ EXPECT_TRUE(peer.received_response());
- ProcessMessages();
+ NotifySetDataBuffer(id, strlen(kTestPageContents));
+ NotifyDataReceived(id, std::string(kTestPageContents, kFirstReceiveSize));
+ ConsumeDataReceived_ACK(id);
+ EXPECT_EQ(0u, queued_messages());
- // FIXME(brettw) when the request complete messages are actually handledo
- // and dispatched, uncomment this.
- //EXPECT_TRUE(callback.complete());
- //EXPECT_STREQ(test_page_contents, callback.data().c_str());
- //EXPECT_EQ(test_page_contents_len, callback.total_encoded_data_length());
+ NotifyDataReceived(id, kTestPageContents + kFirstReceiveSize);
+ ConsumeDataReceived_ACK(id);
+ EXPECT_EQ(0u, queued_messages());
+
+ NotifyRequestComplete(id, strlen(kTestPageContents));
+ EXPECT_EQ(kTestPageContents, peer.data());
+ EXPECT_TRUE(peer.complete());
+ EXPECT_EQ(0u, queued_messages());
}
-// Tests that the request IDs are straight when there are multiple requests.
+// Tests that the request IDs are straight when there are two interleaving
+// requests.
TEST_F(ResourceDispatcherTest, MultipleRequests) {
- // FIXME
+ const char kTestPageContents2[] = "Not kTestPageContents";
+
+ scoped_ptr<ResourceLoaderBridge> bridge1(CreateBridge());
+ TestRequestPeer peer1(bridge1.get());
+ scoped_ptr<ResourceLoaderBridge> bridge2(CreateBridge());
+ TestRequestPeer peer2(bridge2.get());
+
+ EXPECT_TRUE(bridge1->Start(&peer1));
+ int id1 = ConsumeRequestResource();
+ EXPECT_TRUE(bridge2->Start(&peer2));
+ int id2 = ConsumeRequestResource();
+ EXPECT_EQ(0u, queued_messages());
+
+ NotifyReceivedResponse(id1);
+ EXPECT_TRUE(peer1.received_response());
+ EXPECT_FALSE(peer2.received_response());
+ NotifyReceivedResponse(id2);
+ EXPECT_TRUE(peer2.received_response());
+ EXPECT_EQ(0u, queued_messages());
+
+ NotifySetDataBuffer(id2, strlen(kTestPageContents2));
+ NotifyDataReceived(id2, kTestPageContents2);
+ ConsumeDataReceived_ACK(id2);
+ NotifySetDataBuffer(id1, strlen(kTestPageContents));
+ NotifyDataReceived(id1, kTestPageContents);
+ ConsumeDataReceived_ACK(id1);
+ EXPECT_EQ(0u, queued_messages());
+
+ NotifyRequestComplete(id1, strlen(kTestPageContents));
+ EXPECT_EQ(kTestPageContents, peer1.data());
+ EXPECT_TRUE(peer1.complete());
+ EXPECT_FALSE(peer2.complete());
+
+ NotifyRequestComplete(id2, strlen(kTestPageContents2));
+ EXPECT_EQ(kTestPageContents2, peer2.data());
+ EXPECT_TRUE(peer2.complete());
+
+ EXPECT_EQ(0u, queued_messages());
}
-// Tests that the cancel method prevents other messages from being received
+// Tests that the cancel method prevents other messages from being received.
TEST_F(ResourceDispatcherTest, Cancel) {
- // FIXME
+ scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
+ TestRequestPeer peer(bridge.get());
+
+ EXPECT_TRUE(bridge->Start(&peer));
+ int id = ConsumeRequestResource();
+ EXPECT_EQ(0u, queued_messages());
+
+ // Cancel the request.
+ bridge->Cancel();
+ ConsumeCancelRequest(id);
+
+ // Any future messages related to the request should be ignored.
+ NotifyReceivedResponse(id);
+ NotifySetDataBuffer(id, strlen(kTestPageContents));
+ NotifyDataReceived(id, kTestPageContents);
+ NotifyRequestComplete(id, strlen(kTestPageContents));
+
+ EXPECT_EQ(0u, queued_messages());
+ EXPECT_EQ("", peer.data());
+ EXPECT_FALSE(peer.received_response());
+ EXPECT_FALSE(peer.complete());
}
-TEST_F(ResourceDispatcherTest, Cookies) {
- // FIXME
+// Tests that calling cancel during a callback works as expected.
+TEST_F(ResourceDispatcherTest, CancelDuringCallback) {
+ scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
+ TestRequestPeer peer(bridge.get());
+ peer.set_cancel_on_receive_response(true);
+
+ EXPECT_TRUE(bridge->Start(&peer));
+ int id = ConsumeRequestResource();
+ EXPECT_EQ(0u, queued_messages());
+
+ NotifyReceivedResponse(id);
+ EXPECT_TRUE(peer.received_response());
+ // Request should have been cancelled.
+ ConsumeCancelRequest(id);
+
+ // Any future messages related to the request should be ignored.
+ NotifySetDataBuffer(id, strlen(kTestPageContents));
+ NotifyDataReceived(id, kTestPageContents);
+ NotifyRequestComplete(id, strlen(kTestPageContents));
+
+ EXPECT_EQ(0u, queued_messages());
+ EXPECT_EQ("", peer.data());
+ EXPECT_FALSE(peer.complete());
}
-TEST_F(ResourceDispatcherTest, SerializedPostData) {
- // FIXME
-}
+// Checks that redirects work as expected.
+TEST_F(ResourceDispatcherTest, Redirect) {
+ scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
+ TestRequestPeer peer(bridge.get());
-// This class provides functionality to validate whether the ResourceDispatcher
-// object honors the deferred loading contract correctly, i.e. if deferred
-// loading is enabled it should queue up any responses received. If deferred
-// loading is enabled/disabled in the context of a dispatched message, other
-// queued messages should not be dispatched until deferred load is turned off.
-class DeferredResourceLoadingTest : public ResourceDispatcherTest,
- public RequestPeer {
- public:
- DeferredResourceLoadingTest()
- : defer_loading_(false) {
- }
+ EXPECT_TRUE(bridge->Start(&peer));
+ int id = ConsumeRequestResource();
- virtual bool Send(IPC::Message* msg) OVERRIDE {
- delete msg;
- return true;
- }
+ NotifyReceivedRedirect(id);
+ ConsumeFollowRedirect(id);
+ EXPECT_EQ(1, peer.seen_redirects());
- void InitMessages() {
- set_defer_loading(true);
+ NotifyReceivedRedirect(id);
+ ConsumeFollowRedirect(id);
+ EXPECT_EQ(2, peer.seen_redirects());
- ResourceResponseHead response_head;
- response_head.error_code = net::OK;
+ NotifyReceivedResponse(id);
+ EXPECT_TRUE(peer.received_response());
- dispatcher_->OnMessageReceived(
- ResourceMsg_ReceivedResponse(0, response_head));
+ NotifySetDataBuffer(id, strlen(kTestPageContents));
+ NotifyDataReceived(id, kTestPageContents);
+ ConsumeDataReceived_ACK(id);
+
+ NotifyRequestComplete(id, strlen(kTestPageContents));
+ EXPECT_EQ(kTestPageContents, peer.data());
+ EXPECT_TRUE(peer.complete());
+ EXPECT_EQ(0u, queued_messages());
+ EXPECT_EQ(2, peer.seen_redirects());
+}
- // Duplicate the shared memory handle so both the test and the callee can
- // close their copy.
- base::SharedMemoryHandle duplicated_handle;
- EXPECT_TRUE(shared_handle_.ShareToProcess(base::GetCurrentProcessHandle(),
- &duplicated_handle));
+// Tests that that cancelling during a redirect method prevents other messages
+// from being received.
+TEST_F(ResourceDispatcherTest, CancelDuringRedirect) {
+ scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
+ TestRequestPeer peer(bridge.get());
+ peer.set_follow_redirects(false);
+
+ EXPECT_TRUE(bridge->Start(&peer));
+ int id = ConsumeRequestResource();
+ EXPECT_EQ(0u, queued_messages());
+
+ // Redirect the request, which triggers a cancellation.
+ NotifyReceivedRedirect(id);
+ ConsumeCancelRequest(id);
+ EXPECT_EQ(1, peer.seen_redirects());
+ EXPECT_EQ(0u, queued_messages());
+
+ // Any future messages related to the request should be ignored. In practice,
+ // only the NotifyRequestComplete should be received after this point.
+ NotifyReceivedRedirect(id);
+ NotifyReceivedResponse(id);
+ NotifySetDataBuffer(id, strlen(kTestPageContents));
+ NotifyDataReceived(id, kTestPageContents);
+ NotifyRequestComplete(id, strlen(kTestPageContents));
+
+ EXPECT_EQ(0u, queued_messages());
+ EXPECT_EQ("", peer.data());
+ EXPECT_FALSE(peer.complete());
+ EXPECT_EQ(1, peer.seen_redirects());
+}
- dispatcher_->OnMessageReceived(
- ResourceMsg_SetDataBuffer(0, duplicated_handle, 100, 0));
- dispatcher_->OnMessageReceived(ResourceMsg_DataReceived(0, 0, 100, 100));
+// Checks that deferring a request delays messages until it's resumed.
+TEST_F(ResourceDispatcherTest, Defer) {
+ scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
+ TestRequestPeer peer(bridge.get());
+
+ EXPECT_TRUE(bridge->Start(&peer));
+ int id = ConsumeRequestResource();
+ EXPECT_EQ(0u, queued_messages());
+
+ bridge->SetDefersLoading(true);
+ NotifyReceivedResponse(id);
+ NotifySetDataBuffer(id, strlen(kTestPageContents));
+ NotifyDataReceived(id, kTestPageContents);
+ NotifyRequestComplete(id, strlen(kTestPageContents));
+
+ // None of the messages should have been processed yet, so no queued messages
+ // to the browser process, and no data received by the peer.
+ EXPECT_EQ(0u, queued_messages());
+ EXPECT_EQ("", peer.data());
+ EXPECT_FALSE(peer.complete());
+ EXPECT_EQ(0, peer.seen_redirects());
+
+ // Resuming the request should asynchronously unleash the deferred messages.
+ bridge->SetDefersLoading(false);
+ base::RunLoop().RunUntilIdle();
- set_defer_loading(false);
- }
+ ConsumeDataReceived_ACK(id);
+ EXPECT_EQ(0u, queued_messages());
+ EXPECT_TRUE(peer.received_response());
+ EXPECT_EQ(kTestPageContents, peer.data());
+ EXPECT_TRUE(peer.complete());
+}
- // RequestPeer methods.
- virtual void OnUploadProgress(uint64 position, uint64 size) OVERRIDE {
- }
+// Checks that deferring a request during a redirect delays messages until it's
+// resumed.
+TEST_F(ResourceDispatcherTest, DeferOnRedirect) {
+ scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
+ TestRequestPeer peer(bridge.get());
+ peer.set_defer_on_redirect(true);
+
+ EXPECT_TRUE(bridge->Start(&peer));
+ int id = ConsumeRequestResource();
+ EXPECT_EQ(0u, queued_messages());
+
+ // The request should be deferred during the redirect, including the message
+ // to follow the redirect.
+ NotifyReceivedRedirect(id);
+ NotifyReceivedResponse(id);
+ NotifySetDataBuffer(id, strlen(kTestPageContents));
+ NotifyDataReceived(id, kTestPageContents);
+ NotifyRequestComplete(id, strlen(kTestPageContents));
+
+ // None of the messages should have been processed yet, so no queued messages
+ // to the browser process, and no data received by the peer.
+ EXPECT_EQ(0u, queued_messages());
+ EXPECT_EQ("", peer.data());
+ EXPECT_FALSE(peer.complete());
+ EXPECT_EQ(1, peer.seen_redirects());
+
+ // Resuming the request should asynchronously unleash the deferred messages.
+ bridge->SetDefersLoading(false);
+ base::RunLoop().RunUntilIdle();
- virtual bool OnReceivedRedirect(const GURL& new_url,
- const GURL& new_first_party_for_cookies,
- const ResourceResponseInfo& info) OVERRIDE {
- return true;
- }
+ ConsumeFollowRedirect(id);
+ ConsumeDataReceived_ACK(id);
- virtual void OnReceivedResponse(const ResourceResponseInfo& info) OVERRIDE {
- EXPECT_EQ(defer_loading_, false);
- set_defer_loading(true);
- }
+ EXPECT_EQ(0u, queued_messages());
+ EXPECT_TRUE(peer.received_response());
+ EXPECT_EQ(kTestPageContents, peer.data());
+ EXPECT_TRUE(peer.complete());
+ EXPECT_EQ(1, peer.seen_redirects());
+}
- virtual void OnDownloadedData(int len, int encoded_data_length) OVERRIDE {
- }
+// Checks that a deferred request that's cancelled doesn't receive any messages.
+TEST_F(ResourceDispatcherTest, CancelDeferredRequest) {
+ scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
+ TestRequestPeer peer(bridge.get());
- virtual void OnReceivedData(const char* data,
- int data_length,
- int encoded_data_length) OVERRIDE {
- EXPECT_EQ(defer_loading_, false);
- set_defer_loading(false);
- }
+ EXPECT_TRUE(bridge->Start(&peer));
+ int id = ConsumeRequestResource();
+ EXPECT_EQ(0u, queued_messages());
- virtual void OnCompletedRequest(
- int error_code,
- bool was_ignored_by_handler,
- bool stale_copy_in_cache,
- const std::string& security_info,
- const base::TimeTicks& completion_time,
- int64 total_transfer_size) OVERRIDE {
- }
+ bridge->SetDefersLoading(true);
+ NotifyReceivedRedirect(id);
+ bridge->Cancel();
+ ConsumeCancelRequest(id);
- protected:
- virtual void SetUp() OVERRIDE {
- ResourceDispatcherTest::SetUp();
- EXPECT_TRUE(shared_handle_.CreateAnonymous(100));
- }
+ NotifyRequestComplete(id, 0);
+ base::RunLoop().RunUntilIdle();
- virtual void TearDown() OVERRIDE {
- shared_handle_.Close();
- ResourceDispatcherTest::TearDown();
- }
+ // None of the messages should have been processed.
+ EXPECT_EQ(0u, queued_messages());
+ EXPECT_EQ("", peer.data());
+ EXPECT_FALSE(peer.complete());
+ EXPECT_EQ(0, peer.seen_redirects());
+}
- private:
- void set_defer_loading(bool defer) {
- defer_loading_ = defer;
- dispatcher_->SetDefersLoading(0, defer);
- }
+TEST_F(ResourceDispatcherTest, DownloadToFile) {
+ scoped_ptr<ResourceLoaderBridge> bridge(CreateBridgeForDownloadToFile());
+ TestRequestPeer peer(bridge.get());
+ const int kDownloadedIncrement = 100;
+ const int kEncodedIncrement = 50;
+
+ EXPECT_TRUE(bridge->Start(&peer));
+ int id = ConsumeRequestResource();
+ EXPECT_EQ(0u, queued_messages());
+
+ NotifyReceivedResponse(id);
+ EXPECT_EQ(0u, queued_messages());
+ EXPECT_TRUE(peer.received_response());
+
+ int expected_total_downloaded_length = 0;
+ int expected_total_encoded_length = 0;
+ for (int i = 0; i < 10; ++i) {
+ NotifyDataDownloaded(id, kDownloadedIncrement, kEncodedIncrement);
+ ConsumeDataDownloaded_ACK(id);
+ expected_total_downloaded_length += kDownloadedIncrement;
+ expected_total_encoded_length += kEncodedIncrement;
+ EXPECT_EQ(expected_total_downloaded_length,
+ peer.total_downloaded_data_length());
+ EXPECT_EQ(expected_total_encoded_length, peer.total_encoded_data_length());
+ }
+
+ NotifyRequestComplete(id, strlen(kTestPageContents));
+ EXPECT_EQ("", peer.data());
+ EXPECT_TRUE(peer.complete());
+ EXPECT_EQ(0u, queued_messages());
+
+ bridge.reset();
+ ConsumeReleaseDownloadedFile(id);
+ EXPECT_EQ(0u, queued_messages());
+ EXPECT_EQ(expected_total_downloaded_length,
+ peer.total_downloaded_data_length());
+ EXPECT_EQ(expected_total_encoded_length, peer.total_encoded_data_length());
+}
- bool defer_loading() const {
- return defer_loading_;
- }
+// Make sure that when a download to file is cancelled, the file is destroyed.
+TEST_F(ResourceDispatcherTest, CancelDownloadToFile) {
+ scoped_ptr<ResourceLoaderBridge> bridge(CreateBridgeForDownloadToFile());
+ TestRequestPeer peer(bridge.get());
- bool defer_loading_;
- base::SharedMemory shared_handle_;
-};
+ EXPECT_TRUE(bridge->Start(&peer));
+ int id = ConsumeRequestResource();
+ EXPECT_EQ(0u, queued_messages());
-TEST_F(DeferredResourceLoadingTest, DeferredLoadTest) {
- base::MessageLoopForIO message_loop;
+ NotifyReceivedResponse(id);
+ EXPECT_EQ(0u, queued_messages());
+ EXPECT_TRUE(peer.received_response());
- scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
+ // Cancelling the request deletes the file.
+ bridge->Cancel();
+ ConsumeCancelRequest(id);
+ ConsumeReleaseDownloadedFile(id);
- bridge->Start(this);
- InitMessages();
+ // Deleting the bridge shouldn't send another message to delete the file.
+ bridge.reset();
+ EXPECT_EQ(0u, queued_messages());
+}
- // Dispatch deferred messages.
- base::RunLoop().RunUntilIdle();
+TEST_F(ResourceDispatcherTest, Cookies) {
+ // FIXME
+}
+
+TEST_F(ResourceDispatcherTest, SerializedPostData) {
+ // FIXME
}
class TimeConversionTest : public ResourceDispatcherTest,
@@ -343,7 +714,7 @@ class TimeConversionTest : public ResourceDispatcherTest,
scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
bridge->Start(this);
- dispatcher_->OnMessageReceived(
+ dispatcher()->OnMessageReceived(
ResourceMsg_ReceivedResponse(0, response_head));
}