1 /*
2 * Copyright © 2015 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26 #include "config.h"
27
28 #include <string.h>
29 #include "weston-test-client-helper.h"
30 #include "weston-test-fixture-compositor.h"
31
32 static enum test_result_code
fixture_setup(struct weston_test_harness * harness)33 fixture_setup(struct weston_test_harness *harness)
34 {
35 struct compositor_setup setup;
36
37 compositor_setup_defaults(&setup);
38
39 return weston_test_harness_execute_as_client(harness, &setup);
40 }
41 DECLARE_FIXTURE_SETUP(fixture_setup);
42
43 /**
44 * Test (un)plugging devices
45 *
46 * At the end of each test we must return Weston to the previous state
47 * (add all removed devices and remove extra devices), so that
48 * the environment is prepared for the other tests too
49 */
50
51 #define WL_SEAT_CAPABILITY_ALL (WL_SEAT_CAPABILITY_KEYBOARD |\
52 WL_SEAT_CAPABILITY_POINTER |\
53 WL_SEAT_CAPABILITY_TOUCH)
54
55 /* simply test if weston sends the right capabilities when
56 * some devices are removed */
TEST(seat_capabilities_test)57 TEST(seat_capabilities_test)
58 {
59 struct client *cl = create_client_and_test_surface(100, 100, 100, 100);
60 assert(cl->input->caps == WL_SEAT_CAPABILITY_ALL);
61
62 assert(cl->input->pointer);
63 weston_test_device_release(cl->test->weston_test, "pointer");
64 client_roundtrip(cl);
65 assert(!cl->input->pointer);
66 assert(!(cl->input->caps & WL_SEAT_CAPABILITY_POINTER));
67
68 assert(cl->input->keyboard);
69 weston_test_device_release(cl->test->weston_test, "keyboard");
70 client_roundtrip(cl);
71 assert(!cl->input->keyboard);
72 assert(!(cl->input->caps & WL_SEAT_CAPABILITY_KEYBOARD));
73
74 assert(cl->input->touch);
75 weston_test_device_release(cl->test->weston_test, "touch");
76 client_roundtrip(cl);
77 assert(!cl->input->touch);
78 assert(!(cl->input->caps & WL_SEAT_CAPABILITY_TOUCH));
79
80 /* restore previous state */
81 weston_test_device_add(cl->test->weston_test, "keyboard");
82 weston_test_device_add(cl->test->weston_test, "pointer");
83 weston_test_device_add(cl->test->weston_test, "touch");
84 client_roundtrip(cl);
85
86 assert(cl->input->pointer);
87 assert(cl->input->keyboard);
88 assert(cl->input->touch);
89
90 /* add extra devices */
91 weston_test_device_add(cl->test->weston_test, "keyboard");
92 weston_test_device_add(cl->test->weston_test, "pointer");
93 weston_test_device_add(cl->test->weston_test, "touch");
94 client_roundtrip(cl);
95
96 /* remove extra devices */
97 weston_test_device_release(cl->test->weston_test, "keyboard");
98 weston_test_device_release(cl->test->weston_test, "pointer");
99 weston_test_device_release(cl->test->weston_test, "touch");
100 client_roundtrip(cl);
101
102 /* we still should have all the capabilities, since the devices
103 * were doubled */
104 assert(cl->input->caps == WL_SEAT_CAPABILITY_ALL);
105
106 assert(cl->input->pointer);
107 assert(cl->input->keyboard);
108 assert(cl->input->touch);
109 }
110
111 #define COUNT 15
TEST(multiple_device_add_and_remove)112 TEST(multiple_device_add_and_remove)
113 {
114 int i;
115 struct client *cl = create_client_and_test_surface(100, 100, 100, 100);
116
117 /* add device a lot of times */
118 for (i = 0; i < COUNT; ++i) {
119 weston_test_device_add(cl->test->weston_test, "keyboard");
120 weston_test_device_add(cl->test->weston_test, "pointer");
121 weston_test_device_add(cl->test->weston_test, "touch");
122 }
123
124 client_roundtrip(cl);
125
126 assert(cl->input->pointer);
127 assert(cl->input->keyboard);
128 assert(cl->input->touch);
129
130 assert(cl->input->caps == WL_SEAT_CAPABILITY_ALL);
131
132 /* release all new devices */
133 for (i = 0; i < COUNT; ++i) {
134 weston_test_device_release(cl->test->weston_test, "keyboard");
135 weston_test_device_release(cl->test->weston_test, "pointer");
136 weston_test_device_release(cl->test->weston_test, "touch");
137 }
138
139 client_roundtrip(cl);
140
141 /* there is still one from each device left */
142 assert(cl->input->caps == WL_SEAT_CAPABILITY_ALL);
143
144 assert(cl->input->pointer);
145 assert(cl->input->keyboard);
146 assert(cl->input->touch);
147 }
148
TEST(device_release_before_destroy)149 TEST(device_release_before_destroy)
150 {
151 struct client *cl = create_client_and_test_surface(100, 100, 100, 100);
152
153 /* we can release pointer when we won't be using it anymore.
154 * Do it and see what happens if the device is destroyed
155 * right after that */
156 wl_pointer_release(cl->input->pointer->wl_pointer);
157 /* we must free and set to NULL the structures, otherwise
158 * seat capabilities will double-free them */
159 free(cl->input->pointer);
160 cl->input->pointer = NULL;
161
162 wl_keyboard_release(cl->input->keyboard->wl_keyboard);
163 free(cl->input->keyboard);
164 cl->input->keyboard = NULL;
165
166 wl_touch_release(cl->input->touch->wl_touch);
167 free(cl->input->touch);
168 cl->input->touch = NULL;
169
170 weston_test_device_release(cl->test->weston_test, "pointer");
171 weston_test_device_release(cl->test->weston_test, "keyboard");
172 weston_test_device_release(cl->test->weston_test, "touch");
173 client_roundtrip(cl);
174
175 assert(cl->input->caps == 0);
176
177 /* restore previous state */
178 weston_test_device_add(cl->test->weston_test, "pointer");
179 weston_test_device_add(cl->test->weston_test, "keyboard");
180 weston_test_device_add(cl->test->weston_test, "touch");
181 client_roundtrip(cl);
182
183 assert(cl->input->caps == WL_SEAT_CAPABILITY_ALL);
184 }
185
TEST(device_release_before_destroy_multiple)186 TEST(device_release_before_destroy_multiple)
187 {
188 int i;
189
190 /* if weston crashed during this test, then there is
191 * some inconsistency */
192 for (i = 0; i < 30; ++i) {
193 /* Fifty times run the previous test. This will create
194 * fifty clients, because we don't have any
195 * way how to destroy them (worth of adding!). Only one
196 * client will run at a time though and so should have no
197 * effect on the result of the test (after the client
198 * finishes its body, it just 'is' and does nothing). */
199 device_release_before_destroy();
200 }
201 }
202
203 /* normal work-flow test */
TEST(device_release_after_destroy)204 TEST(device_release_after_destroy)
205 {
206 struct client *cl = create_client_and_test_surface(100, 100, 100, 100);
207
208 weston_test_device_release(cl->test->weston_test, "pointer");
209 wl_pointer_release(cl->input->pointer->wl_pointer);
210 /* we must free the memory manually, otherwise seat.capabilities
211 * will try to free it and will use invalid proxy */
212 free(cl->input->pointer);
213 cl->input->pointer = NULL;
214
215 client_roundtrip(cl);
216
217 weston_test_device_release(cl->test->weston_test, "keyboard");
218 wl_keyboard_release(cl->input->keyboard->wl_keyboard);
219 free(cl->input->keyboard);
220 cl->input->keyboard = NULL;
221
222 client_roundtrip(cl);
223
224 weston_test_device_release(cl->test->weston_test, "touch");
225 wl_touch_release(cl->input->touch->wl_touch);
226 free(cl->input->touch);
227 cl->input->touch = NULL;
228
229 client_roundtrip(cl);
230
231 assert(cl->input->caps == 0);
232
233 /* restore previous state */
234 weston_test_device_add(cl->test->weston_test, "pointer");
235 weston_test_device_add(cl->test->weston_test, "keyboard");
236 weston_test_device_add(cl->test->weston_test, "touch");
237 client_roundtrip(cl);
238
239 assert(cl->input->caps == WL_SEAT_CAPABILITY_ALL);
240 }
241
TEST(device_release_after_destroy_multiple)242 TEST(device_release_after_destroy_multiple)
243 {
244 int i;
245
246 /* if weston crashed during this test, then there is
247 * some inconsistency */
248 for (i = 0; i < 30; ++i) {
249 device_release_after_destroy();
250 }
251 }
252
253 /* see https://bugzilla.gnome.org/show_bug.cgi?id=745008
254 * It is a mutter bug, but highly relevant. Weston does not
255 * suffer from this bug atm, but it is worth of testing. */
TEST(get_device_after_destroy)256 TEST(get_device_after_destroy)
257 {
258 struct client *cl = create_client_and_test_surface(100, 100, 100, 100);
259 struct wl_pointer *wl_pointer;
260 struct wl_keyboard *wl_keyboard;
261 struct wl_touch *wl_touch;
262
263 /* There's a race:
264 * 1) compositor destroys device
265 * 2) client asks for the device, because it has not received
266 * the new capabilities yet
267 * 3) compositor gets the request with a new_id for the
268 * destroyed device
269 * 4) client uses the new_id
270 * 5) client gets new capabilities, destroying the objects
271 *
272 * If the compositor just bails out in step 3) and does not
273 * create the resource, then the client gets an error in step 4)
274 * - even though it followed the protocol (it just didn't know
275 * about new capabilities).
276 *
277 * This test simulates this situation
278 */
279
280 /* connection is buffered, so after calling client_roundtrip(),
281 * this whole batch will be delivered to compositor and will
282 * exactly simulate our situation */
283 weston_test_device_release(cl->test->weston_test, "pointer");
284 wl_pointer = wl_seat_get_pointer(cl->input->wl_seat);
285 assert(wl_pointer);
286
287 /* this should be ignored */
288 wl_pointer_set_cursor(wl_pointer, 0, NULL, 0, 0);
289
290 /* this should not be ignored */
291 wl_pointer_release(wl_pointer);
292 client_roundtrip(cl);
293
294 weston_test_device_release(cl->test->weston_test, "keyboard");
295 wl_keyboard = wl_seat_get_keyboard(cl->input->wl_seat);
296 assert(wl_keyboard);
297 wl_keyboard_release(wl_keyboard);
298 client_roundtrip(cl);
299
300 weston_test_device_release(cl->test->weston_test, "touch");
301 wl_touch = wl_seat_get_touch(cl->input->wl_seat);
302 assert(wl_touch);
303 wl_touch_release(wl_touch);
304 client_roundtrip(cl);
305
306 /* get weston to the previous state */
307 weston_test_device_add(cl->test->weston_test, "pointer");
308 weston_test_device_add(cl->test->weston_test, "keyboard");
309 weston_test_device_add(cl->test->weston_test, "touch");
310 client_roundtrip(cl);
311
312 assert(cl->input->caps == WL_SEAT_CAPABILITY_ALL);
313 }
314
TEST(get_device_after_destroy_multiple)315 TEST(get_device_after_destroy_multiple)
316 {
317 int i;
318
319 /* if weston crashed during this test, then there is
320 * some inconsistency */
321 for (i = 0; i < 30; ++i) {
322 get_device_after_destroy();
323 }
324 }
325
TEST(seats_have_names)326 TEST(seats_have_names)
327 {
328 struct client *cl = create_client_and_test_surface(100, 100, 100, 100);
329 struct input *input;
330
331 wl_list_for_each(input, &cl->inputs, link) {
332 assert(input->seat_name);
333 }
334 }
335
TEST(seat_destroy_and_recreate)336 TEST(seat_destroy_and_recreate)
337 {
338 struct client *cl = create_client_and_test_surface(100, 100, 100, 100);
339
340 weston_test_device_release(cl->test->weston_test, "seat");
341 /* Roundtrip to receive and handle the seat global removal event */
342 client_roundtrip(cl);
343
344 assert(!cl->input);
345
346 weston_test_device_add(cl->test->weston_test, "seat");
347 /* First roundtrip to send request and receive new seat global */
348 client_roundtrip(cl);
349 /* Second roundtrip to handle seat events and set up input devices */
350 client_roundtrip(cl);
351
352 assert(cl->input);
353 assert(cl->input->pointer);
354 assert(cl->input->keyboard);
355 assert(cl->input->touch);
356 }
357