iframe_source_unittest.cc revision 0f1bc08d4cfcc34181b0b5cbf065c40f687bf740
1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/search/iframe_source.h"
6
7#include "base/bind.h"
8#include "base/memory/ref_counted_memory.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/message_loop/message_loop.h"
11#include "chrome/browser/search/instant_io_context.h"
12#include "content/public/browser/browser_thread.h"
13#include "content/public/browser/resource_request_info.h"
14#include "content/public/test/mock_resource_context.h"
15#include "content/public/test/test_browser_thread_bundle.h"
16#include "grit/browser_resources.h"
17#include "net/base/request_priority.h"
18#include "net/url_request/url_request.h"
19#include "net/url_request/url_request_context.h"
20#include "net/url_request/url_request_test_util.h"
21#include "testing/gtest/include/gtest/gtest.h"
22#include "url/gurl.h"
23
24const int kNonInstantRendererPID = 0;
25const char kNonInstantOrigin[] = "http://evil";
26const int kInstantRendererPID = 1;
27const char kInstantOrigin[] = "chrome-search://instant";
28const int kInvalidRendererPID = 42;
29
30class TestIframeSource : public IframeSource {
31 public:
32  using IframeSource::GetMimeType;
33  using IframeSource::ShouldServiceRequest;
34  using IframeSource::SendResource;
35  using IframeSource::SendJSWithOrigin;
36
37 protected:
38  virtual std::string GetSource() const OVERRIDE {
39    return "test";
40  }
41
42  virtual bool ServesPath(const std::string& path) const OVERRIDE {
43    return path == "/valid.html" || path == "/valid.js";
44  }
45
46  virtual void StartDataRequest(
47      const std::string& path,
48      int render_process_id,
49      int render_view_id,
50      const content::URLDataSource::GotDataCallback& callback) OVERRIDE {
51  }
52
53  // RenderViewHost is hard to mock in concert with everything else, so stub
54  // this method out for testing.
55  virtual bool GetOrigin(
56      int process_id,
57      int render_view_id,
58      std::string* origin) const OVERRIDE {
59    if (process_id == kInstantRendererPID) {
60      *origin = kInstantOrigin;
61      return true;
62    }
63    if (process_id == kNonInstantRendererPID) {
64      *origin = kNonInstantOrigin;
65      return true;
66    }
67    return false;
68  }
69};
70
71class IframeSourceTest : public testing::Test {
72 public:
73  // net::URLRequest wants to be executed with a message loop that has TYPE_IO.
74  // InstantIOContext needs to be created on the UI thread and have everything
75  // else happen on the IO thread. This setup is a hacky way to satisfy all
76  // those constraints.
77  IframeSourceTest()
78      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
79        resource_context_(&test_url_request_context_),
80        instant_io_context_(NULL),
81        response_(NULL) {
82  }
83
84  TestIframeSource* source() { return source_.get(); }
85
86  std::string response_string() {
87    if (response_.get()) {
88      return std::string(reinterpret_cast<const char*>(response_->front()),
89                         response_->size());
90    }
91    return "";
92  }
93
94  net::URLRequest* MockRequest(
95      const std::string& url,
96      bool allocate_info,
97      int render_process_id,
98      int render_view_id) {
99    net::URLRequest* request =
100        new net::URLRequest(GURL(url),
101                            net::DEFAULT_PRIORITY,
102                            NULL,
103                            resource_context_.GetRequestContext());
104    if (allocate_info) {
105      content::ResourceRequestInfo::AllocateForTesting(request,
106                                                       ResourceType::SUB_FRAME,
107                                                       &resource_context_,
108                                                       render_process_id,
109                                                       render_view_id,
110                                                       false);
111    }
112    return request;
113  }
114
115  void SendResource(int resource_id) {
116    source()->SendResource(resource_id, callback_);
117  }
118
119  void SendJSWithOrigin(
120      int resource_id,
121      int render_process_id,
122      int render_view_id) {
123    source()->SendJSWithOrigin(resource_id, render_process_id, render_view_id,
124                               callback_);
125  }
126
127 private:
128  virtual void SetUp() OVERRIDE {
129    source_.reset(new TestIframeSource());
130    callback_ = base::Bind(&IframeSourceTest::SaveResponse,
131                           base::Unretained(this));
132    instant_io_context_ = new InstantIOContext;
133    InstantIOContext::SetUserDataOnIO(&resource_context_, instant_io_context_);
134    InstantIOContext::AddInstantProcessOnIO(instant_io_context_,
135                                            kInstantRendererPID);
136    response_ = NULL;
137  }
138
139  virtual void TearDown() {
140    source_.reset();
141  }
142
143  void SaveResponse(base::RefCountedMemory* data) {
144    response_ = data;
145  }
146
147  content::TestBrowserThreadBundle thread_bundle_;
148
149  net::TestURLRequestContext test_url_request_context_;
150  content::MockResourceContext resource_context_;
151  scoped_ptr<TestIframeSource> source_;
152  content::URLDataSource::GotDataCallback callback_;
153  scoped_refptr<InstantIOContext> instant_io_context_;
154  scoped_refptr<base::RefCountedMemory> response_;
155};
156
157TEST_F(IframeSourceTest, ShouldServiceRequest) {
158  scoped_ptr<net::URLRequest> request;
159  request.reset(MockRequest("http://test/loader.js", true,
160                            kNonInstantRendererPID, 0));
161  EXPECT_FALSE(source()->ShouldServiceRequest(request.get()));
162  request.reset(MockRequest("chrome-search://bogus/valid.js", true,
163                            kInstantRendererPID, 0));
164  EXPECT_FALSE(source()->ShouldServiceRequest(request.get()));
165  request.reset(MockRequest("chrome-search://test/bogus.js", true,
166                            kInstantRendererPID, 0));
167  EXPECT_FALSE(source()->ShouldServiceRequest(request.get()));
168  request.reset(MockRequest("chrome-search://test/valid.js", true,
169                            kInstantRendererPID, 0));
170  EXPECT_TRUE(source()->ShouldServiceRequest(request.get()));
171  request.reset(MockRequest("chrome-search://test/valid.js", true,
172                            kNonInstantRendererPID, 0));
173  EXPECT_FALSE(source()->ShouldServiceRequest(request.get()));
174  request.reset(MockRequest("chrome-search://test/valid.js", true,
175                            kInvalidRendererPID, 0));
176  EXPECT_FALSE(source()->ShouldServiceRequest(request.get()));
177}
178
179TEST_F(IframeSourceTest, GetMimeType) {
180  // URLDataManagerBackend does not include / in path_and_query.
181  EXPECT_EQ("text/html", source()->GetMimeType("foo.html"));
182  EXPECT_EQ("application/javascript", source()->GetMimeType("foo.js"));
183  EXPECT_EQ("text/css", source()->GetMimeType("foo.css"));
184  EXPECT_EQ("image/png", source()->GetMimeType("foo.png"));
185  EXPECT_EQ("", source()->GetMimeType("bogus"));
186}
187
188TEST_F(IframeSourceTest, SendResource) {
189  SendResource(IDR_MOST_VISITED_TITLE_HTML);
190  EXPECT_FALSE(response_string().empty());
191}
192
193TEST_F(IframeSourceTest, SendJSWithOrigin) {
194  SendJSWithOrigin(IDR_MOST_VISITED_TITLE_JS, kInstantRendererPID, 0);
195  EXPECT_FALSE(response_string().empty());
196  SendJSWithOrigin(IDR_MOST_VISITED_TITLE_JS, kNonInstantRendererPID, 0);
197  EXPECT_FALSE(response_string().empty());
198  SendJSWithOrigin(IDR_MOST_VISITED_TITLE_JS, kInvalidRendererPID, 0);
199  EXPECT_TRUE(response_string().empty());
200}
201