]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blobdiff - tests/src/test-runner.c
Add shared data manager and test
[sojka/lightdm.git] / tests / src / test-runner.c
index d64f5f685ab140dcb705f9b81d61e53fc2c8609b..fec53eae71a440be555a673909d40e2929261fb3 100644 (file)
@@ -12,7 +12,7 @@
 #include <pwd.h>
 
 /* Timeout in ms waiting for the status we expect */
-#define STATUS_TIMEOUT 4000
+static int status_timeout_ms = 4000;
 
 /* Timeout in ms to wait for SIGTERM to be handled by a child process */
 #define KILL_TIMEOUT 2000
@@ -50,11 +50,15 @@ typedef struct
     gchar *user_name;
     gchar *real_name;
     gchar *home_directory;
+    gchar *image;
+    gchar *background;
     gchar *path;
     guint id;
     gchar *language;
     gchar *xsession;
     gchar **layouts;
+    gboolean has_messages;
+    gboolean hidden;
 } AccountsUser;
 static GList *accounts_users = NULL;
 static void handle_user_call (GDBusConnection       *connection,
@@ -84,10 +88,11 @@ typedef struct
     gchar *cookie;
     gchar *path;
     guint id;
+    gboolean locked;
 } CKSession;
 static GList *ck_sessions = NULL;
 static gint ck_session_index = 0;
-static void handle_session_call (GDBusConnection       *connection,
+static void handle_ck_session_call (GDBusConnection       *connection,
                                     const gchar           *sender,
                                     const gchar           *object_path,
                                     const gchar           *interface_name,
@@ -97,13 +102,14 @@ static void handle_session_call (GDBusConnection       *connection,
                                     gpointer               user_data);
 static const GDBusInterfaceVTable ck_session_vtable =
 {
-    handle_session_call,
+    handle_ck_session_call,
 };
 
 typedef struct
 {
     gchar *path;
     guint pid;
+    gboolean locked;
 } Login1Session;
 
 static GList *login1_sessions = NULL;
@@ -119,6 +125,9 @@ static GList *status_clients = NULL;
 static void run_lightdm (void);
 static void quit (int status);
 static void check_status (const gchar *status);
+static AccountsUser *get_accounts_user_by_uid (guint uid);
+static AccountsUser *get_accounts_user_by_name (const gchar *username);
+static void accounts_user_set_hidden (AccountsUser *user, gboolean hidden, gboolean emit_signal);
 
 static gboolean
 kill_timeout_cb (gpointer data)
@@ -235,7 +244,7 @@ quit (int status)
     if (status_socket_name)
         unlink (status_socket_name);
 
-    if (temp_dir)
+    if (temp_dir && getenv ("DEBUG") == NULL)
     {
         gchar *command = g_strdup_printf ("rm -rf %s", temp_dir);
         if (system (command))
@@ -310,6 +319,13 @@ get_script_line (const gchar *prefix)
     return NULL;
 }
 
+static gboolean
+stop_loop (gpointer user_data)
+{
+    g_main_loop_quit ((GMainLoop *)user_data);
+    return G_SOURCE_REMOVE;
+}
+
 static void
 handle_command (const gchar *command)
 {
@@ -389,7 +405,122 @@ handle_command (const gchar *command)
 
     if (strcmp (name, "WAIT") == 0)
     {
-        sleep (1);
+        /* Use a main loop so that our DBus functions are still responsive */
+        GMainLoop *loop = g_main_loop_new (NULL, FALSE);
+        g_timeout_add_seconds (1, stop_loop, loop);
+        g_main_loop_run (loop);
+        g_main_loop_unref (loop);
+    }
+    else if (strcmp (name, "LIST-SHARED-DATA-DIRS") == 0)
+    {
+        gchar *shared_dir;
+        GDir *dir;
+        const gchar *path;
+        GList *paths = NULL, *link;
+        GString *status;
+
+        shared_dir = g_strdup_printf ("%s/var/lib/lightdm-data", temp_dir);
+        dir = g_dir_open (shared_dir, 0, NULL);
+        while ((path = g_dir_read_name (dir)))
+        {
+            gchar *full_path = g_build_filename (shared_dir, path, NULL);
+            paths = g_list_insert_sorted (paths, full_path, (GCompareFunc)g_strcmp0);
+        }
+        g_dir_close (dir);
+        g_free (shared_dir);
+
+        status = g_string_new ("RUNNER LIST-SHARED-DATA-DIRS DIRS=");
+        for (link = paths; link; link = link->next)
+        {
+            path = (const gchar *)link->data;
+            GStatBuf buf;
+            if (g_stat (path, &buf) != 0)
+                continue;
+
+            if (link != paths)
+                g_string_append (status, ",");
+            gchar *basename = g_path_get_basename (path);
+            g_string_append_printf (status, "%s:%u:%u:0%o", basename,
+                                    buf.st_uid, buf.st_gid,
+                                    buf.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO));
+            g_free (basename);
+        }
+        g_list_free_full (paths, g_free);
+
+        check_status (status->str);
+        g_string_free (status, TRUE);
+    }
+    else if (strcmp (name, "LIST-SEATS") == 0)
+    {
+        GVariant *result, *value;
+        GString *status;
+        GVariantIter *iter;
+        const gchar *path;
+        int i = 0;
+
+        result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
+                                              "org.freedesktop.DisplayManager",
+                                              "/org/freedesktop/DisplayManager",
+                                              "org.freedesktop.DBus.Properties",
+                                              "Get",
+                                              g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Seats"),
+                                              G_VARIANT_TYPE ("(v)"),
+                                              G_DBUS_CALL_FLAGS_NONE,
+                                              1000,
+                                              NULL,
+                                              NULL);
+
+        status = g_string_new ("RUNNER LIST-SEATS SEATS=");
+        g_variant_get (result, "(v)", &value);
+        g_variant_get (value, "ao", &iter);
+        while (g_variant_iter_loop (iter, "&o", &path))
+        {
+            if (i != 0)
+                g_string_append (status, ",");
+            g_string_append (status, path);
+            i++;
+        }
+        g_variant_unref (value);
+        g_variant_unref (result);
+
+        check_status (status->str);
+        g_string_free (status, TRUE);
+    }
+    else if (strcmp (name, "LIST-SESSIONS") == 0)
+    {
+        GVariant *result, *value;
+        GString *status;
+        GVariantIter *iter;
+        const gchar *path;
+        int i = 0;
+
+        result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
+                                              "org.freedesktop.DisplayManager",
+                                              "/org/freedesktop/DisplayManager",
+                                              "org.freedesktop.DBus.Properties",
+                                              "Get",
+                                              g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"),
+                                              G_VARIANT_TYPE ("(v)"),
+                                              G_DBUS_CALL_FLAGS_NONE,
+                                              1000,
+                                              NULL,
+                                              NULL);
+
+        status = g_string_new ("RUNNER LIST-SESSIONS SESSIONS=");
+        g_variant_get (result, "(v)", &value);
+        g_variant_get (value, "ao", &iter);
+        while (g_variant_iter_loop (iter, "&o", &path))
+        {
+            if (i != 0)
+                g_string_append (status, ",");
+            g_string_append (status, path);
+            i++;
+        }
+        g_variant_unref (value);
+        g_variant_unref (result);
+
+        check_status (status->str);
+        g_string_free (status, TRUE);
     }
     else if (strcmp (name, "SWITCH-TO-GREETER") == 0)
     {
@@ -494,10 +625,121 @@ handle_command (const gchar *command)
             g_hash_table_insert (children, GINT_TO_POINTER (process->pid), process);
         }
     }
+    else if (strcmp (name, "ADD-USER") == 0)
+    {
+        gchar *status_text, *username;
+        AccountsUser *user;
+
+        username = g_hash_table_lookup (params, "USERNAME");
+        user = get_accounts_user_by_name (username);
+        if (user)
+            accounts_user_set_hidden (user, FALSE, TRUE);
+        else
+            g_warning ("Unknown user %s", username);
+
+        status_text = g_strdup_printf ("RUNNER ADD-USER USERNAME=%s", username);
+        check_status (status_text);
+        g_free (status_text);
+    }
+    else if (strcmp (name, "UPDATE-USER") == 0)
+    {
+        GString *status_text;
+        gchar *username;
+        AccountsUser *user;
+        GError *error = NULL;
+
+        status_text = g_string_new ("RUNNER UPDATE-USER USERNAME=");
+
+        username = g_hash_table_lookup (params, "USERNAME");
+        g_string_append (status_text, username);
+        user = get_accounts_user_by_name (username);
+        if (user)
+        {
+            if (g_hash_table_lookup (params, "NAME"))
+            {
+                user->user_name = g_strdup (g_hash_table_lookup (params, "NAME"));
+                g_string_append_printf (status_text, " NAME=%s", user->user_name);
+            }
+            if (g_hash_table_lookup (params, "REAL-NAME"))
+            {
+                user->real_name = g_strdup (g_hash_table_lookup (params, "REAL-NAME"));
+                g_string_append_printf (status_text, " REAL-NAME=%s", user->real_name);
+            }
+            if (g_hash_table_lookup (params, "HOME-DIRECTORY"))
+            {
+                user->home_directory = g_strdup (g_hash_table_lookup (params, "HOME-DIRECTORY"));
+                g_string_append_printf (status_text, " HOME-DIRECTORY=%s", user->home_directory);
+            }
+            if (g_hash_table_lookup (params, "IMAGE"))
+            {
+                user->image = g_strdup (g_hash_table_lookup (params, "IMAGE"));
+                g_string_append_printf (status_text, " IMAGE=%s", user->image);
+            }
+            if (g_hash_table_lookup (params, "BACKGROUND"))
+            {
+                user->background = g_strdup (g_hash_table_lookup (params, "BACKGROUND"));
+                g_string_append_printf (status_text, " BACKGROUND=%s", user->background);
+            }
+            if (g_hash_table_lookup (params, "LANGUAGE"))
+            {
+                user->language = g_strdup (g_hash_table_lookup (params, "LANGUAGE"));
+                g_string_append_printf (status_text, " LANGUAGE=%s", user->language);
+            }
+            if (g_hash_table_lookup (params, "LAYOUTS"))
+            {
+                const gchar *value = g_hash_table_lookup (params, "LAYOUTS");
+                user->layouts = g_strsplit (value, ";", -1);
+                g_string_append_printf (status_text, " LAYOUTS=%s", value);
+            }
+            if (g_hash_table_lookup (params, "HAS-MESSAGES"))
+            {
+                user->has_messages = g_strcmp0 (g_hash_table_lookup (params, "HAS-MESSAGES"), "TRUE") == 0;
+                g_string_append_printf (status_text, " HAS-MESSAGES=%s", user->has_messages ? "TRUE" : "FALSE");
+            }
+            if (g_hash_table_lookup (params, "SESSION"))
+            {
+                user->xsession = g_strdup (g_hash_table_lookup (params, "SESSION"));
+                g_string_append_printf (status_text, " SESSION=%s", user->xsession);
+            }
+        }
+        else
+            g_warning ("Unknown user %s", username);
+
+        g_dbus_connection_emit_signal (accounts_connection,
+                                       NULL,
+                                       user->path,
+                                       "org.freedesktop.Accounts.User",
+                                       "Changed",
+                                       g_variant_new ("()"),
+                                       &error);
+        if (error)
+            g_warning ("Failed to emit Changed: %s", error->message);
+        g_clear_error (&error);
+
+        check_status (status_text->str);
+        g_string_free (status_text, TRUE);
+    }
+    else if (strcmp (name, "DELETE-USER") == 0)
+    {
+        gchar *status_text, *username;
+        AccountsUser *user;
+
+        username = g_hash_table_lookup (params, "USERNAME");
+        user = get_accounts_user_by_name (username);
+        if (user)
+            accounts_user_set_hidden (user, TRUE, TRUE);
+        else
+            g_warning ("Unknown user %s", username);
+
+        status_text = g_strdup_printf ("RUNNER DELETE-USER USERNAME=%s", username);
+        check_status (status_text);
+        g_free (status_text);
+    }
     /* Forward to external processes */
     else if (g_str_has_prefix (name, "SESSION-") ||
              g_str_has_prefix (name, "GREETER-") ||
-             g_str_has_prefix (name, "XSERVER-"))
+             g_str_has_prefix (name, "XSERVER-") ||
+             strcmp (name, "UNITY-SYSTEM-COMPOSITOR") == 0)
     {
         GList *link;
         for (link = status_clients; link; link = link->next)
@@ -507,9 +749,8 @@ handle_command (const gchar *command)
             GError *error = NULL;
 
             length = strlen (command);
-            g_socket_send (client->socket, (gchar *) &length, sizeof (length), NULL, &error);
-            g_socket_send (client->socket, command, strlen (command), NULL, &error);
-            if (error)
+            if (g_socket_send (client->socket, (gchar *) &length, sizeof (length), NULL, &error) < 0 ||
+                g_socket_send (client->socket, command, strlen (command), NULL, &error) < 0)
                 g_printerr ("Failed to write to client socket: %s\n", error->message);
             g_clear_error (&error);
         }
@@ -525,7 +766,7 @@ handle_command (const gchar *command)
 }
 
 static void
-run_commands ()
+run_commands (void)
 {
     /* Stop daemon if requested */
     while (TRUE)
@@ -597,7 +838,7 @@ check_status (const gchar *status)
 
     /* Restart timeout */
     g_source_remove (status_timeout);
-    status_timeout = g_timeout_add (STATUS_TIMEOUT, status_timeout_cb, NULL);
+    status_timeout = g_timeout_add (status_timeout_ms, status_timeout_cb, NULL);
 
     run_commands ();
 }
@@ -771,7 +1012,7 @@ upower_name_acquired_cb (GDBusConnection *connection,
 }
 
 static void
-start_upower_daemon ()
+start_upower_daemon (void)
 {
     service_count++;
     g_bus_own_name (G_BUS_TYPE_SYSTEM,
@@ -893,22 +1134,32 @@ handle_ck_call (GDBusConnection       *connection,
         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
 }
 
-
-/* Shared between CK and Login1 - identical signatures */
 static void
-handle_session_call (GDBusConnection       *connection,
-                     const gchar           *sender,
-                     const gchar           *object_path,
-                     const gchar           *interface_name,
-                     const gchar           *method_name,
-                     GVariant              *parameters,
-                     GDBusMethodInvocation *invocation,
-                     gpointer               user_data)
+handle_ck_session_call (GDBusConnection       *connection,
+                        const gchar           *sender,
+                        const gchar           *object_path,
+                        const gchar           *interface_name,
+                        const gchar           *method_name,
+                        GVariant              *parameters,
+                        GDBusMethodInvocation *invocation,
+                        gpointer               user_data)
 {
+    CKSession *session = user_data;
+
     if (strcmp (method_name, "Lock") == 0)
+    { 
+        if (!session->locked)
+            check_status ("CONSOLE-KIT LOCK-SESSION");
+        session->locked = TRUE;
         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
+    }
     else if (strcmp (method_name, "Unlock") == 0)
+    {
+        if (session->locked)
+            check_status ("CONSOLE-KIT UNLOCK-SESSION");
+        session->locked = FALSE;
         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
+    }
     else
         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
 }
@@ -997,7 +1248,7 @@ ck_name_acquired_cb (GDBusConnection *connection,
 }
 
 static void
-start_console_kit_daemon ()
+start_console_kit_daemon (void)
 {
     service_count++;
     g_bus_own_name (G_BUS_TYPE_SYSTEM,
@@ -1010,6 +1261,36 @@ start_console_kit_daemon ()
                     NULL);
 }
 
+static void
+handle_login1_session_call (GDBusConnection       *connection,
+                            const gchar           *sender,
+                            const gchar           *object_path,
+                            const gchar           *interface_name,
+                            const gchar           *method_name,
+                            GVariant              *parameters,
+                            GDBusMethodInvocation *invocation,
+                            gpointer               user_data)
+{
+    Login1Session *session = user_data;
+
+    if (strcmp (method_name, "Lock") == 0)
+    {
+        if (!session->locked)
+            check_status ("LOGIN1 LOCK-SESSION");
+        session->locked = TRUE;
+        g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
+    }
+    else if (strcmp (method_name, "Unlock") == 0)
+    {
+        if (session->locked)
+            check_status ("LOGIN1 UNLOCK-SESSION");
+        session->locked = FALSE;
+        g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
+    }
+    else
+        g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
+}
+
 static Login1Session *
 open_login1_session (GDBusConnection *connection,
                      GVariant *params)
@@ -1027,7 +1308,7 @@ open_login1_session (GDBusConnection *connection,
         "</node>";
     static const GDBusInterfaceVTable login1_session_vtable =
     {
-        handle_session_call,
+        handle_login1_session_call,
     };
 
     session = g_malloc0 (sizeof (Login1Session));
@@ -1045,7 +1326,7 @@ open_login1_session (GDBusConnection *connection,
                    error->message);
     g_clear_error (&error);
     if (!login1_session_info)
-        return;
+        return NULL;
 
     g_dbus_connection_register_object (connection,
                                        session->path,
@@ -1222,7 +1503,7 @@ login1_name_acquired_cb (GDBusConnection *connection,
 }
 
 static void
-start_login1_daemon ()
+start_login1_daemon (void)
 {
     service_count++;
     g_bus_own_name (G_BUS_TYPE_SYSTEM,
@@ -1235,12 +1516,101 @@ start_login1_daemon ()
                     NULL);
 }
 
+static AccountsUser *
+get_accounts_user_by_uid (guint uid)
+{
+    GList *link;
+
+    for (link = accounts_users; link; link = link->next)
+    {
+        AccountsUser *u = link->data;
+        if (u->uid == uid)
+            return u;
+    }
+  
+    return NULL;
+}
+
+static AccountsUser *
+get_accounts_user_by_name (const gchar *username)
+{
+    GList *link;
+
+    for (link = accounts_users; link; link = link->next)
+    {
+        AccountsUser *u = link->data;
+        if (strcmp (u->user_name, username) == 0)
+            return u;
+    }
+
+    return NULL;
+}
+
+static void
+accounts_user_set_hidden (AccountsUser *user, gboolean hidden, gboolean emit_signal)
+{
+    GError *error = NULL;
+
+    user->hidden = hidden;
+
+    if (user->hidden && user->id != 0)
+    {
+        g_dbus_connection_unregister_object (accounts_connection, user->id);
+        g_dbus_connection_emit_signal (accounts_connection,
+                                       NULL,
+                                       "/org/freedesktop/Accounts",
+                                       "org.freedesktop.Accounts",
+                                       "UserDeleted",
+                                       g_variant_new ("(o)", user->path),
+                                       &error);
+        if (error)
+            g_warning ("Failed to emit UserDeleted: %s", error->message);
+        g_clear_error (&error);
+
+        user->id = 0;
+    }
+    if (!user->hidden && user->id == 0)
+    {
+        user->id = g_dbus_connection_register_object (accounts_connection,
+                                                      user->path,
+                                                      user_info->interfaces[0],
+                                                      &user_vtable,
+                                                      user,
+                                                      NULL,
+                                                      &error);
+        if (error)
+            g_warning ("Failed to register user: %s", error->message);
+        g_clear_error (&error);
+
+        g_dbus_connection_emit_signal (accounts_connection,
+                                       NULL,
+                                       "/org/freedesktop/Accounts",
+                                       "org.freedesktop.Accounts",
+                                       "UserAdded",
+                                       g_variant_new ("(o)", user->path),
+                                       &error);
+        if (error)
+            g_warning ("Failed to emit UserAdded: %s", error->message);
+        g_clear_error (&error);
+    }
+}
+
 static void
-load_passwd_file ()
+load_passwd_file (void)
 {
     gchar *path, *data, **lines;
+    gchar **user_filter = NULL;
     int i;
 
+    if (g_key_file_has_key (config, "test-runner-config", "accounts-service-user-filter", NULL))
+    {
+        gchar *filter;
+
+        filter = g_key_file_get_string (config, "test-runner-config", "accounts-service-user-filter", NULL);
+        user_filter = g_strsplit (filter, " ", -1);
+        g_free (filter);
+    }
+
     path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL);
     g_file_get_contents (path, &data, NULL, NULL);
     g_free (path);
@@ -1252,27 +1622,20 @@ load_passwd_file ()
         gchar **fields;
         guint uid;
         gchar *user_name, *real_name;
-        GList *link;
         AccountsUser *user = NULL;
-        GError *error = NULL;
 
         fields = g_strsplit (lines[i], ":", -1);
         if (fields == NULL || g_strv_length (fields) < 7)
+        {
+            g_strfreev (fields);
             continue;
+        }
 
         user_name = fields[0];
         uid = atoi (fields[2]);
         real_name = fields[4];
 
-        for (link = accounts_users; link; link = link->next)
-        {
-            AccountsUser *u = link->data;
-            if (u->uid == uid)
-            {
-                user = u;
-                break;
-            }
-        }
+        user = get_accounts_user_by_uid (uid);
         if (!user)
         {
             gchar *path;
@@ -1281,6 +1644,18 @@ load_passwd_file ()
             user = g_malloc0 (sizeof (AccountsUser));
             accounts_users = g_list_append (accounts_users, user);
 
+            /* Only allow users in whitelist */
+            user->hidden = FALSE;
+            if (user_filter)
+            {
+                int j;
+
+                user->hidden = TRUE;
+                for (j = 0; user_filter[j] != NULL; j++)
+                    if (strcmp (user_name, user_filter[j]) == 0)
+                        user->hidden = FALSE;
+            }
+
             dmrc_file = g_key_file_new ();
             path = g_build_filename (temp_dir, "home", user_name, ".dmrc", NULL);
             g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_NONE, NULL);
@@ -1300,17 +1675,15 @@ load_passwd_file ()
             }
             user->xsession = g_key_file_get_string (dmrc_file, "Desktop", "Session", NULL);
             user->layouts = g_key_file_get_string_list (dmrc_file, "X-Accounts", "Layouts", NULL, NULL);
+            if (!user->layouts)
+            {
+                user->layouts = g_malloc (sizeof (gchar *) * 2);
+                user->layouts[0] = g_key_file_get_string (dmrc_file, "Desktop", "Layout", NULL);
+                user->layouts[1] = NULL;
+            }
+            user->has_messages = g_key_file_get_boolean (dmrc_file, "X-Accounts", "HasMessages", NULL);
             user->path = g_strdup_printf ("/org/freedesktop/Accounts/User%d", uid);
-            user->id = g_dbus_connection_register_object (accounts_connection,
-                                                          user->path,
-                                                          user_info->interfaces[0],
-                                                          &user_vtable,
-                                                          user,
-                                                          NULL,
-                                                          &error);
-            if (error)
-                g_warning ("Failed to register user: %s", error->message);
-            g_clear_error (&error);
+            accounts_user_set_hidden (user, user->hidden, FALSE);
 
             g_key_file_free (dmrc_file);
         }
@@ -1342,31 +1715,27 @@ handle_accounts_call (GDBusConnection       *connection,
         for (link = accounts_users; link; link = link->next)
         {
             AccountsUser *user = link->data;
-            g_variant_builder_add_value (&builder, g_variant_new_object_path (user->path));
+            if (!user->hidden && user->uid >= 1000)
+                g_variant_builder_add_value (&builder, g_variant_new_object_path (user->path));
         }
 
         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(ao)", &builder));
     }
     else if (strcmp (method_name, "FindUserByName") == 0)
     {
-        GList *link;
         AccountsUser *user = NULL;
         gchar *user_name;
 
         g_variant_get (parameters, "(&s)", &user_name);
 
         load_passwd_file ();
-        for (link = accounts_users; link; link = link->next)
-        {
-            AccountsUser *u = link->data;
-            if (strcmp (u->user_name, user_name) == 0)
-            {
-                user = u;
-                break;
-            }
-        }
+        user = get_accounts_user_by_name (user_name);
         if (user)
+        {
+            if (user->hidden)
+                accounts_user_set_hidden (user, FALSE, TRUE);
             g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", user->path));
+        }
         else
             g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such user: %s", user_name);
     }
@@ -1396,6 +1765,15 @@ handle_user_call (GDBusConnection       *connection,
         user->xsession = g_strdup (xsession);
 
         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
+
+        /* And notify others that it took */
+        g_dbus_connection_emit_signal (accounts_connection,
+                                       NULL,
+                                       user->path,
+                                       "org.freedesktop.Accounts.User",
+                                       "Changed",
+                                       g_variant_new ("()"),
+                                       NULL);
     }
     else
         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
@@ -1418,10 +1796,18 @@ handle_user_get_property (GDBusConnection       *connection,
         return g_variant_new_string (user->real_name);
     else if (strcmp (property_name, "HomeDirectory") == 0)
         return g_variant_new_string (user->home_directory);
+    else if (strcmp (property_name, "SystemAccount") == 0)
+        return g_variant_new_boolean (user->uid < 1000);
     else if (strcmp (property_name, "BackgroundFile") == 0)
-        return g_variant_new_string ("");
+        return g_variant_new_string (user->background ? user->background : "");
     else if (strcmp (property_name, "Language") == 0)
         return g_variant_new_string (user->language ? user->language : "");
+    else if (strcmp (property_name, "IconFile") == 0)
+        return g_variant_new_string (user->image ? user->image : "");
+    else if (strcmp (property_name, "Shell") == 0)
+        return g_variant_new_string ("/bin/sh");
+    else if (strcmp (property_name, "Uid") == 0)
+        return g_variant_new_uint64 (user->uid);
     else if (strcmp (property_name, "XSession") == 0)
         return g_variant_new_string (user->xsession ? user->xsession : "");
     else if (strcmp (property_name, "XKeyboardLayouts") == 0)
@@ -1432,7 +1818,7 @@ handle_user_get_property (GDBusConnection       *connection,
             return g_variant_new_strv (NULL, 0);
     }
     else if (strcmp (property_name, "XHasMessages") == 0)
-        return g_variant_new_boolean (FALSE);
+        return g_variant_new_boolean (user->has_messages);
 
     return NULL;
 }
@@ -1452,6 +1838,12 @@ accounts_name_acquired_cb (GDBusConnection *connection,
         "      <arg name='name' direction='in' type='s'/>"
         "      <arg name='user' direction='out' type='o'/>"
         "    </method>"
+        "    <signal name='UserAdded'>"
+        "      <arg name='user' type='o'/>"
+        "    </signal>"
+        "    <signal name='UserDeleted'>"
+        "      <arg name='user' type='o'/>"
+        "    </signal>"
         "  </interface>"
         "</node>";
     static const GDBusInterfaceVTable accounts_vtable =
@@ -1467,11 +1859,16 @@ accounts_name_acquired_cb (GDBusConnection *connection,
         "    <property name='UserName' type='s' access='read'/>"
         "    <property name='RealName' type='s' access='read'/>"
         "    <property name='HomeDirectory' type='s' access='read'/>"
+        "    <property name='SystemAccount' type='b' access='read'/>"
         "    <property name='BackgroundFile' type='s' access='read'/>"
         "    <property name='Language' type='s' access='read'/>"
+        "    <property name='IconFile' type='s' access='read'/>"
+        "    <property name='Shell' type='s' access='read'/>"
+        "    <property name='Uid' type='t' access='read'/>"
         "    <property name='XSession' type='s' access='read'/>"
         "    <property name='XKeyboardLayouts' type='as' access='read'/>"
         "    <property name='XHasMessages' type='b' access='read'/>"
+        "    <signal name='Changed' />"
         "  </interface>"
         "</node>";
     GError *error = NULL;
@@ -1508,7 +1905,7 @@ accounts_name_acquired_cb (GDBusConnection *connection,
 }
 
 static void
-start_accounts_service_daemon ()
+start_accounts_service_daemon (void)
 {
     service_count++;
     g_bus_own_name (G_BUS_TYPE_SYSTEM,
@@ -1522,7 +1919,7 @@ start_accounts_service_daemon ()
 }
 
 static void
-run_lightdm ()
+run_lightdm (void)
 {
     GString *command_line;
     gchar **lightdm_argv;
@@ -1531,15 +1928,12 @@ run_lightdm ()
 
     run_commands ();
 
-    status_timeout = g_timeout_add (STATUS_TIMEOUT, status_timeout_cb, NULL);
+    status_timeout = g_timeout_add (status_timeout_ms, status_timeout_cb, NULL);
 
     command_line = g_string_new ("lightdm");
     if (getenv ("DEBUG"))
         g_string_append (command_line, " --debug");
     g_string_append_printf (command_line, " --cache-dir %s/cache", temp_dir);
-    g_string_append_printf (command_line, " --xsessions-dir=%s/usr/share/xsessions", temp_dir);
-    g_string_append_printf (command_line, " --remote-sessions-dir=%s/usr/share/remote-sessions", temp_dir);
-    g_string_append_printf (command_line, " --xgreeters-dir=%s/usr/share/xgreeters", temp_dir);
 
     test_runner_command = g_strdup_printf ("PATH=%s LD_PRELOAD=%s LD_LIBRARY_PATH=%s LIGHTDM_TEST_ROOT=%s DBUS_SESSION_BUS_ADDRESS=%s %s\n",
                                            g_getenv ("PATH"), g_getenv ("LD_PRELOAD"), g_getenv ("LD_LIBRARY_PATH"), g_getenv ("LIGHTDM_TEST_ROOT"), g_getenv ("DBUS_SESSION_BUS_ADDRESS"),
@@ -1575,7 +1969,9 @@ int
 main (int argc, char **argv)
 {
     GMainLoop *loop;
-    gchar *greeter = NULL, *script_name, *config_file, *path, *path1, *path2, *ld_preload, *ld_library_path, *home_dir;
+    int i;
+    gchar *greeter = NULL, *script_name, *config_file, *additional_system_config;
+    gchar *additional_config, *path, *path1, *path2, *ld_preload, *ld_library_path, *home_dir;
     GString *passwd_data, *group_data;
     GSource *status_source;
     gchar cwd[1024];
@@ -1638,22 +2034,30 @@ main (int argc, char **argv)
     g_setenv ("GI_TYPELIB_PATH", path1, TRUE);
     g_free (path1);
 
-    /* Run from a temporary directory */
-    temp_dir = g_build_filename (g_get_tmp_dir (), "lightdm-test-XXXXXX", NULL);
-    if (!mkdtemp (temp_dir))
-    {
-        g_warning ("Error creating temporary directory: %s", strerror (errno));
-        quit (EXIT_FAILURE);
-    }
-    g_chmod (temp_dir, 0755);
+    /* Run in a temporary directory inside the build directory */
+    /* Note we have to pick a name that is short since Unix sockets in this directory have a 108 character limit on their paths */
+    i = 0;
+    while (TRUE) {
+        gchar *name;
+
+        name = g_strdup_printf (".r%d", i);
+        g_free (temp_dir);
+        temp_dir = g_build_filename ("/tmp", name, NULL);
+        g_free (name);
+        if (!g_file_test (temp_dir, G_FILE_TEST_EXISTS))
+            break;
+        i++;
+    }  
+    g_mkdir_with_parents (temp_dir, 0755);
     g_setenv ("LIGHTDM_TEST_ROOT", temp_dir, TRUE);
 
     /* Open socket for status */
-    status_socket_name = g_build_filename (temp_dir, ".status-socket", NULL);
+    /* Note we have to pick a socket name that is short since there is a 108 character limit on the name */
+    status_socket_name = g_build_filename (temp_dir, ".s", NULL);
     unlink (status_socket_name);
     status_socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
     if (error)
-        g_warning ("Error creating status socket: %s", error->message);
+        g_warning ("Error creating status socket %s: %s", status_socket_name, error->message);
     g_clear_error (&error);
     if (status_socket)
     {
@@ -1664,13 +2068,13 @@ main (int argc, char **argv)
         result = g_socket_bind (status_socket, address, FALSE, &error);
         g_object_unref (address);
         if (error)
-            g_warning ("Error binding status socket: %s", error->message);
+            g_warning ("Error binding status socket %s: %s", status_socket_name, error->message);
         g_clear_error (&error);
         if (result)
         {
             result = g_socket_listen (status_socket, &error);
             if (error)
-                g_warning ("Error listening on status socket: %s", error->message);
+                g_warning ("Error listening on status socket %s: %s", status_socket_name, error->message);
             g_clear_error (&error);
         }
         if (!result)
@@ -1688,7 +2092,13 @@ main (int argc, char **argv)
     /* Set up a skeleton file system */
     g_mkdir_with_parents (g_strdup_printf ("%s/etc", temp_dir), 0755);
     g_mkdir_with_parents (g_strdup_printf ("%s/usr/share", temp_dir), 0755);
+    g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/sessions", temp_dir), 0755);
+    g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/remote-sessions", temp_dir), 0755);
+    g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/greeters", temp_dir), 0755);
     g_mkdir_with_parents (g_strdup_printf ("%s/tmp", temp_dir), 0755);
+    g_mkdir_with_parents (g_strdup_printf ("%s/var/lib/lightdm-data", temp_dir), 0755);
+    g_mkdir_with_parents (g_strdup_printf ("%s/var/run", temp_dir), 0755);
+    g_mkdir_with_parents (g_strdup_printf ("%s/var/log", temp_dir), 0755);
 
     /* Copy over the configuration */
     g_mkdir_with_parents (g_strdup_printf ("%s/etc/lightdm", temp_dir), 0755);
@@ -1696,20 +2106,79 @@ main (int argc, char **argv)
         if (system (g_strdup_printf ("cp %s %s/etc/lightdm/lightdm.conf", config_path, temp_dir)))
             perror ("Failed to copy configuration");
 
+    additional_system_config = g_key_file_get_string (config, "test-runner-config", "additional-system-config", NULL);
+    if (additional_system_config)
+    {
+        gchar **files;
+
+        g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/lightdm.conf.d", temp_dir), 0755);
+
+        files = g_strsplit (additional_system_config, " ", -1);
+        for (i = 0; files[i]; i++)
+            if (system (g_strdup_printf ("cp %s/tests/scripts/%s %s/usr/share/lightdm/lightdm.conf.d", SRCDIR, files[i], temp_dir)))
+                perror ("Failed to copy configuration");
+        g_strfreev (files);
+    }
+
+    additional_config = g_key_file_get_string (config, "test-runner-config", "additional-config", NULL);
+    if (additional_config)
+    {
+        gchar **files;
+
+        g_mkdir_with_parents (g_strdup_printf ("%s/etc/lightdm/lightdm.conf.d", temp_dir), 0755);
+
+        files = g_strsplit (additional_config, " ", -1);
+        for (i = 0; files[i]; i++)
+            if (system (g_strdup_printf ("cp %s/tests/scripts/%s %s/etc/lightdm/lightdm.conf.d", SRCDIR, files[i], temp_dir)))
+                perror ("Failed to copy configuration");
+        g_strfreev (files);
+    }
+
+    if (g_key_file_has_key (config, "test-runner-config", "shared-data-dirs", NULL))
+    {
+        gchar *dir_string;
+        gchar **dirs;
+        gint i;
+
+        dir_string = g_key_file_get_string (config, "test-runner-config", "shared-data-dirs", NULL);
+        dirs = g_strsplit (dir_string, " ", -1);
+        g_free (dir_string);
+
+        for (i = 0; dirs[i]; i++)
+        {
+            gchar **fields = g_strsplit (dirs[i], ":", -1);
+            if (g_strv_length (fields) == 4)
+            {
+                gchar *path = g_strdup_printf ("%s/var/lib/lightdm-data/%s", temp_dir, fields[0]);
+                int uid = g_ascii_strtoll (fields[1], NULL, 10);
+                int gid = g_ascii_strtoll (fields[2], NULL, 10);
+                int mode = g_ascii_strtoll (fields[3], NULL, 8);
+                g_mkdir (path, mode);
+                g_chmod (path, mode); /* mkdir filters by umask, so make sure we have what we want */
+                if (chown (path, uid, gid) < 0)
+                  g_warning ("chown (%s) failed: %s", path, strerror (errno));
+                g_free (path);
+            }
+            g_strfreev (fields);
+        }
+
+        g_strfreev (dirs);
+    }
+
     /* Always copy the script */
     if (system (g_strdup_printf ("cp %s %s/script", config_path, temp_dir)))
         perror ("Failed to copy configuration");
 
     /* Copy over the greeter files */
-    if (system (g_strdup_printf ("cp -r %s/xsessions %s/usr/share", DATADIR, temp_dir)))
-        perror ("Failed to copy xsessions");
-    if (system (g_strdup_printf ("cp -r %s/remote-sessions %s/usr/share", DATADIR, temp_dir)))
+    if (system (g_strdup_printf ("cp %s/sessions/* %s/usr/share/lightdm/sessions", DATADIR, temp_dir)))
+        perror ("Failed to copy sessions");
+    if (system (g_strdup_printf ("cp %s/remote-sessions/* %s/usr/share/lightdm/remote-sessions", DATADIR, temp_dir)))
         perror ("Failed to copy remote sessions");
-    if (system (g_strdup_printf ("cp -r %s/xgreeters %s/usr/share", DATADIR, temp_dir)))
-        perror ("Failed to copy xgreeters");
+    if (system (g_strdup_printf ("cp %s/greeters/* %s/usr/share/lightdm/greeters", DATADIR, temp_dir)))
+        perror ("Failed to copy greeters");
 
     /* Set up the default greeter */
-    path = g_build_filename (temp_dir, "usr", "share", "xgreeters", "default.desktop", NULL);
+    path = g_build_filename (temp_dir, "usr", "share", "lightdm", "greeters", "default.desktop", NULL);
     greeter = g_strdup_printf ("%s.desktop", argv[2]);
     if (symlink (greeter, path) < 0)
     {
@@ -1726,87 +2195,85 @@ main (int argc, char **argv)
     {
         gchar *user_name;
         gchar *password;
-        gboolean have_home_dir;
         gchar *real_name;
-        gchar *xsession;
-        gchar *dmrc_layout;
-        gchar *dbus_layouts;
-        gchar *language;
         gint uid;
     } users[] =
     {
         /* Root account */
-        {"root",             "",         TRUE,  "root",               NULL,  NULL, NULL,          NULL,             0},
+        {"root",             "",          "root",                  0},
         /* Unprivileged account for greeters */
-        {"lightdm",          "",         TRUE,  "",                   NULL,  NULL, NULL,          NULL,           100},
+        {"lightdm",          "",          "",                    100},
         /* These accounts have a password */
-        {"have-password1",   "password", TRUE,  "Password User 1",    NULL,  NULL, NULL,          NULL,          1000},
-        {"have-password2",   "password", TRUE,  "Password User 2",    NULL,  NULL, NULL,          NULL,          1001},
-        {"have-password3",   "password", TRUE,  "Password User 3",    NULL,  NULL, NULL,          NULL,          1002},
-        {"have-password4",   "password", TRUE,  "Password User 4",    NULL,  NULL, NULL,          NULL,          1003},
+        {"have-password1",   "password",  "Password User 1",    1000},
+        {"have-password2",   "password",  "Password User 2",    1001},
+        {"have-password3",   "password",  "Password User 3",    1002},
+        {"have-password4",   "password",  "Password User 4",    1003},
         /* This account always prompts for a password, even if using the lightdm-autologin service */
-        {"always-password",  "password", TRUE,  "Password User 4",    NULL,  NULL, NULL,          NULL,          1004},
+        {"always-password",  "password",  "Password User 4",    1004},
         /* These accounts have no password */
-        {"no-password1",     "",         TRUE,  "No Password User 1", NULL,  NULL, NULL,          NULL,          1005},
-        {"no-password2",     "",         TRUE,  "No Password User 2", NULL,  NULL, NULL,          NULL,          1006},
-        {"no-password3",     "",         TRUE,  "No Password User 3", NULL,  NULL, NULL,          NULL,          1007},
-        {"no-password4",     "",         TRUE,  "No Password User 4", NULL,  NULL, NULL,          NULL,          1008},
+        {"no-password1",     "",          "No Password User 1", 1005},
+        {"no-password2",     "",          "No Password User 2", 1006},
+        {"no-password3",     "",          "No Password User 3", 1007},
+        {"no-password4",     "",          "No Password User 4", 1008},
         /* This account has a keyboard layout */
-        {"have-layout",      "",         TRUE,  "Layout User",        NULL,  "us", NULL,          NULL,          1009},
+        {"have-layout",      "",          "Layout User",        1009},
         /* This account has a set of keyboard layouts */
-        {"have-layouts",     "",         TRUE,  "Layouts User",       NULL,  "ru", "fr\toss;ru;", NULL,          1010},
+        {"have-layouts",     "",          "Layouts User",       1010},
         /* This account has a language set */
-        {"have-language",    "",         TRUE,  "Language User",      NULL,  NULL, NULL,          "en_AU.utf8",  1011},
+        {"have-language",    "",          "Language User",      1011},
         /* This account has a preconfigured session */
-        {"have-session",            "",  TRUE,  "Session User", "alternative", NULL, NULL,        NULL,          1012},
+        {"have-session",            "",   "Session User",       1012},
         /* This account has the home directory mounted on login */
-        {"mount-home-dir",   "",         FALSE, "Mounted Home Dir User", NULL, NULL, NULL,        NULL,          1013},
+        {"mount-home-dir",   "",          "Mounted Home Dir User", 1013},
         /* This account is denied access */
-        {"denied",           "",         TRUE,  "Denied User",        NULL,  NULL, NULL,          NULL,          1014},
+        {"denied",           "",          "Denied User",        1014},
         /* This account has expired */
-        {"expired",          "",         TRUE,  "Expired User",       NULL,  NULL, NULL,          NULL,          1015},
+        {"expired",          "",          "Expired User",       1015},
         /* This account needs a password change */
-        {"new-authtok",      "",         TRUE,  "New Token User",     NULL,  NULL, NULL,          NULL,          1016},
+        {"new-authtok",      "",          "New Token User",     1016},
         /* This account is switched to change-user2 when authentication succeeds */
-        {"change-user1",     "",         TRUE,  "Change User 1",      NULL,  NULL, NULL,          NULL,          1017},
-        {"change-user2",     "",         TRUE,  "Change User 2",      NULL,  NULL, NULL,          NULL,          1018},
+        {"change-user1",     "",          "Change User 1",      1017},
+        {"change-user2",     "",          "Change User 2",      1018},
         /* This account switches to invalid-user when authentication succeeds */
-        {"change-user-invalid", "",      TRUE,  "Invalid Change User",NULL,  NULL, NULL,          NULL,          1019},
+        {"change-user-invalid", "",       "Invalid Change User", 1019},
         /* This account crashes on authentication */
-        {"crash-authenticate", "",       TRUE,  "Crash Auth User",    NULL,  NULL, NULL,          NULL,          1020},
+        {"crash-authenticate", "",        "Crash Auth User",    1020},
         /* This account shows an informational prompt on login */
-        {"info-prompt",      "password", TRUE,  "Info Prompt",        NULL,  NULL, NULL,          NULL,          1021},
+        {"info-prompt",      "password",  "Info Prompt",        1021},
         /* This account shows multiple informational prompts on login */
-        {"multi-info-prompt","password", TRUE,  "Multi Info Prompt",  NULL,  NULL, NULL,          NULL,          1022},
+        {"multi-info-prompt","password",  "Multi Info Prompt",  1022},
         /* This account uses two factor authentication */
-        {"two-factor",       "password", TRUE,  "Two Factor",         NULL,  NULL, NULL,          NULL,          1023},
+        {"two-factor",       "password",  "Two Factor",         1023},
         /* This account has a special group */
-        {"group-member",     "password", TRUE,  "Group Member",       NULL,  NULL, NULL,          NULL,          1024},
+        {"group-member",     "password",  "Group Member",       1024},
         /* This account has the home directory created when the session starts */
-        {"make-home-dir",    "",         FALSE, "Make Home Dir User", NULL,  NULL, NULL,          NULL,          1025},
+        {"make-home-dir",    "",          "Make Home Dir User", 1025},
         /* This account fails to open a session */
-        {"session-error",    "password", TRUE,  "Session Error",      NULL,  NULL, NULL,          NULL,          1026},
+        {"session-error",    "password",  "Session Error",      1026},
         /* This account can't establish credentials */
-        {"cred-error",       "password", TRUE,  "Cred Error",         NULL,  NULL, NULL,          NULL,          1027},
+        {"cred-error",       "password",  "Cred Error",         1027},
         /* This account has expired credentials */
-        {"cred-expired",     "password", TRUE,  "Cred Expired",       NULL,  NULL, NULL,          NULL,          1028},
+        {"cred-expired",     "password",  "Cred Expired",       1028},
         /* This account has cannot access their credentials */
-        {"cred-unavail",     "password", TRUE,  "Cred Unavail",       NULL,  NULL, NULL,          NULL,          1029},
+        {"cred-unavail",     "password",  "Cred Unavail",       1029},
         /* This account sends informational messages for each PAM function that is called */
-        {"log-pam",          "password", TRUE,  "Log PAM",            NULL,  NULL, NULL,          NULL,          1030},
+        {"log-pam",          "password",  "Log PAM",            1030},
         /* This account shows multiple prompts on login */
-        {"multi-prompt",     "password", TRUE,  "Multi Prompt",       NULL,  NULL, NULL,          NULL,          1031},
-        {NULL,               NULL,       FALSE, NULL,                 NULL,  NULL, NULL,          NULL,             0}
+        {"multi-prompt",     "password",  "Multi Prompt",       1031},
+        /* This account has an existing corrupt X authority */
+        {"corrupt-xauth",    "password",  "Corrupt Xauthority", 1032},
+        /* User to test properties */
+        {"prop-user",        "",          "TEST",               1033},
+        {NULL,               NULL,        NULL,                    0}
     };
     passwd_data = g_string_new ("");
     group_data = g_string_new ("");
-    int i;
     for (i = 0; users[i].user_name; i++)
     {
         GKeyFile *dmrc_file;
         gboolean save_dmrc = FALSE;
 
-        if (users[i].have_home_dir)
+        if (strcmp (users[i].user_name, "mount-home-dir") != 0 && strcmp (users[i].user_name, "make-home-dir") != 0)
         {
             path = g_build_filename (home_dir, users[i].user_name, NULL);
             g_mkdir_with_parents (path, 0755);
@@ -1816,25 +2283,25 @@ main (int argc, char **argv)
         }
 
         dmrc_file = g_key_file_new ();
-        if (users[i].xsession)
+        if (strcmp (users[i].user_name, "have-session") == 0)
         {
-            g_key_file_set_string (dmrc_file, "Desktop", "Session", users[i].xsession);
+            g_key_file_set_string (dmrc_file, "Desktop", "Session", "alternative");
             save_dmrc = TRUE;
         }
-        if (users[i].dmrc_layout)
+        if (strcmp (users[i].user_name, "have-layout") == 0)
         {
-            g_key_file_set_string (dmrc_file, "Desktop", "Layout", users[i].dmrc_layout);
+            g_key_file_set_string (dmrc_file, "Desktop", "Layout", "us");
             save_dmrc = TRUE;
         }
-        if (users[i].dbus_layouts)
+        if (strcmp (users[i].user_name, "have-layouts") == 0)
         {
-            g_key_file_set_string (dmrc_file, "X-Accounts", "Layouts", users[i].dbus_layouts);
+            g_key_file_set_string (dmrc_file, "Desktop", "Layout", "ru");
+            g_key_file_set_string (dmrc_file, "X-Accounts", "Layouts", "fr\toss;ru;");
             save_dmrc = TRUE;
-
         }
-        if (users[i].language)
+        if (strcmp (users[i].user_name, "have-language") == 0)
         {
-            g_key_file_set_string (dmrc_file, "Desktop", "Language", users[i].language);
+            g_key_file_set_string (dmrc_file, "Desktop", "Language", "en_AU.utf8");
             save_dmrc = TRUE;
         }
 
@@ -1851,6 +2318,17 @@ main (int argc, char **argv)
 
         g_key_file_free (dmrc_file);
 
+        /* Write corrupt X authority file */
+        if (strcmp (users[i].user_name, "corrupt-xauth") == 0)
+        {
+            gchar data[1] = { 0xFF };
+
+            path = g_build_filename (home_dir, users[i].user_name, ".Xauthority", NULL);
+            g_file_set_contents (path, data, 1, NULL);
+            chmod (path, S_IRUSR | S_IWUSR);
+            g_free (path);
+        }
+
         /* Add passwd file entry */
         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);
 
@@ -1870,6 +2348,9 @@ main (int argc, char **argv)
     g_free (path);
     g_string_free (group_data, TRUE);
 
+    if (g_key_file_has_key (config, "test-runner-config", "timeout", NULL))
+        status_timeout_ms = g_key_file_get_integer (config, "test-runner-config", "timeout", NULL) * 1000;
+
     /* Start D-Bus services */
     if (!g_key_file_get_boolean (config, "test-runner-config", "disable-upower", NULL))
         start_upower_daemon ();