Sisyphus
: 1 2023 | : 18631 | : 37533752
en ru br
ALT

:: /
: accountsservice

             Sources      Gear   Bugs and FR  Repocop 

: accountsservice-23.13.9.patch



 generate-version.sh                                |   3 +-
 meson.build                                        |   5 +
 meson_options.txt                                  |   1 +
 po/cs.po                                           |  53 ++-
 po/ru.po                                           |  53 ++-
 src/daemon.c                                       |  41 ++-
 src/libaccountsservice/act-user-manager.c          |  14 +-
 src/user-classify.c                                |   2 +
 subprojects/mocklibc.wrap                          |   2 +
 .../packagefiles/mocklibc-print-indent.diff        |  13 +
 tests/dbusmock/accounts_service.py                 | 393 ---------------------
 tests/mock_services/accounts_service.py            | 393 +++++++++++++++++++++
 tests/test-libaccountsservice.py                   |   4 +-
 13 files changed, 531 insertions(+), 446 deletions(-)
diff --git a/generate-version.sh b/generate-version.sh
index 3f88bff..8375c86 100755
--- a/generate-version.sh
+++ b/generate-version.sh
@@ -4,11 +4,10 @@ exec 3>&2 2> /dev/null
 SRCDIR=$(dirname "$0")
 cd "$SRCDIR"
 CWD=$(realpath "$PWD")
-TOPLEVEL_WORKING_DIR=$(realpath "$(git rev-parse --show-toplevel)")
 exec 2>&3
 
 # If it's not from a git checkout, assume it's from a tarball
-if [ "$TOPLEVEL_WORKING_DIR" != "$CWD" ]; then
+if ! git rev-parse --is-inside-git-dir > /dev/null 2>&1; then
     VERSION_FROM_DIR_NAME=$(basename "$CWD" | sed -n 's/^accountsservice-\([^-]*\)$/\1/p')
 
     if [ -n "$VERSION_FROM_DIR_NAME" ]; then
diff --git a/meson.build b/meson.build
index 4a509e7..04455f6 100644
--- a/meson.build
+++ b/meson.build
@@ -198,6 +198,10 @@ if admin_group == ''
   endif
 endif
 
+default_user_groups = ','.join(get_option('default_user_groups'))
+
+config_h.set_quoted('DEFAULT_USER_GROUPS', default_user_groups)
+
 extra_admin_groups = ','.join(get_option('extra_admin_groups'))
 
 config_h.set_quoted('ADMIN_GROUP', admin_group)
@@ -247,6 +251,7 @@ meson.add_install_script(
 output = '\n' + meson.project_name() + ' was configured with the following options:\n'
 output += '** DocBook documentation build: ' + enable_docbook.to_string() + '\n'
 output += '** Administrator group: ' + admin_group + '\n'
+output += '** Default user groups: ' + default_user_groups + '\n'
 output += '** Extra administrator groups: ' + extra_admin_groups + '\n'
 output += '** GDM configuration: ' + gdm_conf_file + '\n'
 output += '** LightDM configuration: ' + lightdm_conf_file
diff --git a/meson_options.txt b/meson_options.txt
index b34a0fa..47cc9c9 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -4,6 +4,7 @@ option('lightdmconffile', type: 'string', value: '/etc/lightdm/lightdm.conf', de
 
 option('admin_group', type: 'string', value: '', description: 'Set group for administrative accounts')
 option('extra_admin_groups', type: 'array', value: [], description: 'Comma-separated list of extra groups that administrator users are part of')
+option('default_user_groups', type: 'array', value: [], description: 'Comma-separated list of groups that all users are part of by default')
 option('minimum_uid', type: 'integer', value: 1000, description: 'Set minimum uid for human users')
 
 option('elogind', type: 'boolean', value: false, description: 'Use elogind')
diff --git a/po/cs.po b/po/cs.po
index 7cdc2b4..c948c99 100644
--- a/po/cs.po
+++ b/po/cs.po
@@ -1,62 +1,77 @@
 # SOME DESCRIPTIVE TITLE.
 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 # This file is distributed under the same license as the PACKAGE package.
-# 
+#
 # Translators:
 # Marek Černocký <marek@manet.cz>, 2011
 # Ondrej Novak <novak@linux.com>, 2011
+# Daniel Rusek <mail@asciiwolf.com>, 2023
 msgid ""
 msgstr ""
 "Project-Id-Version: accounts service\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2013-01-17 09:48-0500\n"
-"PO-Revision-Date: 2019-02-22 14:19+0000\n"
-"Last-Translator: halfline <halfline@gmail.com>\n"
-"Language-Team: Czech (http://www.transifex.com/freedesktop/accountsservice/language/cs/)\n"
+"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/accountsservice/"
+"accountsservice/issues\n"
+"POT-Creation-Date: 2022-07-31 12:33+0000\n"
+"PO-Revision-Date: 2023-05-31 15:16+0200\n"
+"Last-Translator: Daniel Rusek <mail@asciiwolf.com>\n"
+"Language-Team: Czech (http://www.transifex.com/freedesktop/accountsservice/"
+"language/cs/)\n"
+"Language: cs\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Language: cs\n"
-"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n"
+"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n "
+"<= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n"
+"X-Generator: Poedit 3.3.1\n"
 
-#: ../data/org.freedesktop.accounts.policy.in.h:1
+#: data/org.freedesktop.accounts.policy.in:11
 msgid "Change your own user data"
 msgstr "Změnit své vlastní údaje"
 
-#: ../data/org.freedesktop.accounts.policy.in.h:2
+#: data/org.freedesktop.accounts.policy.in:12
 msgid "Authentication is required to change your own user data"
 msgstr "Pro změnu svých vlastních údajů je vyžadována autentizace"
 
-#: ../data/org.freedesktop.accounts.policy.in.h:3
+#: data/org.freedesktop.accounts.policy.in:21
+msgid "Change your own user password"
+msgstr "Změnit své vlastní heslo"
+
+#: data/org.freedesktop.accounts.policy.in:22
+msgid "Authentication is required to change your own user password"
+msgstr "Pro změnu svého vlastního hesla je vyžadována autentizace"
+
+#: data/org.freedesktop.accounts.policy.in:31
 msgid "Manage user accounts"
 msgstr "Spravovat uživatelské účty"
 
-#: ../data/org.freedesktop.accounts.policy.in.h:4
+#: data/org.freedesktop.accounts.policy.in:32
 msgid "Authentication is required to change user data"
 msgstr "Pro změnu údajů o uživateli je vyžadována autentizace"
 
-#: ../data/org.freedesktop.accounts.policy.in.h:5
+#: data/org.freedesktop.accounts.policy.in:41
 msgid "Change the login screen configuration"
 msgstr "Změnit nastavení přihlašovací obrazovky"
 
-#: ../data/org.freedesktop.accounts.policy.in.h:6
+#: data/org.freedesktop.accounts.policy.in:42
 msgid "Authentication is required to change the login screen configuration"
 msgstr "Pro změnu nastavení přihlašovací obrazovky je vyžadována autentizace"
 
-#: ../src/main.c:127
+#: src/main.c:225
 msgid "Output version information and exit"
 msgstr "Zobrazit informace o verzi a ukončit program"
 
-#: ../src/main.c:128
+#: src/main.c:226
 msgid "Replace existing instance"
 msgstr "Nahradit současnou instanci"
 
-#: ../src/main.c:129
+#: src/main.c:227
 msgid "Enable debugging code"
 msgstr "Povolit ladicí kód"
 
-#: ../src/main.c:149
+#: src/main.c:246
 msgid ""
 "Provides D-Bus interfaces for querying and manipulating\n"
 "user account information."
-msgstr "Poskytuje rozhraní D-Bus pro zobrazování a změny\ninformací o uživatelských účtech"
+msgstr ""
+"Poskytuje rozhraní D-Bus pro zobrazování a změny\n"
+"informací o uživatelských účtech"
diff --git a/po/ru.po b/po/ru.po
index 58d173a..5040794 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -1,61 +1,76 @@
 # SOME DESCRIPTIVE TITLE.
 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 # This file is distributed under the same license as the PACKAGE package.
-# 
+#
 # Translators:
 # Yuri Kozlov <yuray@komyakino.ru>, 2011
 msgid ""
 msgstr ""
 "Project-Id-Version: accounts service\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2013-01-17 09:48-0500\n"
-"PO-Revision-Date: 2019-02-22 14:19+0000\n"
-"Last-Translator: halfline <halfline@gmail.com>\n"
-"Language-Team: Russian (http://www.transifex.com/freedesktop/accountsservice/language/ru/)\n"
+"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/accountsservice/"
+"accountsservice/issues\n"
+"POT-Creation-Date: 2022-07-31 12:33+0000\n"
+"PO-Revision-Date: 2023-04-08 17:12+0300\n"
+"Last-Translator: Aleksandr Melman <Alexmelman88@gmail.com>\n"
+"Language-Team: Russian (http://www.transifex.com/freedesktop/accountsservice/"
+"language/ru/)\n"
+"Language: ru\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Language: ru\n"
-"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
+"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
+"n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || "
+"(n%100>=11 && n%100<=14)? 2 : 3);\n"
+"X-Generator: Poedit 3.2.2\n"
 
-#: ../data/org.freedesktop.accounts.policy.in.h:1
+#: data/org.freedesktop.accounts.policy.in:11
 msgid "Change your own user data"
 msgstr "Изменить личные пользовательские данные"
 
-#: ../data/org.freedesktop.accounts.policy.in.h:2
+#: data/org.freedesktop.accounts.policy.in:12
 msgid "Authentication is required to change your own user data"
 msgstr "Для изменения личных пользовательских данных требуется аутентификация"
 
-#: ../data/org.freedesktop.accounts.policy.in.h:3
+#: data/org.freedesktop.accounts.policy.in:21
+msgid "Change your own user password"
+msgstr "Изменить личный пароль пользователя"
+
+#: data/org.freedesktop.accounts.policy.in:22
+msgid "Authentication is required to change your own user password"
+msgstr "Для изменения личного пароля пользователя требуется аутентификация"
+
+#: data/org.freedesktop.accounts.policy.in:31
 msgid "Manage user accounts"
 msgstr "Управление учётными записями пользователей"
 
-#: ../data/org.freedesktop.accounts.policy.in.h:4
+#: data/org.freedesktop.accounts.policy.in:32
 msgid "Authentication is required to change user data"
 msgstr "Для изменения пользовательских данных требуется аутентификация"
 
-#: ../data/org.freedesktop.accounts.policy.in.h:5
+#: data/org.freedesktop.accounts.policy.in:41
 msgid "Change the login screen configuration"
 msgstr "Изменить настройки экрана входа в систему"
 
-#: ../data/org.freedesktop.accounts.policy.in.h:6
+#: data/org.freedesktop.accounts.policy.in:42
 msgid "Authentication is required to change the login screen configuration"
 msgstr "Для изменения настроек экрана входа в систему требуется аутентификация"
 
-#: ../src/main.c:127
+#: src/main.c:225
 msgid "Output version information and exit"
 msgstr "Вывод информации о версии и выход из программы"
 
-#: ../src/main.c:128
+#: src/main.c:226
 msgid "Replace existing instance"
 msgstr "Заменить существующий экземпляр"
 
-#: ../src/main.c:129
+#: src/main.c:227
 msgid "Enable debugging code"
 msgstr "Включить отладочный код"
 
-#: ../src/main.c:149
+#: src/main.c:246
 msgid ""
 "Provides D-Bus interfaces for querying and manipulating\n"
 "user account information."
-msgstr "Предоставляет интерфейс D-Bus для опроса и изменения\nинформации об учётных данных пользователей."
+msgstr ""
+"Предоставляет интерфейс D-Bus для опроса и изменения\n"
+"информации об учётных данных пользователей."
diff --git a/src/daemon.c b/src/daemon.c
index aa9d050..6e36795 100644
--- a/src/daemon.c
+++ b/src/daemon.c
@@ -1311,6 +1311,7 @@ daemon_create_user_authorized_cb (Daemon                *daemon,
         g_autoptr (GError) error = NULL;
         const gchar *argv[9];
         g_autofree gchar *admin_groups = NULL;
+        g_autofree gchar *user_groups = NULL;
 
         if (getpwnam (cd->user_name) != NULL) {
                 throw_error (context, ERROR_USER_EXISTS, "A user with name '%s' already exists", cd->user_name);
@@ -1323,11 +1324,32 @@ daemon_create_user_authorized_cb (Daemon                *daemon,
         argv[1] = "-m";
         argv[2] = "-c";
         argv[3] = cd->real_name;
+
+        /* Build default user groups */
+        g_auto (GStrv) user_groups_array = NULL;
+        g_autoptr (GStrvBuilder) user_groups_builder = g_strv_builder_new ();
+
+        if (DEFAULT_USER_GROUPS != NULL && DEFAULT_USER_GROUPS[0] != '\0') {
+                g_auto (GStrv) default_user_groups = NULL;
+                default_user_groups = g_strsplit (DEFAULT_USER_GROUPS, ",", 0);
+
+                for (gsize i = 0; default_user_groups[i] != NULL; i++) {
+                        if (getgrnam (default_user_groups[i]) != NULL)
+                                g_strv_builder_add (user_groups_builder, default_user_groups[i]);
+                        else
+                                g_warning ("Group %s doesn’t exist: not adding the user to it", default_user_groups[i]);
+                }
+        }
+        user_groups_array = g_strv_builder_end (user_groups_builder);
+        user_groups = g_strjoinv (",", user_groups_array);
+
         if (cd->account_type == ACCOUNT_TYPE_ADMINISTRATOR) {
                 g_auto (GStrv) admin_groups_array = NULL;
                 g_autoptr (GStrvBuilder) admin_groups_builder = g_strv_builder_new ();
 
                 g_strv_builder_add (admin_groups_builder, ADMIN_GROUP);
+                /* Add default user groups to admin groups */
+                g_strv_builder_add (admin_groups_builder, user_groups);
 
                 if (EXTRA_ADMIN_GROUPS != NULL && EXTRA_ADMIN_GROUPS[0] != '\0') {
                         g_auto (GStrv) extra_admin_groups = NULL;
@@ -1340,6 +1362,7 @@ daemon_create_user_authorized_cb (Daemon                *daemon,
                                         g_warning ("Extra admin group %s doesn’t exist: not adding the user to it", extra_admin_groups[i]);
                         }
                 }
+
                 admin_groups_array = g_strv_builder_end (admin_groups_builder);
                 admin_groups = g_strjoinv (",", admin_groups_array);
 
@@ -1349,9 +1372,11 @@ daemon_create_user_authorized_cb (Daemon                *daemon,
                 argv[7] = cd->user_name;
                 argv[8] = NULL;
         } else if (cd->account_type == ACCOUNT_TYPE_STANDARD) {
-                argv[4] = "--";
-                argv[5] = cd->user_name;
-                argv[6] = NULL;
+                argv[4] = "-G";
+                argv[5] = user_groups;
+                argv[6] = "--";
+                argv[7] = cd->user_name;
+                argv[8] = NULL;
         } else {
                 throw_error (context, ERROR_FAILED, "Don't know how to add user of type %d", cd->account_type);
                 return;
@@ -1803,9 +1828,8 @@ load_autologin (Daemon   *daemon,
         else if (dm_type == DISPLAY_MANAGER_TYPE_GDM)
                 return load_autologin_gdm (daemon, name, enabled, error);
 
-        g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _ ("Unsupported Display Manager"));
-
-        return FALSE;
+        /* Default to GDM for backward compatibility */
+        return load_autologin_gdm (daemon, name, enabled, error);
 }
 
 static gboolean
@@ -1824,7 +1848,7 @@ save_autologin_gdm (Daemon      *daemon,
                                         PATH_GDM_CUSTOM,
                                         G_KEY_FILE_KEEP_COMMENTS,
                                         &local_error)) {
-                /* It's OK for custom.conf to not exist, we will make it */
+                /* It's OK if the GDM config file doesn't exist, since we will make it, if necessary */
                 if (!g_error_matches (local_error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) {
                         g_propagate_error (error, g_steal_pointer (&local_error));
                         return FALSE;
@@ -1885,7 +1909,8 @@ save_autologin (Daemon      *daemon,
         else if (dm_type == DISPLAY_MANAGER_TYPE_GDM)
                 return save_autologin_gdm (daemon, name, enabled, error);
 
-        return FALSE;
+        /* Default to GDM for backward compatibility */
+        return save_autologin_gdm (daemon, name, enabled, error);
 }
 
 gboolean
diff --git a/src/libaccountsservice/act-user-manager.c b/src/libaccountsservice/act-user-manager.c
index 61b4da5..7afe713 100644
--- a/src/libaccountsservice/act-user-manager.c
+++ b/src/libaccountsservice/act-user-manager.c
@@ -153,6 +153,7 @@ typedef struct
         };
         char                              *object_path;
         char                              *description;
+        gulong                             ready_id;
 } ActUserManagerFetchUserRequest;
 
 typedef struct
@@ -717,6 +718,8 @@ on_user_destroyed (ActUserManager *manager,
         ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
         GSList *node;
 
+        priv->new_users = g_slist_remove (priv->new_users, destroyed_user);
+
         node = priv->fetch_user_requests;
         while (node != NULL) {
                 ActUserManagerFetchUserRequest *request;
@@ -1754,6 +1757,7 @@ load_new_session_incrementally (ActUserManagerNewSession *new_session)
                 break;
         case ACT_USER_MANAGER_NEW_SESSION_STATE_LOADED:
                 break;
+        case ACT_USER_MANAGER_NEW_SESSION_STATE_UNLOADED:
         default:
                 g_assert_not_reached ();
         }
@@ -1781,6 +1785,7 @@ free_fetch_user_request (ActUserManagerFetchUserRequest *request)
         g_cancellable_cancel (request->cancellable);
         g_object_unref (request->cancellable);
 
+        g_clear_signal_handler (&request->ready_id, manager);
 
         g_debug ("ActUserManager: unrefing manager owned by fetch user request");
         g_object_unref (manager);
@@ -1823,7 +1828,7 @@ on_user_manager_maybe_ready_for_request (ActUserManager                 *manager
         g_debug ("ActUserManager: user manager now loaded, proceeding with fetch user request for %s",
                  request->description);
 
-        g_signal_handlers_disconnect_by_func (manager, on_user_manager_maybe_ready_for_request, request);
+        g_clear_signal_handler (&request->ready_id, manager);
 
         request->state++;
         fetch_user_incrementally (request);
@@ -1845,8 +1850,10 @@ fetch_user_incrementally (ActUserManagerFetchUserRequest *request)
                 } else {
                         g_debug ("ActUserManager: waiting for user manager to load before finding %s",
                                  request->description);
-                        g_signal_connect (manager, "notify::is-loaded",
-                                          G_CALLBACK (on_user_manager_maybe_ready_for_request), request);
+                        g_assert (request->ready_id == 0);
+                        request->ready_id =
+                                g_signal_connect (manager, "notify::is-loaded",
+                                                  G_CALLBACK (on_user_manager_maybe_ready_for_request), request);
                 }
                 break;
 
@@ -2270,6 +2277,7 @@ load_seat_incrementally (ActUserManager *manager)
         case ACT_USER_MANAGER_SEAT_STATE_LOADED:
                 g_debug ("ActUserManager: Seat loading sequence complete");
                 break;
+        case ACT_USER_MANAGER_NEW_SESSION_STATE_UNLOADED:
         default:
                 g_assert_not_reached ();
         }
diff --git a/src/user-classify.c b/src/user-classify.c
index 2a38a77..ef8b864 100644
--- a/src/user-classify.c
+++ b/src/user-classify.c
@@ -108,6 +108,8 @@ is_invalid_shell (const char *shell)
                 return TRUE;
         } else if (g_strcmp0 (basename, "false") == 0) {
                 return TRUE;
+        } else if (g_strcmp0 (basename, "null") == 0) {
+                return TRUE;
         }
 
         return ret;
diff --git a/subprojects/mocklibc.wrap b/subprojects/mocklibc.wrap
index af82298..539ee83 100644
--- a/subprojects/mocklibc.wrap
+++ b/subprojects/mocklibc.wrap
@@ -8,3 +8,5 @@ source_hash = b2236a6af1028414783e9734a46ea051916ec226479d6a55a3bb823bff68f120
 patch_url = https://wrapdb.mesonbuild.com/v1/projects/mocklibc/1.0/2/get_zip
 patch_filename = mocklibc-1.0-2-wrap.zip
 patch_hash = 0280f96a2eeb3c023e5acf4e00cef03d362868218d4a85347ea45137c0ef6c56
+
+diff_files = mocklibc-print-indent.diff
diff --git a/subprojects/packagefiles/mocklibc-print-indent.diff b/subprojects/packagefiles/mocklibc-print-indent.diff
new file mode 100644
index 0000000..4aaed40
--- /dev/null
+++ b/subprojects/packagefiles/mocklibc-print-indent.diff
@@ -0,0 +1,13 @@
+diff -up mocklibc-1.0/src/netgroup-debug.c.print-indent mocklibc-1.0/src/netgroup-debug.c
+--- mocklibc-1.0/src/netgroup-debug.c.print-indent	2023-04-11 10:20:53.717381559 -0400
++++ mocklibc-1.0/src/netgroup-debug.c	2023-04-11 10:21:02.296270333 -0400
+@@ -21,6 +21,9 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ 
++void print_indent (FILE        *stream,
++                   unsigned int indent);
++
+ void netgroup_debug_print_entry(struct entry *entry, FILE *stream, unsigned int indent) {
+   print_indent(stream, indent);
+ 
diff --git a/tests/dbusmock/accounts_service.py b/tests/dbusmock/accounts_service.py
deleted file mode 100644
index 6f36efe..0000000
--- a/tests/dbusmock/accounts_service.py
+++ /dev/null
@@ -1,393 +0,0 @@
-'''Accounts Service D-Bus mock template'''
-
-# This program is free software; you can redistribute it and/or modify it under
-# the terms of the GNU Lesser General Public License as published by the Free
-# Software Foundation; either version 3 of the License, or (at your option) any
-# later version.  See http://www.gnu.org/copyleft/lgpl.html for the full text
-# of the license.
-
-__author__ = 'Marco Trevisan'
-__email__ = 'marco.trevisan@canonical.com'
-__copyright__ = '(c) 2021 Canonical Ltd.'
-__license__ = 'LGPL 3+'
-
-import sys
-import time
-
-import dbus
-from dbusmock import MOCK_IFACE, mockobject
-
-BUS_NAME = 'org.freedesktop.Accounts'
-MAIN_OBJ = '/org/freedesktop/Accounts'
-MAIN_IFACE = 'org.freedesktop.Accounts'
-USER_IFACE = MAIN_IFACE + '.User'
-SYSTEM_BUS = True
-
-DEFAULT_USER_PASSWORD = 'Pa$$wo0rd'
-
-
-def get_user_path(uid):
-    return '/org/freedesktop/Accounts/User{}'.format(uid)
-
-
-def load(mock, parameters=None):
-    parameters = parameters if parameters else {}
-    mock.mock_users = {}
-    mock.cached_users = []
-    mock.automatic_login_users = set()
-    mock.users_auto_uids = 2000
-
-    mock.AddProperties(MAIN_IFACE, mock.GetAll(MAIN_IFACE))
-
-    for uid, name in parameters.get('users', {}).items():
-        mock.AddUser(uid, name, DEFAULT_USER_PASSWORD, {}, {})
-
-def emit_properties_changed(mock, interface=MAIN_IFACE, properties=None):
-    if properties is None:
-        properties = mock.GetAll(interface)
-    elif isinstance(properties, str):
-        properties = [properties]
-
-    if isinstance(properties, (list, set)):
-        properties = {p: mock.Get(interface, p) for p in properties}
-    elif not isinstance(properties, dict):
-        raise TypeError('Unsupported properties type')
-
-    mock.EmitSignal(dbus.PROPERTIES_IFACE, 'PropertiesChanged', 'sa{sv}as', (
-        interface, properties, []))
-
-
-@dbus.service.method(MOCK_IFACE, in_signature='xssa{sv}a{sv}',
-                     out_signature='o')
-def AddUser(self, uid, username, password=DEFAULT_USER_PASSWORD,
-            overrides=None, password_policy_overrides=None):
-    '''Add user via uid and username and optionally overriding properties
-
-    Returns the new object path.
-   '''
-    path = get_user_path(uid)
-    default_props = {
-        'Uid': dbus.UInt64(uid),
-        'UserName': username,
-        'RealName': username[0].upper() + username[1:] + ' Fake',
-        'AccountType': dbus.Int32(1),
-        'AutomaticLogin': False,
-        'BackgroundFile': '',
-        'Email': '{}@python-dbusmock.org'.format(username),
-        'FormatsLocale': 'C',
-        'HomeDirectory': '/nonexisting/mock-home/{}'.format(username),
-        'IconFile': '',
-        'InputSources': dbus.Array([], signature='a{ss}'),
-        'Language': 'C',
-        'Languages': dbus.Array([], signature='s'),
-        'LocalAccount': True,
-        'Location': '',
-        'Locked': False,
-        'LoginFrequency': dbus.UInt64(0),
-        'LoginHistory': dbus.Array([], signature='(xxa{sv})'),
-        'LoginTime': dbus.Int64(0),
-        'PasswordHint': 'Remember it, come on!',
-        'PasswordMode': 0,
-        'Session': 'mock-session',
-        'SessionType': 'wayland',
-        'Shell': '/usr/bin/zsh',
-        'SystemAccount': False,
-        'XHasMessages': False,
-        'XKeyboardLayouts': dbus.Array([], signature='s'),
-        'XSession': 'mock-xsession',
-    }
-    default_props.update(overrides if overrides else {})
-    self.AddObject(path, USER_IFACE, default_props, [])
-
-    had_users = len(self.mock_users) != 0
-    had_multiple_users = len(self.mock_users) > 1
-    user = mockobject.objects[path]
-    user.password = password
-    user.properties = default_props
-    user.pwd_expiration_policy = {
-        'expiration_time': sys.maxsize,
-        'last_change_time': int(time.time()),
-        'min_days_between_changes': 0,
-        'max_days_between_changes': 0,
-        'days_to_warn': 0,
-        'days_after_expiration_until_lock': 0,
-    }
-    user.pwd_expiration_policy.update(
-        password_policy_overrides if password_policy_overrides else {})
-    self.mock_users[uid] = default_props
-
-    self.EmitSignal(MAIN_IFACE, 'UserAdded', 'o', [path])
-
-    if not had_users:
-        emit_properties_changed(self, MAIN_IFACE, 'HasNoUsers')
-    elif not had_multiple_users and len(self.mock_users) > 1:
-        emit_properties_changed(self, MAIN_IFACE, 'HasMultipleUsers')
-
-    return path
-
-
-@dbus.service.method(MOCK_IFACE, in_signature='', out_signature='ao')
-def ListMockUsers(self):
-    """ List the mock users that have been created """
-    return [get_user_path(uid) for uid in self.mock_users.keys()]
-
-
-@dbus.service.method(MOCK_IFACE, in_signature='s', out_signature='o')
-def AddAutoLoginUser(self, username):
-    """ Enable autologin for an user """
-    path = self.FindUserByName(username)
-    self.automatic_login_users.add(path)
-    user = mockobject.objects[path]
-    set_user_property(user, 'AutomaticLogin', True)
-    emit_properties_changed(self, MAIN_IFACE, 'AutomaticLoginUsers')
-    return path
-
-
-@dbus.service.method(MOCK_IFACE, in_signature='s', out_signature='o')
-def RemoveAutoLoginUser(self, username):
-    """ Disables autologin for an user """
-    path = self.FindUserByName(username)
-    self.automatic_login_users.remove(path)
-    user = mockobject.objects[path]
-    set_user_property(user, 'AutomaticLogin', False)
-    emit_properties_changed(self, MAIN_IFACE, 'AutomaticLoginUsers')
-    return path
-
-
-@dbus.service.method(MAIN_IFACE, in_signature='ssi', out_signature='o')
-def CreateUser(self, name, fullname, account_type):
-    """ Creates an user using the default API """
-    try:
-        self.FindUserByName(name)
-        found = True
-    except dbus.exceptions.DBusException:
-        found = False
-
-    if found:
-        raise dbus.exceptions.DBusException(
-            'User {} already exists'.format(name),
-            name='org.freedesktop.Accounts.Error.Failed')
-
-    self.users_auto_uids += 1
-
-    return self.AddUser(self.users_auto_uids, name, DEFAULT_USER_PASSWORD, {
-        'RealName': fullname, 'AccountType': account_type}, {})
-
-
-@dbus.service.method(MAIN_IFACE, in_signature='xb')
-def DeleteUser(self, uid, _remove_files):
-    """ Removes a created user """
-    path = self.FindUserById(uid)
-
-    had_multiple_users = len(self.mock_users) > 1
-    self.RemoveObject(path)
-    self.mock_users.pop(uid)
-    self.automatic_login_users.discard(path)
-
-    self.EmitSignal(MAIN_IFACE, 'UserDeleted', 'o', [path])
-
-    if len(self.mock_users) == 0:
-        emit_properties_changed(self, MAIN_IFACE, 'HasNoUsers')
-    elif had_multiple_users and len(self.mock_users) < 2:
-        emit_properties_changed(self, MAIN_IFACE, 'HasMultipleUsers')
-
-
-@dbus.service.method(MAIN_IFACE, in_signature='s', out_signature='o')
-def CacheUser(self, username):
-    """ Cache an user """
-    path = self.FindUserByName(username)
-    self.cached_users.append(path)
-    return path
-
-
-@dbus.service.method(MAIN_IFACE, in_signature='s')
-def UncacheUser(self, username):
-    """ Removes an user from the cache """
-    path = self.FindUserByName(username)
-    self.cached_users.remove(path)
-
-
-@dbus.service.method(MAIN_IFACE, in_signature='', out_signature='ao')
-def ListCachedUsers(self):
-    """ Lists the cached users """
-    return self.cached_users
-
-
-@dbus.service.method(MAIN_IFACE, in_signature='x', out_signature='o')
-def FindUserById(_self, uid):
-    """ Finds an user by its user id """
-    user = mockobject.objects.get(get_user_path(uid), None)
-    if not user:
-        raise dbus.exceptions.DBusException(
-            'No such user exists',
-            name='org.freedesktop.Accounts.Error.Failed')
-    return get_user_path(uid)
-
-
-@dbus.service.method(MAIN_IFACE, in_signature='s', out_signature='o')
-def FindUserByName(self, username):
-    """ Finds an user form its name """
-    try:
-        [user_id] = [uid for uid, props in self.mock_users.items()
-                     if props['UserName'] == username]
-    except ValueError as e:
-        raise dbus.exceptions.DBusException(
-            'No such user exists: {}'.format(e),
-            name='org.freedesktop.Accounts.Error.Failed')
-    return get_user_path(user_id)
-
-
-@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='s',
-                     out_signature='a{sv}')
-def GetAll(self, interface):
-    """ Implements the GetAll dbus properties interface method.
-
-    This allows to override the getters using dynamic values.
-    """
-    if interface == MAIN_IFACE:
-        return {
-            'DaemonVersion': 'dbus-mock-0.1',
-            'HasNoUsers': len(self.mock_users) == 0,
-            'HasMultipleUsers': len(self.mock_users) > 1,
-            'AutomaticLoginUsers': dbus.Array(self.automatic_login_users,
-                                              signature='o'),
-        }
-    if interface == USER_IFACE:
-        return self.properties
-    return dbus.Dictionary({}, signature='sv')
-
-
-@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='ss',
-                     out_signature='v')
-def Get(self, interface, prop):
-    """ Implements the Get dbus properties interface method.
-
-    This allows to override the getters using dynamic values, via GetAll.
-    """
-    return self.GetAll(interface)[prop]
-
-
-def set_user_property(user, property_name, value):
-    """ Set an user property and emits the relative signals """
-    if user.properties[property_name] == value:
-        return
-    user.properties[property_name] = value
-    emit_properties_changed(user, USER_IFACE, property_name)
-    user.EmitSignal(USER_IFACE, 'Changed', '', [])
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetUserName(self, user_name):
-    set_user_property(self, 'UserName', user_name)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetRealName(self, real_name):
-    set_user_property(self, 'RealName', real_name)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetEmail(self, email):
-    set_user_property(self, 'Email', email)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetLanguage(self, language):
-    set_user_property(self, 'Language', language)
-
-
-@dbus.service.method(USER_IFACE, in_signature='as')
-def SetLanguages(self, languages):
-    set_user_property(self, 'Languages', dbus.Array(languages, signature='s'))
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetXSession(self, x_session):
-    set_user_property(self, 'XSession', x_session)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetSession(self, session):
-    set_user_property(self, 'Session', session)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetSessionType(self, session_type):
-    set_user_property(self, 'SessionType', session_type)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetLocation(self, location):
-    set_user_property(self, 'Location', location)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetHomeDirectory(self, home_directory):
-    set_user_property(self, 'HomeDirectory', home_directory)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetShell(self, shell):
-    set_user_property(self, 'Shell', shell)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetIconFile(self, icon_file):
-    set_user_property(self, 'IconFile', icon_file)
-
-
-@dbus.service.method(USER_IFACE, in_signature='b')
-def SetLocked(self, locked):
-    set_user_property(self, 'Locked', locked)
-
-
-@dbus.service.method(USER_IFACE, in_signature='i')
-def SetAccountType(self, account_type):
-    set_user_property(self, 'AccountType', account_type)
-
-
-@dbus.service.method(USER_IFACE, in_signature='i')
-def SetPasswordMode(self, password_mode):
-    set_user_property(self, 'PasswordMode', password_mode)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetPasswordHint(self, hint):
-    set_user_property(self, 'PasswordHint', hint)
-
-
-@dbus.service.method(USER_IFACE, in_signature='ss')
-def SetPassword(self, password, hint):
-    self.password = password
-    self.SetPasswordHint(hint)
-
-
-@dbus.service.method(USER_IFACE, in_signature='b')
-def SetAutomaticLogin(self, automatic_login):
-    manager = mockobject.objects[MAIN_OBJ]
-    if automatic_login:
-        manager.AddAutoLoginUser(self.properties['UserName'])
-    else:
-        manager.RemoveAutoLoginUser(self.properties['UserName'])
-
-
-@dbus.service.method(MOCK_IFACE, in_signature='xxxxxxx')
-def SetUserPasswordExpirationPolicy(self, uid, expiration_time,
-                                    last_change_time, min_days_between_changes,
-                                    max_days_between_changes, days_to_warn,
-                                    days_after_expiration_until_lock):
-    user = mockobject.objects[self.FindUserById(uid)]
-    user.pwd_expiration_policy = {
-        'expiration_time': expiration_time,
-        'last_change_time': last_change_time,
-        'min_days_between_changes': min_days_between_changes,
-        'max_days_between_changes': max_days_between_changes,
-        'days_to_warn': days_to_warn,
-        'days_after_expiration_until_lock': days_after_expiration_until_lock,
-    }
-    user.EmitSignal(USER_IFACE, 'Changed', '', [])
-
-
-@dbus.service.method(USER_IFACE, in_signature='', out_signature='xxxxxx')
-def GetPasswordExpirationPolicy(self):
-    return tuple(self.pwd_expiration_policy.values())
diff --git a/tests/mock_services/accounts_service.py b/tests/mock_services/accounts_service.py
new file mode 100644
index 0000000..6f36efe
--- /dev/null
+++ b/tests/mock_services/accounts_service.py
@@ -0,0 +1,393 @@
+'''Accounts Service D-Bus mock template'''
+
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 3 of the License, or (at your option) any
+# later version.  See http://www.gnu.org/copyleft/lgpl.html for the full text
+# of the license.
+
+__author__ = 'Marco Trevisan'
+__email__ = 'marco.trevisan@canonical.com'
+__copyright__ = '(c) 2021 Canonical Ltd.'
+__license__ = 'LGPL 3+'
+
+import sys
+import time
+
+import dbus
+from dbusmock import MOCK_IFACE, mockobject
+
+BUS_NAME = 'org.freedesktop.Accounts'
+MAIN_OBJ = '/org/freedesktop/Accounts'
+MAIN_IFACE = 'org.freedesktop.Accounts'
+USER_IFACE = MAIN_IFACE + '.User'
+SYSTEM_BUS = True
+
+DEFAULT_USER_PASSWORD = 'Pa$$wo0rd'
+
+
+def get_user_path(uid):
+    return '/org/freedesktop/Accounts/User{}'.format(uid)
+
+
+def load(mock, parameters=None):
+    parameters = parameters if parameters else {}
+    mock.mock_users = {}
+    mock.cached_users = []
+    mock.automatic_login_users = set()
+    mock.users_auto_uids = 2000
+
+    mock.AddProperties(MAIN_IFACE, mock.GetAll(MAIN_IFACE))
+
+    for uid, name in parameters.get('users', {}).items():
+        mock.AddUser(uid, name, DEFAULT_USER_PASSWORD, {}, {})
+
+def emit_properties_changed(mock, interface=MAIN_IFACE, properties=None):
+    if properties is None:
+        properties = mock.GetAll(interface)
+    elif isinstance(properties, str):
+        properties = [properties]
+
+    if isinstance(properties, (list, set)):
+        properties = {p: mock.Get(interface, p) for p in properties}
+    elif not isinstance(properties, dict):
+        raise TypeError('Unsupported properties type')
+
+    mock.EmitSignal(dbus.PROPERTIES_IFACE, 'PropertiesChanged', 'sa{sv}as', (
+        interface, properties, []))
+
+
+@dbus.service.method(MOCK_IFACE, in_signature='xssa{sv}a{sv}',
+                     out_signature='o')
+def AddUser(self, uid, username, password=DEFAULT_USER_PASSWORD,
+            overrides=None, password_policy_overrides=None):
+    '''Add user via uid and username and optionally overriding properties
+
+    Returns the new object path.
+   '''
+    path = get_user_path(uid)
+    default_props = {
+        'Uid': dbus.UInt64(uid),
+        'UserName': username,
+        'RealName': username[0].upper() + username[1:] + ' Fake',
+        'AccountType': dbus.Int32(1),
+        'AutomaticLogin': False,
+        'BackgroundFile': '',
+        'Email': '{}@python-dbusmock.org'.format(username),
+        'FormatsLocale': 'C',
+        'HomeDirectory': '/nonexisting/mock-home/{}'.format(username),
+        'IconFile': '',
+        'InputSources': dbus.Array([], signature='a{ss}'),
+        'Language': 'C',
+        'Languages': dbus.Array([], signature='s'),
+        'LocalAccount': True,
+        'Location': '',
+        'Locked': False,
+        'LoginFrequency': dbus.UInt64(0),
+        'LoginHistory': dbus.Array([], signature='(xxa{sv})'),
+        'LoginTime': dbus.Int64(0),
+        'PasswordHint': 'Remember it, come on!',
+        'PasswordMode': 0,
+        'Session': 'mock-session',
+        'SessionType': 'wayland',
+        'Shell': '/usr/bin/zsh',
+        'SystemAccount': False,
+        'XHasMessages': False,
+        'XKeyboardLayouts': dbus.Array([], signature='s'),
+        'XSession': 'mock-xsession',
+    }
+    default_props.update(overrides if overrides else {})
+    self.AddObject(path, USER_IFACE, default_props, [])
+
+    had_users = len(self.mock_users) != 0
+    had_multiple_users = len(self.mock_users) > 1
+    user = mockobject.objects[path]
+    user.password = password
+    user.properties = default_props
+    user.pwd_expiration_policy = {
+        'expiration_time': sys.maxsize,
+        'last_change_time': int(time.time()),
+        'min_days_between_changes': 0,
+        'max_days_between_changes': 0,
+        'days_to_warn': 0,
+        'days_after_expiration_until_lock': 0,
+    }
+    user.pwd_expiration_policy.update(
+        password_policy_overrides if password_policy_overrides else {})
+    self.mock_users[uid] = default_props
+
+    self.EmitSignal(MAIN_IFACE, 'UserAdded', 'o', [path])
+
+    if not had_users:
+        emit_properties_changed(self, MAIN_IFACE, 'HasNoUsers')
+    elif not had_multiple_users and len(self.mock_users) > 1:
+        emit_properties_changed(self, MAIN_IFACE, 'HasMultipleUsers')
+
+    return path
+
+
+@dbus.service.method(MOCK_IFACE, in_signature='', out_signature='ao')
+def ListMockUsers(self):
+    """ List the mock users that have been created """
+    return [get_user_path(uid) for uid in self.mock_users.keys()]
+
+
+@dbus.service.method(MOCK_IFACE, in_signature='s', out_signature='o')
+def AddAutoLoginUser(self, username):
+    """ Enable autologin for an user """
+    path = self.FindUserByName(username)
+    self.automatic_login_users.add(path)
+    user = mockobject.objects[path]
+    set_user_property(user, 'AutomaticLogin', True)
+    emit_properties_changed(self, MAIN_IFACE, 'AutomaticLoginUsers')
+    return path
+
+
+@dbus.service.method(MOCK_IFACE, in_signature='s', out_signature='o')
+def RemoveAutoLoginUser(self, username):
+    """ Disables autologin for an user """
+    path = self.FindUserByName(username)
+    self.automatic_login_users.remove(path)
+    user = mockobject.objects[path]
+    set_user_property(user, 'AutomaticLogin', False)
+    emit_properties_changed(self, MAIN_IFACE, 'AutomaticLoginUsers')
+    return path
+
+
+@dbus.service.method(MAIN_IFACE, in_signature='ssi', out_signature='o')
+def CreateUser(self, name, fullname, account_type):
+    """ Creates an user using the default API """
+    try:
+        self.FindUserByName(name)
+        found = True
+    except dbus.exceptions.DBusException:
+        found = False
+
+    if found:
+        raise dbus.exceptions.DBusException(
+            'User {} already exists'.format(name),
+            name='org.freedesktop.Accounts.Error.Failed')
+
+    self.users_auto_uids += 1
+
+    return self.AddUser(self.users_auto_uids, name, DEFAULT_USER_PASSWORD, {
+        'RealName': fullname, 'AccountType': account_type}, {})
+
+
+@dbus.service.method(MAIN_IFACE, in_signature='xb')
+def DeleteUser(self, uid, _remove_files):
+    """ Removes a created user """
+    path = self.FindUserById(uid)
+
+    had_multiple_users = len(self.mock_users) > 1
+    self.RemoveObject(path)
+    self.mock_users.pop(uid)
+    self.automatic_login_users.discard(path)
+
+    self.EmitSignal(MAIN_IFACE, 'UserDeleted', 'o', [path])
+
+    if len(self.mock_users) == 0:
+        emit_properties_changed(self, MAIN_IFACE, 'HasNoUsers')
+    elif had_multiple_users and len(self.mock_users) < 2:
+        emit_properties_changed(self, MAIN_IFACE, 'HasMultipleUsers')
+
+
+@dbus.service.method(MAIN_IFACE, in_signature='s', out_signature='o')
+def CacheUser(self, username):
+    """ Cache an user """
+    path = self.FindUserByName(username)
+    self.cached_users.append(path)
+    return path
+
+
+@dbus.service.method(MAIN_IFACE, in_signature='s')
+def UncacheUser(self, username):
+    """ Removes an user from the cache """
+    path = self.FindUserByName(username)
+    self.cached_users.remove(path)
+
+
+@dbus.service.method(MAIN_IFACE, in_signature='', out_signature='ao')
+def ListCachedUsers(self):
+    """ Lists the cached users """
+    return self.cached_users
+
+
+@dbus.service.method(MAIN_IFACE, in_signature='x', out_signature='o')
+def FindUserById(_self, uid):
+    """ Finds an user by its user id """
+    user = mockobject.objects.get(get_user_path(uid), None)
+    if not user:
+        raise dbus.exceptions.DBusException(
+            'No such user exists',
+            name='org.freedesktop.Accounts.Error.Failed')
+    return get_user_path(uid)
+
+
+@dbus.service.method(MAIN_IFACE, in_signature='s', out_signature='o')
+def FindUserByName(self, username):
+    """ Finds an user form its name """
+    try:
+        [user_id] = [uid for uid, props in self.mock_users.items()
+                     if props['UserName'] == username]
+    except ValueError as e:
+        raise dbus.exceptions.DBusException(
+            'No such user exists: {}'.format(e),
+            name='org.freedesktop.Accounts.Error.Failed')
+    return get_user_path(user_id)
+
+
+@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='s',
+                     out_signature='a{sv}')
+def GetAll(self, interface):
+    """ Implements the GetAll dbus properties interface method.
+
+    This allows to override the getters using dynamic values.
+    """
+    if interface == MAIN_IFACE:
+        return {
+            'DaemonVersion': 'dbus-mock-0.1',
+            'HasNoUsers': len(self.mock_users) == 0,
+            'HasMultipleUsers': len(self.mock_users) > 1,
+            'AutomaticLoginUsers': dbus.Array(self.automatic_login_users,
+                                              signature='o'),
+        }
+    if interface == USER_IFACE:
+        return self.properties
+    return dbus.Dictionary({}, signature='sv')
+
+
+@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='ss',
+                     out_signature='v')
+def Get(self, interface, prop):
+    """ Implements the Get dbus properties interface method.
+
+    This allows to override the getters using dynamic values, via GetAll.
+    """
+    return self.GetAll(interface)[prop]
+
+
+def set_user_property(user, property_name, value):
+    """ Set an user property and emits the relative signals """
+    if user.properties[property_name] == value:
+        return
+    user.properties[property_name] = value
+    emit_properties_changed(user, USER_IFACE, property_name)
+    user.EmitSignal(USER_IFACE, 'Changed', '', [])
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetUserName(self, user_name):
+    set_user_property(self, 'UserName', user_name)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetRealName(self, real_name):
+    set_user_property(self, 'RealName', real_name)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetEmail(self, email):
+    set_user_property(self, 'Email', email)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetLanguage(self, language):
+    set_user_property(self, 'Language', language)
+
+
+@dbus.service.method(USER_IFACE, in_signature='as')
+def SetLanguages(self, languages):
+    set_user_property(self, 'Languages', dbus.Array(languages, signature='s'))
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetXSession(self, x_session):
+    set_user_property(self, 'XSession', x_session)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetSession(self, session):
+    set_user_property(self, 'Session', session)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetSessionType(self, session_type):
+    set_user_property(self, 'SessionType', session_type)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetLocation(self, location):
+    set_user_property(self, 'Location', location)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetHomeDirectory(self, home_directory):
+    set_user_property(self, 'HomeDirectory', home_directory)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetShell(self, shell):
+    set_user_property(self, 'Shell', shell)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetIconFile(self, icon_file):
+    set_user_property(self, 'IconFile', icon_file)
+
+
+@dbus.service.method(USER_IFACE, in_signature='b')
+def SetLocked(self, locked):
+    set_user_property(self, 'Locked', locked)
+
+
+@dbus.service.method(USER_IFACE, in_signature='i')
+def SetAccountType(self, account_type):
+    set_user_property(self, 'AccountType', account_type)
+
+
+@dbus.service.method(USER_IFACE, in_signature='i')
+def SetPasswordMode(self, password_mode):
+    set_user_property(self, 'PasswordMode', password_mode)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetPasswordHint(self, hint):
+    set_user_property(self, 'PasswordHint', hint)
+
+
+@dbus.service.method(USER_IFACE, in_signature='ss')
+def SetPassword(self, password, hint):
+    self.password = password
+    self.SetPasswordHint(hint)
+
+
+@dbus.service.method(USER_IFACE, in_signature='b')
+def SetAutomaticLogin(self, automatic_login):
+    manager = mockobject.objects[MAIN_OBJ]
+    if automatic_login:
+        manager.AddAutoLoginUser(self.properties['UserName'])
+    else:
+        manager.RemoveAutoLoginUser(self.properties['UserName'])
+
+
+@dbus.service.method(MOCK_IFACE, in_signature='xxxxxxx')
+def SetUserPasswordExpirationPolicy(self, uid, expiration_time,
+                                    last_change_time, min_days_between_changes,
+                                    max_days_between_changes, days_to_warn,
+                                    days_after_expiration_until_lock):
+    user = mockobject.objects[self.FindUserById(uid)]
+    user.pwd_expiration_policy = {
+        'expiration_time': expiration_time,
+        'last_change_time': last_change_time,
+        'min_days_between_changes': min_days_between_changes,
+        'max_days_between_changes': max_days_between_changes,
+        'days_to_warn': days_to_warn,
+        'days_after_expiration_until_lock': days_after_expiration_until_lock,
+    }
+    user.EmitSignal(USER_IFACE, 'Changed', '', [])
+
+
+@dbus.service.method(USER_IFACE, in_signature='', out_signature='xxxxxx')
+def GetPasswordExpirationPolicy(self):
+    return tuple(self.pwd_expiration_policy.values())
diff --git a/tests/test-libaccountsservice.py b/tests/test-libaccountsservice.py
index 723ab51..f0261b1 100644
--- a/tests/test-libaccountsservice.py
+++ b/tests/test-libaccountsservice.py
@@ -39,7 +39,7 @@ class AccountsServiceTestBase(dbusmock.DBusTestCase):
         super().setUp()
         if not hasattr(self, '_mock'):
             template = os.path.join(
-                os.path.dirname(__file__), 'dbusmock/accounts_service.py')
+                os.path.dirname(__file__), 'mock_services/accounts_service.py')
             (self._mock, self._mock_obj) = self.spawn_server_template(
                 template, {}, stdout=subprocess.PIPE)
         self._manager = AccountsService.UserManager.get_default()
@@ -88,7 +88,7 @@ class TestAccountsServicePreExistingUser(AccountsServiceTestBase):
     '''Test mocking AccountsService with pre-existing user'''
     def setUp(self):
         template = os.path.join(
-            os.path.dirname(__file__), 'dbusmock/accounts_service.py')
+            os.path.dirname(__file__), 'mock_services/accounts_service.py')
         (self._mock, self._mock_obj) = self.spawn_server_template(
             template, {'users': { 2001: 'pizza' }}, stdout=subprocess.PIPE)
         super().setUp()
 
: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
: Michael Shigorin