aboutsummaryrefslogtreecommitdiff
path: root/tools/tests/test-stub.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/tests/test-stub.c')
-rw-r--r--tools/tests/test-stub.c459
1 files changed, 459 insertions, 0 deletions
diff --git a/tools/tests/test-stub.c b/tools/tests/test-stub.c
new file mode 100644
index 00000000..5687feca
--- /dev/null
+++ b/tools/tests/test-stub.c
@@ -0,0 +1,459 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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:
+ *
+ * Copyright (C) 2020 Frederic Martinsons <frederic.martinsons@sigfox.com>
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <libmm-glib.h>
+#include <ModemManager-names.h>
+#define MM_LOG_NO_OBJECT
+#include <mm-log-test.h>
+
+#define MM_TEST_IFACE_NAME "org.freedesktop.ModemManager1.LibmmGlibTest"
+
+typedef struct {
+ GMainLoop *loop;
+ MMManager *mm_manager;
+ GDBusConnection *gdbus_connection;
+ GDBusProxy *mm_proxy;
+ GDBusProxy *mm_modem_prop_proxy;
+ GTestDBus *test_bus;
+ gchar *modem_object_path;
+ guint timeout_id;
+ MMSim *sim;
+ gboolean pin_error;
+} TestData;
+
+static void
+setup (TestData **ptdata,
+ gconstpointer data)
+{
+ GError *error = NULL;
+ TestData *tdata = NULL;
+
+ tdata = (TestData *)g_malloc0 (sizeof(TestData));
+ *ptdata = tdata;
+
+ tdata->loop = g_main_loop_new (NULL, FALSE);
+ g_assert_nonnull (tdata->loop);
+
+ tdata->test_bus = g_test_dbus_new (G_TEST_DBUS_NONE);
+ g_assert_nonnull (tdata->test_bus);
+
+ g_test_dbus_add_service_dir (tdata->test_bus, TEST_SERVICES);
+ g_test_dbus_up (tdata->test_bus);
+
+ /* Grab a proxy to the fake NM service to trigger tests */
+ tdata->mm_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
+ NULL,
+ MM_DBUS_SERVICE,
+ MM_DBUS_PATH,
+ MM_TEST_IFACE_NAME,
+ NULL, &error);
+ g_assert_no_error (error);
+
+ tdata->gdbus_connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+ g_assert_no_error (error);
+
+ tdata->mm_manager = mm_manager_new_sync (tdata->gdbus_connection,
+ G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+ NULL,
+ &error);
+ g_assert_no_error (error);
+ g_assert_nonnull (tdata->mm_manager);
+}
+
+static void
+teardown (TestData **ptdata,
+ gconstpointer data)
+{
+ TestData *tdata = NULL;
+
+ tdata = *ptdata;
+ g_clear_object (&tdata->mm_modem_prop_proxy);
+ g_clear_object (&tdata->mm_proxy);
+ g_clear_object (&tdata->mm_manager);
+ g_clear_object (&tdata->gdbus_connection);
+ g_test_dbus_down (tdata->test_bus);
+ g_clear_object (&tdata->test_bus);
+ g_main_loop_unref (tdata->loop);
+ g_free (tdata);
+}
+
+static gboolean
+loop_timeout_cb (gpointer user_data)
+{
+ mm_err ("Timeout has elapsed");
+ g_assert_not_reached ();
+ return G_SOURCE_REMOVE;
+}
+
+static void
+run_loop_for_ms (TestData *tdata,
+ guint32 timeout)
+{
+ mm_info ("Run loop for %u ms", timeout);
+ tdata->timeout_id = g_timeout_add (timeout, loop_timeout_cb, tdata);
+ g_main_loop_run (tdata->loop);
+}
+
+static void
+stop_loop (TestData *tdata)
+{
+ if (tdata->timeout_id) {
+ g_source_remove (tdata->timeout_id);
+ tdata->timeout_id = 0;
+ }
+ mm_info ("Stop the loop");
+ g_main_loop_quit (tdata->loop);
+}
+
+static void
+add_modem_completion_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ GVariant *dbus_return = NULL;
+ GVariant *obj_path_variant = NULL;
+ TestData *tdata = NULL;
+
+ tdata = (TestData*)user_data;
+
+ mm_info ("AddModem DBus call completed");
+ dbus_return = g_dbus_proxy_call_finish (tdata->mm_proxy, res, &error);
+ g_assert_no_error (error);
+ g_assert_nonnull (dbus_return);
+ g_assert_cmpstr (g_variant_get_type_string (dbus_return), == , "(o)");
+
+ obj_path_variant = g_variant_get_child_value (dbus_return, 0);
+ tdata->modem_object_path = g_variant_dup_string (obj_path_variant, NULL);
+
+ g_assert_null (tdata->mm_modem_prop_proxy);
+ tdata->mm_modem_prop_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
+ NULL,
+ MM_DBUS_SERVICE,
+ tdata->modem_object_path,
+ "org.freedesktop.DBus.Properties",
+ NULL, &error);
+
+ g_assert_no_error (error);
+ g_assert_nonnull (tdata->mm_modem_prop_proxy);
+
+ g_variant_unref (dbus_return);
+ g_variant_unref (obj_path_variant);
+
+ stop_loop (tdata);
+}
+
+static gchar*
+add_modem (TestData *tdata,
+ gboolean add_sim,
+ const gchar *iccid)
+{
+ g_dbus_proxy_call (tdata->mm_proxy,
+ "AddModem",
+ g_variant_new ("(bs)", add_sim, iccid),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ 1000,
+ NULL,
+ add_modem_completion_cb,
+ tdata);
+
+ run_loop_for_ms (tdata, 1000);
+ return tdata->modem_object_path;
+}
+
+static void
+emit_state_changed_completion_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ GVariant *dbus_return = NULL;
+ TestData *tdata = NULL;
+
+ tdata = (TestData*)user_data;
+
+ mm_info ("EmitStateChanged DBus call completed");
+ dbus_return = g_dbus_proxy_call_finish (tdata->mm_proxy, res, &error);
+ g_assert_no_error (error);
+ g_assert_nonnull (dbus_return);
+ g_variant_unref (dbus_return);
+
+ stop_loop (tdata);
+}
+
+static void
+set_modem_state (TestData *tdata,
+ MMModemState state,
+ MMModemStateFailedReason reason)
+{
+ GError *error = NULL;
+ GVariant *ret = NULL;
+ GVariant *old_state_variant = NULL;
+ guint old_state = 0;
+
+ g_assert_nonnull (tdata->mm_modem_prop_proxy);
+
+ /* Get current state */
+ ret = g_dbus_proxy_call_sync (tdata->mm_modem_prop_proxy,
+ "org.freedesktop.DBus.Properties.Get",
+ g_variant_new ("(ss)",
+ MM_DBUS_INTERFACE_MODEM,
+ MM_MODEM_PROPERTY_STATE),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1,
+ NULL,
+ &error);
+ g_assert_no_error (error);
+ g_variant_get (ret, "(v)", &old_state_variant);
+ old_state = (guint)g_variant_get_int32 (old_state_variant);
+ g_variant_unref (ret);
+ g_variant_unref (old_state_variant);
+
+ ret = g_dbus_proxy_call_sync (tdata->mm_modem_prop_proxy,
+ "org.freedesktop.DBus.Properties.Set",
+ g_variant_new ("(ssv)",
+ MM_DBUS_INTERFACE_MODEM,
+ MM_MODEM_PROPERTY_STATE,
+ g_variant_new_int32 (state)),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1,
+ NULL,
+ &error);
+ g_assert_no_error (error);
+ g_variant_unref (ret);
+
+ ret = g_dbus_proxy_call_sync (tdata->mm_modem_prop_proxy,
+ "org.freedesktop.DBus.Properties.Set",
+ g_variant_new ("(ssv)",
+ MM_DBUS_INTERFACE_MODEM,
+ MM_MODEM_PROPERTY_STATEFAILEDREASON,
+ g_variant_new_uint32 (reason)),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1,
+ NULL,
+ &error);
+
+ g_assert_no_error (error);
+ g_variant_unref (ret);
+
+ /* Emit state change signal */
+ g_dbus_proxy_call (tdata->mm_proxy,
+ "EmitStateChanged",
+ g_variant_new ("(uuu)", old_state, state, reason),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ 1000,
+ NULL,
+ emit_state_changed_completion_cb,
+ tdata);
+
+ run_loop_for_ms (tdata, 1000);
+}
+
+static void
+set_modem_unlock_completion_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ GVariant *dbus_return = NULL;
+ TestData *tdata = NULL;
+
+ tdata = (TestData*)user_data;
+
+ mm_info ("org.freedesktop.DBus.Properties.Set DBus call completed");
+ dbus_return = g_dbus_proxy_call_finish (tdata->mm_modem_prop_proxy, res, &error);
+ g_assert_no_error (error);
+ g_assert_nonnull (dbus_return);
+ g_variant_unref (dbus_return);
+
+ stop_loop (tdata);
+}
+
+static void
+set_modem_unlock (TestData *tdata,
+ MMModemLock lock_state)
+{
+ g_assert_nonnull (tdata->mm_modem_prop_proxy);
+
+ g_dbus_proxy_call (tdata->mm_modem_prop_proxy,
+ "org.freedesktop.DBus.Properties.Set",
+ g_variant_new ("(ssv)",
+ MM_DBUS_INTERFACE_MODEM,
+ MM_MODEM_PROPERTY_UNLOCKREQUIRED,
+ g_variant_new_uint32 (lock_state)),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ 1000,
+ NULL,
+ set_modem_unlock_completion_cb,
+ tdata);
+
+ run_loop_for_ms (tdata, 1000);
+}
+
+static void
+set_modem_equipment_error (TestData *tdata,
+ MMMobileEquipmentError equipmentError,
+ gboolean clear)
+{
+ GError *error = NULL;
+ GVariant *ret = NULL;
+
+ ret = g_dbus_proxy_call_sync (tdata->mm_proxy,
+ "SetMobileEquipmentError",
+ g_variant_new ("(ub)", equipmentError, clear),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ 3000,
+ NULL,
+ &error);
+ g_assert_no_error (error);
+ g_variant_unref (ret);
+}
+
+static void
+test_modem_interface (TestData **ptdata,
+ gconstpointer data)
+{
+ TestData *tdata = NULL;
+ GDBusObject *modem_object = NULL;
+ MMModem *mm_modem = NULL;
+ g_autofree gchar *modem_path = NULL;
+
+ tdata = *ptdata;
+ /* Add a modem object (with no sim attached) */
+ modem_path = add_modem (tdata, FALSE, "");
+ modem_object = g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (tdata->mm_manager), modem_path);
+ g_assert_nonnull (modem_object);
+
+ mm_modem = mm_object_get_modem (MM_OBJECT (modem_object));
+ g_clear_object (&modem_object);
+
+ /* Check the modem states */
+ g_assert_cmpuint (mm_modem_get_state (mm_modem), ==, MM_MODEM_STATE_UNKNOWN);
+ g_assert_cmpuint (mm_modem_get_state_failed_reason (mm_modem), ==, MM_MODEM_STATE_FAILED_REASON_UNKNOWN);
+
+ /* Set new state and check that it is propagated */
+ set_modem_state (tdata, MM_MODEM_STATE_REGISTERED, MM_MODEM_STATE_FAILED_REASON_NONE);
+
+ g_assert_cmpuint (mm_modem_get_state (mm_modem), ==, MM_MODEM_STATE_REGISTERED);
+ g_assert_cmpuint (mm_modem_get_state_failed_reason (mm_modem), ==, MM_MODEM_STATE_FAILED_REASON_NONE);
+
+ g_clear_object (&mm_modem);
+}
+
+static void
+mm_sim_send_pin_completion_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ gboolean ret = FALSE;
+ TestData *tdata = NULL;
+
+ tdata = (TestData*)user_data;
+
+ mm_info("SendPin DBus method call completed");
+ ret = mm_sim_send_pin_finish (tdata->sim, res, &error);
+ if (tdata->pin_error) {
+ g_assert_nonnull (error);
+ g_assert_false (ret);
+ g_clear_error (&error);
+ } else {
+ g_assert_no_error (error);
+ g_assert_true (ret);
+ }
+ stop_loop (tdata);
+}
+
+static void
+test_sim_interface (TestData **ptdata,
+ gconstpointer data)
+{
+ TestData *tdata = NULL;
+ GDBusObject *modem_object = NULL;
+ MMModem *mm_modem = NULL;
+ GError *error = NULL;
+ g_autofree gchar *modem_path = NULL;
+
+ tdata = *ptdata;
+ /* Add a modem with a sim object */
+ modem_path = add_modem (tdata, TRUE, "89330122503000800750");
+ modem_object = g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (tdata->mm_manager), modem_path);
+ g_assert_nonnull (modem_object);
+ mm_modem = mm_object_get_modem (MM_OBJECT (modem_object));
+ g_clear_object (&modem_object);
+
+ g_assert_cmpuint (mm_modem_get_unlock_required (mm_modem), ==, MM_MODEM_LOCK_NONE);
+ /* Lock the modem */
+ set_modem_unlock (tdata, MM_MODEM_LOCK_SIM_PIN);
+ g_assert_cmpuint (mm_modem_get_unlock_required (mm_modem), ==, MM_MODEM_LOCK_SIM_PIN);
+
+ tdata->sim = mm_modem_get_sim_sync (mm_modem, NULL, &error);
+ g_assert_no_error (error);
+ g_assert_nonnull (tdata->sim);
+ g_assert_cmpstr (mm_sim_get_identifier(tdata->sim), ==, "89330122503000800750");
+
+ /* Send a pin code */
+ tdata->pin_error = FALSE;
+ mm_sim_send_pin (tdata->sim, "1234", NULL, mm_sim_send_pin_completion_cb, tdata);
+ run_loop_for_ms (tdata, 1000);
+
+ /* Check that the modem has been unlocked */
+ g_assert_cmpuint (mm_modem_get_unlock_required (mm_modem), ==, MM_MODEM_LOCK_NONE);
+
+ /* Re lock it */
+ set_modem_unlock (tdata, MM_MODEM_LOCK_SIM_PIN);
+ g_assert_cmpuint (mm_modem_get_unlock_required (mm_modem), ==, MM_MODEM_LOCK_SIM_PIN);
+
+ /* Set an error that will simulate wrong pin code */
+ set_modem_equipment_error (tdata, MM_MOBILE_EQUIPMENT_ERROR_INCORRECT_PASSWORD, FALSE);
+
+ tdata->pin_error = TRUE;
+ mm_sim_send_pin (tdata->sim, "0000", NULL, mm_sim_send_pin_completion_cb, tdata);
+ run_loop_for_ms (tdata, 1000);
+
+ g_assert_cmpuint (mm_modem_get_unlock_required (mm_modem), ==, MM_MODEM_LOCK_SIM_PIN);
+
+ /* Clear the error and retry the pin code */
+ set_modem_equipment_error (tdata, 0, TRUE);
+ tdata->pin_error = FALSE;
+ mm_sim_send_pin (tdata->sim, "1234", NULL, mm_sim_send_pin_completion_cb, tdata);
+ run_loop_for_ms (tdata, 1000);
+
+ g_assert_cmpuint (mm_modem_get_unlock_required (mm_modem), ==, MM_MODEM_LOCK_NONE);
+
+ g_clear_object (&tdata->sim);
+ g_clear_object (&mm_modem);
+}
+
+int main (int argc,
+ char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add ("/MM/stub/modem/interface",
+ TestData *, NULL, setup,
+ test_modem_interface,
+ teardown);
+ g_test_add ("/MM/stub/sim/interface",
+ TestData *, NULL, setup,
+ test_sim_interface,
+ teardown);
+ return g_test_run ();
+}