aboutsummaryrefslogtreecommitdiff
path: root/tests/backend-dbus/test-users.cc
diff options
context:
space:
mode:
Diffstat (limited to 'tests/backend-dbus/test-users.cc')
-rw-r--r--tests/backend-dbus/test-users.cc381
1 files changed, 381 insertions, 0 deletions
diff --git a/tests/backend-dbus/test-users.cc b/tests/backend-dbus/test-users.cc
new file mode 100644
index 0000000..dccacbb
--- /dev/null
+++ b/tests/backend-dbus/test-users.cc
@@ -0,0 +1,381 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gtest-mock-dbus-fixture.h"
+
+#include "backend.h"
+#include "backend-dbus/backend-dbus.h"
+
+/***
+****
+***/
+
+class Users: public GTestMockDBusFixture
+{
+ private:
+
+ typedef GTestMockDBusFixture super;
+
+ protected:
+
+ GCancellable * cancellable;
+ IndicatorSessionUsers * users;
+
+ virtual void SetUp ()
+ {
+ super :: SetUp ();
+
+ init_event_keys (0);
+
+ // init 'users'
+ cancellable = g_cancellable_new ();
+ users = 0;
+ backend_get (cancellable, NULL, &users, NULL);
+ g_assert (users != 0);
+
+ // wait for the users added by GTestMockDBusFixture::SetUp() to show up
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_ADDED, 12);
+ init_event_keys (0);
+ }
+
+ virtual void TearDown ()
+ {
+ g_cancellable_cancel (cancellable);
+ g_clear_object (&cancellable);
+ g_clear_object (&users);
+
+ super :: TearDown ();
+ }
+
+ protected:
+
+ void compare_user (const MockUser * mu, const IndicatorSessionUser * isu, const std::string& user_state)
+ {
+ ASSERT_EQ (user_state, login1_seat->user_state (mu->uid()));
+ ASSERT_EQ (mu->uid(), isu->uid);
+ ASSERT_EQ (mu->login_frequency(), isu->login_frequency);
+ ASSERT_STREQ (mu->username(), isu->user_name);
+ ASSERT_STREQ (mu->realname(), isu->real_name);
+ ASSERT_EQ (mu->uid(), isu->uid);
+ ASSERT_EQ (user_state!="offline", isu->is_logged_in);
+ ASSERT_EQ (user_state=="active", isu->is_current_user);
+ }
+
+ void compare_user (const MockUser * mu, guint uid, const std::string& user_state)
+ {
+ IndicatorSessionUser * isu;
+ isu = indicator_session_users_get_user (users, uid);
+ compare_user (mu, isu, user_state);
+ indicator_session_user_free (isu);
+ }
+
+ void compare_user (guint uid, const std::string& user_state)
+ {
+ IndicatorSessionUser * isu = indicator_session_users_get_user (users, uid);
+ MockUser * mu = accounts->find_by_uid (uid);
+ compare_user (mu, isu, user_state);
+ indicator_session_user_free (isu);
+ }
+
+ private:
+
+ void init_event_keys (size_t n)
+ {
+ expected_event_count = n;
+ event_keys.clear();
+ }
+
+ static gboolean
+ wait_for_signals__timeout (gpointer name)
+ {
+ g_error ("%s: timed out waiting for signal '%s'", G_STRLOC, (char*)name);
+ return G_SOURCE_REMOVE;
+ }
+
+ static void
+ wait_for_signals__event (IndicatorSessionUser * u G_GNUC_UNUSED,
+ guint uid,
+ gpointer gself)
+ {
+ Users * self = static_cast<Users*>(gself);
+
+ self->event_keys.push_back (uid);
+
+ if (self->event_keys.size() == self->expected_event_count)
+ g_main_loop_quit (self->loop);
+ }
+
+ protected:
+
+ std::vector<guint> event_keys;
+ size_t expected_event_count;
+
+ void wait_for_signals (gpointer o, const gchar * name, size_t n)
+ {
+ const int timeout_seconds = 5; // arbitrary
+
+ init_event_keys (n);
+
+ guint handler_id = g_signal_connect (o, name,
+ G_CALLBACK(wait_for_signals__event),
+ this);
+ gulong timeout_id = g_timeout_add_seconds (timeout_seconds,
+ wait_for_signals__timeout,
+ (gpointer)name);
+ g_main_loop_run (loop);
+ g_source_remove (timeout_id);
+ g_signal_handler_disconnect (o, handler_id);
+ }
+};
+
+/***
+****
+***/
+
+/**
+ * Confirm that the fixture's SetUp() and TearDown() work
+ */
+TEST_F (Users, HelloWorld)
+{
+ ASSERT_TRUE (true);
+}
+
+/**
+ * Confirm that 'users' can get the cached users from our Mock Accounts
+ */
+TEST_F (Users, InitialUsers)
+{
+ GList * l;
+ GList * uids = indicator_session_users_get_uids (users);
+
+ ASSERT_EQ (12, g_list_length (uids));
+
+ for (l=uids; l!=NULL; l=l->next)
+ {
+ const guint uid = GPOINTER_TO_UINT (l->data);
+ compare_user (uid, login1_seat->user_state (uid));
+ }
+
+ g_list_free (uids);
+}
+
+/**
+ * Confirm that 'users' can tell when a new user is added
+ */
+TEST_F (Users, UserAdded)
+{
+ MockUser * mu;
+
+ mu = new MockUser (loop, conn, "pcushing", "Peter Cushing", 2);
+ accounts->add_user (mu);
+ ASSERT_EQ (0, event_keys.size());
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_ADDED, 1);
+ ASSERT_EQ (1, event_keys.size());
+ compare_user (mu, event_keys[0], "offline");
+}
+
+/**
+ * Confirm that 'users' can tell when a user is removed
+ */
+TEST_F (Users, UserRemoved)
+{
+ MockUser * mu = accounts->find_by_username ("pdavison");
+
+ /* confirm that users knows about pdavison */
+ IndicatorSessionUser * isu = indicator_session_users_get_user (users, mu->uid());
+ ASSERT_TRUE (isu != NULL);
+ compare_user (mu, isu, "offline");
+ g_clear_pointer (&isu, indicator_session_user_free);
+
+ /* on the bus, remove pdavison. */
+ accounts->remove_user (mu);
+
+ /* now, users should emit a 'user removed' signal... */
+ ASSERT_EQ (0, event_keys.size());
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_REMOVED, 1);
+ ASSERT_EQ (1, event_keys.size());
+
+ /* confirm that users won't give us pdavison's info */
+ isu = indicator_session_users_get_user (users, mu->uid());
+ ASSERT_TRUE (isu == NULL);
+
+ /* confirm that users won't give us pdavison's uid */
+ GList * uids = indicator_session_users_get_uids (users);
+ ASSERT_TRUE (g_list_find (uids, GUINT_TO_POINTER(mu->uid())) == NULL);
+ g_list_free (uids);
+
+ delete mu;
+}
+
+/**
+ * Confirm that 'users' notices when a user's real name changes
+ */
+TEST_F (Users, RealnameChanged)
+{
+ MockUser * mu;
+
+ mu = accounts->find_by_username ("pdavison");
+ const char * const realname = "Peter M. G. Moffett";
+ mu->set_realname (realname);
+ ASSERT_NE (mu->realname(), realname);
+ ASSERT_STREQ (mu->realname(), realname);
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1);
+ ASSERT_EQ (1, event_keys.size());
+ compare_user (mu, event_keys[0], "offline");
+}
+
+/**
+ * Confirm that 'users' notices when users log in and out
+ */
+TEST_F (Users, LogInLogOut)
+{
+ // The fist doctor logs in.
+ // Confirm that 'users' notices.
+ MockUser * mu = accounts->find_by_username ("whartnell");
+ ASSERT_EQ (login1_seat->user_state (mu->uid()), "offline");
+ const int session_tag = login1_manager->add_session (login1_seat, mu);
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1);
+ ASSERT_EQ (1, event_keys.size());
+ compare_user (mu, event_keys[0], "online");
+
+ // The first doctor logs out.
+ // Confirm that 'users' notices.
+ login1_manager->remove_session (login1_seat, session_tag);
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1);
+ ASSERT_EQ (1, event_keys.size());
+ compare_user (mu, event_keys[0], "offline");
+}
+
+/**
+ * Confirm that 'users' notices when the active session changes
+ */
+TEST_F (Users, ActivateSession)
+{
+ // confirm preconditions: msmith is active, msmith is offline
+ MockUser * const whartnell = accounts->find_by_username ("whartnell");
+ ASSERT_EQ (login1_seat->user_state (whartnell->uid()), "offline");
+ MockUser * const msmith = accounts->find_by_username ("msmith");
+ ASSERT_EQ (login1_seat->user_state (msmith->uid()), "active");
+
+ // whartnell logs in... confirm that 'users' notices
+ login1_manager->add_session (login1_seat, whartnell);
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1);
+ ASSERT_EQ (1, event_keys.size());
+ compare_user (whartnell, event_keys[0], "online");
+
+ // activate whartnell's session... confirm that 'users' sees:
+ // 1. msmith changes from 'active' to 'online'
+ // 2. whartnell changes from 'online' to 'active'
+ login1_seat->switch_to_user (whartnell->username());
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 2);
+ ASSERT_EQ (2, event_keys.size());
+ compare_user (msmith, event_keys[0], "online");
+ compare_user (whartnell, event_keys[1], "active");
+
+ // reverse the test
+ login1_seat->switch_to_user (msmith->username());
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 2);
+ ASSERT_EQ (2, event_keys.size());
+ compare_user (whartnell, event_keys[0], "online");
+ compare_user (msmith, event_keys[1], "active");
+}
+
+/**
+ * Confirm that we can change the active session via users' API.
+ * This is nearly the same as ActivateSession but uses users' API
+ */
+TEST_F (Users, ActivateUser)
+{
+ // confirm preconditions: msmith is active, msmith is offline
+ MockUser * const whartnell = accounts->find_by_username ("whartnell");
+ ASSERT_EQ (login1_seat->user_state (whartnell->uid()), "offline");
+ MockUser * const msmith = accounts->find_by_username ("msmith");
+ ASSERT_EQ (login1_seat->user_state (msmith->uid()), "active");
+
+ // whartnell logs in... confirm that 'users' notices
+ login1_manager->add_session (login1_seat, whartnell);
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1);
+ ASSERT_EQ (1, event_keys.size());
+ compare_user (whartnell, event_keys[0], "online");
+
+ // activate whartnell's session... confirm that 'users' sees:
+ // 1. msmith changes from 'active' to 'online'
+ // 2. whartnell changes from 'online' to 'active'
+ indicator_session_users_activate_user (users, whartnell->uid());
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 2);
+ ASSERT_EQ (2, event_keys.size());
+ compare_user (msmith, event_keys[0], "online");
+ compare_user (whartnell, event_keys[1], "active");
+
+ // reverse the test
+ indicator_session_users_activate_user (users, msmith->uid());
+ wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 2);
+ ASSERT_EQ (2, event_keys.size());
+ compare_user (whartnell, event_keys[0], "online");
+ compare_user (msmith, event_keys[1], "active");
+}
+
+/**
+ * Confirm that adding a Guest doesn't show up in the users list
+ */
+TEST_F (Users, UnwantedGuest)
+{
+ GList * uids;
+
+ uids = indicator_session_users_get_uids (users);
+ const size_t n = g_list_length (uids);
+ g_list_free (uids);
+
+ MockUser * mu = new MockUser (loop, conn, "guest-jjbEVV", "Guest", 1);
+ mu->set_system_account (true);
+ accounts->add_user (mu);
+ wait_msec (50);
+
+ uids = indicator_session_users_get_uids (users);
+ ASSERT_EQ (n, g_list_length (uids));
+ g_list_free (uids);
+}
+
+
+/**
+ * Confirm that we can detect live sessions
+ */
+TEST_F (Users, LiveSession)
+{
+ gboolean b;
+
+ // not initially a live session
+ ASSERT_FALSE (indicator_session_users_is_live_session (users));
+ g_object_get (users, INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION, &b, NULL);
+ ASSERT_FALSE (b);
+
+ // now add the criteria for a live session
+ MockUser * live_user = new MockUser (loop, conn, "ubuntu", "Ubuntu", 1, 999);
+ live_user->set_system_account (true);
+ accounts->add_user (live_user);
+ const int session_tag = login1_manager->add_session (login1_seat, live_user);
+ wait_msec (100);
+ login1_seat->activate_session (session_tag);
+ wait_for_signal (users, "notify::" INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION);
+
+ // confirm the backend thinks it's a live session
+ ASSERT_TRUE (indicator_session_users_is_live_session (users));
+ g_object_get (users, INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION, &b, NULL);
+ ASSERT_TRUE (b);
+}