When enabling new profile management programmatically, make sure to set the
[chromium-blink-merge.git] / content / browser / loader / resource_scheduler_unittest.cc
blobf4cb0e0f0919d79b36277a614a4bcf559a25e359
1 // Copyright (c) 2012 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.
5 #include "content/browser/loader/resource_scheduler.h"
7 #include "base/memory/scoped_vector.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "content/browser/browser_thread_impl.h"
11 #include "content/browser/loader/resource_dispatcher_host_impl.h"
12 #include "content/browser/loader/resource_message_filter.h"
13 #include "content/browser/loader/resource_request_info_impl.h"
14 #include "content/common/resource_messages.h"
15 #include "content/public/browser/resource_context.h"
16 #include "content/public/browser/resource_controller.h"
17 #include "content/public/browser/resource_throttle.h"
18 #include "content/public/common/process_type.h"
19 #include "net/base/host_port_pair.h"
20 #include "net/base/request_priority.h"
21 #include "net/http/http_server_properties_impl.h"
22 #include "net/url_request/url_request.h"
23 #include "net/url_request/url_request_test_util.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "webkit/common/resource_type.h"
27 namespace content {
29 namespace {
31 class TestRequestFactory;
33 const int kChildId = 30;
34 const int kRouteId = 75;
36 class TestRequest : public ResourceController {
37 public:
38 TestRequest(scoped_ptr<ResourceThrottle> throttle,
39 scoped_ptr<net::URLRequest> url_request)
40 : started_(false),
41 throttle_(throttle.Pass()),
42 url_request_(url_request.Pass()) {
43 throttle_->set_controller_for_testing(this);
46 bool started() const { return started_; }
48 void Start() {
49 bool deferred = false;
50 throttle_->WillStartRequest(&deferred);
51 started_ = !deferred;
54 const net::URLRequest* url_request() const { return url_request_.get(); }
56 protected:
57 // ResourceController interface:
58 virtual void Cancel() OVERRIDE {}
59 virtual void CancelAndIgnore() OVERRIDE {}
60 virtual void CancelWithError(int error_code) OVERRIDE {}
61 virtual void Resume() OVERRIDE { started_ = true; }
63 private:
64 bool started_;
65 scoped_ptr<ResourceThrottle> throttle_;
66 scoped_ptr<net::URLRequest> url_request_;
69 class CancelingTestRequest : public TestRequest {
70 public:
71 CancelingTestRequest(scoped_ptr<ResourceThrottle> throttle,
72 scoped_ptr<net::URLRequest> url_request)
73 : TestRequest(throttle.Pass(), url_request.Pass()) {
76 void set_request_to_cancel(scoped_ptr<TestRequest> request_to_cancel) {
77 request_to_cancel_ = request_to_cancel.Pass();
80 private:
81 virtual void Resume() OVERRIDE {
82 TestRequest::Resume();
83 request_to_cancel_.reset();
86 scoped_ptr<TestRequest> request_to_cancel_;
89 class FakeResourceContext : public ResourceContext {
90 private:
91 virtual net::HostResolver* GetHostResolver() OVERRIDE { return NULL; }
92 virtual net::URLRequestContext* GetRequestContext() OVERRIDE { return NULL; }
93 virtual bool AllowMicAccess(const GURL& origin) OVERRIDE { return false; }
94 virtual bool AllowCameraAccess(const GURL& origin) OVERRIDE { return false; }
97 class FakeResourceMessageFilter : public ResourceMessageFilter {
98 public:
99 FakeResourceMessageFilter(int child_id)
100 : ResourceMessageFilter(
101 child_id,
102 PROCESS_TYPE_RENDERER,
103 NULL /* appcache_service */,
104 NULL /* blob_storage_context */,
105 NULL /* file_system_context */,
106 NULL /* service_worker_context */,
107 base::Bind(&FakeResourceMessageFilter::GetContexts,
108 base::Unretained(this))) {
111 private:
112 virtual ~FakeResourceMessageFilter() {}
114 void GetContexts(const ResourceHostMsg_Request& request,
115 ResourceContext** resource_context,
116 net::URLRequestContext** request_context) {
117 *resource_context = &context_;
118 *request_context = NULL;
121 FakeResourceContext context_;
124 class ResourceSchedulerTest : public testing::Test {
125 protected:
126 ResourceSchedulerTest()
127 : next_request_id_(0),
128 ui_thread_(BrowserThread::UI, &message_loop_),
129 io_thread_(BrowserThread::IO, &message_loop_) {
130 scheduler_.OnClientCreated(kChildId, kRouteId);
131 context_.set_http_server_properties(http_server_properties_.GetWeakPtr());
134 virtual ~ResourceSchedulerTest() {
135 scheduler_.OnClientDeleted(kChildId, kRouteId);
138 scoped_ptr<net::URLRequest> NewURLRequestWithRoute(
139 const char* url,
140 net::RequestPriority priority,
141 int route_id) {
142 scoped_ptr<net::URLRequest> url_request(
143 context_.CreateRequest(GURL(url), priority, NULL, NULL));
144 ResourceRequestInfoImpl* info = new ResourceRequestInfoImpl(
145 PROCESS_TYPE_RENDERER, // process_type
146 kChildId, // child_id
147 route_id, // route_id
148 0, // origin_pid
149 ++next_request_id_, // request_id
150 MSG_ROUTING_NONE, // render_frame_id
151 false, // is_main_frame
152 false, // parent_is_main_frame
153 0, // parent_render_frame_id
154 ResourceType::SUB_RESOURCE, // resource_type
155 PAGE_TRANSITION_LINK, // transition_type
156 false, // should_replace_current_entry
157 false, // is_download
158 false, // is_stream
159 true, // allow_download
160 false, // has_user_gesture
161 blink::WebReferrerPolicyDefault, // referrer_policy
162 blink::WebPageVisibilityStateVisible, // visibility_state
163 NULL, // context
164 base::WeakPtr<ResourceMessageFilter>(), // filter
165 true); // is_async
166 info->AssociateWithRequest(url_request.get());
167 return url_request.Pass();
170 scoped_ptr<net::URLRequest> NewURLRequest(const char* url,
171 net::RequestPriority priority) {
172 return NewURLRequestWithRoute(url, priority, kRouteId);
175 TestRequest* NewRequestWithRoute(const char* url,
176 net::RequestPriority priority,
177 int route_id) {
178 scoped_ptr<net::URLRequest> url_request(
179 NewURLRequestWithRoute(url, priority, route_id));
180 scoped_ptr<ResourceThrottle> throttle(scheduler_.ScheduleRequest(
181 kChildId, route_id, url_request.get()));
182 TestRequest* request = new TestRequest(throttle.Pass(), url_request.Pass());
183 request->Start();
184 return request;
187 TestRequest* NewRequest(const char* url, net::RequestPriority priority) {
188 return NewRequestWithRoute(url, priority, kRouteId);
191 void ChangeRequestPriority(TestRequest* request,
192 net::RequestPriority new_priority,
193 int intra_priority = 0) {
194 scoped_refptr<FakeResourceMessageFilter> filter(
195 new FakeResourceMessageFilter(kChildId));
196 const ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(
197 request->url_request());
198 const GlobalRequestID& id = info->GetGlobalRequestID();
199 ResourceHostMsg_DidChangePriority msg(id.request_id, new_priority,
200 intra_priority);
201 rdh_.OnMessageReceived(msg, filter.get());
204 int next_request_id_;
205 base::MessageLoopForIO message_loop_;
206 BrowserThreadImpl ui_thread_;
207 BrowserThreadImpl io_thread_;
208 ResourceDispatcherHostImpl rdh_;
209 ResourceScheduler scheduler_;
210 net::HttpServerPropertiesImpl http_server_properties_;
211 net::TestURLRequestContext context_;
214 TEST_F(ResourceSchedulerTest, OneIsolatedLowRequest) {
215 scoped_ptr<TestRequest> request(NewRequest("http://host/1", net::LOWEST));
216 EXPECT_TRUE(request->started());
219 TEST_F(ResourceSchedulerTest, OneLowLoadsUntilIdle) {
220 scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
221 scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
222 scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
223 EXPECT_TRUE(high->started());
224 EXPECT_TRUE(low->started());
225 EXPECT_FALSE(low2->started());
226 high.reset();
227 EXPECT_TRUE(low2->started());
230 TEST_F(ResourceSchedulerTest, OneLowLoadsUntilBodyInserted) {
231 scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
232 scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
233 scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
234 EXPECT_TRUE(high->started());
235 EXPECT_TRUE(low->started());
236 EXPECT_FALSE(low2->started());
237 scheduler_.OnWillInsertBody(kChildId, kRouteId);
238 EXPECT_TRUE(low2->started());
241 TEST_F(ResourceSchedulerTest, OneLowLoadsUntilBodyInsertedExceptSpdy) {
242 http_server_properties_.SetSupportsSpdy(
243 net::HostPortPair("spdyhost", 443), true);
244 scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
245 scoped_ptr<TestRequest> low_spdy(
246 NewRequest("https://spdyhost/high", net::LOWEST));
247 scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
248 scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
249 EXPECT_TRUE(high->started());
250 EXPECT_TRUE(low_spdy->started());
251 EXPECT_TRUE(low->started());
252 EXPECT_FALSE(low2->started());
253 scheduler_.OnWillInsertBody(kChildId, kRouteId);
254 EXPECT_TRUE(low2->started());
257 TEST_F(ResourceSchedulerTest, NavigationResetsState) {
258 scheduler_.OnWillInsertBody(kChildId, kRouteId);
259 scheduler_.OnNavigate(kChildId, kRouteId);
260 scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
261 scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
262 scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
263 EXPECT_TRUE(high->started());
264 EXPECT_TRUE(low->started());
265 EXPECT_FALSE(low2->started());
268 TEST_F(ResourceSchedulerTest, BackgroundRequestStartsImmediately) {
269 const int route_id = 0; // Indicates a background request.
270 scoped_ptr<TestRequest> request(NewRequestWithRoute("http://host/1",
271 net::LOWEST, route_id));
272 EXPECT_TRUE(request->started());
275 TEST_F(ResourceSchedulerTest, StartMultipleLowRequestsWhenIdle) {
276 scoped_ptr<TestRequest> high1(NewRequest("http://host/high1", net::HIGHEST));
277 scoped_ptr<TestRequest> high2(NewRequest("http://host/high2", net::HIGHEST));
278 scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
279 scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
280 EXPECT_TRUE(high1->started());
281 EXPECT_TRUE(high2->started());
282 EXPECT_TRUE(low->started());
283 EXPECT_FALSE(low2->started());
284 high1.reset();
285 EXPECT_FALSE(low2->started());
286 high2.reset();
287 EXPECT_TRUE(low2->started());
290 TEST_F(ResourceSchedulerTest, CancelOtherRequestsWhileResuming) {
291 scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
292 scoped_ptr<TestRequest> low1(NewRequest("http://host/low1", net::LOWEST));
294 scoped_ptr<net::URLRequest> url_request(
295 NewURLRequest("http://host/low2", net::LOWEST));
296 scoped_ptr<ResourceThrottle> throttle(scheduler_.ScheduleRequest(
297 kChildId, kRouteId, url_request.get()));
298 scoped_ptr<CancelingTestRequest> low2(new CancelingTestRequest(
299 throttle.Pass(), url_request.Pass()));
300 low2->Start();
302 scoped_ptr<TestRequest> low3(NewRequest("http://host/low3", net::LOWEST));
303 low2->set_request_to_cancel(low3.Pass());
304 scoped_ptr<TestRequest> low4(NewRequest("http://host/low4", net::LOWEST));
306 EXPECT_TRUE(high->started());
307 EXPECT_FALSE(low2->started());
308 high.reset();
309 EXPECT_TRUE(low1->started());
310 EXPECT_TRUE(low2->started());
311 EXPECT_TRUE(low4->started());
314 TEST_F(ResourceSchedulerTest, LimitedNumberOfDelayableRequestsInFlight) {
315 // We only load low priority resources if there's a body.
316 scheduler_.OnWillInsertBody(kChildId, kRouteId);
318 // Throw in one high priority request to make sure that's not a factor.
319 scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
320 EXPECT_TRUE(high->started());
322 const int kMaxNumDelayableRequestsPerClient = 10; // Should match the .cc.
323 const int kMaxNumDelayableRequestsPerHost = 6;
324 ScopedVector<TestRequest> lows_singlehost;
325 // Queue up to the per-host limit (we subtract the current high-pri request).
326 for (int i = 0; i < kMaxNumDelayableRequestsPerHost - 1; ++i) {
327 string url = "http://host/low" + base::IntToString(i);
328 lows_singlehost.push_back(NewRequest(url.c_str(), net::LOWEST));
329 EXPECT_TRUE(lows_singlehost[i]->started());
332 scoped_ptr<TestRequest> second_last_singlehost(NewRequest("http://host/last",
333 net::LOWEST));
334 scoped_ptr<TestRequest> last_singlehost(NewRequest("http://host/s_last",
335 net::LOWEST));
337 EXPECT_FALSE(second_last_singlehost->started());
338 high.reset();
339 EXPECT_TRUE(second_last_singlehost->started());
340 EXPECT_FALSE(last_singlehost->started());
341 lows_singlehost.erase(lows_singlehost.begin());
342 EXPECT_TRUE(last_singlehost->started());
344 // Queue more requests from different hosts until we reach the total limit.
345 int expected_slots_left =
346 kMaxNumDelayableRequestsPerClient - kMaxNumDelayableRequestsPerHost;
347 EXPECT_GT(expected_slots_left, 0);
348 ScopedVector<TestRequest> lows_differenthosts;
349 for (int i = 0; i < expected_slots_left; ++i) {
350 string url = "http://host" + base::IntToString(i) + "/low";
351 lows_differenthosts.push_back(NewRequest(url.c_str(), net::LOWEST));
352 EXPECT_TRUE(lows_differenthosts[i]->started());
355 scoped_ptr<TestRequest> last_differenthost(NewRequest("http://host_new/last",
356 net::LOWEST));
357 EXPECT_FALSE(last_differenthost->started());
360 TEST_F(ResourceSchedulerTest, RaisePriorityAndStart) {
361 // Dummies to enforce scheduling.
362 scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
363 scoped_ptr<TestRequest> low(NewRequest("http://host/req", net::LOWEST));
365 scoped_ptr<TestRequest> request(NewRequest("http://host/req", net::LOWEST));
366 EXPECT_FALSE(request->started());
368 ChangeRequestPriority(request.get(), net::HIGHEST);
369 EXPECT_TRUE(request->started());
372 TEST_F(ResourceSchedulerTest, RaisePriorityInQueue) {
373 // Dummies to enforce scheduling.
374 scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
375 scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
377 scoped_ptr<TestRequest> request(NewRequest("http://host/req", net::IDLE));
378 scoped_ptr<TestRequest> idle(NewRequest("http://host/idle", net::IDLE));
379 EXPECT_FALSE(request->started());
380 EXPECT_FALSE(idle->started());
382 ChangeRequestPriority(request.get(), net::LOWEST);
383 EXPECT_FALSE(request->started());
384 EXPECT_FALSE(idle->started());
386 const int kMaxNumDelayableRequestsPerClient = 10; // Should match the .cc.
387 ScopedVector<TestRequest> lows;
388 for (int i = 0; i < kMaxNumDelayableRequestsPerClient - 1; ++i) {
389 string url = "http://host/low" + base::IntToString(i);
390 lows.push_back(NewRequest(url.c_str(), net::LOWEST));
393 scheduler_.OnWillInsertBody(kChildId, kRouteId);
394 EXPECT_TRUE(request->started());
395 EXPECT_FALSE(idle->started());
398 TEST_F(ResourceSchedulerTest, LowerPriority) {
399 // Dummies to enforce scheduling.
400 scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
401 scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
403 scoped_ptr<TestRequest> request(NewRequest("http://host/req", net::LOWEST));
404 scoped_ptr<TestRequest> idle(NewRequest("http://host/idle", net::IDLE));
405 EXPECT_FALSE(request->started());
406 EXPECT_FALSE(idle->started());
408 ChangeRequestPriority(request.get(), net::IDLE);
409 EXPECT_FALSE(request->started());
410 EXPECT_FALSE(idle->started());
412 const int kMaxNumDelayableRequestsPerClient = 10; // Should match the .cc.
413 // 2 fewer filler requests: 1 for the "low" dummy at the start, and 1 for the
414 // one at the end, which will be tested.
415 const int kNumFillerRequests = kMaxNumDelayableRequestsPerClient - 2;
416 ScopedVector<TestRequest> lows;
417 for (int i = 0; i < kNumFillerRequests; ++i) {
418 string url = "http://host" + base::IntToString(i) + "/low";
419 lows.push_back(NewRequest(url.c_str(), net::LOWEST));
422 scheduler_.OnWillInsertBody(kChildId, kRouteId);
423 EXPECT_FALSE(request->started());
424 EXPECT_TRUE(idle->started());
427 TEST_F(ResourceSchedulerTest, ReprioritizedRequestGoesToBackOfQueue) {
428 // Dummies to enforce scheduling.
429 scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
430 scoped_ptr<TestRequest> low(NewRequest("http://host/high", net::LOWEST));
432 scoped_ptr<TestRequest> request(NewRequest("http://host/req", net::LOWEST));
433 scoped_ptr<TestRequest> idle(NewRequest("http://host/idle", net::IDLE));
434 EXPECT_FALSE(request->started());
435 EXPECT_FALSE(idle->started());
437 const int kMaxNumDelayableRequestsPerClient = 10; // Should match the .cc.
438 ScopedVector<TestRequest> lows;
439 for (int i = 0; i < kMaxNumDelayableRequestsPerClient; ++i) {
440 string url = "http://host/low" + base::IntToString(i);
441 lows.push_back(NewRequest(url.c_str(), net::LOWEST));
444 ChangeRequestPriority(request.get(), net::IDLE);
445 EXPECT_FALSE(request->started());
446 EXPECT_FALSE(idle->started());
448 ChangeRequestPriority(request.get(), net::LOWEST);
449 EXPECT_FALSE(request->started());
450 EXPECT_FALSE(idle->started());
452 scheduler_.OnWillInsertBody(kChildId, kRouteId);
453 EXPECT_FALSE(request->started());
454 EXPECT_FALSE(idle->started());
457 TEST_F(ResourceSchedulerTest, HigherIntraPriorityGoesToFrontOfQueue) {
458 // Dummies to enforce scheduling.
459 scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
460 scoped_ptr<TestRequest> low(NewRequest("http://host/high", net::LOWEST));
462 const int kMaxNumDelayableRequestsPerClient = 10; // Should match the .cc.
463 ScopedVector<TestRequest> lows;
464 for (int i = 0; i < kMaxNumDelayableRequestsPerClient; ++i) {
465 string url = "http://host/low" + base::IntToString(i);
466 lows.push_back(NewRequest(url.c_str(), net::IDLE));
469 scoped_ptr<TestRequest> request(NewRequest("http://host/req", net::IDLE));
470 EXPECT_FALSE(request->started());
472 ChangeRequestPriority(request.get(), net::IDLE, 1);
473 EXPECT_FALSE(request->started());
475 scheduler_.OnWillInsertBody(kChildId, kRouteId);
476 EXPECT_TRUE(request->started());
479 TEST_F(ResourceSchedulerTest, NonHTTPSchedulesImmediately) {
480 // Dummies to enforce scheduling.
481 scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
482 scoped_ptr<TestRequest> low(NewRequest("http://host/high", net::LOWEST));
484 scoped_ptr<TestRequest> request(
485 NewRequest("chrome-extension://req", net::LOWEST));
486 EXPECT_TRUE(request->started());
489 TEST_F(ResourceSchedulerTest, SpdyProxySchedulesImmediately) {
490 scoped_ptr<TestRequest> high(NewRequest("http://host/high", net::HIGHEST));
491 scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
493 scoped_ptr<TestRequest> request(NewRequest("http://host/req", net::IDLE));
494 EXPECT_FALSE(request->started());
496 scheduler_.OnReceivedSpdyProxiedHttpResponse(kChildId, kRouteId);
497 EXPECT_TRUE(request->started());
499 scoped_ptr<TestRequest> after(NewRequest("http://host/after", net::IDLE));
500 EXPECT_TRUE(after->started());
503 TEST_F(ResourceSchedulerTest, NewSpdyHostInDelayableRequests) {
504 scheduler_.OnWillInsertBody(kChildId, kRouteId);
505 const int kMaxNumDelayableRequestsPerClient = 10; // Should match the .cc.
507 scoped_ptr<TestRequest> low1_spdy(
508 NewRequest("http://spdyhost1:8080/low", net::LOWEST));
509 // Cancel a request after we learn the server supports SPDY.
510 ScopedVector<TestRequest> lows;
511 for (int i = 0; i < kMaxNumDelayableRequestsPerClient - 1; ++i) {
512 string url = "http://host" + base::IntToString(i) + "/low";
513 lows.push_back(NewRequest(url.c_str(), net::LOWEST));
515 scoped_ptr<TestRequest> low1(NewRequest("http://host/low", net::LOWEST));
516 EXPECT_FALSE(low1->started());
517 http_server_properties_.SetSupportsSpdy(
518 net::HostPortPair("spdyhost1", 8080), true);
519 low1_spdy.reset();
520 EXPECT_TRUE(low1->started());
522 low1.reset();
523 scoped_ptr<TestRequest> low2_spdy(
524 NewRequest("http://spdyhost2:8080/low", net::IDLE));
525 // Reprioritize a request after we learn the server supports SPDY.
526 EXPECT_TRUE(low2_spdy->started());
527 http_server_properties_.SetSupportsSpdy(
528 net::HostPortPair("spdyhost2", 8080), true);
529 ChangeRequestPriority(low2_spdy.get(), net::LOWEST);
530 scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
531 EXPECT_TRUE(low2->started());
534 } // unnamed namespace
536 } // namespace content