tests: implement client_destroy()
authorPekka Paalanen <pekka.paalanen@collabora.com>
Fri, 24 Jan 2020 11:14:27 +0000 (13:14 +0200)
committerPekka Paalanen <pekka.paalanen@collabora.com>
Thu, 27 Feb 2020 14:08:42 +0000 (16:08 +0200)
It turns out that if the client is not explicitly destroyed, it will remain
connected until the compositor shuts down because there is no more a client
process that would terminate.

Usually this is not a problem, but if a test file has multiple screenshooting
tests, the windows from earlier tests in the file will remain on screen. That
is not wanted, hence implement client destruction.

To properly destroy a client, we also need a list of outputs. They used to be
simply leaked. This does not fix wl_registry.global_remove for wl_outputs, that
is left for a time when a test will actually need that.

This patch makes only ivi-shell-app test use the new client_destroy() to show
that it actually works. The added log scopes prove it: destroy requests get
sent. Sprinkling client_destroy() around in all other tests is left for a time
when it is actually necessary.

ivi-shell-app is a nicely simple test doing little else, hence I picked it.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
tests/ivi-shell-app-test.c
tests/weston-test-client-helper.c
tests/weston-test-client-helper.h

index b2550e945090b4dfc0dbd68adec6d605647dd8b1..5652c0de7cf1ab0f0e5c38e5d4398e43ddfa5592 100644 (file)
@@ -41,6 +41,7 @@ fixture_setup(struct weston_test_harness *harness)
        compositor_setup_defaults(&setup);
        setup.shell = SHELL_IVI;
        setup.config_file = TESTSUITE_IVI_CONFIG_PATH;
+       setup.logging_scopes = "log,test-harness-plugin,proto";
 
        return weston_test_harness_execute_as_client(harness, &setup);
 }
@@ -84,4 +85,6 @@ TEST(ivi_application_exists)
        client_roundtrip(client);
 
        testlog("Successful bind: %p\n", iviapp);
+
+       client_destroy(client);
 }
index 5f76914a9a013a34c3efe43bdd014c876d71bfd4..be9c8bce1df5c7c5f8e521310c33dd07dc0f995e 100644 (file)
@@ -724,6 +724,15 @@ static const struct wl_output_listener output_listener = {
        output_handle_scale,
 };
 
+static void
+output_destroy(struct output *output)
+{
+       assert(wl_proxy_get_version((struct wl_proxy *)output->wl_output) >= 3);
+       wl_output_release(output->wl_output);
+       wl_list_remove(&output->link);
+       free(output);
+}
+
 static void
 handle_global(void *data, struct wl_registry *registry,
              uint32_t id, const char *interface, uint32_t version)
@@ -741,6 +750,13 @@ handle_global(void *data, struct wl_registry *registry,
        global->version = version;
        wl_list_insert(client->global_list.prev, &global->link);
 
+       /* We deliberately bind all globals with the maximum (advertised)
+        * version, because this test suite must be kept up-to-date with
+        * Weston. We must always implement at least the version advertised
+        * by Weston. This is not ok for normal clients, but it is ok in
+        * this test suite.
+        */
+
        if (strcmp(interface, "wl_compositor") == 0) {
                client->wl_compositor =
                        wl_registry_bind(registry, id,
@@ -766,6 +782,7 @@ handle_global(void *data, struct wl_registry *registry,
                                         &wl_output_interface, version);
                wl_output_add_listener(output->wl_output,
                                       &output_listener, output);
+               wl_list_insert(&client->output_list, &output->link);
                client->output = output;
        } else if (strcmp(interface, "weston_test") == 0) {
                test = xzalloc(sizeof *test);
@@ -805,6 +822,14 @@ client_find_input_with_name(struct client *client, uint32_t name)
        return NULL;
 }
 
+static void
+global_destroy(struct global *global)
+{
+       wl_list_remove(&global->link);
+       free(global->interface);
+       free(global);
+}
+
 static void
 handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
 {
@@ -824,9 +849,9 @@ handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
                }
        }
 
-       wl_list_remove(&global->link);
-       free(global->interface);
-       free(global);
+       /* XXX: handle wl_output */
+
+       global_destroy(global);
 }
 
 static const struct wl_registry_listener registry_listener = {
@@ -916,6 +941,7 @@ create_client(void)
        assert(client->wl_display);
        wl_list_init(&client->global_list);
        wl_list_init(&client->inputs);
+       wl_list_init(&client->output_list);
 
        /* setup registry so we can bind to interfaces */
        client->wl_registry = wl_display_get_registry(client->wl_display);
@@ -965,6 +991,16 @@ create_test_surface(struct client *client)
        return surface;
 }
 
+void
+surface_destroy(struct surface *surface)
+{
+       if (surface->wl_surface)
+               wl_surface_destroy(surface->wl_surface);
+       if (surface->buffer)
+               buffer_destroy(surface->buffer);
+       free(surface);
+}
+
 struct client *
 create_client_and_test_surface(int x, int y, int width, int height)
 {
@@ -999,6 +1035,46 @@ create_client_and_test_surface(int x, int y, int width, int height)
        return client;
 }
 
+void
+client_destroy(struct client *client)
+{
+       if (client->surface)
+               surface_destroy(client->surface);
+
+       while (!wl_list_empty(&client->inputs)) {
+               input_destroy(container_of(client->inputs.next,
+                                          struct input, link));
+       }
+
+       while (!wl_list_empty(&client->output_list)) {
+               output_destroy(container_of(client->output_list.next,
+                                           struct output, link));
+       }
+
+       while (!wl_list_empty(&client->global_list)) {
+               global_destroy(container_of(client->global_list.next,
+                                           struct global, link));
+       }
+
+       if (client->test) {
+               weston_test_destroy(client->test->weston_test);
+               free(client->test);
+       }
+
+       if (client->wl_shm)
+               wl_shm_destroy(client->wl_shm);
+       if (client->wl_compositor)
+               wl_compositor_destroy(client->wl_compositor);
+       if (client->wl_registry)
+               wl_registry_destroy(client->wl_registry);
+
+       client_roundtrip(client);
+
+       if (client->wl_display)
+               wl_display_disconnect(client->wl_display);
+       free(client);
+}
+
 static const char*
 output_path(void)
 {
index cbb0512da4f296c3472db4be36084b3bde6c596f..f4ed919f8cc47c44883105fd2e42017295e5b936 100644 (file)
@@ -57,6 +57,7 @@ struct client {
        int has_argb;
        struct wl_list global_list;
        bool has_wl_drm;
+       struct wl_list output_list; /* struct output::link */
 };
 
 struct global {
@@ -145,6 +146,7 @@ struct touch {
 
 struct output {
        struct wl_output *wl_output;
+       struct wl_list link; /* struct client::output_list */
        int x;
        int y;
        int width;
@@ -161,7 +163,7 @@ struct buffer {
 
 struct surface {
        struct wl_surface *wl_surface;
-       struct output *output;
+       struct output *output; /* not owned */
        int x;
        int y;
        int width;
@@ -184,9 +186,15 @@ struct range {
 struct client *
 create_client(void);
 
+void
+client_destroy(struct client *client);
+
 struct surface *
 create_test_surface(struct client *client);
 
+void
+surface_destroy(struct surface *surface);
+
 struct client *
 create_client_and_test_surface(int x, int y, int width, int height);