Merge lp:~robertcarr/mir/refactor-input-acceptance-take-1 into lp:mir
- refactor-input-acceptance-take-1
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Robert Carr |
Approved revision: | no longer in the source branch. |
Merged at revision: | 1210 |
Proposed branch: | lp:~robertcarr/mir/refactor-input-acceptance-take-1 |
Merge into: | lp:mir |
Prerequisite: | lp:~robertcarr/mir/client-input-report |
Diff against target: |
1323 lines (+479/-665) 4 files modified
include/test/mir_test/client_event_matchers.h (+119/-0) include/test/mir_test_framework/input_testing_server_configuration.h (+2/-10) tests/acceptance-tests/test_client_input.cpp (+358/-543) tests/mir_test_framework/input_testing_server_options.cpp (+0/-112) |
To merge this branch: | bzr merge lp:~robertcarr/mir/refactor-input-acceptance-take-1 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexandros Frantzis (community) | Approve | ||
Alan Griffiths | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email: mp+194265@code.launchpad.net |
This proposal supersedes a proposal from 2013-11-07.
Commit message
Some cleanups to test_client_
Description of the change
First take at simplifying input acceptance tests with a better shared fixture.
Merged client-input-report to debug an issue, so hopefully we can merge this after.
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1206
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1207
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
Looks sane in general. I am not familiar enough with the functionality to be sure everything is covered adequately.
Alexandros Frantzis (afrantzis) wrote : | # |
Looks good.
Robert Carr (robertcarr) wrote : | # |
The tests are basically identical. Mostly about.
1. Removing some dead code (wait_until_
2. Factoring out highly repetitive code: i.e. this sort of stuff
918 - struct ServerConfiguration : mtf::InputTesti
919 - {
920 - mtf::CrossProce
921 -
922 - ServerConfigura
923 - : input_cb_
--------------
0 - void inject_input()
301 - {
302 - wait_until_
303 - input_cb_
304 -
309 - } server_
310 - launch_
-------------
311 -
312 - struct KeyReceivingClient : InputClient
313 - {
314 - KeyReceivingCli
3. Removing some noise from the file, i.e. client_
I can't quite see the end yet so am trying to make small improvements like this, but would eventually like to get to something super succint:
mtf::InputRecei
client.
Preview Diff
1 | === added file 'include/test/mir_test/client_event_matchers.h' |
2 | --- include/test/mir_test/client_event_matchers.h 1970-01-01 00:00:00 +0000 |
3 | +++ include/test/mir_test/client_event_matchers.h 2013-11-07 17:24:53 +0000 |
4 | @@ -0,0 +1,119 @@ |
5 | +/* |
6 | + * Copyright © 2013 Canonical Ltd. |
7 | + * |
8 | + * This program is free software: you can redistribute it and/or modify it |
9 | + * under the terms of the GNU General Public License version 3, |
10 | + * as published by the Free Software Foundation. |
11 | + * |
12 | + * This program is distributed in the hope that it will be useful, |
13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | + * GNU General Public License for more details. |
16 | + * |
17 | + * You should have received a copy of the GNU General Public License |
18 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | + * |
20 | + * Authored by: Robert Carr <robert.carr@canonical.com> |
21 | + */ |
22 | + |
23 | +#include "mir_toolkit/event.h" |
24 | + |
25 | +#include <xkbcommon/xkbcommon.h> |
26 | +#include <xkbcommon/xkbcommon-keysyms.h> |
27 | + |
28 | +#include <gmock/gmock.h> |
29 | + |
30 | +namespace mir |
31 | +{ |
32 | +namespace test |
33 | +{ |
34 | + |
35 | +MATCHER(KeyDownEvent, "") |
36 | +{ |
37 | + if (arg->type != mir_event_type_key) |
38 | + return false; |
39 | + if (arg->key.action != mir_key_action_down) // Key down |
40 | + return false; |
41 | + |
42 | + return true; |
43 | +} |
44 | +MATCHER_P(KeyOfSymbol, keysym, "") |
45 | +{ |
46 | + if (static_cast<xkb_keysym_t>(arg->key.key_code) == (uint)keysym) |
47 | + return true; |
48 | + return false; |
49 | +} |
50 | + |
51 | +MATCHER(HoverEnterEvent, "") |
52 | +{ |
53 | + if (arg->type != mir_event_type_motion) |
54 | + return false; |
55 | + if (arg->motion.action != mir_motion_action_hover_enter) |
56 | + return false; |
57 | + |
58 | + return true; |
59 | +} |
60 | +MATCHER(HoverExitEvent, "") |
61 | +{ |
62 | + if (arg->type != mir_event_type_motion) |
63 | + return false; |
64 | + if (arg->motion.action != mir_motion_action_hover_exit) |
65 | + return false; |
66 | + |
67 | + return true; |
68 | +} |
69 | + |
70 | +MATCHER_P2(ButtonDownEvent, x, y, "") |
71 | +{ |
72 | + if (arg->type != mir_event_type_motion) |
73 | + return false; |
74 | + if (arg->motion.action != mir_motion_action_down) |
75 | + return false; |
76 | + if (arg->motion.button_state == 0) |
77 | + return false; |
78 | + if (arg->motion.pointer_coordinates[0].x != x) |
79 | + return false; |
80 | + if (arg->motion.pointer_coordinates[0].y != y) |
81 | + return false; |
82 | + return true; |
83 | +} |
84 | + |
85 | +MATCHER_P2(ButtonUpEvent, x, y, "") |
86 | +{ |
87 | + if (arg->type != mir_event_type_motion) |
88 | + return false; |
89 | + if (arg->motion.action != mir_motion_action_up) |
90 | + return false; |
91 | + if (arg->motion.pointer_coordinates[0].x != x) |
92 | + return false; |
93 | + if (arg->motion.pointer_coordinates[0].y != y) |
94 | + return false; |
95 | + return true; |
96 | +} |
97 | + |
98 | +MATCHER_P2(MotionEventWithPosition, x, y, "") |
99 | +{ |
100 | + if (arg->type != mir_event_type_motion) |
101 | + return false; |
102 | + if (arg->motion.action != mir_motion_action_move && |
103 | + arg->motion.action != mir_motion_action_hover_move) |
104 | + return false; |
105 | + if (arg->motion.pointer_coordinates[0].x != x) |
106 | + return false; |
107 | + if (arg->motion.pointer_coordinates[0].y != y) |
108 | + return false; |
109 | + return true; |
110 | +} |
111 | + |
112 | +MATCHER(MovementEvent, "") |
113 | +{ |
114 | + if (arg->type != mir_event_type_motion) |
115 | + return false; |
116 | + if (arg->motion.action != mir_motion_action_move && |
117 | + arg->motion.action != mir_motion_action_hover_move) |
118 | + return false; |
119 | + return true; |
120 | +} |
121 | + |
122 | +} |
123 | +} |
124 | |
125 | === modified file 'include/test/mir_test_framework/input_testing_server_configuration.h' |
126 | --- include/test/mir_test_framework/input_testing_server_configuration.h 2013-08-28 03:41:48 +0000 |
127 | +++ include/test/mir_test_framework/input_testing_server_configuration.h 2013-11-07 17:24:53 +0000 |
128 | @@ -52,8 +52,6 @@ |
129 | namespace mir_test_framework |
130 | { |
131 | |
132 | -enum ClientLifecycleState { starting, appeared, vanished }; |
133 | - |
134 | class InputTestingServerConfiguration : public TestingServerConfiguration |
135 | { |
136 | public: |
137 | @@ -63,24 +61,18 @@ |
138 | void on_exit(); |
139 | |
140 | std::shared_ptr<mir::input::InputConfiguration> the_input_configuration() override; |
141 | - std::shared_ptr<mir::frontend::Shell> the_frontend_shell() override; |
142 | + |
143 | + mir::input::android::FakeEventHub* fake_event_hub; |
144 | |
145 | protected: |
146 | virtual void inject_input() = 0; |
147 | - mir::input::android::FakeEventHub* fake_event_hub; |
148 | |
149 | void wait_until_client_appears(std::string const& surface_name); |
150 | |
151 | private: |
152 | - std::mutex lifecycle_lock; |
153 | - |
154 | - std::condition_variable lifecycle_condition; |
155 | - std::map<std::string, ClientLifecycleState> client_lifecycles; |
156 | - |
157 | std::thread input_injection_thread; |
158 | |
159 | std::shared_ptr<mir::test::doubles::FakeEventHubInputConfiguration> input_configuration; |
160 | - std::shared_ptr<mir::frontend::Shell> frontend_shell; |
161 | }; |
162 | |
163 | } |
164 | |
165 | === modified file 'tests/acceptance-tests/test_client_input.cpp' |
166 | --- tests/acceptance-tests/test_client_input.cpp 2013-10-28 21:41:27 +0000 |
167 | +++ tests/acceptance-tests/test_client_input.cpp 2013-11-07 17:24:53 +0000 |
168 | @@ -35,6 +35,7 @@ |
169 | #include "mir_test/fake_event_hub.h" |
170 | #include "mir_test/event_factory.h" |
171 | #include "mir_test/wait_condition.h" |
172 | +#include "mir_test/client_event_matchers.h" |
173 | #include "mir_test_framework/cross_process_sync.h" |
174 | #include "mir_test_framework/display_server_test_fixture.h" |
175 | #include "mir_test_framework/input_testing_server_configuration.h" |
176 | @@ -42,9 +43,6 @@ |
177 | #include <gtest/gtest.h> |
178 | #include <gmock/gmock.h> |
179 | |
180 | -#include <xkbcommon/xkbcommon.h> |
181 | -#include <xkbcommon/xkbcommon-keysyms.h> |
182 | - |
183 | #include <thread> |
184 | #include <functional> |
185 | #include <map> |
186 | @@ -213,281 +211,6 @@ |
187 | static int const surface_height = 100; |
188 | }; |
189 | |
190 | -MATCHER(KeyDownEvent, "") |
191 | -{ |
192 | - if (arg->type != mir_event_type_key) |
193 | - return false; |
194 | - if (arg->key.action != mir_key_action_down) // Key down |
195 | - return false; |
196 | - |
197 | - return true; |
198 | -} |
199 | -MATCHER_P(KeyOfSymbol, keysym, "") |
200 | -{ |
201 | - if (static_cast<xkb_keysym_t>(arg->key.key_code) == (uint)keysym) |
202 | - return true; |
203 | - return false; |
204 | -} |
205 | - |
206 | -MATCHER(HoverEnterEvent, "") |
207 | -{ |
208 | - if (arg->type != mir_event_type_motion) |
209 | - return false; |
210 | - if (arg->motion.action != mir_motion_action_hover_enter) |
211 | - return false; |
212 | - |
213 | - return true; |
214 | -} |
215 | -MATCHER(HoverExitEvent, "") |
216 | -{ |
217 | - if (arg->type != mir_event_type_motion) |
218 | - return false; |
219 | - if (arg->motion.action != mir_motion_action_hover_exit) |
220 | - return false; |
221 | - |
222 | - return true; |
223 | -} |
224 | - |
225 | -MATCHER_P2(ButtonDownEvent, x, y, "") |
226 | -{ |
227 | - if (arg->type != mir_event_type_motion) |
228 | - return false; |
229 | - if (arg->motion.action != mir_motion_action_down) |
230 | - return false; |
231 | - if (arg->motion.button_state == 0) |
232 | - return false; |
233 | - if (arg->motion.pointer_coordinates[0].x != x) |
234 | - return false; |
235 | - if (arg->motion.pointer_coordinates[0].y != y) |
236 | - return false; |
237 | - return true; |
238 | -} |
239 | - |
240 | -MATCHER_P2(ButtonUpEvent, x, y, "") |
241 | -{ |
242 | - if (arg->type != mir_event_type_motion) |
243 | - return false; |
244 | - if (arg->motion.action != mir_motion_action_up) |
245 | - return false; |
246 | - if (arg->motion.pointer_coordinates[0].x != x) |
247 | - return false; |
248 | - if (arg->motion.pointer_coordinates[0].y != y) |
249 | - return false; |
250 | - return true; |
251 | -} |
252 | - |
253 | -MATCHER_P2(MotionEventWithPosition, x, y, "") |
254 | -{ |
255 | - if (arg->type != mir_event_type_motion) |
256 | - return false; |
257 | - if (arg->motion.action != mir_motion_action_move && |
258 | - arg->motion.action != mir_motion_action_hover_move) |
259 | - return false; |
260 | - if (arg->motion.pointer_coordinates[0].x != x) |
261 | - return false; |
262 | - if (arg->motion.pointer_coordinates[0].y != y) |
263 | - return false; |
264 | - return true; |
265 | -} |
266 | - |
267 | -MATCHER(MovementEvent, "") |
268 | -{ |
269 | - if (arg->type != mir_event_type_motion) |
270 | - return false; |
271 | - if (arg->motion.action != mir_motion_action_move && |
272 | - arg->motion.action != mir_motion_action_hover_move) |
273 | - return false; |
274 | - return true; |
275 | -} |
276 | - |
277 | -} |
278 | - |
279 | - |
280 | -using TestClientInput = BespokeDisplayServerTestFixture; |
281 | - |
282 | -TEST_F(TestClientInput, clients_receive_key_input) |
283 | -{ |
284 | - using namespace ::testing; |
285 | - |
286 | - int const num_events_produced = 3; |
287 | - static std::string const test_client_name = "1"; |
288 | - |
289 | - mtf::CrossProcessSync fence; |
290 | - |
291 | - struct ServerConfiguration : mtf::InputTestingServerConfiguration |
292 | - { |
293 | - mtf::CrossProcessSync input_cb_setup_fence; |
294 | - |
295 | - ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence) |
296 | - : input_cb_setup_fence(input_cb_setup_fence) |
297 | - { |
298 | - } |
299 | - |
300 | - void inject_input() |
301 | - { |
302 | - wait_until_client_appears(test_client_name); |
303 | - input_cb_setup_fence.wait_for_signal_ready_for(); |
304 | - |
305 | - for (int i = 0; i < num_events_produced; i++) |
306 | - fake_event_hub->synthesize_event(mis::a_key_down_event() |
307 | - .of_scancode(KEY_ENTER)); |
308 | - } |
309 | - } server_config(fence); |
310 | - launch_server_process(server_config); |
311 | - |
312 | - struct KeyReceivingClient : InputClient |
313 | - { |
314 | - KeyReceivingClient(const mtf::CrossProcessSync& fence) : InputClient(fence, test_client_name) {} |
315 | - void expect_input(mt::WaitCondition& events_received) override |
316 | - { |
317 | - using namespace ::testing; |
318 | - InSequence seq; |
319 | - |
320 | - EXPECT_CALL(*handler, handle_input(KeyDownEvent())).Times(2); |
321 | - EXPECT_CALL(*handler, handle_input(KeyDownEvent())).Times(1) |
322 | - .WillOnce(mt::WakeUp(&events_received)); |
323 | - } |
324 | - } client_config(fence); |
325 | - launch_client_process(client_config); |
326 | -} |
327 | - |
328 | -TEST_F(TestClientInput, clients_receive_us_english_mapped_keys) |
329 | -{ |
330 | - using namespace ::testing; |
331 | - static std::string const test_client_name = "1"; |
332 | - mtf::CrossProcessSync fence; |
333 | - |
334 | - struct ServerConfiguration : mtf::InputTestingServerConfiguration |
335 | - { |
336 | - mtf::CrossProcessSync input_cb_setup_fence; |
337 | - |
338 | - ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence) |
339 | - : input_cb_setup_fence(input_cb_setup_fence) |
340 | - { |
341 | - } |
342 | - |
343 | - void inject_input() |
344 | - { |
345 | - wait_until_client_appears(test_client_name); |
346 | - input_cb_setup_fence.wait_for_signal_ready_for(); |
347 | - |
348 | - fake_event_hub->synthesize_event(mis::a_key_down_event() |
349 | - .of_scancode(KEY_LEFTSHIFT)); |
350 | - fake_event_hub->synthesize_event(mis::a_key_down_event() |
351 | - .of_scancode(KEY_4)); |
352 | - |
353 | - } |
354 | - } server_config{fence}; |
355 | - launch_server_process(server_config); |
356 | - |
357 | - struct KeyReceivingClient : InputClient |
358 | - { |
359 | - KeyReceivingClient(const mtf::CrossProcessSync& fence) : InputClient(fence, test_client_name) {} |
360 | - |
361 | - void expect_input(mt::WaitCondition& events_received) override |
362 | - { |
363 | - using namespace ::testing; |
364 | - |
365 | - InSequence seq; |
366 | - EXPECT_CALL(*handler, handle_input(AllOf(KeyDownEvent(), KeyOfSymbol(XKB_KEY_Shift_L)))).Times(1); |
367 | - EXPECT_CALL(*handler, handle_input(AllOf(KeyDownEvent(), KeyOfSymbol(XKB_KEY_dollar)))).Times(1) |
368 | - .WillOnce(mt::WakeUp(&events_received)); |
369 | - } |
370 | - } client_config{fence}; |
371 | - launch_client_process(client_config); |
372 | -} |
373 | - |
374 | -TEST_F(TestClientInput, clients_receive_motion_inside_window) |
375 | -{ |
376 | - using namespace ::testing; |
377 | - static std::string const test_client_name = "1"; |
378 | - mtf::CrossProcessSync fence; |
379 | - |
380 | - struct ServerConfiguration : public mtf::InputTestingServerConfiguration |
381 | - { |
382 | - mtf::CrossProcessSync input_cb_setup_fence; |
383 | - |
384 | - ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence) |
385 | - : input_cb_setup_fence(input_cb_setup_fence) |
386 | - { |
387 | - } |
388 | - |
389 | - void inject_input() |
390 | - { |
391 | - wait_until_client_appears(test_client_name); |
392 | - input_cb_setup_fence.wait_for_signal_ready_for(); |
393 | - |
394 | - fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(InputClient::surface_width - 1, |
395 | - InputClient::surface_height - 1)); |
396 | - fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(2,2)); |
397 | - } |
398 | - } server_config{fence}; |
399 | - launch_server_process(server_config); |
400 | - |
401 | - struct MotionReceivingClient : InputClient |
402 | - { |
403 | - MotionReceivingClient(const mtf::CrossProcessSync& fence) : InputClient(fence, test_client_name) {} |
404 | - |
405 | - void expect_input(mt::WaitCondition& events_received) override |
406 | - { |
407 | - using namespace ::testing; |
408 | - |
409 | - InSequence seq; |
410 | - |
411 | - // We should see the cursor enter |
412 | - EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(1); |
413 | - EXPECT_CALL(*handler, handle_input( |
414 | - MotionEventWithPosition(InputClient::surface_width - 1, |
415 | - InputClient::surface_height - 1))).Times(1) |
416 | - .WillOnce(mt::WakeUp(&events_received)); |
417 | - // But we should not receive an event for the second movement outside of our surface! |
418 | - } |
419 | - } client_config{fence}; |
420 | - launch_client_process(client_config); |
421 | -} |
422 | - |
423 | -TEST_F(TestClientInput, clients_receive_button_events_inside_window) |
424 | -{ |
425 | - using namespace ::testing; |
426 | - |
427 | - static std::string const test_client_name = "1"; |
428 | - mtf::CrossProcessSync fence; |
429 | - |
430 | - struct ServerConfiguration : public mtf::InputTestingServerConfiguration |
431 | - { |
432 | - mtf::CrossProcessSync input_cb_setup_fence; |
433 | - |
434 | - ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence) |
435 | - : input_cb_setup_fence(input_cb_setup_fence) |
436 | - { |
437 | - } |
438 | - |
439 | - void inject_input() |
440 | - { |
441 | - wait_until_client_appears(test_client_name); |
442 | - input_cb_setup_fence.wait_for_signal_ready_for(); |
443 | - |
444 | - fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down)); |
445 | - } |
446 | - } server_config{fence}; |
447 | - launch_server_process(server_config); |
448 | - |
449 | - struct ButtonReceivingClient : InputClient |
450 | - { |
451 | - ButtonReceivingClient(const mtf::CrossProcessSync& fence) : InputClient(fence, test_client_name) {} |
452 | - |
453 | - void expect_input(mt::WaitCondition& events_received) override |
454 | - { |
455 | - using namespace ::testing; |
456 | - |
457 | - InSequence seq; |
458 | - |
459 | - // The cursor starts at (0, 0). |
460 | - EXPECT_CALL(*handler, handle_input(ButtonDownEvent(0, 0))).Times(1) |
461 | - .WillOnce(mt::WakeUp(&events_received)); |
462 | - } |
463 | - } client_config{fence}; |
464 | - launch_client_process(client_config); |
465 | } |
466 | |
467 | namespace |
468 | @@ -497,34 +220,251 @@ |
469 | |
470 | struct StaticPlacementStrategy : public msh::PlacementStrategy |
471 | { |
472 | - StaticPlacementStrategy(GeometryMap const& positions, |
473 | + StaticPlacementStrategy(std::shared_ptr<msh::PlacementStrategy> const& underlying_strategy, |
474 | + GeometryMap const& positions, |
475 | DepthMap const& depths) |
476 | - : surface_geometry_by_name(positions), |
477 | + : underlying_strategy(underlying_strategy), |
478 | + surface_geometry_by_name(positions), |
479 | surface_depths_by_name(depths) |
480 | { |
481 | } |
482 | |
483 | - StaticPlacementStrategy(GeometryMap const& positions) |
484 | - : StaticPlacementStrategy(positions, DepthMap()) |
485 | + StaticPlacementStrategy(std::shared_ptr<msh::PlacementStrategy> const& underlying_strategy, |
486 | + GeometryMap const& positions) |
487 | + : StaticPlacementStrategy(underlying_strategy, positions, DepthMap()) |
488 | { |
489 | } |
490 | |
491 | - msh::SurfaceCreationParameters place(msh::Session const&, msh::SurfaceCreationParameters const& request_parameters) |
492 | + msh::SurfaceCreationParameters place(msh::Session const& session, msh::SurfaceCreationParameters const& request_parameters) |
493 | { |
494 | auto placed = request_parameters; |
495 | auto const& name = request_parameters.name; |
496 | - auto geometry = surface_geometry_by_name[name]; |
497 | - |
498 | - placed.top_left = geometry.top_left; |
499 | - placed.size = geometry.size; |
500 | + |
501 | + auto it = surface_geometry_by_name.find(name); |
502 | + if (it != surface_geometry_by_name.end()) |
503 | + { |
504 | + auto const& geometry = it->second; |
505 | + placed.top_left = geometry.top_left; |
506 | + placed.size = geometry.size; |
507 | + } |
508 | + else |
509 | + { |
510 | + placed = underlying_strategy->place(session, placed); |
511 | + } |
512 | placed.depth = surface_depths_by_name[name]; |
513 | |
514 | return placed; |
515 | } |
516 | + |
517 | + std::shared_ptr<msh::PlacementStrategy> const underlying_strategy; |
518 | GeometryMap surface_geometry_by_name; |
519 | DepthMap surface_depths_by_name; |
520 | }; |
521 | |
522 | +std::shared_ptr<mtf::InputTestingServerConfiguration> |
523 | +make_event_producing_server(mtf::CrossProcessSync const& client_ready_fence, |
524 | + int number_of_clients, |
525 | + std::function<void(mtf::InputTestingServerConfiguration& server)> const& produce_events, |
526 | + GeometryMap const& client_geometry_map, DepthMap const& client_depth_map) |
527 | +{ |
528 | + struct ServerConfiguration : mtf::InputTestingServerConfiguration |
529 | + { |
530 | + mtf::CrossProcessSync input_cb_setup_fence; |
531 | + int const number_of_clients; |
532 | + std::function<void(mtf::InputTestingServerConfiguration& server)> const produce_events; |
533 | + GeometryMap const client_geometry; |
534 | + DepthMap const client_depth; |
535 | + |
536 | + ServerConfiguration(mtf::CrossProcessSync const& input_cb_setup_fence, int number_of_clients, |
537 | + std::function<void(mtf::InputTestingServerConfiguration& server)> const& produce_events, |
538 | + GeometryMap const& client_geometry, DepthMap const& client_depth) |
539 | + : input_cb_setup_fence(input_cb_setup_fence), |
540 | + number_of_clients(number_of_clients), |
541 | + produce_events(produce_events), |
542 | + client_geometry(client_geometry), |
543 | + client_depth(client_depth) |
544 | + { |
545 | + } |
546 | + |
547 | + std::shared_ptr<msh::PlacementStrategy> the_shell_placement_strategy() override |
548 | + { |
549 | + return std::make_shared<StaticPlacementStrategy>(InputTestingServerConfiguration::the_shell_placement_strategy(), |
550 | + client_geometry, client_depth); |
551 | + } |
552 | + |
553 | + void inject_input() |
554 | + { |
555 | + for (int i = 1; i < number_of_clients + 1; i++) |
556 | + EXPECT_EQ(i, input_cb_setup_fence.wait_for_signal_ready_for()); |
557 | + produce_events(*this); |
558 | + } |
559 | + }; |
560 | + return std::make_shared<ServerConfiguration>(client_ready_fence, number_of_clients, |
561 | + produce_events, client_geometry_map, client_depth_map); |
562 | +} |
563 | + |
564 | +std::shared_ptr<mtf::InputTestingServerConfiguration> |
565 | +make_event_producing_server(mtf::CrossProcessSync const& client_ready_fence, int number_of_clients, |
566 | + std::function<void(mtf::InputTestingServerConfiguration& server)> const& produce_events) |
567 | +{ |
568 | + return make_event_producing_server(client_ready_fence, number_of_clients, |
569 | + produce_events, GeometryMap(), DepthMap()); |
570 | +} |
571 | + |
572 | +std::shared_ptr<InputClient> |
573 | +make_event_expecting_client(std::string const& client_name, mtf::CrossProcessSync const& client_ready_fence, |
574 | + std::function<void(MockInputHandler &, mt::WaitCondition&)> const& expect_input) |
575 | +{ |
576 | + struct EventReceivingClient : InputClient |
577 | + { |
578 | + std::function<void(MockInputHandler&, mt::WaitCondition&)> const expect_cb; |
579 | + |
580 | + EventReceivingClient(mtf::CrossProcessSync const& client_ready_fence, std::string const& client_name, |
581 | + std::function<void(MockInputHandler&, mt::WaitCondition&)> const& expect_cb) |
582 | + : InputClient(client_ready_fence, client_name), |
583 | + expect_cb(expect_cb) |
584 | + { |
585 | + } |
586 | + void expect_input(mt::WaitCondition& events_received) override |
587 | + { |
588 | + expect_cb(*handler, events_received); |
589 | + } |
590 | + }; |
591 | + return std::make_shared<EventReceivingClient>(client_ready_fence, client_name, expect_input); |
592 | +} |
593 | + |
594 | +std::shared_ptr<InputClient> |
595 | +make_event_expecting_client(mtf::CrossProcessSync const& client_ready_fence, |
596 | + std::function<void(MockInputHandler &, mt::WaitCondition&)> const& expect_input) |
597 | +{ |
598 | + return make_event_expecting_client("input-test-client", client_ready_fence, expect_input); |
599 | +} |
600 | + |
601 | +} |
602 | + |
603 | + |
604 | +using TestClientInput = BespokeDisplayServerTestFixture; |
605 | + |
606 | +TEST_F(TestClientInput, clients_receive_key_input) |
607 | +{ |
608 | + using namespace ::testing; |
609 | + |
610 | + static std::string const test_client_name = "1"; |
611 | + |
612 | + mtf::CrossProcessSync fence; |
613 | + |
614 | + auto server_config = make_event_producing_server(fence, 1, |
615 | + [&](mtf::InputTestingServerConfiguration& server) |
616 | + { |
617 | + int const num_events_produced = 3; |
618 | + |
619 | + for (int i = 0; i < num_events_produced; i++) |
620 | + server.fake_event_hub->synthesize_event(mis::a_key_down_event() |
621 | + .of_scancode(KEY_ENTER)); |
622 | + }); |
623 | + launch_server_process(*server_config); |
624 | + |
625 | + auto client_config = make_event_expecting_client(fence, |
626 | + [&](MockInputHandler& handler, mt::WaitCondition& events_received) |
627 | + { |
628 | + using namespace ::testing; |
629 | + InSequence seq; |
630 | + |
631 | + EXPECT_CALL(handler, handle_input(mt::KeyDownEvent())).Times(2); |
632 | + EXPECT_CALL(handler, handle_input(mt::KeyDownEvent())).Times(1) |
633 | + .WillOnce(mt::WakeUp(&events_received)); |
634 | + |
635 | + }); |
636 | + launch_client_process(*client_config); |
637 | +} |
638 | + |
639 | +TEST_F(TestClientInput, clients_receive_us_english_mapped_keys) |
640 | +{ |
641 | + using namespace ::testing; |
642 | + static std::string const test_client_name = "1"; |
643 | + mtf::CrossProcessSync fence; |
644 | + |
645 | + auto server_config = make_event_producing_server(fence, 1, |
646 | + [&](mtf::InputTestingServerConfiguration& server) |
647 | + { |
648 | + server.fake_event_hub->synthesize_event(mis::a_key_down_event() |
649 | + .of_scancode(KEY_LEFTSHIFT)); |
650 | + server.fake_event_hub->synthesize_event(mis::a_key_down_event() |
651 | + .of_scancode(KEY_4)); |
652 | + }); |
653 | + launch_server_process(*server_config); |
654 | + |
655 | + auto client_config = make_event_expecting_client(fence, |
656 | + [&](MockInputHandler& handler, mt::WaitCondition& events_received) |
657 | + { |
658 | + using namespace ::testing; |
659 | + InSequence seq; |
660 | + |
661 | + EXPECT_CALL(handler, handle_input(AllOf(mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_Shift_L)))).Times(1); |
662 | + EXPECT_CALL(handler, handle_input(AllOf(mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_dollar)))).Times(1) |
663 | + .WillOnce(mt::WakeUp(&events_received)); |
664 | + }); |
665 | + launch_client_process(*client_config); |
666 | +} |
667 | + |
668 | +TEST_F(TestClientInput, clients_receive_motion_inside_window) |
669 | +{ |
670 | + using namespace ::testing; |
671 | + static std::string const test_client_name = "1"; |
672 | + mtf::CrossProcessSync fence; |
673 | + |
674 | + auto server_config = make_event_producing_server(fence, 1, |
675 | + [&](mtf::InputTestingServerConfiguration& server) |
676 | + { |
677 | + server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(InputClient::surface_width - 1, |
678 | + InputClient::surface_height - 1)); |
679 | + server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(2,2)); |
680 | + }); |
681 | + launch_server_process(*server_config); |
682 | + |
683 | + auto client_config = make_event_expecting_client(fence, |
684 | + [&](MockInputHandler& handler, mt::WaitCondition& events_received) |
685 | + { |
686 | + using namespace ::testing; |
687 | + InSequence seq; |
688 | + |
689 | + // We should see the cursor enter |
690 | + EXPECT_CALL(handler, handle_input(mt::HoverEnterEvent())).Times(1); |
691 | + EXPECT_CALL(handler, handle_input( |
692 | + mt::MotionEventWithPosition(InputClient::surface_width - 1, |
693 | + InputClient::surface_height - 1))).Times(1) |
694 | + .WillOnce(mt::WakeUp(&events_received)); |
695 | + // But we should not receive an event for the second movement outside of our surface! |
696 | + }); |
697 | + launch_client_process(*client_config); |
698 | +} |
699 | + |
700 | +TEST_F(TestClientInput, clients_receive_button_events_inside_window) |
701 | +{ |
702 | + using namespace ::testing; |
703 | + |
704 | + static std::string const test_client_name = "1"; |
705 | + mtf::CrossProcessSync fence; |
706 | + |
707 | + auto server_config = make_event_producing_server(fence, 1, |
708 | + [&](mtf::InputTestingServerConfiguration& server) |
709 | + { |
710 | + server.fake_event_hub->synthesize_event(mis::a_button_down_event() |
711 | + .of_button(BTN_LEFT).with_action(mis::EventAction::Down)); |
712 | + }); |
713 | + launch_server_process(*server_config); |
714 | + |
715 | + auto client_config = make_event_expecting_client(fence, |
716 | + [&](MockInputHandler& handler, mt::WaitCondition& events_received) |
717 | + { |
718 | + using namespace ::testing; |
719 | + InSequence seq; |
720 | + |
721 | + // The cursor starts at (0, 0). |
722 | + EXPECT_CALL(handler, handle_input(mt::ButtonDownEvent(0, 0))).Times(1) |
723 | + .WillOnce(mt::WakeUp(&events_received)); |
724 | + }); |
725 | + launch_client_process(*client_config); |
726 | } |
727 | |
728 | TEST_F(TestClientInput, multiple_clients_receive_motion_inside_windows) |
729 | @@ -539,77 +479,42 @@ |
730 | static std::string const test_client_2 = "2"; |
731 | mtf::CrossProcessSync fence; |
732 | |
733 | - struct ServerConfiguration : mtf::InputTestingServerConfiguration |
734 | - { |
735 | - mtf::CrossProcessSync input_cb_setup_fence; |
736 | - |
737 | - ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence) |
738 | - : input_cb_setup_fence(input_cb_setup_fence) |
739 | - { |
740 | - } |
741 | - |
742 | - std::shared_ptr<msh::PlacementStrategy> the_shell_placement_strategy() override |
743 | - { |
744 | - static GeometryMap positions; |
745 | - positions[test_client_1] = geom::Rectangle{geom::Point{0, 0}, |
746 | - geom::Size{client_width, client_height}}; |
747 | - positions[test_client_2] = geom::Rectangle{geom::Point{screen_width/2, screen_height/2}, |
748 | - geom::Size{client_width, client_height}}; |
749 | - |
750 | - return std::make_shared<StaticPlacementStrategy>(positions); |
751 | - } |
752 | - |
753 | - void inject_input() override |
754 | - { |
755 | - wait_until_client_appears(test_client_1); |
756 | - EXPECT_EQ(1, input_cb_setup_fence.wait_for_signal_ready_for()); |
757 | - wait_until_client_appears(test_client_2); |
758 | - EXPECT_EQ(2, input_cb_setup_fence.wait_for_signal_ready_for()); |
759 | - |
760 | + static GeometryMap positions; |
761 | + positions[test_client_1] = geom::Rectangle{geom::Point{0, 0}, |
762 | + geom::Size{client_width, client_height}}; |
763 | + positions[test_client_2] = geom::Rectangle{geom::Point{screen_width/2, screen_height/2}, |
764 | + geom::Size{client_width, client_height}}; |
765 | + |
766 | + auto server_config = make_event_producing_server(fence, 2, |
767 | + [&](mtf::InputTestingServerConfiguration& server) |
768 | + { |
769 | // In the bounds of the first surface |
770 | - fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(screen_width/2-1, screen_height/2-1)); |
771 | + server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(screen_width/2-1, screen_height/2-1)); |
772 | // In the bounds of the second surface |
773 | - fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(screen_width/2, screen_height/2)); |
774 | - } |
775 | - } server_config{fence}; |
776 | - |
777 | - launch_server_process(server_config); |
778 | - |
779 | - struct InputClientOne : InputClient |
780 | - { |
781 | - InputClientOne(const mtf::CrossProcessSync& fence) |
782 | - : InputClient(fence, test_client_1) |
783 | - { |
784 | - } |
785 | - |
786 | - void expect_input(mt::WaitCondition& events_received) override |
787 | - { |
788 | - InSequence seq; |
789 | - EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(1); |
790 | - EXPECT_CALL(*handler, handle_input(MotionEventWithPosition(client_width - 1, client_height - 1))).Times(1); |
791 | - EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(1) |
792 | - .WillOnce(mt::WakeUp(&events_received)); |
793 | - } |
794 | - } client_1{fence}; |
795 | - |
796 | - struct InputClientTwo : InputClient |
797 | - { |
798 | - InputClientTwo(const mtf::CrossProcessSync& fence) |
799 | - : InputClient(fence, test_client_2) |
800 | - { |
801 | - } |
802 | - |
803 | - void expect_input(mt::WaitCondition& events_received) override |
804 | - { |
805 | - InSequence seq; |
806 | - EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(1); |
807 | - EXPECT_CALL(*handler, handle_input(MotionEventWithPosition(client_width - 1, client_height - 1))).Times(1) |
808 | - .WillOnce(mt::WakeUp(&events_received)); |
809 | - } |
810 | - } client_2{fence}; |
811 | - |
812 | - launch_client_process(client_1); |
813 | - launch_client_process(client_2); |
814 | + server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(screen_width/2, screen_height/2)); |
815 | + }, positions, DepthMap()); |
816 | + launch_server_process(*server_config); |
817 | + |
818 | + auto client_1 = make_event_expecting_client(test_client_1, fence, |
819 | + [&](MockInputHandler& handler, mt::WaitCondition& events_received) |
820 | + { |
821 | + InSequence seq; |
822 | + EXPECT_CALL(handler, handle_input(mt::HoverEnterEvent())).Times(1); |
823 | + EXPECT_CALL(handler, handle_input(mt::MotionEventWithPosition(client_width - 1, client_height - 1))).Times(1); |
824 | + EXPECT_CALL(handler, handle_input(mt::HoverExitEvent())).Times(1) |
825 | + .WillOnce(mt::WakeUp(&events_received)); |
826 | + }); |
827 | + auto client_2 = make_event_expecting_client(test_client_2, fence, |
828 | + [&](MockInputHandler& handler, mt::WaitCondition& events_received) |
829 | + { |
830 | + InSequence seq; |
831 | + EXPECT_CALL(handler, handle_input(mt::HoverEnterEvent())).Times(1); |
832 | + EXPECT_CALL(handler, handle_input(mt::MotionEventWithPosition(client_width - 1, client_height - 1))).Times(1) |
833 | + .WillOnce(mt::WakeUp(&events_received)); |
834 | + }); |
835 | + |
836 | + launch_client_process(*client_1); |
837 | + launch_client_process(*client_2); |
838 | } |
839 | |
840 | namespace |
841 | @@ -639,6 +544,7 @@ |
842 | std::vector<geom::Rectangle> const input_rectangles; |
843 | }; |
844 | } |
845 | + |
846 | TEST_F(TestClientInput, clients_do_not_receive_motion_outside_input_region) |
847 | { |
848 | using namespace ::testing; |
849 | @@ -670,7 +576,7 @@ |
850 | static GeometryMap positions; |
851 | positions[test_client_name] = screen_geometry; |
852 | |
853 | - return std::make_shared<StaticPlacementStrategy>(positions); |
854 | + return std::make_shared<StaticPlacementStrategy>(InputTestingServerConfiguration::the_shell_placement_strategy(), positions); |
855 | } |
856 | std::shared_ptr<msh::SurfaceFactory> the_shell_surface_factory() override |
857 | { |
858 | @@ -680,7 +586,6 @@ |
859 | |
860 | void inject_input() override |
861 | { |
862 | - wait_until_client_appears(test_client_name); |
863 | input_cb_setup_fence.wait_for_signal_ready_for(); |
864 | |
865 | // First we will move the cursor in to the input region on the left side of the window. We should see a click here |
866 | @@ -697,35 +602,26 @@ |
867 | fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT)); |
868 | } |
869 | } server_config{fence}; |
870 | - |
871 | launch_server_process(server_config); |
872 | |
873 | - struct ClientConfig : InputClient |
874 | - { |
875 | - ClientConfig(const mtf::CrossProcessSync& fence) |
876 | - : InputClient(fence, test_client_name) |
877 | - { |
878 | - } |
879 | - |
880 | - void expect_input(mt::WaitCondition& events_received) override |
881 | - { |
882 | - |
883 | - EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(AnyNumber()); |
884 | - EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(AnyNumber()); |
885 | - EXPECT_CALL(*handler, handle_input(MovementEvent())).Times(AnyNumber()); |
886 | + auto client_config = make_event_expecting_client(test_client_name, fence, |
887 | + [&](MockInputHandler& handler, mt::WaitCondition& events_received) |
888 | + { |
889 | + EXPECT_CALL(handler, handle_input(mt::HoverEnterEvent())).Times(AnyNumber()); |
890 | + EXPECT_CALL(handler, handle_input(mt::HoverExitEvent())).Times(AnyNumber()); |
891 | + EXPECT_CALL(handler, handle_input(mt::MovementEvent())).Times(AnyNumber()); |
892 | |
893 | { |
894 | // We should see two of the three button pairs. |
895 | InSequence seq; |
896 | - EXPECT_CALL(*handler, handle_input(ButtonDownEvent(1, 1))).Times(1); |
897 | - EXPECT_CALL(*handler, handle_input(ButtonUpEvent(1, 1))).Times(1); |
898 | - EXPECT_CALL(*handler, handle_input(ButtonDownEvent(99, 99))).Times(1); |
899 | - EXPECT_CALL(*handler, handle_input(ButtonUpEvent(99, 99))).Times(1) |
900 | + EXPECT_CALL(handler, handle_input(mt::ButtonDownEvent(1, 1))).Times(1); |
901 | + EXPECT_CALL(handler, handle_input(mt::ButtonUpEvent(1, 1))).Times(1); |
902 | + EXPECT_CALL(handler, handle_input(mt::ButtonDownEvent(99, 99))).Times(1); |
903 | + EXPECT_CALL(handler, handle_input(mt::ButtonUpEvent(99, 99))).Times(1) |
904 | .WillOnce(mt::WakeUp(&events_received)); |
905 | } |
906 | - } |
907 | - } client_config{fence}; |
908 | - launch_client_process(client_config); |
909 | + }); |
910 | + launch_client_process(*client_config); |
911 | } |
912 | |
913 | TEST_F(TestClientInput, surfaces_obscure_motion_events_by_stacking) |
914 | @@ -742,98 +638,62 @@ |
915 | static geom::Rectangle const screen_geometry{geom::Point{0, 0}, |
916 | geom::Size{screen_width, screen_height}}; |
917 | |
918 | - struct ServerConfiguration : mtf::InputTestingServerConfiguration |
919 | - { |
920 | - mtf::CrossProcessSync input_cb_setup_fence; |
921 | - |
922 | - ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence) |
923 | - : input_cb_setup_fence(input_cb_setup_fence) |
924 | - { |
925 | - } |
926 | - |
927 | - std::shared_ptr<msh::PlacementStrategy> the_shell_placement_strategy() override |
928 | - { |
929 | - static GeometryMap positions; |
930 | - positions[test_client_name_1] = screen_geometry; |
931 | - |
932 | - auto smaller_geometry = screen_geometry; |
933 | - smaller_geometry.size.width = geom::Width{screen_width/2}; |
934 | - positions[test_client_name_2] = smaller_geometry; |
935 | - |
936 | - static DepthMap depths; |
937 | - depths[test_client_name_1] = ms::DepthId{0}; |
938 | - depths[test_client_name_2] = ms::DepthId{1}; |
939 | - |
940 | - return std::make_shared<StaticPlacementStrategy>(positions, depths); |
941 | - } |
942 | - |
943 | - void inject_input() override |
944 | - { |
945 | - wait_until_client_appears(test_client_name_1); |
946 | - input_cb_setup_fence.wait_for_signal_ready_for(); |
947 | - wait_until_client_appears(test_client_name_2); |
948 | - input_cb_setup_fence.wait_for_signal_ready_for(); |
949 | - |
950 | + static GeometryMap positions; |
951 | + positions[test_client_name_1] = screen_geometry; |
952 | + |
953 | + auto smaller_geometry = screen_geometry; |
954 | + smaller_geometry.size.width = geom::Width{screen_width/2}; |
955 | + positions[test_client_name_2] = smaller_geometry; |
956 | + |
957 | + static DepthMap depths; |
958 | + depths[test_client_name_1] = ms::DepthId{0}; |
959 | + depths[test_client_name_2] = ms::DepthId{1}; |
960 | + |
961 | + auto server_config = make_event_producing_server(fence, 2, |
962 | + [&](mtf::InputTestingServerConfiguration& server) |
963 | + { |
964 | // First we will move the cursor in to the region where client 2 obscures client 1 |
965 | - fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1, 1)); |
966 | - fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down)); |
967 | - fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT)); |
968 | + server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1, 1)); |
969 | + server.fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down)); |
970 | + server.fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT)); |
971 | // Now we move to the unobscured region of client 1 |
972 | - fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(50, 0)); |
973 | - fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down)); |
974 | - fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT)); |
975 | - } |
976 | - } server_config{fence}; |
977 | - |
978 | - launch_server_process(server_config); |
979 | - |
980 | - struct ClientConfigOne : InputClient |
981 | - { |
982 | - ClientConfigOne(const mtf::CrossProcessSync& fence) |
983 | - : InputClient(fence, test_client_name_1) |
984 | - { |
985 | - } |
986 | - |
987 | - void expect_input(mt::WaitCondition& events_received) override |
988 | - { |
989 | - EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(AnyNumber()); |
990 | - EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(AnyNumber()); |
991 | - EXPECT_CALL(*handler, handle_input(MovementEvent())).Times(AnyNumber()); |
992 | - |
993 | + server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(50, 0)); |
994 | + server.fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down)); |
995 | + server.fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT)); |
996 | + }, positions, depths); |
997 | + launch_server_process(*server_config); |
998 | + |
999 | + auto client_config_1 = make_event_expecting_client(test_client_name_1, fence, |
1000 | + [&](MockInputHandler& handler, mt::WaitCondition& events_received) |
1001 | + { |
1002 | + EXPECT_CALL(handler, handle_input(mt::HoverEnterEvent())).Times(AnyNumber()); |
1003 | + EXPECT_CALL(handler, handle_input(mt::HoverExitEvent())).Times(AnyNumber()); |
1004 | + EXPECT_CALL(handler, handle_input(mt::MovementEvent())).Times(AnyNumber()); |
1005 | { |
1006 | // We should only see one button event sequence. |
1007 | InSequence seq; |
1008 | - EXPECT_CALL(*handler, handle_input(ButtonDownEvent(51, 1))).Times(1); |
1009 | - EXPECT_CALL(*handler, handle_input(ButtonUpEvent(51, 1))).Times(1) |
1010 | + EXPECT_CALL(handler, handle_input(mt::ButtonDownEvent(51, 1))).Times(1); |
1011 | + EXPECT_CALL(handler, handle_input(mt::ButtonUpEvent(51, 1))).Times(1) |
1012 | .WillOnce(mt::WakeUp(&events_received)); |
1013 | } |
1014 | - } |
1015 | - } client_config_1{fence}; |
1016 | - launch_client_process(client_config_1); |
1017 | - |
1018 | - struct ClientConfigTwo : InputClient |
1019 | - { |
1020 | - ClientConfigTwo(const mtf::CrossProcessSync& fence) |
1021 | - : InputClient(fence, test_client_name_2) |
1022 | - { |
1023 | - } |
1024 | - |
1025 | - void expect_input(mt::WaitCondition& events_received) override |
1026 | - { |
1027 | - EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(AnyNumber()); |
1028 | - EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(AnyNumber()); |
1029 | - EXPECT_CALL(*handler, handle_input(MovementEvent())).Times(AnyNumber()); |
1030 | - |
1031 | + }); |
1032 | + auto client_config_2 = make_event_expecting_client(test_client_name_2, fence, |
1033 | + [&](MockInputHandler& handler, mt::WaitCondition& events_received) |
1034 | + { |
1035 | + EXPECT_CALL(handler, handle_input(mt::HoverEnterEvent())).Times(AnyNumber()); |
1036 | + EXPECT_CALL(handler, handle_input(mt::HoverExitEvent())).Times(AnyNumber()); |
1037 | + EXPECT_CALL(handler, handle_input(mt::MovementEvent())).Times(AnyNumber()); |
1038 | { |
1039 | // Likewise we should only see one button sequence. |
1040 | InSequence seq; |
1041 | - EXPECT_CALL(*handler, handle_input(ButtonDownEvent(1, 1))).Times(1); |
1042 | - EXPECT_CALL(*handler, handle_input(ButtonUpEvent(1, 1))).Times(1) |
1043 | + EXPECT_CALL(handler, handle_input(mt::ButtonDownEvent(1, 1))).Times(1); |
1044 | + EXPECT_CALL(handler, handle_input(mt::ButtonUpEvent(1, 1))).Times(1) |
1045 | .WillOnce(mt::WakeUp(&events_received)); |
1046 | } |
1047 | - } |
1048 | - } client_config_2{fence}; |
1049 | - launch_client_process(client_config_2); |
1050 | + }); |
1051 | + |
1052 | + launch_client_process(*client_config_1); |
1053 | + launch_client_process(*client_config_2); |
1054 | } |
1055 | |
1056 | namespace |
1057 | @@ -853,93 +713,48 @@ |
1058 | static std::string const test_client_name = "1"; |
1059 | static std::string const test_client_2_name = "2"; |
1060 | mtf::CrossProcessSync fence, first_client_ready_fence, second_client_done_fence; |
1061 | - |
1062 | - struct ServerConfiguration : public mtf::InputTestingServerConfiguration |
1063 | - { |
1064 | - mtf::CrossProcessSync input_cb_setup_fence; |
1065 | - mtf::CrossProcessSync second_client_done_fence; |
1066 | - |
1067 | - ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence, |
1068 | - const mtf::CrossProcessSync& second_client_done_fence) |
1069 | - : input_cb_setup_fence(input_cb_setup_fence), |
1070 | - second_client_done_fence(second_client_done_fence) |
1071 | - { |
1072 | - } |
1073 | - |
1074 | - void hide_session_by_name(std::string const& session_name) |
1075 | - { |
1076 | - the_shell_session_container()->for_each([&](std::shared_ptr<msh::Session> const& session) -> void |
1077 | - { |
1078 | - if (session->name() == session_name) |
1079 | - session->hide(); |
1080 | - }); |
1081 | - } |
1082 | - |
1083 | - void inject_input() |
1084 | - { |
1085 | - wait_until_client_appears(test_client_name); |
1086 | - wait_until_client_appears(test_client_2_name); |
1087 | - input_cb_setup_fence.wait_for_signal_ready_for(); |
1088 | - |
1089 | + |
1090 | + static DepthMap depths; |
1091 | + depths[test_client_name] = ms::DepthId{0}; |
1092 | + depths[test_client_2_name] = ms::DepthId{1}; |
1093 | + |
1094 | + auto server_config = make_event_producing_server(fence, 2, |
1095 | + [&](mtf::InputTestingServerConfiguration& server) |
1096 | + { |
1097 | // We send one event and then hide the surface on top before sending the next. |
1098 | - // So we expect each of the two surfaces to receive one event pair. |
1099 | - fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1,1)); |
1100 | - |
1101 | + // So we expect each of the two surfaces to receive one even |
1102 | + server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1,1)); |
1103 | // We use a fence to ensure we do not hide the client |
1104 | // before event dispatch occurs |
1105 | second_client_done_fence.wait_for_signal_ready_for(); |
1106 | - hide_session_by_name(test_client_2_name); |
1107 | - |
1108 | - fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1,1)); |
1109 | - } |
1110 | - } server_config{fence, second_client_done_fence}; |
1111 | - launch_server_process(server_config); |
1112 | - |
1113 | - struct ButtonClientOne : InputClient |
1114 | - { |
1115 | - ButtonClientOne(const mtf::CrossProcessSync& fence) |
1116 | - : InputClient(fence, test_client_name) |
1117 | - { |
1118 | - } |
1119 | - |
1120 | - void expect_input(mt::WaitCondition& events_received) override |
1121 | - { |
1122 | - EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(AnyNumber()); |
1123 | - EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(AnyNumber()); |
1124 | - EXPECT_CALL(*handler, handle_input(MotionEventWithPosition(2, 2))).Times(1) |
1125 | + |
1126 | + server.the_shell_session_container()->for_each([&](std::shared_ptr<msh::Session> const& session) -> void |
1127 | + { |
1128 | + if (session->name() == test_client_2_name) |
1129 | + session->hide(); |
1130 | + }); |
1131 | + |
1132 | + server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1,1)); |
1133 | + }, GeometryMap(), depths); |
1134 | + launch_server_process(*server_config); |
1135 | + |
1136 | + auto client_config_1 = make_event_expecting_client(test_client_name, fence, |
1137 | + [&](MockInputHandler& handler, mt::WaitCondition& events_received) |
1138 | + { |
1139 | + EXPECT_CALL(handler, handle_input(mt::HoverEnterEvent())).Times(AnyNumber()); |
1140 | + EXPECT_CALL(handler, handle_input(mt::HoverExitEvent())).Times(AnyNumber()); |
1141 | + EXPECT_CALL(handler, handle_input(mt::MotionEventWithPosition(2, 2))).Times(1) |
1142 | .WillOnce(mt::WakeUp(&events_received)); |
1143 | - } |
1144 | - } client_1{first_client_ready_fence}; |
1145 | - struct ButtonClientTwo : InputClient |
1146 | - { |
1147 | - mtf::CrossProcessSync first_client_ready; |
1148 | - mtf::CrossProcessSync done_fence; |
1149 | - |
1150 | - ButtonClientTwo(mtf::CrossProcessSync const& fence, mtf::CrossProcessSync const& first_client_ready, |
1151 | - mtf::CrossProcessSync const& done_fence) |
1152 | - : InputClient(fence, test_client_2_name), |
1153 | - first_client_ready(first_client_ready), |
1154 | - done_fence(done_fence) |
1155 | - { |
1156 | - } |
1157 | - void exec() |
1158 | - { |
1159 | - // Ensure we stack on top of the first client |
1160 | - first_client_ready.wait_for_signal_ready_for(); |
1161 | - InputClient::exec(); |
1162 | - } |
1163 | - |
1164 | - void expect_input(mt::WaitCondition& events_received) override |
1165 | - { |
1166 | - EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(AnyNumber()); |
1167 | - EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(AnyNumber()); |
1168 | - EXPECT_CALL(*handler, handle_input(MotionEventWithPosition(1, 1))).Times(1) |
1169 | - .WillOnce(DoAll(SignalFence(&done_fence), mt::WakeUp(&events_received))); |
1170 | - } |
1171 | - } client_2{fence, first_client_ready_fence, second_client_done_fence}; |
1172 | - |
1173 | - // Client 2 is launched second so will be the first to receive input |
1174 | - |
1175 | - launch_client_process(client_1); |
1176 | - launch_client_process(client_2); |
1177 | + }); |
1178 | + auto client_config_2 = make_event_expecting_client(test_client_2_name, fence, |
1179 | + [&](MockInputHandler& handler, mt::WaitCondition& events_received) |
1180 | + { |
1181 | + EXPECT_CALL(handler, handle_input(mt::HoverEnterEvent())).Times(AnyNumber()); |
1182 | + EXPECT_CALL(handler, handle_input(mt::HoverExitEvent())).Times(AnyNumber()); |
1183 | + EXPECT_CALL(handler, handle_input(mt::MotionEventWithPosition(1, 1))).Times(1) |
1184 | + .WillOnce(DoAll(SignalFence(&second_client_done_fence), mt::WakeUp(&events_received))); |
1185 | + }); |
1186 | + |
1187 | + launch_client_process(*client_config_1); |
1188 | + launch_client_process(*client_config_2); |
1189 | } |
1190 | |
1191 | === modified file 'tests/mir_test_framework/input_testing_server_options.cpp' |
1192 | --- tests/mir_test_framework/input_testing_server_options.cpp 2013-09-19 18:18:35 +0000 |
1193 | +++ tests/mir_test_framework/input_testing_server_options.cpp 2013-11-07 17:24:53 +0000 |
1194 | @@ -36,8 +36,6 @@ |
1195 | |
1196 | namespace mtf = mir_test_framework; |
1197 | |
1198 | -namespace ms = mir::surfaces; |
1199 | -namespace msh = mir::shell; |
1200 | namespace mf = mir::frontend; |
1201 | namespace mg = mir::graphics; |
1202 | namespace mi = mir::input; |
1203 | @@ -45,63 +43,6 @@ |
1204 | namespace geom = mir::geometry; |
1205 | namespace mtd = mir::test::doubles; |
1206 | |
1207 | -namespace |
1208 | -{ |
1209 | -class SurfaceReadinessListener |
1210 | -{ |
1211 | -public: |
1212 | - virtual ~SurfaceReadinessListener() = default; |
1213 | - |
1214 | - virtual void channel_ready_for_input(std::string const& channel_name) = 0; |
1215 | - |
1216 | -protected: |
1217 | - SurfaceReadinessListener() = default; |
1218 | - SurfaceReadinessListener(SurfaceReadinessListener const&) = delete; |
1219 | - SurfaceReadinessListener& operator=(SurfaceReadinessListener const&) = delete; |
1220 | -}; |
1221 | - |
1222 | -class ProxyShell : public mf::Shell |
1223 | -{ |
1224 | -public: |
1225 | - ProxyShell(std::shared_ptr<mf::Shell> const& underlying_shell, |
1226 | - std::shared_ptr<SurfaceReadinessListener> const listener) |
1227 | - : underlying_shell(underlying_shell), |
1228 | - listener(listener) |
1229 | - { |
1230 | - } |
1231 | - |
1232 | - ~ProxyShell() noexcept(true) = default; |
1233 | - |
1234 | - mf::SurfaceId create_surface_for(std::shared_ptr<mf::Session> const& session, |
1235 | - msh::SurfaceCreationParameters const& params) |
1236 | - { |
1237 | - return underlying_shell->create_surface_for(session, params); |
1238 | - } |
1239 | - |
1240 | - std::shared_ptr<mf::Session> open_session(std::string const& name, |
1241 | - std::shared_ptr<mf::EventSink> const& sink) |
1242 | - { |
1243 | - return underlying_shell->open_session(name, sink); |
1244 | - } |
1245 | - |
1246 | - void close_session(std::shared_ptr<mf::Session> const& session) |
1247 | - { |
1248 | - underlying_shell->close_session(session); |
1249 | - } |
1250 | - |
1251 | - void handle_surface_created(std::shared_ptr<mf::Session> const& session) |
1252 | - { |
1253 | - underlying_shell->handle_surface_created(session); |
1254 | - listener->channel_ready_for_input(session->name()); |
1255 | - } |
1256 | - |
1257 | -private: |
1258 | - std::shared_ptr<mf::Shell> const underlying_shell; |
1259 | - std::shared_ptr<SurfaceReadinessListener> const listener; |
1260 | -}; |
1261 | - |
1262 | -} |
1263 | - |
1264 | mtf::InputTestingServerConfiguration::InputTestingServerConfiguration() |
1265 | { |
1266 | } |
1267 | @@ -136,56 +77,3 @@ |
1268 | |
1269 | return input_configuration; |
1270 | } |
1271 | - |
1272 | -std::shared_ptr<mf::Shell> mtf::InputTestingServerConfiguration::the_frontend_shell() |
1273 | -{ |
1274 | - struct LifecycleTracker : public SurfaceReadinessListener |
1275 | - { |
1276 | - LifecycleTracker(std::mutex& lifecycle_lock, |
1277 | - std::condition_variable &lifecycle_condition, |
1278 | - std::map<std::string, mtf::ClientLifecycleState> &client_lifecycles) |
1279 | - : lifecycle_lock(lifecycle_lock), |
1280 | - lifecycle_condition(lifecycle_condition), |
1281 | - client_lifecycles(client_lifecycles) |
1282 | - { |
1283 | - } |
1284 | - void channel_ready_for_input(std::string const& channel_name) |
1285 | - { |
1286 | - std::unique_lock<std::mutex> lg(lifecycle_lock); |
1287 | - client_lifecycles[channel_name] = mtf::ClientLifecycleState::appeared; |
1288 | - lifecycle_condition.notify_all(); |
1289 | - } |
1290 | - |
1291 | - std::mutex &lifecycle_lock; |
1292 | - std::condition_variable &lifecycle_condition; |
1293 | - std::map<std::string, mtf::ClientLifecycleState> &client_lifecycles; |
1294 | - }; |
1295 | - |
1296 | - if (!frontend_shell) |
1297 | - { |
1298 | - auto readiness_listener = std::make_shared<LifecycleTracker>(lifecycle_lock, |
1299 | - lifecycle_condition, |
1300 | - client_lifecycles); |
1301 | - frontend_shell = std::make_shared<ProxyShell>(DefaultServerConfiguration::the_frontend_shell(), readiness_listener); |
1302 | - } |
1303 | - |
1304 | - return frontend_shell; |
1305 | -} |
1306 | - |
1307 | -void mtf::InputTestingServerConfiguration::wait_until_client_appears(std::string const& channel_name) |
1308 | -{ |
1309 | - std::unique_lock<std::mutex> lg(lifecycle_lock); |
1310 | - |
1311 | - std::chrono::minutes timeout(2); |
1312 | - auto end_time = std::chrono::system_clock::now() + timeout; |
1313 | - |
1314 | - if (client_lifecycles[channel_name] == vanished) |
1315 | - { |
1316 | - BOOST_THROW_EXCEPTION(std::runtime_error("Waiting for a client (" + channel_name + ") to appear but it has already vanished")); |
1317 | - } |
1318 | - while (client_lifecycles[channel_name] != appeared) |
1319 | - { |
1320 | - if (lifecycle_condition.wait_until(lg, end_time) == std::cv_status::timeout) |
1321 | - BOOST_THROW_EXCEPTION(std::runtime_error("Timed out waiting for client (" + channel_name + ") to appear")); |
1322 | - } |
1323 | -} |
FAILED: Continuous integration, rev:1205 /code.launchpad .net/~robertcar r/mir/refactor- input-acceptanc e-take- 1/+merge/ 194265/ +edit-commit- message
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
http:// jenkins. qa.ubuntu. com/job/ mir-team- mir-development -branch- ci/347/ jenkins. qa.ubuntu. com/job/ mir-android- trusty- i386-build/ 139 jenkins. qa.ubuntu. com/job/ mir-clang- trusty- amd64-build/ 136/console jenkins. qa.ubuntu. com/job/ mir-team- mir-development -branch- trusty- amd64-ci/ 76/console jenkins. qa.ubuntu. com/job/ mir-team- mir-development -branch- trusty- armhf-ci/ 76 jenkins. qa.ubuntu. com/job/ mir-team- mir-development -branch- trusty- armhf-ci/ 76/artifact/ work/output/ *zip*/output. zip
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild: 10.97.0. 26:8080/ job/mir- team-mir- development- branch- ci/347/ rebuild
http://