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