• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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