tests: add test_seat_release() for symmetry
[platform/upstream/weston.git] / tests / devices-test.c
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
31 /**
32  * Test (un)plugging devices
33  *
34  * At the end of each test we must return Weston to the previous state
35  * (add all removed devices and remove extra devices), so that
36  * the environment is prepared for the other tests too
37  */
38
39 #define WL_SEAT_CAPABILITY_ALL (WL_SEAT_CAPABILITY_KEYBOARD |\
40                                 WL_SEAT_CAPABILITY_POINTER  |\
41                                 WL_SEAT_CAPABILITY_TOUCH)
42
43 char *server_parameters = "--shell=weston-test-desktop-shell.so";
44
45 /* simply test if weston sends the right capabilities when
46  * some devices are removed */
47 TEST(seat_capabilities_test)
48 {
49         struct client *cl = create_client_and_test_surface(100, 100, 100, 100);
50         assert(cl->input->caps == WL_SEAT_CAPABILITY_ALL);
51
52         assert(cl->input->pointer);
53         weston_test_device_release(cl->test->weston_test, "pointer");
54         client_roundtrip(cl);
55         assert(!cl->input->pointer);
56         assert(!(cl->input->caps & WL_SEAT_CAPABILITY_POINTER));
57
58         assert(cl->input->keyboard);
59         weston_test_device_release(cl->test->weston_test, "keyboard");
60         client_roundtrip(cl);
61         assert(!cl->input->keyboard);
62         assert(!(cl->input->caps & WL_SEAT_CAPABILITY_KEYBOARD));
63
64         assert(cl->input->touch);
65         weston_test_device_release(cl->test->weston_test, "touch");
66         client_roundtrip(cl);
67         assert(!cl->input->touch);
68         assert(!(cl->input->caps & WL_SEAT_CAPABILITY_TOUCH));
69
70         /* restore previous state */
71         weston_test_device_add(cl->test->weston_test, "keyboard");
72         weston_test_device_add(cl->test->weston_test, "pointer");
73         weston_test_device_add(cl->test->weston_test, "touch");
74         client_roundtrip(cl);
75
76         assert(cl->input->pointer);
77         assert(cl->input->keyboard);
78         assert(cl->input->touch);
79
80         /* add extra devices */
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         /* remove extra devices */
87         weston_test_device_release(cl->test->weston_test, "keyboard");
88         weston_test_device_release(cl->test->weston_test, "pointer");
89         weston_test_device_release(cl->test->weston_test, "touch");
90         client_roundtrip(cl);
91
92         /* we still should have all the capabilities, since the devices
93          * were doubled */
94         assert(cl->input->caps == WL_SEAT_CAPABILITY_ALL);
95
96         assert(cl->input->pointer);
97         assert(cl->input->keyboard);
98         assert(cl->input->touch);
99 }
100
101 #define COUNT 15
102 TEST(multiple_device_add_and_remove)
103 {
104         int i;
105         struct client *cl = create_client_and_test_surface(100, 100, 100, 100);
106
107         /* add device a lot of times */
108         for (i = 0; i < COUNT; ++i) {
109                 weston_test_device_add(cl->test->weston_test, "keyboard");
110                 weston_test_device_add(cl->test->weston_test, "pointer");
111                 weston_test_device_add(cl->test->weston_test, "touch");
112         }
113
114         client_roundtrip(cl);
115
116         assert(cl->input->pointer);
117         assert(cl->input->keyboard);
118         assert(cl->input->touch);
119
120         assert(cl->input->caps == WL_SEAT_CAPABILITY_ALL);
121
122         /* release all new devices */
123         for (i = 0; i < COUNT; ++i) {
124                 weston_test_device_release(cl->test->weston_test, "keyboard");
125                 weston_test_device_release(cl->test->weston_test, "pointer");
126                 weston_test_device_release(cl->test->weston_test, "touch");
127         }
128
129         client_roundtrip(cl);
130
131         /* there is still one from each device left */
132         assert(cl->input->caps == WL_SEAT_CAPABILITY_ALL);
133
134         assert(cl->input->pointer);
135         assert(cl->input->keyboard);
136         assert(cl->input->touch);
137 }
138
139 TEST(device_release_before_destroy)
140 {
141         struct client *cl = create_client_and_test_surface(100, 100, 100, 100);
142
143         /* we can release pointer when we won't be using it anymore.
144          * Do it and see what happens if the device is destroyed
145          * right after that */
146         wl_pointer_release(cl->input->pointer->wl_pointer);
147         /* we must free and set to NULL the structures, otherwise
148          * seat capabilities will double-free them */
149         free(cl->input->pointer);
150         cl->input->pointer = NULL;
151
152         wl_keyboard_release(cl->input->keyboard->wl_keyboard);
153         free(cl->input->keyboard);
154         cl->input->keyboard = NULL;
155
156         wl_touch_release(cl->input->touch->wl_touch);
157         free(cl->input->touch);
158         cl->input->touch = NULL;
159
160         weston_test_device_release(cl->test->weston_test, "pointer");
161         weston_test_device_release(cl->test->weston_test, "keyboard");
162         weston_test_device_release(cl->test->weston_test, "touch");
163         client_roundtrip(cl);
164
165         assert(cl->input->caps == 0);
166
167         /* restore previous state */
168         weston_test_device_add(cl->test->weston_test, "pointer");
169         weston_test_device_add(cl->test->weston_test, "keyboard");
170         weston_test_device_add(cl->test->weston_test, "touch");
171         client_roundtrip(cl);
172
173         assert(cl->input->caps == WL_SEAT_CAPABILITY_ALL);
174 }
175
176 TEST(device_release_before_destroy_multiple)
177 {
178         int i;
179
180         /* if weston crashed during this test, then there is
181          * some inconsistency */
182         for (i = 0; i < 30; ++i) {
183                 /* Fifty times run the previous test. This will create
184                  * fifty clients, because we don't have any
185                  * way how to destroy them (worth of adding!). Only one
186                  * client will run at a time though and so should have no
187                  * effect on the result of the test (after the client
188                  * finishes its body, it just 'is' and does nothing). */
189                 device_release_before_destroy();
190         }
191 }
192
193 /* normal work-flow test */
194 TEST(device_release_after_destroy)
195 {
196         struct client *cl = create_client_and_test_surface(100, 100, 100, 100);
197
198         weston_test_device_release(cl->test->weston_test, "pointer");
199         wl_pointer_release(cl->input->pointer->wl_pointer);
200         /* we must free the memory manually, otherwise seat.capabilities
201          * will try to free it and will use invalid proxy */
202         free(cl->input->pointer);
203         cl->input->pointer = NULL;
204
205         client_roundtrip(cl);
206
207         weston_test_device_release(cl->test->weston_test, "keyboard");
208         wl_keyboard_release(cl->input->keyboard->wl_keyboard);
209         free(cl->input->keyboard);
210         cl->input->keyboard = NULL;
211
212         client_roundtrip(cl);
213
214         weston_test_device_release(cl->test->weston_test, "touch");
215         wl_touch_release(cl->input->touch->wl_touch);
216         free(cl->input->touch);
217         cl->input->touch = NULL;
218
219         client_roundtrip(cl);
220
221         assert(cl->input->caps == 0);
222
223         /* restore previous state */
224         weston_test_device_add(cl->test->weston_test, "pointer");
225         weston_test_device_add(cl->test->weston_test, "keyboard");
226         weston_test_device_add(cl->test->weston_test, "touch");
227         client_roundtrip(cl);
228
229         assert(cl->input->caps == WL_SEAT_CAPABILITY_ALL);
230 }
231
232 TEST(device_release_after_destroy_multiple)
233 {
234         int i;
235
236         /* if weston crashed during this test, then there is
237          * some inconsistency */
238         for (i = 0; i < 30; ++i) {
239                 device_release_after_destroy();
240         }
241 }
242
243 /* see https://bugzilla.gnome.org/show_bug.cgi?id=745008
244  * It is a mutter bug, but highly relevant. Weston does not
245  * suffer from this bug atm, but it is worth of testing. */
246 TEST(get_device_after_destroy)
247 {
248         struct client *cl = create_client_and_test_surface(100, 100, 100, 100);
249         struct wl_pointer *wl_pointer;
250         struct wl_keyboard *wl_keyboard;
251         struct wl_touch *wl_touch;
252
253         /* There's a race:
254          *  1) compositor destroys device
255          *  2) client asks for the device, because it has not received
256          *     the new capabilities yet
257          *  3) compositor gets the request with a new_id for the
258          *     destroyed device
259          *  4) client uses the new_id
260          *  5) client gets new capabilities, destroying the objects
261          *
262          * If the compositor just bails out in step 3) and does not
263          * create the resource, then the client gets an error in step 4)
264          * - even though it followed the protocol (it just didn't know
265          * about new capabilities).
266          *
267          * This test simulates this situation
268          */
269
270         /* connection is buffered, so after calling client_roundtrip(),
271          * this whole batch will be delivered to compositor and will
272          * exactly simulate our situation */
273         weston_test_device_release(cl->test->weston_test, "pointer");
274         wl_pointer = wl_seat_get_pointer(cl->input->wl_seat);
275         assert(wl_pointer);
276
277         /* this should be ignored */
278         wl_pointer_set_cursor(wl_pointer, 0, NULL, 0, 0);
279
280         /* this should not be ignored */
281         wl_pointer_release(wl_pointer);
282         client_roundtrip(cl);
283
284         weston_test_device_release(cl->test->weston_test, "keyboard");
285         wl_keyboard = wl_seat_get_keyboard(cl->input->wl_seat);
286         assert(wl_keyboard);
287         wl_keyboard_release(wl_keyboard);
288         client_roundtrip(cl);
289
290         weston_test_device_release(cl->test->weston_test, "touch");
291         wl_touch = wl_seat_get_touch(cl->input->wl_seat);
292         assert(wl_touch);
293         wl_touch_release(wl_touch);
294         client_roundtrip(cl);
295
296         /* get weston to the previous state */
297         weston_test_device_add(cl->test->weston_test, "pointer");
298         weston_test_device_add(cl->test->weston_test, "keyboard");
299         weston_test_device_add(cl->test->weston_test, "touch");
300         client_roundtrip(cl);
301
302         assert(cl->input->caps == WL_SEAT_CAPABILITY_ALL);
303 }
304
305 TEST(get_device_after_destroy_multiple)
306 {
307         int i;
308
309         /* if weston crashed during this test, then there is
310          * some inconsistency */
311         for (i = 0; i < 30; ++i) {
312                 get_device_after_destroy();
313         }
314 }
315
316 TEST(seats_have_names)
317 {
318         struct client *cl = create_client_and_test_surface(100, 100, 100, 100);
319         struct input *input;
320
321         wl_list_for_each(input, &cl->inputs, link) {
322                 assert(input->seat_name);
323         }
324 }
325
326 TEST(seat_destroy_and_recreate)
327 {
328         struct client *cl = create_client_and_test_surface(100, 100, 100, 100);
329
330         weston_test_device_release(cl->test->weston_test, "seat");
331         /* Roundtrip to receive and handle the seat global removal event */
332         client_roundtrip(cl);
333
334         assert(!cl->input);
335
336         weston_test_device_add(cl->test->weston_test, "seat");
337         /* First roundtrip to send request and receive new seat global */
338         client_roundtrip(cl);
339         /* Second roundtrip to handle seat events and set up input devices */
340         client_roundtrip(cl);
341
342         assert(cl->input);
343         assert(cl->input->pointer);
344         assert(cl->input->keyboard);
345         assert(cl->input->touch);
346 }