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

Side by Side Diff: content/browser/renderer_host/input/input_queue_unittest.cc

Issue 20356003: Provided batched input delivery with a BufferedInputRouter (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Refactoring Created 7 years, 3 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 (c) 2013 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 <vector>
6
7 #include "base/memory/scoped_ptr.h"
8 #include "content/browser/renderer_host/input/browser_input_event.h"
9 #include "content/browser/renderer_host/input/input_queue.h"
10 #include "content/browser/renderer_host/input/input_queue_client.h"
11 #include "content/common/input/event_packet.h"
12 #include "content/common/input/input_event.h"
13 #include "content/common/input/ipc_input_event_payload.h"
14 #include "content/common/input/web_input_event_payload.h"
15 #include "content/common/input_messages.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "ui/base/latency_info.h"
18
19 namespace content {
20 namespace {
21
22 using WebKit::WebGestureEvent;
23 using WebKit::WebInputEvent;
24 using WebKit::WebKeyboardEvent;
25 using WebKit::WebMouseEvent;
26 using WebKit::WebMouseWheelEvent;
27 using WebKit::WebTouchEvent;
28
29 class InputQueueTest : public testing::Test,
30 public InputQueueClient,
31 public BrowserInputEventClient {
32 public:
33 InputQueueTest()
34 : queue_(new InputQueue(this)),
35 routing_id_(0),
36 num_flush_completions_(0),
37 num_flush_requests_(0),
38 num_packet_deliveries_(0),
39 next_input_id_(1) {
40 }
41
42 // InputQueueClient
43 virtual void Deliver(const EventPacket& packet) OVERRIDE {
44 EXPECT_LT(0u, packet.size());
45 ++num_packet_deliveries_;
46 current_packet_id_ = packet.id();
47 current_packet_dispositions_.resize(packet.size(), INPUT_EVENT_UNHANDLED);
48 }
49
50 virtual void DidFinishFlush() OVERRIDE {
51 ++num_flush_completions_;
52 }
53
54 virtual void SetNeedsFlush() OVERRIDE {
55 ++num_flush_requests_;
56 }
57
58 // BrowserInputEventClient
59 virtual void OnDispatched(const BrowserInputEvent& event,
60 InputEventDisposition disposition) OVERRIDE {
61 acked_dispositions_.push_back(disposition);
62 }
63
64 virtual void OnDispatched(
65 const BrowserInputEvent& event,
66 InputEventDisposition disposition,
67 ScopedVector<BrowserInputEvent>* followup) OVERRIDE {
68 acked_followup_dispositions_.push_back(disposition);
69 if (event_to_inject_)
70 followup->push_back(event_to_inject_.release());
71 }
72
73 int num_flush_requests() const { return num_flush_requests_; }
74 int num_flush_completions() const { return num_flush_completions_; }
75 int num_packet_deliveries() const { return num_packet_deliveries_; }
76
77 protected:
78 scoped_ptr<BrowserInputEvent> CreateIPCInputEvent(IPC::Message* message) {
79 return BrowserInputEvent::Create(
80 NextInputID(),
81 IPCInputEventPayload::Create(make_scoped_ptr(message)),
82 this);
83 }
84
85 scoped_ptr<BrowserInputEvent> CreateWebInputEvent(
86 WebInputEvent::Type web_type) {
87 WebKit::WebMouseEvent mouse;
88 WebKit::WebMouseWheelEvent wheel;
89 WebKit::WebTouchEvent touch;
90 WebKit::WebGestureEvent gesture;
91 WebKit::WebKeyboardEvent keyboard;
92
93 WebKit::WebInputEvent* web_event = NULL;
94 if (WebInputEvent::isMouseEventType(web_type))
95 web_event = &mouse;
96 else if (WebInputEvent::isKeyboardEventType(web_type))
97 web_event = &keyboard;
98 else if (WebInputEvent::isTouchEventType(web_type))
99 web_event = &touch;
100 else if (WebInputEvent::isGestureEventType(web_type))
101 web_event = &gesture;
102 else
103 web_event = &wheel;
104 web_event->type = web_type;
105
106 return BrowserInputEvent::Create(
107 NextInputID(),
108 WebInputEventPayload::Create(*web_event, ui::LatencyInfo(), false),
109 this);
110 }
111
112 void QueueEvent(IPC::Message* message) {
113 queue_->QueueEvent(CreateIPCInputEvent(message));
114 }
115
116 void QueueEvent(WebInputEvent::Type web_type) {
117 queue_->QueueEvent(CreateWebInputEvent(web_type));
118 }
119
120 bool Flush(InputEventDisposition disposition) {
121 StartFlush();
122 return FinishFlush(disposition);
123 }
124
125 void StartFlush() {
126 acked_dispositions_.clear();
127 acked_followup_dispositions_.clear();
128 current_packet_id_ = 0;
129 current_packet_dispositions_.clear();
130 queue_->BeginFlush();
131 }
132
133 bool FinishFlush(InputEventDisposition disposition) {
134 if (!current_packet_id_)
135 return false;
136 current_packet_dispositions_ = InputEventDispositions(
137 current_packet_dispositions_.size(),
138 disposition);
139 return InputQueue::ACK_OK ==
140 queue_->OnEventPacketAck(current_packet_id_,
141 current_packet_dispositions_);
142 }
143
144 int64 NextInputID() {
145 return next_input_id_++;
146 }
147
148 scoped_ptr<InputQueue> queue_;
149
150 int routing_id_;
151 int64 current_packet_id_;
152 InputEventDispositions current_packet_dispositions_;
153
154 InputEventDispositions acked_dispositions_;
155 InputEventDispositions acked_followup_dispositions_;
156 scoped_ptr<BrowserInputEvent> event_to_inject_;
157
158 int num_flush_completions_;
159 int num_flush_requests_;
160 int num_packet_deliveries_;
161 int next_input_id_;
162 };
163
164 TEST_F(InputQueueTest, SetNeedsFlushOnQueueEvent) {
165 EXPECT_EQ(0, num_flush_requests());
166
167 QueueEvent(WebInputEvent::MouseDown);
168 EXPECT_EQ(1, num_flush_requests());
169
170 // Additional queued events should not trigger additional flush requests.
171 QueueEvent(WebInputEvent::MouseUp);
172 EXPECT_EQ(1, num_flush_requests());
173 QueueEvent(WebInputEvent::TouchStart);
174 EXPECT_EQ(1, num_flush_requests());
175 }
176
177 TEST_F(InputQueueTest, NoSetNeedsFlushOnQueueIfFlushing) {
178 QueueEvent(WebInputEvent::GestureScrollBegin);
179 EXPECT_EQ(1, num_flush_requests());
180
181 StartFlush();
182 EXPECT_EQ(1, num_flush_requests());
183 EXPECT_EQ(1, num_packet_deliveries());
184
185 // Events queued after a flush will not trigger an additional flush request.
186 QueueEvent(WebInputEvent::GestureScrollBegin);
187 EXPECT_EQ(1, num_flush_requests());
188 QueueEvent(WebInputEvent::GestureScrollEnd);
189 EXPECT_EQ(1, num_flush_requests());
190 }
191
192 #ifdef NDEBUG // This triggers a DCHECK.
193 TEST_F(InputQueueTest, NoSetNeedsFlushOnInvalidEvent) {
194 queue_->QueueEvent(BrowserInputEvent::Create(
195 0, IPCInputEventPayload::Create(
196 scoped_ptr<IPC::Message>(new InputMsg_Copy(1))), this));
197 EXPECT_EQ(0, num_flush_requests());
198
199 queue_->QueueEvent(BrowserInputEvent::Create(
200 1, scoped_ptr<IPCInputEventPayload>(), this));
201 EXPECT_EQ(0, num_flush_requests());
202 }
203 #endif
204
205 TEST_F(InputQueueTest, SetNeedsFlushAfterDidFinishFlushIfEventsQueued) {
206 QueueEvent(WebInputEvent::GestureScrollBegin);
207 EXPECT_EQ(1, num_flush_requests());
208
209 StartFlush();
210 EXPECT_EQ(1, num_packet_deliveries());
211
212 QueueEvent(WebInputEvent::GestureScrollBegin);
213 EXPECT_EQ(1, num_flush_requests());
214
215 // An additional flush request is sent for the event queued after the flush.
216 ASSERT_TRUE(current_packet_id_);
217 ASSERT_TRUE(FinishFlush(INPUT_EVENT_IMPL_THREAD_CONSUMED));
218 EXPECT_EQ(1, num_flush_completions());
219 EXPECT_EQ(2, num_flush_requests());
220 }
221
222 TEST_F(InputQueueTest, EventPacketSentAfterFlush) {
223 EXPECT_EQ(0, num_packet_deliveries());
224 QueueEvent(WebInputEvent::GestureScrollBegin);
225 EXPECT_EQ(0, num_packet_deliveries());
226 StartFlush();
227 EXPECT_EQ(1, num_packet_deliveries());
228 }
229
230 TEST_F(InputQueueTest, AcksHandledInProperOrder) {
231 QueueEvent(WebInputEvent::GestureScrollBegin);
232 QueueEvent(WebInputEvent::GestureScrollEnd);
233 QueueEvent(WebInputEvent::GestureFlingStart);
234
235 queue_->BeginFlush();
236 ASSERT_EQ(3u, current_packet_dispositions_.size());
237 current_packet_dispositions_[0] = INPUT_EVENT_IMPL_THREAD_CONSUMED;
238 current_packet_dispositions_[1] = INPUT_EVENT_MAIN_THREAD_CONSUMED;
239 current_packet_dispositions_[2] =
240 INPUT_EVENT_MAIN_THREAD_NO_CONSUMER_EXISTS;
241 queue_->OnEventPacketAck(current_packet_id_, current_packet_dispositions_);
242 EXPECT_EQ(1, num_flush_completions());
243
244 ASSERT_EQ(3u, acked_dispositions_.size());
245 EXPECT_EQ(acked_dispositions_[0], INPUT_EVENT_IMPL_THREAD_CONSUMED);
246 EXPECT_EQ(acked_dispositions_[1], INPUT_EVENT_MAIN_THREAD_CONSUMED);
247 EXPECT_EQ(acked_dispositions_[2], INPUT_EVENT_MAIN_THREAD_NO_CONSUMER_EXISTS);
248 }
249
250 TEST_F(InputQueueTest, FollowupWhenFollowupEventNotConsumed) {
251 InputEventDisposition unconsumed_dispositions[] = {
252 INPUT_EVENT_IMPL_THREAD_NO_CONSUMER_EXISTS,
253 INPUT_EVENT_MAIN_THREAD_NOT_PREVENT_DEFAULTED,
254 INPUT_EVENT_MAIN_THREAD_NO_CONSUMER_EXISTS
255 };
256 for (size_t i = 0; i < arraysize(unconsumed_dispositions); ++i) {
257 QueueEvent(WebInputEvent::GestureScrollBegin);
258 QueueEvent(WebInputEvent::TouchStart);
259 QueueEvent(WebInputEvent::TouchMove);
260
261 Flush(unconsumed_dispositions[i]);
262 EXPECT_EQ(1u, acked_dispositions_.size()) << i;
263 EXPECT_EQ(2u, acked_followup_dispositions_.size()) << i;
264 }
265 }
266
267 TEST_F(InputQueueTest, NoFollowupWhenFollowupEventConsumed) {
268 InputEventDisposition consumed_dispositions[] = {
269 INPUT_EVENT_IMPL_THREAD_CONSUMED,
270 INPUT_EVENT_MAIN_THREAD_PREVENT_DEFAULTED,
271 INPUT_EVENT_MAIN_THREAD_CONSUMED
272 };
273 for (size_t i = 0; i < arraysize(consumed_dispositions); ++i) {
274 QueueEvent(WebInputEvent::GestureScrollBegin);
275 QueueEvent(WebInputEvent::TouchStart);
276 QueueEvent(WebInputEvent::TouchMove);
277
278 Flush(consumed_dispositions[i]);
279 EXPECT_EQ(3u, acked_dispositions_.size()) << i;
280 EXPECT_EQ(0u, acked_followup_dispositions_.size()) << i;
281 }
282 }
283
284 TEST_F(InputQueueTest, FlushOnEmptyQueueIgnored) {
285 Flush(INPUT_EVENT_MAIN_THREAD_CONSUMED);
286 EXPECT_EQ(0, num_flush_requests());
287 EXPECT_EQ(0, num_flush_completions());
288
289 QueueEvent(WebInputEvent::GestureScrollBegin);
290 Flush(INPUT_EVENT_MAIN_THREAD_CONSUMED);
291 EXPECT_EQ(1, num_flush_requests());
292 EXPECT_EQ(1, num_flush_completions());
293
294 Flush(INPUT_EVENT_MAIN_THREAD_CONSUMED);
295 EXPECT_EQ(1, num_flush_requests());
296 EXPECT_EQ(1, num_flush_completions());
297 }
298
299 TEST_F(InputQueueTest, FlushContinuesUntilAllEventsProcessed) {
300 QueueEvent(WebInputEvent::GestureScrollBegin);
301 QueueEvent(WebInputEvent::GestureScrollEnd);
302 QueueEvent(WebInputEvent::GestureFlingStart);
303
304 EXPECT_EQ(1, num_flush_requests());
305 Flush(INPUT_EVENT_COULD_NOT_DELIVER);
306 EXPECT_EQ(0, num_flush_completions());
307
308 FinishFlush(INPUT_EVENT_COULD_NOT_DELIVER);
309 EXPECT_EQ(0, num_flush_completions());
310
311 ASSERT_TRUE(FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED));
312 EXPECT_EQ(1, num_flush_completions());
313 }
314
315 TEST_F(InputQueueTest, InvalidPacketAckIgnored) {
316 // Packet never flushed, any ack should be ignored.
317 InputQueue::AckResult result =
318 queue_->OnEventPacketAck(0, InputEventDispositions());
319 EXPECT_EQ(InputQueue::ACK_UNEXPECTED, result);
320
321 QueueEvent(WebInputEvent::GestureScrollBegin);
322 StartFlush();
323 // Tamper with the sent packet by adding an extra event.
324 current_packet_dispositions_.push_back(INPUT_EVENT_MAIN_THREAD_CONSUMED);
325 bool valid_packet_ack = FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED);
326 EXPECT_EQ(0, num_flush_completions());
327 EXPECT_FALSE(valid_packet_ack);
328
329 // Fix the packet.
330 current_packet_dispositions_.pop_back();
331 valid_packet_ack = FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED);
332 EXPECT_EQ(1, num_flush_completions());
333 EXPECT_TRUE(valid_packet_ack);
334
335 // Tamper with the packet by changing the id.
336 QueueEvent(WebInputEvent::GestureScrollBegin);
337 StartFlush();
338 int64 packet_ack_id = -1;
339 std::swap(current_packet_id_, packet_ack_id);
340 valid_packet_ack = FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED);
341 EXPECT_EQ(1, num_flush_completions());
342 EXPECT_FALSE(valid_packet_ack);
343
344 // Fix the packet.
345 std::swap(current_packet_id_, packet_ack_id);
346 valid_packet_ack = FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED);
347 EXPECT_EQ(2, num_flush_completions());
348 EXPECT_TRUE(valid_packet_ack);
349 }
350
351 TEST_F(InputQueueTest, InjectedEventsAckedBeforeDidFinishFlush) {
352 QueueEvent(WebInputEvent::GestureScrollBegin);
353 QueueEvent(WebInputEvent::TouchMove);
354
355 event_to_inject_ = CreateIPCInputEvent(new InputMsg_Copy(routing_id_));
356 Flush(INPUT_EVENT_IMPL_THREAD_NO_CONSUMER_EXISTS);
357 EXPECT_EQ(0, num_flush_completions());
358
359 // The injected event should now be in the event packet.
360 EXPECT_EQ(1u, current_packet_dispositions_.size());
361 EXPECT_EQ(1u, acked_followup_dispositions_.size());
362 ASSERT_TRUE(FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED));
363 EXPECT_EQ(1, num_flush_completions());
364
365 QueueEvent(WebInputEvent::GestureScrollBegin);
366 QueueEvent(WebInputEvent::TouchStart);
367 event_to_inject_ = CreateWebInputEvent(WebInputEvent::TouchMove);
368 Flush(INPUT_EVENT_MAIN_THREAD_NO_CONSUMER_EXISTS);
369 // |event_to_inject_| is now in the event packet.
370 EXPECT_EQ(1u, acked_followup_dispositions_.size());
371 EXPECT_EQ(1u, current_packet_dispositions_.size());
372
373 event_to_inject_ = CreateWebInputEvent(WebInputEvent::TouchMove);
374 // the next |event_to_inject_| is now in the event packet.
375 ASSERT_TRUE(FinishFlush(INPUT_EVENT_MAIN_THREAD_NO_CONSUMER_EXISTS));
376
377 EXPECT_EQ(2u, acked_followup_dispositions_.size());
378 EXPECT_EQ(1u, current_packet_dispositions_.size());
379 EXPECT_EQ(1, num_flush_completions());
380
381 ASSERT_TRUE(FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED));
382 EXPECT_EQ(2, num_flush_completions());
383 }
384
385 } // namespace
386 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698