diff options
Diffstat (limited to 'callouts/tests/test-dispatcher-envp.c')
-rw-r--r-- | callouts/tests/test-dispatcher-envp.c | 615 |
1 files changed, 615 insertions, 0 deletions
diff --git a/callouts/tests/test-dispatcher-envp.c b/callouts/tests/test-dispatcher-envp.c new file mode 100644 index 000000000..b4dbd784a --- /dev/null +++ b/callouts/tests/test-dispatcher-envp.c @@ -0,0 +1,615 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; 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, 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 (C) 2011 Red Hat, Inc. + * + */ + +#include <config.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <glib.h> +#include <glib-object.h> + +#include "nm-connection.h" +#include "nm-setting-connection.h" +#include "nm-dispatcher-utils.h" +#include "nm-dbus-glib-types.h" +#include "nm-dispatcher-action.h" +#include "nm-utils.h" + +/*******************************************/ + +static void +value_destroy (gpointer data) +{ + GValue *value = (GValue *) data; + + g_value_unset (value); + g_slice_free (GValue, value); +} + +static GHashTable * +value_hash_create (void) +{ + return g_hash_table_new_full (g_str_hash, g_str_equal, g_free, value_destroy); +} + +static void +value_hash_add (GHashTable *hash, + const char *key, + GValue *value) +{ + g_hash_table_insert (hash, g_strdup (key), value); +} + +static void +value_hash_add_string (GHashTable *hash, + const char *key, + const char *str) +{ + GValue *value; + + value = g_slice_new0 (GValue); + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, str); + + value_hash_add (hash, key, value); +} + +static void +value_hash_add_object_path (GHashTable *hash, + const char *key, + const char *op) +{ + GValue *value; + + value = g_slice_new0 (GValue); + g_value_init (value, DBUS_TYPE_G_OBJECT_PATH); + g_value_set_boxed (value, op); + + value_hash_add (hash, key, value); +} + +static void +value_hash_add_uint (GHashTable *hash, + const char *key, + guint32 val) +{ + GValue *value; + + value = g_slice_new0 (GValue); + g_value_init (value, G_TYPE_UINT); + g_value_set_uint (value, val); + + value_hash_add (hash, key, value); +} + +static void +value_hash_add_strv (GHashTable *hash, + const char *key, + GPtrArray *array) +{ + GValue *value; + + value = g_slice_new0 (GValue); + g_value_init (value, DBUS_TYPE_G_ARRAY_OF_STRING); + g_value_take_boxed (value, array); + value_hash_add (hash, key, value); +} + +static void +value_hash_add_uint_array (GHashTable *hash, + const char *key, + GArray *array) +{ + GValue *value; + + value = g_slice_new0 (GValue); + g_value_init (value, DBUS_TYPE_G_UINT_ARRAY); + g_value_take_boxed (value, array); + value_hash_add (hash, key, value); +} + +static gboolean +parse_main (GKeyFile *kf, + GHashTable **out_con_hash, + GHashTable **out_con_props, + char **out_iface, + char **out_action, + GError **error) +{ + char *uuid, *id; + NMConnection *connection; + NMSettingConnection *s_con; + + *out_iface = g_key_file_get_string (kf, "main", "iface", error); + if (*out_iface == NULL) + return FALSE; + + *out_action = g_key_file_get_string (kf, "main", "action", error); + if (*out_action == NULL) + return FALSE; + + uuid = g_key_file_get_string (kf, "main", "uuid", error); + if (uuid == NULL) + return FALSE; + id = g_key_file_get_string (kf, "main", "id", error); + if (id == NULL) + return FALSE; + + connection = nm_connection_new (); + g_assert (connection); + s_con = (NMSettingConnection *) nm_setting_connection_new (); + g_assert (s_con); + g_object_set (s_con, + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_ID, id, + NULL); + g_free (uuid); + g_free (id); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + *out_con_hash = nm_connection_to_hash (connection, NM_SETTING_HASH_FLAG_ALL); + g_object_unref (connection); + + *out_con_props = value_hash_create (); + value_hash_add_object_path (*out_con_props, "connection-path", "/org/freedesktop/NetworkManager/Connections/5"); + + return TRUE; +} + +static gboolean +parse_device (GKeyFile *kf, GHashTable **out_device_props, GError **error) +{ + char *tmp; + gint i; + + *out_device_props = value_hash_create (); + + i = g_key_file_get_integer (kf, "device", "state", error); + if (i == 0) + return FALSE; + value_hash_add_uint (*out_device_props, NMD_DEVICE_PROPS_STATE, (guint) i); + + i = g_key_file_get_integer (kf, "device", "type", error); + if (i == 0) + return FALSE; + value_hash_add_uint (*out_device_props, NMD_DEVICE_PROPS_TYPE, (guint) i); + + tmp = g_key_file_get_string (kf, "device", "interface", error); + if (tmp == NULL) + return FALSE; + value_hash_add_string (*out_device_props, NMD_DEVICE_PROPS_INTERFACE, tmp); + g_free (tmp); + + tmp = g_key_file_get_string (kf, "device", "ip-interface", error); + if (tmp == NULL) + return FALSE; + value_hash_add_string (*out_device_props, NMD_DEVICE_PROPS_IP_INTERFACE, tmp); + g_free (tmp); + + tmp = g_key_file_get_string (kf, "device", "path", error); + if (tmp == NULL) + return FALSE; + value_hash_add_object_path (*out_device_props, NMD_DEVICE_PROPS_PATH, tmp); + g_free (tmp); + + return TRUE; +} + +static gboolean +add_uint_array (GKeyFile *kf, + GHashTable *props, + const char *section, + const char *key, + GError **error) +{ + char *tmp; + char **split, **iter; + GArray *items; + + tmp = g_key_file_get_string (kf, section, key, error); + if (tmp == NULL) { + g_clear_error (error); + return TRUE; + } + split = g_strsplit_set (tmp, " ", -1); + g_free (tmp); + + if (g_strv_length (split) > 0) { + items = g_array_sized_new (FALSE, TRUE, sizeof (guint32), g_strv_length (split)); + for (iter = split; iter && *iter; iter++) { + if (strlen (g_strstrip (*iter))) { + struct in_addr addr; + + g_assert_cmpint (inet_pton (AF_INET, *iter, &addr), ==, 1); + g_array_append_val (items, addr.s_addr); + } + } + value_hash_add_uint_array (props, key, items); + } + g_strfreev (split); + return TRUE; +} + +static gboolean +parse_ip4 (GKeyFile *kf, GHashTable **out_props, const char *section, GError **error) +{ + char *tmp; + char **split, **iter; + GPtrArray *domains; + GSList *list; + GValue *val; + + *out_props = value_hash_create (); + + /* search domains */ + tmp = g_key_file_get_string (kf, section, "domains", error); + if (tmp == NULL) + return FALSE; + split = g_strsplit_set (tmp, " ", -1); + g_free (tmp); + + if (g_strv_length (split) > 0) { + domains = g_ptr_array_sized_new (g_strv_length (split)); + for (iter = split; iter && *iter; iter++) { + if (strlen (g_strstrip (*iter))) + g_ptr_array_add (domains, g_strdup (*iter)); + } + value_hash_add_strv (*out_props, "domains", domains); + } + g_strfreev (split); + + /* nameservers */ + if (!add_uint_array (kf, *out_props, "ip4", "nameservers", error)) + return FALSE; + /* wins-servers */ + if (!add_uint_array (kf, *out_props, "ip4", "wins-servers", error)) + return FALSE; + + /* Addresses */ + tmp = g_key_file_get_string (kf, section, "addresses", error); + if (tmp == NULL) + return FALSE; + split = g_strsplit_set (tmp, ",", -1); + g_free (tmp); + + if (g_strv_length (split) > 0) { + list = NULL; + for (iter = split; iter && *iter; iter++) { + NMIP4Address *addr; + struct in_addr a; + char *p; + + if (strlen (g_strstrip (*iter)) == 0) + continue; + + addr = nm_ip4_address_new (); + + p = strchr (*iter, '/'); + g_assert (p); + *p++ = '\0'; + + g_assert_cmpint (inet_pton (AF_INET, *iter, &a), ==, 1); + nm_ip4_address_set_address (addr, a.s_addr); + nm_ip4_address_set_prefix (addr, (guint) atoi (p)); + + p = strchr (p, ' '); + g_assert (p); + p++; + + g_assert_cmpint (inet_pton (AF_INET, p, &a), ==, 1); + nm_ip4_address_set_gateway (addr, a.s_addr); + + list = g_slist_append (list, addr); + } + + val = g_slice_new0 (GValue); + g_value_init (val, DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT); + nm_utils_ip4_addresses_to_gvalue (list, val); + value_hash_add (*out_props, "addresses", val); + } + g_strfreev (split); + + /* Routes */ + tmp = g_key_file_get_string (kf, section, "routes", error); + g_clear_error (error); + if (tmp) { + split = g_strsplit_set (tmp, ",", -1); + g_free (tmp); + + if (g_strv_length (split) > 0) { + list = NULL; + for (iter = split; iter && *iter; iter++) { + NMIP4Route *route; + struct in_addr a; + char *p; + + if (strlen (g_strstrip (*iter)) == 0) + continue; + + route = nm_ip4_route_new (); + + p = strchr (*iter, '/'); + g_assert (p); + *p++ = '\0'; + + g_assert_cmpint (inet_pton (AF_INET, *iter, &a), ==, 1); + nm_ip4_route_set_dest (route, a.s_addr); + nm_ip4_route_set_prefix (route, (guint) atoi (p)); + + p = strchr (p, ' '); + g_assert (p); + p++; + + g_assert_cmpint (inet_pton (AF_INET, p, &a), ==, 1); + nm_ip4_route_set_next_hop (route, a.s_addr); + + p = strchr (p, ' '); + g_assert (p); + p++; + nm_ip4_route_set_metric (route, (guint) atoi (p)); + + list = g_slist_append (list, route); + } + + val = g_slice_new0 (GValue); + g_value_init (val, DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT); + nm_utils_ip4_routes_to_gvalue (list, val); + value_hash_add (*out_props, "routes", val); + } + g_strfreev (split); + } + + return TRUE; +} + +static gboolean +parse_dhcp (GKeyFile *kf, + const char *group_name, + GHashTable **out_props, + GError **error) +{ + char **keys, **iter, *val; + + keys = g_key_file_get_keys (kf, group_name, NULL, error); + if (!keys) + return FALSE; + + *out_props = value_hash_create (); + for (iter = keys; iter && *iter; iter++) { + val = g_key_file_get_string (kf, group_name, *iter, error); + if (!val) + return FALSE; + value_hash_add_string (*out_props, *iter, val); + g_free (val); + } + + return TRUE; +} + +static gboolean +get_dispatcher_file (const char *file, + GHashTable **out_con_hash, + GHashTable **out_con_props, + GHashTable **out_device_props, + GHashTable **out_device_ip4_props, + GHashTable **out_device_ip6_props, + GHashTable **out_device_dhcp4_props, + GHashTable **out_device_dhcp6_props, + const char **out_vpn_ip_iface, + GHashTable **out_vpn_ip4_props, + GHashTable **out_vpn_ip6_props, + char **out_expected_iface, + char **out_action, + GHashTable **out_env, + GError **error) +{ + GKeyFile *kf; + gboolean success = FALSE; + char **keys, **iter, *val; + + kf = g_key_file_new (); + if (!g_key_file_load_from_file (kf, file, G_KEY_FILE_NONE, error)) + return FALSE; + + if (!parse_main (kf, out_con_hash, out_con_props, out_expected_iface, out_action, error)) + goto out; + + if (!parse_device (kf, out_device_props, error)) + goto out; + + if (g_key_file_has_group (kf, "ip4")) { + if (!parse_ip4 (kf, out_device_ip4_props, "ip4", error)) + goto out; + } + + if (g_key_file_has_group (kf, "dhcp4")) { + if (!parse_dhcp (kf, "dhcp4", out_device_dhcp4_props, error)) + goto out; + } + + if (g_key_file_has_group (kf, "dhcp6")) { + if (!parse_dhcp (kf, "dhcp6", out_device_dhcp4_props, error)) + goto out; + } + + g_assert (g_key_file_has_group (kf, "env")); + keys = g_key_file_get_keys (kf, "env", NULL, error); + *out_env = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + for (iter = keys; iter && *iter; iter++) { + val = g_key_file_get_string (kf, "env", *iter, error); + if (!val) + goto out; + g_hash_table_insert (*out_env, + g_strdup_printf ("%s=%s", *iter, val), + GUINT_TO_POINTER (1)); + g_free (val); + } + g_strfreev (keys); + + success = TRUE; + +out: + g_key_file_free (kf); + return success; +} + +/*******************************************/ + +static void +test_generic (const char *path, const char *file) +{ + GHashTable *con_hash = NULL; + GHashTable *con_props = NULL; + GHashTable *device_props = NULL; + GHashTable *device_ip4_props = NULL; + GHashTable *device_ip6_props = NULL; + GHashTable *device_dhcp4_props = NULL; + GHashTable *device_dhcp6_props = NULL; + const char *vpn_ip_iface = NULL; + GHashTable *vpn_ip4_props = NULL; + GHashTable *vpn_ip6_props = NULL; + char *expected_iface = NULL; + char *action = NULL; + char *out_iface = NULL; + GHashTable *expected_env = NULL; + GError *error = NULL; + gboolean success; + char *p; + char **denv, **iter; + + /* Read in the test file */ + p = g_strdup_printf ("%s/%s", path, file); + success = get_dispatcher_file (p, + &con_hash, + &con_props, + &device_props, + &device_ip4_props, + &device_ip6_props, + &device_dhcp4_props, + &device_dhcp6_props, + &vpn_ip_iface, + &vpn_ip4_props, + &vpn_ip6_props, + &expected_iface, + &action, + &expected_env, + &error); + g_free (p); + g_assert_no_error (error); + g_assert (success); + + /* Get the environment from the dispatcher code */ + denv = nm_dispatcher_utils_construct_envp (action, + con_hash, + con_props, + device_props, + device_ip4_props, + device_ip6_props, + device_dhcp4_props, + device_dhcp6_props, + vpn_ip_iface, + vpn_ip4_props, + vpn_ip6_props, + &out_iface); + + /* Print out environment for now */ + g_message ("\n"); + for (iter = denv; iter && *iter; iter++) + g_message (" %s", *iter); + + g_assert_cmpint (g_strv_length (denv), ==, g_hash_table_size (expected_env)); + + { + GHashTableIter k; + const char *key; + g_hash_table_iter_init (&k, expected_env); + while (g_hash_table_iter_next (&k, (gpointer) &key, NULL)) + g_message (" %s", key); + } + + /* Compare dispatcher generated env and expected env */ + for (iter = denv; iter && *iter; iter++) { + gpointer foo; + + foo = g_hash_table_lookup (expected_env, *iter); + if (!foo) + g_warning ("Failed to find %s in environment", *iter); + g_assert (foo); + } + + g_assert_cmpstr (expected_iface, ==, out_iface); +} + +/*******************************************/ + +static void +test_old_up (const char *path) +{ + test_generic (path, "dispatcher-old-up"); +} + +static void +test_old_down (const char *path) +{ + test_generic (path, "dispatcher-old-down"); +} + +static void +test_old_vpn_up (const char *path) +{ + test_generic (path, "dispatcher-old-vpn-up"); +} + +static void +test_old_vpn_down (const char *path) +{ + test_generic (path, "dispatcher-old-vpn-down"); +} + +/*******************************************/ + +#if GLIB_CHECK_VERSION(2,25,12) +typedef GTestFixtureFunc TCFunc; +#else +typedef void (*TCFunc)(void); +#endif + +#define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (TCFunc) t, NULL) + +int main (int argc, char **argv) +{ + GTestSuite *suite; + + g_assert (argc > 1); + + g_test_init (&argc, &argv, NULL); + g_type_init (); + + suite = g_test_get_root (); + + g_test_suite_add (suite, TESTCASE (test_old_up, argv[1])); + g_test_suite_add (suite, TESTCASE (test_old_down, argv[1])); + g_test_suite_add (suite, TESTCASE (test_old_vpn_up, argv[1])); + g_test_suite_add (suite, TESTCASE (test_old_vpn_down, argv[1])); + + return g_test_run (); +} + |