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

Side by Side Diff: remoting/host/linux/x11_character_injector_unittest.cc

Issue 2346643003: [Remoting Host] Handle text event characters that are not presented on the keyboard (Closed)
Patch Set: Fix Flakiness Created 4 years, 2 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 "remoting/host/linux/x11_character_injector.h"
6
7 #include <stdarg.h>
8
9 #include <map>
10
11 #include "base/memory/ptr_util.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/run_loop.h"
14 #include "base/threading/thread_task_runner_handle.h"
15 #include "remoting/host/linux/x11_keyboard.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace {
19
20 const int kMappingExpireMs = 200;
21
22 const int kSyncDelayMs = 10;
23
24 constexpr base::TimeDelta kSyncDelay =
25 base::TimeDelta::FromMilliseconds(kSyncDelayMs);
26
27 base::TimeDelta TimeDeltaMs(int ms) {
28 return base::TimeDelta::FromMilliseconds(ms);
29 }
30
31 } // namespace
32
33 namespace remoting {
34
35 class FakeX11Keyboard : public X11Keyboard {
Sergey Ulanov 2016/09/27 18:40:49 Add a short comment here to explain how this class
Yuwei 2016/09/28 18:45:55 Done.
36 public:
37 struct KeyPressExpectation {
38 base::TimeDelta min_delay; // To the last key press.
39 uint32_t keycode;
40 };
41
42 struct ChangeKeyMappingExpectation {
43 uint32_t keycode;
44 uint32_t code_point;
45 };
46
47 explicit FakeX11Keyboard(const std::vector<uint32_t>& available_keycodes);
48 ~FakeX11Keyboard() override;
49
50 std::vector<uint32_t> GetUnusedKeycodes() override;
Sergey Ulanov 2016/09/27 18:40:49 // X11Keyboard interface.
Yuwei 2016/09/28 18:45:55 Done.
51
52 void PressKey(uint32_t keycode, uint32_t modifiers) override;
53 bool FindKeycode(uint32_t code_point,
54 uint32_t* keycode,
55 uint32_t* modifiers) override;
56 bool ChangeKeyMapping(uint32_t keycode, uint32_t code_point) override;
57 void Flush() override;
58 void Sync() override;
59
60 void ExpectKeyPress(const std::vector<KeyPressExpectation>& sequence);
61 void ExpectChangeKeyMapping(
62 const std::vector<ChangeKeyMappingExpectation>& sequence);
63 void InjectorAboutToDestruct();
64
65 // Sets a callback to be called when the keypress expectation queue becomes
66 // empty.
67 void SetKeyPressFinishedCallback(const base::Closure& callback) {
68 keypress_finished_callback_ = callback;
69 }
70
71 private:
72 std::map<uint32_t, uint32_t> keycode_mapping_;
Sergey Ulanov 2016/09/27 18:40:49 unordered_map (not that performance matters here,
Yuwei 2016/09/28 18:45:55 Done.
73 std::queue<KeyPressExpectation> keypress_expectations_;
74 std::queue<ChangeKeyMappingExpectation> change_key_mapping_expectations_;
75 bool injector_about_to_destruct_ = false;
76 base::TimeTicks last_keypress_time_;
77 base::Closure keypress_finished_callback_;
78 };
79
80 FakeX11Keyboard::FakeX11Keyboard(
81 const std::vector<uint32_t>& available_keycodes) {
82 for (uint32_t keycode : available_keycodes) {
83 keycode_mapping_.insert({keycode, 0});
84 }
85 }
86
87 FakeX11Keyboard::~FakeX11Keyboard() {
88 DCHECK(keypress_expectations_.empty());
89 DCHECK(change_key_mapping_expectations_.empty());
90 for (const auto& pair : keycode_mapping_) {
91 EXPECT_EQ(0u, pair.second);
92 }
93 }
94
95 std::vector<uint32_t> FakeX11Keyboard::GetUnusedKeycodes() {
96 std::vector<uint32_t> keycodes;
97 for (const auto& pair : keycode_mapping_) {
98 if (!pair.second) {
99 keycodes.push_back(pair.first);
100 }
101 }
102 return keycodes;
103 }
104
105 void FakeX11Keyboard::PressKey(uint32_t keycode, uint32_t modifiers) {
106 ASSERT_FALSE(keypress_expectations_.empty());
107 KeyPressExpectation& expectation = keypress_expectations_.front();
108 ASSERT_EQ(expectation.keycode, keycode);
109 base::TimeTicks now = base::TimeTicks::Now();
110 base::TimeDelta delay = now - last_keypress_time_;
111 ASSERT_GE(delay, expectation.min_delay);
112 last_keypress_time_ = now;
113 keypress_expectations_.pop();
114 if (keypress_expectations_.empty() && keypress_finished_callback_) {
115 keypress_finished_callback_.Run();
116 }
117 }
118
119 bool FakeX11Keyboard::FindKeycode(uint32_t code_point,
120 uint32_t* keycode,
121 uint32_t* modifiers) {
122 auto position = std::find_if(keycode_mapping_.begin(), keycode_mapping_.end(),
123 [code_point](const std::pair<uint32_t, uint32_t>& pair) {
124 return pair.second == code_point;
125 });
126 if (position == keycode_mapping_.end()) {
127 return false;
128 }
129 *keycode = position->first;
130 *modifiers = 0;
131 return true;
132 }
133
134 bool FakeX11Keyboard::ChangeKeyMapping(uint32_t keycode, uint32_t code_point) {
135 if (injector_about_to_destruct_) {
136 EXPECT_EQ(0u, code_point);
137 } else {
138 EXPECT_FALSE(change_key_mapping_expectations_.empty())
139 << "Unexpected change key request. Key Code: " << keycode
140 << " Code Point: " << code_point;
141 ChangeKeyMappingExpectation& expectation =
142 change_key_mapping_expectations_.front();
143 EXPECT_EQ(expectation.keycode, keycode);
144 EXPECT_EQ(expectation.code_point, code_point);
145 change_key_mapping_expectations_.pop();
146 }
147
148 keycode_mapping_[keycode] = code_point;
149 return true;
150 }
151
152 void FakeX11Keyboard::Flush() {}
153
154 void FakeX11Keyboard::Sync() {
155 usleep(kSyncDelayMs * 1000);
Sergey Ulanov 2016/09/27 18:40:49 Why do we need to sleep here?
Yuwei 2016/09/28 18:45:55 This was a simulation of sync delay and can help f
156 }
157
158 void FakeX11Keyboard::ExpectKeyPress(
159 const std::vector<KeyPressExpectation>& sequence) {
160 for (const auto& expectation : sequence) {
Sergey Ulanov 2016/09/27 18:40:49 keypress_expectations_.insert( keypress_expectat
Yuwei 2016/09/28 18:45:55 Done in ExpectEnterCodePoints(). Changed queue to
161 keypress_expectations_.push(expectation);
162 }
163 }
164
165 void FakeX11Keyboard::ExpectChangeKeyMapping(
166 const std::vector<ChangeKeyMappingExpectation>& sequence) {
167 for (const auto& expectation : sequence) {
Sergey Ulanov 2016/09/27 18:40:49 use std::vector::insert()
Yuwei 2016/09/28 18:45:55 Obsolete.
168 change_key_mapping_expectations_.push(expectation);
169 }
170 }
171
172 void FakeX11Keyboard::InjectorAboutToDestruct() {
173 injector_about_to_destruct_ = true;
174 }
175
176 class X11CharacterInjectorTest : public testing::Test {
177 public:
178 void SetUp() override;
179 void TearDown() override;
180
181 protected:
182 void ResetRunLoop();
183 void FillUntilFull(bool immediately_run);
184
185 std::unique_ptr<X11CharacterInjector> injector_;
186 FakeX11Keyboard* keyboard_; // Owned by |injector_|.
187
188 base::MessageLoop message_loop_;
189 std::unique_ptr<base::RunLoop> run_loop_;
190 };
191
192 void X11CharacterInjectorTest::SetUp() {
193 keyboard_ = new FakeX11Keyboard({55, 54, 53, 52, 51});
194 injector_.reset(new X11CharacterInjector(base::WrapUnique(keyboard_)));
195 ResetRunLoop();
196 }
197
198 void X11CharacterInjectorTest::TearDown() {
199 run_loop_->Run();
200 keyboard_->InjectorAboutToDestruct();
201 injector_.reset();
202 }
203
204 void X11CharacterInjectorTest::ResetRunLoop() {
205 run_loop_.reset(new base::RunLoop());
206 keyboard_->SetKeyPressFinishedCallback(run_loop_->QuitClosure());
207 }
208
209 void X11CharacterInjectorTest::FillUntilFull(bool immediately_run) {
210 injector_->Inject(1);
211 injector_->Inject(2);
212 injector_->Inject(3);
213 injector_->Inject(4);
214 injector_->Inject(5);
215
216 keyboard_->ExpectChangeKeyMapping(
217 {{55, 1}, {54, 2}, {53, 3}, {52, 4}, {51, 5}});
218
219 keyboard_->ExpectKeyPress(
220 {{kSyncDelay, 55},
221 {kSyncDelay, 54},
222 {kSyncDelay, 53},
223 {kSyncDelay, 52},
224 {kSyncDelay, 51}});
225 if (immediately_run) {
226 run_loop_->Run();
227 ResetRunLoop();
228 }
229 }
230
231 TEST_F(X11CharacterInjectorTest, TestNoMappingNoExpectation) {
232 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
233 run_loop_->QuitClosure());
234 }
235
236 TEST_F(X11CharacterInjectorTest, TestTypeOneCharacter) {
237 injector_->Inject(123);
238
239 keyboard_->ExpectChangeKeyMapping({{55, 123}});
240 keyboard_->ExpectKeyPress({{kSyncDelay, 55}});
241 }
242
243 TEST_F(X11CharacterInjectorTest, TestMapCharactersUntilFull) {
244 FillUntilFull(false);
245 }
246
247 TEST_F(X11CharacterInjectorTest, TestMapOneCharacterWhenFull) {
248 FillUntilFull(false);
249 injector_->Inject(6);
250
251 keyboard_->ExpectChangeKeyMapping({{55, 6}});
252
253 const int kDelayForReuseCode =
254 kMappingExpireMs - 5 * kSyncDelayMs;
255
256 keyboard_->ExpectKeyPress({{TimeDeltaMs(kDelayForReuseCode), 55}});
257 }
258
259 TEST_F(X11CharacterInjectorTest, TestImmediatelyReuseOldKeycodeAfterExpired) {
260 FillUntilFull(true);
261
262 usleep((kMappingExpireMs + 50) * 1000);
263
264 injector_->Inject(6);
265
266 keyboard_->ExpectChangeKeyMapping({{55, 6}});
267
268 keyboard_->ExpectKeyPress({{kSyncDelay, 55}});
269 }
270
271 TEST_F(X11CharacterInjectorTest, TestReusingMappedCharacterLowersPriority) {
272 FillUntilFull(true);
273
274 usleep((kMappingExpireMs + 50) * 1000);
275
276 injector_->Inject(1);
277 injector_->Inject(6);
278
279 keyboard_->ExpectChangeKeyMapping({{54, 6}});
280
281 keyboard_->ExpectKeyPress({{kSyncDelay, 55}, {kSyncDelay, 54}});
282 }
283
284 TEST_F(X11CharacterInjectorTest, TestOrderAfterReusingCharacters) {
285 auto inject_and_wait = [this](uint32_t keycode,
Sergey Ulanov 2016/09/27 18:40:49 Make this a class method instead of a closure?
Yuwei 2016/09/28 18:45:55 Made InjectAndRun function
286 uint32_t code_point) {
287 keyboard_->ExpectKeyPress(
288 {{base::TimeDelta(), keycode}});
289 injector_->Inject(code_point);
290 run_loop_->Run();
291 ResetRunLoop();
292 usleep(kSyncDelayMs * 1000);
293 };
294
295 FillUntilFull(true);
296
297 inject_and_wait(54, 2);
Sergey Ulanov 2016/09/27 18:40:49 These tests are too rigorous in the way they set e
Yuwei 2016/09/28 18:45:55 I would say different ordering rules? Changing dat
298 inject_and_wait(52, 4);
299 inject_and_wait(51, 5);
300 inject_and_wait(55, 1);
301 inject_and_wait(53, 3);
302
303 usleep((kMappingExpireMs + 50) * 1000);
304
305 injector_->Inject(31);
306 injector_->Inject(32);
307 injector_->Inject(33);
308 injector_->Inject(34);
309 injector_->Inject(35);
310
311 keyboard_->ExpectChangeKeyMapping({
312 {54, 31}, {52, 32}, {51, 33}, {55, 34}, {53, 35}});
313
314 keyboard_->ExpectKeyPress(
315 {{kSyncDelay, 54},
316 {kSyncDelay, 52},
317 {kSyncDelay, 51},
318 {kSyncDelay, 55},
319 {kSyncDelay, 53}});
320 }
321
322 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698