~linaro-graphics-wg/compiz-core/linaro-gles2-debianpatches

« back to all changes in this revision

Viewing changes to tests/integration/xig/src/test-runner.c

  • Committer: smspillaz
  • Author(s): Robert Ancell
  • Date: 2012-01-20 16:29:27 UTC
  • mto: (2753.36.135 compiz-core)
  • mto: This revision was merged to the branch mainline in revision 2905.
  • Revision ID: sam.spilsbury@canonical.com-20120120162927-7ero8ca8nq80zp6k
Added Xig Testing infrastructure to compiz

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <stdlib.h>
 
2
#include <stdio.h>
 
3
#include <string.h>
 
4
#include <ctype.h>
 
5
#include <errno.h>
 
6
#include <glib.h>
 
7
#include <gio/gio.h>
 
8
#include <unistd.h>
 
9
#include <sys/types.h>
 
10
#include <sys/socket.h>
 
11
#include <sys/un.h>
 
12
#include <sys/wait.h>
 
13
#include <config.h>
 
14
 
 
15
#include <xig.h>
 
16
 
 
17
/* For some reason sys/un.h doesn't define this */
 
18
#ifndef UNIX_PATH_MAX
 
19
#define UNIX_PATH_MAX 108
 
20
#endif
 
21
 
 
22
/* Timeout in ms waiting for the status we expect */
 
23
#define STATUS_TIMEOUT 2000
 
24
 
 
25
/* Timeout in ms to wait for SIGTERM to kill compiz */
 
26
#define KILL_TIMEOUT 2000
 
27
 
 
28
static XigServer *xserver;
 
29
static GKeyFile *config;
 
30
static GPid compiz_pid = 0;
 
31
static GList *statuses = NULL;
 
32
static GList *script = NULL;
 
33
static GList *script_iter = NULL;
 
34
static guint status_timeout = 0;
 
35
static gboolean failed = FALSE;
 
36
static guint compiz_kill_timeout = 0;
 
37
 
 
38
static void check_status (const gchar *status);
 
39
 
 
40
static gboolean
 
41
compiz_kill_timeout_cb (gpointer data)
 
42
{
 
43
    if (getenv ("DEBUG"))
 
44
        g_print ("Sending SIGKILL to compiz\n");
 
45
    kill (compiz_pid, SIGKILL);
 
46
    compiz_kill_timeout = 0;
 
47
    return FALSE;
 
48
}
 
49
 
 
50
static void
 
51
stop_compiz ()
 
52
{
 
53
    if (compiz_pid && compiz_kill_timeout == 0)
 
54
    {
 
55
        if (getenv ("DEBUG"))
 
56
            g_print ("Sending SIGTERM to compiz process %d\n", compiz_pid);
 
57
        kill (compiz_pid, SIGINT);
 
58
        compiz_kill_timeout = g_timeout_add (KILL_TIMEOUT, compiz_kill_timeout_cb, NULL);
 
59
    } 
 
60
}
 
61
 
 
62
static void
 
63
restart_compiz ()
 
64
{
 
65
    if (compiz_pid)
 
66
    {
 
67
        if (getenv ("DEBUG"))
 
68
            g_print ("Sending SIGHUP to compiz process %d\n", compiz_pid);
 
69
        kill (compiz_pid, SIGHUP);
 
70
    }
 
71
}
 
72
 
 
73
static void
 
74
quit (int status)
 
75
{
 
76
    if (xserver)
 
77
        xig_server_stop (xserver);
 
78
    if (compiz_pid)
 
79
        kill (compiz_pid, SIGKILL);
 
80
 
 
81
    exit (status);
 
82
}
 
83
 
 
84
static void
 
85
fail (const gchar *event, const gchar *expected)
 
86
{
 
87
    GList *link;
 
88
 
 
89
    if (failed)
 
90
        return;
 
91
    failed = TRUE;
 
92
 
 
93
    g_printerr ("Test failed, got the following events:\n");
 
94
    for (link = statuses; link; link = link->next)
 
95
        g_printerr ("    %s\n", (gchar *)link->data);
 
96
    if (event)
 
97
        g_printerr ("    %s\n", event);
 
98
    if (expected)
 
99
        g_printerr ("    ^^^ expected \"%s\"\n", expected);
 
100
    else
 
101
        g_printerr ("^^^ expected nothing\n");
 
102
 
 
103
    /* Either wait for the compiz to quit, or stop now if it already is */
 
104
    if (compiz_pid)
 
105
        stop_compiz ();
 
106
    else
 
107
        quit (EXIT_FAILURE);
 
108
}
 
109
 
 
110
static gchar *
 
111
get_script_line ()
 
112
{
 
113
    if (!script_iter)
 
114
        return NULL;
 
115
    return script_iter->data;
 
116
}
 
117
 
 
118
static void
 
119
compiz_exit_cb (GPid pid, gint status, gpointer data)
 
120
{
 
121
    gchar *status_text;
 
122
 
 
123
    compiz_pid = 0;
 
124
  
 
125
    if (compiz_kill_timeout)
 
126
        g_source_remove (compiz_kill_timeout);
 
127
    compiz_kill_timeout = 0;
 
128
 
 
129
    /* Quit when compiz does */
 
130
    if (failed)
 
131
        quit (EXIT_FAILURE);
 
132
 
 
133
    if (WIFEXITED (status))
 
134
        status_text = g_strdup_printf ("COMPIZ EXIT STATUS=%d", WEXITSTATUS (status));
 
135
    else
 
136
        status_text = g_strdup_printf ("COMPIZ TERMINATE SIGNAL=%d", WTERMSIG (status));
 
137
    check_status (status_text);
 
138
    g_free (status_text);
 
139
}
 
140
 
 
141
static void
 
142
unmap_notify_cb (XigWindow *window)
 
143
{
 
144
    gchar *status_text;
 
145
 
 
146
    status_text = g_strdup_printf ("UNMAP-NOTIFY ID=%d", xig_window_get_id (window));
 
147
    check_status (status_text);
 
148
    g_free (status_text);
 
149
}
 
150
 
 
151
static void
 
152
map_notify_cb (XigWindow *window)
 
153
{
 
154
    gchar *status_text;
 
155
 
 
156
    status_text = g_strdup_printf ("MAP-NOTIFY ID=%d", xig_window_get_id (window));
 
157
    check_status (status_text);
 
158
    g_free (status_text);
 
159
}
 
160
 
 
161
static void
 
162
reparent_notify_cb (XigWindow *window)
 
163
{
 
164
    gchar *status_text;
 
165
 
 
166
    status_text = g_strdup_printf ("REPARENT-NOTIFY ID=%d", xig_window_get_id (window));
 
167
    check_status (status_text);
 
168
    g_free (status_text);
 
169
}
 
170
 
 
171
static void
 
172
configure_notify_cb (XigWindow *window)
 
173
{
 
174
    gchar *status_text;
 
175
 
 
176
    status_text = g_strdup_printf ("CONFIGURE-NOTIFY ID=%d", xig_window_get_id (window));
 
177
    check_status (status_text);
 
178
    g_free (status_text);
 
179
}
 
180
 
 
181
static void
 
182
run_commands ()
 
183
{
 
184
    /* Stop compiz if requested */
 
185
    while (TRUE)
 
186
    {
 
187
        gchar *command, *name = NULL, *c;
 
188
        GHashTable *params;
 
189
 
 
190
        command = get_script_line ();
 
191
        if (!command)
 
192
            break;
 
193
 
 
194
        /* Commands start with an asterisk */
 
195
        if (command[0] != '*')
 
196
            break;
 
197
        statuses = g_list_append (statuses, g_strdup (command));
 
198
        script_iter = script_iter->next;
 
199
 
 
200
        c = command + 1;
 
201
        while (*c && !isspace (*c))
 
202
            c++;
 
203
        name = g_strdup_printf ("%.*s", (int) (c - command - 1), command + 1);
 
204
 
 
205
        params = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 
206
        while (TRUE)
 
207
        {
 
208
            gchar *start, *param_name, *param_value;
 
209
          
 
210
            while (isspace (*c))
 
211
                c++;
 
212
            start = c;
 
213
            while (*c && !isspace (*c) && *c != '=')
 
214
                c++;
 
215
            if (*c == '\0')
 
216
                break;
 
217
 
 
218
            param_name = g_strdup_printf ("%.*s", (int) (c - start), start);
 
219
 
 
220
            if (*c == '=')
 
221
            {
 
222
                c++;
 
223
                while (isspace (*c))
 
224
                    c++;
 
225
                if (*c == '\"')
 
226
                {
 
227
                    gboolean escaped = FALSE;
 
228
                    GString *value;
 
229
 
 
230
                    c++;
 
231
                    value = g_string_new ("");
 
232
                    while (*c)
 
233
                    {
 
234
                        if (*c == '\\')
 
235
                        {
 
236
                            if (escaped)
 
237
                            {
 
238
                                g_string_append_c (value, '\\');
 
239
                                escaped = FALSE;
 
240
                            }
 
241
                            else
 
242
                                escaped = TRUE;
 
243
                        }
 
244
                        else if (!escaped && *c == '\"')
 
245
                            break;
 
246
                        if (!escaped)
 
247
                            g_string_append_c (value, *c);
 
248
                        c++;
 
249
                    }
 
250
                    param_value = value->str;
 
251
                    g_string_free (value, FALSE);
 
252
                    if (*c == '\"')
 
253
                        c++;
 
254
                }
 
255
                else
 
256
                {
 
257
                    start = c;
 
258
                    while (*c && !isspace (*c))
 
259
                        c++;
 
260
                    param_value = g_strdup_printf ("%.*s", (int) (c - start), start);
 
261
                }
 
262
            }
 
263
            else
 
264
                param_value = g_strdup ("");
 
265
 
 
266
            g_hash_table_insert (params, param_name, param_value);
 
267
        }
 
268
 
 
269
        if (strcmp (name, "STOP-XSERVER") == 0)
 
270
            xig_server_stop (xserver);
 
271
        else if (strcmp (name, "STOP-COMPIZ") == 0)
 
272
            stop_compiz ();
 
273
        else if (strcmp (name, "RESTART-COMPIZ") == 0)
 
274
            restart_compiz ();
 
275
        else if (strcmp (name, "CREATE-WINDOW") == 0)
 
276
        {
 
277
            XigWindow *root, *window;
 
278
            gchar *v;
 
279
            guint32 id = 0;
 
280
            gint16 x = 0, y = 0;
 
281
            guint16 width = 0, height = 0, border_width = 0;
 
282
 
 
283
            v = g_hash_table_lookup (params, "ID");
 
284
            if (v)
 
285
                id = atoi (v);
 
286
            v = g_hash_table_lookup (params, "X");
 
287
            if (v)
 
288
                x = atoi (v);
 
289
            v = g_hash_table_lookup (params, "Y");
 
290
            if (v)
 
291
                y = atoi (v);
 
292
            v = g_hash_table_lookup (params, "WIDTH");
 
293
            if (v)
 
294
                width = atoi (v);
 
295
            v = g_hash_table_lookup (params, "HEIGHT");
 
296
            if (v)
 
297
                height = atoi (v);
 
298
            v = g_hash_table_lookup (params, "BORDER-WIDTH");
 
299
            if (v)
 
300
                border_width = atoi (v);
 
301
 
 
302
            root = xig_server_get_root (xserver, 0);
 
303
            window = xig_window_add_child (root, NULL, id,
 
304
                                           XIG_WINDOW_CLASS_InputOutput,
 
305
                                           x, y, width, height, border_width,
 
306
                                           xig_window_get_visual (root),
 
307
                                           0, NULL, 0, NULL, 0, 0, 0, 0, 0, 0, FALSE, FALSE);
 
308
            g_signal_connect (window, "unmap-notify", G_CALLBACK (unmap_notify_cb), NULL);
 
309
            g_signal_connect (window, "map-notify", G_CALLBACK (map_notify_cb), NULL);
 
310
            g_signal_connect (window, "reparent-notify", G_CALLBACK (reparent_notify_cb), NULL);
 
311
            g_signal_connect (window, "configure-notify", G_CALLBACK (configure_notify_cb), NULL);
 
312
        }
 
313
        else if (strcmp (name, "MAP-WINDOW") == 0)
 
314
        {
 
315
            gchar *v;
 
316
            guint32 id = 0;
 
317
            XigWindow *window;
 
318
 
 
319
            v = g_hash_table_lookup (params, "ID");
 
320
            if (v)
 
321
                id = atoi (v);
 
322
 
 
323
            window = xig_server_get_window (xserver, id);
 
324
            xig_window_map (window, NULL);
 
325
        }
 
326
        else
 
327
        {
 
328
            g_printerr ("Unknown command '%s'\n", name);
 
329
            quit (EXIT_FAILURE);
 
330
            return;
 
331
        }
 
332
 
 
333
        g_free (name);
 
334
        g_hash_table_unref (params);
 
335
    }
 
336
 
 
337
    gchar *l = get_script_line ();
 
338
 
 
339
    /* Stop at the end of the script */
 
340
    if (l == NULL)
 
341
    {
 
342
        if (compiz_pid)
 
343
            stop_compiz ();
 
344
        else
 
345
            quit (EXIT_SUCCESS);
 
346
    }
 
347
}
 
348
 
 
349
static gboolean
 
350
status_timeout_cb (gpointer data)
 
351
{
 
352
    fail ("(timeout)", get_script_line ());
 
353
    status_timeout = 0;
 
354
    return FALSE;
 
355
}
 
356
 
 
357
static void
 
358
check_status (const gchar *status)
 
359
{
 
360
    gchar *pattern;
 
361
 
 
362
    if (getenv ("DEBUG"))
 
363
        g_print ("%s\n", status);
 
364
 
 
365
    if (failed)
 
366
        return;
 
367
 
 
368
    statuses = g_list_append (statuses, g_strdup (status));
 
369
 
 
370
    /* Try and match against expected */
 
371
    pattern = get_script_line ();
 
372
    if (!pattern || !g_regex_match_simple (pattern, status, 0, 0))
 
373
    {
 
374
        fail (NULL, pattern);
 
375
        return;
 
376
    }
 
377
    script_iter = script_iter->next;
 
378
 
 
379
    /* Restart timeout */
 
380
    if (status_timeout)
 
381
        g_source_remove (status_timeout);
 
382
    status_timeout = g_timeout_add (STATUS_TIMEOUT, status_timeout_cb, NULL);
 
383
 
 
384
    run_commands ();
 
385
}
 
386
 
 
387
static void
 
388
signal_cb (int signum)
 
389
{
 
390
    if (compiz_pid != 0)
 
391
    {
 
392
        if (compiz_pid)
 
393
        {
 
394
            g_print ("Caught signal %d, killing Compiz\n", signum);
 
395
            kill (compiz_pid, SIGKILL);
 
396
        }
 
397
        else
 
398
            g_print ("Caught signal %d, quitting\n", signum);      
 
399
    }
 
400
    else
 
401
    {
 
402
        g_print ("Caught signal %d, quitting\n", signum);
 
403
        quit (EXIT_FAILURE);
 
404
    }
 
405
}
 
406
 
 
407
static void
 
408
load_script (const gchar *filename)
 
409
{
 
410
    int i;
 
411
    gchar *data, **lines;
 
412
 
 
413
    if (!g_file_get_contents (filename, &data, NULL, NULL))
 
414
    {
 
415
        g_printerr ("Unable to load script: %s\n", filename);
 
416
        quit (EXIT_FAILURE);
 
417
    }
 
418
 
 
419
    lines = g_strsplit (data, "\n", -1);
 
420
    g_free (data);
 
421
 
 
422
    /* Load lines with #? prefix as expected behaviour */
 
423
    for (i = 0; lines[i]; i++)
 
424
    {
 
425
        gchar *line = g_strstrip (lines[i]);
 
426
        if (g_str_has_prefix (line, "#?"))
 
427
            script = g_list_append (script, g_strdup (line+2));
 
428
    }
 
429
    script_iter = script;
 
430
    g_strfreev (lines);
 
431
}
 
432
 
 
433
static void
 
434
client_connected_cb (XigServer *server,
 
435
                     XigRemoteClient *client)
 
436
{
 
437
    check_status ("X CLIENT-CONNECTED");
 
438
}
 
439
 
 
440
static void
 
441
client_disconnected_cb (XigServer *server, XigRemoteClient *client)
 
442
{
 
443
    check_status ("X CLIENT-DISCONNECTED");
 
444
}
 
445
 
 
446
static gboolean
 
447
client_stdout_cb (GIOChannel   *source,
 
448
                  GIOCondition condition,
 
449
                  gpointer     data)
 
450
{
 
451
    gchar *str_return;
 
452
    gsize length;
 
453
    gsize terminator_pos;
 
454
    GError *error;
 
455
 
 
456
    if (condition & G_IO_IN)
 
457
    {
 
458
        while (g_io_channel_read_line (source,
 
459
                                       &str_return,
 
460
                                       &length,
 
461
                                       &terminator_pos,
 
462
                                       &error) == G_IO_STATUS_NORMAL)
 
463
        {
 
464
            if (getenv ("DEBUG"))
 
465
                g_print ("%s", str_return);
 
466
 
 
467
            /* This is a really bad heuristic, but its the only
 
468
             * sane IPC I can think of right now */
 
469
            if (strncmp ("execvp: ", str_return, 8) == 0)
 
470
            {
 
471
                /* Update the pid to the new compiz process */
 
472
                sscanf (&str_return[8], "%d", &compiz_pid);
 
473
            }
 
474
            g_free (str_return);
 
475
        }
 
476
    }
 
477
 
 
478
    return TRUE;
 
479
}
 
480
 
 
481
int
 
482
main (int argc, char **argv)
 
483
{
 
484
    GMainLoop *loop;
 
485
    XigScreen *screen;
 
486
    XigVisual *visual;
 
487
    gchar *script_name, *config_file, *config_path;
 
488
    GString *command_line;
 
489
    gchar **compiz_env, **compiz_argv;
 
490
    gint compiz_stdin, compiz_stdout, compiz_stderr;
 
491
    GIOChannel *compiz_stdout_channel = NULL;
 
492
    GError *error = NULL;
 
493
 
 
494
    signal (SIGINT, signal_cb);
 
495
    signal (SIGTERM, signal_cb);
 
496
 
 
497
    g_type_init ();
 
498
 
 
499
    loop = g_main_loop_new (NULL, FALSE);
 
500
 
 
501
    if (argc != 2)
 
502
    {
 
503
        g_printerr ("Usage %s SCRIPT-NAME\n", argv[0]);
 
504
        quit (EXIT_FAILURE);
 
505
    }
 
506
    script_name = argv[1];
 
507
    config_file = g_strdup_printf ("%s.conf", script_name);
 
508
    config_path = g_build_filename (COMPIZ_XIG_TEST_SOURCE_DIR "/scripts", config_file, NULL);
 
509
    g_free (config_file);
 
510
 
 
511
    config = g_key_file_new ();
 
512
    g_key_file_load_from_file (config, config_path, G_KEY_FILE_NONE, NULL);
 
513
 
 
514
    load_script (config_path);
 
515
 
 
516
    /* Disable config if requested */
 
517
    if (g_key_file_has_key (config, "test-runner-config", "have-config", NULL) &&
 
518
        !g_key_file_get_boolean (config, "test-runner-config", "have-config", NULL))
 
519
        config_path = NULL;
 
520
 
 
521
    g_print ("----------------------------------------\n");
 
522
    g_print ("Running script %s\n", script_name);
 
523
 
 
524
    /* Create an X server to test with */
 
525
    xserver = xig_server_new ("compiz-test", 99);
 
526
    xig_server_set_listen_tcp (xserver, FALSE);
 
527
    g_signal_connect (xserver, "client-connected", G_CALLBACK (client_connected_cb), NULL);
 
528
    g_signal_connect (xserver, "client-disconnected", G_CALLBACK (client_disconnected_cb), NULL);
 
529
    xig_server_add_pixmap_format (xserver, 1, 1, 32);
 
530
    xig_server_add_pixmap_format (xserver, 4, 8, 32);
 
531
    xig_server_add_pixmap_format (xserver, 8, 8, 32);
 
532
    xig_server_add_pixmap_format (xserver, 15, 16, 32);
 
533
    xig_server_add_pixmap_format (xserver, 16, 16, 32);
 
534
    xig_server_add_pixmap_format (xserver, 24, 32, 32);
 
535
    xig_server_add_pixmap_format (xserver, 32, 32, 32);
 
536
    screen = xig_server_add_screen (xserver, 0x00FFFFFF, 0x00000000, 1024, 768, 1024, 768);
 
537
    visual = xig_screen_add_visual (screen, 24, XIG_VISUAL_CLASS_TrueColor, 8, 1, 0x00FF0000, 0x0000FF00, 0x000000FF);
 
538
    xig_screen_add_root (screen, visual);
 
539
 
 
540
    run_commands ();
 
541
 
 
542
    status_timeout = g_timeout_add (STATUS_TIMEOUT, status_timeout_cb, NULL);
 
543
 
 
544
    if (!xig_server_start (xserver, &error))
 
545
    {
 
546
        g_printerr ("Failed to start Xig X server: %s", error->message);
 
547
        quit (EXIT_FAILURE);
 
548
    }
 
549
 
 
550
    compiz_env = g_strsplit ("DISPLAY=:99", " ", -1);
 
551
    command_line = g_string_new (compiz_BINARY_DIR "/src/compiz");
 
552
    g_print ("Start Compiz with command: %s\n", command_line->str);
 
553
    if (!g_shell_parse_argv (command_line->str, NULL, &compiz_argv, &error))
 
554
    {
 
555
        g_warning ("Error parsing command line: %s", error->message);
 
556
        quit (EXIT_FAILURE);
 
557
    }
 
558
    g_clear_error (&error);
 
559
    if (!g_spawn_async_with_pipes (NULL, /* working directory */
 
560
                                   compiz_argv,
 
561
                                   compiz_env,
 
562
                                   G_SPAWN_DO_NOT_REAP_CHILD,
 
563
                                   NULL, NULL, /* child setup */
 
564
                                   &compiz_pid,
 
565
                                   &compiz_stdin,
 
566
                                   &compiz_stdout,
 
567
                                   &compiz_stderr,
 
568
                                   &error))
 
569
    {
 
570
        g_warning ("Error launching Compiz: %s", error->message);
 
571
        quit (EXIT_FAILURE);
 
572
    }
 
573
    g_clear_error (&error);
 
574
    g_child_watch_add (compiz_pid, compiz_exit_cb, NULL);
 
575
    if (getenv ("DEBUG"))
 
576
        g_print ("Compiz running with PID %d\n", compiz_pid);
 
577
 
 
578
    compiz_stdout_channel = g_io_channel_unix_new (compiz_stdout);
 
579
    g_io_channel_set_flags (compiz_stdout_channel, G_IO_FLAG_NONBLOCK, NULL);
 
580
    g_io_add_watch (compiz_stdout_channel, G_IO_IN, client_stdout_cb, NULL);
 
581
 
 
582
    check_status ("COMPIZ START");
 
583
 
 
584
    g_main_loop_run (loop);
 
585
 
 
586
    g_object_unref (compiz_stdout_channel);
 
587
 
 
588
    return EXIT_FAILURE;
 
589
}