OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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 // Tests exercising the Chrome Plugin API. | |
5 | |
6 #include "base/file_util.h" | |
7 #include "base/message_loop_proxy.h" | |
8 #include "base/path_service.h" | |
9 #include "base/string_util.h" | |
10 #include "chrome/browser/chrome_plugin_host.h" | |
11 #include "chrome/browser/profiles/profile.h" | |
12 #include "chrome/common/chrome_plugin_lib.h" | |
13 #include "chrome/common/net/url_request_context_getter.h" | |
14 #include "chrome/test/chrome_plugin/test_chrome_plugin.h" | |
15 #include "chrome/test/test_url_request_context_getter.h" | |
16 #include "content/browser/browser_thread.h" | |
17 #include "net/base/io_buffer.h" | |
18 #include "net/http/http_response_headers.h" | |
19 #include "net/url_request/url_request_test_job.h" | |
20 #include "net/url_request/url_request_test_util.h" | |
21 #include "net/test/test_server.h" | |
22 #include "testing/gtest/include/gtest/gtest.h" | |
23 | |
24 namespace { | |
25 | |
26 const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data"); | |
27 const char kPluginFilename[] = "test_chrome_plugin.dll"; | |
28 const int kResponseBufferSize = 4096; | |
29 | |
30 class ChromePluginTest : public testing::Test, | |
31 public net::URLRequest::Delegate { | |
32 public: | |
33 ChromePluginTest() | |
34 : io_thread_(BrowserThread::IO, &message_loop_), | |
35 request_(NULL), | |
36 response_buffer_(new net::IOBuffer(kResponseBufferSize)), | |
37 plugin_(NULL), | |
38 expected_payload_(NULL), | |
39 request_context_getter_(new TestURLRequestContextGetter()) { | |
40 test_funcs_.test_make_request = NULL; | |
41 } | |
42 | |
43 // Loads/unloads the chrome test plugin. | |
44 void LoadPlugin(); | |
45 void UnloadPlugin(); | |
46 | |
47 // Runs the test and expects the given payload as a response. If expectation | |
48 // is NULL, the request is expected to fail. | |
49 void RunTest(const GURL& url, const TestResponsePayload* expected_payload); | |
50 | |
51 // net::URLRequest::Delegate implementations | |
52 virtual void OnResponseStarted(net::URLRequest* request); | |
53 virtual void OnReadCompleted(net::URLRequest* request, int bytes_read); | |
54 | |
55 // Helper called when the net::URLRequest is done. | |
56 void OnURLRequestComplete(); | |
57 | |
58 // testing::Test | |
59 virtual void SetUp() { | |
60 LoadPlugin(); | |
61 net::URLRequest::RegisterProtocolFactory("test", | |
62 &net::URLRequestTestJob::Factory); | |
63 | |
64 // We need to setup a default request context in order to issue HTTP | |
65 // requests. | |
66 DCHECK(!Profile::GetDefaultRequestContext()); | |
67 Profile::set_default_request_context(request_context_getter_.get()); | |
68 } | |
69 virtual void TearDown() { | |
70 UnloadPlugin(); | |
71 net::URLRequest::RegisterProtocolFactory("test", NULL); | |
72 | |
73 Profile::set_default_request_context(NULL); | |
74 | |
75 // Clear the request before flushing the message loop since killing the | |
76 // request can result in the generation of more tasks. | |
77 request_.reset(); | |
78 | |
79 // Flush the message loop to make Purify happy. | |
80 message_loop_.RunAllPending(); | |
81 } | |
82 protected: | |
83 MessageLoopForIO message_loop_; | |
84 BrowserThread io_thread_; | |
85 | |
86 // Note: we use net::URLRequest (instead of URLFetcher) because this allows | |
87 // the request to be intercepted. | |
88 scoped_ptr<net::URLRequest> request_; | |
89 scoped_refptr<net::IOBuffer> response_buffer_; | |
90 std::string response_data_; | |
91 | |
92 ChromePluginLib* plugin_; | |
93 TestFuncParams::PluginFuncs test_funcs_; | |
94 const TestResponsePayload* expected_payload_; | |
95 scoped_refptr<URLRequestContextGetter> request_context_getter_; | |
96 }; | |
97 | |
98 static void STDCALL CPT_Complete(CPRequest* request, bool success, | |
99 const std::string& raw_headers, | |
100 const std::string& body) { | |
101 GURL url(request->url); | |
102 if (url == GURL(kChromeTestPluginPayloads[0].url)) { | |
103 // This URL should fail, because the plugin should not have intercepted it. | |
104 EXPECT_FALSE(success); | |
105 MessageLoop::current()->Quit(); | |
106 return; | |
107 } | |
108 | |
109 scoped_refptr<net::HttpResponseHeaders> headers( | |
110 new net::HttpResponseHeaders(raw_headers)); | |
111 EXPECT_TRUE(success); | |
112 EXPECT_EQ(200, headers->response_code()); | |
113 | |
114 if (url == net::URLRequestTestJob::test_url_1()) { | |
115 EXPECT_EQ(net::URLRequestTestJob::test_data_1(), body); | |
116 } else if (url == net::URLRequestTestJob::test_url_2()) { | |
117 EXPECT_EQ(net::URLRequestTestJob::test_data_2(), body); | |
118 } else if (url.spec().find("echo") != std::string::npos) { | |
119 EXPECT_EQ(kChromeTestPluginPostData, body); | |
120 } | |
121 | |
122 MessageLoop::current()->Quit(); | |
123 } | |
124 | |
125 static void STDCALL CPT_InvokeLater(TestFuncParams::CallbackFunc callback, | |
126 void* callback_data, int delay_ms) { | |
127 MessageLoop::current()->PostDelayedTask(FROM_HERE, | |
128 NewRunnableFunction(callback, callback_data), delay_ms); | |
129 } | |
130 | |
131 void ChromePluginTest::LoadPlugin() { | |
132 FilePath path; | |
133 PathService::Get(base::DIR_EXE, &path); | |
134 path = path.AppendASCII(kPluginFilename); | |
135 plugin_ = ChromePluginLib::Create(path, GetCPBrowserFuncsForBrowser()); | |
136 ASSERT_TRUE(plugin_); | |
137 | |
138 // Exchange test APIs with the plugin. | |
139 TestFuncParams params; | |
140 params.bfuncs.test_complete = CPT_Complete; | |
141 params.bfuncs.invoke_later = CPT_InvokeLater; | |
142 EXPECT_EQ(CPERR_SUCCESS, plugin_->CP_Test(¶ms)); | |
143 test_funcs_ = params.pfuncs; | |
144 } | |
145 | |
146 void ChromePluginTest::UnloadPlugin() { | |
147 ChromePluginLib::UnloadAllPlugins(); | |
148 plugin_ = NULL; | |
149 } | |
150 | |
151 void ChromePluginTest::RunTest(const GURL& url, | |
152 const TestResponsePayload* expected_payload) { | |
153 expected_payload_ = expected_payload; | |
154 | |
155 response_data_.clear(); | |
156 request_.reset(new net::URLRequest(url, this)); | |
157 request_->set_context(new TestURLRequestContext()); | |
158 request_->Start(); | |
159 | |
160 MessageLoop::current()->Run(); | |
161 } | |
162 | |
163 void ChromePluginTest::OnResponseStarted(net::URLRequest* request) { | |
164 DCHECK(request == request_); | |
165 | |
166 int bytes_read = 0; | |
167 if (request_->status().is_success()) | |
168 request_->Read(response_buffer_, kResponseBufferSize, &bytes_read); | |
169 OnReadCompleted(request_.get(), bytes_read); | |
170 } | |
171 | |
172 void ChromePluginTest::OnReadCompleted(net::URLRequest* request, | |
173 int bytes_read) { | |
174 DCHECK(request == request_); | |
175 | |
176 do { | |
177 if (!request_->status().is_success() || bytes_read <= 0) | |
178 break; | |
179 response_data_.append(response_buffer_->data(), bytes_read); | |
180 } while (request_->Read(response_buffer_, kResponseBufferSize, &bytes_read)); | |
181 | |
182 if (!request_->status().is_io_pending()) { | |
183 OnURLRequestComplete(); | |
184 } | |
185 } | |
186 | |
187 void ChromePluginTest::OnURLRequestComplete() { | |
188 if (expected_payload_) { | |
189 EXPECT_TRUE(request_->status().is_success()); | |
190 | |
191 EXPECT_EQ(expected_payload_->status, request_->GetResponseCode()); | |
192 if (expected_payload_->mime_type) { | |
193 std::string mime_type; | |
194 EXPECT_TRUE(request_->response_headers()->GetMimeType(&mime_type)); | |
195 EXPECT_EQ(expected_payload_->mime_type, mime_type); | |
196 } | |
197 if (expected_payload_->body) { | |
198 EXPECT_EQ(expected_payload_->body, response_data_); | |
199 } | |
200 } else { | |
201 EXPECT_FALSE(request_->status().is_success()); | |
202 } | |
203 | |
204 MessageLoop::current()->Quit(); | |
205 // If MessageLoop::current() != main_loop_, it will be shut down when the | |
206 // main loop returns and this thread subsequently goes out of scope. | |
207 } | |
208 | |
209 // Tests that the plugin can intercept URLs. | |
210 TEST_F(ChromePluginTest, DoesIntercept) { | |
211 for (size_t i = 0; i < arraysize(kChromeTestPluginPayloads); ++i) { | |
212 RunTest(GURL(kChromeTestPluginPayloads[i].url), | |
213 &kChromeTestPluginPayloads[i]); | |
214 } | |
215 } | |
216 | |
217 // Tests that non-intercepted URLs are handled normally. | |
218 TEST_F(ChromePluginTest, DoesNotIntercept) { | |
219 TestResponsePayload about_blank = { | |
220 "about:blank", | |
221 false, | |
222 -1, | |
223 NULL, | |
224 "" | |
225 }; | |
226 RunTest(GURL(about_blank.url), &about_blank); | |
227 } | |
228 | |
229 // Tests that unloading the plugin correctly unregisters URL interception. | |
230 TEST_F(ChromePluginTest, UnregisterIntercept) { | |
231 UnloadPlugin(); | |
232 | |
233 RunTest(GURL(kChromeTestPluginPayloads[0].url), NULL); | |
234 } | |
235 | |
236 static void ProcessAllPendingMessages() { | |
237 while (net::URLRequestTestJob::ProcessOnePendingMessage()); | |
238 } | |
239 | |
240 // Tests that the plugin can issue a GET request and receives the data when | |
241 // it comes back synchronously. | |
242 TEST_F(ChromePluginTest, CanMakeGETRequestSync) { | |
243 // test_url_1 has a synchronous response | |
244 EXPECT_EQ(CPERR_SUCCESS, test_funcs_.test_make_request( | |
245 "GET", net::URLRequestTestJob::test_url_1())); | |
246 | |
247 // Note: we must add this task after we make the request, so that | |
248 // net::URLRequestTestJob's StartAsync task is added and run first. | |
249 MessageLoop::current()->PostTask(FROM_HERE, | |
250 NewRunnableFunction(&ProcessAllPendingMessages)); | |
251 MessageLoop::current()->Run(); | |
252 } | |
253 | |
254 // Tests that the plugin can issue a GET request and receives the data when | |
255 // it comes back asynchronously. | |
256 TEST_F(ChromePluginTest, CanMakeGETRequestAsync) { | |
257 // test_url_2 has an asynchronous response | |
258 EXPECT_EQ(CPERR_SUCCESS, test_funcs_.test_make_request( | |
259 "GET", net::URLRequestTestJob::test_url_2())); | |
260 | |
261 // Note: we must add this task after we make the request, so that | |
262 // net::URLRequestTestJob's StartAsync task is added and run first. | |
263 MessageLoop::current()->PostTask(FROM_HERE, | |
264 NewRunnableFunction(&ProcessAllPendingMessages)); | |
265 MessageLoop::current()->Run(); | |
266 } | |
267 | |
268 // Tests that the plugin can issue a POST request. | |
269 TEST_F(ChromePluginTest, CanMakePOSTRequest) { | |
270 net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot)); | |
271 ASSERT_TRUE(test_server.Start()); | |
272 | |
273 GURL url = test_server.GetURL("echo"); | |
274 | |
275 EXPECT_EQ(CPERR_SUCCESS, test_funcs_.test_make_request("POST", url)); | |
276 | |
277 // Note: we must add this task after we make the request, so that | |
278 // net::URLRequestTestJob's StartAsync task is added and run first. | |
279 MessageLoop::current()->PostTask(FROM_HERE, | |
280 NewRunnableFunction(&ProcessAllPendingMessages)); | |
281 MessageLoop::current()->Run(); | |
282 } | |
283 | |
284 // Tests that the plugin does not intercept its own requests. | |
285 TEST_F(ChromePluginTest, DoesNotInterceptOwnRequest) { | |
286 const TestResponsePayload& payload = kChromeTestPluginPayloads[0]; | |
287 | |
288 EXPECT_EQ(CPERR_SUCCESS, test_funcs_.test_make_request( | |
289 "GET", GURL(payload.url))); | |
290 | |
291 MessageLoop::current()->Run(); | |
292 } | |
293 | |
294 } // namespace | |
OLD | NEW |