Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(567)

Side by Side Diff: content/browser/loader/url_loader_factory_holder_unittest.cc

Issue 1970693002: Use mojo for Chrome Loading, Part 1 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 "content/browser/loader/url_loader_factory_holder.h"
6
7 #include <memory>
8 #include <string>
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/files/file_path.h"
14 #include "base/location.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/path_service.h"
19 #include "base/run_loop.h"
20 #include "content/browser/loader/mojo_async_resource_handler.h"
21 #include "content/browser/loader/resource_dispatcher_host_impl.h"
22 #include "content/browser/loader/resource_message_filter.h"
23 #include "content/common/resource_request.h"
24 #include "content/common/resource_request_completion_status.h"
25 #include "content/common/url_loader.mojom.h"
26 #include "content/common/url_loader_factory.mojom.h"
27 #include "content/public/browser/resource_context.h"
28 #include "content/public/browser/resource_dispatcher_host_delegate.h"
29 #include "content/public/common/content_paths.h"
30 #include "content/public/test/test_browser_context.h"
31 #include "content/public/test/test_browser_thread_bundle.h"
32 #include "mojo/public/c/system/data_pipe.h"
33 #include "mojo/public/c/system/types.h"
34 #include "mojo/public/cpp/bindings/binding.h"
35 #include "mojo/public/cpp/system/data_pipe.h"
36 #include "net/base/io_buffer.h"
37 #include "net/base/net_errors.h"
38 #include "net/http/http_response_headers.h"
39 #include "net/http/http_response_info.h"
40 #include "net/http/http_status_code.h"
41 #include "net/http/http_util.h"
42 #include "net/test/url_request/url_request_failed_job.h"
43 #include "net/test/url_request/url_request_mock_http_job.h"
44 #include "net/url_request/url_request_filter.h"
45 #include "testing/gtest/include/gtest/gtest.h"
46 #include "url/gurl.h"
47
48 namespace content {
49
50 namespace {
51
52 class FakeURLLoaderClient final : public mojom::URLLoaderClient {
53 public:
54 FakeURLLoaderClient() : binding_(this) {}
55
56 void OnReceiveResponse(const ResourceResponseHead& response_head) override {
57 has_received_response_ = true;
58 response_head_ = response_head;
59 if (!quit_closure_.Equals(base::Closure()))
mmenke 2016/06/13 20:56:58 There's either an is_empty() or is_null() method t
kinuko 2016/06/14 08:45:29 is_null() is most common I believe
yhirano 2016/07/12 10:49:11 operator bool() is simpler, I think.
60 quit_closure_.Run();
61 }
62 void OnStartLoadingResponseBody(
63 mojo::ScopedDataPipeConsumerHandle body) override {
64 response_body_ = std::move(body);
65 if (!quit_closure_.Equals(base::Closure()))
mmenke 2016/06/13 20:56:58 is_null()
yhirano 2016/07/12 10:49:11 Done.
66 quit_closure_.Run();
67 }
68 void OnComplete(const ResourceRequestCompletionStatus& status) override {
69 has_received_completion_ = true;
70 completion_status_ = status;
71 if (!quit_closure_.Equals(base::Closure()))
mmenke 2016/06/13 20:56:58 is_null()
yhirano 2016/07/12 10:49:11 Done.
72 quit_closure_.Run();
73 }
74
75 bool has_received_response() const { return has_received_response_; }
76 bool has_received_completion() const { return has_received_completion_; }
77 const ResourceResponseHead& response_head() const { return response_head_; }
78 mojo::DataPipeConsumerHandle response_body() { return response_body_.get(); }
79 const ResourceRequestCompletionStatus& completion_status() const {
80 return completion_status_;
81 }
82
83 mojom::URLLoaderClientPtr CreateInterfacePtrAndBind() {
84 return binding_.CreateInterfacePtrAndBind();
85 }
86
87 void set_quit_closure(const base::Closure& quit_closure) {
88 quit_closure_ = quit_closure;
89 }
90
91 private:
92 mojo::Binding<mojom::URLLoaderClient> binding_;
93 ResourceResponseHead response_head_;
94 mojo::ScopedDataPipeConsumerHandle response_body_;
95 ResourceRequestCompletionStatus completion_status_;
96 bool has_received_response_ = false;
97 bool has_received_completion_ = false;
98 base::Closure quit_closure_;
99
100 DISALLOW_COPY_AND_ASSIGN(FakeURLLoaderClient);
101 };
102
103 class RejectingResourceDispatcherHostDelegate final
104 : public ResourceDispatcherHostDelegate {
105 public:
106 RejectingResourceDispatcherHostDelegate() {}
107 bool ShouldBeginRequest(const std::string& method,
108 const GURL& url,
109 ResourceType resource_type,
110 ResourceContext* resource_context) override {
111 return false;
112 }
113
114 DISALLOW_COPY_AND_ASSIGN(RejectingResourceDispatcherHostDelegate);
115 };
116
117 class TestURLRequestJobForBrokenBody final : public net::URLRequestJob {
118 public:
119 TestURLRequestJobForBrokenBody(net::URLRequest* request,
120 net::NetworkDelegate* network_delegate)
121 : URLRequestJob(request, network_delegate), weak_factory_(this) {}
122
123 void Start() override {
124 base::ThreadTaskRunnerHandle::Get()->PostTask(
125 FROM_HERE, base::Bind(&TestURLRequestJobForBrokenBody::StartAsync,
126 weak_factory_.GetWeakPtr()));
127 }
128
129 int ReadRawData(net::IOBuffer* buf, int buf_size) override {
130 DCHECK_GT(buf_size, 0);
131 if (++counter_ > 1)
132 return net::ERR_FAILED;
133 buf->data()[0] = 'a';
134 return 1;
135 }
136
137 int GetResponseCode() const override { return 200; }
138
139 void GetResponseInfo(net::HttpResponseInfo* info) override {
140 std::string raw_headers;
141 raw_headers.append(
142 "HTTP/1.1 200 OK\n"
143 "Content-type: text/plain\n");
144 info->headers =
145 new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
146 raw_headers.c_str(), static_cast<int>(raw_headers.length())));
147 }
148
149 private:
150 void StartAsync() { NotifyHeadersComplete(); }
151
152 int counter_ = 0;
153 base::WeakPtrFactory<TestURLRequestJobForBrokenBody> weak_factory_;
154
155 DISALLOW_COPY_AND_ASSIGN(TestURLRequestJobForBrokenBody);
156 };
157
158 class TestInterceptorForBrokenBody final : public net::URLRequestInterceptor {
159 public:
160 explicit TestInterceptorForBrokenBody(const GURL& url) : url_(url) {}
161
162 net::URLRequestJob* MaybeInterceptRequest(
163 net::URLRequest* request,
164 net::NetworkDelegate* network_delegate) const override {
165 if (request->url() != url_)
166 return nullptr;
167
168 return new TestURLRequestJobForBrokenBody(request, network_delegate);
169 }
170
171 private:
172 const GURL url_;
173
174 DISALLOW_COPY_AND_ASSIGN(TestInterceptorForBrokenBody);
175 };
176
177 class URLLoaderFactoryImplTest : public ::testing::TestWithParam<size_t> {
mmenke 2016/06/13 20:56:59 You should document what the size_t is.
yhirano 2016/07/12 10:49:11 Done.
178 public:
179 URLLoaderFactoryImplTest()
180 : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
181 browser_context_(new TestBrowserContext()),
182 resource_message_filter_(new ResourceMessageFilter(
183 0,
184 0,
185 nullptr,
186 nullptr,
187 nullptr,
188 nullptr,
189 nullptr,
190 base::Bind(&URLLoaderFactoryImplTest::GetContexts,
191 base::Unretained(this)))) {
192 MojoAsyncResourceHandler::SetAllocationSizeForTesting(GetParam());
193
194 factory_impl_holder_.reset(new URLLoaderFactoryHolder(
195 resource_message_filter_, mojo::GetProxy(&factory_)));
196
197 // Calling this function creates a request context.
198 browser_context_->GetResourceContext()->GetRequestContext();
199 base::RunLoop().RunUntilIdle();
200 }
201
202 ~URLLoaderFactoryImplTest() override {
203 rdh_.SetDelegate(nullptr);
204 net::URLRequestFilter::GetInstance()->ClearHandlers();
205
206 rdh_.CancelRequestsForProcess(resource_message_filter_->child_id());
207 base::RunLoop().RunUntilIdle();
208 }
209
210 void GetContexts(ResourceType resource_type,
211 int origin_pid,
212 ResourceContext** resource_context,
213 net::URLRequestContext** request_context) {
214 *resource_context = browser_context_->GetResourceContext();
215 *request_context =
216 browser_context_->GetResourceContext()->GetRequestContext();
217 }
218
219 void RunUntilNextNotification(FakeURLLoaderClient* client) {
220 base::RunLoop run_loop;
221 client->set_quit_closure(run_loop.QuitClosure());
222 run_loop.Run();
223 }
224
225 TestBrowserThreadBundle thread_bundle_;
226 ResourceDispatcherHostImpl rdh_;
227 std::unique_ptr<TestBrowserContext> browser_context_;
228 scoped_refptr<ResourceMessageFilter> resource_message_filter_;
229 mojom::URLLoaderFactoryPtr factory_;
230 std::unique_ptr<URLLoaderFactoryHolder> factory_impl_holder_;
231
232 DISALLOW_COPY_AND_ASSIGN(URLLoaderFactoryImplTest);
233 };
234
235 TEST_P(URLLoaderFactoryImplTest, GetResponse) {
236 mojom::URLLoaderPtr loader;
237 base::FilePath root;
238 PathService::Get(DIR_TEST_DATA, &root);
239 net::URLRequestMockHTTPJob::AddUrlHandlers(root,
240 BrowserThread::GetBlockingPool());
mmenke 2016/06/13 20:56:59 Suggest adding all these mock handler setup calls
yhirano 2016/07/12 10:49:11 I'd prefer writing case-specific preparation in th
mmenke 2016/07/12 15:10:45 You call net::URLRequestFailedJob::AddUrlHandler()
yhirano 2016/07/13 12:04:57 I removed one of them at PS49, so there is one net
241 ResourceRequest request;
242 FakeURLLoaderClient client;
243 // Assume the file contents is small enough to be stored in the data pipe.
244 request.url = net::URLRequestMockHTTPJob::GetMockUrl("hello.html");
245 request.method = "GET";
246 factory_->CreateLoaderAndStart(mojo::GetProxy(&loader), 1, request,
247 client.CreateInterfacePtrAndBind());
248
249 ASSERT_FALSE(client.has_received_response());
250 ASSERT_FALSE(client.response_body().is_valid());
251 ASSERT_FALSE(client.has_received_completion());
252
253 RunUntilNextNotification(&client);
254 ASSERT_TRUE(client.has_received_response());
255 ASSERT_FALSE(client.has_received_completion());
256 ASSERT_FALSE(client.has_received_completion());
257
258 RunUntilNextNotification(&client);
259 ASSERT_TRUE(client.has_received_response());
260 ASSERT_TRUE(client.response_body().is_valid());
261 ASSERT_FALSE(client.has_received_completion());
262
263 RunUntilNextNotification(&client);
264 ASSERT_TRUE(client.has_received_completion());
265
266 EXPECT_EQ(200, client.response_head().headers->response_code());
267 std::string content_type;
268 client.response_head().headers->GetNormalizedHeader("content-type",
269 &content_type);
270 EXPECT_EQ("text/html", content_type);
271 EXPECT_EQ(0, client.completion_status().error_code);
272
273 std::string contents;
274 while (true) {
275 char buffer[16];
276 uint32_t read = sizeof(buffer);
277 MojoResult r = mojo::ReadDataRaw(client.response_body(), buffer, &read,
278 MOJO_READ_DATA_FLAG_NONE);
279 if (r == MOJO_RESULT_FAILED_PRECONDITION)
280 break;
281 if (r == MOJO_RESULT_SHOULD_WAIT)
282 continue;
283 ASSERT_EQ(MOJO_RESULT_OK, r);
284 contents += std::string(buffer, read);
285 }
286 EXPECT_EQ(
287 "<!doctype html>\n"
288 "<p>hello</p>\n",
289 contents);
290 }
291
292 TEST_P(URLLoaderFactoryImplTest, GetFailedResponse) {
293 mojom::URLLoaderPtr loader;
294 ResourceRequest request;
295 FakeURLLoaderClient client;
296 net::URLRequestFailedJob::AddUrlHandler();
297 request.url = net::URLRequestFailedJob::GetMockHttpUrlWithFailurePhase(
298 net::URLRequestFailedJob::START, net::ERR_TIMED_OUT);
299 request.method = "GET";
300 factory_->CreateLoaderAndStart(mojo::GetProxy(&loader), 1, request,
301 client.CreateInterfacePtrAndBind());
302
303 RunUntilNextNotification(&client);
304 ASSERT_FALSE(client.has_received_response());
305 ASSERT_FALSE(client.response_body().is_valid());
306 ASSERT_TRUE(client.has_received_completion());
307
308 EXPECT_EQ(net::ERR_TIMED_OUT, client.completion_status().error_code);
309 }
310
311 // This test tests a case where resource loading is cancelled before started.
312 TEST_P(URLLoaderFactoryImplTest, InvalidURL) {
313 mojom::URLLoaderPtr loader;
314 ResourceRequest request;
315 FakeURLLoaderClient client;
316 request.url = GURL();
317 request.method = "GET";
318 ASSERT_FALSE(request.url.is_valid());
319 factory_->CreateLoaderAndStart(mojo::GetProxy(&loader), 1, request,
320 client.CreateInterfacePtrAndBind());
321
322 RunUntilNextNotification(&client);
323 ASSERT_FALSE(client.has_received_response());
324 ASSERT_FALSE(client.response_body().is_valid());
325 ASSERT_TRUE(client.has_received_completion());
326
327 EXPECT_EQ(net::ERR_ABORTED, client.completion_status().error_code);
328 }
329
330 // This test tests a case where resource loading is cancelled before started.
331 TEST_P(URLLoaderFactoryImplTest, ShouldNotRequestURL) {
332 mojom::URLLoaderPtr loader;
333 RejectingResourceDispatcherHostDelegate rdh_delegate;
334 rdh_.SetDelegate(&rdh_delegate);
335 ResourceRequest request;
336 FakeURLLoaderClient client;
337 request.url = GURL("http://localhost/");
338 request.method = "GET";
339 factory_->CreateLoaderAndStart(mojo::GetProxy(&loader), 1, request,
340 client.CreateInterfacePtrAndBind());
341
342 RunUntilNextNotification(&client);
343 rdh_.SetDelegate(nullptr);
344
345 ASSERT_FALSE(client.has_received_response());
346 ASSERT_FALSE(client.response_body().is_valid());
347 ASSERT_TRUE(client.has_received_completion());
348
349 EXPECT_EQ(net::ERR_ABORTED, client.completion_status().error_code);
350 }
351
352 TEST_P(URLLoaderFactoryImplTest, FailedAfterResponseStarted) {
353 mojom::URLLoaderPtr loader;
354 ResourceRequest request;
355 FakeURLLoaderClient client;
356 net::URLRequestFailedJob::AddUrlHandler();
357 request.url = net::URLRequestFailedJob::GetMockHttpUrlWithFailurePhase(
358 net::URLRequestFailedJob::READ_ASYNC, net::ERR_TIMED_OUT);
359 request.method = "GET";
360 factory_->CreateLoaderAndStart(mojo::GetProxy(&loader), 1, request,
361 client.CreateInterfacePtrAndBind());
362
363 ASSERT_FALSE(client.has_received_response());
364 ASSERT_FALSE(client.response_body().is_valid());
365 ASSERT_FALSE(client.has_received_completion());
366
367 RunUntilNextNotification(&client);
368 ASSERT_FALSE(client.has_received_response());
369 ASSERT_TRUE(client.response_body().is_valid());
370 ASSERT_FALSE(client.has_received_completion());
371
372 RunUntilNextNotification(&client);
373 ASSERT_FALSE(client.has_received_response());
374 ASSERT_TRUE(client.response_body().is_valid());
375 ASSERT_TRUE(client.has_received_completion());
376
377 EXPECT_EQ(net::ERR_TIMED_OUT, client.completion_status().error_code);
378 }
379
380 TEST_P(URLLoaderFactoryImplTest, BrokenBody) {
381 mojom::URLLoaderPtr loader;
382 ResourceRequest request;
383 FakeURLLoaderClient client;
384 request.url = GURL("http://www.example.com/test");
385 request.method = "GET";
386 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
387 request.url,
388 base::WrapUnique(new TestInterceptorForBrokenBody(request.url)));
389 factory_->CreateLoaderAndStart(mojo::GetProxy(&loader), 1, request,
390 client.CreateInterfacePtrAndBind());
391
392 ASSERT_FALSE(client.has_received_response());
393 ASSERT_FALSE(client.response_body().is_valid());
394 ASSERT_FALSE(client.has_received_completion());
395
396 RunUntilNextNotification(&client);
397 ASSERT_FALSE(client.has_received_response());
398 ASSERT_TRUE(client.response_body().is_valid());
399 ASSERT_TRUE(client.has_received_completion());
400
401 EXPECT_EQ(net::ERR_FAILED, client.completion_status().error_code);
402 }
403
404 INSTANTIATE_TEST_CASE_P(URLLoaderFactoryImplTest,
405 URLLoaderFactoryImplTest,
406 ::testing::Values(128, 32 * 1024));
mmenke 2016/06/13 20:56:58 None of these tests seem to return anything with a
yhirano 2016/07/12 10:49:11 The parameter is not for such cases. The mime snif
407
408 } // namespace
mmenke 2016/06/13 20:56:58 How about a test that fails the CheckForSufficient
mmenke 2016/06/13 20:56:58 Can we make BeginWriteDataRaw return sync/async/er
mmenke 2016/06/13 20:56:59 Should have tests that check each of the strings i
yhirano 2016/07/12 10:49:11 These are tested in mojo_async_resource_handler_un
409
410 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698