/* A very basic feature test for TpAccountManager
*
* Copyright (C) 2009 Collabora Ltd.
* Copyright (C) 2009 Nokia Corporation
*
* Copying and distribution of this file, with or without modification,
* are permitted in any medium without royalty provided the copyright
* notice and this notice are preserved.
*/
#include
#include
#include
#include "tests/lib/simple-account-manager.h"
#include "tests/lib/util.h"
typedef struct {
GFunc action;
gpointer user_data;
} ScriptAction;
typedef struct {
GMainLoop *mainloop;
TpDBusDaemon *dbus;
TpTestsSimpleAccountManager *service /* initialized in prepare_service */;
TpAccountManager *am;
TpAccount *account;
gboolean prepared /* The result of prepare_finish */;
guint timeout_id;
GQueue *script /* A list of GAsyncReadyCallback */;
GError *error /* initialized where needed */;
} Test;
/**
* Functions for manipulating scripts follow this comment.
* In order to be generally useful, the script should probably be stored in its
* own data structure, rather than passed around with the test, and the
* user_data argument would need to be the test or something. As it is, these
* library-like functions rely on being defined after the Test struct.
*/
static ScriptAction *
script_action_new (GFunc action,
gpointer data)
{
ScriptAction *script_action = g_new (ScriptAction, 1);
script_action->action = action;
script_action->user_data = data;
return script_action;
}
static void
script_action_free (ScriptAction *action)
{
g_free (action);
}
/**
* If data is passed in, you are responsible for freeing it. This will not be
* done for you.
*/
static void
script_append_action (Test *test,
GFunc action,
gpointer data)
{
g_queue_push_tail (test->script, script_action_new (action, data));
}
static void
script_continue (gpointer script_data)
{
Test *test = (Test *) script_data;
ScriptAction *action;
/* pop the next action */
action = (ScriptAction *) g_queue_pop_head (test->script);
action->action (script_data, action->user_data);
script_action_free (action);
}
static gboolean
test_timed_out (gpointer data)
{
Test *test = (Test *) data;
g_assert_not_reached ();
test->prepared = FALSE;
/* Note that this is a completely bogus error, but it only gets returned if
* you comment out the g_assert_not_reached() above. */
test->error = g_error_new_literal (TP_ERRORS, TP_DBUS_ERROR_INCONSISTENT,
"timeout");
g_print ("about to quit");
g_main_loop_quit (test->mainloop);
g_print ("just quit");
return FALSE;
}
static void
quit_action (gpointer script_data,
gpointer user_data G_GNUC_UNUSED)
{
Test *test = (Test *) script_data;
g_main_loop_quit (test->mainloop);
}
static void
script_start_with_deadline (Test *test,
guint timeout)
{
script_append_action (test, quit_action, NULL);
test->timeout_id = g_timeout_add (timeout, test_timed_out, test);
script_continue (test);
g_main_loop_run (test->mainloop);
}
/**
* Setup and teardown functions follow this comment.
*/
static void
setup (Test *test,
gconstpointer data)
{
g_type_init ();
tp_debug_set_flags ("all");
test->mainloop = g_main_loop_new (NULL, FALSE);
test->dbus = tp_tests_dbus_daemon_dup_or_die ();
test->am = NULL;
test->timeout_id = 0;
test->script = g_queue_new ();
}
static void
setup_service (Test *test,
gconstpointer data)
{
setup (test, data);
g_assert (tp_dbus_daemon_request_name (test->dbus,
TP_ACCOUNT_MANAGER_BUS_NAME, FALSE, &test->error));
test->service = tp_tests_object_new_static_class (
TP_TESTS_TYPE_SIMPLE_ACCOUNT_MANAGER, NULL);
tp_dbus_daemon_register_object (test->dbus, TP_ACCOUNT_MANAGER_OBJECT_PATH,
test->service);
}
static void
teardown (Test *test,
gconstpointer data)
{
if (test->am != NULL)
{
g_object_unref (test->am);
test->am = NULL;
}
if (test->timeout_id != 0)
{
g_source_remove (test->timeout_id);
test->timeout_id = 0;
}
g_queue_free (test->script);
test->script = NULL;
/* make sure any pending things have happened */
tp_tests_proxy_run_until_dbus_queue_processed (test->dbus);
g_object_unref (test->dbus);
test->dbus = NULL;
g_main_loop_unref (test->mainloop);
test->mainloop = NULL;
}
static void
teardown_service (Test *test,
gconstpointer data)
{
script_start_with_deadline (test, 1000);
g_assert (
tp_dbus_daemon_release_name (test->dbus, TP_ACCOUNT_MANAGER_BUS_NAME,
&test->error));
tp_dbus_daemon_unregister_object (test->dbus, test->service);
g_object_unref (test->service);
test->service = NULL;
teardown (test, data);
}
/**
* Non-dbus tests follow this comment
*/
static void
test_new (Test *test,
gconstpointer data G_GNUC_UNUSED)
{
test->am = tp_account_manager_new (test->dbus);
}
static void
test_dup (Test *test,
gconstpointer data G_GNUC_UNUSED)
{
TpAccountManager *one, *two;
TpDBusDaemon *dbus_one, *dbus_two;
one = tp_account_manager_dup ();
two = tp_account_manager_dup ();
g_assert (one == two);
dbus_one = tp_dbus_daemon_dup (NULL);
dbus_two = tp_proxy_get_dbus_daemon (one);
g_assert (dbus_one == dbus_two);
g_object_unref (dbus_one);
g_object_unref (two);
g_object_unref (one);
}
/**
* Actions for use with script_append_action() follow this comment. They are
* used in tests which involve asyncronous actions.
*/
static void
noop_action (gpointer script_data,
gpointer user_data G_GNUC_UNUSED)
{
script_continue (script_data);
}
static void
finish_prepare_action (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
Test *test = (Test *) user_data;
gboolean is_prepared_reply;
TpAccountManager *am = TP_ACCOUNT_MANAGER (source_object);
g_assert (test->am == am);
test->prepared = tp_account_manager_prepare_finish (am, res, &test->error);
is_prepared_reply = tp_account_manager_is_prepared (test->am,
TP_ACCOUNT_MANAGER_FEATURE_CORE);
g_assert_cmpint (is_prepared_reply, ==, test->prepared);
script_continue (test);
}
static void
prepare_action (gpointer script_data,
gpointer user_data G_GNUC_UNUSED)
{
Test *test = (Test *) script_data;
tp_account_manager_prepare_async (test->am, NULL, finish_prepare_action, test);
}
static void
manager_new_action (gpointer script_data,
gpointer user_data G_GNUC_UNUSED)
{
Test *test = (Test *) script_data;
test->am = tp_account_manager_new (test->dbus);
script_continue (test);
}
/* We really don't want to have MC being launched during this test */
static void
finish_assert_am_not_activatable_action (TpDBusDaemon *proxy,
const gchar * const *names,
const GError *error,
gpointer user_data,
GObject *weak_object)
{
guint i;
g_assert (error == NULL);
for (i=0; names[i] != NULL; i++)
{
g_assert_cmpstr (names[i], !=, TP_ACCOUNT_MANAGER_BUS_NAME);
g_assert_cmpstr (names[i], !=, "org.freedesktop.Telepathy.MissionControl5");
}
script_continue (user_data);
}
static void
assert_am_not_activatable_action (gpointer script_data,
gpointer user_data)
{
Test *test = (Test *) script_data;
tp_dbus_daemon_list_activatable_names (test->dbus, 500,
finish_assert_am_not_activatable_action, test, NULL, NULL);
}
static void
assert_core_not_ready_action (gpointer script_data,
gpointer user_data G_GNUC_UNUSED)
{
Test *test = (Test *) script_data;
g_assert (!tp_account_manager_is_prepared (test->am,
TP_ACCOUNT_MANAGER_FEATURE_CORE));
script_continue (script_data);
}
static void
assert_feature_not_ready_action (gpointer script_data,
gpointer user_data)
{
Test *test = (Test *) script_data;
g_assert (!tp_account_manager_is_prepared (test->am,
g_quark_from_string ((gchar *) user_data)));
g_free (user_data);
script_continue (script_data);
}
static void
prepare_feature_action (gpointer script_data,
gpointer user_data)
{
Test *test = (Test *) script_data;
GQuark features[3];
features[0] = TP_ACCOUNT_MANAGER_FEATURE_CORE;
features[1] = g_quark_from_string ((gchar *) user_data);
features[2] = 0;
tp_account_manager_prepare_async (test->am, features, finish_prepare_action, test);
g_free (user_data);
}
static void
assert_ok_action (gpointer script_data,
gpointer user_data G_GNUC_UNUSED)
{
Test *test = (Test *) script_data;
g_assert_no_error (test->error);
g_assert (test->prepared);
script_continue (script_data);
}
static void
assert_failed_action (gpointer script_data,
gpointer user_data G_GNUC_UNUSED)
{
Test *test = (Test *) script_data;
g_assert (test->error != NULL);
g_error_free (test->error);
test->error = NULL;
script_continue (script_data);
}
/**
* account related functions below this comment
*/
static void
ensure_action (gpointer script_data,
gpointer user_data)
{
char *path = (char *) user_data;
Test *test = (Test *) script_data;
g_assert (test != NULL);
g_assert (test->am != NULL);
g_assert (tp_account_manager_is_prepared (test->am, TP_ACCOUNT_MANAGER_FEATURE_CORE));
test->account = tp_account_manager_ensure_account (test->am,
path);
script_continue (script_data);
}
static void
assert_account_ok_action (gpointer script_data,
gpointer user_data G_GNUC_UNUSED)
{
Test *test = (Test *) script_data;
g_assert (test->account != NULL);
script_continue (script_data);
}
static void
finish_account_prepare_action (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
Test *test = (Test *) user_data;
TpAccount *account = TP_ACCOUNT (source_object);
g_assert (test->account == account);
test->prepared = tp_account_prepare_finish (account, res, &test->error);
g_assert (test->prepared == tp_account_is_prepared (account, TP_ACCOUNT_FEATURE_CORE));
script_continue (test);
}
static void
account_prepare_action (gpointer script_data,
gpointer user_data G_GNUC_UNUSED)
{
Test *test = (Test *) script_data;
tp_account_prepare_async (test->account, NULL, finish_account_prepare_action, test);
}
static void
register_service_action (gpointer script_data,
gpointer user_data G_GNUC_UNUSED)
{
Test *test = (Test *) script_data;
tp_dbus_daemon_register_object (test->dbus, TP_ACCOUNT_MANAGER_OBJECT_PATH,
test->service);
script_continue (test);
}
/**
* Asyncronous tests below this comment. Tests append action functions and
* arguments to a script. Once the test function has returned, the teardown
* function is responsible for running the script, and quitting the mainloop
* afterwards.
* Action functions are each responsible for ensuring that the next action is
* called.
*/
static void
test_prepare (Test *test,
gconstpointer data G_GNUC_UNUSED)
{
script_append_action (test, assert_am_not_activatable_action, NULL);
script_append_action (test, manager_new_action, NULL);
script_append_action (test, assert_core_not_ready_action, NULL);
script_append_action (test, prepare_action, NULL);
script_append_action (test, noop_action, NULL);
}
/**
* Tests the usual case where prepare succeeds.
*/
static void
test_prepare_success (Test *test,
gconstpointer data G_GNUC_UNUSED)
{
test_prepare (test, data);
script_append_action (test, assert_ok_action, NULL);
}
/**
* Tests the case where the well-known name is not provided.
* This should be run with setup rather than setup_service to make this the case.
* TODO: use g_assert_error (err, dom, c) to fix the domain and code.
*/
static void
test_prepare_no_name (Test *test,
gconstpointer data G_GNUC_UNUSED)
{
test_prepare (test, data);
script_append_action (test, assert_failed_action, NULL);
/* Since we are using teardown rather than teardown_service, we need to
* run the script ourselves */
script_start_with_deadline (test, 1000);
}
/**
* Tests the case where the object has been destroyed.
* TODO: use g_assert_error (err, dom, c) to fix the domain and code.
*/
static void
test_prepare_destroyed (Test *test,
gconstpointer data G_GNUC_UNUSED)
{
tp_dbus_daemon_unregister_object (test->dbus, test->service);
test_prepare (test, data);
script_append_action (test, assert_failed_action, NULL);
script_append_action (test, register_service_action, NULL);
}
/**
* Calling prepare with unknown features should succeed, but is_prepared()
* on an unknown feature should return FALSE.
*/
static void
test_prepare_unknown_features (Test *test,
gconstpointer data G_GNUC_UNUSED)
{
test_prepare_success (test, data);
script_append_action (test, prepare_feature_action, g_strdup ("fake-feature"));
script_append_action (test, assert_ok_action, NULL);
script_append_action (test, assert_feature_not_ready_action, g_strdup ("fake-feature"));
}
static void
test_ensure (Test *test,
gconstpointer data G_GNUC_UNUSED)
{
test_prepare (test, data);
script_append_action (test, assert_ok_action, NULL);
script_append_action (test, ensure_action,
TP_ACCOUNT_OBJECT_PATH_BASE "fakecm/fakeproto/account");
script_append_action (test, assert_account_ok_action, NULL);
script_append_action (test, account_prepare_action, NULL);
script_append_action (test, assert_failed_action, NULL);
}
int
main (int argc,
char **argv)
{
g_test_init (&argc, &argv, NULL);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add ("/am/new", Test, NULL, setup, test_new, teardown);
g_test_add ("/am/dup", Test, NULL, setup, test_dup, teardown);
g_test_add ("/am/prepare/success", Test, NULL, setup_service,
test_prepare_success, teardown_service);
g_test_add ("/am/prepare/destroyed", Test, NULL, setup_service,
test_prepare_destroyed, teardown_service);
/* WARNING: This test is run using setup/teardown rather than setup_service*/
g_test_add ("/am/prepare/name-not-provided", Test, NULL, setup,
test_prepare_no_name, teardown);
g_test_add ("/am/prepare/unknown_features", Test, NULL, setup_service,
test_prepare_unknown_features, teardown_service);
g_test_add ("/am/ensure", Test, NULL, setup_service,
test_ensure, teardown_service);
return g_test_run ();
}