10 #include <sys/socket.h>
14 /* For some reason sys/un.h doesn't define this */
16 #define UNIX_PATH_MAX 108
19 static GPid lightdm_pid = 0;
20 static gchar *status_socket_name = NULL;
21 static gboolean expect_exit = FALSE;
22 static GList *statuses = NULL;
23 static GList *script = NULL;
24 static GList *script_iter = NULL;
25 static guint status_timeout = 0;
26 static gboolean failed = FALSE;
27 static gchar *temp_dir = NULL;
28 static GList *children = NULL;
30 static void check_status (const gchar *status);
36 kill (lightdm_pid, SIGTERM);
45 if (status_socket_name)
46 unlink (status_socket_name);
48 for (link = children; link; link = link->next)
50 GPid pid = GPOINTER_TO_INT (link->data);
56 gchar *command = g_strdup_printf ("rm -r %s", temp_dir);
58 perror ("Failed to delete temp directory");
65 fail (const gchar *event, const gchar *expected)
73 g_printerr ("Test failed, got the following events:\n");
74 for (link = statuses; link; link = link->next)
75 g_printerr (" %s\n", (gchar *)link->data);
77 g_printerr (" %s\n", event);
79 g_printerr (" ^^^ expected \"%s\"\n", expected);
81 g_printerr ("^^^ expected nothing\n");
83 /* Either wait for the daemon to quit, or stop now if it already is */
95 return script_iter->data;
99 daemon_exit_cb (GPid pid, gint status, gpointer data)
103 /* Quit when the daemon does */
109 if (WIFEXITED (status))
110 status_text = g_strdup_printf ("RUNNER DAEMON-EXIT STATUS=%d", WEXITSTATUS (status));
112 status_text = g_strdup_printf ("RUNNER DAEMON-TERMINATE SIGNAL=%d", WTERMSIG (status));
113 check_status (status_text);
117 open_unix_socket (const gchar *name)
120 struct sockaddr_un address;
122 s = socket (AF_UNIX, SOCK_DGRAM, 0);
125 address.sun_family = AF_UNIX;
126 strncpy (address.sun_path, name, UNIX_PATH_MAX);
127 if (bind (s, (struct sockaddr *) &address, sizeof (address)) < 0)
135 /* Stop daemon if requested */
138 gchar *command, *name = NULL, *c;
141 command = get_script_line ();
145 /* Commands start with an asterisk */
146 if (command[0] != '*')
148 statuses = g_list_append (statuses, g_strdup (command));
149 script_iter = script_iter->next;
152 while (*c && !isspace (*c))
154 name = g_strdup_printf ("%.*s", (int) (c - command - 1), command + 1);
156 params = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
159 gchar *start, *param_name, *param_value;
164 while (*c && !isspace (*c) && *c != '=')
169 param_name = g_strdup_printf ("%.*s", (int) (c - start), start);
178 gboolean escaped = FALSE;
182 value = g_string_new ("");
189 g_string_append_c (value, '\\');
195 else if (!escaped && *c == '\"')
198 g_string_append_c (value, *c);
201 param_value = value->str;
202 g_string_free (value, FALSE);
209 while (*c && !isspace (*c))
211 param_value = g_strdup_printf ("%.*s", (int) (c - start), start);
215 param_value = g_strdup ("");
217 g_hash_table_insert (params, param_name, param_value);
220 if (strcmp (name, "WAIT") == 0)
224 else if (strcmp (name, "SWITCH-TO-GREETER") == 0)
226 g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL),
227 "org.freedesktop.DisplayManager",
228 "/org/freedesktop/DisplayManager/Seat0",
229 "org.freedesktop.DisplayManager.Seat",
231 g_variant_new ("()"),
232 G_VARIANT_TYPE ("()"),
233 G_DBUS_CALL_FLAGS_NONE,
237 check_status ("RUNNER SWITCH-TO-GREETER");
239 else if (strcmp (name, "SWITCH-TO-USER") == 0)
241 gchar *status_text, *username;
243 username = g_hash_table_lookup (params, "USERNAME");
244 g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL),
245 "org.freedesktop.DisplayManager",
246 "/org/freedesktop/DisplayManager/Seat0",
247 "org.freedesktop.DisplayManager.Seat",
249 g_variant_new ("(ss)", username, ""),
250 G_VARIANT_TYPE ("()"),
251 G_DBUS_CALL_FLAGS_NONE,
255 status_text = g_strdup_printf ("RUNNER SWITCH-TO-USER USERNAME=%s", username);
256 check_status (status_text);
257 g_free (status_text);
259 else if (strcmp (name, "SWITCH-TO-GUEST") == 0)
261 g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL),
262 "org.freedesktop.DisplayManager",
263 "/org/freedesktop/DisplayManager/Seat0",
264 "org.freedesktop.DisplayManager.Seat",
266 g_variant_new ("(s)", ""),
267 G_VARIANT_TYPE ("()"),
268 G_DBUS_CALL_FLAGS_NONE,
272 check_status ("RUNNER SWITCH-TO-GUEST");
274 else if (strcmp (name, "STOP-DAEMON") == 0)
279 else if (strcmp (name, "START-XSERVER") == 0)
281 gchar *xserver_args, *command_line;
284 GError *error = NULL;
286 xserver_args = g_hash_table_lookup (params, "ARGS");
289 command_line = g_strdup_printf ("%s/tests/src/test-xserver %s", BUILDDIR, xserver_args);
291 g_debug ("Run %s", command_line);
292 if (!g_shell_parse_argv (command_line, NULL, &argv, &error) ||
293 !g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, &pid, &error))
295 g_printerr ("Error starting X server: %s", error->message);
299 children = g_list_append (children, GINT_TO_POINTER (pid));
303 g_printerr ("Unknown command '%s'\n", name);
309 g_hash_table_unref (params);
312 /* Stop at the end of the script */
313 if (get_script_line () == NULL)
326 status_timeout_cb (gpointer data)
328 fail ("(timeout)", get_script_line ());
333 check_status (const gchar *status)
340 statuses = g_list_append (statuses, g_strdup (status));
342 if (getenv ("DEBUG"))
343 g_print ("%s\n", status);
345 /* Try and match against expected */
346 pattern = get_script_line ();
347 if (!pattern || !g_regex_match_simple (pattern, status, 0, 0))
349 fail (NULL, pattern);
352 script_iter = script_iter->next;
354 /* Restart timeout */
355 g_source_remove (status_timeout);
356 status_timeout = g_timeout_add (2000, status_timeout_cb, NULL);
362 status_message_cb (GIOChannel *channel, GIOCondition condition, gpointer data)
368 s = g_io_channel_unix_get_fd (channel);
369 n_read = recv (s, buffer, 1023, 0);
371 g_warning ("Error reading from socket: %s", strerror (errno));
372 else if (n_read == 0)
376 buffer[n_read] = '\0';
377 check_status ((gchar *) buffer);
384 signal_cb (int signum)
386 if (lightdm_pid != 0)
388 g_print ("Caught signal %d, killing daemon\n", signum);
393 g_print ("Caught signal %d, quitting\n", signum);
399 load_script (const gchar *name)
402 gchar *filename, *path, *data, **lines;
404 filename = g_strdup_printf ("%s.script", name);
405 path = g_build_filename (SRCDIR, "tests", "scripts", filename, NULL);
408 if (!g_file_get_contents (path, &data, NULL, NULL))
410 g_printerr ("Unable to load script: %s\n", path);
415 lines = g_strsplit (data, "\n", -1);
418 for (i = 0; lines[i]; i++)
420 gchar *line = g_strstrip (lines[i]);
422 /* Skip empty lines and comments */
423 if (line[0] == '\0' || line[0] == '#')
426 script = g_list_append (script, g_strdup (line));
428 script_iter = script;
433 main (int argc, char **argv)
436 gchar *greeter = NULL, *script_name, *config_file, *config_path, *path, *path1, *path2, *ld_library_path, *home_dir;
437 GString *passwd_data;
439 gchar *dbus_command, dbus_address[1024];
441 GString *command_line;
445 gchar **lightdm_argv;
447 GError *error = NULL;
449 signal (SIGINT, signal_cb);
450 signal (SIGTERM, signal_cb);
454 loop = g_main_loop_new (NULL, FALSE);
456 if (argc != 2 && argc != 3)
458 g_printerr ("Usage %s SCRIPT-NAME [GREETER]\n", argv[0]);
461 script_name = argv[1];
462 config_file = g_strdup_printf ("%s.conf", script_name);
463 config_path = g_build_filename (SRCDIR, "tests", "scripts", config_file, NULL);
464 g_free (config_file);
469 load_script (script_name);
471 g_print ("----------------------------------------\n");
472 g_print ("Running script %s\n", script_name);
474 if (!getcwd (cwd, 1024))
476 g_critical ("Error getting current directory: %s", strerror (errno));
480 /* Don't contact our X server */
481 g_unsetenv ("DISPLAY");
483 /* Use locally built libraries and binaries */
484 path = g_strdup_printf ("%s/tests/src/.libs:%s/tests/src:%s/tests/src:%s", BUILDDIR, BUILDDIR, SRCDIR, g_getenv ("PATH"));
485 g_setenv ("PATH", path, TRUE);
487 path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", ".libs", NULL);
488 path2 = g_build_filename (BUILDDIR, "liblightdm-qt", ".libs", NULL);
489 ld_library_path = g_strdup_printf ("%s:%s", path1, path2);
492 g_setenv ("LD_LIBRARY_PATH", ld_library_path, TRUE);
493 g_free (ld_library_path);
495 /* Set config for child processes to read */
497 g_setenv ("LIGHTDM_TEST_CONFIG", config_path, TRUE);
499 /* Run local D-Bus daemon */
500 if (pipe (dbus_pipe) < 0)
502 g_warning ("Error creating pipe: %s", strerror (errno));
505 dbus_command = g_strdup_printf ("dbus-daemon --session --print-address=%d", dbus_pipe[1]);
506 if (!g_shell_parse_argv (dbus_command, NULL, &dbus_argv, &error))
508 g_warning ("Error parsing command line: %s", error->message);
511 g_clear_error (&error);
512 if (!g_spawn_async (NULL, dbus_argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_LEAVE_DESCRIPTORS_OPEN, NULL, NULL, &pid, &error))
514 g_warning ("Error launching LightDM: %s", error->message);
517 children = g_list_append (children, GINT_TO_POINTER (pid));
518 n_read = read (dbus_pipe[0], dbus_address, 1023);
521 g_warning ("Error reading D-Bus address: %s", strerror (errno));
524 dbus_address[n_read] = '\0';
525 g_setenv ("DBUS_SESSION_BUS_ADDRESS", dbus_address, TRUE);
527 /* Open socket for status */
528 status_socket_name = g_build_filename (cwd, ".status-socket", NULL);
529 g_setenv ("LIGHTDM_TEST_STATUS_SOCKET", status_socket_name, TRUE);
530 unlink (status_socket_name);
531 status_socket = open_unix_socket (status_socket_name);
532 if (status_socket < 0)
534 g_warning ("Error opening status socket: %s", strerror (errno));
537 g_io_add_watch (g_io_channel_unix_new (status_socket), G_IO_IN, status_message_cb, NULL);
539 /* Make fake users */
540 temp_dir = g_build_filename (cwd, "lightdm-test-XXXXXX", NULL);
541 if (!mkdtemp (temp_dir))
543 g_warning ("Error creating temporary directory: %s", strerror (errno));
546 home_dir = g_build_filename (temp_dir, "home", NULL);
547 g_setenv ("LIGHTDM_TEST_HOME_DIR", home_dir, TRUE);
548 passwd_data = g_string_new ("");
558 {"alice", "password", "Alice User", 1000},
559 {"bob", "", "Bob User", 1001},
563 for (i = 0; users[i].user_name; i++)
565 path = g_build_filename (home_dir, users[i].user_name, NULL);
566 g_mkdir_with_parents (path, 0755);
569 g_string_append_printf (passwd_data, "%s:%s:%d:%d:%s:%s/home/%s:/bin/sh\n", users[i].user_name, users[i].password, users[i].uid, users[i].uid, users[i].real_name, temp_dir, users[i].user_name);
572 path = g_build_filename (temp_dir, "passwd", NULL);
573 g_setenv ("LIGHTDM_TEST_PASSWD_FILE", path, TRUE);
574 g_file_set_contents (path, passwd_data->str, -1, NULL);
576 g_string_free (passwd_data, TRUE);
580 status_timeout = g_timeout_add (2000, status_timeout_cb, NULL);
582 command_line = g_string_new ("../src/lightdm");
583 if (getenv ("DEBUG"))
584 g_string_append (command_line, " --debug");
585 if (fopen (config_path, "r"))
586 g_string_append_printf (command_line, " --config %s", config_path);
587 g_string_append (command_line, " --test-mode");
588 g_string_append(command_line, " --xserver-command=test-xserver");
590 g_string_append_printf (command_line, " --greeter-session=%s", greeter);
591 g_string_append (command_line, " --session-wrapper=");
592 g_string_append_printf (command_line, " --passwd-file %s/passwd", temp_dir);
593 g_string_append_printf (command_line, " --cache-dir %s/cache", temp_dir);
594 g_string_append_printf (command_line, " --xsessions-dir=%s/tests/data/xsessions", SRCDIR);
595 g_string_append_printf (command_line, " --xgreeters-dir=%s/tests/data/xgreeters", SRCDIR);
596 g_string_append (command_line, " --minimum-vt=0");
597 g_string_append (command_line, " --minimum-display-number=50");
599 g_print ("Start daemon with command: PATH=%s LD_LIBRARY_PATH=%s LIGHTDM_TEST_STATUS_SOCKET=%s DBUS_SESSION_BUS_ADDRESS=%s %s\n",
600 g_getenv ("PATH"), g_getenv ("LD_LIBRARY_PATH"), g_getenv ("LIGHTDM_TEST_STATUS_SOCKET"), g_getenv ("DBUS_SESSION_BUS_ADDRESS"),
603 if (!g_shell_parse_argv (command_line->str, NULL, &lightdm_argv, &error))
605 g_warning ("Error parsing command line: %s", error->message);
608 g_clear_error (&error);
610 if (!g_spawn_async (NULL, lightdm_argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &lightdm_pid, &error))
612 g_warning ("Error launching LightDM: %s", error->message);
615 g_clear_error (&error);
617 check_status ("RUNNER DAEMON-START");
619 g_child_watch_add (lightdm_pid, daemon_exit_cb, NULL);
621 g_main_loop_run (loop);