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

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

Issue 2092993002: Browser process changes for Resource Timing sizes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Stop using AllocateForTesting() Created 4 years, 5 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/async_resource_handler.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <memory>
10 #include <string>
11 #include <tuple>
12 #include <utility>
13 #include <vector>
14
15 #include "base/bind.h"
16 #include "base/bind_helpers.h"
17 #include "base/feature_list.h"
18 #include "base/logging.h"
19 #include "base/memory/ptr_util.h"
20 #include "base/memory/ref_counted.h"
21 #include "base/memory/shared_memory_handle.h"
22 #include "base/memory/weak_ptr.h"
23 #include "base/process/process.h"
24 #include "base/process/process_handle.h"
25 #include "base/run_loop.h"
26 #include "base/strings/string_number_conversions.h"
27 #include "content/browser/loader/resource_dispatcher_host_impl.h"
28 #include "content/browser/loader/resource_loader.h"
29 #include "content/browser/loader/resource_loader_delegate.h"
30 #include "content/browser/loader/resource_message_filter.h"
31 #include "content/browser/loader/resource_request_info_impl.h"
32 #include "content/common/resource_messages.h"
33 #include "content/common/resource_request.h"
34 #include "content/public/browser/resource_context.h"
35 #include "content/public/browser/resource_request_info.h"
36 #include "content/public/common/content_features.h"
37 #include "content/public/common/process_type.h"
38 #include "content/public/common/resource_type.h"
39 #include "content/public/test/mock_resource_context.h"
40 #include "content/public/test/test_browser_thread_bundle.h"
41 #include "ipc/ipc_message.h"
42 #include "ipc/ipc_message_macros.h"
43 #include "net/http/http_response_headers.h"
44 #include "net/http/http_util.h"
45 #include "net/url_request/url_request.h"
46 #include "net/url_request/url_request_context.h"
47 #include "net/url_request/url_request_job_factory_impl.h"
48 #include "net/url_request/url_request_test_job.h"
49 #include "net/url_request/url_request_test_util.h"
50 #include "testing/gtest/include/gtest/gtest.h"
51 #include "ui/base/page_transition_types.h"
52 #include "url/gurl.h"
53
54 namespace content {
55
56 namespace {
57
58 // This string is repeated as necessary to create a response body of the
59 // required size. It is 8 bytes so that repeated doubling can achieve any power
60 // of 2 size exactly.
61 const char kBaseData[] = "Hello. ";
62
63 // Response short enough to be inlined into a single IPC.
64 const GURL kTestURLShort("test:short");
65
66 // Response can be sent in a single chunk (not inlined).
67 const GURL kTestURLMedium("test:medium");
68
69 // Size of response to kTestURLMedium. It should be a power of 2 and larger than
70 // kInlinedLeadingChunkSize.
71 const size_t kMediumLength = 4096;
72
73 // Response requires two chunks.
74 const GURL kTestURLLarge("test:large");
75
76 // Size of response to kTestURLLarge. It should be a power of 2 and larger than
77 // kMaxAllocationSize.
78 const size_t kLargeLength = 64 * 1024;
79
80 std::string RepeatData(size_t target_size) {
81 std::string data = kBaseData;
82 data.reserve(target_size);
83 while (data.size() < target_size)
84 data += data;
85 return data;
86 }
kinuko 2016/07/11 02:35:24 Why can't we use simple method like std::string(ta
Adam Rice 2016/07/11 05:16:36 Oh. Yes. Sorry. Done.
87
88 // This test job adds a Content-Length header and implements
89 // GetTotalReceivedBytes().
90 class TestJob : public net::URLRequestTestJob {
91 public:
92 TestJob(net::URLRequest* request, net::NetworkDelegate* network_delegate)
93 : net::URLRequestTestJob(request, network_delegate, true) {}
94
95 // URLRequestJob implementation:
kinuko 2016/07/11 02:35:25 Should we have a TODO to implement this in URLRequ
Adam Rice 2016/07/11 05:16:36 Done.
96 int64_t GetTotalReceivedBytes() const override {
97 std::string http_headers = net::HttpUtil::ConvertHeadersBackToHTTPResponse(
98 response_headers_->raw_headers());
99 return http_headers.size() + offset_;
100 }
101
102 protected:
103 // Override URLRequestTestJob behaviour.
104 void StartAsync() override {
kinuko 2016/07/11 02:35:25 I think it's easier to extend / more readable if w
Adam Rice 2016/07/11 05:16:36 That is simpler. Done.
105 std::string data;
106 if (request_->url() == kTestURLShort) {
107 data = kBaseData;
108 } else if (request_->url() == kTestURLMedium) {
109 data = RepeatData(kMediumLength);
110 } else if (request_->url() == kTestURLLarge) {
111 data = RepeatData(kLargeLength);
112 }
113 if (data.empty()) {
114 URLRequestTestJob::StartAsync();
115 return;
116 }
117
118 std::string headers = test_headers();
119 response_headers_ = new net::HttpResponseHeaders(
120 net::HttpUtil::AssembleRawHeaders(headers.data(), headers.size()));
121
122 response_data_ = data;
123 response_headers_->AddHeader("Content-Length: " +
124 base::SizeTToString(data.size()));
125 URLRequestTestJob::StartAsync();
126 }
127
128 private:
129 DISALLOW_COPY_AND_ASSIGN(TestJob);
130 };
131
132 class TestJobProtocolHandler
133 : public net::URLRequestJobFactory::ProtocolHandler {
134 public:
135 net::URLRequestJob* MaybeCreateJob(
136 net::URLRequest* request,
137 net::NetworkDelegate* network_delegate) const override {
138 return new TestJob(request, network_delegate);
139 }
140 };
141
142 // A subclass of ResourceMessageFilter that records IPC messages that are sent.
143 class RecordingResourceMessageFilter : public ResourceMessageFilter {
144 public:
145 RecordingResourceMessageFilter(ResourceContext* resource_context,
146 net::URLRequestContext* request_context)
147 : ResourceMessageFilter(
148 0,
149 PROCESS_TYPE_RENDERER,
150 nullptr,
151 nullptr,
152 nullptr,
153 nullptr,
154 nullptr,
155 base::Bind(&RecordingResourceMessageFilter::GetContexts,
156 base::Unretained(this))),
157 resource_context_(resource_context),
158 request_context_(request_context) {
159 set_peer_process_for_testing(base::Process::Current());
160 }
161
162 const std::vector<std::unique_ptr<IPC::Message>>& messages() const {
163 return messages_;
164 }
165
166 // IPC::Sender implementation
167 bool Send(IPC::Message* message) override {
168 if (message->type() == ResourceMsg_SetDataBuffer::ID)
169 ConsumeHandle(*message);
170 messages_.push_back(base::WrapUnique(message));
171 return true;
172 }
173
174 private:
175 ~RecordingResourceMessageFilter() override {}
176
177 void GetContexts(ResourceType resource_type,
178 int origin_pid,
179 ResourceContext** resource_context,
180 net::URLRequestContext** request_context) {
181 *resource_context = resource_context_;
182 *request_context = request_context_;
183 }
184
185 // Unpickle the base::SharedMemoryHandle to avoid warnings about
186 // "MessageAttachmentSet destroyed with unconsumed descriptors".
187 void ConsumeHandle(const IPC::Message& message) {
188 IPC_BEGIN_MESSAGE_MAP(RecordingResourceMessageFilter, message)
189 IPC_MESSAGE_HANDLER(ResourceMsg_SetDataBuffer, OnSetDataBuffer)
190 IPC_MESSAGE_UNHANDLED(NOTREACHED())
191 IPC_END_MESSAGE_MAP()
kinuko 2016/07/11 02:35:25 Isn't it more compact / easier to read if we just
Adam Rice 2016/07/11 05:16:36 I didn't think that would work. I should have trie
192 }
193
194 void OnSetDataBuffer(int request_id,
195 base::SharedMemoryHandle shm_handle,
196 int shm_size,
197 base::ProcessId renderer_pid) {}
198
199 ResourceContext* const resource_context_;
200 net::URLRequestContext* const request_context_;
201 std::vector<std::unique_ptr<IPC::Message>> messages_;
202 };
203
204 class AsyncResourceHandlerTest : public ::testing::Test {
205 protected:
206 AsyncResourceHandlerTest()
207 : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP), context_(true) {}
208
209 void CreateRequest(const GURL& url) {
210 test_job_factory_.SetProtocolHandler(
211 "test", base::MakeUnique<TestJobProtocolHandler>());
212 context_.set_job_factory(&test_job_factory_);
213 context_.Init();
214 std::unique_ptr<net::URLRequest> request =
215 context_.CreateRequest(GURL(url), net::DEFAULT_PRIORITY, nullptr);
216 resource_context_ = base::MakeUnique<MockResourceContext>(&context_);
217 filter_ = make_scoped_refptr(
218 new RecordingResourceMessageFilter(resource_context_.get(), &context_));
219 ResourceRequestInfoImpl* info = new ResourceRequestInfoImpl(
Mike West 2016/07/08 13:14:37 Nit: Wrap this in `// clang format off` at the top
Adam Rice 2016/07/11 02:07:59 Actually, the comments on each line are sufficient
kinuko 2016/07/11 02:35:24 Note that ResourceRequestInfo::AllocateForTesting
Adam Rice 2016/07/11 05:16:36 ResourceRequestInfo::AllocateForTesting() only set
kinuko 2016/07/11 06:43:38 I see... then we probably need to live with this l
220 PROCESS_TYPE_RENDERER, // process_type
221 0, // child_id
222 0, // route_id
223 -1, // frame_tree_node_id
224 0, // origin_pid
225 0, // request_id
226 0, // render_frame_id
227 false, // is_main_frame
228 false, // parent_is_main_frame
229 RESOURCE_TYPE_IMAGE, // resource_type
230 ui::PAGE_TRANSITION_LINK, // transition_type
231 false, // should_replace_current_entry
232 false, // is_download
233 false, // is_stream
234 false, // allow_download
235 false, // has_user_gesture
236 false, // enable load timing
237 false, // enable upload progress
238 false, // do_not_prompt_for_login
239 blink::WebReferrerPolicyDefault, // referrer_policy
240 blink::WebPageVisibilityStateVisible, // visibility_state
241 resource_context_.get(), // context
242 filter_->GetWeakPtr(), // filter
243 false, // report_raw_headers
244 true, // is_async
245 false, // is_using_lofi
246 std::string(), // original_headers
247 nullptr); // body
248 info->AssociateWithRequest(request.get());
249 std::unique_ptr<AsyncResourceHandler> handler =
250 base::MakeUnique<AsyncResourceHandler>(request.get(), &rdh_);
251 loader_delegate_.reset(new TrivialResourceLoaderDelegate(this));
252 loader_ =
253 base::MakeUnique<ResourceLoader>(std::move(request), std::move(handler),
254 nullptr, loader_delegate_.get());
255 }
256
257 void StartRequest() { loader_->StartRequest(); }
258
259 void WaitForFinish() { finish_waiter_.Run(); }
kinuko 2016/07/11 02:35:25 StartRequest and WaitForFinish are called only fro
Adam Rice 2016/07/11 05:16:36 Done.
260
261 void CreateStartAndWait(const GURL& url) {
262 CreateRequest(url);
263 StartRequest();
264 WaitForFinish();
265 }
266
267 TestBrowserThreadBundle thread_bundle_;
268 ResourceDispatcherHostImpl rdh_;
269 net::TestURLRequestContext context_;
270 net::URLRequestJobFactoryImpl test_job_factory_;
271 std::unique_ptr<MockResourceContext> resource_context_;
272 scoped_refptr<RecordingResourceMessageFilter> filter_;
273 std::unique_ptr<ResourceLoader> loader_;
274 base::RunLoop finish_waiter_;
kinuko 2016/07/11 02:35:24 Looks like all fields other than filter_ can be ac
Adam Rice 2016/07/11 05:16:36 Done.
275
276 private:
277 class TrivialResourceLoaderDelegate : public ResourceLoaderDelegate {
kinuko 2016/07/11 02:35:24 I think AsyncResourceHandlerTest can directly impl
Adam Rice 2016/07/11 05:16:36 Done.
278 public:
279 explicit TrivialResourceLoaderDelegate(AsyncResourceHandlerTest* fixture)
280 : fixture_(fixture) {}
281 ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
282 ResourceLoader* loader,
283 net::AuthChallengeInfo* auth_info) override {
284 return nullptr;
285 }
286
287 bool HandleExternalProtocol(ResourceLoader* loader,
288 const GURL& url) override {
289 return false;
290 }
291 void DidStartRequest(ResourceLoader* loader) override {}
292 void DidReceiveRedirect(ResourceLoader* loader,
293 const GURL& new_url) override {}
294 void DidReceiveResponse(ResourceLoader* loader) override {}
295 void DidFinishLoading(ResourceLoader* loader) override {
296 fixture_->DidFinishLoading();
297 }
298
299 private:
300 AsyncResourceHandlerTest* fixture_;
301 };
302
303 void DidFinishLoading() {
304 loader_.reset();
305 finish_waiter_.Quit();
306 }
307
308 std::unique_ptr<TrivialResourceLoaderDelegate> loader_delegate_;
309 };
310
311 std::unique_ptr<ResourceMsg_DataReceived::Param> UnpackDataReceivedIPC(
312 const IPC::Message* msg) {
313 if (ResourceMsg_DataReceived::ID != msg->type())
314 return nullptr;
315 std::unique_ptr<ResourceMsg_DataReceived::Param> params =
316 base::MakeUnique<ResourceMsg_DataReceived::Param>();
317 ResourceMsg_DataReceived::Read(msg, params.get());
318 return params;
319 }
320
321 std::unique_ptr<ResourceMsg_InlinedDataChunkReceived::Param>
322 UnpackInlinedDataChunkReceivedIPC(const IPC::Message* msg) {
323 if (ResourceMsg_InlinedDataChunkReceived::ID != msg->type())
324 return nullptr;
325 std::unique_ptr<ResourceMsg_InlinedDataChunkReceived::Param> params =
326 base::MakeUnique<ResourceMsg_InlinedDataChunkReceived::Param>();
327 ResourceMsg_InlinedDataChunkReceived::Read(msg, params.get());
328 return params;
329 }
330
331 TEST_F(AsyncResourceHandlerTest, Construct) {
332 CreateRequest(net::URLRequestTestJob::test_url_1());
333 }
334
335 TEST_F(AsyncResourceHandlerTest, OneChunkLengths) {
336 CreateStartAndWait(kTestURLMedium);
337 const auto& messages = filter_->messages();
338 ASSERT_EQ(4u, messages.size());
339 auto params = UnpackDataReceivedIPC(messages[2].get());
340 ASSERT_TRUE(params);
kinuko 2016/07/11 02:35:24 I have a feeling that these two lines can be repla
Adam Rice 2016/07/11 05:16:36 Read() doesn't check the message type, so I had to
341
342 int encoded_data_length = std::get<3>(*params);
343 EXPECT_EQ(4163, encoded_data_length);
344 int encoded_body_length = std::get<4>(*params);
345 EXPECT_EQ(4096, encoded_body_length);
346 }
347
348 TEST_F(AsyncResourceHandlerTest, InlinedChunkLengths) {
349 // TODO(ricea): Remove this Feature-enabling code once the feature is on by
350 // default.
351 auto feature_list = base::MakeUnique<base::FeatureList>();
352 feature_list->InitializeFromCommandLine(
353 features::kOptimizeLoadingIPCForSmallResources.name, "");
354 base::FeatureList::ClearInstanceForTesting();
355 base::FeatureList::SetInstance(std::move(feature_list));
356
357 CreateStartAndWait(kTestURLShort);
358 const auto& messages = filter_->messages();
359 ASSERT_EQ(3u, messages.size());
360 auto params = UnpackInlinedDataChunkReceivedIPC(messages[1].get());
361 ASSERT_TRUE(params);
362
363 int encoded_data_length = std::get<2>(*params);
364 EXPECT_EQ(72, encoded_data_length);
365 int encoded_body_length = std::get<3>(*params);
366 EXPECT_EQ(8, encoded_body_length);
367
368 base::FeatureList::ClearInstanceForTesting();
369 base::FeatureList::SetInstance(base::MakeUnique<base::FeatureList>());
370 }
371
372 TEST_F(AsyncResourceHandlerTest, TwoChunksLengths) {
373 CreateStartAndWait(kTestURLLarge);
374 const auto& messages = filter_->messages();
375 ASSERT_EQ(5u, messages.size());
376 auto params = UnpackDataReceivedIPC(messages[2].get());
377 ASSERT_TRUE(params);
378
379 int encoded_data_length = std::get<3>(*params);
380 EXPECT_EQ(32836, encoded_data_length);
381 int encoded_body_length = std::get<4>(*params);
382 EXPECT_EQ(32768, encoded_body_length);
383
384 params = UnpackDataReceivedIPC(messages[3].get());
385 ASSERT_TRUE(params);
386 encoded_data_length = std::get<3>(*params);
387 EXPECT_EQ(32768, encoded_data_length);
388 encoded_body_length = std::get<4>(*params);
389 EXPECT_EQ(32768, encoded_body_length);
390 }
391
392 } // namespace
393
394 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698