aboutsummaryrefslogtreecommitdiff
path: root/tests/backend-dbus
diff options
context:
space:
mode:
Diffstat (limited to 'tests/backend-dbus')
-rw-r--r--tests/backend-dbus/CMakeLists.txt60
-rw-r--r--tests/backend-dbus/gtest-mock-dbus-fixture.h125
-rw-r--r--tests/backend-dbus/mock-accounts.cc143
-rw-r--r--tests/backend-dbus/mock-accounts.h73
-rw-r--r--tests/backend-dbus/mock-display-manager-seat.cc139
-rw-r--r--tests/backend-dbus/mock-display-manager-seat.h72
-rw-r--r--tests/backend-dbus/mock-end-session-dialog.cc61
-rw-r--r--tests/backend-dbus/mock-end-session-dialog.h67
-rw-r--r--tests/backend-dbus/mock-login1-manager.cc241
-rw-r--r--tests/backend-dbus/mock-login1-manager.h74
-rw-r--r--tests/backend-dbus/mock-login1-seat.cc244
-rw-r--r--tests/backend-dbus/mock-login1-seat.h76
-rw-r--r--tests/backend-dbus/mock-object.cc122
-rw-r--r--tests/backend-dbus/mock-object.h62
-rw-r--r--tests/backend-dbus/mock-screen-saver.cc71
-rw-r--r--tests/backend-dbus/mock-screen-saver.h53
-rw-r--r--tests/backend-dbus/mock-session-manager.cc66
-rw-r--r--tests/backend-dbus/mock-session-manager.h50
-rw-r--r--tests/backend-dbus/mock-user.cc123
-rw-r--r--tests/backend-dbus/mock-user.h57
-rw-r--r--tests/backend-dbus/mock-webcredentials.cc39
-rw-r--r--tests/backend-dbus/mock-webcredentials.h42
-rw-r--r--tests/backend-dbus/test-actions.cc434
-rw-r--r--tests/backend-dbus/test-guest.cc193
-rw-r--r--tests/backend-dbus/test-users.cc381
25 files changed, 3068 insertions, 0 deletions
diff --git a/tests/backend-dbus/CMakeLists.txt b/tests/backend-dbus/CMakeLists.txt
new file mode 100644
index 0000000..e28d8e6
--- /dev/null
+++ b/tests/backend-dbus/CMakeLists.txt
@@ -0,0 +1,60 @@
+# build libgtest
+add_library (gtest STATIC
+ ${GTEST_SOURCE_DIR}/gtest-all.cc
+ ${GTEST_SOURCE_DIR}/gtest_main.cc)
+set_target_properties (gtest PROPERTIES INCLUDE_DIRECTORIES
+ ${GTEST_INCLUDE_DIR})
+
+SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -g ${CC_WARNING_ARGS}")
+
+# build desktopmock
+add_library (desktopmock STATIC
+ mock-accounts.cc
+ mock-accounts.h
+ mock-login1-manager.cc
+ mock-login1-manager.h
+ mock-login1-seat.cc
+ mock-login1-seat.h
+ mock-display-manager-seat.cc
+ mock-display-manager-seat.h
+ mock-end-session-dialog.cc
+ mock-end-session-dialog.h
+ mock-object.cc
+ mock-object.h
+ mock-screen-saver.cc
+ mock-screen-saver.h
+ mock-session-manager.cc
+ mock-session-manager.h
+ mock-user.cc
+ mock-user.h
+ mock-webcredentials.cc
+ mock-webcredentials.h)
+
+include_directories (${SERVICE_INCLUDE_DIRS})
+include_directories (${CMAKE_SOURCE_DIR}/src)
+include_directories (${CMAKE_BINARY_DIR}/src)
+include_directories (${CMAKE_SOURCE_DIR}/tests)
+
+# test the Actions class
+add_executable (test-actions
+ test-actions.cc)
+add_test (test-actions test-actions)
+set_tests_properties (test-actions PROPERTIES COMPILE_FLAGS "${SERVICE_CFLAGS}")
+target_link_libraries (test-actions desktopmock backenddbus libindicatorsessionservice gtest ${SERVICE_LDFLAGS} ${GTEST_LIBS} ${GCOV_LIBS})
+
+# test the Guest class
+add_executable (test-guest
+ test-guest.cc)
+add_test (test-guest test-guest)
+set_tests_properties (test-guest PROPERTIES COMPILE_FLAGS "${SERVICE_CFLAGS}")
+target_link_libraries (test-guest desktopmock backenddbus libindicatorsessionservice gtest ${SERVICE_LDFLAGS} ${GTEST_LIBS} ${GCOV_LIBS})
+
+# test the Users class
+add_executable (test-users
+ test-users.cc)
+add_test (test-users test-users)
+set_tests_properties (test-users PROPERTIES COMPILE_FLAGS "${SERVICE_CFLAGS}")
+target_link_libraries (test-users desktopmock backenddbus libindicatorsessionservice gtest ${SERVICE_LDFLAGS} ${GTEST_LIBS} ${GCOV_LIBS})
+
+
+
diff --git a/tests/backend-dbus/gtest-mock-dbus-fixture.h b/tests/backend-dbus/gtest-mock-dbus-fixture.h
new file mode 100644
index 0000000..bab82bf
--- /dev/null
+++ b/tests/backend-dbus/gtest-mock-dbus-fixture.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gtest-dbus-fixture.h"
+
+#include "mock-accounts.h"
+#include "mock-login1-manager.h"
+#include "mock-login1-seat.h"
+#include "mock-display-manager-seat.h"
+#include "mock-end-session-dialog.h"
+#include "mock-screen-saver.h"
+#include "mock-session-manager.h"
+#include "mock-user.h"
+#include "mock-webcredentials.h"
+
+/***
+****
+***/
+
+class GTestMockDBusFixture: public GTestDBusFixture
+{
+ private:
+
+ typedef GTestDBusFixture super;
+
+ protected:
+
+ MockScreenSaver * screen_saver;
+ MockSessionManager * session_manager;
+ MockDisplayManagerSeat * dm_seat;
+ MockAccounts * accounts;
+ MockLogin1Manager * login1_manager;
+ MockLogin1Seat * login1_seat;
+ MockEndSessionDialog * end_session_dialog;
+ MockWebcredentials * webcredentials;
+
+ protected:
+
+ virtual void SetUp ()
+ {
+ super :: SetUp ();
+
+ webcredentials = new MockWebcredentials (loop, conn);
+ end_session_dialog = new MockEndSessionDialog (loop, conn);
+ session_manager = new MockSessionManager (loop, conn);
+ screen_saver = new MockScreenSaver (loop, conn);
+ dm_seat = new MockDisplayManagerSeat (loop, conn);
+ g_setenv ("XDG_SEAT_PATH", dm_seat->path(), TRUE);
+ dm_seat->set_guest_allowed (false);
+ login1_manager = new MockLogin1Manager (loop, conn);
+ login1_seat = new MockLogin1Seat (loop, conn, true);
+ g_setenv ("XDG_SEAT", login1_seat->seat_id(), TRUE);
+ login1_manager->add_seat (login1_seat);
+ accounts = build_accounts_mock ();
+ MockUser * user = accounts->find_by_username ("msmith");
+ const int session_tag = login1_manager->add_session (login1_seat, user);
+ dm_seat->set_login1_seat (login1_seat);
+ dm_seat->switch_to_user (user->username());
+ ASSERT_EQ (session_tag, login1_seat->active_session());
+ }
+
+ protected:
+
+ virtual void TearDown ()
+ {
+ delete accounts;
+ delete login1_manager;
+ delete dm_seat;
+ delete screen_saver;
+ delete session_manager;
+ delete end_session_dialog;
+ delete webcredentials;
+
+ super :: TearDown ();
+ }
+
+ private:
+
+ MockAccounts * build_accounts_mock ()
+ {
+ struct {
+ guint64 login_frequency;
+ const gchar * user_name;
+ const gchar * real_name;
+ } users[] = {
+ { 134, "whartnell", "First Doctor" },
+ { 119, "ptroughton", "Second Doctor" },
+ { 128, "jpertwee", "Third Doctor" },
+ { 172, "tbaker", "Fourth Doctor" },
+ { 69, "pdavison", "Fifth Doctor" },
+ { 31, "cbaker", "Sixth Doctor" },
+ { 42, "smccoy", "Seventh Doctor" },
+ { 1, "pmcgann", "Eigth Doctor" },
+ { 13, "ceccleston", "Ninth Doctor" },
+ { 47, "dtennant", "Tenth Doctor" },
+ { 34, "msmith", "Eleventh Doctor" },
+ { 1, "rhurndall", "First Doctor" }
+ };
+
+ MockAccounts * a = new MockAccounts (loop, conn);
+ for (int i=0, n=G_N_ELEMENTS(users); i<n; ++i)
+ a->add_user (new MockUser (loop, conn,
+ users[i].user_name,
+ users[i].real_name,
+ users[i].login_frequency));
+ return a;
+ }
+};
+
diff --git a/tests/backend-dbus/mock-accounts.cc b/tests/backend-dbus/mock-accounts.cc
new file mode 100644
index 0000000..16e37d2
--- /dev/null
+++ b/tests/backend-dbus/mock-accounts.cc
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mock-accounts.h"
+#include "mock-user.h"
+
+namespace
+{
+ const char * const DBUS_ACCOUNTS_NAME = "org.freedesktop.Accounts";
+
+ const char * const DBUS_ACCOUNTS_PATH = "/org/freedesktop/Accounts";
+}
+
+/***
+****
+***/
+
+void
+MockAccounts :: add_user (MockUser * user)
+{
+ g_assert (my_users.count(user) == 0);
+
+ my_users.insert (user);
+ my_uid_to_user[user->uid()] = user;
+ my_path_to_user[user->path()] = user;
+ my_username_to_user[user->username()] = user;
+
+ accounts_emit_user_added (my_skeleton, user->path());
+}
+
+void
+MockAccounts :: remove_user (MockUser * user)
+{
+ g_assert (my_users.count(user) == 1);
+
+ my_users.erase (user);
+ my_uid_to_user.erase (user->uid());
+ my_path_to_user.erase (user->path());
+ my_username_to_user.erase (user->username());
+
+ accounts_emit_user_deleted (my_skeleton, user->path());
+}
+
+MockUser *
+MockAccounts :: find_by_uid (guint64 uid)
+{
+ const uid_to_user_t::iterator it (my_uid_to_user.find(uid));
+
+ if (it != my_uid_to_user.end())
+ return it->second;
+
+ g_warn_if_reached ();
+ return 0;
+}
+
+MockUser *
+MockAccounts :: find_by_username (const char * username)
+{
+ const username_to_user_t::iterator it (my_username_to_user.find(username));
+
+ if (it != my_path_to_user.end())
+ return it->second;
+
+ g_warn_if_reached ();
+ return 0;
+}
+
+/***
+****
+***/
+
+gboolean
+MockAccounts :: on_find_user_by_id_static (Accounts * a,
+ GDBusMethodInvocation * invocation,
+ guint64 uid,
+ gpointer gself)
+{
+ MockUser * user = static_cast<MockAccounts*>(gself)->find_by_uid (uid);
+ accounts_complete_find_user_by_id (a, invocation, user ? user->path() : "");
+ return true;
+}
+
+gboolean
+MockAccounts :: on_list_cached_users_static (Accounts * a,
+ GDBusMethodInvocation * invocation,
+ gpointer gself)
+{
+ int i;
+ const char ** paths;
+ const users_t& users = static_cast<MockAccounts*>(gself)->my_users;
+
+ i = 0;
+ paths = g_new0 (const char*, users.size() + 1);
+ for (auto it : users)
+ paths[i++] = it->path();
+ accounts_complete_list_cached_users (a, invocation, paths);
+ g_free (paths);
+
+ return true;
+}
+
+/***
+****
+***/
+
+MockAccounts :: MockAccounts (GMainLoop * loop,
+ GDBusConnection * bus_connection):
+ MockObject (loop, bus_connection, DBUS_ACCOUNTS_NAME, DBUS_ACCOUNTS_PATH),
+ my_skeleton (accounts_skeleton_new ())
+{
+ g_signal_connect (my_skeleton, "handle-list-cached-users",
+ G_CALLBACK(on_list_cached_users_static), this);
+ g_signal_connect (my_skeleton, "handle-find-user-by-id",
+ G_CALLBACK(on_find_user_by_id_static), this);
+
+ set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton));
+}
+
+MockAccounts :: ~MockAccounts ()
+{
+ for (users_t::iterator it(my_users.begin()),
+ end(my_users.end()); it!=end; ++it)
+ delete *it;
+
+ g_signal_handlers_disconnect_by_data (my_skeleton, this);
+ g_clear_object (&my_skeleton);
+}
diff --git a/tests/backend-dbus/mock-accounts.h b/tests/backend-dbus/mock-accounts.h
new file mode 100644
index 0000000..8032441
--- /dev/null
+++ b/tests/backend-dbus/mock-accounts.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MOCK_ACCOUNTS_H
+#define MOCK_ACCOUNTS_H
+
+#include <set>
+#include <string>
+#include <map>
+#include "mock-object.h"
+#include "backend-dbus/dbus-accounts.h" // struct Accounts
+
+class MockUser;
+
+class MockAccounts: public MockObject
+{
+ public:
+
+ MockAccounts (GMainLoop * loop,
+ GDBusConnection * bus_connection);
+ virtual ~MockAccounts ();
+
+ void add_user (MockUser * user);
+ void remove_user (MockUser * user);
+ size_t size() const { return my_users.size(); }
+ MockUser * find_by_uid (guint64 uid);
+ MockUser * find_by_username (const char * username);
+
+ private:
+
+ Accounts * my_skeleton;
+
+ typedef std::set<MockUser*> users_t;
+ users_t my_users;
+
+ typedef std::map<guint,MockUser*> uid_to_user_t;
+ uid_to_user_t my_uid_to_user;
+
+ typedef std::map<std::string,MockUser*> path_to_user_t;
+ path_to_user_t my_path_to_user;
+
+ typedef std::map<std::string,MockUser*> username_to_user_t;
+ username_to_user_t my_username_to_user;
+
+ private:
+
+ static gboolean on_find_user_by_id_static (Accounts *,
+ GDBusMethodInvocation *,
+ guint64,
+ gpointer);
+
+ static gboolean on_list_cached_users_static (Accounts *,
+ GDBusMethodInvocation *,
+ gpointer);
+};
+
+#endif // #ifndef MOCK_ACCOUNTS_H
diff --git a/tests/backend-dbus/mock-display-manager-seat.cc b/tests/backend-dbus/mock-display-manager-seat.cc
new file mode 100644
index 0000000..c8a4857
--- /dev/null
+++ b/tests/backend-dbus/mock-display-manager-seat.cc
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mock-display-manager-seat.h"
+#include "mock-login1-seat.h"
+
+namespace
+{
+ const char * const DISPLAY_MANAGER_NAME = "org.freedesktop.DisplayManager";
+
+ std::string
+ next_unique_path ()
+ {
+ static int id = 12; // arbitrary; doesn't matter
+
+ char * tmp;
+ std::string ret;
+
+ tmp = g_strdup_printf ("/org/freedesktop/DisplayManager/Seat%d", id++);
+ ret = tmp;
+ g_free (tmp);
+ return ret;
+ }
+}
+
+/***
+****
+***/
+
+void
+MockDisplayManagerSeat :: switch_to_greeter ()
+{
+ my_last_action = GREETER;
+}
+
+gboolean
+MockDisplayManagerSeat :: handle_switch_to_greeter (DisplayManagerSeat * o,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ static_cast<MockDisplayManagerSeat*>(gself)->switch_to_greeter ();
+ display_manager_seat_complete_switch_to_greeter (o, inv);
+ return true;
+}
+
+void
+MockDisplayManagerSeat :: set_guest_allowed (bool b)
+{
+ display_manager_seat_set_has_guest_account (my_skeleton, b);
+}
+
+gboolean
+MockDisplayManagerSeat :: handle_switch_to_guest (DisplayManagerSeat * o,
+ GDBusMethodInvocation * inv,
+ const gchar * session_name G_GNUC_UNUSED,
+ gpointer gself)
+{
+ static_cast<MockDisplayManagerSeat*>(gself)->switch_to_guest ();
+ display_manager_seat_complete_switch_to_guest (o, inv);
+ return true;
+}
+
+void
+MockDisplayManagerSeat :: switch_to_guest ()
+{
+ g_assert (my_login1_seat != 0);
+
+ my_last_action = GUEST;
+ my_login1_seat->switch_to_guest ();
+}
+
+gboolean
+MockDisplayManagerSeat :: handle_switch_to_user (DisplayManagerSeat * o,
+ GDBusMethodInvocation * inv,
+ const gchar * username,
+ const gchar * session_name G_GNUC_UNUSED,
+ gpointer gself)
+{
+ static_cast<MockDisplayManagerSeat*>(gself)->switch_to_user (username);
+ display_manager_seat_complete_switch_to_user (o, inv);
+ return true;
+}
+
+void
+MockDisplayManagerSeat :: switch_to_user (const char * username)
+{
+ g_assert (my_login1_seat != 0);
+
+ my_last_action = USER;
+ my_login1_seat->switch_to_user (username);
+}
+
+void
+MockDisplayManagerSeat :: set_login1_seat (MockLogin1Seat * seat)
+{
+ my_login1_seat = seat;
+}
+
+/***
+****
+***/
+
+MockDisplayManagerSeat :: MockDisplayManagerSeat (GMainLoop * loop,
+ GDBusConnection * connection):
+ MockObject (loop, connection, DISPLAY_MANAGER_NAME, next_unique_path()),
+ my_skeleton (display_manager_seat_skeleton_new ()),
+ my_last_action (NONE)
+{
+ g_signal_connect (my_skeleton, "handle-switch-to-guest",
+ G_CALLBACK(handle_switch_to_guest), this);
+ g_signal_connect (my_skeleton, "handle-switch-to-user",
+ G_CALLBACK(handle_switch_to_user), this);
+ g_signal_connect (my_skeleton, "handle-switch-to-greeter",
+ G_CALLBACK(handle_switch_to_greeter), this);
+
+ set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton));
+}
+
+MockDisplayManagerSeat :: ~MockDisplayManagerSeat ()
+{
+ //g_signal_handlers_disconnect_by_data (my_skeleton, this);
+ g_clear_object (&my_skeleton);
+}
diff --git a/tests/backend-dbus/mock-display-manager-seat.h b/tests/backend-dbus/mock-display-manager-seat.h
new file mode 100644
index 0000000..fcdd17a
--- /dev/null
+++ b/tests/backend-dbus/mock-display-manager-seat.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MOCK_DISPLAY_MANAGER_SEAT_H
+#define MOCK_DISPLAY_MANAGER_SEAT_H
+
+#include "mock-object.h" // parent class
+#include "backend-dbus/dbus-display-manager.h"
+
+class MockLogin1Seat;
+
+class MockDisplayManagerSeat: public MockObject
+{
+ public:
+
+ MockDisplayManagerSeat (GMainLoop * loop,
+ GDBusConnection * bus_connection);
+ virtual ~MockDisplayManagerSeat ();
+
+ void set_guest_allowed (bool b);
+
+ void set_login1_seat (MockLogin1Seat * login1_seat);
+
+ void switch_to_guest ();
+
+ void switch_to_greeter ();
+
+ void switch_to_user (const char * username);
+
+ public:
+
+ enum Action { NONE, GUEST, GREETER, USER };
+
+ Action last_action () const { return my_last_action; }
+
+ private:
+
+ static gboolean handle_switch_to_greeter (DisplayManagerSeat *o,
+ GDBusMethodInvocation *inv,
+ gpointer gself);
+ static gboolean handle_switch_to_guest (DisplayManagerSeat *o,
+ GDBusMethodInvocation *inv,
+ const gchar *session_name,
+ gpointer gself);
+ static gboolean handle_switch_to_user (DisplayManagerSeat * o,
+ GDBusMethodInvocation * inv,
+ const gchar * username,
+ const gchar * session_name,
+ gpointer gself);
+
+ DisplayManagerSeat * my_skeleton;
+ MockLogin1Seat * my_login1_seat;
+ Action my_last_action;
+};
+
+#endif // #ifndef MOCK_DISPLAY_MANAGER_SEAT_H
diff --git a/tests/backend-dbus/mock-end-session-dialog.cc b/tests/backend-dbus/mock-end-session-dialog.cc
new file mode 100644
index 0000000..2772423
--- /dev/null
+++ b/tests/backend-dbus/mock-end-session-dialog.cc
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mock-end-session-dialog.h"
+
+gboolean
+MockEndSessionDialog :: handle_open (EndSessionDialog * object,
+ GDBusMethodInvocation * invocation,
+ guint arg_type G_GNUC_UNUSED,
+ guint arg_timestamp G_GNUC_UNUSED,
+ guint arg_seconds_to_stay_open G_GNUC_UNUSED,
+ const gchar * const * inhibitor_paths G_GNUC_UNUSED,
+ gpointer gself)
+{
+ static_cast<MockEndSessionDialog*>(gself)->my_isOpen = true;
+ end_session_dialog_complete_open (object, invocation);
+ return true;
+}
+
+/***
+****
+***/
+
+namespace
+{
+ const char * const MY_NAME = "com.canonical.Unity";
+ const char * const MY_PATH = "/org/gnome/SessionManager/EndSessionDialog";
+}
+
+MockEndSessionDialog :: MockEndSessionDialog (GMainLoop * loop,
+ GDBusConnection * bus_connection):
+ MockObject (loop, bus_connection, MY_NAME, MY_PATH),
+ my_skeleton (end_session_dialog_skeleton_new ()),
+ my_isOpen (false)
+{
+ g_signal_connect (my_skeleton, "handle-open",
+ G_CALLBACK(handle_open), this);
+
+ set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton));
+}
+
+MockEndSessionDialog :: ~MockEndSessionDialog ()
+{
+ g_clear_object (&my_skeleton);
+}
diff --git a/tests/backend-dbus/mock-end-session-dialog.h b/tests/backend-dbus/mock-end-session-dialog.h
new file mode 100644
index 0000000..468715c
--- /dev/null
+++ b/tests/backend-dbus/mock-end-session-dialog.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MOCK_END_SESSION_DIALOG_H
+#define MOCK_END_SESSION_DIALOG_H
+
+#include "mock-object.h" // parent class
+#include "backend-dbus/dbus-end-session-dialog.h" // EndSessionDialog
+
+class MockEndSessionDialog: public MockObject
+{
+ public:
+
+ MockEndSessionDialog (GMainLoop * loop,
+ GDBusConnection * bus_connection);
+ virtual ~MockEndSessionDialog ();
+
+ bool is_open () const { return my_isOpen; }
+
+ void cancel () { my_isOpen = false; end_session_dialog_emit_canceled (my_skeleton); }
+ void confirm_logout () { my_isOpen = false; end_session_dialog_emit_confirmed_logout (my_skeleton); }
+ void confirm_reboot () { my_isOpen = false; end_session_dialog_emit_confirmed_reboot (my_skeleton); }
+ void confirm_shutdown () { my_isOpen = false; end_session_dialog_emit_confirmed_shutdown (my_skeleton); }
+ void close () { my_isOpen = false; end_session_dialog_emit_closed (my_skeleton); }
+
+ private:
+
+ EndSessionDialog * my_skeleton;
+
+ bool my_isOpen;
+
+ static gboolean handle_open (EndSessionDialog *,
+ GDBusMethodInvocation *,
+ guint,
+ guint,
+ guint,
+ const gchar * const *,
+ gpointer);
+
+
+#if 0
+ static gboolean handle_lock (GnomeScreenSaver *,
+ GDBusMethodInvocation *,
+ gpointer);
+ static gboolean handle_simulate_user_activity (GnomeScreenSaver *,
+ GDBusMethodInvocation *,
+ gpointer);
+#endif
+};
+
+#endif
diff --git a/tests/backend-dbus/mock-login1-manager.cc b/tests/backend-dbus/mock-login1-manager.cc
new file mode 100644
index 0000000..4461125
--- /dev/null
+++ b/tests/backend-dbus/mock-login1-manager.cc
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mock-login1-manager.h"
+#include "mock-login1-seat.h"
+#include "mock-user.h"
+
+namespace
+{
+ const char * const BUS_NAME = "org.freedesktop.login1";
+
+ const char * const BUS_PATH = "/org/freedesktop/login1";
+}
+
+/***
+****
+***/
+
+void
+MockLogin1Manager :: emit_session_new (MockLogin1Seat * seat, int tag) const
+{
+ std::string id;
+ std::string path;
+ seat->get_session_id_and_path_for_tag (tag, id, path);
+
+ login1_manager_emit_session_new (my_skeleton, id.c_str(), path.c_str());
+}
+
+int
+MockLogin1Manager :: add_session (MockLogin1Seat * seat, MockUser * user)
+{
+ g_assert (my_seats.count(seat) == 1);
+
+ const int session_tag = seat->add_session (user);
+ emit_session_new (seat, session_tag);
+ return session_tag;
+}
+
+void
+MockLogin1Manager :: emit_session_removed (MockLogin1Seat * seat, int tag) const
+{
+ std::string id;
+ std::string path;
+ seat->get_session_id_and_path_for_tag (tag, id, path);
+
+ login1_manager_emit_session_removed (my_skeleton, id.c_str(), path.c_str());
+}
+
+void
+MockLogin1Manager :: remove_session (MockLogin1Seat * seat, int session_tag)
+{
+ seat->remove_session (session_tag);
+ emit_session_removed (seat, session_tag);
+}
+
+void
+MockLogin1Manager :: add_seat (MockLogin1Seat * seat)
+{
+ g_assert (my_seats.count(seat) == 0);
+
+ my_seats.insert (seat);
+ std::set<int> sessions = seat->sessions ();
+ for (auto tag : sessions)
+ emit_session_new (seat, tag);
+}
+
+/***
+****
+***/
+
+GVariant *
+MockLogin1Manager :: list_sessions () const
+{
+ GVariantBuilder b;
+
+ g_variant_builder_init (&b, G_VARIANT_TYPE("a(susso)"));
+
+ for (auto seat : my_seats)
+ {
+ GVariant * seat_sessions = seat->list_sessions ();
+
+ GVariantIter iter;
+ g_variant_iter_init (&iter, seat_sessions);
+ GVariant * child;
+ while ((child = g_variant_iter_next_value (&iter)))
+ {
+ g_variant_builder_add_value (&b, child);
+ g_variant_unref (child);
+ }
+ }
+
+ return g_variant_builder_end (&b);
+}
+
+/***
+**** Skeleton Handlers
+***/
+
+gboolean
+MockLogin1Manager :: handle_list_sessions (Login1Manager * m,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ GVariant * sessions = static_cast<MockLogin1Manager*>(gself)->list_sessions();
+ login1_manager_complete_list_sessions (m, inv, sessions);
+ return true;
+}
+
+gboolean
+MockLogin1Manager :: handle_can_suspend (Login1Manager * m,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ const std::string& s = static_cast<MockLogin1Manager*>(gself)->can_suspend();
+ login1_manager_complete_can_suspend (m, inv, s.c_str());
+ return true;
+}
+
+gboolean
+MockLogin1Manager :: handle_can_hibernate (Login1Manager * m,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ const std::string& s = static_cast<MockLogin1Manager*>(gself)->can_hibernate();
+ login1_manager_complete_can_hibernate (m, inv, s.c_str());
+ return true;
+}
+
+gboolean
+MockLogin1Manager :: handle_reboot (Login1Manager * m,
+ GDBusMethodInvocation * inv,
+ gboolean interactive G_GNUC_UNUSED,
+ gpointer gself)
+{
+ static_cast<MockLogin1Manager*>(gself)->my_last_action = "reboot";
+ login1_manager_complete_reboot (m, inv);
+ return true;
+}
+
+gboolean
+MockLogin1Manager :: handle_power_off (Login1Manager * m,
+ GDBusMethodInvocation * inv,
+ gboolean interactive G_GNUC_UNUSED,
+ gpointer gself)
+{
+ static_cast<MockLogin1Manager*>(gself)->my_last_action = "power-off";
+ login1_manager_complete_power_off (m, inv);
+ return true;
+}
+
+gboolean
+MockLogin1Manager :: handle_suspend (Login1Manager * m,
+ GDBusMethodInvocation * inv,
+ gboolean interactive G_GNUC_UNUSED,
+ gpointer gself)
+{
+ static_cast<MockLogin1Manager*>(gself)->my_last_action = "suspend";
+ login1_manager_complete_suspend (m, inv);
+ return true;
+}
+
+gboolean
+MockLogin1Manager :: handle_hibernate (Login1Manager * m,
+ GDBusMethodInvocation * inv,
+ gboolean interactive G_GNUC_UNUSED,
+ gpointer gself)
+{
+ static_cast<MockLogin1Manager*>(gself)->my_last_action = "hibernate";
+ login1_manager_complete_hibernate (m, inv);
+ return true;
+}
+
+/***
+****
+***/
+
+const std::string&
+MockLogin1Manager :: can_suspend () const
+{
+ return my_can_suspend;
+}
+
+const std::string&
+MockLogin1Manager :: can_hibernate () const
+{
+ return my_can_hibernate;
+}
+
+/***
+****
+***/
+
+MockLogin1Manager :: MockLogin1Manager (GMainLoop * loop,
+ GDBusConnection * conn):
+ MockObject (loop, conn, BUS_NAME, BUS_PATH),
+ my_skeleton (login1_manager_skeleton_new ()),
+ my_can_suspend ("yes"),
+ my_can_hibernate ("yes")
+{
+ g_signal_connect (my_skeleton, "handle-can-suspend",
+ G_CALLBACK(handle_can_suspend), this);
+ g_signal_connect (my_skeleton, "handle-can-hibernate",
+ G_CALLBACK(handle_can_hibernate), this);
+ g_signal_connect (my_skeleton, "handle_reboot",
+ G_CALLBACK(handle_reboot), this);
+ g_signal_connect (my_skeleton, "handle-power-off",
+ G_CALLBACK(handle_power_off), this);
+ g_signal_connect (my_skeleton, "handle-suspend",
+ G_CALLBACK(handle_suspend), this);
+ g_signal_connect (my_skeleton, "handle-hibernate",
+ G_CALLBACK(handle_hibernate), this);
+ g_signal_connect (my_skeleton, "handle-list-sessions",
+ G_CALLBACK(handle_list_sessions), this);
+
+ set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton));
+}
+
+MockLogin1Manager :: ~MockLogin1Manager ()
+{
+ for (auto seat : my_seats)
+ delete seat;
+
+ g_signal_handlers_disconnect_by_data (my_skeleton, this);
+ g_clear_object (&my_skeleton);
+}
diff --git a/tests/backend-dbus/mock-login1-manager.h b/tests/backend-dbus/mock-login1-manager.h
new file mode 100644
index 0000000..f630329
--- /dev/null
+++ b/tests/backend-dbus/mock-login1-manager.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MOCK_LOGIN1_MANAGER_H
+#define MOCK_LOGIN1_MANAGER_H
+
+#include <set>
+#include <string>
+#include "mock-object.h"
+#include "backend-dbus/dbus-login1-manager.h"
+
+class MockLogin1Seat;
+class MockUser;
+
+class MockLogin1Manager: public MockObject
+{
+ public:
+
+ MockLogin1Manager (GMainLoop * loop,
+ GDBusConnection * bus_connection);
+ virtual ~MockLogin1Manager ();
+
+ int add_session (MockLogin1Seat * seat, MockUser * user);
+ void remove_session (MockLogin1Seat * seat, int session_tag);
+
+ void add_seat (MockLogin1Seat * seat);
+
+ const std::string& can_suspend () const;
+ const std::string& can_hibernate () const;
+
+ const std::string& last_action () const { return my_last_action; }
+ void clear_last_action () { my_last_action.clear(); }
+
+ private:
+
+ void emit_session_new (MockLogin1Seat * seat, int tag) const;
+ void emit_session_removed (MockLogin1Seat * seat, int tag) const;
+
+ GVariant * list_sessions () const;
+
+ static gboolean handle_list_sessions (Login1Manager *, GDBusMethodInvocation *, gpointer);
+ static gboolean handle_can_suspend (Login1Manager *, GDBusMethodInvocation *, gpointer);
+ static gboolean handle_can_hibernate (Login1Manager *, GDBusMethodInvocation *, gpointer);
+ static gboolean handle_reboot (Login1Manager *, GDBusMethodInvocation *, gboolean, gpointer);
+ static gboolean handle_power_off (Login1Manager *, GDBusMethodInvocation *, gboolean, gpointer);
+ static gboolean handle_suspend (Login1Manager *, GDBusMethodInvocation *, gboolean, gpointer);
+ static gboolean handle_hibernate (Login1Manager *, GDBusMethodInvocation *, gboolean, gpointer);
+
+ private:
+
+ Login1Manager * my_skeleton;
+ std::set<MockLogin1Seat*> my_seats;
+ std::string my_can_suspend;
+ std::string my_can_hibernate;
+ std::string my_last_action;
+};
+
+#endif // #ifndef MOCK_LOGIN1_MANAGER_H
diff --git a/tests/backend-dbus/mock-login1-seat.cc b/tests/backend-dbus/mock-login1-seat.cc
new file mode 100644
index 0000000..49d7fb6
--- /dev/null
+++ b/tests/backend-dbus/mock-login1-seat.cc
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mock-login1-seat.h"
+
+#include "mock-object.h"
+#include "mock-user.h"
+
+namespace
+{
+ const char * BUS_NAME = "org.freedesktop.login1";
+
+ std::string next_unique_sid ()
+ {
+ static int id = 1;
+
+ char * tmp;
+ std::string ret;
+
+ tmp = g_strdup_printf ("/org/freedesktop/login1/seat/seat%d", id++);
+ ret = tmp;
+ g_free (tmp);
+ return ret;
+ }
+
+ static int next_session_tag = 1;
+}
+
+void
+MockLogin1Seat :: get_session_id_and_path_for_tag (int tag,
+ std::string & id,
+ std::string & path)
+{
+ if (tag)
+ {
+ char tmp[80];
+
+ g_snprintf (tmp, sizeof(tmp), "c%d", tag);
+ id = tmp;
+
+ g_snprintf (tmp, sizeof(tmp), "/org/freedesktop/login1/session/%s", id.c_str());
+ path = tmp;
+ }
+ else
+ {
+ id = "";
+ path = "";
+ }
+}
+
+
+/***
+****
+***/
+
+void
+MockLogin1Seat :: update_sessions_property ()
+{
+ GVariantBuilder b;
+
+ g_variant_builder_init (&b, G_VARIANT_TYPE("a(so)"));
+ for (const auto& it : my_sessions)
+ {
+ std::string id, path;
+ get_session_id_and_path_for_tag (it.first, id, path);
+ g_variant_builder_add (&b, "(so)", id.c_str(), path.c_str());
+ }
+
+ GVariant * v = g_variant_builder_end (&b);
+ g_object_set (my_skeleton, "sessions", v, NULL);
+}
+
+void
+MockLogin1Seat :: update_active_session_property ()
+{
+ std::string id;
+ std::string path;
+ get_session_id_and_path_for_tag (my_active_session, id, path);
+
+ GVariant * v = g_variant_new ("(so)", id.c_str(), path.c_str());
+ g_object_set (my_skeleton, "active-session", v, NULL);
+}
+
+void
+MockLogin1Seat :: update_can_multi_session_property ()
+{
+ g_object_set (my_skeleton, "can-multi-session", my_can_multi_session, NULL);
+}
+
+/***
+****
+***/
+
+/* lists this seat's sessions in the format of Login1Manager::ListSessions() */
+GVariant *
+MockLogin1Seat :: list_sessions ()
+{
+ GVariantBuilder b;
+ g_variant_builder_init (&b, G_VARIANT_TYPE("a(susso)"));
+ for (auto it : my_sessions)
+ {
+ std::string id, path;
+ get_session_id_and_path_for_tag (it.first, id, path);
+ g_variant_builder_add (&b, "(susso)",
+ id.c_str(),
+ uint32_t(it.second->uid()),
+ it.second->username(),
+ seat_id(),
+ path.c_str());
+ }
+
+ return g_variant_builder_end (&b);
+}
+
+/***
+****
+***/
+
+std::set<int>
+MockLogin1Seat :: sessions () const
+{
+ std::set<int> ret;
+
+ for (auto it : my_sessions)
+ ret.insert (it.first);
+
+ return ret;
+}
+
+int
+MockLogin1Seat :: add_session (MockUser * user)
+{
+ const int tag = next_session_tag++;
+
+ my_sessions[tag] = user;
+ update_sessions_property ();
+
+ return tag;
+}
+
+void
+MockLogin1Seat :: remove_session (int session_tag)
+{
+ my_sessions.erase (session_tag);
+ update_sessions_property ();
+}
+
+/***
+****
+***/
+
+std::string
+MockLogin1Seat :: user_state (unsigned int uid) const
+{
+ for (auto it : my_sessions)
+ if (it.second->uid() == uid)
+ return it.first == my_active_session ? "active" : "online";
+
+ return "offline"; // no matching session
+}
+
+void
+MockLogin1Seat :: activate_session (int session_tag)
+{
+ g_assert (my_sessions.count(session_tag) == 1);
+
+ if (my_active_session != session_tag)
+ {
+ std::string id, path;
+ my_active_session = session_tag;
+ get_session_id_and_path_for_tag (session_tag, id, path);
+ g_setenv ("XDG_SESSION_ID", id.c_str(), true);
+ update_active_session_property ();
+
+ }
+}
+
+void
+MockLogin1Seat :: switch_to_guest ()
+{
+ for (const auto& it : my_sessions)
+ {
+ if (it.second->is_guest())
+ {
+ activate_session (it.first);
+ return;
+ }
+ }
+
+ g_warn_if_reached ();
+}
+
+void
+MockLogin1Seat :: switch_to_user (const char * username)
+{
+ for (const auto& it : my_sessions)
+ {
+ if (!g_strcmp0 (username, it.second->username()))
+ {
+ activate_session (it.first);
+ return;
+ }
+ }
+
+ g_warn_if_reached ();
+}
+
+/***
+**** Life Cycle
+***/
+
+MockLogin1Seat :: MockLogin1Seat (GMainLoop * loop,
+ GDBusConnection * bus_connection,
+ bool can_activate_sessions):
+ MockObject (loop, bus_connection, BUS_NAME, next_unique_sid()),
+ my_skeleton (login1_seat_skeleton_new ()),
+ my_active_session (0),
+ my_can_multi_session (can_activate_sessions)
+
+{
+ set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton));
+ update_can_multi_session_property ();
+}
+
+MockLogin1Seat :: ~MockLogin1Seat ()
+{
+ g_clear_object (&my_skeleton);
+}
diff --git a/tests/backend-dbus/mock-login1-seat.h b/tests/backend-dbus/mock-login1-seat.h
new file mode 100644
index 0000000..254ebe9
--- /dev/null
+++ b/tests/backend-dbus/mock-login1-seat.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MOCK_LOGIN1_SEAT_H
+#define MOCK_LOGIN1_SEAT_H
+
+#include <cstring> /* strrchr */
+#include <map>
+#include <set>
+#include <string>
+#include "backend-dbus/dbus-login1-seat.h"
+#include "mock-object.h"
+
+class MockUser;
+class MockLogin1Session;
+
+class MockLogin1Seat: public MockObject
+{
+ public:
+
+ MockLogin1Seat (GMainLoop * loop,
+ GDBusConnection * bus_connection,
+ bool can_activate_sessions);
+
+ virtual ~MockLogin1Seat ();
+
+ const char * seat_id() const { return strrchr(path(),'/')+1; }
+
+ int add_session (MockUser * user);
+ void remove_session (int session_tag);
+ std::set<int> sessions () const;
+ int active_session () const { return my_active_session; }
+
+ std::string user_state (unsigned int uid) const;
+
+ bool can_activate_sessions () const { return my_can_multi_session; }
+ void activate_session (int session_tag);
+ void switch_to_guest ();
+ void switch_to_user (const char * username);
+
+ //const char * sid() { return path(); }
+ //MockLogin1Session * find (const char * ssid);
+
+ GVariant * list_sessions ();
+
+ static void get_session_id_and_path_for_tag (int tag, std::string& id, std::string& path);
+
+ private:
+ void update_sessions_property ();
+ void update_active_session_property ();
+ void update_can_multi_session_property ();
+
+ private:
+ Login1Seat * my_skeleton;
+ std::map<int,MockUser*> my_sessions;
+ int my_active_session;
+ bool my_can_multi_session;
+};
+
+#endif // #ifndef MOCK_LOGIN1_SEAT_H
diff --git a/tests/backend-dbus/mock-object.cc b/tests/backend-dbus/mock-object.cc
new file mode 100644
index 0000000..af9330b
--- /dev/null
+++ b/tests/backend-dbus/mock-object.cc
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include "mock-object.h"
+
+namespace
+{
+ const int TIMEOUT_SECONDS = 5;
+
+ gboolean on_timeout_reached (gpointer loop)
+ {
+ g_main_loop_quit (static_cast<GMainLoop*>(loop));
+ return G_SOURCE_REMOVE;
+ }
+
+ void on_name_acquired (GDBusConnection * connection G_GNUC_UNUSED,
+ const char * name G_GNUC_UNUSED,
+ gpointer loop)
+ {
+ //g_debug ("name '%s' acquired", name);
+ g_main_loop_quit (static_cast<GMainLoop*>(loop));
+ }
+
+ void on_name_lost (GDBusConnection * connection G_GNUC_UNUSED,
+ const char * name G_GNUC_UNUSED,
+ gpointer loop)
+ {
+ //g_debug ("name '%s' lost", name);
+ g_main_loop_quit (static_cast<GMainLoop*>(loop));
+ }
+}
+
+void
+MockObject :: set_skeleton (GDBusInterfaceSkeleton * skeleton)
+{
+ g_assert (skeleton != NULL);
+ g_assert (my_skeleton == NULL);
+ g_assert (g_variant_is_object_path (my_object_path.c_str()));
+ g_assert (my_owner_id == 0);
+
+ my_skeleton = G_DBUS_INTERFACE_SKELETON (g_object_ref (skeleton));
+
+ GError * err = NULL;
+ g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON(my_skeleton),
+ my_bus_connection,
+ my_object_path.c_str(),
+ &err);
+ g_assert_no_error (err);
+
+ my_owner_id = g_bus_own_name_on_connection (my_bus_connection,
+ my_object_name.c_str(),
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_name_acquired,
+ on_name_lost,
+ my_loop,
+ NULL);
+
+ // wait for the name to be acquired or timeout, whichever comes first
+ const guint timeout_id = g_timeout_add_seconds (TIMEOUT_SECONDS,
+ on_timeout_reached,
+ my_loop);
+ g_main_loop_run (my_loop);
+ g_assert (g_main_context_find_source_by_id (NULL, timeout_id) != NULL);
+ g_source_remove (timeout_id);
+}
+
+/***
+****
+***/
+
+MockObject :: MockObject (GMainLoop * loop,
+ GDBusConnection * bus_connection,
+ const std::string & object_name,
+ const std::string & object_path):
+ my_owner_id (0),
+ my_loop (g_main_loop_ref (loop)),
+ my_bus_connection (G_DBUS_CONNECTION (g_object_ref (bus_connection))),
+ my_object_name (object_name),
+ my_object_path (object_path),
+ my_skeleton (0)
+{
+}
+
+MockObject :: ~MockObject ()
+{
+ g_main_loop_unref (my_loop);
+
+ if (my_owner_id != 0)
+ {
+ g_bus_unown_name (my_owner_id);
+
+ my_owner_id = 0;
+ }
+
+ if (my_skeleton)
+ {
+ g_dbus_interface_skeleton_unexport (my_skeleton);
+
+ g_clear_object (&my_skeleton);
+ }
+
+ g_clear_object (&my_bus_connection);
+}
diff --git a/tests/backend-dbus/mock-object.h b/tests/backend-dbus/mock-object.h
new file mode 100644
index 0000000..8dc7070
--- /dev/null
+++ b/tests/backend-dbus/mock-object.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MOCK_OBJECT_H
+#define MOCK_OBJECT_H
+
+#include <string>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+class MockObject
+{
+ public:
+
+ MockObject (GMainLoop * loop,
+ GDBusConnection * bus_connection,
+ const std::string & object_name,
+ const std::string & object_path);
+
+ virtual ~MockObject ();
+
+ const char * name() const { return my_object_name.c_str(); }
+ const char * path() const { return my_object_path.c_str(); }
+
+ GDBusInterfaceSkeleton * skeleton() { return my_skeleton; }
+
+ protected:
+
+ guint my_owner_id;
+ GMainLoop * my_loop;
+ GDBusConnection * my_bus_connection;
+ const std::string my_object_name;
+ const std::string my_object_path;
+ GDBusInterfaceSkeleton * my_skeleton;
+
+ void set_skeleton (GDBusInterfaceSkeleton * skeleton);
+
+ private:
+ // safeguard to make sure we don't copy-by-value...
+ // this object's holding a handful of pointers
+ MockObject (const MockObject& rhs);
+ MockObject& operator= (const MockObject& rhs);
+};
+
+#endif
diff --git a/tests/backend-dbus/mock-screen-saver.cc b/tests/backend-dbus/mock-screen-saver.cc
new file mode 100644
index 0000000..1d3bb11
--- /dev/null
+++ b/tests/backend-dbus/mock-screen-saver.cc
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mock-screen-saver.h"
+
+
+gboolean
+MockScreenSaver :: handle_lock (GnomeScreenSaver * ss,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ static_cast<MockScreenSaver*>(gself)->my_last_action = Lock;
+ gnome_screen_saver_complete_lock (ss, inv);
+ return true;
+}
+
+gboolean
+MockScreenSaver :: handle_simulate_user_activity (GnomeScreenSaver * ss,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ static_cast<MockScreenSaver*>(gself)->my_last_action = UserActivity;
+ gnome_screen_saver_complete_simulate_user_activity (ss, inv);
+ return true;
+}
+
+/***
+****
+***/
+
+namespace
+{
+ const char * const SCREENSAVER_NAME = "org.gnome.ScreenSaver";
+ const char * const SCREENSAVER_PATH = "/org/gnome/ScreenSaver";
+
+}
+
+MockScreenSaver :: MockScreenSaver (GMainLoop * loop,
+ GDBusConnection * bus_connection):
+ MockObject (loop, bus_connection, SCREENSAVER_NAME, SCREENSAVER_PATH),
+ my_skeleton (gnome_screen_saver_skeleton_new ()),
+ my_last_action (None)
+{
+ g_signal_connect (my_skeleton, "handle-lock",
+ G_CALLBACK(handle_lock), this);
+ g_signal_connect (my_skeleton, "handle-simulate-user-activity",
+ G_CALLBACK(handle_simulate_user_activity), this);
+
+ set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton));
+}
+
+MockScreenSaver :: ~MockScreenSaver ()
+{
+ g_clear_object (&my_skeleton);
+}
diff --git a/tests/backend-dbus/mock-screen-saver.h b/tests/backend-dbus/mock-screen-saver.h
new file mode 100644
index 0000000..c57a4c6
--- /dev/null
+++ b/tests/backend-dbus/mock-screen-saver.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MOCK_SCREENSAVER_H
+#define MOCK_SCREENSAVER_H
+
+#include "mock-object.h" // parent class
+#include "backend-dbus/gnome-screen-saver.h" // GnomeScreenSaver
+
+class MockScreenSaver: public MockObject
+{
+ public:
+
+ MockScreenSaver (GMainLoop * loop,
+ GDBusConnection * bus_connection);
+ virtual ~MockScreenSaver ();
+
+ public:
+
+ enum Action { None, Lock, UserActivity };
+ Action last_action () { return my_last_action; }
+
+ private:
+
+ GnomeScreenSaver * my_skeleton;
+ Action my_last_action;
+
+ static gboolean handle_lock (GnomeScreenSaver *,
+ GDBusMethodInvocation *,
+ gpointer);
+ static gboolean handle_simulate_user_activity (GnomeScreenSaver *,
+ GDBusMethodInvocation *,
+ gpointer);
+
+};
+
+#endif
diff --git a/tests/backend-dbus/mock-session-manager.cc b/tests/backend-dbus/mock-session-manager.cc
new file mode 100644
index 0000000..7a4ce87
--- /dev/null
+++ b/tests/backend-dbus/mock-session-manager.cc
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mock-session-manager.h"
+
+gboolean
+MockSessionManager :: handle_logout (GnomeSessionManager * gsm,
+ GDBusMethodInvocation * inv,
+ guint arg,
+ gpointer gself)
+{
+ Action action;
+ switch (arg) {
+ case 0: action = LogoutNormal; break;
+ case 1: action = LogoutQuiet; break;
+ case 2: action = LogoutForce; break;
+ default: action = None; break;
+ }
+ static_cast<MockSessionManager*>(gself)->my_last_action = action;
+ gnome_session_manager_complete_logout (gsm, inv);
+ return true;
+}
+
+ /***
+****
+***/
+
+namespace
+{
+ const char * const SESSION_MANAGER_NAME = "org.gnome.SessionManager";
+ const char * const SESSION_MANAGER_PATH = "/org/gnome/SessionManager";
+
+}
+
+MockSessionManager :: MockSessionManager (GMainLoop * loop,
+ GDBusConnection * bus_connection):
+ MockObject (loop, bus_connection, SESSION_MANAGER_NAME, SESSION_MANAGER_PATH),
+ my_skeleton (gnome_session_manager_skeleton_new ()),
+ my_last_action (None)
+{
+ g_signal_connect (my_skeleton, "handle-logout",
+ G_CALLBACK(handle_logout), this);
+
+ set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton));
+}
+
+MockSessionManager :: ~MockSessionManager ()
+{
+ g_clear_object (&my_skeleton);
+}
diff --git a/tests/backend-dbus/mock-session-manager.h b/tests/backend-dbus/mock-session-manager.h
new file mode 100644
index 0000000..6a21277
--- /dev/null
+++ b/tests/backend-dbus/mock-session-manager.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MOCK_SESSION_MANAGER_H
+#define MOCK_SESSION_MANAGER_H
+
+#include "mock-object.h" // parent class
+#include "backend-dbus/gnome-session-manager.h" // GnomeSessionManager
+
+class MockSessionManager: public MockObject
+{
+ public:
+
+ MockSessionManager (GMainLoop * loop,
+ GDBusConnection * bus_connection);
+ virtual ~MockSessionManager ();
+
+ public:
+
+ enum Action { None, LogoutNormal, LogoutQuiet, LogoutForce };
+ Action last_action () { return my_last_action; }
+
+ private:
+
+ GnomeSessionManager * my_skeleton;
+ Action my_last_action;
+
+ static gboolean handle_logout (GnomeSessionManager *,
+ GDBusMethodInvocation *,
+ guint,
+ gpointer);
+};
+
+#endif
diff --git a/tests/backend-dbus/mock-user.cc b/tests/backend-dbus/mock-user.cc
new file mode 100644
index 0000000..f74b5a4
--- /dev/null
+++ b/tests/backend-dbus/mock-user.cc
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mock-user.h"
+
+/***
+****
+***/
+
+const char *
+MockUser :: username () const
+{
+ return accounts_user_get_user_name (my_skeleton);
+}
+
+const char *
+MockUser :: realname () const
+{
+ return accounts_user_get_real_name (my_skeleton);
+}
+
+void
+MockUser :: set_realname (const char * realname)
+{
+ accounts_user_set_real_name (my_skeleton, realname);
+ accounts_user_emit_changed (my_skeleton);
+}
+
+guint
+MockUser :: uid () const
+{
+ return accounts_user_get_uid (my_skeleton);
+}
+
+guint64
+MockUser :: login_frequency () const
+{
+ return accounts_user_get_login_frequency (my_skeleton);
+}
+
+void
+MockUser :: set_system_account (gboolean b)
+{
+ accounts_user_set_system_account (my_skeleton, b);
+}
+
+bool
+MockUser :: is_guest () const
+{
+ // a guest will look like this:
+ // username:[guest-jjbEVV] realname:[Guest] system:[1]
+ return accounts_user_get_system_account (my_skeleton)
+ && !g_ascii_strcasecmp (accounts_user_get_real_name(my_skeleton), "Guest");
+}
+
+/***
+****
+***/
+
+namespace
+{
+ const char * const DBUS_ACCOUNTS_NAME = "org.freedesktop.Accounts";
+
+ static guint next_uid = 1000;
+
+ std::string path_for_uid (guint uid)
+ {
+ char * tmp;
+ std::string ret;
+ const char * const DBUS_ACCOUNTS_PATH = "/org/freedesktop/Accounts";
+ tmp = g_strdup_printf ("%s/User%u", DBUS_ACCOUNTS_PATH, uid);
+ ret = tmp;
+ g_free (tmp);
+ return ret;
+ }
+}
+
+guint
+MockUser :: get_next_uid ()
+{
+ return next_uid++;
+}
+
+
+MockUser :: MockUser (GMainLoop * loop,
+ GDBusConnection * bus_connection,
+ const char * userName,
+ const char * realName,
+ guint64 login_frequency,
+ guint uid_):
+ MockObject (loop, bus_connection, DBUS_ACCOUNTS_NAME, path_for_uid(uid_)),
+ my_skeleton (accounts_user_skeleton_new ())
+{
+ accounts_user_set_uid (my_skeleton, uid_);
+ accounts_user_set_user_name (my_skeleton, userName);
+ accounts_user_set_real_name (my_skeleton, realName);
+ accounts_user_set_login_frequency (my_skeleton, login_frequency);
+ accounts_user_set_system_account (my_skeleton, false);
+
+ set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton));
+}
+
+MockUser :: ~MockUser ()
+{
+ g_signal_handlers_disconnect_by_data (my_skeleton, this);
+ g_clear_object (&my_skeleton);
+}
diff --git a/tests/backend-dbus/mock-user.h b/tests/backend-dbus/mock-user.h
new file mode 100644
index 0000000..c1d3d0f
--- /dev/null
+++ b/tests/backend-dbus/mock-user.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MOCK_USER_H
+#define MOCK_USER_H
+
+#include "mock-object.h" // parent class
+#include "backend-dbus/dbus-user.h" // AccountsUser
+
+class MockUser: public MockObject
+{
+ protected:
+
+ static guint get_next_uid ();
+
+ public:
+
+ MockUser (GMainLoop * loop,
+ GDBusConnection * bus_connection,
+ const char * userName,
+ const char * realName,
+ guint64 login_frequency,
+ guint uid = get_next_uid());
+ virtual ~MockUser ();
+
+ const char * username () const;
+ const char * realname () const;
+ void set_realname (const char *);
+ guint uid () const;
+ guint64 login_frequency () const;
+ //bool system_account() const;
+
+ bool is_guest() const;
+ void set_system_account (gboolean b);
+
+ private:
+
+ AccountsUser * my_skeleton;
+};
+
+#endif
diff --git a/tests/backend-dbus/mock-webcredentials.cc b/tests/backend-dbus/mock-webcredentials.cc
new file mode 100644
index 0000000..22e10b7
--- /dev/null
+++ b/tests/backend-dbus/mock-webcredentials.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mock-webcredentials.h"
+
+namespace
+{
+ const char * const MY_NAME = "com.canonical.indicators.webcredentials";
+ const char * const MY_PATH = "/com/canonical/indicators/webcredentials";
+}
+
+MockWebcredentials :: MockWebcredentials (GMainLoop * loop,
+ GDBusConnection * bus_connection):
+ MockObject (loop, bus_connection, MY_NAME, MY_PATH),
+ my_skeleton (webcredentials_skeleton_new ())
+{
+ set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton));
+}
+
+MockWebcredentials :: ~MockWebcredentials ()
+{
+ g_clear_object (&my_skeleton);
+}
diff --git a/tests/backend-dbus/mock-webcredentials.h b/tests/backend-dbus/mock-webcredentials.h
new file mode 100644
index 0000000..fd1b10c
--- /dev/null
+++ b/tests/backend-dbus/mock-webcredentials.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MOCK_WEBCREDENTIALS_H
+#define MOCK_WEBCREDENTIALS_H
+
+#include "mock-object.h" // parent class
+#include "backend-dbus/dbus-webcredentials.h" // Webcredentials
+
+class MockWebcredentials: public MockObject
+{
+ public:
+
+ MockWebcredentials (GMainLoop * loop,
+ GDBusConnection * bus_connection);
+ virtual ~MockWebcredentials ();
+
+ bool has_error () const { return webcredentials_get_error_status (my_skeleton); }
+ void set_error (bool b) const { webcredentials_set_error_status (my_skeleton, b); }
+
+ private:
+
+ Webcredentials * my_skeleton;
+};
+
+#endif
diff --git a/tests/backend-dbus/test-actions.cc b/tests/backend-dbus/test-actions.cc
new file mode 100644
index 0000000..c0f8517
--- /dev/null
+++ b/tests/backend-dbus/test-actions.cc
@@ -0,0 +1,434 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gtest-mock-dbus-fixture.h"
+
+#include "backend.h"
+#include "backend-dbus/backend-dbus.h"
+
+#define SUPPRESS_KEY "suppress-logout-restart-shutdown"
+
+/***
+****
+***/
+
+class Actions: public GTestMockDBusFixture
+{
+ private:
+
+ typedef GTestMockDBusFixture super;
+
+ protected:
+
+ GCancellable * cancellable;
+ IndicatorSessionActions * actions;
+ GSettings * indicator_settings;
+
+ virtual void SetUp ()
+ {
+ super :: SetUp ();
+
+ // init 'actions'
+ indicator_settings = g_settings_new ("com.canonical.indicator.session");
+ cancellable = g_cancellable_new ();
+ actions = 0;
+ backend_get (cancellable, &actions, NULL, NULL);
+ g_assert (actions != 0);
+ wait_msec (300);
+ }
+
+ virtual void TearDown ()
+ {
+ g_cancellable_cancel (cancellable);
+ g_clear_object (&indicator_settings);
+ g_clear_object (&cancellable);
+ g_clear_object (&actions);
+
+ super :: TearDown ();
+ }
+};
+
+/***
+****
+***/
+
+TEST_F (Actions, HelloWorld)
+{
+ ASSERT_TRUE (true);
+}
+
+namespace
+{
+ static gboolean toggle_can_switch (gpointer settings)
+ {
+ const char * key = "disable-user-switching";
+ gboolean b = g_settings_get_boolean (G_SETTINGS(settings), key);
+ g_settings_set_boolean (G_SETTINGS(settings), key, !b);
+ return G_SOURCE_REMOVE;
+ }
+}
+
+TEST_F (Actions, CanSwitch)
+{
+ const char * schema_id = "org.gnome.desktop.lockdown";
+ const char * settings_key = "disable-user-switching";
+ GSettings * s = g_settings_new (schema_id);
+
+ for (int i=0; i<3; ++i)
+ {
+ bool b;
+ gboolean b2;
+
+ b = login1_seat->can_activate_sessions() && !g_settings_get_boolean (s, settings_key);
+ ASSERT_EQ (b, indicator_session_actions_can_switch (actions));
+ g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_SWITCH, &b2, NULL);
+ ASSERT_EQ (b, b2);
+
+ g_idle_add (toggle_can_switch, s);
+ wait_for_signal (actions, "notify::" INDICATOR_SESSION_ACTIONS_PROP_CAN_SWITCH);
+ }
+
+ g_object_unref (s);
+}
+
+namespace
+{
+ static gboolean toggle_can_lock (gpointer settings)
+ {
+ const char * key = "disable-lock-screen";
+ gboolean b = g_settings_get_boolean (G_SETTINGS(settings), key);
+ g_settings_set_boolean (G_SETTINGS(settings), key, !b);
+ return G_SOURCE_REMOVE;
+ }
+}
+
+TEST_F (Actions, CanLock)
+{
+ const char * schema_id = "org.gnome.desktop.lockdown";
+ const char * settings_key = "disable-lock-screen";
+ GSettings * s = g_settings_new (schema_id);
+
+ for (int i=0; i<3; ++i)
+ {
+ bool b;
+ gboolean b2;
+
+ b = g_settings_get_boolean (s, settings_key);
+ ASSERT_EQ (b, !indicator_session_actions_can_lock (actions));
+ g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_LOCK, &b2, NULL);
+ ASSERT_EQ (b, !b2);
+
+ g_idle_add (toggle_can_lock, s);
+ wait_for_signal (actions, "notify::" INDICATOR_SESSION_ACTIONS_PROP_CAN_LOCK);
+ }
+
+ g_object_unref (s);
+}
+
+namespace
+{
+ static gboolean toggle_can_logout (gpointer settings)
+ {
+ const char * key = "disable-log-out";
+ gboolean b = g_settings_get_boolean (G_SETTINGS(settings), key);
+ g_settings_set_boolean (G_SETTINGS(settings), key, !b);
+ return G_SOURCE_REMOVE;
+ }
+}
+
+TEST_F (Actions, CanLogout)
+{
+ const char * schema_id = "org.gnome.desktop.lockdown";
+ const char * settings_key = "disable-log-out";
+ GSettings * s = g_settings_new (schema_id);
+
+ for (int i=0; i<3; ++i)
+ {
+ bool b;
+ gboolean b2;
+
+ b = g_settings_get_boolean (s, settings_key);
+ ASSERT_EQ (b, !indicator_session_actions_can_logout (actions));
+ g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_LOGOUT, &b2, NULL);
+ ASSERT_EQ (b, !b2);
+
+ g_idle_add (toggle_can_logout, s);
+ wait_for_signal (actions, "notify::" INDICATOR_SESSION_ACTIONS_PROP_CAN_LOGOUT);
+ }
+
+ g_object_unref (s);
+}
+
+TEST_F (Actions, CanSuspend)
+{
+ const std::string can_suspend = login1_manager->can_suspend ();
+ gboolean b = indicator_session_actions_can_suspend (actions);
+ ASSERT_EQ (b, can_suspend=="yes" || can_suspend=="challenge");
+}
+
+TEST_F (Actions, CanHibernate)
+{
+ const std::string can_hibernate = login1_manager->can_hibernate ();
+ gboolean b = indicator_session_actions_can_hibernate (actions);
+ ASSERT_EQ (b, can_hibernate=="yes" || can_hibernate=="challenge");
+}
+
+TEST_F (Actions, Reboot)
+{
+ ASSERT_TRUE (login1_manager->last_action().empty());
+ ASSERT_FALSE (g_settings_get_boolean (indicator_settings, SUPPRESS_KEY));
+
+ // confirm that user is prompted
+ // and that no action is taken when the user cancels the dialog
+ indicator_session_actions_reboot (actions);
+ wait_msec (50);
+ ASSERT_TRUE (end_session_dialog->is_open());
+ end_session_dialog->cancel();
+ wait_msec (50);
+ ASSERT_TRUE (login1_manager->last_action().empty());
+
+ // confirm that user is prompted
+ // and that no action is taken when the user cancels the dialog
+ indicator_session_actions_reboot (actions);
+ wait_msec (50);
+ ASSERT_TRUE (end_session_dialog->is_open ());
+ end_session_dialog->confirm_reboot ();
+ wait_msec (100);
+ ASSERT_EQ (login1_manager->last_action(), "reboot");
+
+ // confirm that we try to reboot w/o prompting
+ // if prompting is disabled
+ login1_manager->clear_last_action ();
+ ASSERT_EQ ("", login1_manager->last_action());
+ g_settings_set_boolean (indicator_settings, SUPPRESS_KEY, TRUE);
+ wait_msec (50);
+ ASSERT_TRUE (login1_manager->last_action().empty());
+ wait_msec (50);
+ indicator_session_actions_reboot (actions);
+ wait_msec (50);
+ ASSERT_EQ ("reboot", login1_manager->last_action());
+
+ g_settings_reset (indicator_settings, SUPPRESS_KEY);
+}
+
+TEST_F (Actions, PowerOff)
+{
+ ASSERT_TRUE (login1_manager->last_action().empty());
+
+ // confirm that user is prompted
+ // and that no action is taken when the user cancels the dialog
+ indicator_session_actions_power_off (actions);
+ wait_msec (50);
+ ASSERT_TRUE (end_session_dialog->is_open());
+ end_session_dialog->cancel();
+ wait_msec (50);
+ ASSERT_TRUE (login1_manager->last_action().empty());
+
+ // confirm that user is prompted
+ // and that no action is taken when the user cancels the dialog
+ indicator_session_actions_power_off (actions);
+ wait_msec (50);
+ ASSERT_TRUE (end_session_dialog->is_open ());
+ end_session_dialog->confirm_shutdown ();
+ wait_msec (100);
+ ASSERT_EQ (login1_manager->last_action(), "power-off");
+
+ // confirm that we try to shutdown w/o prompting
+ // if the EndSessionDialog isn't available
+ // if prompting is disabled
+ login1_manager->clear_last_action ();
+ ASSERT_EQ ("", login1_manager->last_action());
+ g_settings_set_boolean (indicator_settings, SUPPRESS_KEY, TRUE);
+ wait_msec (50);
+ indicator_session_actions_power_off (actions);
+ wait_msec (50);
+ ASSERT_EQ (login1_manager->last_action(), "power-off");
+
+ g_settings_reset (indicator_settings, SUPPRESS_KEY);
+}
+
+TEST_F (Actions, Logout)
+{
+ ASSERT_EQ (MockSessionManager::None, session_manager->last_action ());
+
+ // confirm that user is prompted
+ // and that no action is taken when the user cancels the dialog
+ indicator_session_actions_logout (actions);
+ wait_msec (50);
+ ASSERT_TRUE (end_session_dialog->is_open());
+ end_session_dialog->cancel();
+ wait_msec (50);
+ ASSERT_EQ (MockSessionManager::None, session_manager->last_action ());
+
+ // confirm that user is prompted
+ // and that no action is taken when the user cancels the dialog
+ indicator_session_actions_logout (actions);
+ wait_msec (50);
+ ASSERT_TRUE (end_session_dialog->is_open ());
+ end_session_dialog->confirm_logout ();
+ wait_msec (100);
+ ASSERT_EQ (MockSessionManager::LogoutQuiet, session_manager->last_action ());
+
+ // confirm that we try to call SessionManager::LogoutQuet
+ // when prompts are disabled
+ login1_manager->clear_last_action ();
+ ASSERT_EQ ("", login1_manager->last_action());
+ g_settings_set_boolean (indicator_settings, SUPPRESS_KEY, TRUE);
+ wait_msec (50);
+ indicator_session_actions_logout (actions);
+ wait_msec (50);
+ ASSERT_EQ (MockSessionManager::LogoutQuiet, session_manager->last_action ());
+
+ g_settings_reset (indicator_settings, SUPPRESS_KEY);
+}
+
+TEST_F (Actions, Suspend)
+{
+ ASSERT_TRUE (login1_manager->last_action().empty());
+ indicator_session_actions_suspend (actions);
+ wait_msec (50);
+ ASSERT_EQ (login1_manager->last_action(), "suspend");
+}
+
+TEST_F (Actions, Hibernate)
+{
+ ASSERT_TRUE (login1_manager->last_action().empty());
+ indicator_session_actions_hibernate (actions);
+ wait_msec (50);
+ ASSERT_EQ (login1_manager->last_action(), "hibernate");
+}
+
+TEST_F (Actions, SwitchToScreensaver)
+{
+ ASSERT_EQ (MockScreenSaver::None, screen_saver->last_action());
+ indicator_session_actions_switch_to_screensaver (actions);
+ wait_msec (50);
+ ASSERT_EQ (MockScreenSaver::Lock, screen_saver->last_action());
+}
+
+TEST_F (Actions, SwitchToGreeter)
+{
+ ASSERT_NE (MockDisplayManagerSeat::GREETER, dm_seat->last_action());
+ indicator_session_actions_switch_to_greeter (actions);
+ wait_msec (50);
+ ASSERT_EQ (MockDisplayManagerSeat::GREETER, dm_seat->last_action());
+}
+
+TEST_F (Actions, SwitchToGuest)
+{
+ // allow guests
+ dm_seat->set_guest_allowed (true);
+
+ // set up a guest
+ MockUser * guest_user = new MockUser (loop, conn, "guest-zzbEVV", "Guest", 10);
+ guest_user->set_system_account (true);
+ accounts->add_user (guest_user);
+ int guest_session_tag = login1_manager->add_session (login1_seat, guest_user);
+
+ // try to switch to guest
+ indicator_session_actions_switch_to_guest (actions);
+ wait_for_signal (login1_seat->skeleton(), "notify::active-session");
+ ASSERT_EQ (guest_session_tag, login1_seat->active_session());
+ wait_msec (50);
+}
+
+TEST_F (Actions, SwitchToUsername)
+{
+ const char * const dr1_username = "whartnell";
+ const char * const dr2_username = "ptroughton";
+ MockUser * dr1_user;
+ MockUser * dr2_user;
+ int dr1_session;
+ int dr2_session;
+
+ dr1_user = accounts->find_by_username (dr1_username);
+ dr1_session = login1_manager->add_session (login1_seat, dr1_user);
+
+ dr2_user = accounts->find_by_username (dr2_username);
+ dr2_session = login1_manager->add_session (login1_seat, dr2_user);
+
+ indicator_session_actions_switch_to_username (actions, dr1_username);
+ wait_for_signal (login1_seat->skeleton(), "notify::active-session");
+ ASSERT_EQ (dr1_session, login1_seat->active_session());
+ wait_msec (50);
+
+ indicator_session_actions_switch_to_username (actions, dr2_username);
+ wait_for_signal (login1_seat->skeleton(), "notify::active-session");
+ ASSERT_EQ (dr2_session, login1_seat->active_session());
+ wait_msec (50);
+
+ indicator_session_actions_switch_to_username (actions, dr1_username);
+ wait_for_signal (login1_seat->skeleton(), "notify::active-session");
+ ASSERT_EQ (dr1_session, login1_seat->active_session());
+ wait_msec (50);
+}
+
+TEST_F (Actions, HasOnlineAccountError)
+{
+ bool b;
+ gboolean gb;
+
+ b = webcredentials->has_error ();
+ ASSERT_EQ (b, indicator_session_actions_has_online_account_error (actions));
+ g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_HAS_ONLINE_ACCOUNT_ERROR, &gb, NULL);
+ ASSERT_EQ (b, gb);
+
+ b = !b;
+ webcredentials->set_error (b);
+ wait_msec (50);
+ ASSERT_EQ (b, indicator_session_actions_has_online_account_error (actions));
+ g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_HAS_ONLINE_ACCOUNT_ERROR, &gb, NULL);
+ ASSERT_EQ (b, gb);
+
+ b = !b;
+ webcredentials->set_error (b);
+ wait_msec (50);
+ ASSERT_EQ (b, indicator_session_actions_has_online_account_error (actions));
+ g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_HAS_ONLINE_ACCOUNT_ERROR, &gb, NULL);
+ ASSERT_EQ (b, gb);
+}
+
+namespace
+{
+ static gboolean toggle_suppress (gpointer settings)
+ {
+ const char * key = SUPPRESS_KEY;
+ gboolean b = g_settings_get_boolean (G_SETTINGS(settings), key);
+ g_settings_set_boolean (G_SETTINGS(settings), key, !b);
+ return G_SOURCE_REMOVE;
+ }
+}
+
+TEST_F (Actions, SuppressPrompts)
+{
+ for (int i=0; i<3; ++i)
+ {
+ bool b;
+ gboolean b2;
+
+ b = indicator_session_actions_can_prompt (actions);
+ b2 = !g_settings_get_boolean (indicator_settings, SUPPRESS_KEY);
+ ASSERT_EQ (b, b2);
+
+ g_idle_add (toggle_suppress, indicator_settings);
+ wait_for_signal (actions, "notify::" INDICATOR_SESSION_ACTIONS_PROP_CAN_PROMPT);
+ }
+
+ g_settings_reset (indicator_settings, SUPPRESS_KEY);
+}
diff --git a/tests/backend-dbus/test-guest.cc b/tests/backend-dbus/test-guest.cc
new file mode 100644
index 0000000..f71d445
--- /dev/null
+++ b/tests/backend-dbus/test-guest.cc
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gtest-mock-dbus-fixture.h"
+
+#include "backend.h"
+#include "backend-dbus/backend-dbus.h"
+
+/***
+****
+***/
+
+class Guest: public GTestMockDBusFixture
+{
+ private:
+
+ typedef GTestMockDBusFixture super;
+
+ protected:
+
+ GCancellable * cancellable;
+ IndicatorSessionGuest * guest;
+
+ virtual void SetUp ()
+ {
+ super :: SetUp ();
+
+ // get the guest-dbus
+ cancellable = g_cancellable_new ();
+ guest = 0;
+ backend_get (cancellable, NULL, NULL, &guest);
+ wait_msec (100);
+
+ // test the default state
+ ASSERT_TRUE (guest != 0);
+ ASSERT_FALSE (indicator_session_guest_is_allowed (guest));
+ ASSERT_FALSE (indicator_session_guest_is_logged_in (guest));
+ ASSERT_FALSE (indicator_session_guest_is_active (guest));
+ }
+
+ virtual void TearDown ()
+ {
+ g_cancellable_cancel (cancellable);
+ g_clear_object (&cancellable);
+ g_clear_object (&guest);
+
+ super :: TearDown ();
+ }
+
+ protected:
+
+ void add_mock_guest (MockUser *& guest_user,
+ int & guest_session_tag)
+ {
+ guest_user = new MockUser (loop, conn, "guest-jjbEVV", "Guest", 10, 100);
+ accounts->add_user (guest_user);
+ guest_user->set_system_account (true);
+ guest_session_tag = login1_manager->add_session (login1_seat, guest_user);
+ }
+};
+
+/**
+ * Confirms that the Fixture's SetUp() and TearDown() work
+ */
+TEST_F (Guest, HelloWorld)
+{
+ ASSERT_TRUE (true);
+}
+
+/**
+ * Toggle in the DM whether or not guests are allowed.
+ * Confirm that "guest" reflects the changes.
+ */
+TEST_F (Guest, Allowed)
+{
+ dm_seat->set_guest_allowed (true);
+ wait_for_signal (guest, "notify::guest-is-allowed");
+ ASSERT_TRUE (indicator_session_guest_is_allowed (guest));
+ ASSERT_FALSE (indicator_session_guest_is_logged_in (guest));
+ ASSERT_FALSE (indicator_session_guest_is_active (guest));
+
+ dm_seat->set_guest_allowed (false);
+ wait_for_signal (guest, "notify::guest-is-allowed");
+ ASSERT_FALSE (indicator_session_guest_is_allowed (guest));
+ ASSERT_FALSE (indicator_session_guest_is_logged_in (guest));
+ ASSERT_FALSE (indicator_session_guest_is_active (guest));
+}
+
+/**
+ * Have a guest user log in & out.
+ * Confirm that "guest" reflects the changes.
+ */
+TEST_F (Guest, Login)
+{
+ gboolean b;
+
+ dm_seat->set_guest_allowed (true);
+
+ // Log a Guest in
+ // And confirm that guest's is_login changes to true
+ MockUser * guest_user;
+ int session_tag;
+ add_mock_guest (guest_user, session_tag);
+ wait_for_signal (guest, "notify::guest-is-logged-in");
+ ASSERT_TRUE (indicator_session_guest_is_allowed (guest));
+ ASSERT_TRUE (indicator_session_guest_is_logged_in (guest));
+ g_object_get (guest, INDICATOR_SESSION_GUEST_PROPERTY_LOGGED_IN, &b,NULL);
+ ASSERT_TRUE (b);
+ ASSERT_FALSE (indicator_session_guest_is_active (guest));
+
+ // Log the Guest User out
+ // and confirm that guest's is_login changes to false
+ login1_manager->remove_session (login1_seat, session_tag);
+ accounts->remove_user (guest_user);
+ delete guest_user;
+ wait_for_signal (guest, "notify::guest-is-logged-in");
+ ASSERT_TRUE (indicator_session_guest_is_allowed (guest));
+ ASSERT_FALSE (indicator_session_guest_is_logged_in (guest));
+ g_object_get (guest, INDICATOR_SESSION_GUEST_PROPERTY_LOGGED_IN, &b,NULL);
+ ASSERT_FALSE (b);
+ ASSERT_FALSE (indicator_session_guest_is_active (guest));
+}
+
+/**
+ * Activate a Guest session, then activate a different session.
+ * Confirm that "guest" reflects the changes.
+ */
+TEST_F (Guest, Active)
+{
+ gboolean b;
+ const int user_session_tag = login1_seat->active_session();
+
+ dm_seat->set_guest_allowed (true);
+ MockUser * guest_user;
+ int guest_session_tag;
+ add_mock_guest (guest_user, guest_session_tag);
+
+ // Activate the guest session
+ // and confirm that guest's is_active changes to true
+ login1_seat->activate_session (guest_session_tag);
+ wait_for_signal (guest, "notify::guest-is-active-session");
+ ASSERT_TRUE (indicator_session_guest_is_allowed (guest));
+ ASSERT_TRUE (indicator_session_guest_is_logged_in (guest));
+ ASSERT_TRUE (indicator_session_guest_is_active (guest));
+ g_object_get (guest, INDICATOR_SESSION_GUEST_PROPERTY_ACTIVE, &b,NULL);
+ ASSERT_TRUE (b);
+
+ // Activate a non-guest session
+ // and confirm that guest's is_active changes to false
+ login1_seat->activate_session (user_session_tag);
+ wait_for_signal (guest, "notify::guest-is-active-session");
+ ASSERT_TRUE (indicator_session_guest_is_allowed (guest));
+ ASSERT_TRUE (indicator_session_guest_is_logged_in (guest));
+ ASSERT_FALSE (indicator_session_guest_is_active (guest));
+ g_object_get (guest, INDICATOR_SESSION_GUEST_PROPERTY_ACTIVE, &b,NULL);
+ ASSERT_FALSE (b);
+}
+
+/**
+ * Activate a guest session using the "guest" API.
+ * Confirm that the guest session gets activated on the bus.
+ */
+TEST_F (Guest, Activate)
+{
+ dm_seat->set_guest_allowed (true);
+ wait_for_signal (guest, "notify::guest-is-allowed");
+
+ MockUser * guest_user;
+ int guest_session_tag;
+ add_mock_guest (guest_user, guest_session_tag);
+
+ indicator_session_guest_switch_to_guest (guest);
+
+ wait_for_signal (login1_seat->skeleton(), "notify::active-session");
+ ASSERT_EQ (guest_session_tag, login1_seat->active_session());
+ wait_msec (50);
+}
diff --git a/tests/backend-dbus/test-users.cc b/tests/backend-dbus/test-users.cc
new file mode 100644
index 0000000..dccacbb
--- /dev/null
+++ b/tests/backend-dbus/test-users.cc
@@ -0,0 +1,381 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gtest-mock-dbus-fixture.h"
+
+#include "backend.h"
+#include "backend-dbus/backend-dbus.h"
+
+/***
+****
+***/
+
+class Users: public GTestMockDBusFixture
+{
+ private:
+
+ typedef GTestMockDBusFixture super;
+
+ protected:
+
+ GCancellable * cancellable;
+ IndicatorSessionUsers * users;
+
+ virtual void SetUp ()
+ {
+ super :: SetUp ();
+
+ init_event_keys (0);
+
+ // init 'users'
+ cancellable = g_cancellable_new ();
+ users = 0;
+ backend_get (cancellable, NULL, &users, NULL);
+ g_assert (users != 0);
+
+ // wait for the users added by GTestMockDBusFixture::SetUp() to show up
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_ADDED, 12);
+ init_event_keys (0);
+ }
+
+ virtual void TearDown ()
+ {
+ g_cancellable_cancel (cancellable);
+ g_clear_object (&cancellable);
+ g_clear_object (&users);
+
+ super :: TearDown ();
+ }
+
+ protected:
+
+ void compare_user (const MockUser * mu, const IndicatorSessionUser * isu, const std::string& user_state)
+ {
+ ASSERT_EQ (user_state, login1_seat->user_state (mu->uid()));
+ ASSERT_EQ (mu->uid(), isu->uid);
+ ASSERT_EQ (mu->login_frequency(), isu->login_frequency);
+ ASSERT_STREQ (mu->username(), isu->user_name);
+ ASSERT_STREQ (mu->realname(), isu->real_name);
+ ASSERT_EQ (mu->uid(), isu->uid);
+ ASSERT_EQ (user_state!="offline", isu->is_logged_in);
+ ASSERT_EQ (user_state=="active", isu->is_current_user);
+ }
+
+ void compare_user (const MockUser * mu, guint uid, const std::string& user_state)
+ {
+ IndicatorSessionUser * isu;
+ isu = indicator_session_users_get_user (users, uid);
+ compare_user (mu, isu, user_state);
+ indicator_session_user_free (isu);
+ }
+
+ void compare_user (guint uid, const std::string& user_state)
+ {
+ IndicatorSessionUser * isu = indicator_session_users_get_user (users, uid);
+ MockUser * mu = accounts->find_by_uid (uid);
+ compare_user (mu, isu, user_state);
+ indicator_session_user_free (isu);
+ }
+
+ private:
+
+ void init_event_keys (size_t n)
+ {
+ expected_event_count = n;
+ event_keys.clear();
+ }
+
+ static gboolean
+ wait_for_signals__timeout (gpointer name)
+ {
+ g_error ("%s: timed out waiting for signal '%s'", G_STRLOC, (char*)name);
+ return G_SOURCE_REMOVE;
+ }
+
+ static void
+ wait_for_signals__event (IndicatorSessionUser * u G_GNUC_UNUSED,
+ guint uid,
+ gpointer gself)
+ {
+ Users * self = static_cast<Users*>(gself);
+
+ self->event_keys.push_back (uid);
+
+ if (self->event_keys.size() == self->expected_event_count)
+ g_main_loop_quit (self->loop);
+ }
+
+ protected:
+
+ std::vector<guint> event_keys;
+ size_t expected_event_count;
+
+ void wait_for_signals (gpointer o, const gchar * name, size_t n)
+ {
+ const int timeout_seconds = 5; // arbitrary
+
+ init_event_keys (n);
+
+ guint handler_id = g_signal_connect (o, name,
+ G_CALLBACK(wait_for_signals__event),
+ this);
+ gulong timeout_id = g_timeout_add_seconds (timeout_seconds,
+ wait_for_signals__timeout,
+ (gpointer)name);
+ g_main_loop_run (loop);
+ g_source_remove (timeout_id);
+ g_signal_handler_disconnect (o, handler_id);
+ }
+};
+
+/***
+****
+***/
+
+/**
+ * Confirm that the fixture's SetUp() and TearDown() work
+ */
+TEST_F (Users, HelloWorld)
+{
+ ASSERT_TRUE (true);
+}
+
+/**
+ * Confirm that 'users' can get the cached users from our Mock Accounts
+ */
+TEST_F (Users, InitialUsers)
+{
+ GList * l;
+ GList * uids = indicator_session_users_get_uids (users);
+
+ ASSERT_EQ (12, g_list_length (uids));
+
+ for (l=uids; l!=NULL; l=l->next)
+ {
+ const guint uid = GPOINTER_TO_UINT (l->data);
+ compare_user (uid, login1_seat->user_state (uid));
+ }
+
+ g_list_free (uids);
+}
+
+/**
+ * Confirm that 'users' can tell when a new user is added
+ */
+TEST_F (Users, UserAdded)
+{
+ MockUser * mu;
+
+ mu = new MockUser (loop, conn, "pcushing", "Peter Cushing", 2);
+ accounts->add_user (mu);
+ ASSERT_EQ (0, event_keys.size());
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_ADDED, 1);
+ ASSERT_EQ (1, event_keys.size());
+ compare_user (mu, event_keys[0], "offline");
+}
+
+/**
+ * Confirm that 'users' can tell when a user is removed
+ */
+TEST_F (Users, UserRemoved)
+{
+ MockUser * mu = accounts->find_by_username ("pdavison");
+
+ /* confirm that users knows about pdavison */
+ IndicatorSessionUser * isu = indicator_session_users_get_user (users, mu->uid());
+ ASSERT_TRUE (isu != NULL);
+ compare_user (mu, isu, "offline");
+ g_clear_pointer (&isu, indicator_session_user_free);
+
+ /* on the bus, remove pdavison. */
+ accounts->remove_user (mu);
+
+ /* now, users should emit a 'user removed' signal... */
+ ASSERT_EQ (0, event_keys.size());
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_REMOVED, 1);
+ ASSERT_EQ (1, event_keys.size());
+
+ /* confirm that users won't give us pdavison's info */
+ isu = indicator_session_users_get_user (users, mu->uid());
+ ASSERT_TRUE (isu == NULL);
+
+ /* confirm that users won't give us pdavison's uid */
+ GList * uids = indicator_session_users_get_uids (users);
+ ASSERT_TRUE (g_list_find (uids, GUINT_TO_POINTER(mu->uid())) == NULL);
+ g_list_free (uids);
+
+ delete mu;
+}
+
+/**
+ * Confirm that 'users' notices when a user's real name changes
+ */
+TEST_F (Users, RealnameChanged)
+{
+ MockUser * mu;
+
+ mu = accounts->find_by_username ("pdavison");
+ const char * const realname = "Peter M. G. Moffett";
+ mu->set_realname (realname);
+ ASSERT_NE (mu->realname(), realname);
+ ASSERT_STREQ (mu->realname(), realname);
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1);
+ ASSERT_EQ (1, event_keys.size());
+ compare_user (mu, event_keys[0], "offline");
+}
+
+/**
+ * Confirm that 'users' notices when users log in and out
+ */
+TEST_F (Users, LogInLogOut)
+{
+ // The fist doctor logs in.
+ // Confirm that 'users' notices.
+ MockUser * mu = accounts->find_by_username ("whartnell");
+ ASSERT_EQ (login1_seat->user_state (mu->uid()), "offline");
+ const int session_tag = login1_manager->add_session (login1_seat, mu);
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1);
+ ASSERT_EQ (1, event_keys.size());
+ compare_user (mu, event_keys[0], "online");
+
+ // The first doctor logs out.
+ // Confirm that 'users' notices.
+ login1_manager->remove_session (login1_seat, session_tag);
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1);
+ ASSERT_EQ (1, event_keys.size());
+ compare_user (mu, event_keys[0], "offline");
+}
+
+/**
+ * Confirm that 'users' notices when the active session changes
+ */
+TEST_F (Users, ActivateSession)
+{
+ // confirm preconditions: msmith is active, msmith is offline
+ MockUser * const whartnell = accounts->find_by_username ("whartnell");
+ ASSERT_EQ (login1_seat->user_state (whartnell->uid()), "offline");
+ MockUser * const msmith = accounts->find_by_username ("msmith");
+ ASSERT_EQ (login1_seat->user_state (msmith->uid()), "active");
+
+ // whartnell logs in... confirm that 'users' notices
+ login1_manager->add_session (login1_seat, whartnell);
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1);
+ ASSERT_EQ (1, event_keys.size());
+ compare_user (whartnell, event_keys[0], "online");
+
+ // activate whartnell's session... confirm that 'users' sees:
+ // 1. msmith changes from 'active' to 'online'
+ // 2. whartnell changes from 'online' to 'active'
+ login1_seat->switch_to_user (whartnell->username());
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 2);
+ ASSERT_EQ (2, event_keys.size());
+ compare_user (msmith, event_keys[0], "online");
+ compare_user (whartnell, event_keys[1], "active");
+
+ // reverse the test
+ login1_seat->switch_to_user (msmith->username());
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 2);
+ ASSERT_EQ (2, event_keys.size());
+ compare_user (whartnell, event_keys[0], "online");
+ compare_user (msmith, event_keys[1], "active");
+}
+
+/**
+ * Confirm that we can change the active session via users' API.
+ * This is nearly the same as ActivateSession but uses users' API
+ */
+TEST_F (Users, ActivateUser)
+{
+ // confirm preconditions: msmith is active, msmith is offline
+ MockUser * const whartnell = accounts->find_by_username ("whartnell");
+ ASSERT_EQ (login1_seat->user_state (whartnell->uid()), "offline");
+ MockUser * const msmith = accounts->find_by_username ("msmith");
+ ASSERT_EQ (login1_seat->user_state (msmith->uid()), "active");
+
+ // whartnell logs in... confirm that 'users' notices
+ login1_manager->add_session (login1_seat, whartnell);
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1);
+ ASSERT_EQ (1, event_keys.size());
+ compare_user (whartnell, event_keys[0], "online");
+
+ // activate whartnell's session... confirm that 'users' sees:
+ // 1. msmith changes from 'active' to 'online'
+ // 2. whartnell changes from 'online' to 'active'
+ indicator_session_users_activate_user (users, whartnell->uid());
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 2);
+ ASSERT_EQ (2, event_keys.size());
+ compare_user (msmith, event_keys[0], "online");
+ compare_user (whartnell, event_keys[1], "active");
+
+ // reverse the test
+ indicator_session_users_activate_user (users, msmith->uid());
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 2);
+ ASSERT_EQ (2, event_keys.size());
+ compare_user (whartnell, event_keys[0], "online");
+ compare_user (msmith, event_keys[1], "active");
+}
+
+/**
+ * Confirm that adding a Guest doesn't show up in the users list
+ */
+TEST_F (Users, UnwantedGuest)
+{
+ GList * uids;
+
+ uids = indicator_session_users_get_uids (users);
+ const size_t n = g_list_length (uids);
+ g_list_free (uids);
+
+ MockUser * mu = new MockUser (loop, conn, "guest-jjbEVV", "Guest", 1);
+ mu->set_system_account (true);
+ accounts->add_user (mu);
+ wait_msec (50);
+
+ uids = indicator_session_users_get_uids (users);
+ ASSERT_EQ (n, g_list_length (uids));
+ g_list_free (uids);
+}
+
+
+/**
+ * Confirm that we can detect live sessions
+ */
+TEST_F (Users, LiveSession)
+{
+ gboolean b;
+
+ // not initially a live session
+ ASSERT_FALSE (indicator_session_users_is_live_session (users));
+ g_object_get (users, INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION, &b, NULL);
+ ASSERT_FALSE (b);
+
+ // now add the criteria for a live session
+ MockUser * live_user = new MockUser (loop, conn, "ubuntu", "Ubuntu", 1, 999);
+ live_user->set_system_account (true);
+ accounts->add_user (live_user);
+ const int session_tag = login1_manager->add_session (login1_seat, live_user);
+ wait_msec (100);
+ login1_seat->activate_session (session_tag);
+ wait_for_signal (users, "notify::" INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION);
+
+ // confirm the backend thinks it's a live session
+ ASSERT_TRUE (indicator_session_users_is_live_session (users));
+ g_object_get (users, INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION, &b, NULL);
+ ASSERT_TRUE (b);
+}