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

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: Use ResourceRequestInfo::AllocateForTesting(). Small code and comment cleanups. 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 }
87
88 // A Content-Length response header is needed for a response to be eligible for
89 // inlining in an IPC. GetTotalReceivedBytes() must be implemented to test that
90 // it is sent correctly by IPC. net::URLRequestTestJob doesn't supply a
91 // Content-Length header or implement GetTotalReceivedBytes(). TestJob is a
92 // subclass that adds these features, and also serves sufficiently large
93 // responses for our tests.
kinuko 2016/07/08 09:39:28 While this description is very useful for reviewin
Adam Rice 2016/07/08 11:21:10 Done.
94 class TestJob : public net::URLRequestTestJob {
95 public:
96 TestJob(net::URLRequest* request, net::NetworkDelegate* network_delegate)
97 : net::URLRequestTestJob(request, network_delegate, true) {}
98
99 // URLRequestJob implementation:
100 int64_t GetTotalReceivedBytes() const override {
101 std::string http_headers = net::HttpUtil::ConvertHeadersBackToHTTPResponse(
102 response_headers_->raw_headers());
103 return http_headers.size() + offset_;
104 }
105
106 protected:
107 // Override URLRequestTestJob behaviour.
108 void StartAsync() override {
109 std::string data;
110 if (request_->url() == kTestURLShort) {
111 data = kBaseData;
112 } else if (request_->url() == kTestURLMedium) {
113 data = RepeatData(kMediumLength);
114 } else if (request_->url() == kTestURLLarge) {
115 data = RepeatData(kLargeLength);
116 }
117 if (data.empty()) {
118 URLRequestTestJob::StartAsync();
119 return;
120 }
121
122 std::string headers = test_headers();
123 response_headers_ = new net::HttpResponseHeaders(
124 net::HttpUtil::AssembleRawHeaders(headers.data(), headers.size()));
125
126 response_data_ = data;
127 response_headers_->AddHeader("Content-Length: " +
128 base::SizeTToString(data.size()));
129 URLRequestTestJob::StartAsync();
130 }
131
132 private:
133 DISALLOW_COPY_AND_ASSIGN(TestJob);
134 };
135
136 // A ProtocolHandler is necessary to set TestJob as the URLRequestJob.
kinuko 2016/07/08 09:39:28 I understand you added this as a follow-up for my
Adam Rice 2016/07/08 11:21:10 Done.
137 class TestJobProtocolHandler
138 : public net::URLRequestJobFactory::ProtocolHandler {
139 public:
140 // URLRequestJobFactory::ProtocolHandler implementation:
kinuko 2016/07/08 09:39:28 nit: in this case it's obvious too, I don't think
Adam Rice 2016/07/08 11:21:10 Done.
141 net::URLRequestJob* MaybeCreateJob(
142 net::URLRequest* request,
143 net::NetworkDelegate* network_delegate) const override {
144 return new TestJob(request, network_delegate);
145 }
146 };
147
148 // A subclass of ResourceMessageFilter that records IPC messages that are sent.
149 class RecordingResourceMessageFilter : public ResourceMessageFilter {
150 public:
151 RecordingResourceMessageFilter(ResourceContext* resource_context,
152 net::URLRequestContext* request_context)
153 : ResourceMessageFilter(
154 0,
155 PROCESS_TYPE_RENDERER,
156 nullptr,
157 nullptr,
158 nullptr,
159 nullptr,
160 nullptr,
161 base::Bind(&RecordingResourceMessageFilter::GetContexts,
162 base::Unretained(this))),
163 resource_context_(resource_context),
164 request_context_(request_context) {
165 set_peer_process_for_testing(base::Process::Current());
166 }
167
168 const std::vector<std::unique_ptr<IPC::Message>>& messages() const {
169 return messages_;
170 }
171
172 // IPC::Sender implementation
173 bool Send(IPC::Message* message) override {
174 if (message->type() == ResourceMsg_SetDataBuffer::ID)
175 ConsumeHandle(*message);
176 messages_.push_back(base::WrapUnique(message));
177 return true;
178 }
179
180 private:
181 ~RecordingResourceMessageFilter() override {}
182
183 void GetContexts(ResourceType resource_type,
184 int origin_pid,
185 ResourceContext** resource_context,
186 net::URLRequestContext** request_context) {
187 *resource_context = resource_context_;
188 *request_context = request_context_;
189 }
190
191 // Unpickle the base::SharedMemoryHandle to avoid warnings about
192 // "MessageAttachmentSet destroyed with unconsumed descriptors".
193 void ConsumeHandle(const IPC::Message& message) {
194 IPC_BEGIN_MESSAGE_MAP(RecordingResourceMessageFilter, message)
195 IPC_MESSAGE_HANDLER(ResourceMsg_SetDataBuffer, OnSetDataBuffer)
196 IPC_MESSAGE_UNHANDLED(NOTREACHED())
197 IPC_END_MESSAGE_MAP()
198 }
199
200 void OnSetDataBuffer(int request_id,
201 base::SharedMemoryHandle shm_handle,
202 int shm_size,
203 base::ProcessId renderer_pid) {}
204
205 ResourceContext* const resource_context_;
206 net::URLRequestContext* const request_context_;
207 std::vector<std::unique_ptr<IPC::Message>> messages_;
208 };
209
210 class AsyncResourceHandlerTest : public ::testing::Test {
211 protected:
212 AsyncResourceHandlerTest()
213 : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP), context_(true) {}
214
215 void CreateRequest(const GURL& url) {
216 test_job_factory_.SetProtocolHandler(
217 "test", base::MakeUnique<TestJobProtocolHandler>());
218 context_.set_job_factory(&test_job_factory_);
219 context_.Init();
220 std::unique_ptr<net::URLRequest> request =
221 context_.CreateRequest(GURL(url), net::DEFAULT_PRIORITY, nullptr);
222 resource_context_ = base::MakeUnique<MockResourceContext>(&context_);
223 filter_ = make_scoped_refptr(
224 new RecordingResourceMessageFilter(resource_context_.get(), &context_));
225 ResourceRequestInfo::AllocateForTesting(request.get(), RESOURCE_TYPE_IMAGE,
226 resource_context_.get(),
227 0, // render_process_id
228 0, // render_view_id
229 0, // render_frame_id
230 false, // is_main_frame
231 false, // parent_is_main_frame
232 false, // allow_download
233 true, // is_async
234 false); // is_using_lofi
235 std::unique_ptr<AsyncResourceHandler> handler =
236 base::MakeUnique<AsyncResourceHandler>(request.get(), &rdh_);
237 loader_delegate_.reset(new TrivialResourceLoaderDelegate(this));
238 loader_ =
239 base::MakeUnique<ResourceLoader>(std::move(request), std::move(handler),
240 nullptr, loader_delegate_.get());
241 }
242
243 void StartRequest() { loader_->StartRequest(); }
244
245 void WaitForFinish() { finish_waiter_.Run(); }
246
247 void CreateStartAndWait(const GURL& url) {
248 CreateRequest(url);
249 StartRequest();
250 WaitForFinish();
251 }
252
253 TestBrowserThreadBundle thread_bundle_;
254 ResourceDispatcherHostImpl rdh_;
255 net::TestURLRequestContext context_;
256 net::URLRequestJobFactoryImpl test_job_factory_;
257 std::unique_ptr<MockResourceContext> resource_context_;
258 scoped_refptr<RecordingResourceMessageFilter> filter_;
259 std::unique_ptr<ResourceLoader> loader_;
260 base::RunLoop finish_waiter_;
261
262 private:
263 class TrivialResourceLoaderDelegate : public ResourceLoaderDelegate {
264 public:
265 explicit TrivialResourceLoaderDelegate(AsyncResourceHandlerTest* fixture)
266 : fixture_(fixture) {}
267 ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
268 ResourceLoader* loader,
269 net::AuthChallengeInfo* auth_info) override {
270 return nullptr;
271 }
272
273 bool HandleExternalProtocol(ResourceLoader* loader,
274 const GURL& url) override {
275 return false;
276 }
277 void DidStartRequest(ResourceLoader* loader) override {}
278 void DidReceiveRedirect(ResourceLoader* loader,
279 const GURL& new_url) override {}
280 void DidReceiveResponse(ResourceLoader* loader) override {}
281 void DidFinishLoading(ResourceLoader* loader) override {
282 fixture_->DidFinishLoading();
283 }
284
285 private:
286 AsyncResourceHandlerTest* fixture_;
287 };
288
289 void DidFinishLoading() {
290 loader_.reset();
291 finish_waiter_.Quit();
292 }
293
294 std::unique_ptr<TrivialResourceLoaderDelegate> loader_delegate_;
295 };
296
297 std::unique_ptr<ResourceMsg_DataReceived::Param> UnpackDataReceivedIPC(
298 const IPC::Message* msg) {
299 if (ResourceMsg_DataReceived::ID != msg->type())
300 return nullptr;
301 static_assert(std::tuple_size<ResourceMsg_DataReceived::Param>::value == 5u,
302 "ResourceMsg_DataReceived argument count has changed. Tests "
303 "must be updated.");
kinuko 2016/07/08 09:39:28 I feel these static_asserts are a bit too much. Wh
Adam Rice 2016/07/08 11:21:10 I wanted to save debugging time. But since new arg
304 std::unique_ptr<ResourceMsg_DataReceived::Param> params =
305 base::MakeUnique<ResourceMsg_DataReceived::Param>();
306 if (!ResourceMsg_DataReceived::Read(msg, params.get()))
kinuko 2016/07/08 09:39:28 Is checking the return value that useful here?
Adam Rice 2016/07/08 11:21:10 As far I can tell it will only catch bugs in the I
307 return nullptr;
308 return params;
309 }
310
311 std::unique_ptr<ResourceMsg_InlinedDataChunkReceived::Param>
312 UnpackInlinedDataChunkReceivedIPC(const IPC::Message* msg) {
313 if (ResourceMsg_InlinedDataChunkReceived::ID != msg->type())
314 return nullptr;
315 static_assert(
316 std::tuple_size<ResourceMsg_InlinedDataChunkReceived::Param>::value == 4u,
317 "ResourceMsg_InlinedDataChunkReceived argument count has changed. Tests "
318 "must be updated.");
319 std::unique_ptr<ResourceMsg_InlinedDataChunkReceived::Param> params =
320 base::MakeUnique<ResourceMsg_InlinedDataChunkReceived::Param>();
321 if (!ResourceMsg_InlinedDataChunkReceived::Read(msg, params.get()))
322 return nullptr;
323 return params;
324 }
325
326 TEST_F(AsyncResourceHandlerTest, Construct) {
327 CreateRequest(net::URLRequestTestJob::test_url_1());
328 }
329
330 TEST_F(AsyncResourceHandlerTest, OneChunkLengths) {
331 CreateStartAndWait(kTestURLMedium);
332 const auto& messages = filter_->messages();
333 ASSERT_EQ(4u, messages.size());
334 auto params = UnpackDataReceivedIPC(messages[2].get());
335 ASSERT_TRUE(params);
336
337 int encoded_data_length = std::get<3>(*params);
338 EXPECT_EQ(4163, encoded_data_length);
339 int encoded_body_length = std::get<4>(*params);
340 EXPECT_EQ(4096, encoded_body_length);
341 }
342
343 TEST_F(AsyncResourceHandlerTest, InlinedChunkLengths) {
344 // TODO(ricea): Remove this Feature-enabling code once the feature is on by
345 // default.
346 auto feature_list = base::MakeUnique<base::FeatureList>();
347 feature_list->InitializeFromCommandLine(
348 features::kOptimizeLoadingIPCForSmallResources.name, "");
349 base::FeatureList::ClearInstanceForTesting();
350 base::FeatureList::SetInstance(std::move(feature_list));
351
352 CreateStartAndWait(kTestURLShort);
353 const auto& messages = filter_->messages();
354 ASSERT_EQ(3u, messages.size());
355 auto params = UnpackInlinedDataChunkReceivedIPC(messages[1].get());
356 ASSERT_TRUE(params);
357
358 int encoded_data_length = std::get<2>(*params);
359 EXPECT_EQ(72, encoded_data_length);
360 int encoded_body_length = std::get<3>(*params);
361 EXPECT_EQ(8, encoded_body_length);
362
363 base::FeatureList::ClearInstanceForTesting();
364 base::FeatureList::SetInstance(base::MakeUnique<base::FeatureList>());
365 }
366
367 TEST_F(AsyncResourceHandlerTest, TwoChunksLengths) {
368 CreateStartAndWait(kTestURLLarge);
369 const auto& messages = filter_->messages();
370 ASSERT_EQ(5u, messages.size());
371 auto params = UnpackDataReceivedIPC(messages[2].get());
372 ASSERT_TRUE(params);
373
374 int encoded_data_length = std::get<3>(*params);
375 EXPECT_EQ(32836, encoded_data_length);
376 int encoded_body_length = std::get<4>(*params);
377 EXPECT_EQ(32768, encoded_body_length);
378
379 params = UnpackDataReceivedIPC(messages[3].get());
380 ASSERT_TRUE(params);
381 encoded_data_length = std::get<3>(*params);
382 EXPECT_EQ(32768, encoded_data_length);
383 encoded_body_length = std::get<4>(*params);
384 EXPECT_EQ(32768, encoded_body_length);
385 }
386
387 } // namespace
388
389 } // 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