root/content/child/resource_dispatcher_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. OnUploadProgress
  2. OnReceivedRedirect
  3. OnReceivedResponse
  4. OnDownloadedData
  5. OnReceivedData
  6. OnCompletedRequest
  7. complete
  8. data
  9. total_encoded_data_length
  10. Send
  11. ProcessMessages
  12. SetUp
  13. TearDown
  14. CreateBridge
  15. TEST_F
  16. TEST_F
  17. TEST_F
  18. TEST_F
  19. TEST_F
  20. Send
  21. InitMessages
  22. OnUploadProgress
  23. OnReceivedRedirect
  24. OnReceivedResponse
  25. OnDownloadedData
  26. OnReceivedData
  27. OnCompletedRequest
  28. SetUp
  29. TearDown
  30. set_defer_loading
  31. defer_loading
  32. TEST_F
  33. Send
  34. PerformTest
  35. OnUploadProgress
  36. OnReceivedRedirect
  37. OnReceivedResponse
  38. OnDownloadedData
  39. OnReceivedData
  40. OnCompletedRequest
  41. response_info
  42. TEST_F
  43. TEST_F
  44. TEST_F

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string>
#include <vector>

#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/process/process.h"
#include "base/process/process_handle.h"
#include "content/child/request_extra_data.h"
#include "content/child/request_info.h"
#include "content/child/resource_dispatcher.h"
#include "content/common/resource_messages.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/public/child/request_peer.h"
#include "content/public/common/resource_response.h"
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/child/resource_loader_bridge.h"
#include "webkit/common/appcache/appcache_interfaces.h"

using webkit_glue::ResourceLoaderBridge;
using webkit_glue::ResourceResponseInfo;

namespace content {

static const char test_page_url[] = "http://www.google.com/";
static const char test_page_headers[] =
  "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[] =
  "<html><head><title>Google</title></head><body><h1>Google</h1></body></html>";
static const uint32 test_page_contents_len = arraysize(test_page_contents) - 1;

// Listens for request response data and stores it so that it can be compared
// to the reference data.
class TestRequestCallback : public RequestPeer {
 public:
  TestRequestCallback() : complete_(false) {
  }

  virtual void OnUploadProgress(uint64 position, uint64 size) OVERRIDE {
  }

  virtual bool OnReceivedRedirect(
      const GURL& new_url,
      const ResourceResponseInfo& info,
      bool* has_new_first_party_for_cookies,
      GURL* new_first_party_for_cookies) OVERRIDE {
    *has_new_first_party_for_cookies = false;
    return true;
  }

  virtual void OnReceivedResponse(const ResourceResponseInfo& info) OVERRIDE {
  }

  virtual void OnDownloadedData(int len, int encoded_data_length) OVERRIDE {
  }

  virtual void OnReceivedData(const char* data,
                              int data_length,
                              int encoded_data_length) OVERRIDE {
    EXPECT_FALSE(complete_);
    data_.append(data, data_length);
    total_encoded_data_length_ += encoded_data_length;
  }

  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 {
    EXPECT_FALSE(complete_);
    complete_ = true;
  }

  bool complete() const {
    return complete_;
  }
  const std::string& data() const {
    return data_;
  }
  int total_encoded_data_length() const {
    return total_encoded_data_length_;
  }

 private:
  bool complete_;
  std::string data_;
  int total_encoded_data_length_;
};


// Sets up the message sender override for the unit test
class ResourceDispatcherTest : public testing::Test, public IPC::Sender {
 public:
  // Emulates IPC send operations (IPC::Sender) by adding
  // pending messages to the queue.
  virtual bool Send(IPC::Message* msg) OVERRIDE {
    message_queue_.push_back(IPC::Message(*msg));
    delete msg;
    return true;
  }

  // Emulates the browser process and processes the pending IPC messages,
  // returning the hardcoded file contents.
  void ProcessMessages() {
    while (!message_queue_.empty()) {
      int request_id;
      ResourceHostMsg_Request request;
      ASSERT_TRUE(ResourceHostMsg_RequestResource::Read(
          &message_queue_[0], &request_id, &request));

      // 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());
    }
  }

 protected:
  // testing::Test
  virtual void SetUp() OVERRIDE {
    dispatcher_.reset(new ResourceDispatcher(this));
  }
  virtual void TearDown() OVERRIDE {
    dispatcher_.reset();
  }

  ResourceLoaderBridge* CreateBridge() {
    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.referrer = GURL();
    request_info.headers = std::string();
    request_info.load_flags = 0;
    request_info.requestor_pid = 0;
    request_info.request_type = ResourceType::SUB_RESOURCE;
    request_info.appcache_host_id = appcache::kNoHostId;
    request_info.routing_id = 0;
    RequestExtraData extra_data;
    request_info.extra_data = &extra_data;

    return dispatcher_->CreateBridge(request_info);
  }

  std::vector<IPC::Message> message_queue_;
  static scoped_ptr<ResourceDispatcher> dispatcher_;
};

/*static*/
scoped_ptr<ResourceDispatcher> ResourceDispatcherTest::dispatcher_;

// Does a simple request and tests that the correct data is received.
TEST_F(ResourceDispatcherTest, RoundTrip) {
  TestRequestCallback callback;
  ResourceLoaderBridge* bridge = CreateBridge();

  bridge->Start(&callback);

  ProcessMessages();

  // 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());

  delete bridge;
}

// Tests that the request IDs are straight when there are multiple requests.
TEST_F(ResourceDispatcherTest, MultipleRequests) {
  // FIXME
}

// Tests that the cancel method prevents other messages from being received
TEST_F(ResourceDispatcherTest, Cancel) {
  // FIXME
}

TEST_F(ResourceDispatcherTest, Cookies) {
  // FIXME
}

TEST_F(ResourceDispatcherTest, SerializedPostData) {
  // FIXME
}

// 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) {
  }

  virtual bool Send(IPC::Message* msg) OVERRIDE {
    delete msg;
    return true;
  }

  void InitMessages() {
    set_defer_loading(true);

    ResourceResponseHead response_head;
    response_head.error_code = net::OK;

    dispatcher_->OnMessageReceived(
        ResourceMsg_ReceivedResponse(0, response_head));

    // 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));

    dispatcher_->OnMessageReceived(
        ResourceMsg_SetDataBuffer(0, duplicated_handle, 100, 0));
    dispatcher_->OnMessageReceived(ResourceMsg_DataReceived(0, 0, 100, 100));

    set_defer_loading(false);
  }

  // RequestPeer methods.
  virtual void OnUploadProgress(uint64 position, uint64 size) OVERRIDE {
  }

  virtual bool OnReceivedRedirect(
      const GURL& new_url,
      const ResourceResponseInfo& info,
      bool* has_new_first_party_for_cookies,
      GURL* new_first_party_for_cookies) OVERRIDE {
    *has_new_first_party_for_cookies = false;
    return true;
  }

  virtual void OnReceivedResponse(const ResourceResponseInfo& info) OVERRIDE {
    EXPECT_EQ(defer_loading_, false);
    set_defer_loading(true);
  }

  virtual void OnDownloadedData(int len, int encoded_data_length) OVERRIDE {
  }

  virtual void OnReceivedData(const char* data,
                              int data_length,
                              int encoded_data_length) OVERRIDE {
    EXPECT_EQ(defer_loading_, false);
    set_defer_loading(false);
  }

  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 {
  }

 protected:
  virtual void SetUp() OVERRIDE {
    ResourceDispatcherTest::SetUp();
    EXPECT_TRUE(shared_handle_.CreateAnonymous(100));
  }

  virtual void TearDown() OVERRIDE {
    shared_handle_.Close();
    ResourceDispatcherTest::TearDown();
  }

 private:
  void set_defer_loading(bool defer) {
    defer_loading_ = defer;
    dispatcher_->SetDefersLoading(0, defer);
  }

  bool defer_loading() const {
    return defer_loading_;
  }

  bool defer_loading_;
  base::SharedMemory shared_handle_;
};

TEST_F(DeferredResourceLoadingTest, DeferredLoadTest) {
  base::MessageLoopForIO message_loop;

  ResourceLoaderBridge* bridge = CreateBridge();

  bridge->Start(this);
  InitMessages();

  // Dispatch deferred messages.
  message_loop.RunUntilIdle();
  delete bridge;
}

class TimeConversionTest : public ResourceDispatcherTest,
                           public RequestPeer {
 public:
  virtual bool Send(IPC::Message* msg) OVERRIDE {
    delete msg;
    return true;
  }

  void PerformTest(const ResourceResponseHead& response_head) {
    scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
    bridge->Start(this);

    dispatcher_->OnMessageReceived(
        ResourceMsg_ReceivedResponse(0, response_head));
  }

  // RequestPeer methods.
  virtual void OnUploadProgress(uint64 position, uint64 size) OVERRIDE {
  }

  virtual bool OnReceivedRedirect(
      const GURL& new_url,
      const ResourceResponseInfo& info,
      bool* has_new_first_party_for_cookies,
      GURL* new_first_party_for_cookies) OVERRIDE {
    return true;
  }

  virtual void OnReceivedResponse(const ResourceResponseInfo& info) OVERRIDE {
    response_info_ = info;
  }

  virtual void OnDownloadedData(int len, int encoded_data_length) OVERRIDE {
  }

  virtual void OnReceivedData(const char* data,
                              int data_length,
                              int encoded_data_length) OVERRIDE {
  }

  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 {
  }

  const ResourceResponseInfo& response_info() const { return response_info_; }

 private:
  ResourceResponseInfo response_info_;
};

// TODO(simonjam): Enable this when 10829031 lands.
TEST_F(TimeConversionTest, DISABLED_ProperlyInitialized) {
  ResourceResponseHead response_head;
  response_head.error_code = net::OK;
  response_head.request_start = base::TimeTicks::FromInternalValue(5);
  response_head.response_start = base::TimeTicks::FromInternalValue(15);
  response_head.load_timing.request_start_time = base::Time::Now();
  response_head.load_timing.request_start =
      base::TimeTicks::FromInternalValue(10);
  response_head.load_timing.connect_timing.connect_start =
      base::TimeTicks::FromInternalValue(13);

  PerformTest(response_head);

  EXPECT_LT(base::TimeTicks(), response_info().load_timing.request_start);
  EXPECT_EQ(base::TimeTicks(),
            response_info().load_timing.connect_timing.dns_start);
  EXPECT_LE(response_head.load_timing.request_start,
            response_info().load_timing.connect_timing.connect_start);
}

TEST_F(TimeConversionTest, PartiallyInitialized) {
  ResourceResponseHead response_head;
  response_head.error_code = net::OK;
  response_head.request_start = base::TimeTicks::FromInternalValue(5);
  response_head.response_start = base::TimeTicks::FromInternalValue(15);

  PerformTest(response_head);

  EXPECT_EQ(base::TimeTicks(), response_info().load_timing.request_start);
  EXPECT_EQ(base::TimeTicks(),
            response_info().load_timing.connect_timing.dns_start);
}

TEST_F(TimeConversionTest, NotInitialized) {
  ResourceResponseHead response_head;
  response_head.error_code = net::OK;

  PerformTest(response_head);

  EXPECT_EQ(base::TimeTicks(), response_info().load_timing.request_start);
  EXPECT_EQ(base::TimeTicks(),
            response_info().load_timing.connect_timing.dns_start);
}

}  // namespace content

/* [<][>][^][v][top][bottom][index][help] */