diff options
author | Charles Kerr <charles.kerr@canonical.com> | 2013-03-22 16:34:34 -0500 |
---|---|---|
committer | Charles Kerr <charles.kerr@canonical.com> | 2013-03-22 16:34:34 -0500 |
commit | ae39f7001e5603010afc02de29787ade6d48ef14 (patch) | |
tree | 74c303a86603134fc2b86d1c428475a60e455e3f /tests | |
parent | e4e327f139dd139a91893fc7f19061a37d4b47e9 (diff) | |
download | ayatana-indicator-session-ae39f7001e5603010afc02de29787ade6d48ef14.tar.gz ayatana-indicator-session-ae39f7001e5603010afc02de29787ade6d48ef14.tar.bz2 ayatana-indicator-session-ae39f7001e5603010afc02de29787ade6d48ef14.zip |
port indicator-session to GMenu/cmake. Code coverage increased from 0% to 95.4%.
Diffstat (limited to 'tests')
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"); } |