/* * * Connection Manager * * Copyright (C) 2011 BMW Car IT GmbH. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 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 warranty of * MERCHANTABILITY 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "session-test.h" #define POLICYDIR STORAGEDIR "/session_policy_local" enum test_session_state { TEST_SESSION_STATE_0 = 0, TEST_SESSION_STATE_1 = 1, TEST_SESSION_STATE_2 = 2, TEST_SESSION_STATE_3 = 3, }; static enum test_session_state get_session_state(struct test_session *session) { return GPOINTER_TO_UINT(session->fix->user_data); } static void set_session_state(struct test_session *session, enum test_session_state state) { session->fix->user_data = GUINT_TO_POINTER(state); } static struct test_session *get_session(struct test_session *session, unsigned int index) { return &session->fix->session[index]; } static void test_session_create_no_notify(struct test_fix *fix) { DBusMessage *msg; util_session_create(fix, 1); msg = manager_create_session(fix->session->connection, fix->session->info, "/foo"); g_assert(msg); g_assert(dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_ERROR); dbus_message_unref(msg); util_idle_call(fix, util_quit_loop, util_session_destroy); } static void test_session_destroy_no_notify(struct test_fix *fix) { DBusMessage *msg; util_session_create(fix, 1); msg = manager_destroy_session(fix->session->connection, "/foo"); g_assert(!msg); util_idle_call(fix, util_quit_loop, util_session_destroy); } static void test_session_create_notify(struct test_session *session) { LOG("session %p", session); util_idle_call(session->fix, util_quit_loop, util_session_destroy); } static void test_session_create(struct test_fix *fix) { struct test_session *session; DBusMessage *msg; int err; util_session_create(fix, 1); session = fix->session; session->notify_path = "/foo"; session->notify = test_session_create_notify; err = session_notify_register(session, session->notify_path); g_assert(err == 0); msg = manager_create_session(session->connection, session->info, session->notify_path); g_assert(msg); g_assert(dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_ERROR); dbus_message_unref(msg); } static void test_session_create_destroy(struct test_fix *fix) { struct test_session *session; util_session_create(fix, 1); session = fix->session; session->notify_path = g_strdup("/foo"); util_session_init(fix->session); util_session_cleanup(fix->session); util_idle_call(fix, util_quit_loop, util_session_destroy); } static void test_session_create_dup_notification(struct test_fix *fix) { struct test_session *session0, *session1; DBusMessage *msg; util_session_create(fix, 2); session0 = &fix->session[0]; session1 = &fix->session[1]; session0->notify_path = g_strdup("/foo"); session1->notify_path = session0->notify_path; util_session_init(session0); msg = manager_create_session(session1->connection, session1->info, session1->notify_path); g_assert(msg); util_session_cleanup(session0); util_idle_call(fix, util_quit_loop, util_session_destroy); } static void test_session_create_many_notify(struct test_session *session) { unsigned int nr; LOG("session %p", session); nr = GPOINTER_TO_UINT(session->fix->user_data); nr--; session->fix->user_data = GUINT_TO_POINTER(nr); if (nr > 0) return; util_idle_call(session->fix, util_quit_loop, util_session_destroy); } static void test_session_create_many(struct test_fix *fix) { struct test_session *session; unsigned int i, max; max = 100; fix->user_data = GUINT_TO_POINTER(max); util_session_create(fix, max); for (i = 0; i < max; i++) { session = &fix->session[i]; session->notify_path = g_strdup_printf("/foo/%d", i); session->notify = test_session_create_many_notify; util_session_init(session); } } static void set_session_mode(struct test_fix *fix, bool enable) { DBusMessage *msg; msg = manager_set_session_mode(fix->main_connection, enable); g_assert(msg); g_assert(dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_ERROR); dbus_message_unref(msg); } static void test_session_connect_notify(struct test_session *session) { LOG("session %p state %d", session, session->info->state); if (session->info->state == CONNMAN_SESSION_STATE_DISCONNECTED) return; util_session_cleanup(session); util_idle_call(session->fix, util_quit_loop, util_session_destroy); } static void test_session_connect(struct test_fix *fix) { struct test_session *session; DBusMessage *msg; util_session_create(fix, 1); session = fix->session; session->notify_path = g_strdup("/foo"); session->notify = test_session_connect_notify; util_session_init(session); msg = session_connect(session->connection, session); g_assert(msg); g_assert(dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_ERROR); dbus_message_unref(msg); } static void test_session_disconnect_notify(struct test_session *session) { LOG("session %p state %d", session, session->info->state); if (session->info->state >= CONNMAN_SESSION_STATE_CONNECTED) return; util_session_cleanup(session); util_idle_call(session->fix, util_quit_loop, util_session_destroy); } static void test_session_disconnect(struct test_fix *fix) { struct test_session *session; DBusMessage *msg; util_session_create(fix, 1); session = fix->session; session->notify_path = g_strdup("/foo"); session->notify = test_session_disconnect_notify; util_session_init(session); msg = session_disconnect(session->connection, session); g_assert(msg); dbus_message_unref(msg); } static void test_session_connect_disconnect_notify(struct test_session *session) { enum test_session_state state = get_session_state(session); enum test_session_state next_state = state; DBusMessage *msg; LOG("state %d session %p %s state %d", state, session, session->notify_path, session->info->state); switch (state) { case TEST_SESSION_STATE_0: if (session->info->state == CONNMAN_SESSION_STATE_DISCONNECTED) next_state = TEST_SESSION_STATE_1; if (session->info->state == CONNMAN_SESSION_STATE_CONNECTED) { LOG("state was already connected, continuing"); next_state = TEST_SESSION_STATE_2; } break; case TEST_SESSION_STATE_1: if (session->info->state >= CONNMAN_SESSION_STATE_CONNECTED) next_state = TEST_SESSION_STATE_2; break; case TEST_SESSION_STATE_2: if (session->info->state == CONNMAN_SESSION_STATE_DISCONNECTED) next_state = TEST_SESSION_STATE_3; default: break; } if (state == next_state) return; set_session_state(session, next_state); LOG("next_state %d", next_state); switch (next_state) { case TEST_SESSION_STATE_1: msg = session_connect(session->connection, session); g_assert(msg); dbus_message_unref(msg); return; case TEST_SESSION_STATE_2: msg = session_disconnect(session->connection, session); g_assert(msg); dbus_message_unref(msg); return; case TEST_SESSION_STATE_3: util_session_cleanup(session); util_idle_call(session->fix, util_quit_loop, util_session_destroy); return; default: return; } } static void test_session_connect_disconnect(struct test_fix *fix) { struct test_session *session; /* * +-------------------+ * | START | * +-------------------+ * | * | connect foo * v * +-------------------+ * | FOO-CONNECTED | * +-------------------+ * | * | disconnect foo * v * +-------------------+ * | END | * +-------------------+ */ util_session_create(fix, 1); session = fix->session; session->notify_path = g_strdup("/foo"); session->notify = test_session_connect_disconnect_notify; util_session_init(session); set_session_state(session, TEST_SESSION_STATE_0); } static void test_session_connect_free_ride_notify(struct test_session *session) { struct test_session *session0 = get_session(session, 0); struct test_session *session1 = get_session(session, 1); enum test_session_state state = get_session_state(session); enum test_session_state next_state = state; DBusMessage *msg; LOG("state %d session %p %s state %d", state, session, session->notify_path, session->info->state); switch (state) { case TEST_SESSION_STATE_0: if (session0->info->state == CONNMAN_SESSION_STATE_DISCONNECTED && session1->info->state == CONNMAN_SESSION_STATE_DISCONNECTED) { next_state = TEST_SESSION_STATE_1; } if (session0->info->state == CONNMAN_SESSION_STATE_CONNECTED && session1->info->state == CONNMAN_SESSION_STATE_CONNECTED) { LOG("state was already connected, continuing"); next_state = TEST_SESSION_STATE_2; } break; case TEST_SESSION_STATE_1: if (session0->info->state >= CONNMAN_SESSION_STATE_CONNECTED && session1->info->state >= CONNMAN_SESSION_STATE_CONNECTED) { next_state = TEST_SESSION_STATE_2; } break; case TEST_SESSION_STATE_2: if (session0->info->state == CONNMAN_SESSION_STATE_DISCONNECTED && (session1->info->state == CONNMAN_SESSION_STATE_DISCONNECTED || session1->info->state == CONNMAN_SESSION_STATE_CONNECTED) ) { LOG("session0 /foo is disconnected, session1 /bar " "can be either connected or disconnected"); next_state = TEST_SESSION_STATE_3; } break; case TEST_SESSION_STATE_3: return; } if (state == next_state) return; set_session_state(session, next_state); LOG("next_state %d", next_state); switch (next_state) { case TEST_SESSION_STATE_0: return; case TEST_SESSION_STATE_1: msg = session_connect(session0->connection, session0); g_assert(msg); dbus_message_unref(msg); return; case TEST_SESSION_STATE_2: msg = session_disconnect(session0->connection, session0); g_assert(msg); dbus_message_unref(msg); return; case TEST_SESSION_STATE_3: util_session_cleanup(session0); util_session_cleanup(session1); util_idle_call(session0->fix, util_quit_loop, util_session_destroy); return; } } static void test_session_connect_free_ride(struct test_fix *fix) { struct test_session *session0, *session1; /* * +-------------------+ * | START | * +-------------------+ * | * | connect foo * v * +-------------------+ * | FOO-CONNECTED | * +-------------------+ * | * | free-ride bar * v * +-------------------+ * | FOO-BAR-CONNECTED | * +-------------------+ * | * | disconnect foo * v * +-------------------+ * | END | * +-------------------+ */ util_session_create(fix, 2); session0 = &fix->session[0]; session1 = &fix->session[1]; session0->notify_path = g_strdup("/foo"); session1->notify_path = g_strdup("/bar"); session0->notify = test_session_connect_free_ride_notify; session1->notify = test_session_connect_free_ride_notify; util_session_init(session0); util_session_init(session1); set_session_state(session0, TEST_SESSION_STATE_0); } static void policy_save(GKeyFile *keyfile, char *pathname) { gchar *data = NULL; gsize length = 0; GError *error = NULL; data = g_key_file_to_data(keyfile, &length, NULL); if (!g_file_set_contents(pathname, data, length, &error)) { DBG("Failed to store information: %s", error->message); g_error_free(error); g_assert(0); } g_free(data); } static void policy_allowed_bearers(const char *allowed_bearers) { struct passwd *pwd; uid_t uid; char *pathname; GKeyFile *keyfile; LOG("update to '%s'", allowed_bearers); uid = getuid(); pwd = getpwuid(uid); g_assert(pwd); keyfile = g_key_file_new(); g_key_file_set_string(keyfile, "policy_foo", "uid", pwd->pw_name); g_key_file_set_string(keyfile, "policy_foo", "AllowedBearers", allowed_bearers); pathname = g_strdup_printf("%s/foo.policy", POLICYDIR); policy_save(keyfile, pathname); g_free(pathname); g_key_file_free(keyfile); } static void policy_remove_file(void) { char *pathname; pathname = g_strdup_printf("%s/foo.policy", POLICYDIR); unlink(pathname); g_free(pathname); } static void test_session_policy_notify(struct test_session *session) { enum test_session_state state = get_session_state(session); enum test_session_state next_state = state; DBusMessage *msg; LOG("state %d session %p %s state %d", state, session, session->notify_path, session->info->state); switch (state) { case TEST_SESSION_STATE_0: if (session->info->state == CONNMAN_SESSION_STATE_DISCONNECTED) next_state = TEST_SESSION_STATE_1; break; case TEST_SESSION_STATE_1: if (session->info->state >= CONNMAN_SESSION_STATE_CONNECTED) next_state = TEST_SESSION_STATE_2; break; case TEST_SESSION_STATE_2: if (session->info->state == CONNMAN_SESSION_STATE_DISCONNECTED) next_state = TEST_SESSION_STATE_3; default: break; } if (state == next_state) return; set_session_state(session, next_state); LOG("next_state %d", next_state); switch (next_state) { case TEST_SESSION_STATE_1: policy_allowed_bearers("ethernet"); msg = session_connect(session->connection, session); g_assert(msg); dbus_message_unref(msg); return; case TEST_SESSION_STATE_2: policy_allowed_bearers(""); return; case TEST_SESSION_STATE_3: policy_remove_file(); util_session_cleanup(session); util_idle_call(session->fix, util_quit_loop, util_session_destroy); return; default: return; } } static void test_session_policy(struct test_fix *fix) { struct test_session *session; /* * +-------------------+ * | START | * +-------------------+ * | * | write policy AllowedBearers = ethernet * v * +-------------------+ * | FOO-CONNECTED | * +-------------------+ * | * | write policy AllowedBearers = * v * +-------------------+ * | END | * +-------------------+ */ policy_remove_file(); util_session_create(fix, 1); session = fix->session; session->notify_path = g_strdup("/foo"); session->notify = test_session_policy_notify; util_session_init(session); set_session_state(session, TEST_SESSION_STATE_0); } static bool is_online(struct test_fix *fix) { if (g_strcmp0(fix->manager.state, "online") == 0) return true; return false; } static void enable_session_mode(struct test_fix *fix) { set_session_mode(fix, true); if (!is_online(fix)) util_idle_call(fix, util_quit_loop, NULL); } static void manager_state_changed(struct test_fix *fix) { if (!is_online(fix)) { fix->manager_changed = NULL; util_idle_call(fix, util_quit_loop, NULL); } } static void disable_session_mode(struct test_fix *fix) { set_session_mode(fix, false); } static void setup_cb(struct test_fix *fix) { fix->manager_changed = manager_state_changed; util_call(fix, enable_session_mode, NULL); } static void teardown_cb(struct test_fix *fix) { util_call(fix, disable_session_mode, NULL); util_idle_call(fix, util_quit_loop, NULL); } int main(int argc, char *argv[]) { g_test_init(&argc, &argv, NULL); util_test_add("/manager/session create no notify", test_session_create_no_notify, setup_cb, teardown_cb); util_test_add("/manager/session destroy no notify", test_session_destroy_no_notify, setup_cb, teardown_cb); util_test_add("/manager/session create", test_session_create, setup_cb, teardown_cb); util_test_add("/manager/session create destroy", test_session_create_destroy, setup_cb, teardown_cb); util_test_add("/manager/session create duplicate notification", test_session_create_dup_notification, setup_cb, teardown_cb); util_test_add("/manager/session create many", test_session_create_many, setup_cb, teardown_cb); util_test_add("/session/connect", test_session_connect, setup_cb, teardown_cb); util_test_add("/session/disconnect", test_session_disconnect, setup_cb, teardown_cb); util_test_add("/session/connect disconnect", test_session_connect_disconnect, setup_cb, teardown_cb); util_test_add("/session/connect free-ride", test_session_connect_free_ride, setup_cb, teardown_cb); util_test_add("/session/policy", test_session_policy, setup_cb, teardown_cb); return g_test_run(); }