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

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: Code review Created 7 years, 4 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/input_ack_handler.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_messages.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/base/latency_info.h"
16
17 namespace content {
18 namespace {
19
20 using WebKit::WebGestureEvent;
21 using WebKit::WebInputEvent;
22 using WebKit::WebKeyboardEvent;
23 using WebKit::WebMouseEvent;
24 using WebKit::WebMouseWheelEvent;
25 using WebKit::WebTouchEvent;
26
27 class InputQueueTest : public testing::Test,
28 public InputQueueClient {
29 public:
30 InputQueueTest()
31 : queue_(new InputQueue(this)),
32 routing_id_(0),
33 num_flush_completions_(0),
34 num_flush_requests_(0),
35 last_input_id_(0) {
36 }
37
38 // InputQueueClient
39 virtual void Deliver(const EventPacket& packet) OVERRIDE {
40 EXPECT_LT(0u, packet.events.size());
41 current_packet_.reset(new EventPacket(packet));
42 }
43
44 virtual void DidFlush() OVERRIDE {
45 ++num_flush_completions_;
46 }
47
48 virtual void SetNeedsFlush() OVERRIDE {
49 ++num_flush_requests_;
50 }
51
52 virtual std::vector<InputEvent> OnInputEventAck(
53 const InputEvent& acked_event) OVERRIDE {
54 std::vector<InputEvent> followup_events;
55 switch (acked_event.type) {
56 case INPUT_EVENT_NEEDS_ACK:
57 acked_events_.push_back(acked_event);
58 break;
59 case INPUT_EVENT_NEEDS_ACK_AND_HAS_FOLLOWUP:
60 acked_events_with_followup_.push_back(acked_event);
61 if (event_to_inject_)
62 followup_events.push_back(*event_to_inject_);
63 break;
64 default:
65 break;
66 }
67 return followup_events;
68 }
69
70 int num_flush_requests() const { return num_flush_requests_; }
71 int num_flush_completions() const { return num_flush_completions_; }
72
73 protected:
74
75 void QueueEvent(WebInputEvent::Type web_type, bool has_followup = false) {
76 scoped_ptr<WebInputEvent> web_event;
77 if (WebInputEvent::isMouseEventType(web_type)) {
78 web_event.reset(new WebMouseEvent());
79 } else if (WebInputEvent::isKeyboardEventType(web_type)) {
80 web_event.reset(new WebKeyboardEvent());
81 } else if (WebInputEvent::isTouchEventType(web_type)) {
82 web_event.reset(new WebTouchEvent());
83 } else if (WebInputEvent::isUserGestureEventType(web_type)) {
84 web_event.reset(new WebGestureEvent());
85 } else {
86 web_event.reset(new WebMouseWheelEvent());
87 }
88 web_event->type = web_type;
89
90 InputEventType type = has_followup ? INPUT_EVENT_NEEDS_ACK_AND_HAS_FOLLOWUP
91 : INPUT_EVENT_NEEDS_ACK;
92
93 QueueEvent(InputMsg_HandleInputEvent(routing_id_,
94 web_event.get(),
95 ui::LatencyInfo(),
96 false), type);
97 }
98
99 void QueueEvent(const IPC::Message& message, InputEventType type) {
100 queue_->QueueEvent(InputEvent(NewInputID(), type, message), NULL);
101 }
102
103 bool Flush(InputEventState ack_state) {
104 StartFlush();
105 return FinishFlush(ack_state);
106 }
107
108 void StartFlush() {
109 acked_events_.clear();
110 acked_events_with_followup_.clear();
111 current_packet_.reset();
112 queue_->FlushEventsInCurrentFrame();
113 }
114
115 bool FinishFlush(InputEventState ack_state) {
116 if (!current_packet_)
117 return false;
118 for (size_t i = 0; i < current_packet_->events.size(); ++i)
119 current_packet_->events[i].state = ack_state;
120 return InputQueue::ACK_OK == queue_->OnEventPacketAck(*current_packet_);
121 }
122
123 int64 NewInputID() {
124 return ++last_input_id_;
125 }
126
127 scoped_ptr<InputQueue> queue_;
128
129 int routing_id_;
130 scoped_ptr<EventPacket> current_packet_;
131 std::vector<InputEvent> acked_events_;
132 std::vector<InputEvent> acked_events_with_followup_;
133 scoped_ptr<InputEvent> event_to_inject_;
134
135 int num_flush_completions_;
136 int num_flush_requests_;
137 int last_input_id_;
138 };
139
140 TEST_F(InputQueueTest, SetNeedsFlushOnQueueEvent) {
141 EXPECT_EQ(0, num_flush_requests());
142
143 QueueEvent(WebInputEvent::MouseDown);
144 EXPECT_EQ(1, num_flush_requests());
145
146 // Additional queued events should not trigger additional flush requests.
147 QueueEvent(WebInputEvent::MouseUp);
148 EXPECT_EQ(1, num_flush_requests());
149 QueueEvent(WebInputEvent::TouchStart);
150 EXPECT_EQ(1, num_flush_requests());
151 }
152
153 TEST_F(InputQueueTest, NoSetNeedsFlushOnQueueIfFlushing) {
154 QueueEvent(WebInputEvent::GestureScrollBegin);
155 EXPECT_EQ(1, num_flush_requests());
156
157 queue_->FlushEventsInCurrentFrame();
158 EXPECT_EQ(1, num_flush_requests());
159
160 // Events queued after a flush will not trigger an additional flush request.
161 QueueEvent(WebInputEvent::GestureScrollBegin);
162 EXPECT_EQ(1, num_flush_requests());
163 QueueEvent(WebInputEvent::GestureScrollEnd);
164 EXPECT_EQ(1, num_flush_requests());
165 }
166
167 TEST_F(InputQueueTest, SetNeedsFlushAfterDidFlushIfEventsQueued) {
168 QueueEvent(WebInputEvent::GestureScrollBegin);
169 EXPECT_EQ(1, num_flush_requests());
170
171 StartFlush();
172
173 QueueEvent(WebInputEvent::GestureScrollBegin);
174 EXPECT_EQ(1, num_flush_requests());
175
176 // An additional flush request is sent for the event queued after the flush.
177 EXPECT_TRUE(FinishFlush(INPUT_EVENT_IMPL_THREAD_ABSORBED));
178 EXPECT_EQ(1, num_flush_completions());
179 EXPECT_EQ(2, num_flush_requests());
180 }
181
182 TEST_F(InputQueueTest, EventPacketSentAfterFlush) {
183 EXPECT_EQ(NULL, current_packet_.get());
184 QueueEvent(WebInputEvent::GestureScrollBegin);
185 EXPECT_EQ(NULL, current_packet_.get());
186 StartFlush();
187 EXPECT_TRUE(NULL != current_packet_.get());
188 }
189
190 TEST_F(InputQueueTest, AcksHandledInProperOrder) {
191 QueueEvent(WebInputEvent::GestureScrollBegin);
192 QueueEvent(WebInputEvent::GestureScrollEnd);
193 QueueEvent(WebInputEvent::GestureFlingStart);
194
195 queue_->FlushEventsInCurrentFrame();
196 current_packet_->events[0].state = INPUT_EVENT_IMPL_THREAD_ABSORBED;
197 current_packet_->events[1].state = INPUT_EVENT_MAIN_THREAD_ABSORBED;
198 current_packet_->events[2].state = INPUT_EVENT_MAIN_THREAD_NO_HANDLER_EXISTS;
199 queue_->OnEventPacketAck(*current_packet_);
200 EXPECT_EQ(1, num_flush_completions());
201
202 EXPECT_EQ(acked_events_[0].state, INPUT_EVENT_IMPL_THREAD_ABSORBED);
203 EXPECT_EQ(acked_events_[1].state, INPUT_EVENT_MAIN_THREAD_ABSORBED);
204 EXPECT_EQ(acked_events_[2].state, INPUT_EVENT_MAIN_THREAD_NO_HANDLER_EXISTS);
205 }
206
207 TEST_F(InputQueueTest, NullAckObserverOK) {
208 queue_->QueueEvent(
209 InputEvent(NewInputID(),
210 INPUT_EVENT_ONE_WAY,
211 InputMsg_Copy(routing_id_)), NULL);
212 queue_->QueueEvent(
213 InputEvent(NewInputID(),
214 INPUT_EVENT_NEEDS_ACK,
215 InputMsg_Copy(routing_id_)), NULL);
216
217 Flush(INPUT_EVENT_MAIN_THREAD_ABSORBED);
218 EXPECT_EQ(1u, acked_events_.size());
219 EXPECT_EQ(1, num_flush_completions());
220 }
221
222 TEST_F(InputQueueTest, AckInjectorOnlyIfHasFollowup) {
223 QueueEvent(WebInputEvent::GestureScrollBegin);
224 QueueEvent(WebInputEvent::GestureScrollEnd, true);
225 QueueEvent(WebInputEvent::GestureFlingStart, true);
226
227 Flush(INPUT_EVENT_MAIN_THREAD_ABSORBED);
228 EXPECT_EQ(1u, acked_events_.size());
229 EXPECT_EQ(2u, acked_events_with_followup_.size());
230 }
231
232 TEST_F(InputQueueTest, FlushOnEmptyQueueIgnored) {
233 Flush(INPUT_EVENT_MAIN_THREAD_ABSORBED);
234 EXPECT_EQ(0, num_flush_requests());
235 EXPECT_EQ(0, num_flush_completions());
236
237 QueueEvent(WebInputEvent::GestureScrollBegin);
238 Flush(INPUT_EVENT_MAIN_THREAD_ABSORBED);
239 EXPECT_EQ(1, num_flush_requests());
240 EXPECT_EQ(1, num_flush_completions());
241
242 Flush(INPUT_EVENT_MAIN_THREAD_ABSORBED);
243 EXPECT_EQ(1, num_flush_requests());
244 EXPECT_EQ(1, num_flush_completions());
245 }
246
247 TEST_F(InputQueueTest, FlushContinuesUntilAllEventsProcessed) {
248 QueueEvent(WebInputEvent::GestureScrollBegin);
249 QueueEvent(WebInputEvent::GestureScrollEnd);
250 QueueEvent(WebInputEvent::GestureFlingStart);
251
252 EXPECT_EQ(1, num_flush_requests());
253 Flush(INPUT_EVENT_IMPL_THREAD_COULD_NOT_DELIVER);
254 EXPECT_EQ(0, num_flush_completions());
255
256 FinishFlush(INPUT_EVENT_MAIN_THREAD_COULD_NOT_DELIVER);
257 EXPECT_EQ(0, num_flush_completions());
258
259 ASSERT_TRUE(FinishFlush(INPUT_EVENT_MAIN_THREAD_ABSORBED));
260 EXPECT_EQ(1, num_flush_completions());
261 }
262
263 TEST_F(InputQueueTest, InvalidPacketAckIgnored) {
264 // Packet never flushed, any ack should be ignored.
265 InputQueue::AckResult result = queue_->OnEventPacketAck(EventPacket());
266 EXPECT_EQ(InputQueue::ACK_UNEXPECTED, result);
267
268 QueueEvent(WebInputEvent::GestureScrollBegin);
269 StartFlush();
270 // Tamper with the sent packet by adding an extra event.
271 current_packet_->events.push_back(
272 InputEvent(NewInputID(),
273 INPUT_EVENT_NEEDS_ACK,
274 InputMsg_Copy(routing_id_)));
275 bool valid_packet_ack = FinishFlush(INPUT_EVENT_MAIN_THREAD_ABSORBED);
276 EXPECT_EQ(0, num_flush_completions());
277 EXPECT_FALSE(valid_packet_ack);
278
279 // Fix the packet.
280 current_packet_->events.pop_back();
281 valid_packet_ack = FinishFlush(INPUT_EVENT_MAIN_THREAD_ABSORBED);
282 EXPECT_EQ(1, num_flush_completions());
283 EXPECT_TRUE(valid_packet_ack);
284
285 // Tamper with the packet by changing an event type.
286 QueueEvent(WebInputEvent::GestureScrollBegin);
287 StartFlush();
288 current_packet_->events[0].type = INPUT_EVENT_ONE_WAY;
289 valid_packet_ack = FinishFlush(INPUT_EVENT_MAIN_THREAD_ABSORBED);
290 EXPECT_EQ(1, num_flush_completions());
291 EXPECT_FALSE(valid_packet_ack);
292
293 // Fix the packet.
294 current_packet_->events[0].type = INPUT_EVENT_NEEDS_ACK;
295 valid_packet_ack = FinishFlush(INPUT_EVENT_MAIN_THREAD_ABSORBED);
296 EXPECT_EQ(2, num_flush_completions());
297 EXPECT_TRUE(valid_packet_ack);
298 }
299
300 TEST_F(InputQueueTest, InjectedEventsAckedBeforeDidFlush) {
301 QueueEvent(WebInputEvent::GestureScrollBegin);
302 QueueEvent(WebInputEvent::GestureScrollEnd, true);
303
304 event_to_inject_.reset(
305 new InputEvent(NewInputID(),
306 INPUT_EVENT_ONE_WAY,
307 InputMsg_Copy(routing_id_)));
308 Flush(INPUT_EVENT_MAIN_THREAD_ABSORBED);
309 EXPECT_EQ(0, num_flush_completions());
310
311 // The injected event should now be in the event packet.
312 EXPECT_EQ(1u, current_packet_->events.size());
313 EXPECT_EQ(1u, acked_events_with_followup_.size());
314 ASSERT_TRUE(FinishFlush(INPUT_EVENT_MAIN_THREAD_ABSORBED));
315 EXPECT_EQ(1, num_flush_completions());
316
317 QueueEvent(WebInputEvent::GestureScrollBegin);
318 QueueEvent(WebInputEvent::GestureScrollEnd, true);
319 event_to_inject_.reset(
320 new InputEvent(NewInputID(),
321 INPUT_EVENT_NEEDS_ACK_AND_HAS_FOLLOWUP,
322 InputMsg_Copy(routing_id_)));
323 Flush(INPUT_EVENT_MAIN_THREAD_ABSORBED);
324 // |event_to_inject_| should now be in the event packet.
325 EXPECT_EQ(1u, acked_events_with_followup_.size());
326 EXPECT_EQ(1u, current_packet_->events.size());
327 ASSERT_TRUE(FinishFlush(INPUT_EVENT_MAIN_THREAD_ABSORBED));
328
329 // |event_to_inject_| should still be in the event packet.
330 EXPECT_EQ(2u, acked_events_with_followup_.size());
331 EXPECT_EQ(1u, current_packet_->events.size());
332 EXPECT_EQ(1, num_flush_completions());
333 event_to_inject_.reset();
334
335 ASSERT_TRUE(FinishFlush(INPUT_EVENT_MAIN_THREAD_ABSORBED));
336 EXPECT_EQ(2, num_flush_completions());
337 }
338
339 } // namespace
340 } // namespace content
341
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698