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

Side by Side Diff: content/renderer/scheduler/resource_dispatch_throttler_unittest.cc

Issue 847883002: Reland "Throttle resource message requests during user interaction" (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 5 years, 10 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 2014 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/renderer/scheduler/resource_dispatch_throttler.h"
6
7 #include "base/memory/scoped_vector.h"
8 #include "content/common/resource_messages.h"
9 #include "content/test/fake_renderer_scheduler.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11
12 namespace content {
13 namespace {
14
15 const uint32 kRequestsPerFlush = 4;
16 const double kFlushPeriodSeconds = 1.f / 60;
17 const int kRoutingId = 1;
18
19 typedef ScopedVector<IPC::Message> ScopedMessages;
20
21 int GetRequestId(const IPC::Message& msg) {
22 int request_id = -1;
23 switch (msg.type()) {
24 case ResourceHostMsg_RequestResource::ID: {
25 PickleIterator iter(msg);
26 int routing_id = -1;
27 if (!iter.ReadInt(&routing_id) || !iter.ReadInt(&request_id))
28 NOTREACHED() << "Invalid id for resource request message.";
29 } break;
30
31 case ResourceHostMsg_DidChangePriority::ID:
32 case ResourceHostMsg_ReleaseDownloadedFile::ID:
33 case ResourceHostMsg_CancelRequest::ID:
34 if (!PickleIterator(msg).ReadInt(&request_id))
35 NOTREACHED() << "Invalid id for resource message.";
36 break;
37
38 default:
39 NOTREACHED() << "Invalid message for resource throttling.";
40 break;
41 }
42 return request_id;
43 }
44
45 class SenderSink : public IPC::Sender {
46 public:
47 SenderSink(ScopedMessages* sent_messages) : sent_messages_(sent_messages) {}
48
49 // IPC::Sender implementation:
50 bool Send(IPC::Message* msg) override {
51 sent_messages_->push_back(msg);
52 return true;
53 }
54
55 private:
56 ScopedMessages* sent_messages_;
57 };
58
59 } // namespace
60
61 class ResourceDispatchThrottlerTest : public testing::Test,
62 public FakeRendererScheduler,
63 public ResourceDispatchThrottler {
64 public:
65 ResourceDispatchThrottlerTest()
66 : ResourceDispatchThrottler(
67 &sender_sink_,
68 this,
davidben 2015/02/03 19:46:48 Having the FakeRendererScheduler and the ResourceD
jdduke (slow) 2015/02/04 01:39:50 Yeah, I get lazy in testing code sometimes, but th
69 base::TimeDelta::FromSecondsD(kFlushPeriodSeconds),
70 kRequestsPerFlush),
71 sender_sink_(&sent_messages_),
72 flush_scheduled_(false),
73 anticipate_(false),
74 last_request_id_(0) {}
75 ~ResourceDispatchThrottlerTest() override {}
76
77 // RendererScheduler implementation:
78 bool IsHighPriorityWorkAnticipated() override { return anticipate_; }
79
80 protected:
81 base::TimeTicks Now() const override { return now_; }
82
83 void ScheduleFlush() override { flush_scheduled_ = true; }
84
85 void SetHighPriorityWorkAnticipated(bool anticipate) {
86 anticipate_ = anticipate;
87 }
88
89 void Advance(base::TimeDelta delta) { now_ += delta; }
90
91 bool RunScheduledFlush() {
92 if (!flush_scheduled_)
93 return false;
94
95 flush_scheduled_ = false;
96 Flush();
97 return true;
98 }
99
100 bool RequestResource() {
101 ResourceHostMsg_Request request;
102 request.download_to_file = true;
103 return Send(new ResourceHostMsg_RequestResource(
104 kRoutingId, ++last_request_id_, request));
105 }
106
107 void RequestResourcesUntilThrottled() {
108 SetHighPriorityWorkAnticipated(true);
109 GetAndResetSentMessageCount();
110 for (RequestResource(); GetAndResetSentMessageCount(); RequestResource()) {
davidben 2015/02/03 19:46:48 This looks very different from a normal for loop.
jdduke (slow) 2015/02/04 01:39:50 Done.
111 }
112 }
113
114 bool UpdateRequestPriority(int request_id, net::RequestPriority priority) {
115 return Send(new ResourceHostMsg_DidChangePriority(request_id, priority, 0));
116 }
117
118 bool ReleaseDownloadedFile(int request_id) {
119 return Send(new ResourceHostMsg_ReleaseDownloadedFile(request_id));
120 }
121
122 bool CancelRequest(int request_id) {
123 return Send(new ResourceHostMsg_CancelRequest(request_id));
124 }
125
126 bool RequestResourceSync() {
127 SyncLoadResult result;
128 return Send(new ResourceHostMsg_SyncLoad(
129 kRoutingId, ++last_request_id_, ResourceHostMsg_Request(), &result));
130 }
131
132 size_t GetAndResetSentMessageCount() {
133 size_t sent_message_count = sent_messages_.size();
134 sent_messages_.clear();
135 return sent_message_count;
136 }
137
138 const IPC::Message* LastSentMessage() const {
139 return sent_messages_.empty() ? nullptr : sent_messages_.back();
140 }
141
142 int LastSentRequestId() const {
143 const IPC::Message* msg = LastSentMessage();
144 if (!msg)
145 return -1;
146
147 int routing_id = -1;
148 int request_id = -1;
149 PickleIterator iter(*msg);
150 CHECK(IPC::ReadParam(msg, &iter, &routing_id));
151 CHECK(IPC::ReadParam(msg, &iter, &request_id));
152 return request_id;
153 }
154
155 bool flush_scheduled() const { return flush_scheduled_; }
156
157 int last_request_id() const { return last_request_id_; }
158
159 ScopedMessages sent_messages_;
160
161 private:
162 SenderSink sender_sink_;
163 base::MessageLoopForUI message_loop_;
164 base::TimeTicks now_;
165 bool flush_scheduled_;
166 bool anticipate_;
167 int last_request_id_;
168
169 DISALLOW_COPY_AND_ASSIGN(ResourceDispatchThrottlerTest);
170 };
171
172 TEST_F(ResourceDispatchThrottlerTest, NotThrottledByDefault) {
173 SetHighPriorityWorkAnticipated(false);
174 for (size_t i = 0; i < kRequestsPerFlush * 2; ++i) {
175 RequestResource();
176 EXPECT_EQ(i + 1, sent_messages_.size());
177 }
178 }
179
180 TEST_F(ResourceDispatchThrottlerTest, NotThrottledIfSendLimitNotReached) {
181 SetHighPriorityWorkAnticipated(true);
182 for (size_t i = 0; i < kRequestsPerFlush; ++i) {
183 RequestResource();
184 EXPECT_EQ(i + 1, sent_messages_.size());
185 }
186 }
187
188 TEST_F(ResourceDispatchThrottlerTest, ThrottledWhenHighPriorityWork) {
189 SetHighPriorityWorkAnticipated(true);
190 for (size_t i = 0; i < kRequestsPerFlush; ++i)
191 RequestResource();
192 ASSERT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
193
194 RequestResource();
195 EXPECT_EQ(0U, sent_messages_.size());
196
197 EXPECT_TRUE(RunScheduledFlush());
198 EXPECT_EQ(1U, sent_messages_.size());
199 }
200
201 TEST_F(ResourceDispatchThrottlerTest,
202 ThrottledWhenDeferredMessageQueueNonEmpty) {
203 SetHighPriorityWorkAnticipated(true);
204 for (size_t i = 0; i < kRequestsPerFlush; ++i)
205 RequestResource();
206 ASSERT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
207
208 RequestResource();
209 EXPECT_EQ(0U, sent_messages_.size());
210 SetHighPriorityWorkAnticipated(false);
211 RequestResource();
212 EXPECT_EQ(0U, sent_messages_.size());
213
214 EXPECT_TRUE(RunScheduledFlush());
215 EXPECT_EQ(2U, sent_messages_.size());
216 }
217
218 TEST_F(ResourceDispatchThrottlerTest, NotThrottledIfSufficientTimePassed) {
219 SetHighPriorityWorkAnticipated(true);
220
221 for (size_t i = 0; i < kRequestsPerFlush * 2; ++i) {
222 Advance(base::TimeDelta::FromSecondsD(kFlushPeriodSeconds * 2));
223 RequestResource();
224 EXPECT_EQ(1U, GetAndResetSentMessageCount());
225 EXPECT_FALSE(flush_scheduled());
226 }
227 }
228
229 TEST_F(ResourceDispatchThrottlerTest, NotThrottledIfSyncMessage) {
230 SetHighPriorityWorkAnticipated(true);
231
232 RequestResourceSync();
233 EXPECT_EQ(1U, GetAndResetSentMessageCount());
234
235 // Saturate the queue.
236 for (size_t i = 0; i < kRequestsPerFlush * 2; ++i)
237 RequestResource();
238 ASSERT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
239
240 // Unthrottled message types should pass through untouched.
241 RequestResourceSync();
242 EXPECT_EQ(1U, GetAndResetSentMessageCount());
243 RequestResourceSync();
244 EXPECT_EQ(1U, GetAndResetSentMessageCount());
245
246 // Deferred messages should flush as usual.
247 EXPECT_TRUE(RunScheduledFlush());
248 EXPECT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
249 }
250
251 TEST_F(ResourceDispatchThrottlerTest, MultipleFlushes) {
252 SetHighPriorityWorkAnticipated(true);
253 for (size_t i = 0; i < kRequestsPerFlush * 4; ++i)
254 RequestResource();
255 ASSERT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
256
257 for (size_t i = 0; i < 3; ++i) {
258 EXPECT_TRUE(RunScheduledFlush());
259 EXPECT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount()) << i;
davidben 2015/02/03 19:46:47 You could probably stick a SCOPED_TRACE(i) and tha
jdduke (slow) 2015/02/04 01:39:50 Done.
260 }
261
262 EXPECT_FALSE(flush_scheduled());
263 EXPECT_EQ(0U, sent_messages_.size());
264 }
265
266 TEST_F(ResourceDispatchThrottlerTest, MultipleFlushesWhileReceiving) {
267 SetHighPriorityWorkAnticipated(true);
268 for (size_t i = 0; i < kRequestsPerFlush * 4; ++i)
269 RequestResource();
270 ASSERT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
271
272 for (size_t i = 0; i < 3; ++i) {
273 EXPECT_TRUE(RunScheduledFlush());
274 EXPECT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount()) << i;
275 for (size_t j = 0; j < kRequestsPerFlush; ++j)
276 RequestResource();
277 EXPECT_EQ(0U, sent_messages_.size()) << i;
278 }
279
280 for (size_t i = 0; i < 3; ++i) {
281 EXPECT_TRUE(RunScheduledFlush());
282 EXPECT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
283 }
284
285 EXPECT_FALSE(flush_scheduled());
286 EXPECT_EQ(0U, sent_messages_.size());
287 }
288
289 TEST_F(ResourceDispatchThrottlerTest, NonRequestsNeverTriggerThrottling) {
290 RequestResource();
291 ASSERT_EQ(1U, GetAndResetSentMessageCount());
292
293 for (size_t i = 0; i < kRequestsPerFlush * 3; ++i)
294 UpdateRequestPriority(last_request_id(), net::HIGHEST);
295 EXPECT_EQ(kRequestsPerFlush * 3, sent_messages_.size());
296
297 RequestResource();
298 EXPECT_EQ(1U + kRequestsPerFlush * 3, GetAndResetSentMessageCount());
299 }
300
301 TEST_F(ResourceDispatchThrottlerTest, NonRequestsDeferredWhenThrottling) {
302 RequestResource();
303 ASSERT_EQ(1U, GetAndResetSentMessageCount());
304
305 RequestResourcesUntilThrottled();
306 UpdateRequestPriority(last_request_id(), net::HIGHEST);
307 ReleaseDownloadedFile(last_request_id());
308 CancelRequest(last_request_id());
309
310 EXPECT_TRUE(RunScheduledFlush());
311 EXPECT_EQ(4U, GetAndResetSentMessageCount());
312 EXPECT_FALSE(flush_scheduled());
313 }
314
315 TEST_F(ResourceDispatchThrottlerTest, MessageOrderingPreservedWhenThrottling) {
316 SetHighPriorityWorkAnticipated(true);
317 for (size_t i = 0; i < kRequestsPerFlush; ++i)
318 RequestResource();
319 ASSERT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
320
321 for (size_t i = 0; i < kRequestsPerFlush; ++i) {
322 RequestResource();
323 UpdateRequestPriority(last_request_id(), net::HIGHEST);
324 CancelRequest(last_request_id() - 1);
325 }
326 ASSERT_EQ(0U, sent_messages_.size());
327
328 EXPECT_TRUE(RunScheduledFlush());
329 ASSERT_EQ(kRequestsPerFlush * 3, sent_messages_.size());
330 for (size_t i = 0; i < sent_messages_.size(); i+=3) {
331 const auto& request_msg = *sent_messages_[i];
332 const auto& priority_msg = *sent_messages_[i + 1];
333 const auto& cancel_msg = *sent_messages_[i + 2];
334
335 EXPECT_EQ(request_msg.type(), ResourceHostMsg_RequestResource::ID) << i;
336 EXPECT_EQ(priority_msg.type(), ResourceHostMsg_DidChangePriority::ID) << i;
337 EXPECT_EQ(cancel_msg.type(), ResourceHostMsg_CancelRequest::ID) << i;
338
339 EXPECT_EQ(GetRequestId(request_msg), GetRequestId(priority_msg));
340 EXPECT_EQ(GetRequestId(request_msg) - 1, GetRequestId(cancel_msg));
341 }
342 EXPECT_FALSE(flush_scheduled());
343 }
344
345 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698