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

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: Add missing explicit keyword 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 // Should be larger than kInlinedLeadingChunkSize
kinuko 2016/07/08 05:57:05 nit: end sentence with period (here and below)
Adam Rice 2016/07/08 07:45:25 Done.
59 const size_t kMediumLength = 4096;
60
61 // Should be larger than kMaxAllocationSize
62 const size_t kLargeLength = 64 * 1024;
63
64 const char kBaseData[] = "Hello. ";
65
66 // URLRequestTestJob doesn't implement GetTotalReceivedBytes(), so subclass it.
67 class TestJob : public net::URLRequestTestJob {
68 public:
69 TestJob(net::URLRequest* request, net::NetworkDelegate* network_delegate)
70 : net::URLRequestTestJob(request, network_delegate, true) {}
71
72 // All these URLs have a content-length header.
73
74 // Response can be inlined into IPC.
75 static GURL test_url_short_length() { return GURL("test:short"); }
76
77 // Response can be sent in a single chunk.
78 static GURL test_url_medium_length() { return GURL("test:medium"); }
79
80 // Response requires multiple chunks.
81 static GURL test_url_large_length() { return GURL("test:large"); }
kinuko 2016/07/08 05:57:05 Not sure why these need to be static methods, just
Adam Rice 2016/07/08 07:45:24 Sorry, I was copying URLRequestTestJob without thi
82
83 // URLRequestJob implementation
84 int64_t GetTotalReceivedBytes() const override {
85 std::string http_headers = net::HttpUtil::ConvertHeadersBackToHTTPResponse(
86 response_headers_->raw_headers());
87 return http_headers.size() + offset_;
88 }
89
90 protected:
91 void StartAsync() override {
92 std::string spec = request_->url().spec();
93 std::string data;
94 if (spec == test_url_short_length().spec()) {
kinuko 2016/07/08 05:57:05 nit: == operator just works for GURLs, no need to
Adam Rice 2016/07/08 07:45:25 Done.
95 data = kBaseData;
96 } else if (spec == test_url_medium_length().spec()) {
97 data = RepeatData(kMediumLength);
98 } else if (spec == test_url_large_length().spec()) {
99 data = RepeatData(kLargeLength);
100 }
101 if (data.empty()) {
102 URLRequestTestJob::StartAsync();
103 return;
104 }
105
106 std::string headers = test_headers();
107 response_headers_ = new net::HttpResponseHeaders(
108 net::HttpUtil::AssembleRawHeaders(headers.data(), headers.size()));
109
110 response_data_ = data;
111 response_headers_->AddHeader("Content-Length: " +
112 base::SizeTToString(data.size()));
113 URLRequestTestJob::StartAsync();
114 }
115
116 private:
117 std::string RepeatData(size_t target_size) {
118 std::string data = kBaseData;
119 data.reserve(target_size);
120 while (data.size() < target_size)
121 data += data;
122 return data;
123 }
124
125 DISALLOW_COPY_AND_ASSIGN(TestJob);
126 };
127
128 class TestJobProtocolHandler
kinuko 2016/07/08 05:57:05 While writing up all these test harness is nice an
Adam Rice 2016/07/08 07:45:25 A real URLRequest is needed to return non-zero val
129 : public net::URLRequestJobFactory::ProtocolHandler {
130 public:
131 // URLRequestJobFactory::ProtocolHandler implementation:
132 net::URLRequestJob* MaybeCreateJob(
133 net::URLRequest* request,
134 net::NetworkDelegate* network_delegate) const override {
135 return new TestJob(request, network_delegate);
136 }
137 };
138
139 // A subclass of ResourceMessageFilter that records IPC messages that are sent.
140 class RecordingResourceMessageFilter : public ResourceMessageFilter {
141 public:
142 RecordingResourceMessageFilter(ResourceContext* resource_context,
143 net::URLRequestContext* request_context)
144 : ResourceMessageFilter(
145 0,
146 PROCESS_TYPE_RENDERER,
147 nullptr,
148 nullptr,
149 nullptr,
150 nullptr,
151 nullptr,
152 base::Bind(&RecordingResourceMessageFilter::GetContexts,
153 base::Unretained(this))),
154 resource_context_(resource_context),
155 request_context_(request_context) {
156 set_peer_process_for_testing(base::Process::Current());
157 }
158
159 const std::vector<std::unique_ptr<IPC::Message>>& messages() const {
160 return messages_;
161 }
162
163 // IPC::Sender implementation
164 bool Send(IPC::Message* message) override {
165 if (message->type() == ResourceMsg_SetDataBuffer::ID)
166 ConsumeHandle(*message);
167 messages_.push_back(base::WrapUnique(message));
168 return true;
169 }
170
171 private:
172 ~RecordingResourceMessageFilter() override {}
173
174 void GetContexts(ResourceType resource_type,
175 int origin_pid,
176 ResourceContext** resource_context,
177 net::URLRequestContext** request_context) {
178 *resource_context = resource_context_;
179 *request_context = request_context_;
180 }
181
182 // Unpickle the base::SharedMemoryHandle to avoid warnings about
183 // "MessageAttachmentSet destroyed with unconsumed descriptors".
184 void ConsumeHandle(const IPC::Message& message) {
185 IPC_BEGIN_MESSAGE_MAP(RecordingResourceMessageFilter, message)
186 IPC_MESSAGE_HANDLER(ResourceMsg_SetDataBuffer, OnSetDataBuffer)
187 IPC_MESSAGE_UNHANDLED(NOTREACHED())
188 IPC_END_MESSAGE_MAP()
189 }
190
191 void OnSetDataBuffer(int request_id,
192 base::SharedMemoryHandle shm_handle,
193 int shm_size,
194 base::ProcessId renderer_pid) {}
195
196 ResourceContext* const resource_context_;
197 net::URLRequestContext* const request_context_;
198 std::vector<std::unique_ptr<IPC::Message>> messages_;
199 };
200
201 class AsyncResourceHandlerTest : public ::testing::Test {
202 protected:
203 AsyncResourceHandlerTest()
204 : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP), context_(true) {}
205
206 void CreateRequest(const GURL& url) {
207 test_job_factory_.SetProtocolHandler(
208 "test", base::MakeUnique<TestJobProtocolHandler>());
209 context_.set_job_factory(&test_job_factory_);
210 context_.Init();
211 std::unique_ptr<net::URLRequest> request =
212 context_.CreateRequest(GURL(url), net::DEFAULT_PRIORITY, nullptr);
213 resource_context_ = base::MakeUnique<MockResourceContext>(&context_);
214 filter_ = make_scoped_refptr(
215 new RecordingResourceMessageFilter(resource_context_.get(), &context_));
216 ResourceRequestInfoImpl* info = new ResourceRequestInfoImpl(
kinuko 2016/07/08 05:57:05 Use ResourceRequestInfo::AllocateForTesting ?
Adam Rice 2016/07/08 07:45:25 Done.
Adam Rice 2016/07/08 11:21:10 I failed to spot that AllocateForTesting() doesn't
217 PROCESS_TYPE_RENDERER, // process_type
218 0, // child_id
219 0, // route_id
220 -1, // frame_tree_node_id
221 0, // origin_pid
222 0, // request_id
223 0, // render_frame_id
224 false, // is_main_frame
225 false, // parent_is_main_frame
226 RESOURCE_TYPE_IMAGE, // resource_type
227 ui::PAGE_TRANSITION_LINK, // transition_type
228 false, // should_replace_current_entry
229 false, // is_download
230 false, // is_stream
231 false, // allow_download
232 false, // has_user_gesture
233 false, // enable load timing
234 false, // enable upload progress
235 false, // do_not_prompt_for_login
236 blink::WebReferrerPolicyDefault, // referrer_policy
237 blink::WebPageVisibilityStateVisible, // visibility_state
238 resource_context_.get(), // context
239 filter_->GetWeakPtr(), // filter
240 false, // report_raw_headers
241 true, // is_async
242 false, // is_using_lofi
243 std::string(), // original_headers
244 nullptr); // body
245 info->AssociateWithRequest(request.get());
246 std::unique_ptr<AsyncResourceHandler> handler =
247 base::MakeUnique<AsyncResourceHandler>(request.get(), &rdh_);
248 loader_delegate_.reset(new TrivialResourceLoaderDelegate(this));
249 loader_ =
250 base::MakeUnique<ResourceLoader>(std::move(request), std::move(handler),
251 nullptr, loader_delegate_.get());
252 }
253
254 void StartRequest() { loader_->StartRequest(); }
255
256 void WaitForFinish() { finish_waiter_.Run(); }
257
258 void CreateStartAndWait(const GURL& url) {
259 CreateRequest(url);
260 StartRequest();
261 WaitForFinish();
262 }
263
264 TestBrowserThreadBundle thread_bundle_;
265 ResourceDispatcherHostImpl rdh_;
266 net::TestURLRequestContext context_;
267 net::URLRequestJobFactoryImpl test_job_factory_;
268 std::unique_ptr<MockResourceContext> resource_context_;
269 scoped_refptr<RecordingResourceMessageFilter> filter_;
270 std::unique_ptr<ResourceLoader> loader_;
271 base::RunLoop finish_waiter_;
272
273 private:
274 class TrivialResourceLoaderDelegate : public ResourceLoaderDelegate {
275 public:
276 explicit TrivialResourceLoaderDelegate(AsyncResourceHandlerTest* fixture)
277 : fixture_(fixture) {}
278 ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
279 ResourceLoader* loader,
280 net::AuthChallengeInfo* auth_info) override {
281 return nullptr;
282 }
283
284 bool HandleExternalProtocol(ResourceLoader* loader,
285 const GURL& url) override {
286 return false;
287 }
288 void DidStartRequest(ResourceLoader* loader) override {}
289 void DidReceiveRedirect(ResourceLoader* loader,
290 const GURL& new_url) override {}
291 void DidReceiveResponse(ResourceLoader* loader) override {}
292 void DidFinishLoading(ResourceLoader* loader) override {
293 fixture_->DidFinishLoading();
294 }
295
296 private:
297 AsyncResourceHandlerTest* fixture_;
298 };
299
300 void DidFinishLoading() {
301 loader_.reset();
302 finish_waiter_.Quit();
303 }
304
305 std::unique_ptr<TrivialResourceLoaderDelegate> loader_delegate_;
306 };
307
308 std::unique_ptr<ResourceMsg_DataReceived::Param> UnpackDataReceivedIPC(
309 const IPC::Message* msg) {
310 if (ResourceMsg_DataReceived::ID != msg->type())
311 return nullptr;
312 static_assert(std::tuple_size<ResourceMsg_DataReceived::Param>::value == 5u,
313 "ResourceMsg_DataReceived argument count has changed. Tests "
314 "must be updated.");
315 std::unique_ptr<ResourceMsg_DataReceived::Param> params =
316 base::MakeUnique<ResourceMsg_DataReceived::Param>();
317 if (!ResourceMsg_DataReceived::Read(msg, params.get()))
318 return nullptr;
319 return params;
320 }
321
322 std::unique_ptr<ResourceMsg_InlinedDataChunkReceived::Param>
323 UnpackInlinedDataChunkReceivedIPC(const IPC::Message* msg) {
324 if (ResourceMsg_InlinedDataChunkReceived::ID != msg->type())
325 return nullptr;
326 static_assert(
327 std::tuple_size<ResourceMsg_InlinedDataChunkReceived::Param>::value == 4u,
328 "ResourceMsg_InlinedDataChunkReceived argument count has changed. Tests "
329 "must be updated.");
330 std::unique_ptr<ResourceMsg_InlinedDataChunkReceived::Param> params =
331 base::MakeUnique<ResourceMsg_InlinedDataChunkReceived::Param>();
332 if (!ResourceMsg_InlinedDataChunkReceived::Read(msg, params.get()))
333 return nullptr;
334 return params;
335 }
336
337 TEST_F(AsyncResourceHandlerTest, Construct) {
338 CreateRequest(net::URLRequestTestJob::test_url_1());
339 }
340
341 TEST_F(AsyncResourceHandlerTest, OneChunkLengths) {
342 CreateStartAndWait(TestJob::test_url_medium_length());
343 const auto& messages = filter_->messages();
344 ASSERT_EQ(4u, messages.size());
345 auto params = UnpackDataReceivedIPC(messages[2].get());
346 ASSERT_TRUE(params);
347
348 int encoded_data_length = std::get<3>(*params);
349 EXPECT_EQ(4163, encoded_data_length);
350 int encoded_body_length = std::get<4>(*params);
351 EXPECT_EQ(4096, encoded_body_length);
352 }
353
354 TEST_F(AsyncResourceHandlerTest, InlinedChunkLengths) {
355 // TODO(ricea): Remove this Feature-enabling code once the feature is on by
356 // default.
357 auto feature_list = base::MakeUnique<base::FeatureList>();
358 feature_list->InitializeFromCommandLine(
359 features::kOptimizeLoadingIPCForSmallResources.name, "");
360 base::FeatureList::ClearInstanceForTesting();
361 base::FeatureList::SetInstance(std::move(feature_list));
362
363 CreateStartAndWait(TestJob::test_url_short_length());
364 const auto& messages = filter_->messages();
365 ASSERT_EQ(3u, messages.size());
366 auto params = UnpackInlinedDataChunkReceivedIPC(messages[1].get());
367 ASSERT_TRUE(params);
368
369 int encoded_data_length = std::get<2>(*params);
370 EXPECT_EQ(72, encoded_data_length);
371 int encoded_body_length = std::get<3>(*params);
372 EXPECT_EQ(8, encoded_body_length);
373
374 base::FeatureList::ClearInstanceForTesting();
375 base::FeatureList::SetInstance(base::MakeUnique<base::FeatureList>());
376 }
377
378 TEST_F(AsyncResourceHandlerTest, TwoChunksLengths) {
379 CreateStartAndWait(TestJob::test_url_large_length());
380 const auto& messages = filter_->messages();
381 ASSERT_EQ(5u, messages.size());
382 auto params = UnpackDataReceivedIPC(messages[2].get());
383 ASSERT_TRUE(params);
384
385 int encoded_data_length = std::get<3>(*params);
386 EXPECT_EQ(32836, encoded_data_length);
387 int encoded_body_length = std::get<4>(*params);
388 EXPECT_EQ(32768, encoded_body_length);
389
390 params = UnpackDataReceivedIPC(messages[3].get());
391 ASSERT_TRUE(params);
392 encoded_data_length = std::get<3>(*params);
393 EXPECT_EQ(32768, encoded_data_length);
394 encoded_body_length = std::get<4>(*params);
395 EXPECT_EQ(32768, encoded_body_length);
396 }
397
398 } // namespace
399
400 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/loader/async_resource_handler.cc ('k') | content/browser/loader/sync_resource_handler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698