aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/CMakeLists.txt53
-rw-r--r--tests/Makefile.am51
-rw-r--r--tests/Makefile.am.strings38
-rw-r--r--tests/backend-dbus/CMakeLists.txt62
-rw-r--r--tests/backend-dbus/gtest-mock-dbus-fixture.h130
-rw-r--r--tests/backend-dbus/mock-accounts.cc156
-rw-r--r--tests/backend-dbus/mock-accounts.h74
-rw-r--r--tests/backend-dbus/mock-consolekit-manager.cc156
-rw-r--r--tests/backend-dbus/mock-consolekit-manager.h77
-rw-r--r--tests/backend-dbus/mock-consolekit-seat.cc220
-rw-r--r--tests/backend-dbus/mock-consolekit-seat.h75
-rw-r--r--tests/backend-dbus/mock-consolekit-session.cc113
-rw-r--r--tests/backend-dbus/mock-consolekit-session.h65
-rw-r--r--tests/backend-dbus/mock-display-manager-seat.cc140
-rw-r--r--tests/backend-dbus/mock-display-manager-seat.h72
-rw-r--r--tests/backend-dbus/mock-end-session-dialog.cc89
-rw-r--r--tests/backend-dbus/mock-end-session-dialog.h67
-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-upower.cc103
-rw-r--r--tests/backend-dbus/mock-upower.h72
-rw-r--r--tests/backend-dbus/mock-user.cc131
-rw-r--r--tests/backend-dbus/mock-user.h57
-rw-r--r--tests/backend-dbus/mock-webcredentials.cc54
-rw-r--r--tests/backend-dbus/mock-webcredentials.h42
-rw-r--r--tests/backend-dbus/test-actions.cc454
-rw-r--r--tests/backend-dbus/test-guest.cc192
-rw-r--r--tests/backend-dbus/test-users.cc377
-rw-r--r--tests/backend-mock-actions.c229
-rw-r--r--tests/backend-mock-actions.h61
-rw-r--r--tests/backend-mock-guest.c129
-rw-r--r--tests/backend-mock-guest.h61
-rw-r--r--tests/backend-mock-users.c189
-rw-r--r--tests/backend-mock-users.h70
-rw-r--r--tests/backend-mock.c44
-rw-r--r--tests/backend-mock.h38
-rw-r--r--tests/com.canonical.indicator.session.backendmock.gschema.xml41
-rw-r--r--tests/com.canonical.indicator.session.gschema.xml32
-rw-r--r--tests/gtest-dbus-fixture.h134
-rw-r--r--tests/indicator-session.service.in4
-rw-r--r--tests/test-service.cc831
45 files changed, 5220 insertions, 187 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 0000000..45ab69f
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,53 @@
+# build the necessary schemas
+set_directory_properties (PROPERTIES
+ ADDITIONAL_MAKE_CLEAN_FILES gschemas.compiled)
+set_source_files_properties (gschemas.compiled GENERATED)
+
+# GSettings:
+# compile the schemas our tests use (indicator-session's, lockdown, media-keys)
+# into a gschemas.compiled file in this directory, and help the tests to find
+# that file by setting -DSCHEMA_DIR
+set (SCHEMA_DIR ${CMAKE_CURRENT_BINARY_DIR})
+add_definitions(-DSCHEMA_DIR="${SCHEMA_DIR}")
+execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} gio-2.0 --variable glib_compile_schemas
+ OUTPUT_VARIABLE COMPILE_SCHEMA_EXECUTABLE
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+add_custom_command (OUTPUT gschemas.compiled
+ DEPENDS ${CMAKE_BINARY_DIR}/data/com.canonical.indicator.session.gschema.xml
+ ${CMAKE_SOURCE_DIR}/tests/com.canonical.indicator.session.backendmock.gschema.xml
+ ${CMAKE_SOURCE_DIR}/tests/org.gnome.desktop.lockdown.gschema.xml
+ ${CMAKE_SOURCE_DIR}/tests/org.gnome.settings-daemon.plugins.media-keys.gschema.xml
+ COMMAND cp -f ${CMAKE_BINARY_DIR}/data/*gschema.xml ${SCHEMA_DIR}
+ COMMAND cp -f ${CMAKE_SOURCE_DIR}/tests/*gschema.xml ${SCHEMA_DIR}
+ COMMAND ${COMPILE_SCHEMA_EXECUTABLE} ${SCHEMA_DIR})
+
+# DBus Activation
+configure_file (indicator-session.service.in indicator-session.service)
+add_definitions(-DINDICATOR_SERVICE_DIR="${CMAKE_CURRENT_BINARY_DIR}")
+
+# look for hearder in our src dir, and also in the directories where we autogenerate files...
+include_directories (${CMAKE_SOURCE_DIR}/src)
+include_directories (${CMAKE_CURRENT_BINARY_DIR} ${SERVICE_INCLUDE_DIRS})
+
+# backendmock
+add_library (backendmock STATIC
+ backend-mock-actions.c
+ backend-mock-actions.h
+ backend-mock.c
+ backend-mock.h
+ backend-mock-guest.c
+ backend-mock-guest.h
+ backend-mock-users.c
+ backend-mock-users.h)
+set_target_properties (backendmock PROPERTIES COMPILE_FLAGS " ${CC_WARNING_ARGS}")
+
+# test-service
+add_executable (test-service
+ test-service.cc
+ gschemas.compiled)
+set_target_properties (test-service PROPERTIES COMPILE_FLAGS " ${CC_WARNING_ARGS}")
+add_test (test-service test-service)
+add_dependencies (test-service libindicatorsessionservice backendmock)
+target_link_libraries (test-service libindicatorsessionservice backendmock gtest ${SERVICE_LIBRARIES} ${GTEST_LIBS})
+
+add_subdirectory (backend-dbus)
diff --git a/tests/Makefile.am b/tests/Makefile.am
deleted file mode 100644
index 071f684..0000000
--- a/tests/Makefile.am
+++ /dev/null
@@ -1,51 +0,0 @@
-TESTS =
-CLEANFILES =
-BUILT_SOURCES =
-check_PROGRAMS =
-
-integrationcheckdir = .
-integrationcheck_PROGRAMS =
-
-###
-###
-###
-
-# stock UMB tests on user-visible strings
-include $(srcdir)/Makefile.am.strings
-
-check_LIBRARIES = libgtest.a
-nodist_libgtest_a_SOURCES = \
- $(GTEST_SOURCE)/gtest-all.cc \
- $(GTEST_SOURCE)/gtest_main.cc
-
-AM_CPPFLAGS = $(GTEST_CPPFLAGS) -I${top_srcdir}/src -Wall -Werror
-AM_CXXFLAGS = $(GTEST_CXXFLAGS)
-
-###
-###
-###
-
-BUILT_SOURCES += gschemas.compiled
-CLEANFILES += gschemas.compiled
-gschemas.compiled: Makefile
- $(AM_V_at) cp -f $(top_builddir)/data/*gschema.xml .
- $(AM_V_GEN) $(GLIB_COMPILE_SCHEMAS) --targetdir=. .
-
-
-integrationcheck:
- ./test-service
-
-integrationcheck_PROGRAMS += test-service
-test_service_SOURCES = test-service.cc
-test_service_LDADD = \
- $(TEST_SERVICE_LIBS) \
- $(XORG_GTEST_LDFLAGS) \
- libgtest.a
-test_service_CPPFLAGS = \
- -DSCHEMA_DIR="\"$(top_builddir)/tests/\"" \
- -DINDICATOR_SERVICE_DIR="\"$(abs_builddir)\"" \
- -DINDICATOR_SERVICE_PATH="\"$(top_builddir)/src/indicator-session-service\"" \
- $(TEST_SERVICE_CFLAGS) \
- $(AM_CPPFLAGS)
-
-
diff --git a/tests/Makefile.am.strings b/tests/Makefile.am.strings
deleted file mode 100644
index 26a23a8..0000000
--- a/tests/Makefile.am.strings
+++ /dev/null
@@ -1,38 +0,0 @@
-TESTS += \
- test-ellipsis \
- test-space-ellipsis \
- test-ascii-quotes
-
-#####
-# Tests for there being proper ellipsis instead of three periods in a row
-#####
-test-ellipsis: $(top_srcdir)/po
- @echo "#!/bin/bash" > $@
- @echo "(cd $(top_srcdir)/po && make $(GETTEXT_PACKAGE).pot)" >> $@
- @echo "grep -c -e \"^msgid.*\.\.\.\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"Ellipsis found in user visible strings\" >&2 && exit 1" >> $@
- @echo "exit 0" >> $@
- @chmod +x $@
-
-#####
-# Tests for there being a space before an ellipsis
-#####
-test-space-ellipsis: $(top_srcdir)/po
- @echo "#!/bin/bash" > $@
- @echo "(cd $(top_srcdir)/po && make $(GETTEXT_PACKAGE).pot)" >> $@
- @echo "grep -c -e \"^msgid.* …\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"Space before ellipsis found in user visible strings\" >&2 && exit 1" >> $@
- @echo "exit 0" >> $@
- @chmod +x $@
-
-#####
-# Tests for ASCII quote types
-#####
-test-ascii-quotes: $(top_srcdir)/po
- @echo "#!/bin/bash" > $@
- @echo "(cd $(top_srcdir)/po && make $(GETTEXT_PACKAGE).pot)" >> $@
- @echo "grep -c -e \"^msgid \\\".*'.*\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"ASCII apostrophy found in user visible strings\" >&2 && exit 1" >> $@
- @echo "grep -c -e \"^msgid \\\".*\\\".*\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"ASCII quote found in user visible strings\" >&2 && exit 1" >> $@
- @echo "grep -c -e \"^msgid \\\".*\\\`.*\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"ASCII backtick found in user visible strings\" >&2 && exit 1" >> $@
- @echo "exit 0" >> $@
- @chmod +x $@
-
-CLEANFILES += $(TESTS)
diff --git a/tests/backend-dbus/CMakeLists.txt b/tests/backend-dbus/CMakeLists.txt
new file mode 100644
index 0000000..7cd7030
--- /dev/null
+++ b/tests/backend-dbus/CMakeLists.txt
@@ -0,0 +1,62 @@
+# 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})
+
+# build desktopmock
+add_library (desktopmock STATIC
+ mock-accounts.cc
+ mock-accounts.h
+ mock-consolekit-manager.cc
+ mock-consolekit-manager.h
+ mock-consolekit-seat.cc
+ mock-consolekit-seat.h
+ mock-consolekit-session.cc
+ mock-consolekit-session.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-upower.cc
+ mock-upower.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..5c4e312
--- /dev/null
+++ b/tests/backend-dbus/gtest-mock-dbus-fixture.h
@@ -0,0 +1,130 @@
+/*
+ * 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-consolekit-manager.h"
+#include "mock-consolekit-seat.h"
+#include "mock-consolekit-session.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-upower.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;
+ MockConsoleKitSession * ck_session;
+ MockConsoleKitSeat * ck_seat;
+ MockConsoleKitManager * ck_manager;
+ MockUPower * upower;
+ 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);
+ upower = new MockUPower (loop, conn);
+ dm_seat = new MockDisplayManagerSeat (loop, conn);
+ g_setenv ("XDG_SEAT_PATH", dm_seat->path(), TRUE);
+ dm_seat->set_guest_allowed (false);
+ accounts = build_accounts_mock ();
+ ck_manager = new MockConsoleKitManager (loop, conn);
+ ck_seat = new MockConsoleKitSeat (loop, conn, true);
+ MockUser * user = accounts->find_by_username ("msmith");
+ ck_session = ck_seat->add_session_by_user (user);
+ ck_manager->add_seat (ck_seat);
+ dm_seat->set_consolekit_seat (ck_seat);
+ dm_seat->switch_to_user (user->username());
+ ASSERT_EQ (ck_session, ck_manager->current_session());
+ }
+
+ protected:
+
+ virtual void TearDown ()
+ {
+ delete accounts;
+ delete ck_manager;
+ delete dm_seat;
+ delete upower;
+ 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..2a0e7e7
--- /dev/null
+++ b/tests/backend-dbus/mock-accounts.cc
@@ -0,0 +1,156 @@
+/*
+ * 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_path (const char * path)
+{
+ const path_to_user_t::iterator it (my_path_to_user.find(path));
+
+ if (it != my_path_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 (users_t::iterator it(users.begin()),
+ end(users.end()); it!=end; ++it)
+ 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..95da102
--- /dev/null
+++ b/tests/backend-dbus/mock-accounts.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_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_path (const char * path);
+ 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-consolekit-manager.cc b/tests/backend-dbus/mock-consolekit-manager.cc
new file mode 100644
index 0000000..40f9bf9
--- /dev/null
+++ b/tests/backend-dbus/mock-consolekit-manager.cc
@@ -0,0 +1,156 @@
+/*
+ * 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-consolekit-manager.h"
+#include "mock-consolekit-seat.h"
+#include "mock-consolekit-session.h"
+
+namespace
+{
+ const char * CONSOLEKIT_MANAGER_NAME = "org.freedesktop.ConsoleKit";
+
+ const char * CONSOLEKIT_MANAGER_PATH = "/org/freedesktop/ConsoleKit/Manager";
+
+ void on_active_session_changed (ConsoleKitSeat * o G_GNUC_UNUSED,
+ const gchar * new_ssid,
+ gpointer ssid)
+ {
+ *static_cast<std::string*>(ssid) = new_ssid;
+ }
+}
+
+/***
+****
+***/
+
+gboolean
+MockConsoleKitManager :: on_get_current_session (ConsoleKitManager * m,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ MockConsoleKitManager * self = static_cast<MockConsoleKitManager*>(gself);
+ const std::string& ssid = self->my_current_ssid;
+ console_kit_manager_complete_get_current_session (m, inv, ssid.c_str());
+ return true;
+}
+
+gboolean
+MockConsoleKitManager :: on_get_seats (ConsoleKitManager * m,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ int i;
+ char ** sids;
+ const seats_t& seats = static_cast<MockConsoleKitManager*>(gself)->my_seats;
+
+ i = 0;
+ sids = g_new0 (char*, seats.size()+1);
+ for (seats_t::const_iterator it(seats.begin()),
+ end(seats.end()); it!=end; ++it)
+ sids[i++] = (char*) (*it)->path();
+ console_kit_manager_complete_get_seats (m, inv, sids);
+ g_strfreev (sids);
+
+ return true;
+}
+
+gboolean
+MockConsoleKitManager :: handle_restart (ConsoleKitManager * ckm,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ static_cast<MockConsoleKitManager*>(gself)->my_last_action = Restart;
+ console_kit_manager_complete_restart (ckm, inv);
+ return true;
+}
+
+gboolean
+MockConsoleKitManager :: handle_stop (ConsoleKitManager * ckm,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ static_cast<MockConsoleKitManager*>(gself)->my_last_action = Shutdown;
+ console_kit_manager_complete_stop (ckm, inv);
+ return true;
+}
+
+/***
+****
+***/
+
+MockConsoleKitSession *
+MockConsoleKitManager :: current_session ()
+{
+ MockConsoleKitSession * ret = 0;
+
+ for (seats_t::iterator it(my_seats.begin()),
+ end(my_seats.end()); it!=end; ++it)
+ if ((ret = (*it)->find (my_current_ssid.c_str())))
+ break;
+
+ return ret;
+}
+
+void
+MockConsoleKitManager :: add_seat (MockConsoleKitSeat * seat)
+{
+ g_assert (my_seats.count(seat) == 0);
+
+ my_seats.insert (seat);
+
+ console_kit_manager_emit_seat_added (my_skeleton, seat->sid());
+
+ g_signal_connect (seat->skeleton(), "active-session-changed",
+ G_CALLBACK(on_active_session_changed), &my_current_ssid);
+}
+
+/***
+****
+***/
+
+MockConsoleKitManager :: MockConsoleKitManager (GMainLoop * loop,
+ GDBusConnection * conn):
+ MockObject (loop, conn, CONSOLEKIT_MANAGER_NAME, CONSOLEKIT_MANAGER_PATH),
+ my_skeleton (console_kit_manager_skeleton_new ()),
+ my_last_action (None)
+{
+ g_signal_connect (my_skeleton, "handle-get-current-session",
+ G_CALLBACK(on_get_current_session), this);
+ g_signal_connect (my_skeleton, "handle-get-seats",
+ G_CALLBACK(on_get_seats), this);
+ g_signal_connect (my_skeleton, "handle-stop",
+ G_CALLBACK(handle_stop), this);
+ g_signal_connect (my_skeleton, "handle-restart",
+ G_CALLBACK(handle_restart), this);
+
+ set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton));
+}
+
+MockConsoleKitManager :: ~MockConsoleKitManager ()
+{
+ for (seats_t::iterator it(my_seats.begin()); it!=my_seats.end(); ++it)
+ {
+ MockConsoleKitSeat * seat = *it;
+ g_signal_handlers_disconnect_by_data (seat->skeleton(), &my_current_ssid);
+ delete seat;
+ }
+
+ g_signal_handlers_disconnect_by_data (my_skeleton, this);
+ g_clear_object (&my_skeleton);
+}
diff --git a/tests/backend-dbus/mock-consolekit-manager.h b/tests/backend-dbus/mock-consolekit-manager.h
new file mode 100644
index 0000000..c5942b2
--- /dev/null
+++ b/tests/backend-dbus/mock-consolekit-manager.h
@@ -0,0 +1,77 @@
+/*
+ * 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_CONSOLEKIT_MANAGER_H
+#define MOCK_CONSOLEKIT_MANAGER_H
+
+#include <set>
+#include <string>
+#include "mock-object.h"
+#include "backend-dbus/dbus-consolekit-manager.h"
+
+class MockConsoleKitSession;
+class MockConsoleKitSeat;
+
+class MockConsoleKitManager: public MockObject
+{
+ public:
+
+ MockConsoleKitManager (GMainLoop * loop,
+ GDBusConnection * bus_connection);
+ virtual ~MockConsoleKitManager ();
+
+ void add_seat (MockConsoleKitSeat * seat);
+
+ MockConsoleKitSession * current_session ();
+
+ public:
+
+ enum Action { None, Shutdown, Restart };
+
+ Action last_action () const { return my_last_action; }
+
+ void clear_last_action () { my_last_action = None; }
+
+ private:
+
+ typedef std::set<MockConsoleKitSeat*> seats_t;
+ seats_t my_seats;
+
+ ConsoleKitManager * my_skeleton;
+
+ std::string my_current_ssid;
+
+ Action my_last_action;
+
+ static gboolean on_get_current_session (ConsoleKitManager *,
+ GDBusMethodInvocation *,
+ gpointer );
+ static gboolean on_get_seats (ConsoleKitManager *,
+ GDBusMethodInvocation *,
+ gpointer );
+ static gboolean handle_restart (ConsoleKitManager *,
+ GDBusMethodInvocation *,
+ gpointer);
+ static gboolean handle_stop (ConsoleKitManager *,
+ GDBusMethodInvocation *,
+ gpointer);
+
+};
+
+#endif // #ifndef MOCK_CONSOLEKIT_MANAGER_H
diff --git a/tests/backend-dbus/mock-consolekit-seat.cc b/tests/backend-dbus/mock-consolekit-seat.cc
new file mode 100644
index 0000000..ce1fbad
--- /dev/null
+++ b/tests/backend-dbus/mock-consolekit-seat.cc
@@ -0,0 +1,220 @@
+/*
+ * 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-consolekit-seat.h"
+
+#include "mock-object.h"
+#include "mock-consolekit-session.h"
+#include "mock-user.h"
+
+namespace
+{
+ const char * CONSOLEKIT_BUS_NAME = "org.freedesktop.ConsoleKit";
+
+ std::string next_unique_sid ()
+ {
+ static int id = 1;
+
+ char * tmp;
+ std::string ret;
+
+ tmp = g_strdup_printf ("/org/freedesktop/ConsoleKit/Seat%d", id++);
+ ret = tmp;
+ g_free (tmp);
+ return ret;
+ }
+}
+
+/***
+****
+***/
+
+void
+MockConsoleKitSeat :: activate_session (MockConsoleKitSession * session)
+{
+ g_assert (my_sessions.count(session) == 1);
+
+ const char * ssid = session->ssid ();
+ if (my_active_ssid != ssid)
+ {
+ my_active_ssid = ssid;
+ console_kit_seat_emit_active_session_changed (my_skeleton, ssid);
+ }
+}
+
+void
+MockConsoleKitSeat :: switch_to_guest ()
+{
+ for (sessions_t::iterator it(my_sessions.begin()),
+ end(my_sessions.end()); it!=end; ++it)
+ {
+ MockConsoleKitSession * session (*it);
+
+ if (session->user()->is_guest())
+ {
+ activate_session (*it);
+ return;
+ }
+ }
+
+ g_warn_if_reached ();
+}
+
+void
+MockConsoleKitSeat :: switch_to_user (const char * username)
+{
+ for (sessions_t::iterator it(my_sessions.begin()),
+ end(my_sessions.end()); it!=end; ++it)
+ {
+ MockConsoleKitSession * session (*it);
+
+ if (!g_strcmp0 (username, session->user()->username()))
+ {
+ activate_session (*it);
+ return;
+ }
+ }
+
+ g_warn_if_reached ();
+}
+
+/***
+****
+***/
+
+MockConsoleKitSession *
+MockConsoleKitSeat :: add_session_by_user (MockUser * mu)
+{
+ g_assert (mu != 0);
+
+ MockConsoleKitSession * session;
+
+ session = new MockConsoleKitSession (my_loop, my_bus_connection);
+ session->set_user (mu);
+ add_session (session);
+ return session;
+}
+
+void
+MockConsoleKitSeat :: add_session (MockConsoleKitSession * session)
+{
+ g_assert (my_sessions.count(session) == 0);
+
+ my_sessions.insert (session);
+ session->set_sid (path());
+ console_kit_seat_emit_session_added (my_skeleton, session->ssid());
+}
+
+void
+MockConsoleKitSeat :: remove_session (MockConsoleKitSession * session)
+{
+ g_assert (my_sessions.count(session) == 1);
+
+ my_sessions.erase (session);
+ session->set_sid ("");
+ console_kit_seat_emit_session_removed (my_skeleton, session->ssid());
+}
+
+/***
+**** Handlers
+***/
+
+gboolean
+MockConsoleKitSeat :: on_can_activate_sessions (ConsoleKitSeat * cks,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ bool b = static_cast<MockConsoleKitSeat*>(gself)->my_can_activate_sessions;
+ console_kit_seat_complete_can_activate_sessions (cks, inv, b);
+ return true;
+}
+
+gboolean
+MockConsoleKitSeat :: on_get_active_session (ConsoleKitSeat * cks,
+ GDBusMethodInvocation * invoke,
+ gpointer gself)
+{
+ std::string ssid = static_cast<MockConsoleKitSeat*>(gself)->my_active_ssid;
+ console_kit_seat_complete_get_active_session (cks, invoke, ssid.c_str());
+ return true;
+}
+
+gboolean
+MockConsoleKitSeat :: on_get_sessions (ConsoleKitSeat * cks,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ int i;
+ const char ** paths;
+ sessions_t& sessions = static_cast<MockConsoleKitSeat*>(gself)->my_sessions;
+
+ i = 0;
+ paths = g_new0 (const char*, sessions.size() + 1);
+ for (sessions_t::iterator it(sessions.begin()),
+ end(sessions.end()); it!=end; ++it)
+ paths[i++] = (*it)->path();
+
+ g_debug ("returning a list of %d sessions", i);
+ console_kit_seat_complete_get_sessions (cks, inv, paths);
+ g_free (paths);
+
+ return true;
+}
+
+MockConsoleKitSession *
+MockConsoleKitSeat :: find (const char * ssid)
+{
+ for (sessions_t::iterator it(my_sessions.begin()),
+ end(my_sessions.end()); it!=end; ++it)
+ if (!g_strcmp0 ((*it)->path(), ssid))
+ return *it;
+
+ return 0;
+}
+
+/***
+**** Life Cycle
+***/
+
+MockConsoleKitSeat :: MockConsoleKitSeat (GMainLoop * loop,
+ GDBusConnection * bus_connection,
+ bool can_activate_sessions):
+ MockObject (loop, bus_connection, CONSOLEKIT_BUS_NAME, next_unique_sid()),
+ my_skeleton (console_kit_seat_skeleton_new ()),
+ my_can_activate_sessions (can_activate_sessions)
+{
+ g_signal_connect (my_skeleton, "handle-get-active-session",
+ G_CALLBACK(on_get_active_session), this);
+ g_signal_connect (my_skeleton, "handle-get-sessions",
+ G_CALLBACK(on_get_sessions), this);
+ g_signal_connect (my_skeleton, "handle-can-activate-sessions",
+ G_CALLBACK(on_can_activate_sessions), this);
+
+ set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton));
+}
+
+MockConsoleKitSeat :: ~MockConsoleKitSeat ()
+{
+ for (sessions_t::iterator it(my_sessions.begin()),
+ end(my_sessions.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-consolekit-seat.h b/tests/backend-dbus/mock-consolekit-seat.h
new file mode 100644
index 0000000..aa52276
--- /dev/null
+++ b/tests/backend-dbus/mock-consolekit-seat.h
@@ -0,0 +1,75 @@
+/*
+ * 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_CONSOLEKIT_SEAT_H
+#define MOCK_CONSOLEKIT_SEAT_H
+
+#include <set>
+#include <string>
+#include "backend-dbus/dbus-consolekit-seat.h"
+#include "mock-object.h"
+
+class MockUser;
+class MockConsoleKitSession;
+
+class MockConsoleKitSeat: public MockObject
+{
+ public:
+
+ MockConsoleKitSeat (GMainLoop * loop,
+ GDBusConnection * bus_connection,
+ bool can_activate_sessions);
+ virtual ~MockConsoleKitSeat ();
+
+ const char * sid() { return path(); }
+ MockConsoleKitSession * add_session_by_user (MockUser * user);
+ void add_session (MockConsoleKitSession * session);
+ void remove_session (MockConsoleKitSession * session);
+ void activate_session (MockConsoleKitSession * session);
+ void switch_to_guest ();
+ void switch_to_user (const char * username);
+ bool can_activate_sessions () const { return my_can_activate_sessions; }
+ MockConsoleKitSession * find (const char * ssid);
+
+ private:
+
+ static gboolean on_get_active_session (ConsoleKitSeat * cks,
+ GDBusMethodInvocation * inv,
+ gpointer gself);
+ static gboolean on_get_sessions (ConsoleKitSeat * cks,
+ GDBusMethodInvocation * inv,
+ gpointer gself);
+ static gboolean on_can_activate_sessions (ConsoleKitSeat * cks,
+ GDBusMethodInvocation * inv,
+ gpointer gself);
+
+
+ private:
+
+ ConsoleKitSeat * my_skeleton;
+
+ std::string my_active_ssid;
+
+ typedef std::set<MockConsoleKitSession*> sessions_t;
+ sessions_t my_sessions;
+ bool my_can_activate_sessions;
+
+};
+
+#endif // #ifndef MOCK_CONSOLEKIT_SEAT_H
diff --git a/tests/backend-dbus/mock-consolekit-session.cc b/tests/backend-dbus/mock-consolekit-session.cc
new file mode 100644
index 0000000..2f39411
--- /dev/null
+++ b/tests/backend-dbus/mock-consolekit-session.cc
@@ -0,0 +1,113 @@
+/*
+ * 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-consolekit-session.h"
+#include "mock-user.h"
+
+namespace
+{
+ const char * const DEFAULT_X11_DISPLAY = ":0:0";
+
+ const char * const CONSOLEKIT_NAME = "org.freedesktop.ConsoleKit";
+
+ std::string next_unique_ssid ()
+ {
+ static int id = 333; // arbitrary
+
+ char * tmp;
+ std::string ret;
+
+ tmp = g_strdup_printf ("/org/freedesktop/ConsoleKit/Session%d", id++);
+ ret = tmp;
+ g_free (tmp);
+ return ret;
+ }
+}
+
+void
+MockConsoleKitSession :: set_user (MockUser * user)
+{
+ my_user = user;
+}
+
+/***
+****
+***/
+
+gboolean
+MockConsoleKitSession :: on_get_seat_id_static (ConsoleKitSession * cks,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ const std::string& sid = static_cast<MockConsoleKitSession*>(gself)->my_sid;
+ g_debug ("%s %s returning seat id of %s", G_STRLOC, G_STRFUNC, sid.c_str());
+ console_kit_session_complete_get_seat_id (cks, inv, sid.c_str());
+ return true;
+}
+
+gboolean
+MockConsoleKitSession :: on_get_unix_user_static (ConsoleKitSession * cks,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ MockUser * user = static_cast<MockConsoleKitSession*>(gself)->my_user;
+ g_debug ("%s %s returning uid of %u", G_STRLOC, G_STRFUNC, user->uid());
+ console_kit_session_complete_get_unix_user (cks, inv, user->uid());
+ return true;
+}
+
+gboolean
+MockConsoleKitSession :: on_get_x11_display (ConsoleKitSession * cks,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ MockConsoleKitSession * self = static_cast<MockConsoleKitSession*>(gself);
+ const char * x11 = self->x11_display();
+ g_debug ("%s %s returning x11 display '%s'", G_STRLOC, G_STRFUNC, x11);
+ console_kit_session_complete_get_x11_display (cks, inv, x11);
+ return true;
+}
+
+/***
+****
+***/
+
+MockConsoleKitSession :: MockConsoleKitSession (GMainLoop * loop,
+ GDBusConnection * conn):
+ MockObject (loop, conn, CONSOLEKIT_NAME, next_unique_ssid ()),
+ my_skeleton (console_kit_session_skeleton_new ()),
+ my_x11_display (DEFAULT_X11_DISPLAY),
+ my_user (0)
+{
+ g_signal_connect (my_skeleton, "handle-get-seat-id",
+ G_CALLBACK(on_get_seat_id_static), this);
+ g_signal_connect (my_skeleton, "handle-get-unix-user",
+ G_CALLBACK(on_get_unix_user_static), this);
+ g_signal_connect (my_skeleton, "handle-get-x11-display",
+ G_CALLBACK(on_get_x11_display), this);
+
+ set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton));
+}
+
+MockConsoleKitSession :: ~MockConsoleKitSession ()
+{
+ const int n = g_signal_handlers_disconnect_by_data (my_skeleton, this);
+ g_assert (n == 3);
+ g_clear_object (&my_skeleton);
+}
diff --git a/tests/backend-dbus/mock-consolekit-session.h b/tests/backend-dbus/mock-consolekit-session.h
new file mode 100644
index 0000000..7759f72
--- /dev/null
+++ b/tests/backend-dbus/mock-consolekit-session.h
@@ -0,0 +1,65 @@
+/*
+ * 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_CONSOLEKIT_SESSION_H
+#define MOCK_CONSOLEKIT_SESSION_H
+
+#include <string>
+#include "mock-object.h"
+#include "backend-dbus/dbus-consolekit-session.h"
+
+class MockUser;
+
+class MockConsoleKitSession: public MockObject
+{
+ public:
+
+ MockConsoleKitSession (GMainLoop * loop,
+ GDBusConnection * bus_connection);
+ virtual ~MockConsoleKitSession ();
+
+ MockUser * user () { return my_user; }
+ void set_user (MockUser * user);
+ const char * ssid () { return path(); }
+ void set_sid (const std::string& sid) { my_sid = sid; }
+ const char * x11_display() { return my_x11_display.c_str(); }
+ void set_x11_display (const std::string& x) { my_x11_display = x; }
+
+ private:
+
+ static gboolean on_get_seat_id_static (ConsoleKitSession *,
+ GDBusMethodInvocation *,
+ gpointer);
+ static gboolean on_get_unix_user_static (ConsoleKitSession *,
+ GDBusMethodInvocation *,
+ gpointer);
+ static gboolean on_get_x11_display (ConsoleKitSession *,
+ GDBusMethodInvocation *,
+ gpointer);
+
+
+ private:
+
+ ConsoleKitSession * my_skeleton;
+ std::string my_sid;
+ std::string my_x11_display;
+ MockUser * my_user;
+};
+
+#endif // #ifndef MOCK_CONSOLEKIT_SESSION_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..9f30ae1
--- /dev/null
+++ b/tests/backend-dbus/mock-display-manager-seat.cc
@@ -0,0 +1,140 @@
+/*
+ * 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-consolekit-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_ck_seat != 0);
+
+ my_last_action = GUEST;
+ my_ck_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_ck_seat != 0);
+
+ my_last_action = USER;
+ my_ck_seat->switch_to_user (username);
+}
+
+void
+MockDisplayManagerSeat :: set_consolekit_seat (MockConsoleKitSeat * seat)
+{
+ my_ck_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_ck_seat (0),
+ 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..b0ea415
--- /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 MockConsoleKitSeat;
+
+class MockDisplayManagerSeat: public MockObject
+{
+ public:
+
+ MockDisplayManagerSeat (GMainLoop * loop,
+ GDBusConnection * bus_connection);
+ virtual ~MockDisplayManagerSeat ();
+
+ void set_guest_allowed (bool b);
+
+ void set_consolekit_seat (MockConsoleKitSeat * ck_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;
+ MockConsoleKitSeat * my_ck_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..e289a83
--- /dev/null
+++ b/tests/backend-dbus/mock-end-session-dialog.cc
@@ -0,0 +1,89 @@
+/*
+ * 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"
+
+#if 0
+gboolean
+MockEndSessionDialog :: handle_lock (GnomeScreenSaver * ss,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ static_cast<MockEndSessionDialog*>(gself)->my_last_action = Lock;
+ gnome_screen_saver_complete_lock (ss, inv);
+ return true;
+}
+
+gboolean
+MockEndSessionDialog :: handle_simulate_user_activity (GnomeScreenSaver * ss,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ static_cast<MockEndSessionDialog*>(gself)->my_last_action = UserActivity;
+ gnome_screen_saver_complete_simulate_user_activity (ss, inv);
+ return true;
+}
+#endif
+
+gboolean
+MockEndSessionDialog :: handle_open (EndSessionDialog * object,
+ GDBusMethodInvocation * invocation,
+ guint arg_type,
+ guint arg_timestamp,
+ guint arg_seconds_to_stay_open,
+ const gchar * const * inhibitor_paths,
+ 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_isOpen (false),
+ my_skeleton (end_session_dialog_skeleton_new ())
+{
+ g_signal_connect (my_skeleton, "handle-open",
+ G_CALLBACK(handle_open), this);
+#if 0
+ 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);
+#endif
+
+ 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-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-upower.cc b/tests/backend-dbus/mock-upower.cc
new file mode 100644
index 0000000..65757b3
--- /dev/null
+++ b/tests/backend-dbus/mock-upower.cc
@@ -0,0 +1,103 @@
+/*
+ * 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-upower.h"
+
+
+gboolean
+MockUPower :: handle_suspend (UPower * upower,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ static_cast<MockUPower*>(gself)->my_last_action = Suspend;
+ upower_complete_suspend (upower, inv);
+ return true;
+}
+
+gboolean
+MockUPower :: handle_hibernate (UPower * upower,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ static_cast<MockUPower*>(gself)->my_last_action = Hibernate;
+ upower_complete_hibernate (upower, inv);
+ return true;
+}
+
+gboolean
+MockUPower :: handle_suspend_allowed (UPower * upower,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ const bool allowed = static_cast<MockUPower*>(gself)->my_can_suspend;
+ upower_complete_suspend_allowed (upower, inv, allowed);
+ return true;
+}
+
+gboolean
+MockUPower :: handle_hibernate_allowed (UPower * upower,
+ GDBusMethodInvocation * inv,
+ gpointer gself)
+{
+ const bool allowed = static_cast<MockUPower*>(gself)->my_can_hibernate;
+ upower_complete_hibernate_allowed (upower, inv, allowed);
+ return true;
+}
+
+/***
+****
+***/
+
+namespace
+{
+ const char * const UPOWER_NAME = "org.freedesktop.UPower";
+ const char * const UPOWER_PATH = "/org/freedesktop/UPower";
+
+}
+
+MockUPower :: MockUPower (GMainLoop * loop,
+ GDBusConnection * bus_connection):
+ MockObject (loop, bus_connection, UPOWER_NAME, UPOWER_PATH),
+ my_skeleton (upower_skeleton_new ()),
+ my_can_suspend (true),
+ my_can_hibernate (true),
+ my_suspend_allowed (true),
+ my_hibernate_allowed (true),
+ my_last_action (None)
+{
+ //set_can_hibernate (false);
+ //set_can_suspend (true);
+
+ g_signal_connect (my_skeleton, "handle-suspend",
+ G_CALLBACK(handle_suspend), this);
+ g_signal_connect (my_skeleton, "handle-suspend-allowed",
+ G_CALLBACK(handle_suspend_allowed), this);
+
+ g_signal_connect (my_skeleton, "handle-hibernate",
+ G_CALLBACK(handle_hibernate), this);
+ g_signal_connect (my_skeleton, "handle-hibernate-allowed",
+ G_CALLBACK(handle_hibernate_allowed), this);
+
+ set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton));
+}
+
+MockUPower :: ~MockUPower ()
+{
+ g_clear_object (&my_skeleton);
+}
diff --git a/tests/backend-dbus/mock-upower.h b/tests/backend-dbus/mock-upower.h
new file mode 100644
index 0000000..351d0f7
--- /dev/null
+++ b/tests/backend-dbus/mock-upower.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_UPOWER_H
+#define MOCK_UPOWER_H
+
+#include "mock-object.h" // parent class
+#include "backend-dbus/dbus-upower.h" // UPower
+
+class MockUPower: public MockObject
+{
+ public:
+
+ MockUPower (GMainLoop * loop,
+ GDBusConnection * bus_connection);
+ virtual ~MockUPower ();
+
+ void set_can_suspend (bool b) { upower_set_can_suspend (my_skeleton, b); }
+ void set_can_hibernate (bool b) { upower_set_can_hibernate (my_skeleton, b); }
+
+ bool suspend_allowed () const { return my_suspend_allowed; }
+ bool hibernate_allowed () const { return my_suspend_allowed; }
+ bool can_suspend () const { return upower_get_can_suspend (my_skeleton); }
+ bool can_hibernate () const { return upower_get_can_hibernate (my_skeleton); }
+
+ public:
+
+ enum Action { None, Suspend, Hibernate };
+ Action last_action () { return my_last_action; }
+
+ private:
+
+ UPower * my_skeleton;
+ bool my_can_suspend;
+ bool my_can_hibernate;
+ bool my_suspend_allowed;
+ bool my_hibernate_allowed;
+ Action my_last_action;
+
+ static gboolean handle_suspend_allowed (UPower *,
+ GDBusMethodInvocation *,
+ gpointer);
+ static gboolean handle_suspend (UPower *,
+ GDBusMethodInvocation *,
+ gpointer);
+
+ static gboolean handle_hibernate_allowed (UPower *,
+ GDBusMethodInvocation *,
+ gpointer);
+ static gboolean handle_hibernate (UPower *,
+ GDBusMethodInvocation *,
+ gpointer);
+
+};
+
+#endif
diff --git a/tests/backend-dbus/mock-user.cc b/tests/backend-dbus/mock-user.cc
new file mode 100644
index 0000000..abf2e21
--- /dev/null
+++ b/tests/backend-dbus/mock-user.cc
@@ -0,0 +1,131 @@
+/*
+ * 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);
+}
+
+#if 0
+bool
+MockUser :: system_account() const
+{
+ return accounts_user_get_system_account (my_skeleton);
+}
+#endif
+
+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..44fa8ac
--- /dev/null
+++ b/tests/backend-dbus/mock-webcredentials.cc
@@ -0,0 +1,54 @@
+/*
+ * 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_can_hibernate (false);
+ //set_can_suspend (true);
+
+#if 0
+ g_signal_connect (my_skeleton, "handle-suspend",
+ G_CALLBACK(handle_suspend), this);
+ g_signal_connect (my_skeleton, "handle-suspend-allowed",
+ G_CALLBACK(handle_suspend_allowed), this);
+
+ g_signal_connect (my_skeleton, "handle-hibernate",
+ G_CALLBACK(handle_hibernate), this);
+ g_signal_connect (my_skeleton, "handle-hibernate-allowed",
+ G_CALLBACK(handle_hibernate_allowed), this);
+#endif
+
+ 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..212ca76
--- /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); }
+ bool 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..f79c913
--- /dev/null
+++ b/tests/backend-dbus/test-actions.cc
@@ -0,0 +1,454 @@
+/*
+ * 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 Actions: public GTestMockDBusFixture
+{
+ private:
+
+ typedef GTestMockDBusFixture super;
+
+ protected:
+
+ GCancellable * cancellable;
+ IndicatorSessionActions * actions;
+
+ virtual void SetUp ()
+ {
+ super :: SetUp ();
+
+ // init 'actions'
+ cancellable = g_cancellable_new ();
+ actions = 0;
+ backend_get (cancellable, &actions, NULL, NULL);
+ g_assert (actions != 0);
+ wait_msec (100);
+ }
+
+ virtual void TearDown ()
+ {
+ g_cancellable_cancel (cancellable);
+ 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 = ck_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)
+{
+ bool b;
+ bool can;
+ bool allowed;
+ gboolean b2;
+
+ can = upower->can_suspend ();
+ allowed = upower->suspend_allowed ();
+ b = can && allowed;
+
+ ASSERT_EQ (b, indicator_session_actions_can_suspend (actions));
+ g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_SUSPEND, &b2, NULL);
+ ASSERT_EQ (b, b2);
+
+ for (int i=0; i<2; ++i)
+ {
+ can = !can;
+ b = can && allowed;
+
+ upower->set_can_suspend (can);
+ wait_for_signal (actions, "notify::" INDICATOR_SESSION_ACTIONS_PROP_CAN_SUSPEND);
+ ASSERT_EQ (b, indicator_session_actions_can_suspend (actions));
+ g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_SUSPEND, &b2, NULL);
+ ASSERT_EQ (b, b2);
+ }
+}
+
+TEST_F (Actions, CanHibernate)
+{
+ bool b;
+ bool can;
+ bool allowed;
+ gboolean b2;
+
+ can = upower->can_hibernate ();
+ allowed = upower->hibernate_allowed ();
+ b = can && allowed;
+
+ ASSERT_EQ (b, indicator_session_actions_can_hibernate (actions));
+ g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_HIBERNATE, &b2, NULL);
+ ASSERT_EQ (b, b2);
+
+#if 0
+ for (int i=0; i<2; ++i)
+ {
+ b = !b;
+ upower->set_can_hibernate (b);
+ wait_for_signal (actions, "notify::" INDICATOR_SESSION_ACTIONS_PROP_CAN_HIBERNATE);
+ ASSERT_EQ (b, indicator_session_actions_can_hibernate (actions));
+ g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_HIBERNATE, &b2, NULL);
+ ASSERT_EQ (b, b2);
+ }
+#endif
+}
+
+TEST_F (Actions, Restart)
+{
+ ASSERT_EQ (MockConsoleKitManager::None, ck_manager->last_action());
+
+ // confirm that user is prompted
+ // and that no action is taken when the user cancels the dialog
+ indicator_session_actions_restart (actions);
+ wait_msec (50);
+ ASSERT_TRUE (end_session_dialog->is_open());
+ end_session_dialog->cancel();
+ wait_msec (50);
+ ASSERT_EQ (MockConsoleKitManager::None, ck_manager->last_action());
+
+ // confirm that user is prompted
+ // and that no action is taken when the user cancels the dialog
+ indicator_session_actions_restart (actions);
+ wait_msec (50);
+ ASSERT_TRUE (end_session_dialog->is_open ());
+ end_session_dialog->confirm_reboot ();
+ wait_msec (100);
+ ASSERT_EQ (MockConsoleKitManager::Restart, ck_manager->last_action());
+
+ // confirm that we try to restart w/o prompting
+ // if the EndSessionDialog isn't available
+ delete end_session_dialog;
+ end_session_dialog = 0;
+ ck_manager->clear_last_action ();
+ ASSERT_EQ (MockConsoleKitManager::None, ck_manager->last_action());
+ wait_msec (50);
+ indicator_session_actions_restart (actions);
+ wait_msec (50);
+ ASSERT_EQ (MockConsoleKitManager::Restart, ck_manager->last_action());
+}
+
+TEST_F (Actions, Shutdown)
+{
+ ASSERT_EQ (MockConsoleKitManager::None, ck_manager->last_action());
+
+ // confirm that user is prompted
+ // and that no action is taken when the user cancels the dialog
+ indicator_session_actions_shutdown (actions);
+ wait_msec (50);
+ ASSERT_TRUE (end_session_dialog->is_open());
+ end_session_dialog->cancel();
+ wait_msec (50);
+ ASSERT_EQ (MockConsoleKitManager::None, ck_manager->last_action());
+
+ // confirm that user is prompted
+ // and that no action is taken when the user cancels the dialog
+ indicator_session_actions_shutdown (actions);
+ wait_msec (50);
+ ASSERT_TRUE (end_session_dialog->is_open ());
+ end_session_dialog->confirm_shutdown ();
+ wait_msec (100);
+ ASSERT_EQ (MockConsoleKitManager::Shutdown, ck_manager->last_action());
+
+ // confirm that we try to shutdown w/o prompting
+ // if the EndSessionDialog isn't available
+ delete end_session_dialog;
+ end_session_dialog = 0;
+ ck_manager->clear_last_action ();
+ wait_msec (50);
+ indicator_session_actions_shutdown (actions);
+ wait_msec (50);
+ ASSERT_EQ (MockConsoleKitManager::Shutdown, ck_manager->last_action());
+}
+
+TEST_F (Actions, Logout)
+{
+ ASSERT_EQ (MockConsoleKitManager::None, ck_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_shutdown (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::LogoutNormal
+ // if the EndSessionDialog isn't available
+ delete end_session_dialog;
+ end_session_dialog = 0;
+ wait_msec (50);
+ indicator_session_actions_logout (actions);
+ wait_msec (50);
+ ASSERT_EQ (MockSessionManager::LogoutNormal, session_manager->last_action ());
+}
+
+TEST_F (Actions, Suspend)
+{
+ ASSERT_EQ (MockUPower::None, upower->last_action());
+ indicator_session_actions_suspend (actions);
+ wait_msec (50);
+ ASSERT_EQ (MockUPower::Suspend, upower->last_action());
+}
+
+TEST_F (Actions, Hibernate)
+{
+ ASSERT_EQ (MockUPower::None, upower->last_action());
+ indicator_session_actions_hibernate (actions);
+ wait_msec (50);
+ ASSERT_EQ (MockUPower::Hibernate, upower->last_action());
+}
+
+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);
+ MockUser * guest_user;
+ MockConsoleKitSession * guest_ck_session;
+
+ // set up a guest
+ guest_user = new MockUser (loop, conn, "guest-zzbEVV", "Guest", 10);
+ guest_user->set_system_account (true);
+ accounts->add_user (guest_user);
+ guest_ck_session = ck_seat->add_session_by_user (guest_user);
+
+ // try to switch to guest
+ indicator_session_actions_switch_to_guest (actions);
+ wait_for_signal (ck_seat->skeleton(), "active-session-changed");
+ ASSERT_EQ (guest_ck_session, ck_manager->current_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;
+ MockConsoleKitSession * dr1_session;
+ MockConsoleKitSession * dr2_session;
+
+ dr1_user = accounts->find_by_username (dr1_username);
+ dr1_session = ck_seat->add_session_by_user (dr1_user);
+
+ dr2_user = accounts->find_by_username (dr2_username);
+ dr2_session = ck_seat->add_session_by_user (dr2_user);
+
+ indicator_session_actions_switch_to_username (actions, dr1_username);
+ wait_for_signal (ck_seat->skeleton(), "active-session-changed");
+ ASSERT_EQ (dr1_session, ck_manager->current_session());
+ wait_msec (50);
+
+ indicator_session_actions_switch_to_username (actions, dr2_username);
+ wait_for_signal (ck_seat->skeleton(), "active-session-changed");
+ ASSERT_EQ (dr2_session, ck_manager->current_session());
+ wait_msec (50);
+
+ indicator_session_actions_switch_to_username (actions, dr1_username);
+ wait_for_signal (ck_seat->skeleton(), "active-session-changed");
+ ASSERT_EQ (dr1_session, ck_manager->current_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);
+}
+
+TEST_F (Actions, CanPrompt)
+{
+ gboolean b;
+
+ ASSERT_TRUE (indicator_session_actions_can_prompt (actions));
+
+ delete end_session_dialog;
+ end_session_dialog = 0;
+ wait_msec (50);
+ ASSERT_FALSE (indicator_session_actions_can_prompt (actions));
+ g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_PROMPT, &b, NULL);
+ ASSERT_FALSE (b);
+
+ end_session_dialog = new MockEndSessionDialog (loop, conn);
+ wait_msec (50);
+ ASSERT_TRUE (indicator_session_actions_can_prompt (actions));
+ g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_PROMPT, &b, NULL);
+ ASSERT_TRUE (b);
+}
diff --git a/tests/backend-dbus/test-guest.cc b/tests/backend-dbus/test-guest.cc
new file mode 100644
index 0000000..db55dd1
--- /dev/null
+++ b/tests/backend-dbus/test-guest.cc
@@ -0,0 +1,192 @@
+/*
+ * 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,
+ MockConsoleKitSession *& guest_session)
+ {
+ guest_user = new MockUser (loop, conn, "guest-jjbEVV", "Guest", 10);
+ guest_user->set_system_account (true);
+ accounts->add_user (guest_user);
+ guest_session = new MockConsoleKitSession (loop, conn);
+ guest_session->set_user (guest_user);
+ ck_seat->add_session (guest_session);
+ }
+};
+
+/**
+ * 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;
+ MockConsoleKitSession * guest_session;
+ add_mock_guest (guest_user, guest_session);
+ 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
+ ck_seat->remove_session (guest_session);
+ accounts->remove_user (guest_user);
+ delete guest_user;
+ delete guest_session;
+ 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;
+
+ dm_seat->set_guest_allowed (true);
+ MockUser * guest_user;
+ MockConsoleKitSession * guest_session;
+ add_mock_guest (guest_user, guest_session);
+
+ // Activate the guest session
+ // and confirm that guest's is_active changes to true
+ ck_seat->activate_session (guest_session);
+ 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
+ ck_seat->activate_session (ck_session);
+ 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);
+ MockUser * guest_user;
+ MockConsoleKitSession * guest_session;
+ add_mock_guest (guest_user, guest_session);
+
+ indicator_session_guest_switch_to_guest (guest);
+ wait_for_signal (ck_seat->skeleton(), "active-session-changed");
+ ASSERT_EQ (guest_session, ck_manager->current_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..bd0547d
--- /dev/null
+++ b/tests/backend-dbus/test-users.cc
@@ -0,0 +1,377 @@
+/*
+ * 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_msec (100);
+ }
+
+ virtual void TearDown ()
+ {
+ g_cancellable_cancel (cancellable);
+ g_clear_object (&cancellable);
+ g_clear_object (&users);
+
+ super :: TearDown ();
+ }
+
+ protected:
+
+ void compare_user (const IndicatorSessionUser * isu,
+ MockUser * mu,
+ bool is_logged_in,
+ bool is_current_user)
+ {
+ ASSERT_TRUE (isu != 0);
+ ASSERT_TRUE (mu != 0);
+
+ 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 (is_logged_in, isu->is_logged_in);
+ ASSERT_EQ (is_current_user, isu->is_current_user);
+ // FIXME: test icon file?
+ }
+
+ void compare_user (const std::string & key,
+ MockUser * mu,
+ bool is_logged_in,
+ bool is_current_user)
+ {
+ IndicatorSessionUser * isu;
+ isu = indicator_session_users_get_user (users, key.c_str());
+ compare_user (isu, mu, is_logged_in, is_current_user);
+ 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,
+ const char * key,
+ gpointer gself)
+ {
+ Users * self = static_cast<Users*>(gself);
+
+ self->event_keys.push_back (key);
+
+ if (self->event_keys.size() == self->expected_event_count)
+ g_main_loop_quit (self->loop);
+ }
+
+ protected:
+
+ std::vector<std::string> 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)
+{
+ const guint logged_in_uid = ck_session->user()->uid();
+ GStrv keys = indicator_session_users_get_keys (users);
+
+ ASSERT_EQ (12, g_strv_length (keys));
+
+ for (int i=0; keys && keys[i]; ++i)
+ {
+ MockUser * mu = accounts->find_by_path (keys[i]);
+ const bool is_logged_in = mu->uid() == logged_in_uid;
+ const bool is_current_user = mu->uid() == logged_in_uid;
+ compare_user (keys[i], mu, is_logged_in, is_current_user);
+ }
+
+ g_strfreev (keys);
+}
+
+/**
+ * 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());
+ ASSERT_STREQ (mu->path(), event_keys[0].c_str());
+
+ compare_user (event_keys[0], mu, false, false);
+}
+
+/**
+ * Confirm that 'users' can tell when a user is removed
+ */
+TEST_F (Users, UserRemoved)
+{
+ MockUser * mu;
+
+ mu = accounts->find_by_username ("pdavison");
+ accounts->remove_user (mu);
+ ASSERT_EQ (0, event_keys.size());
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_REMOVED, 1);
+ ASSERT_EQ (1, event_keys.size());
+ ASSERT_STREQ (mu->path(), event_keys[0].c_str());
+
+ GStrv keys = indicator_session_users_get_keys (users);
+ ASSERT_EQ (11, g_strv_length (keys));
+ g_strfreev (keys);
+
+ ASSERT_TRUE (indicator_session_users_get_user (users, mu->path()) == NULL);
+
+ 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());
+ ASSERT_STREQ (mu->path(), event_keys[0].c_str());
+ compare_user (mu->path(), mu, false, false);
+}
+
+/**
+ * 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");
+ compare_user (mu->path(), mu, false, false);
+ MockConsoleKitSession * session = ck_seat->add_session_by_user (mu);
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1);
+ ASSERT_STREQ (mu->path(), event_keys[0].c_str());
+ compare_user (mu->path(), mu, true, false);
+
+ // The fist doctor logs out.
+ // Confirm that 'users' notices.
+ ck_seat->remove_session (session);
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1);
+ ASSERT_EQ (1, event_keys.size());
+ ASSERT_STREQ (mu->path(), event_keys[0].c_str());
+ compare_user (event_keys[0], mu, false, false);
+
+ delete session;
+}
+
+/**
+ * Confirm that 'users' notices when the active session changes
+ */
+TEST_F (Users, ActivateSession)
+{
+ // The fist doctor logs in.
+ // Confirm that 'users' notices.
+ MockUser * mu = accounts->find_by_username ("whartnell");
+ compare_user (mu->path(), mu, false, false);
+ MockConsoleKitSession * session = ck_seat->add_session_by_user (mu);
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1);
+ ASSERT_STREQ (mu->path(), event_keys[0].c_str());
+ compare_user (mu->path(), mu, true, false);
+
+ // activate the first doctor's session.
+ // confirm that 'users' sees he's active and that ck_session isn't.
+ // this should come in the form of two 'user-changed' events
+ ck_seat->activate_session (session);
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 2);
+ ASSERT_EQ (2, event_keys.size());
+ compare_user (event_keys[0], ck_session->user(), true, false);
+ compare_user (event_keys[1], mu, true, true);
+
+ // switch back to the previous
+ // confirm that 'users' sees it's active and the first doctor's session isn't
+ // this should come in the form of two 'user-changed' events
+ ck_seat->activate_session (ck_session);
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 2);
+ ASSERT_EQ (2, event_keys.size());
+ compare_user (event_keys[0], mu, true, false);
+ compare_user (event_keys[1], ck_session->user(), true, true);
+}
+
+/**
+ * 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)
+{
+ // The fist doctor logs in.
+ // Confirm that 'users' notices.
+ MockUser * mu = accounts->find_by_username ("whartnell");
+ compare_user (mu->path(), mu, false, false);
+ MockConsoleKitSession * session = ck_seat->add_session_by_user (mu);
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1);
+ ASSERT_STREQ (mu->path(), event_keys[0].c_str());
+ compare_user (mu->path(), mu, true, false);
+
+ // activate the first doctor's session.
+ // confirm that 'users' sees he's active and that ck_session isn't.
+ // this should come in the form of two 'user-changed' events
+ indicator_session_users_activate_user (users, mu->path());
+ ck_seat->activate_session (session);
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 2);
+ ASSERT_EQ (2, event_keys.size());
+ compare_user (event_keys[0], ck_session->user(), true, false);
+ compare_user (event_keys[1], mu, true, true);
+
+ // switch back to the previous
+ // confirm that 'users' sees it's active and the first doctor's session isn't
+ // this should come in the form of two 'user-changed' events
+ indicator_session_users_activate_user (users, ck_session->user()->path());
+ ck_seat->activate_session (ck_session);
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 2);
+ ASSERT_EQ (2, event_keys.size());
+ compare_user (event_keys[0], mu, true, false);
+ compare_user (event_keys[1], ck_session->user(), true, true);
+}
+
+/**
+ * Confirm that adding a Guest doesn't show up in the users list
+ */
+TEST_F (Users, UnwantedGuest)
+{
+ GStrv keys;
+
+ keys = indicator_session_users_get_keys (users);
+ const size_t n = g_strv_length (keys);
+ g_strfreev (keys);
+
+ MockUser * mu = new MockUser (loop, conn, "guest-jjbEVV", "Guest", 1);
+ mu->set_system_account (true);
+ accounts->add_user (mu);
+ wait_msec (50);
+
+ keys = indicator_session_users_get_keys (users);
+ ASSERT_EQ (n, g_strv_length (keys));
+ g_strfreev (keys);
+}
+
+
+/**
+ * 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);
+ MockConsoleKitSession * session = ck_seat->add_session_by_user (live_user);
+ wait_msec (100);
+ ck_seat->activate_session (session);
+ 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);
+}
diff --git a/tests/backend-mock-actions.c b/tests/backend-mock-actions.c
new file mode 100644
index 0000000..121c7ba
--- /dev/null
+++ b/tests/backend-mock-actions.c
@@ -0,0 +1,229 @@
+/*
+ * 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 "backend-mock.h"
+#include "backend-mock-actions.h"
+
+G_DEFINE_TYPE (IndicatorSessionActionsMock,
+ indicator_session_actions_mock,
+ INDICATOR_TYPE_SESSION_ACTIONS)
+
+/***
+**** Virtual Functions
+***/
+
+static gboolean
+my_can_lock (IndicatorSessionActions * self G_GNUC_UNUSED)
+{
+ return g_settings_get_boolean (mock_settings, "can-lock");
+}
+
+static gboolean
+my_can_logout (IndicatorSessionActions * self G_GNUC_UNUSED)
+{
+ return g_settings_get_boolean (mock_settings, "can-logout");
+}
+
+static gboolean
+my_can_switch (IndicatorSessionActions * self G_GNUC_UNUSED)
+{
+ return g_settings_get_boolean (mock_settings, "can-switch-sessions");
+}
+
+static gboolean
+my_can_suspend (IndicatorSessionActions * self G_GNUC_UNUSED)
+{
+ return g_settings_get_boolean (mock_settings, "can-suspend");
+}
+
+static gboolean
+my_can_hibernate (IndicatorSessionActions * self G_GNUC_UNUSED)
+{
+ return g_settings_get_boolean (mock_settings, "can-hibernate");
+}
+
+static void
+my_logout (IndicatorSessionActions * self G_GNUC_UNUSED)
+{
+ g_settings_set_string (mock_settings, "last-command", "logout");
+}
+
+static void
+my_suspend (IndicatorSessionActions * self G_GNUC_UNUSED)
+{
+ g_settings_set_string (mock_settings, "last-command", "suspend");
+}
+
+static void
+my_hibernate (IndicatorSessionActions * self G_GNUC_UNUSED)
+{
+ g_settings_set_string (mock_settings, "last-command", "hibernate");
+}
+
+static void
+my_restart (IndicatorSessionActions * self G_GNUC_UNUSED)
+{
+ g_settings_set_string (mock_settings, "last-command", "restart");
+}
+
+static void
+my_shutdown (IndicatorSessionActions * self G_GNUC_UNUSED)
+{
+ g_settings_set_string (mock_settings, "last-command", "shutdown");
+}
+
+static void
+my_switch_to_screensaver (IndicatorSessionActions * self G_GNUC_UNUSED)
+{
+ g_settings_set_string (mock_settings, "last-command", "switch-to-screensaver");
+}
+
+static void
+my_switch_to_greeter (IndicatorSessionActions * self G_GNUC_UNUSED)
+{
+ g_settings_set_string (mock_settings, "last-command", "switch-to-greeter");
+}
+
+static void
+my_switch_to_guest (IndicatorSessionActions * self G_GNUC_UNUSED)
+{
+ g_settings_set_string (mock_settings, "last-command", "switch-to-guest");
+}
+
+static void
+my_switch_to_username (IndicatorSessionActions * self G_GNUC_UNUSED,
+ const char * username)
+{
+ gchar * str = g_strdup_printf ("switch-to-user::%s", username);
+ g_settings_set_string (mock_settings, "last-command", str);
+}
+
+static void
+my_help (IndicatorSessionActions * self G_GNUC_UNUSED)
+{
+ g_settings_set_string (mock_settings, "last-command", "help");
+}
+
+static void
+my_about (IndicatorSessionActions * self G_GNUC_UNUSED)
+{
+ g_settings_set_string (mock_settings, "last-command", "about");
+}
+
+static void
+my_settings (IndicatorSessionActions * self G_GNUC_UNUSED)
+{
+ g_settings_set_string (mock_settings, "last-command", "settings");
+}
+
+static gboolean
+my_can_prompt (IndicatorSessionActions * self G_GNUC_UNUSED)
+{
+ return g_settings_get_boolean (mock_settings, "can-prompt");
+}
+
+static gboolean
+my_has_online_account_error (IndicatorSessionActions * self G_GNUC_UNUSED)
+{
+ return g_settings_get_boolean (mock_settings, "has-online-account-error");
+}
+
+static void
+my_dispose (GObject * o)
+{
+ G_OBJECT_CLASS (indicator_session_actions_mock_parent_class)->dispose (o);
+}
+
+static void
+my_finalize (GObject * o)
+{
+ G_OBJECT_CLASS (indicator_session_actions_mock_parent_class)->finalize (o);
+}
+
+/***
+**** GObject Boilerplate
+***/
+
+static void
+/* cppcheck-suppress unusedFunction */
+indicator_session_actions_mock_class_init (IndicatorSessionActionsMockClass * klass)
+{
+ GObjectClass * object_class;
+ IndicatorSessionActionsClass * actions_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = my_dispose;
+ object_class->finalize = my_finalize;
+
+ actions_class = INDICATOR_SESSION_ACTIONS_CLASS (klass);
+ actions_class->can_lock = my_can_lock;
+ actions_class->can_logout = my_can_logout;
+ actions_class->can_switch = my_can_switch;
+ actions_class->can_suspend = my_can_suspend;
+ actions_class->can_hibernate = my_can_hibernate;
+ actions_class->can_prompt = my_can_prompt;
+ actions_class->has_online_account_error = my_has_online_account_error;
+ actions_class->logout = my_logout;
+ actions_class->suspend = my_suspend;
+ actions_class->hibernate = my_hibernate;
+ actions_class->restart = my_restart;
+ actions_class->shutdown = my_shutdown;
+ actions_class->settings = my_settings;
+ actions_class->help = my_help;
+ actions_class->about = my_about;
+ actions_class->switch_to_screensaver = my_switch_to_screensaver;
+ actions_class->switch_to_greeter = my_switch_to_greeter;
+ actions_class->switch_to_guest = my_switch_to_guest;
+ actions_class->switch_to_username = my_switch_to_username;
+}
+
+static void
+/* cppcheck-suppress unusedFunction */
+indicator_session_actions_mock_init (IndicatorSessionActionsMock * self)
+{
+ g_signal_connect_swapped (mock_settings, "changed::can-lock",
+ G_CALLBACK(indicator_session_actions_notify_can_lock), self);
+ g_signal_connect_swapped (mock_settings, "changed::can-logout",
+ G_CALLBACK(indicator_session_actions_notify_can_logout), self);
+ g_signal_connect_swapped (mock_settings, "changed::can-switch-sessions",
+ G_CALLBACK(indicator_session_actions_notify_can_switch), self);
+ g_signal_connect_swapped (mock_settings, "changed::can-suspend",
+ G_CALLBACK(indicator_session_actions_notify_can_suspend), self);
+ g_signal_connect_swapped (mock_settings, "changed::can-hibernate",
+ G_CALLBACK(indicator_session_actions_notify_can_hibernate), self);
+ g_signal_connect_swapped (mock_settings, "changed::can-prompt",
+ G_CALLBACK(indicator_session_actions_notify_can_prompt), self);
+ g_signal_connect_swapped (mock_settings, "changed::has-online-account-error",
+ G_CALLBACK(indicator_session_actions_notify_has_online_account_error), self);
+}
+
+/***
+**** Public
+***/
+
+IndicatorSessionActions *
+indicator_session_actions_mock_new (void)
+{
+ gpointer o = g_object_new (INDICATOR_TYPE_SESSION_ACTIONS_MOCK, NULL);
+
+ return INDICATOR_SESSION_ACTIONS (o);
+}
diff --git a/tests/backend-mock-actions.h b/tests/backend-mock-actions.h
new file mode 100644
index 0000000..bd9ed47
--- /dev/null
+++ b/tests/backend-mock-actions.h
@@ -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/>.
+ */
+
+#ifndef __INDICATOR_SESSION_ACTIONS_MOCK_H__
+#define __INDICATOR_SESSION_ACTIONS_MOCK_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "actions.h" /* parent class */
+
+G_BEGIN_DECLS
+
+#define INDICATOR_TYPE_SESSION_ACTIONS_MOCK (indicator_session_actions_mock_get_type())
+#define INDICATOR_SESSION_ACTIONS_MOCK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_ACTIONS_MOCK, IndicatorSessionActionsMock))
+#define INDICATOR_SESSION_ACTIONS_MOCK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_ACTIONS_MOCK, IndicatorSessionActionsMockClass))
+#define INDICATOR_IS_SESSION_ACTIONS_MOCK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_ACTIONS_MOCK))
+
+typedef struct _IndicatorSessionActionsMock IndicatorSessionActionsMock;
+typedef struct _IndicatorSessionActionsMockPriv IndicatorSessionActionsMockPriv;
+typedef struct _IndicatorSessionActionsMockClass IndicatorSessionActionsMockClass;
+
+/**
+ * An implementation of IndicatorSessionActions that gets its user information
+ * from org.freedesktop.ConsoleKit and org.freedesktop.Accounts over DBus.
+ */
+struct _IndicatorSessionActionsMock
+{
+ /*< private >*/
+ IndicatorSessionActions parent;
+ IndicatorSessionActionsMockPriv * priv;
+};
+
+struct _IndicatorSessionActionsMockClass
+{
+ IndicatorSessionActionsClass parent_class;
+};
+
+GType indicator_session_actions_mock_get_type (void);
+
+IndicatorSessionActions * indicator_session_actions_mock_new (void);
+
+G_END_DECLS
+
+#endif /* __INDICATOR_SESSION_ACTIONS_MOCK_H__ */
diff --git a/tests/backend-mock-guest.c b/tests/backend-mock-guest.c
new file mode 100644
index 0000000..0428783
--- /dev/null
+++ b/tests/backend-mock-guest.c
@@ -0,0 +1,129 @@
+/*
+ * 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 "backend-mock-guest.h"
+
+struct _IndicatorSessionGuestMockPriv
+{
+ gboolean guest_is_active;
+ gboolean guest_is_logged_in;
+ gboolean guest_is_allowed;
+};
+
+typedef IndicatorSessionGuestMockPriv priv_t;
+
+G_DEFINE_TYPE (IndicatorSessionGuestMock,
+ indicator_session_guest_mock,
+ INDICATOR_TYPE_SESSION_GUEST)
+
+/***
+**** Virtual Functions
+***/
+
+static void
+my_dispose (GObject * o)
+{
+ G_OBJECT_CLASS (indicator_session_guest_mock_parent_class)->dispose (o);
+}
+
+static void
+my_finalize (GObject * o)
+{
+ G_OBJECT_CLASS (indicator_session_guest_mock_parent_class)->finalize (o);
+}
+
+static gboolean
+my_is_allowed (IndicatorSessionGuest * self)
+{
+ return INDICATOR_SESSION_GUEST_MOCK(self)->priv->guest_is_allowed;
+}
+
+static gboolean
+my_is_logged_in (IndicatorSessionGuest * self)
+{
+ g_return_val_if_fail (INDICATOR_IS_SESSION_GUEST_MOCK(self), FALSE);
+
+ return INDICATOR_SESSION_GUEST_MOCK(self)->priv->guest_is_logged_in;
+}
+
+static gboolean
+my_is_active (IndicatorSessionGuest * self)
+{
+ return INDICATOR_SESSION_GUEST_MOCK(self)->priv->guest_is_active;
+}
+
+static void
+my_switch_to_guest (IndicatorSessionGuest * self)
+{
+ g_message ("%s %s FIXME", G_STRLOC, G_STRFUNC);
+}
+
+/***
+**** GObject Boilerplate
+***/
+
+static void
+/* cppcheck-suppress unusedFunction */
+indicator_session_guest_mock_class_init (IndicatorSessionGuestMockClass * klass)
+{
+ GObjectClass * object_class;
+ IndicatorSessionGuestClass * guest_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = my_dispose;
+ object_class->finalize = my_finalize;
+
+ guest_class = INDICATOR_SESSION_GUEST_CLASS (klass);
+ guest_class->is_allowed = my_is_allowed;
+ guest_class->is_logged_in = my_is_logged_in;
+ guest_class->is_active = my_is_active;
+ guest_class->switch_to_guest = my_switch_to_guest;
+
+ g_type_class_add_private (klass, sizeof (IndicatorSessionGuestMockPriv));
+}
+
+static void
+/* cppcheck-suppress unusedFunction */
+indicator_session_guest_mock_init (IndicatorSessionGuestMock * self)
+{
+ priv_t * p;
+
+ p = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ INDICATOR_TYPE_SESSION_GUEST_MOCK,
+ IndicatorSessionGuestMockPriv);
+ self->priv = p;
+
+ p->guest_is_allowed = TRUE;
+ p->guest_is_active = FALSE;
+ p->guest_is_logged_in = FALSE;
+}
+
+/***
+**** Public
+***/
+
+IndicatorSessionGuest *
+indicator_session_guest_mock_new (void)
+{
+ gpointer o = g_object_new (INDICATOR_TYPE_SESSION_GUEST_MOCK, NULL);
+
+ return INDICATOR_SESSION_GUEST (o);
+}
diff --git a/tests/backend-mock-guest.h b/tests/backend-mock-guest.h
new file mode 100644
index 0000000..db6ce86
--- /dev/null
+++ b/tests/backend-mock-guest.h
@@ -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/>.
+ */
+
+#ifndef __GUEST_MOCK_H__
+#define __GUEST_MOCK_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "guest.h" /* parent class */
+
+G_BEGIN_DECLS
+
+#define INDICATOR_TYPE_SESSION_GUEST_MOCK (indicator_session_guest_mock_get_type())
+#define INDICATOR_SESSION_GUEST_MOCK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_GUEST_MOCK, IndicatorSessionGuestMock))
+#define INDICATOR_SESSION_GUEST_MOCK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_GUEST_MOCK, IndicatorSessionGuestMockClass))
+#define INDICATOR_IS_SESSION_GUEST_MOCK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_GUEST_MOCK))
+
+typedef struct _IndicatorSessionGuestMock IndicatorSessionGuestMock;
+typedef struct _IndicatorSessionGuestMockPriv IndicatorSessionGuestMockPriv;
+typedef struct _IndicatorSessionGuestMockClass IndicatorSessionGuestMockClass;
+
+/**
+ * An implementation of IndicatorSessionGuest that gets its user information
+ * from org.freedesktop.ConsoleKit and org.freedesktop.Accounts over DBus.
+ */
+struct _IndicatorSessionGuestMock
+{
+ /*< private >*/
+ IndicatorSessionGuest parent;
+ IndicatorSessionGuestMockPriv * priv;
+};
+
+struct _IndicatorSessionGuestMockClass
+{
+ IndicatorSessionGuestClass parent_class;
+};
+
+GType indicator_session_guest_mock_get_type (void);
+
+IndicatorSessionGuest * indicator_session_guest_mock_new (void);
+
+G_END_DECLS
+
+#endif
diff --git a/tests/backend-mock-users.c b/tests/backend-mock-users.c
new file mode 100644
index 0000000..d9ab5a8
--- /dev/null
+++ b/tests/backend-mock-users.c
@@ -0,0 +1,189 @@
+/*
+ * 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 "backend-mock.h"
+#include "backend-mock-users.h"
+
+struct _IndicatorSessionUsersMockPriv
+{
+ GHashTable * users;
+};
+
+typedef IndicatorSessionUsersMockPriv priv_t;
+
+G_DEFINE_TYPE (IndicatorSessionUsersMock,
+ indicator_session_users_mock,
+ INDICATOR_TYPE_SESSION_USERS)
+
+/***
+****
+***/
+
+static void
+my_dispose (GObject * o)
+{
+ G_OBJECT_CLASS (indicator_session_users_mock_parent_class)->dispose (o);
+}
+
+static void
+my_finalize (GObject * o)
+{
+ priv_t * p = INDICATOR_SESSION_USERS_MOCK (o)->priv;
+
+ g_hash_table_destroy (p->users);
+
+ G_OBJECT_CLASS (indicator_session_users_mock_parent_class)->finalize (o);
+}
+
+static gboolean
+my_is_live_session (IndicatorSessionUsers * users G_GNUC_UNUSED)
+{
+ return g_settings_get_boolean (mock_settings, "is-live-session");
+}
+
+static void
+my_activate_user (IndicatorSessionUsers * users, const char * key)
+{
+ g_message ("%s %s users %p key %s FIXME", G_STRLOC, G_STRFUNC, (void*)users, key);
+}
+
+static GStrv
+my_get_keys (IndicatorSessionUsers * users)
+{
+ int i;
+ priv_t * p;
+ gchar ** keys;
+ GHashTableIter iter;
+ gpointer key;
+
+ g_return_val_if_fail (INDICATOR_IS_SESSION_USERS_MOCK(users), NULL);
+ p = INDICATOR_SESSION_USERS_MOCK (users)->priv;
+
+ i = 0;
+ keys = g_new (gchar*, g_hash_table_size(p->users)+1);
+ g_hash_table_iter_init (&iter, p->users);
+ while (g_hash_table_iter_next (&iter, &key, NULL))
+ keys[i++] = g_strdup (key);
+ keys[i] = NULL;
+
+ return keys;
+}
+
+static IndicatorSessionUser *
+my_get_user (IndicatorSessionUsers * self, const gchar * key)
+{
+ priv_t * p;
+ const IndicatorSessionUser * src;
+ IndicatorSessionUser * ret = NULL;
+
+ g_return_val_if_fail (INDICATOR_IS_SESSION_USERS_MOCK(self), NULL);
+ p = INDICATOR_SESSION_USERS_MOCK (self)->priv;
+
+ if ((src = g_hash_table_lookup (p->users, key)))
+ {
+ ret = g_new0 (IndicatorSessionUser, 1);
+ ret->is_current_user = src->is_current_user;
+ ret->is_logged_in = src->is_logged_in;
+ ret->uid = src->uid;
+ ret->login_frequency = src->login_frequency;
+ ret->user_name = g_strdup (src->user_name);
+ ret->real_name = g_strdup (src->real_name);
+ ret->icon_file = g_strdup (src->icon_file);
+ }
+
+ return ret;
+}
+
+static void
+/* cppcheck-suppress unusedFunction */
+indicator_session_users_mock_class_init (IndicatorSessionUsersMockClass * klass)
+{
+ GObjectClass * object_class;
+ IndicatorSessionUsersClass * users_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = my_dispose;
+ object_class->finalize = my_finalize;
+
+ users_class = INDICATOR_SESSION_USERS_CLASS (klass);
+ users_class->is_live_session = my_is_live_session;
+ users_class->get_keys = my_get_keys;
+ users_class->get_user = my_get_user;
+ users_class->activate_user = my_activate_user;
+
+ g_type_class_add_private (klass, sizeof (IndicatorSessionUsersMockPriv));
+}
+
+static void
+/* cppcheck-suppress unusedFunction */
+indicator_session_users_mock_init (IndicatorSessionUsersMock * self)
+{
+ priv_t * p;
+
+ p = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ INDICATOR_TYPE_SESSION_USERS_MOCK,
+ IndicatorSessionUsersMockPriv);
+ self->priv = p;
+
+ p->users = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify)indicator_session_user_free);
+
+ g_signal_connect_swapped (mock_settings, "changed::is-live-session",
+ G_CALLBACK(indicator_session_users_notify_is_live_session), self);
+}
+
+/***
+**** Public
+***/
+
+IndicatorSessionUsers *
+indicator_session_users_mock_new (void)
+{
+ gpointer o = g_object_new (INDICATOR_TYPE_SESSION_USERS_MOCK, NULL);
+
+ return INDICATOR_SESSION_USERS (o);
+}
+
+
+void
+indicator_session_users_mock_add_user (IndicatorSessionUsersMock * self,
+ const char * key,
+ IndicatorSessionUser * user)
+{
+ g_return_if_fail (INDICATOR_IS_SESSION_USERS_MOCK (self));
+ g_return_if_fail (key && *key);
+ g_return_if_fail (user != NULL);
+
+ g_hash_table_insert (self->priv->users, g_strdup(key), user);
+ indicator_session_users_added (INDICATOR_SESSION_USERS (self), key);
+}
+
+void
+indicator_session_users_mock_remove_user (IndicatorSessionUsersMock * self,
+ const char * key)
+{
+ g_return_if_fail (INDICATOR_IS_SESSION_USERS_MOCK (self));
+ g_return_if_fail (key && *key);
+
+ g_hash_table_remove (self->priv->users, key);
+ indicator_session_users_removed (INDICATOR_SESSION_USERS (self), key);
+}
+
diff --git a/tests/backend-mock-users.h b/tests/backend-mock-users.h
new file mode 100644
index 0000000..c7e11d3
--- /dev/null
+++ b/tests/backend-mock-users.h
@@ -0,0 +1,70 @@
+/*
+ * 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 __USERS_MOCK_H__
+#define __USERS_MOCK_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "users.h" /* parent class */
+
+G_BEGIN_DECLS
+
+#define INDICATOR_TYPE_SESSION_USERS_MOCK (indicator_session_users_mock_get_type())
+#define INDICATOR_SESSION_USERS_MOCK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_USERS_MOCK, IndicatorSessionUsersMock))
+#define INDICATOR_SESSION_USERS_MOCK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_USERS_MOCK, IndicatorSessionUsersMockClass))
+#define INDICATOR_IS_SESSION_USERS_MOCK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_USERS_MOCK))
+
+typedef struct _IndicatorSessionUsersMock IndicatorSessionUsersMock;
+typedef struct _IndicatorSessionUsersMockPriv IndicatorSessionUsersMockPriv;
+typedef struct _IndicatorSessionUsersMockClass IndicatorSessionUsersMockClass;
+
+/**
+ * An implementation of IndicatorSessionUsers that gets its user information
+ * from org.freedesktop.ConsoleKit and org.freedesktop.Accounts over DBus.
+ */
+struct _IndicatorSessionUsersMock
+{
+ /*< private >*/
+ IndicatorSessionUsers parent;
+ IndicatorSessionUsersMockPriv * priv;
+};
+
+struct _IndicatorSessionUsersMockClass
+{
+ IndicatorSessionUsersClass parent_class;
+};
+
+GType indicator_session_users_mock_get_type (void);
+
+IndicatorSessionUsers * indicator_session_users_mock_new (void);
+
+void indicator_session_users_mock_add_user (IndicatorSessionUsersMock * self,
+ const char * key,
+ IndicatorSessionUser * user);
+
+void indicator_session_users_mock_remove_user (IndicatorSessionUsersMock * self,
+ const char * key);
+
+
+
+G_END_DECLS
+
+#endif
diff --git a/tests/backend-mock.c b/tests/backend-mock.c
new file mode 100644
index 0000000..48d7de4
--- /dev/null
+++ b/tests/backend-mock.c
@@ -0,0 +1,44 @@
+/*
+ * 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 "backend-mock.h"
+#include "backend-mock-actions.h"
+#include "backend-mock-guest.h"
+#include "backend-mock-users.h"
+
+GSettings * mock_settings = NULL;
+IndicatorSessionActions * mock_actions = NULL;
+IndicatorSessionUsers * mock_users = NULL;
+IndicatorSessionGuest * mock_guest = NULL;
+
+void
+backend_get (GCancellable * cancellable G_GNUC_UNUSED,
+ IndicatorSessionActions ** setme_actions,
+ IndicatorSessionUsers ** setme_users,
+ IndicatorSessionGuest ** setme_guest)
+{
+ if (setme_actions != NULL)
+ *setme_actions = g_object_ref (mock_actions);
+
+ if (setme_users != NULL)
+ *setme_users = g_object_ref (mock_users);
+
+ if (setme_guest != NULL)
+ *setme_guest = g_object_ref (mock_guest);
+}
diff --git a/tests/backend-mock.h b/tests/backend-mock.h
new file mode 100644
index 0000000..d80a185
--- /dev/null
+++ b/tests/backend-mock.h
@@ -0,0 +1,38 @@
+/*
+ * 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 __BACKEND_MOCK_H__
+#define __BACKEND_MOCK_H__
+
+#include <gio/gio.h> /* GCancellable */
+
+#include "actions.h"
+#include "guest.h"
+#include "users.h"
+
+G_BEGIN_DECLS
+
+extern GSettings * mock_settings;
+extern IndicatorSessionActions * mock_actions;
+extern IndicatorSessionUsers * mock_users;
+extern IndicatorSessionGuest * mock_guest;
+
+G_END_DECLS
+
+#endif
diff --git a/tests/com.canonical.indicator.session.backendmock.gschema.xml b/tests/com.canonical.indicator.session.backendmock.gschema.xml
new file mode 100644
index 0000000..34479df
--- /dev/null
+++ b/tests/com.canonical.indicator.session.backendmock.gschema.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schemalist gettext-domain="gsettings-desktop-schemas">
+ <schema path="/com/canonical/indicator/session/backendmock/" id="com.canonical.indicator.session.backendmock">
+ <key type="s" name="last-command">
+ <default>''</default>
+ <summary>The last command activated</summary>
+ </key>
+ <key type="b" name="has-online-account-error">
+ <default>false</default>
+ <summary>Has online account error</summary>
+ </key>
+ <key type="b" name="can-hibernate">
+ <default>true</default>
+ <summary>Is hibernation allowed?</summary>
+ </key>
+ <key type="b" name="can-suspend">
+ <default>true</default>
+ <summary>Is suspending allowed?</summary>
+ </key>
+ <key type="b" name="can-logout">
+ <default>true</default>
+ <summary>Is logging out allowed?</summary>
+ </key>
+ <key type="b" name="can-lock">
+ <default>true</default>
+ <summary>Is locking the session allowed?</summary>
+ </key>
+ <key type="b" name="can-switch-sessions">
+ <default>true</default>
+ <summary>Is switching sessions allowed?</summary>
+ </key>
+ <key type="b" name="can-prompt">
+ <default>true</default>
+ <summary>Do we have a way of prompting for confirmation?</summary>
+ </key>
+ <key type="b" name="is-live-session">
+ <default>false</default>
+ <summary>Is this a session running on a live CD?</summary>
+ </key>
+ </schema>
+</schemalist>
diff --git a/tests/com.canonical.indicator.session.gschema.xml b/tests/com.canonical.indicator.session.gschema.xml
new file mode 100644
index 0000000..76b2be3
--- /dev/null
+++ b/tests/com.canonical.indicator.session.gschema.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schemalist>
+ <schema path="/apps/indicator-session/" id="com.canonical.indicator.session">
+ <key type="b" name="suppress-logout-restart-shutdown">
+ <default>false</default>
+ <summary>Suppress the dialog to confirm logout, restart and shutdown action</summary>
+ <description>Whether or not to show confirmation dialogs for logout, restart and shutdown actions.</description>
+ </key>
+ <key type="b" name="suppress-logout-menuitem">
+ <default>false</default>
+ <summary>Remove the Log Out item from the session menu</summary>
+ <description>Makes it so that the logout button doesn’t show in the session menu.</description>
+ </key>
+ <key type="b" name="suppress-restart-menuitem">
+ <default>false</default>
+ <summary>Remove the Restart item from the session menu</summary>
+ <description>Makes it so that the restart button doesn’t show in the session menu.</description>
+ </key>
+ <key type="b" name="suppress-shutdown-menuitem">
+ <default>false</default>
+ <summary>Remove the shutdown item from the session menu</summary>
+ <description>Makes it so that the shutdown button doesn’t show in the session menu.</description>
+ </key>
+ <key type="b" name="show-real-name-on-panel">
+ <default>false</default>
+ <summary>Determine the visibility of the User's real name on the panel</summary>
+ <description>Allow for the Removal of the users name from the panel</description>
+ </key>
+
+ </schema>
+
+</schemalist> \ No newline at end of file
diff --git a/tests/gtest-dbus-fixture.h b/tests/gtest-dbus-fixture.h
new file mode 100644
index 0000000..e6cd9c7
--- /dev/null
+++ b/tests/gtest-dbus-fixture.h
@@ -0,0 +1,134 @@
+/*
+ * 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 <gtest/gtest.h>
+
+/***
+****
+***/
+
+class GTestDBusFixture : public ::testing::Test
+{
+ private:
+
+ static void
+ on_bus_opened (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself)
+ {
+ GTestDBusFixture * self = static_cast<GTestDBusFixture*>(gself);
+
+ GError * err = 0;
+ self->conn = g_bus_get_finish (res, &err);
+ g_assert_no_error (err);
+
+ g_main_loop_quit (self->loop);
+ }
+
+ static void
+ on_bus_closed (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself)
+ {
+ GTestDBusFixture * self = static_cast<GTestDBusFixture*>(gself);
+
+ GError * err = 0;
+ g_dbus_connection_close_finish (self->conn, res, &err);
+ g_assert_no_error (err);
+
+ g_main_loop_quit (self->loop);
+ }
+
+ static gboolean
+ wait_for_signal__timeout (gpointer name)
+ {
+ g_error ("%s: timed out waiting for signal '%s'", G_STRLOC, (char*)name);
+ return G_SOURCE_REMOVE;
+ }
+
+ protected:
+
+ virtual void SetUp ()
+ {
+ conn = 0;
+ test_dbus = 0;
+ loop = 0;
+
+ g_setenv ("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, TRUE);
+ g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
+ g_debug ("SCHEMA_DIR is %s", SCHEMA_DIR);
+
+ // pull up a test dbus
+ loop = g_main_loop_new (NULL, FALSE);
+ test_dbus = g_test_dbus_new (G_TEST_DBUS_NONE);
+ g_test_dbus_add_service_dir (test_dbus, INDICATOR_SERVICE_DIR);
+ g_debug ("INDICATOR_SERVICE_DIR is %s", INDICATOR_SERVICE_DIR);
+ g_test_dbus_up (test_dbus);
+ const char * address;
+ address = g_test_dbus_get_bus_address (test_dbus);
+ g_setenv ("DBUS_SYSTEM_BUS_ADDRESS", address, TRUE);
+ g_debug ("test_dbus's address is %s", address);
+
+ // wait for the GDBusConnection before returning
+ g_bus_get (G_BUS_TYPE_SYSTEM, NULL, on_bus_opened, this);
+ g_main_loop_run (loop);
+ }
+
+ virtual void TearDown()
+ {
+ // close the bus connection
+ g_dbus_connection_close (conn, NULL, on_bus_closed, this);
+ g_main_loop_run (loop);
+ g_clear_object (&conn);
+
+ // tear down the test dbus
+ g_test_dbus_down (test_dbus);
+ g_clear_object (&test_dbus);
+
+ g_clear_pointer (&loop, g_main_loop_unref);
+ }
+
+ /* convenience func to loop while waiting for a GObject's signal */
+ void wait_for_signal (gpointer o, const gchar * signal)
+ {
+ const int timeout_seconds = 5; // arbitrary
+
+ // wait for the signal or for timeout, whichever comes first
+ guint handler_id = g_signal_connect_swapped (o, signal,
+ G_CALLBACK(g_main_loop_quit),
+ loop);
+ gulong timeout_id = g_timeout_add_seconds (timeout_seconds,
+ wait_for_signal__timeout,
+ loop);
+ g_main_loop_run (loop);
+ g_source_remove (timeout_id);
+ g_signal_handler_disconnect (o, handler_id);
+ }
+
+ /* convenience func to loop for N msec */
+ void wait_msec (int msec)
+ {
+ guint id = g_timeout_add (msec, (GSourceFunc)g_main_loop_quit, loop);
+ g_main_loop_run (loop);
+ g_source_remove (id);
+ }
+
+ GMainLoop * loop;
+ GTestDBus * test_dbus;
+ GDBusConnection * conn;
+};
diff --git a/tests/indicator-session.service.in b/tests/indicator-session.service.in
index 80aab0d..fb3798a 100644
--- a/tests/indicator-session.service.in
+++ b/tests/indicator-session.service.in
@@ -1,3 +1,3 @@
[D-BUS Service]
-Name=com.canonical.indicator.session
-Exec=@abs_top_builddir@/src/indicator-session-service
+Name=com.canonical.indicator.session-test
+Exec=${CMAKE_BINARY_DIR}/src/indicator-session-service --mock
diff --git a/tests/test-service.cc b/tests/test-service.cc
index b1ca5bc..058fc3d 100644
--- a/tests/test-service.cc
+++ b/tests/test-service.cc
@@ -17,70 +17,329 @@ 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-object.h>
-#include <gio/gio.h>
-#include <glib.h>
-
-#include <gtest/gtest.h>
-
-#include "shared-names.h"
+#include "gtest-dbus-fixture.h"
+#include "service.h"
+#include "backend-mock.h"
+#include "backend-mock-users.h"
+#include "backend-mock-guest.h"
+#include "backend-mock-actions.h"
/***
****
***/
-#define INDICATOR_SERVICE_OBJECT_PATH "/org/ayatana/indicator/service"
-#define INDICATOR_SERVICE_INTERFACE_NAME "org.ayatana.indicator.service"
+#if 0
+namespace
+{
+ void
+ dump_menu_model (GMenuModel * model, int depth)
+ {
+ GString * indent = g_string_new_len (" ", (depth*4));
+ const int n = g_menu_model_get_n_items (model);
+ g_message ("%s depth[%d] menu model[%p] has %d items", indent->str, depth, (void*)model, n);
+
+ for (int i=0; i<n; ++i)
+ {
+ const char * name;
+ GMenuModel * link_value;
+ GVariant * attribute_value;
+
+ GMenuAttributeIter * attribute_iter = g_menu_model_iterate_item_attributes (model, i);
+ while (g_menu_attribute_iter_get_next (attribute_iter, &name, &attribute_value))
+ {
+ char * str = g_variant_print (attribute_value, TRUE);
+ g_message ("%s depth[%d] menu model[%p] item[%d] attribute key[%s] value[%s]", indent->str, depth, (void*)model, i, name, str);
+ g_free (str);
+ g_variant_unref (attribute_value);
+ }
+ g_clear_object (&attribute_iter);
+
+ GMenuLinkIter * link_iter = g_menu_model_iterate_item_links (model, i);
+ while (g_menu_link_iter_get_next (link_iter, &name, &link_value))
+ {
+ g_message ("%s depth[%d] menu model[%p] item[%d] attribute key[%s] model[%p]", indent->str, depth, (void*)model, i, name, (void*)link_value);
+ dump_menu_model (link_value, depth+1);
+ g_object_unref (link_value);
+ }
+ g_clear_object (&link_iter);
+ }
+ g_string_free (indent, TRUE);
+ }
+}
+#endif
-class ClientTest : public ::testing::Test
+
+/* cppcheck-suppress noConstructor */
+class ServiceTest: public GTestDBusFixture
{
+ typedef GTestDBusFixture super;
+
+ enum { TIME_LIMIT_SEC = 10 };
+
+ private:
+
+ static void on_name_appeared (GDBusConnection * connection G_GNUC_UNUSED,
+ const gchar * name G_GNUC_UNUSED,
+ const gchar * name_owner G_GNUC_UNUSED,
+ gpointer gself)
+ {
+ g_main_loop_quit (static_cast<ServiceTest*>(gself)->loop);
+ }
+
+ GSList * menu_references;
+
+ bool any_item_changed;
+
+ static void on_items_changed (GMenuModel * model G_GNUC_UNUSED,
+ gint position G_GNUC_UNUSED,
+ gint removed G_GNUC_UNUSED,
+ gint added G_GNUC_UNUSED,
+ gpointer any_item_changed)
+ {
+ *((gboolean*)any_item_changed) = true;
+ }
+
+ protected:
+
+ void activate_subtree (GMenuModel * model)
+ {
+ // query the GDBusMenuModel for information to activate it
+ int n = g_menu_model_get_n_items (model);
+ if (!n)
+ {
+ // give the model a moment to populate its info
+ wait_msec (100);
+ n = g_menu_model_get_n_items (model);
+ }
+
+ // keep a ref so that it stays activated
+ menu_references = g_slist_prepend (menu_references, g_object_ref(model));
+
+ g_signal_connect (model, "items-changed", G_CALLBACK(on_items_changed), &any_item_changed);
+
+ // recurse
+ for (int i=0; i<n; ++i)
+ {
+ GMenuModel * link;
+ GMenuLinkIter * iter = g_menu_model_iterate_item_links (model, i);
+ while (g_menu_link_iter_get_next (iter, NULL, &link))
+ {
+ activate_subtree (link);
+ g_object_unref (link);
+ }
+ g_clear_object (&iter);
+ }
+ }
+
+ void sync_menu (void)
+ {
+ g_slist_free_full (menu_references, (GDestroyNotify)g_object_unref);
+ menu_references = NULL;
+ activate_subtree (G_MENU_MODEL (menu_model));
+ }
+
+ GDBusMenuModel * menu_model;
+ GDBusActionGroup * action_group;
+ IndicatorSessionService * service;
+ GTimer * timer;
+ GSettings * indicator_settings;
+
+ virtual void SetUp ()
+ {
+ super :: SetUp ();
+
+ menu_references = NULL;
+ any_item_changed = NULL;
+
+ timer = g_timer_new ();
+ mock_settings = g_settings_new ("com.canonical.indicator.session.backendmock");
+ mock_actions = indicator_session_actions_mock_new ();
+ mock_users = indicator_session_users_mock_new ();
+ mock_guest = indicator_session_guest_mock_new ();
+ indicator_settings = g_settings_new ("com.canonical.indicator.session");
+
+ // Start an IndicatorSessionService and wait for it to appear on the bus.
+ // This way our calls to g_dbus_*_get() in the next paragraph won't activate
+ // a second copy of the service...
+ service = indicator_session_service_new (true);
+
+ // confirm that the property got set
+ gboolean replace = FALSE;
+ g_object_get (service, "replace", &replace, NULL);
+ ASSERT_TRUE (replace);
+
+ // wait for the service to show up on the bus
+ const guint watch_id = g_bus_watch_name_on_connection (conn,
+ "com.canonical.indicator.session-test",
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ on_name_appeared, // quits the loop
+ NULL, this, NULL);
+ const guint timer_id = g_timeout_add_seconds (TIME_LIMIT_SEC, (GSourceFunc)g_main_loop_quit, loop);
+ g_main_loop_run (loop);
+ g_source_remove (timer_id);
+ g_bus_unwatch_name (watch_id);
+ ASSERT_FALSE (times_up());
+
+ // get the actions & menus that the service exported.
+ action_group = g_dbus_action_group_get (conn,
+ "com.canonical.indicator.session-test",
+ "/com/canonical/indicator/session");
+ menu_model = g_dbus_menu_model_get (conn,
+ "com.canonical.indicator.session-test",
+ "/com/canonical/indicator/session/desktop");
+ // the actions are added asynchronously, so wait for the actions
+ if (!g_action_group_has_action (G_ACTION_GROUP(action_group), "about"))
+ wait_for_signal (action_group, "action-added");
+ // activate all the groups in the menu so it'll be ready when we need it
+ g_signal_connect (menu_model, "items-changed", G_CALLBACK(on_items_changed), &any_item_changed);
+ sync_menu ();
+ }
+
+ virtual void TearDown ()
+ {
+ g_clear_pointer (&timer, g_timer_destroy);
+
+ g_slist_free_full (menu_references, (GDestroyNotify)g_object_unref);
+ menu_references = NULL;
+ g_clear_object (&menu_model);
+
+ g_clear_object (&action_group);
+ g_clear_object (&mock_settings);
+ g_clear_object (&indicator_settings);
+ g_clear_object (&service);
+ g_clear_object (&mock_actions);
+ g_clear_object (&mock_users);
+ g_clear_object (&mock_guest);
+ wait_msec (100);
+
+ super :: TearDown ();
+ }
+
protected:
- GTestDBus * test_dbus;
- GDBusConnection * session_bus;
- GMainLoop * main_loop;
+ bool times_up () const
+ {
+ return g_timer_elapsed (timer, NULL) >= TIME_LIMIT_SEC;
+ }
+
+ void wait_for_has_action (const char * name)
+ {
+ while (!g_action_group_has_action (G_ACTION_GROUP(action_group), name) && !times_up())
+ wait_msec (50);
+
+ ASSERT_FALSE (times_up());
+ ASSERT_TRUE (g_action_group_has_action (G_ACTION_GROUP(action_group), name));
+ }
- virtual void SetUp()
+ void wait_for_menu_resync (void)
{
- test_dbus = NULL;
- session_bus = NULL;
- main_loop = NULL;
+ any_item_changed = false;
+ while (!times_up() && !any_item_changed)
+ wait_msec (50);
+ sync_menu ();
+ }
+
+ protected:
+
+ void check_last_command_is (const char * expected)
+ {
+ char * str = g_settings_get_string (mock_settings, "last-command");
+ ASSERT_STREQ (expected, str);
+ g_free (str);
+ }
- static bool first_run = true;
- if (first_run)
+ void test_simple_action (const char * action_name)
+ {
+ wait_for_has_action (action_name);
+
+ g_action_group_activate_action (G_ACTION_GROUP (action_group), action_name, NULL);
+ wait_for_signal (mock_settings, "changed::last-command");
+ check_last_command_is (action_name);
+ }
+
+ protected:
+
+ bool find_menu_item_for_action (const char * action_key, GMenuModel ** setme, int * item_index)
+ {
+ bool success = false;
+
+ for (GSList * l=menu_references; !success && (l!=NULL); l=l->next)
{
- g_setenv ("INDICATOR_SERVICE_SHUTDOWN_TIMEOUT", "1000", TRUE);
- g_unsetenv ("INDICATOR_ALLOW_NO_WATCHERS");
- g_unsetenv ("INDICATOR_SERVICE_REPLACE_MODE");
- g_setenv ("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, TRUE);
- g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
- first_run = false;
+ GMenuModel * mm = G_MENU_MODEL (l->data);
+ const int n = g_menu_model_get_n_items (mm);
+
+ for (int i=0; !success && i<n; ++i)
+ {
+ char * action = NULL;
+ if (!g_menu_model_get_item_attribute (mm, i, G_MENU_ATTRIBUTE_ACTION, "s", &action))
+ continue;
+
+ if ((success = !g_strcmp0 (action, action_key)))
+ {
+ if (setme != NULL)
+ *setme = G_MENU_MODEL (g_object_ref (G_OBJECT(mm)));
+
+ if (item_index != NULL)
+ *item_index = i;
+ }
+
+ g_free (action);
+ }
}
- main_loop = g_main_loop_new (NULL, FALSE);
- // pull up a test dbus that's pointed at our test .service file
- test_dbus = g_test_dbus_new (G_TEST_DBUS_NONE);
- g_debug (G_STRLOC" service dir path is \"%s\"", INDICATOR_SERVICE_DIR);
- g_test_dbus_add_service_dir (test_dbus, INDICATOR_SERVICE_DIR);
+ return success;
+ }
+
+ bool action_menuitem_label_is_ellipsized (const char * action_name)
+ {
+ int pos = -1;
+ GMenuModel * model = 0;
+ bool ellipsized = false;
+ char * label = NULL;
+
+ if (find_menu_item_for_action (action_name, &model, &pos))
+ {
+ g_menu_model_get_item_attribute (model, pos, G_MENU_ATTRIBUTE_LABEL, "s", &label);
+ g_object_unref (G_OBJECT(model));
+ }
+
+ ellipsized = (label != NULL) && g_str_has_suffix (label, "\342\200\246");
+ g_free (label);
+ return ellipsized;
+ }
+
+ void check_header (const char * expected_label, const char * expected_icon, const char * expected_a11y)
+ {
+ GVariant * variant;
+ const gchar * label = NULL;
+ const gchar * icon = NULL;
+ const gchar * a11y = NULL;
+ gboolean visible;
+
+ variant = g_action_group_get_action_state (G_ACTION_GROUP(action_group), "_header");
+ g_variant_get (variant, "(&s&s&sb)", &label, &icon, &a11y, &visible);
+
+ if (expected_label != NULL)
+ ASSERT_STREQ (expected_label, label);
- // allow the service to exist w/o a sync indicator
- g_setenv ("INDICATOR_ALLOW_NO_WATCHERS", "1", TRUE);
+ if (expected_icon != NULL)
+ ASSERT_STREQ (expected_icon, icon);
- g_test_dbus_up (test_dbus);
- g_debug (G_STRLOC" this test bus' address is \"%s\"", g_test_dbus_get_bus_address(test_dbus));
- session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
- g_debug (G_STRLOC" the dbus connection %p unique name is \"%s\"", session_bus, g_dbus_connection_get_unique_name(session_bus));
- g_debug (G_STRLOC" the dbus connection %p refcount is %d", session_bus, G_OBJECT(session_bus)->ref_count);
+ if (expected_a11y != NULL)
+ ASSERT_STREQ (expected_a11y, a11y);
+
+ // the session menu is always visible...
+ ASSERT_TRUE (visible);
+
+ g_variant_unref (variant);
}
- // undo SetUp
- virtual void TearDown()
+ void check_label (const char * expected_label, GMenuModel * model, int pos)
{
- g_clear_object (&session_bus);
- g_debug (G_STRLOC" tearing down the bus");
- g_test_dbus_down (test_dbus);
- g_clear_object (&test_dbus);
- g_clear_pointer (&main_loop, g_main_loop_unref);
+ char * label = NULL;
+ ASSERT_TRUE (g_menu_model_get_item_attribute (model, pos, G_MENU_ATTRIBUTE_LABEL, "s", &label));
+ ASSERT_STREQ (expected_label, label);
+ g_free (label);
}
};
@@ -88,58 +347,438 @@ class ClientTest : public ::testing::Test
****
***/
+#if 0
+TEST_F (ServiceTest, HelloWorld)
+{
+ ASSERT_TRUE (true);
+}
+#endif
+
+TEST_F (ServiceTest, About)
+{
+ test_simple_action ("about");
+}
+
+TEST_F (ServiceTest, Help)
+{
+ test_simple_action ("help");
+}
+
+TEST_F (ServiceTest, Hibernate)
+{
+ test_simple_action ("hibernate");
+}
+
+TEST_F (ServiceTest, Settings)
+{
+ test_simple_action ("settings");
+}
+
+TEST_F (ServiceTest, Logout)
+{
+ test_simple_action ("logout");
+}
+
+TEST_F (ServiceTest, Shutdown)
+{
+ test_simple_action ("shutdown");
+}
+
+TEST_F (ServiceTest, Restart)
+{
+ test_simple_action ("restart");
+}
+
+TEST_F (ServiceTest, SwitchToScreensaver)
+{
+ test_simple_action ("switch-to-screensaver");
+}
+
+TEST_F (ServiceTest, SwitchToGuest)
+{
+ test_simple_action ("switch-to-guest");
+}
+
+TEST_F (ServiceTest, SwitchToGreeter)
+{
+ test_simple_action ("switch-to-greeter");
+}
+
+TEST_F (ServiceTest, Suspend)
+{
+ test_simple_action ("suspend");
+}
+
+#if 0
+namespace
+{
+ gboolean
+ find_menu_item_for_action (GMenuModel * top, const char * action_key, GMenuModel ** setme, int * item_index)
+ {
+ gboolean success = FALSE;
+ const int n = g_menu_model_get_n_items (top);
+
+ for (int i=0; !success && i<n; ++i)
+ {
+ char * action = NULL;
+ if (g_menu_model_get_item_attribute (top, i, G_MENU_ATTRIBUTE_ACTION, "s", &action))
+ {
+ if ((success = !g_strcmp0 (action, action_key)))
+ {
+ *setme = G_MENU_MODEL (g_object_ref (G_OBJECT(top)));
+ *item_index = i;
+ }
+
+ g_free (action);
+ }
+
+ const char * name = NULL;
+ GMenuModel * link_value = NULL;
+ GMenuLinkIter * link_iter = g_menu_model_iterate_item_links (top, i);
+ while (!success && g_menu_link_iter_get_next (link_iter, &name, &link_value))
+ {
+ success = find_menu_item_for_action (link_value, action_key, setme, item_index);
+ g_object_unref (link_value);
+ }
+ g_clear_object (&link_iter);
+ }
+
+ return success;
+ }
+
+ gchar *
+ get_menu_label_for_action (GMenuModel * top, const char * action)
+ {
+ int pos;
+ GMenuModel * model;
+ gchar * label = NULL;
+
+ if (find_menu_item_for_action (top, action, &model, &pos))
+ {
+ g_menu_model_get_item_attribute (model, pos, G_MENU_ATTRIBUTE_LABEL, "s", &label);
+ g_object_unref (G_OBJECT(model));
+ }
+
+ return label;
+ }
+
+ gboolean str_is_ellipsized (const char * str)
+ {
+ g_assert (str != NULL);
+ return g_str_has_suffix (str, "\342\200\246");
+ }
+}
+#endif
+
+TEST_F (ServiceTest, ConfirmationDisabledByBackend)
+{
+ const char * const confirm_supported_key = "can-prompt";
+ const char * const confirm_disabled_key = "suppress-logout-restart-shutdown";
+
+ bool confirm_supported = g_settings_get_boolean (mock_settings, confirm_supported_key);
+ bool confirm_disabled = g_settings_get_boolean (indicator_settings, confirm_disabled_key);
+ bool confirm = confirm_supported && !confirm_disabled;
+
+ // confirm that the ellipsis are correct
+ ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.switch-to-greeter"));
+ ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.logout"));
+ ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.restart"));
+ ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.shutdown"));
+
+ // now toggle the can-prompt flag
+ confirm_supported = !confirm_supported;
+ g_settings_set_boolean (mock_settings, confirm_supported_key, confirm_supported);
+ confirm = confirm_supported && !confirm_disabled;
+
+ wait_for_menu_resync ();
+
+ // confirm that the ellipsis are correct
+ ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.switch-to-greeter"));
+ ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.logout"));
+ ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.restart"));
+ ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.shutdown"));
+
+ // cleanup
+ g_settings_reset (mock_settings, confirm_supported_key);
+}
+
+TEST_F (ServiceTest, ConfirmationDisabledByUser)
+{
+ const char * const confirm_supported_key = "can-prompt";
+ const char * const confirm_disabled_key = "suppress-logout-restart-shutdown";
+
+ bool confirm_supported = g_settings_get_boolean (mock_settings, confirm_supported_key);
+ bool confirm_disabled = g_settings_get_boolean (indicator_settings, confirm_disabled_key);
+ bool confirm = confirm_supported && !confirm_disabled;
+
+ // confirm that the ellipsis are correct
+ ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.switch-to-greeter"));
+ ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.logout"));
+ ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.restart"));
+ ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.shutdown"));
+
+ // now toggle the can-prompt flag
+ confirm_disabled = !confirm_disabled;
+ g_settings_set_boolean (indicator_settings, confirm_disabled_key, confirm_disabled);
+ confirm = confirm_supported && !confirm_disabled;
+
+ wait_for_menu_resync ();
+
+ // confirm that the ellipsis are correct
+ ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.switch-to-greeter"));
+ ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.logout"));
+ ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.restart"));
+ ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.shutdown"));
+
+ // cleanup
+ g_settings_reset (indicator_settings, confirm_disabled_key);
+}
+
/**
- * This is a basic test to see if we can launch indicator-session-service
- * and call its "GetUserRealName" method. The test succeeds if we can launch
- * the service, call the method, and get response that equals g_get_real_name().
- *
- * (You may be wondering why GetUserRealName() exists at all, instead of clients
- * using g_get_real_name(). It's because the former updates itslef when the user
- * edits his real name, while the latter returns its cached copy of the old name.)
+ * Check that the default menu has items for each of these actions
*/
-TEST_F (ClientTest, TestCanStartService)
-{
- GError * error;
- GVariant * result;
- const gchar * name;
-
- // call GetUserRealName(), which as a side effect should activate
- // indicator-session-service via the .service file in the tests/ directory
- error = NULL;
- result = g_dbus_connection_call_sync (session_bus,
- INDICATOR_SESSION_DBUS_NAME,
- INDICATOR_SESSION_SERVICE_DBUS_OBJECT,
- INDICATOR_SESSION_SERVICE_DBUS_IFACE,
- "GetUserRealName",
- NULL,
- G_VARIANT_TYPE("(s)"),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- NULL,
- &error);
-
- EXPECT_TRUE (error == NULL);
- ASSERT_TRUE (result != NULL);
-
- if (error != NULL)
- {
- g_warning ("GetUserRealName failed: %s", error->message);
- g_clear_error (&error);
- }
-
- name = NULL;
- g_variant_get (result, "(&s)", &name);
- ASSERT_STREQ (g_get_real_name(), name);
- g_clear_pointer (&result, g_variant_unref);
-
- // call IndicatorService's Shutdown() method for a clean exit
- result = g_dbus_connection_call_sync (session_bus,
- INDICATOR_SESSION_DBUS_NAME,
- "/org/ayatana/indicator/service",
- "org.ayatana.indicator.service",
- "Shutdown", NULL,
- NULL,
- G_DBUS_CALL_FLAGS_NONE,
- -1, NULL, NULL);
- g_clear_pointer (&result, g_variant_unref);
+TEST_F (ServiceTest, DefaultMenuItems)
+{
+ ASSERT_TRUE (find_menu_item_for_action ("indicator.about", NULL, NULL));
+ ASSERT_TRUE (find_menu_item_for_action ("indicator.help", NULL, NULL));
+ ASSERT_TRUE (find_menu_item_for_action ("indicator.settings", NULL, NULL));
+ ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", NULL, NULL));
+ ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-guest", NULL, NULL));
+ ASSERT_TRUE (find_menu_item_for_action ("indicator.logout", NULL, NULL));
+ ASSERT_TRUE (find_menu_item_for_action ("indicator.suspend", NULL, NULL));
+ ASSERT_TRUE (find_menu_item_for_action ("indicator.hibernate", NULL, NULL));
+ ASSERT_TRUE (find_menu_item_for_action ("indicator.restart", NULL, NULL));
+ ASSERT_TRUE (find_menu_item_for_action ("indicator.shutdown", NULL, NULL));
+}
+
+TEST_F (ServiceTest, OnlineAccountError)
+{
+ bool err;
+ int pos = -1;
+ GMenuModel * model = 0;
+ const char * const error_key = "has-online-account-error";
+
+ // check the initial default header state
+ check_header ("", "system-devices-panel", "System");
+
+ // check that the menuitems' existence matches the error flag
+ err = g_settings_get_boolean (mock_settings, error_key);
+ ASSERT_FALSE (err);
+ ASSERT_EQ (err, find_menu_item_for_action ("indicator.online-accounts", &model, &pos));
+ g_clear_object (&model);
+
+ // now toggle the error flag
+ err = !err;
+ g_settings_set_boolean (mock_settings, error_key, err);
+
+ // wait for the _header action and error menuitem to update
+ wait_for_menu_resync ();
+
+ // check that the menuitems' existence matches the error flag
+ ASSERT_TRUE (g_settings_get_boolean (mock_settings, error_key));
+ ASSERT_TRUE (find_menu_item_for_action ("indicator.online-accounts", &model, &pos));
+ g_clear_object (&model);
+
+ // check that the header's icon and a11y adjusted to the error state
+ check_header ("", "system-devices-panel-alert", "System (Attention Required)");
+
+ // cleanup
+ g_settings_reset (mock_settings, error_key);
+}
+
+namespace
+{
+ gboolean set_live_session_to_true (gpointer unused G_GNUC_UNUSED)
+ {
+ const char * const live_session_key = "is-live-session";
+ g_settings_set_boolean (mock_settings, live_session_key, true);
+ return G_SOURCE_REMOVE;
+ }
+}
+
+TEST_F (ServiceTest, LiveSession)
+{
+ gboolean b;
+ const char * const live_session_key = "is-live-session";
+
+ // default BackendMock is not a live session
+ ASSERT_FALSE (g_settings_get_boolean (mock_settings, live_session_key));
+ g_object_get (mock_users, INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION, &b, NULL);
+ ASSERT_FALSE (b);
+
+ // confirm that we can see live sessions
+ g_idle_add (set_live_session_to_true, NULL);
+ wait_for_signal (mock_users, "notify::" INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION);
+ ASSERT_TRUE (g_settings_get_boolean (mock_settings, live_session_key));
+ wait_msec (50);
+ g_object_get (mock_users, INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION, &b, NULL);
+ ASSERT_TRUE (b);
+
+ // cleanup
+ g_settings_reset (mock_settings, live_session_key);
+}
+
+
+TEST_F (ServiceTest, User)
+{
+ const char * const error_key = "has-online-account-error";
+ const char * const show_name_key = "show-real-name-on-panel";
+
+ const struct {
+ guint64 login_frequency;
+ const gchar * user_name;
+ const gchar * real_name;
+ } account_info[] = {
+ { 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" }
+ };
+
+ // Find the switcher menu model.
+ // In BackendMock's default setup, it will only two menuitems: greeter & guest
+ int pos = 0;
+ GMenuModel * switch_menu = 0;
+ ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", &switch_menu, &pos));
+ ASSERT_EQ (0, pos);
+ ASSERT_EQ (2, g_menu_model_get_n_items (switch_menu));
+ g_clear_object (&switch_menu);
+
+ // now add some users
+ IndicatorSessionUser * users[12];
+ for (int i=0; i<12; ++i)
+ users[i] = 0;
+ for (int i=0; i<5; ++i)
+ {
+ IndicatorSessionUser * u = g_new0 (IndicatorSessionUser, 1);
+ u->is_current_user = false;
+ u->is_logged_in = false;
+ u->uid = 101 + i;
+ u->login_frequency = account_info[i].login_frequency;
+ u->user_name = g_strdup (account_info[i].user_name);
+ u->real_name = g_strdup (account_info[i].real_name);
+ indicator_session_users_mock_add_user (INDICATOR_SESSION_USERS_MOCK(mock_users), u->user_name, u);
+ users[i] = u;
+ }
+
+ wait_for_menu_resync ();
+
+ // now there should be 7 menuitems: greeter + guest + the five doctors
+ ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", &switch_menu, &pos));
+ ASSERT_EQ (0, pos);
+ ASSERT_EQ (7, g_menu_model_get_n_items (switch_menu));
+ // confirm that the doctor names are sorted
+ check_label ("Fifth Doctor", switch_menu, 2);
+ check_label ("First Doctor", switch_menu, 3);
+ check_label ("Fourth Doctor", switch_menu, 4);
+ check_label ("Second Doctor", switch_menu, 5);
+ check_label ("Third Doctor", switch_menu, 6);
+ g_clear_object (&switch_menu);
+
+ // now remove a couple of 'em
+ indicator_session_users_mock_remove_user (INDICATOR_SESSION_USERS_MOCK(mock_users), account_info[3].user_name);
+ indicator_session_users_mock_remove_user (INDICATOR_SESSION_USERS_MOCK(mock_users), account_info[4].user_name);
+
+ wait_for_menu_resync ();
+
+ // now there should be 5 menuitems: greeter + guest + the three doctors
+ ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", &switch_menu, &pos));
+ ASSERT_EQ (0, pos);
+ ASSERT_EQ (5, g_menu_model_get_n_items (switch_menu));
+ // confirm that the doctor names are sorted
+ check_label ("First Doctor", switch_menu, 2);
+ check_label ("Second Doctor", switch_menu, 3);
+ check_label ("Third Doctor", switch_menu, 4);
+ g_clear_object (&switch_menu);
+
+ // now let's have the third one be the current user
+ users[2]->is_current_user = true;
+ users[2]->is_logged_in = true;
+ indicator_session_users_changed (mock_users, users[2]->user_name);
+
+ wait_for_menu_resync ();
+
+ // now there should be 5 menuitems: greeter + guest + the three doctors
+ ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", &switch_menu, &pos));
+ ASSERT_EQ (0, pos);
+ ASSERT_EQ (5, g_menu_model_get_n_items (switch_menu));
+ g_clear_object (&switch_menu);
+
+ // oh hey, while we've got an active user let's check the header
+ ASSERT_FALSE (g_settings_get_boolean (indicator_settings, show_name_key));
+ ASSERT_FALSE (g_settings_get_boolean (mock_settings, error_key));
+ check_header ("", "system-devices-panel", "System");
+ g_settings_set_boolean (indicator_settings, show_name_key, true);
+ wait_for_signal (action_group, "action-state-changed");
+ check_header ("Third Doctor", "system-devices-panel", "System, Third Doctor");
+ g_settings_set_boolean (mock_settings, error_key, true);
+ wait_for_signal (action_group, "action-state-changed");
+ check_header ("Third Doctor", "system-devices-panel-alert", "System, Third Doctor (Attention Required)");
+ g_settings_reset (mock_settings, error_key);
+ g_settings_reset (indicator_settings, show_name_key);
+ wait_for_menu_resync ();
+
+ // try setting the max user count to 2...
+ // since troughton has the fewest logins, he should get culled
+ g_object_set (service, "max-users", 2, NULL);
+ guint max_users;
+ g_object_get (service, "max-users", &max_users, NULL);
+ ASSERT_EQ (2, max_users);
+ wait_for_menu_resync ();
+ ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", &switch_menu, &pos));
+ ASSERT_EQ (0, pos);
+ ASSERT_EQ (4, g_menu_model_get_n_items (switch_menu));
+ check_label ("First Doctor", switch_menu, 2);
+ check_label ("Third Doctor", switch_menu, 3);
+ g_clear_object (&switch_menu);
+
+ // add some more, test sorting and culling.
+ // add in all the doctors, but only show 7, and make msmith the current session
+ g_object_set (service, "max-users", 7, NULL);
+ g_object_get (service, "max-users", &max_users, NULL);
+ ASSERT_EQ (7, max_users);
+ for (int i=3; i<12; ++i)
+ {
+ IndicatorSessionUser * u = g_new0 (IndicatorSessionUser, 1);
+ u->is_current_user = false;
+ u->is_logged_in = false;
+ u->uid = 101 + i;
+ u->login_frequency = account_info[i].login_frequency;
+ u->user_name = g_strdup (account_info[i].user_name);
+ u->real_name = g_strdup (account_info[i].real_name);
+ indicator_session_users_mock_add_user (INDICATOR_SESSION_USERS_MOCK(mock_users), u->user_name, u);
+ users[i] = u;
+ }
+ users[2]->is_current_user = false;
+ indicator_session_users_changed (mock_users, users[2]->user_name);
+ users[10]->is_current_user = true;
+ users[10]->is_logged_in = true;
+ indicator_session_users_changed (mock_users, users[10]->user_name);
+ wait_for_menu_resync ();
+ ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", &switch_menu, &pos));
+ ASSERT_EQ (0, pos);
+ ASSERT_EQ (9, g_menu_model_get_n_items (switch_menu));
+ check_label ("Eleventh Doctor", switch_menu, 2);
+ check_label ("Fifth Doctor", switch_menu, 3);
+ check_label ("First Doctor", switch_menu, 4);
+ check_label ("Fourth Doctor", switch_menu, 5);
+ check_label ("Second Doctor", switch_menu, 6);
+ check_label ("Tenth Doctor", switch_menu, 7);
+ check_label ("Third Doctor", switch_menu, 8);
+ g_clear_object (&switch_menu);
+
+ // now switch to one of the doctors
+ g_action_group_activate_action (G_ACTION_GROUP(action_group),
+ "switch-to-user",
+ g_variant_new_string("tbaker"));
+ wait_for_signal (mock_settings, "changed::last-command");
+ check_last_command_is ("switch-to-user::tbaker");
}