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