Merge lp:~afrantzis/mir/fix-1342567-test-client-cursor-api into lp:mir
- fix-1342567-test-client-cursor-api
- Merge into development-branch
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Alexandros Frantzis | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 1894 | ||||
Proposed branch: | lp:~afrantzis/mir/fix-1342567-test-client-cursor-api | ||||
Merge into: | lp:mir | ||||
Diff against target: |
766 lines (+265/-382) 1 file modified
tests/acceptance-tests/test_client_cursor_api.cpp (+265/-382) |
||||
To merge this branch: | bzr merge lp:~afrantzis/mir/fix-1342567-test-client-cursor-api | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Daniel van Vugt | Approve | ||
Kevin DuBois (community) | Approve | ||
Review via email: mp+233316@code.launchpad.net |
Commit message
tests: Refactor the TestClientCursorAPI tests to simplify them and fix races (LP: #1342567)
Description of the change
tests: Refactor the TestClientCursorAPI tests to simplify them and fix races
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1889
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Daniel van Vugt (vanvugt) wrote : | # |
Sure, why not.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
ABORTED: http://
SUCCESS: http://
PS Jenkins bot (ps-jenkins) : | # |
Preview Diff
1 | === modified file 'tests/acceptance-tests/test_client_cursor_api.cpp' |
2 | --- tests/acceptance-tests/test_client_cursor_api.cpp 2014-09-01 04:53:25 +0000 |
3 | +++ tests/acceptance-tests/test_client_cursor_api.cpp 2014-09-04 08:51:10 +0000 |
4 | @@ -1,5 +1,5 @@ |
5 | /* |
6 | - * Copyright © 2013 Canonical Ltd. |
7 | + * Copyright © 2013-2014 Canonical Ltd. |
8 | * |
9 | * This program is free software: you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 3 as |
11 | @@ -14,40 +14,34 @@ |
12 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
13 | * |
14 | * Authored by: Robert Carr <robert.carr@canonical.com> |
15 | + * Alexandros Frantzis <alexandros.frantzis@canonical.com> |
16 | */ |
17 | |
18 | #include "mir/graphics/cursor.h" |
19 | #include "mir/graphics/cursor_image.h" |
20 | #include "mir/input/cursor_images.h" |
21 | -#include "mir/scene/surface.h" |
22 | -#include "mir/scene/surface_factory.h" |
23 | -#include "mir/scene/null_observer.h" |
24 | -#include "mir/scene/null_surface_observer.h" |
25 | - |
26 | -#include "mir_toolkit/mir_client_library.h" |
27 | - |
28 | -#include "mir_test/barrier.h" |
29 | -#include "mir_test/fake_event_hub.h" |
30 | + |
31 | +#include "mir_test_framework/in_process_server.h" |
32 | +#include "mir_test_framework/fake_event_hub_server_configuration.h" |
33 | +#include "mir_test_framework/declarative_placement_strategy.h" |
34 | +#include "mir_test_framework/using_stub_client_platform.h" |
35 | + |
36 | #include "mir_test/fake_shared.h" |
37 | +#include "mir_test/spin_wait.h" |
38 | #include "mir_test/wait_condition.h" |
39 | -#include "mir_test_framework/input_testing_server_configuration.h" |
40 | -#include "mir_test_framework/testing_client_configuration.h" |
41 | -#include "mir_test_framework/declarative_placement_strategy.h" |
42 | -#include "mir_test_framework/deferred_in_process_server.h" |
43 | -#include "mir_test_framework/using_stub_client_platform.h" |
44 | +#include "mir_test/fake_event_hub.h" |
45 | + |
46 | +#include "mir_toolkit/mir_client_library.h" |
47 | |
48 | #include <gtest/gtest.h> |
49 | #include <gmock/gmock.h> |
50 | |
51 | +namespace mt = mir::test; |
52 | +namespace mtf = mir_test_framework; |
53 | +namespace geom = mir::geometry; |
54 | namespace mg = mir::graphics; |
55 | -namespace ms = mir::scene; |
56 | -namespace msh = mir::shell; |
57 | namespace mi = mir::input; |
58 | namespace mis = mir::input::synthesis; |
59 | -namespace geom = mir::geometry; |
60 | - |
61 | -namespace mt = mir::test; |
62 | -namespace mtf = mir_test_framework; |
63 | |
64 | namespace |
65 | { |
66 | @@ -59,9 +53,7 @@ |
67 | |
68 | // We are not interested in mocking the motion in these tests as we |
69 | // generate it ourself. |
70 | - void move_to(geom::Point) |
71 | - { |
72 | - } |
73 | + void move_to(geom::Point) override {} |
74 | }; |
75 | |
76 | struct NamedCursorImage : public mg::CursorImage |
77 | @@ -71,16 +63,17 @@ |
78 | { |
79 | } |
80 | |
81 | - void const* as_argb_8888() const { return nullptr; } |
82 | - geom::Size size() const { return geom::Size{}; } |
83 | - geom::Displacement hotspot() const { return geom::Displacement{0, 0}; } |
84 | + void const* as_argb_8888() const override { return nullptr; } |
85 | + geom::Size size() const override { return geom::Size{}; } |
86 | + geom::Displacement hotspot() const override { return geom::Displacement{0, 0}; } |
87 | |
88 | std::string const cursor_name; |
89 | }; |
90 | |
91 | struct NamedCursorImages : public mi::CursorImages |
92 | { |
93 | - std::shared_ptr<mg::CursorImage> image(std::string const& name, geom::Size const& /* size */) |
94 | + std::shared_ptr<mg::CursorImage> |
95 | + image(std::string const& name, geom::Size const& /* size */) override |
96 | { |
97 | return std::make_shared<NamedCursorImage>(name); |
98 | } |
99 | @@ -90,7 +83,7 @@ |
100 | { |
101 | auto image = dynamic_cast<NamedCursorImage const*>(&i); |
102 | assert(image); |
103 | - |
104 | + |
105 | return image->cursor_name == name; |
106 | } |
107 | |
108 | @@ -104,84 +97,122 @@ |
109 | return cursor_is_named(arg, name); |
110 | } |
111 | |
112 | -struct ClientConfig : mtf::TestingClientConfiguration |
113 | +struct CursorClient |
114 | { |
115 | - std::string connect_string; |
116 | - |
117 | + CursorClient(std::string const& connect_string, std::string const& client_name) |
118 | + : connect_string{connect_string}, client_name{client_name} |
119 | + { |
120 | + } |
121 | + |
122 | + virtual ~CursorClient() |
123 | + { |
124 | + teardown.wake_up_everyone(); |
125 | + if (client_thread.joinable()) |
126 | + client_thread.join(); |
127 | + } |
128 | + |
129 | + void run() |
130 | + { |
131 | + mir::test::WaitCondition setup_done; |
132 | + |
133 | + client_thread = std::thread{ |
134 | + [this,&setup_done] |
135 | + { |
136 | + auto const connection = |
137 | + mir_connect_sync(connect_string.c_str(), client_name.c_str()); |
138 | + |
139 | + MirSurfaceParameters const request_params = |
140 | + { |
141 | + client_name.c_str(), |
142 | + // For this fixture, we force geometry on server side |
143 | + 0, 0, |
144 | + mir_pixel_format_abgr_8888, |
145 | + mir_buffer_usage_hardware, |
146 | + mir_display_output_id_invalid |
147 | + }; |
148 | + auto const surface = |
149 | + mir_connection_create_surface_sync(connection, &request_params); |
150 | + |
151 | + mir_surface_swap_buffers_sync(surface); |
152 | + |
153 | + wait_for_surface_to_become_focused_and_exposed(surface); |
154 | + |
155 | + setup_cursor(surface); |
156 | + |
157 | + setup_done.wake_up_everyone(); |
158 | + |
159 | + teardown.wait_for_at_most_seconds(10); |
160 | + mir_surface_release_sync(surface); |
161 | + mir_connection_release(connection); |
162 | + }}; |
163 | + |
164 | + setup_done.wait_for_at_most_seconds(5); |
165 | + } |
166 | + |
167 | + virtual void setup_cursor(MirSurface*) |
168 | + { |
169 | + } |
170 | + |
171 | + void wait_for_surface_to_become_focused_and_exposed(MirSurface* surface) |
172 | + { |
173 | + bool success = mt::spin_wait_for_condition_or_timeout( |
174 | + [surface] |
175 | + { |
176 | + return mir_surface_get_visibility(surface) == mir_surface_visibility_exposed && |
177 | + mir_surface_get_focus(surface) == mir_surface_focused; |
178 | + }, |
179 | + std::chrono::seconds{5}); |
180 | + |
181 | + if (!success) |
182 | + throw std::runtime_error("Timeout waiting for surface to become focused and exposed"); |
183 | + } |
184 | + |
185 | + std::string const connect_string; |
186 | std::string const client_name; |
187 | |
188 | - mt::Barrier& set_cursor_complete; |
189 | - mt::Barrier& client_may_exit; |
190 | - |
191 | - std::function<void(MirSurface*)> set_cursor; |
192 | - |
193 | - ClientConfig(std::string const& client_name, |
194 | - mt::Barrier& cursor_ready_fence, |
195 | - mt::Barrier& client_may_exit_fence) |
196 | - : client_name(client_name), |
197 | - set_cursor_complete(cursor_ready_fence), |
198 | - client_may_exit(client_may_exit_fence) |
199 | - { |
200 | - } |
201 | - |
202 | - virtual void thread_exec() |
203 | - { |
204 | - auto connection = mir_connect_sync(connect_string.c_str(), |
205 | - client_name.c_str()); |
206 | - |
207 | - ASSERT_TRUE(connection != NULL); |
208 | - MirSurfaceParameters const request_params = |
209 | - { |
210 | - client_name.c_str(), |
211 | - // For this fixture, we force geometry on server side |
212 | - 0, 0, |
213 | - mir_pixel_format_abgr_8888, |
214 | - mir_buffer_usage_hardware, |
215 | - mir_display_output_id_invalid |
216 | - }; |
217 | - auto surface = mir_connection_create_surface_sync(connection, &request_params); |
218 | - |
219 | - set_cursor(surface); |
220 | - set_cursor_complete.ready(); |
221 | - |
222 | - client_may_exit.ready(); |
223 | - |
224 | - mir_surface_release_sync(surface); |
225 | - mir_connection_release(connection); |
226 | - } |
227 | - void tear_down() { if (thread.joinable()) thread.join(); } |
228 | - |
229 | - void exec() override |
230 | - { |
231 | - thread = std::thread([this]{ thread_exec(); }); |
232 | - } |
233 | -private: |
234 | - std::thread thread; |
235 | -}; |
236 | - |
237 | -struct ServerConfiguration : mtf::InputTestingServerConfiguration |
238 | -{ |
239 | - mt::Barrier& cursor_configured_fence; |
240 | - mt::Barrier& client_may_exit_fence; |
241 | - |
242 | - std::function<void(MockCursor&, mt::WaitCondition&)> expect_cursor_states; |
243 | - std::function<void(ServerConfiguration*)> synthesize_cursor_motion; |
244 | - |
245 | - mtf::SurfaceGeometries client_geometries; |
246 | - mtf::SurfaceDepths client_depths; |
247 | - |
248 | - MockCursor cursor; |
249 | - |
250 | - ServerConfiguration(mt::Barrier& cursor_configured_fence, mt::Barrier& client_may_exit_fence) |
251 | - : cursor_configured_fence(cursor_configured_fence), |
252 | - client_may_exit_fence(client_may_exit_fence) |
253 | - { |
254 | - } |
255 | - |
256 | - std::shared_ptr<ms::PlacementStrategy> the_placement_strategy() override |
257 | + std::thread client_thread; |
258 | + mir::test::WaitCondition teardown; |
259 | +}; |
260 | + |
261 | +struct DisabledCursorClient : CursorClient |
262 | +{ |
263 | + using CursorClient::CursorClient; |
264 | + |
265 | + void setup_cursor(MirSurface* surface) override |
266 | + { |
267 | + auto conf = mir_cursor_configuration_from_name(mir_disabled_cursor_name); |
268 | + mir_wait_for(mir_surface_configure_cursor(surface, conf)); |
269 | + mir_cursor_configuration_destroy(conf); |
270 | + } |
271 | +}; |
272 | + |
273 | +struct NamedCursorClient : CursorClient |
274 | +{ |
275 | + NamedCursorClient( |
276 | + std::string const& connect_string, |
277 | + std::string const& client_name, |
278 | + std::string const& cursor_name) |
279 | + : CursorClient{connect_string, client_name}, |
280 | + cursor_name{cursor_name} |
281 | + { |
282 | + } |
283 | + |
284 | + void setup_cursor(MirSurface* surface) override |
285 | + { |
286 | + auto conf = mir_cursor_configuration_from_name(cursor_name.c_str()); |
287 | + mir_wait_for(mir_surface_configure_cursor(surface, conf)); |
288 | + mir_cursor_configuration_destroy(conf); |
289 | + } |
290 | + |
291 | + std::string const cursor_name; |
292 | +}; |
293 | + |
294 | +struct TestServerConfiguration : mtf::FakeEventHubServerConfiguration |
295 | +{ |
296 | + std::shared_ptr<mir::scene::PlacementStrategy> the_placement_strategy() override |
297 | { |
298 | return std::make_shared<mtf::DeclarativePlacementStrategy>( |
299 | - InputTestingServerConfiguration::the_placement_strategy(), |
300 | + FakeEventHubServerConfiguration::the_placement_strategy(), |
301 | client_geometries, client_depths); |
302 | } |
303 | |
304 | @@ -189,83 +220,51 @@ |
305 | { |
306 | return mt::fake_shared(cursor); |
307 | } |
308 | - |
309 | + |
310 | std::shared_ptr<mi::CursorImages> the_cursor_images() override |
311 | { |
312 | return std::make_shared<NamedCursorImages>(); |
313 | } |
314 | - |
315 | - void inject_input() |
316 | - { |
317 | - using namespace ::testing; |
318 | - cursor_configured_fence.ready(); |
319 | - |
320 | - mt::WaitCondition expectations_satisfied; |
321 | - |
322 | - // Clear any states applied during server initialization. |
323 | - Mock::VerifyAndClearExpectations(&cursor); |
324 | - expect_cursor_states(cursor, expectations_satisfied); |
325 | - |
326 | - // We are only interested in the cursor image changes, not |
327 | - // the synthetic motion. |
328 | - |
329 | - synthesize_cursor_motion(this); |
330 | - expectations_satisfied.wait_for_at_most_seconds(60); |
331 | - |
332 | - Mock::VerifyAndClearExpectations(&cursor); |
333 | + |
334 | + MockCursor cursor; |
335 | + mtf::SurfaceGeometries client_geometries; |
336 | + mtf::SurfaceDepths client_depths; |
337 | +}; |
338 | + |
339 | +struct TestClientCursorAPI : mtf::InProcessServer |
340 | +{ |
341 | + mir::DefaultServerConfiguration& server_config() override |
342 | + { |
343 | + return server_configuration_; |
344 | + } |
345 | + |
346 | + TestServerConfiguration& test_server_config() |
347 | + { |
348 | + return server_configuration_; |
349 | + } |
350 | + |
351 | + mir::input::android::FakeEventHub* fake_event_hub() |
352 | + { |
353 | + return server_configuration_.fake_event_hub; |
354 | + } |
355 | + |
356 | + void client_shutdown_expectations() |
357 | + { |
358 | + using namespace testing; |
359 | + Mock::VerifyAndClearExpectations(&test_server_config().cursor); |
360 | |
361 | // Client shutdown |
362 | - EXPECT_CALL(cursor, show(_)).Times(AnyNumber()); |
363 | - EXPECT_CALL(cursor, hide()).Times(AnyNumber()); |
364 | - client_may_exit_fence.ready(); |
365 | + EXPECT_CALL(test_server_config().cursor, show(_)).Times(AnyNumber()); |
366 | + EXPECT_CALL(test_server_config().cursor, hide()).Times(AnyNumber()); |
367 | } |
368 | - |
369 | -}; |
370 | |
371 | -struct TestClientCursorAPI : mtf::DeferredInProcessServer |
372 | -{ |
373 | - std::string const client_name_1 = "1"; |
374 | - std::string const client_name_2 = "2"; |
375 | - std::string const client_cursor_1 = "cursor-1"; |
376 | - std::string const client_cursor_2 = "cursor-2"; |
377 | - |
378 | - // Reset to higher values for more clients. |
379 | - mt::Barrier cursor_configured_fence{2}; |
380 | - mt::Barrier client_may_exit_fence{2}; |
381 | - |
382 | - ServerConfiguration server_configuration{cursor_configured_fence, client_may_exit_fence}; |
383 | - mir::DefaultServerConfiguration& server_config() override { return server_configuration; } |
384 | + std::string const client_name_1{"client-1"}; |
385 | + std::string const client_name_2{"client-2"}; |
386 | + std::string const client_cursor_1{"cursor-1"}; |
387 | + std::string const client_cursor_2{"cursor-2"}; |
388 | + TestServerConfiguration server_configuration_; |
389 | + mir::test::WaitCondition expectations_satisfied; |
390 | mtf::UsingStubClientPlatform using_stub_client_platform; |
391 | - |
392 | - ClientConfig client_config_1{client_name_1, cursor_configured_fence, client_may_exit_fence}; |
393 | - ClientConfig client_config_2{client_name_2, cursor_configured_fence, client_may_exit_fence}; |
394 | - |
395 | - // Default number allows one client. |
396 | - void set_client_count(unsigned count) |
397 | - { |
398 | - cursor_configured_fence.reset(count + 1); |
399 | - client_may_exit_fence.reset(count + 1); |
400 | - } |
401 | - |
402 | - void start_server() |
403 | - { |
404 | - DeferredInProcessServer::start_server(); |
405 | - server_configuration.exec(); |
406 | - } |
407 | - |
408 | - void start_client(ClientConfig& config) |
409 | - { |
410 | - config.connect_string = new_connection(); |
411 | - config.exec(); |
412 | - } |
413 | - |
414 | - void TearDown() |
415 | - { |
416 | - client_config_1.tear_down(); |
417 | - client_config_2.tear_down(); |
418 | - server_configuration.on_exit(); |
419 | - DeferredInProcessServer::TearDown(); |
420 | - } |
421 | }; |
422 | |
423 | } |
424 | @@ -277,238 +276,107 @@ |
425 | { |
426 | using namespace ::testing; |
427 | |
428 | - server_configuration.client_geometries[client_name_1] = geom::Rectangle{geom::Point{geom::X{1}, geom::Y{0}}, |
429 | - geom::Size{geom::Width{1}, geom::Height{1}}}; |
430 | - |
431 | - |
432 | - server_configuration.expect_cursor_states = [](MockCursor& cursor, mt::WaitCondition& expectations_satisfied) |
433 | - { |
434 | - EXPECT_CALL(cursor, hide()).Times(1) |
435 | - .WillOnce(mt::WakeUp(&expectations_satisfied)); |
436 | - }; |
437 | - server_configuration.synthesize_cursor_motion = [](ServerConfiguration *server) |
438 | - { |
439 | - server->fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1, 0)); |
440 | - }; |
441 | - start_server(); |
442 | - |
443 | - client_config_1.set_cursor = [](MirSurface *surface) |
444 | - { |
445 | - auto conf = mir_cursor_configuration_from_name(mir_disabled_cursor_name); |
446 | - mir_wait_for(mir_surface_configure_cursor(surface, conf)); |
447 | - mir_cursor_configuration_destroy(conf); |
448 | - }; |
449 | - start_client(client_config_1); |
450 | + test_server_config().client_geometries[client_name_1] = |
451 | + geom::Rectangle{{1, 0}, {1, 1}}; |
452 | + |
453 | + DisabledCursorClient client{new_connection(), client_name_1}; |
454 | + client.run(); |
455 | + |
456 | + EXPECT_CALL(test_server_config().cursor, hide()) |
457 | + .WillOnce(mt::WakeUp(&expectations_satisfied)); |
458 | + |
459 | + fake_event_hub()->synthesize_event(mis::a_motion_event().with_movement(1, 0)); |
460 | + |
461 | + expectations_satisfied.wait_for_at_most_seconds(5); |
462 | + |
463 | + client_shutdown_expectations(); |
464 | } |
465 | |
466 | TEST_F(TestClientCursorAPI, cursor_restored_when_leaving_surface) |
467 | { |
468 | using namespace ::testing; |
469 | |
470 | - server_configuration.client_geometries[client_name_1] = geom::Rectangle{geom::Point{geom::X{1}, geom::Y{0}}, |
471 | - geom::Size{geom::Width{1}, geom::Height{1}}}; |
472 | - |
473 | - mtf::CrossProcessSync client_ready_fence, client_may_exit_fence; |
474 | - |
475 | - server_configuration.expect_cursor_states = [](MockCursor& cursor, mt::WaitCondition& expectations_satisfied) |
476 | - { |
477 | - InSequence seq; |
478 | - EXPECT_CALL(cursor, hide()).Times(1); |
479 | - EXPECT_CALL(cursor, show(DefaultCursorImage())).Times(1) |
480 | - .WillOnce(mt::WakeUp(&expectations_satisfied)); |
481 | - }; |
482 | - server_configuration.synthesize_cursor_motion = [](ServerConfiguration *server) |
483 | - { |
484 | - server->fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1, 0)); |
485 | - server->fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(2,0)); |
486 | - }; |
487 | - start_server(); |
488 | - |
489 | - |
490 | - client_config_1.set_cursor = [](MirSurface *surface) |
491 | - { |
492 | - // Disable cursor |
493 | - auto conf = mir_cursor_configuration_from_name(mir_disabled_cursor_name); |
494 | - mir_wait_for(mir_surface_configure_cursor(surface, conf)); |
495 | - mir_cursor_configuration_destroy(conf); |
496 | - }; |
497 | - start_client(client_config_1); |
498 | + test_server_config().client_geometries[client_name_1] = |
499 | + geom::Rectangle{{1, 0}, {1, 1}}; |
500 | + |
501 | + DisabledCursorClient client{new_connection(), client_name_1}; |
502 | + client.run(); |
503 | + |
504 | + InSequence seq; |
505 | + EXPECT_CALL(test_server_config().cursor, hide()); |
506 | + EXPECT_CALL(test_server_config().cursor, show(DefaultCursorImage())) |
507 | + .WillOnce(mt::WakeUp(&expectations_satisfied)); |
508 | + |
509 | + fake_event_hub()->synthesize_event(mis::a_motion_event().with_movement(1, 0)); |
510 | + fake_event_hub()->synthesize_event(mis::a_motion_event().with_movement(2, 0)); |
511 | + |
512 | + expectations_satisfied.wait_for_at_most_seconds(5); |
513 | + |
514 | + client_shutdown_expectations(); |
515 | } |
516 | |
517 | TEST_F(TestClientCursorAPI, cursor_changed_when_crossing_surface_boundaries) |
518 | { |
519 | using namespace ::testing; |
520 | |
521 | - server_configuration.client_geometries[client_name_1] = geom::Rectangle{geom::Point{geom::X{1}, geom::Y{0}}, |
522 | - geom::Size{geom::Width{1}, geom::Height{1}}}; |
523 | - server_configuration.client_geometries[client_name_2] = geom::Rectangle{geom::Point{geom::X{2}, geom::Y{0}}, |
524 | - geom::Size{geom::Width{1}, geom::Height{1}}}; |
525 | - set_client_count(2); |
526 | - |
527 | - server_configuration.expect_cursor_states = |
528 | - [this](MockCursor& cursor, mt::WaitCondition& expectations_satisfied) |
529 | - { |
530 | - InSequence seq; |
531 | - EXPECT_CALL(cursor, show(CursorNamed(client_cursor_1))).Times(1); |
532 | - EXPECT_CALL(cursor, show(CursorNamed(client_cursor_2))).Times(1) |
533 | - .WillOnce(mt::WakeUp(&expectations_satisfied)); |
534 | - }; |
535 | - server_configuration.synthesize_cursor_motion = |
536 | - [](ServerConfiguration *server) |
537 | - { |
538 | - server->fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1, 0)); |
539 | - server->fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1, 0)); |
540 | - }; |
541 | - start_server(); |
542 | - |
543 | - client_config_1.set_cursor = |
544 | - [this](MirSurface *surface) |
545 | - { |
546 | - auto conf = mir_cursor_configuration_from_name(client_cursor_1.c_str()); |
547 | - mir_wait_for(mir_surface_configure_cursor(surface, conf)); |
548 | - mir_cursor_configuration_destroy(conf); |
549 | - }; |
550 | - start_client(client_config_1); |
551 | - |
552 | - client_config_2.set_cursor = |
553 | - [this](MirSurface *surface) |
554 | - { |
555 | - auto conf = mir_cursor_configuration_from_name(client_cursor_2.c_str()); |
556 | - mir_wait_for(mir_surface_configure_cursor(surface, conf)); |
557 | - mir_cursor_configuration_destroy(conf); |
558 | - }; |
559 | - start_client(client_config_2); |
560 | + test_server_config().client_geometries[client_name_1] = |
561 | + geom::Rectangle{{1, 0}, {1, 1}}; |
562 | + test_server_config().client_geometries[client_name_2] = |
563 | + geom::Rectangle{{2, 0}, {1, 1}}; |
564 | + |
565 | + NamedCursorClient client_1{new_connection(), client_name_1, client_cursor_1}; |
566 | + NamedCursorClient client_2{new_connection(), client_name_2, client_cursor_2}; |
567 | + client_1.run(); |
568 | + client_2.run(); |
569 | + |
570 | + InSequence seq; |
571 | + EXPECT_CALL(test_server_config().cursor, show(CursorNamed(client_cursor_1))); |
572 | + EXPECT_CALL(test_server_config().cursor, show(CursorNamed(client_cursor_2))) |
573 | + .WillOnce(mt::WakeUp(&expectations_satisfied)); |
574 | + |
575 | + fake_event_hub()->synthesize_event(mis::a_motion_event().with_movement(1, 0)); |
576 | + fake_event_hub()->synthesize_event(mis::a_motion_event().with_movement(1, 0)); |
577 | + |
578 | + expectations_satisfied.wait_for_at_most_seconds(5); |
579 | + |
580 | + client_shutdown_expectations(); |
581 | } |
582 | |
583 | TEST_F(TestClientCursorAPI, cursor_request_taken_from_top_surface) |
584 | { |
585 | using namespace ::testing; |
586 | |
587 | - server_configuration.client_geometries[client_name_1] = geom::Rectangle{geom::Point{geom::X{1}, geom::Y{0}}, |
588 | - geom::Size{geom::Width{1}, geom::Height{1}}}; |
589 | - server_configuration.client_geometries[client_name_2] = geom::Rectangle{geom::Point{geom::X{1}, geom::Y{0}}, |
590 | - geom::Size{geom::Width{1}, geom::Height{1}}}; |
591 | - server_configuration.client_depths[client_name_1] = ms::DepthId{0}; |
592 | - server_configuration.client_depths[client_name_2] = ms::DepthId{1}; |
593 | - |
594 | - set_client_count(2); |
595 | - |
596 | - server_configuration.expect_cursor_states = |
597 | - [this](MockCursor& cursor, mt::WaitCondition& expectations_satisfied) |
598 | - { |
599 | - InSequence seq; |
600 | - EXPECT_CALL(cursor, show(CursorNamed(client_cursor_2))).Times(1) |
601 | - .WillOnce(mt::WakeUp(&expectations_satisfied)); |
602 | - }; |
603 | - server_configuration.synthesize_cursor_motion = |
604 | - [](ServerConfiguration *server) |
605 | - { |
606 | - server->fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1, 0)); |
607 | - }; |
608 | - start_server(); |
609 | - |
610 | - |
611 | - client_config_1.set_cursor = |
612 | - [this](MirSurface *surface) |
613 | - { |
614 | - auto conf = mir_cursor_configuration_from_name(client_cursor_1.c_str()); |
615 | - mir_wait_for(mir_surface_configure_cursor(surface, conf)); |
616 | - mir_cursor_configuration_destroy(conf); |
617 | - }; |
618 | - client_config_2.set_cursor = |
619 | - [this](MirSurface *surface) |
620 | - { |
621 | - auto conf = mir_cursor_configuration_from_name(client_cursor_2.c_str()); |
622 | - mir_wait_for(mir_surface_configure_cursor(surface, conf)); |
623 | - mir_cursor_configuration_destroy(conf); |
624 | - }; |
625 | - start_client(client_config_1); |
626 | - start_client(client_config_2); |
627 | -} |
628 | - |
629 | -namespace |
630 | -{ |
631 | - |
632 | -// In the following test the cursor changes are not responsive |
633 | -// to cursor motion so we need a different synchronization model. |
634 | -struct WaitsToChangeCursorClient : ClientConfig |
635 | -{ |
636 | - WaitsToChangeCursorClient(std::string const& client_name, |
637 | - mt::Barrier& cursor_ready_fence, |
638 | - mt::Barrier& client_may_exit_fence) |
639 | - : ClientConfig(client_name, cursor_ready_fence, client_may_exit_fence) |
640 | - { |
641 | - } |
642 | - |
643 | - void thread_exec() override |
644 | - { |
645 | - auto connection = mir_connect_sync(connect_string.c_str(), |
646 | - client_name.c_str()); |
647 | - |
648 | - ASSERT_TRUE(connection != NULL); |
649 | - MirSurfaceParameters const request_params = |
650 | - { |
651 | - client_name.c_str(), |
652 | - // For this fixture, we force geometry on server side |
653 | - 0, 0, |
654 | - mir_pixel_format_abgr_8888, |
655 | - mir_buffer_usage_hardware, |
656 | - mir_display_output_id_invalid |
657 | - }; |
658 | - auto surface = mir_connection_create_surface_sync(connection, &request_params); |
659 | - |
660 | - set_cursor_complete.ready(); |
661 | - set_cursor(surface); |
662 | - |
663 | - client_may_exit.ready(); |
664 | - |
665 | - mir_surface_release_sync(surface); |
666 | - mir_connection_release(connection); |
667 | - } |
668 | -}; |
669 | - |
670 | -struct TestClientCursorAPINoMotion : TestClientCursorAPI |
671 | -{ |
672 | - mt::Barrier client_may_change_cursor{2}; |
673 | - WaitsToChangeCursorClient waiting_client{client_name_1, cursor_configured_fence, client_may_exit_fence}; |
674 | - |
675 | - void TearDown() override |
676 | - { |
677 | - waiting_client.tear_down(); |
678 | - TestClientCursorAPI::TearDown(); |
679 | - } |
680 | -}; |
681 | - |
682 | -} |
683 | - |
684 | -TEST_F(TestClientCursorAPINoMotion, cursor_request_applied_without_cursor_motion) |
685 | + test_server_config().client_geometries[client_name_1] = |
686 | + geom::Rectangle{{1, 0}, {1, 1}}; |
687 | + test_server_config().client_geometries[client_name_2] = |
688 | + geom::Rectangle{{1, 0}, {1, 1}}; |
689 | + |
690 | + NamedCursorClient client_1{new_connection(), client_name_1, client_cursor_1}; |
691 | + NamedCursorClient client_2{new_connection(), client_name_2, client_cursor_2}; |
692 | + client_1.run(); |
693 | + client_2.run(); |
694 | + |
695 | + EXPECT_CALL(test_server_config().cursor, show(CursorNamed(client_cursor_2))) |
696 | + .WillOnce(mt::WakeUp(&expectations_satisfied)); |
697 | + |
698 | + fake_event_hub()->synthesize_event(mis::a_motion_event().with_movement(1, 0)); |
699 | + |
700 | + expectations_satisfied.wait_for_at_most_seconds(5); |
701 | + |
702 | + client_shutdown_expectations(); |
703 | +} |
704 | + |
705 | +TEST_F(TestClientCursorAPI, cursor_request_applied_without_cursor_motion) |
706 | { |
707 | using namespace ::testing; |
708 | |
709 | - server_configuration.client_geometries[client_name_1] = |
710 | - geom::Rectangle{geom::Point{geom::X{0}, geom::Y{0}}, |
711 | - geom::Size{geom::Width{1}, geom::Height{1}}}; |
712 | - |
713 | - server_configuration.expect_cursor_states = |
714 | - [this](MockCursor& cursor, mt::WaitCondition& expectations_satisfied) |
715 | - { |
716 | - InSequence seq; |
717 | - EXPECT_CALL(cursor, show(CursorNamed(client_cursor_1))).Times(1); |
718 | - EXPECT_CALL(cursor, hide()).Times(1) |
719 | - .WillOnce(mt::WakeUp(&expectations_satisfied)); |
720 | - }; |
721 | - server_configuration.synthesize_cursor_motion = |
722 | - [this](ServerConfiguration * /* server */) |
723 | - { |
724 | - client_may_change_cursor.ready(); |
725 | - }; |
726 | - start_server(); |
727 | + struct ChangingCursorClient : NamedCursorClient |
728 | + { |
729 | + using NamedCursorClient::NamedCursorClient; |
730 | |
731 | - waiting_client.set_cursor = |
732 | - [this](MirSurface *surface) |
733 | + void setup_cursor(MirSurface* surface) override |
734 | { |
735 | - client_may_change_cursor.ready(); |
736 | - auto conf1 = mir_cursor_configuration_from_name(client_cursor_1.c_str()); |
737 | + auto conf1 = mir_cursor_configuration_from_name(cursor_name.c_str()); |
738 | auto conf2 = mir_cursor_configuration_from_name(mir_disabled_cursor_name); |
739 | |
740 | mir_wait_for(mir_surface_configure_cursor(surface, conf1)); |
741 | @@ -516,7 +384,22 @@ |
742 | |
743 | mir_cursor_configuration_destroy(conf1); |
744 | mir_cursor_configuration_destroy(conf2); |
745 | - }; |
746 | - start_client(waiting_client); |
747 | + } |
748 | + }; |
749 | + |
750 | + test_server_config().client_geometries[client_name_1] = |
751 | + geom::Rectangle{{0, 0}, {1, 1}}; |
752 | + |
753 | + ChangingCursorClient client{new_connection(), client_name_1, client_cursor_1}; |
754 | + |
755 | + InSequence seq; |
756 | + EXPECT_CALL(test_server_config().cursor, show(CursorNamed(client_cursor_1))); |
757 | + EXPECT_CALL(test_server_config().cursor, hide()) |
758 | + .WillOnce(mt::WakeUp(&expectations_satisfied)); |
759 | + |
760 | + client.run(); |
761 | + |
762 | + expectations_satisfied.wait_for_at_most_seconds(5); |
763 | + |
764 | + client_shutdown_expectations(); |
765 | } |
766 | - |
FAILED: Continuous integration, rev:1889 jenkins. qa.ubuntu. com/job/ mir-team- mir-development -branch- ci/2612/ jenkins. qa.ubuntu. com/job/ mir-android- utopic- i386-build/ 1605 jenkins. qa.ubuntu. com/job/ mir-clang- utopic- amd64-build/ 1611 jenkins. qa.ubuntu. com/job/ mir-mediumtests -utopic- touch/1587 jenkins. qa.ubuntu. com/job/ mir-team- mir-development -branch- utopic- amd64-ci/ 1134/console jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- utopic- armhf/524 jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- utopic- armhf/524/ artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ mir-mediumtests -runner- mako/2651 s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 12628
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/mir- team-mir- development- branch- ci/2612/ rebuild
http://