iframe_source_unittest.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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/url_request/url_request.h"
18#include "net/url_request/url_request_context.h"
19#include "net/url_request/url_request_test_util.h"
20#include "testing/gtest/include/gtest/gtest.h"
21#include "url/gurl.h"
22
23const int kNonInstantRendererPID = 0;
24const char kNonInstantOrigin[] = "http://evil";
25const int kInstantRendererPID = 1;
26const char kInstantOrigin[] = "chrome-search://instant";
27const int kInvalidRendererPID = 42;
28
29class TestIframeSource : public IframeSource {
30 public:
31  using IframeSource::GetMimeType;
32  using IframeSource::ShouldServiceRequest;
33  using IframeSource::SendResource;
34  using IframeSource::SendJSWithOrigin;
35
36 protected:
37  virtual std::string GetSource() const OVERRIDE {
38    return "test";
39  }
40
41  virtual bool ServesPath(const std::string& path) const OVERRIDE {
42    return path == "/valid.html" || path == "/valid.js";
43  }
44
45  virtual void StartDataRequest(
46      const std::string& path,
47      int render_process_id,
48      int render_view_id,
49      const content::URLDataSource::GotDataCallback& callback) OVERRIDE {
50  }
51
52  // RenderViewHost is hard to mock in concert with everything else, so stub
53  // this method out for testing.
54  virtual bool GetOrigin(
55      int process_id,
56      int render_view_id,
57      std::string* origin) const OVERRIDE {
58    if (process_id == kInstantRendererPID) {
59      *origin = kInstantOrigin;
60      return true;
61    }
62    if (process_id == kNonInstantRendererPID) {
63      *origin = kNonInstantOrigin;
64      return true;
65    }
66    return false;
67  }
68};
69
70class IframeSourceTest : public testing::Test {
71 public:
72  // net::URLRequest wants to be executed with a message loop that has TYPE_IO.
73  // InstantIOContext needs to be created on the UI thread and have everything
74  // else happen on the IO thread. This setup is a hacky way to satisfy all
75  // those constraints.
76  IframeSourceTest()
77      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
78        resource_context_(&test_url_request_context_),
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                                                       false);
108    }
109    return request;
110  }
111
112  void SendResource(int resource_id) {
113    source()->SendResource(resource_id, callback_);
114  }
115
116  void SendJSWithOrigin(
117      int resource_id,
118      int render_process_id,
119      int render_view_id) {
120    source()->SendJSWithOrigin(resource_id, render_process_id, render_view_id,
121                               callback_);
122  }
123
124 private:
125  virtual void SetUp() OVERRIDE {
126    source_.reset(new TestIframeSource());
127    callback_ = base::Bind(&IframeSourceTest::SaveResponse,
128                           base::Unretained(this));
129    instant_io_context_ = new InstantIOContext;
130    InstantIOContext::SetUserDataOnIO(&resource_context_, instant_io_context_);
131    InstantIOContext::AddInstantProcessOnIO(instant_io_context_,
132                                            kInstantRendererPID);
133    response_ = NULL;
134  }
135
136  virtual void TearDown() {
137    source_.reset();
138  }
139
140  void SaveResponse(base::RefCountedMemory* data) {
141    response_ = data;
142  }
143
144  content::TestBrowserThreadBundle thread_bundle_;
145
146  net::TestURLRequestContext test_url_request_context_;
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_MOST_VISITED_TITLE_HTML);
187  EXPECT_FALSE(response_string().empty());
188}
189
190TEST_F(IframeSourceTest, SendJSWithOrigin) {
191  SendJSWithOrigin(IDR_MOST_VISITED_TITLE_JS, kInstantRendererPID, 0);
192  EXPECT_FALSE(response_string().empty());
193  SendJSWithOrigin(IDR_MOST_VISITED_TITLE_JS, kNonInstantRendererPID, 0);
194  EXPECT_FALSE(response_string().empty());
195  SendJSWithOrigin(IDR_MOST_VISITED_TITLE_JS, kInvalidRendererPID, 0);
196  EXPECT_TRUE(response_string().empty());
197}
198