summaryrefslogtreecommitdiff
path: root/callouts/tests/test-dispatcher-envp.c
diff options
context:
space:
mode:
Diffstat (limited to 'callouts/tests/test-dispatcher-envp.c')
-rw-r--r--callouts/tests/test-dispatcher-envp.c615
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 ();
+}
+