This adds tests for the network panel based on the test service found in NetworkManager. Another possible solution may be to use the one from dbusmock, however NetworkManager already has readily available code to write tests in C which makes checking the widget hierarchy easier.
297 lines
8.4 KiB
C
297 lines
8.4 KiB
C
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
|
/*
|
|
* 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, 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.
|
|
*
|
|
* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Copyright 2010 - 2014, 2018 Red Hat, Inc.
|
|
*
|
|
*/
|
|
|
|
/* Static functions to help with testing */
|
|
|
|
|
|
/* nmtst_create_minimal_connection is copied from nm-test-utils.h. */
|
|
|
|
static inline NMConnection *
|
|
nmtst_create_minimal_connection (const char *id, const char *uuid, const char *type, NMSettingConnection **out_s_con)
|
|
{
|
|
NMConnection *con;
|
|
NMSetting *s_base = NULL;
|
|
NMSettingConnection *s_con;
|
|
gs_free char *uuid_free = NULL;
|
|
|
|
g_assert (id);
|
|
|
|
if (uuid)
|
|
g_assert (nm_utils_is_uuid (uuid));
|
|
else
|
|
uuid = uuid_free = nm_utils_uuid_generate ();
|
|
|
|
if (type) {
|
|
GType type_g;
|
|
|
|
type_g = nm_setting_lookup_type (type);
|
|
|
|
g_assert (type_g != G_TYPE_INVALID);
|
|
|
|
s_base = g_object_new (type_g, NULL);
|
|
g_assert (NM_IS_SETTING (s_base));
|
|
}
|
|
|
|
con = nm_simple_connection_new ();
|
|
|
|
s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
|
|
|
|
g_object_set (s_con,
|
|
NM_SETTING_CONNECTION_ID, id,
|
|
NM_SETTING_CONNECTION_UUID, uuid,
|
|
NM_SETTING_CONNECTION_TYPE, type,
|
|
NULL);
|
|
nm_connection_add_setting (con, NM_SETTING (s_con));
|
|
|
|
if (s_base)
|
|
nm_connection_add_setting (con, s_base);
|
|
|
|
if (out_s_con)
|
|
*out_s_con = s_con;
|
|
return con;
|
|
}
|
|
|
|
|
|
typedef struct {
|
|
GMainLoop *loop;
|
|
NMDevice *device;
|
|
NMClient *client;
|
|
|
|
NMActiveConnection *ac;
|
|
|
|
const gchar * const *client_props;
|
|
const gchar * const *device_props;
|
|
|
|
int client_remaining;
|
|
int device_remaining;
|
|
int other_remaining;
|
|
} EventWaitInfo;
|
|
|
|
|
|
#define WAIT_CHECK_REMAINING() \
|
|
if (info->client_remaining == 0 && info->device_remaining == 0 && info->other_remaining == 0) { \
|
|
g_debug ("Got expected events, quitting mainloop"); \
|
|
g_main_loop_quit (info->loop); \
|
|
} \
|
|
if (info->client_remaining < 0 || info->device_remaining < 0 || info->other_remaining < 0) { \
|
|
g_error ("Pending events are negative: client: %d, device: %d, other: %d", info->client_remaining, info->device_remaining, info->other_remaining); \
|
|
g_assert_not_reached (); \
|
|
}
|
|
|
|
#define WAIT_DECL() \
|
|
EventWaitInfo info = {0}; \
|
|
gint _timeout_id;
|
|
#define WAIT_DEVICE(_device, count, ...) \
|
|
info.device = (_device); \
|
|
info.device_remaining = (count); \
|
|
{ const gchar * const *props = (const char const *[]){ __VA_ARGS__, NULL }; \
|
|
info.device_props = props; } \
|
|
g_signal_connect ((_device), "notify", G_CALLBACK (device_notify_cb), &info);
|
|
#define WAIT_CLIENT(_client, count, ...) \
|
|
info.client = (_client); \
|
|
info.client_remaining = (count); \
|
|
info.client_props = (const char *[]) {__VA_ARGS__, NULL}; \
|
|
g_signal_connect ((_client), "notify", G_CALLBACK (client_notify_cb), &info);
|
|
|
|
#define WAIT_DESTROY() \
|
|
g_source_remove (_timeout_id); \
|
|
if (info.device) \
|
|
g_signal_handlers_disconnect_by_func (info.device, G_CALLBACK (device_notify_cb), &info); \
|
|
if (info.client) \
|
|
g_signal_handlers_disconnect_by_func (info.client, G_CALLBACK (client_notify_cb), &info); \
|
|
g_main_loop_unref (info.loop);
|
|
|
|
#define WAIT_FINISHED(timeout) \
|
|
info.loop = g_main_loop_new (NULL, FALSE); \
|
|
_timeout_id = g_timeout_add_seconds ((timeout), timeout_cb, &info); \
|
|
g_main_loop_run (info.loop); \
|
|
WAIT_DESTROY()
|
|
|
|
static gboolean
|
|
timeout_cb (gpointer user_data)
|
|
{
|
|
EventWaitInfo *info = user_data;
|
|
|
|
if (info)
|
|
g_error ("Pending events are: client: %d, device: %d, other: %d", info->client_remaining, info->device_remaining, info->other_remaining); \
|
|
g_assert_not_reached ();
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
static void
|
|
device_notify_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data)
|
|
{
|
|
EventWaitInfo *info = user_data;
|
|
|
|
g_assert (device == info->device);
|
|
|
|
if (!g_strv_contains (info->device_props, g_param_spec_get_name (pspec))) {
|
|
g_debug ("Ignoring notification for device property %s", g_param_spec_get_name (pspec));
|
|
return;
|
|
}
|
|
|
|
g_debug ("Counting notification for device property %s", g_param_spec_get_name (pspec));
|
|
|
|
info->device_remaining--;
|
|
WAIT_CHECK_REMAINING()
|
|
}
|
|
|
|
static void
|
|
client_notify_cb (NMClient *client, GParamSpec *pspec, gpointer user_data)
|
|
{
|
|
EventWaitInfo *info = user_data;
|
|
|
|
g_assert (client == info->client);
|
|
|
|
if (!g_strv_contains (info->client_props, g_param_spec_get_name (pspec))) {
|
|
g_debug ("Ignoring notification for client property %s", g_param_spec_get_name (pspec));
|
|
return;
|
|
}
|
|
|
|
g_debug ("Counting notification for client property %s", g_param_spec_get_name (pspec));
|
|
|
|
info->client_remaining--;
|
|
WAIT_CHECK_REMAINING()
|
|
}
|
|
|
|
static void
|
|
nmtst_set_device_state (NMTstcServiceInfo *sinfo, NMDevice *device, NMDeviceState state, NMDeviceStateReason reason)
|
|
{
|
|
GError *error = NULL;
|
|
WAIT_DECL()
|
|
|
|
g_debug ("Setting device %s state to %d with reason %d", nm_device_get_iface (device), state, reason);
|
|
|
|
g_dbus_proxy_call_sync (sinfo->proxy,
|
|
"SetDeviceState",
|
|
g_variant_new ("(suu)", nm_object_get_path (NM_OBJECT (device)), state, reason),
|
|
G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
|
3000,
|
|
NULL,
|
|
&error);
|
|
g_assert_no_error (error);
|
|
|
|
WAIT_DEVICE(device, 1, "state-reason")
|
|
WAIT_FINISHED(5)
|
|
}
|
|
|
|
static void
|
|
nmtst_set_wired_speed (NMTstcServiceInfo *sinfo, NMDevice *device, guint32 speed)
|
|
{
|
|
GError *error = NULL;
|
|
WAIT_DECL()
|
|
|
|
g_debug ("Setting device %s speed to %d", nm_device_get_iface (device), speed);
|
|
|
|
g_dbus_proxy_call_sync (sinfo->proxy,
|
|
"SetWiredSpeed",
|
|
g_variant_new ("(su)", nm_object_get_path (NM_OBJECT (device)), speed),
|
|
G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
|
3000,
|
|
NULL,
|
|
&error);
|
|
|
|
g_assert_no_error (error);
|
|
|
|
WAIT_DEVICE(device, 2, "speed", "carrier")
|
|
WAIT_FINISHED(5)
|
|
}
|
|
|
|
|
|
static void
|
|
device_removed_cb (NMClient *client,
|
|
NMDevice *device,
|
|
gpointer user_data)
|
|
{
|
|
EventWaitInfo *info = user_data;
|
|
|
|
g_assert (device);
|
|
g_assert (device == info->device);
|
|
|
|
info->other_remaining--;
|
|
WAIT_CHECK_REMAINING()
|
|
}
|
|
|
|
static void
|
|
nmtst_remove_device (NMTstcServiceInfo *sinfo, NMClient *client, NMDevice *device)
|
|
{
|
|
GError *error = NULL;
|
|
WAIT_DECL()
|
|
|
|
g_object_ref (device);
|
|
|
|
g_dbus_proxy_call_sync (sinfo->proxy,
|
|
"RemoveDevice",
|
|
g_variant_new ("(s)", nm_object_get_path (NM_OBJECT (device))),
|
|
G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
|
3000,
|
|
NULL,
|
|
&error);
|
|
g_assert_no_error (error);
|
|
|
|
info.device = device;
|
|
info.client = client;
|
|
info.other_remaining = 1;
|
|
g_signal_connect (client, "device-removed",
|
|
G_CALLBACK (device_removed_cb), &info);
|
|
|
|
WAIT_FINISHED(5)
|
|
|
|
g_object_unref(device);
|
|
g_signal_handlers_disconnect_by_func (client, device_removed_cb, &info);
|
|
}
|
|
|
|
static void
|
|
add_and_activate_cb (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
NMClient *client = NM_CLIENT (object);
|
|
EventWaitInfo *info = user_data;
|
|
GError *error = NULL;
|
|
|
|
info->ac = nm_client_add_and_activate_connection_finish (client, result, &error);
|
|
g_assert_no_error (error);
|
|
g_assert (info->ac != NULL);
|
|
|
|
info->other_remaining--;
|
|
WAIT_CHECK_REMAINING()
|
|
}
|
|
|
|
static NMActiveConnection*
|
|
nmtst_add_and_activate_connection (NMTstcServiceInfo *sinfo, NMClient *client, NMDevice *device, NMConnection *conn)
|
|
{
|
|
WAIT_DECL()
|
|
|
|
nm_client_add_and_activate_connection_async (client, conn, device, NULL,
|
|
NULL, add_and_activate_cb, &info);
|
|
|
|
info.other_remaining = 1;
|
|
WAIT_CLIENT(client, 1, NM_CLIENT_ACTIVE_CONNECTIONS);
|
|
WAIT_DEVICE(device, 1, NM_DEVICE_ACTIVE_CONNECTION);
|
|
|
|
g_object_unref (conn);
|
|
|
|
WAIT_FINISHED(5)
|
|
|
|
g_assert (info.ac != NULL);
|
|
|
|
return info.ac;
|
|
}
|